From ad727a136a6b592b14cfaa719ae895c119391044 Mon Sep 17 00:00:00 2001 From: ElzorFox Date: Tue, 16 Jun 2020 16:22:22 +0500 Subject: VKontakte: prepare for upgrade VK API version - part 3 --- protocols/VKontakte/src/misc.cpp | 11 +- protocols/VKontakte/src/vk.h | 2 + protocols/VKontakte/src/vk_chats.cpp | 282 ++++++++++++++++++++++++++++-- protocols/VKontakte/src/vk_history.cpp | 10 +- protocols/VKontakte/src/vk_messages.cpp | 152 +++++++++++++++- protocols/VKontakte/src/vk_pollserver.cpp | 2 +- protocols/VKontakte/src/vk_proto.h | 1 + protocols/VKontakte/src/vkjs.js | 55 ++++++ 8 files changed, 497 insertions(+), 18 deletions(-) (limited to 'protocols/VKontakte') diff --git a/protocols/VKontakte/src/misc.cpp b/protocols/VKontakte/src/misc.cpp index 82cf1fb737..c3ff2f4f8e 100644 --- a/protocols/VKontakte/src/misc.cpp +++ b/protocols/VKontakte/src/misc.cpp @@ -1312,7 +1312,12 @@ CMStringW CVkProto::GetFwdMessages(const JSONNode &jnMessages, const JSONNode &j for (auto &jnUser : jnFUsers) { int iUserId = jnUser["id"].as_int(); - CMStringW wszNick(FORMAT, L"%s %s", jnUser["first_name"].as_mstring().c_str(), jnUser["last_name"].as_mstring().c_str()); + CMStringW wszNick(jnUser["name"].as_mstring()); + + if (!wszNick.IsEmpty()) + iUserId *= -1; + else + wszNick.AppendFormat(L"%s %s", jnUser["first_name"].as_mstring().c_str(), jnUser["last_name"].as_mstring().c_str()); CVkUserInfo *vkUser = new CVkUserInfo(jnUser["id"].as_int(), false, wszNick, UserProfileUrl(iUserId), FindUser(iUserId)); vkUsers.insert(vkUser); @@ -1320,7 +1325,11 @@ CMStringW CVkProto::GetFwdMessages(const JSONNode &jnMessages, const JSONNode &j for (auto &jnMsg : jnMessages) { +#if (VK_NEW_API == 1) + UINT uid = jnMsg["from_id"].as_int(); +#else UINT uid = jnMsg["user_id"].as_int(); +#endif CVkUserInfo *vkUser = vkUsers.find((CVkUserInfo *)&uid); CMStringW wszNick, wszUrl; diff --git a/protocols/VKontakte/src/vk.h b/protocols/VKontakte/src/vk.h index 06eb52bf97..2ab0052a98 100644 --- a/protocols/VKontakte/src/vk.h +++ b/protocols/VKontakte/src/vk.h @@ -88,6 +88,8 @@ along with this program. If not, see . #define VK_USER_DEACTIVATE_ACTION 9321 +#define VK_CHAT_FLAG 2000000000 + #define VK_NEW_API 0 #if (VK_NEW_API == 0) diff --git a/protocols/VKontakte/src/vk_chats.cpp b/protocols/VKontakte/src/vk_chats.cpp index cf385b0644..9106e4a6b3 100644 --- a/protocols/VKontakte/src/vk_chats.cpp +++ b/protocols/VKontakte/src/vk_chats.cpp @@ -36,20 +36,16 @@ CVkChatInfo* CVkProto::AppendConversationChat(int iChatId, const JSONNode& jnIte return nullptr; - if (!jnItem) - return nullptr; - - - const JSONNode& jnLastMessage = jnItem["last_message"]; - const JSONNode& jnChatSettings = jnItem["chat_settings"]; + const JSONNode& jnConversation = jnItem ? jnItem["conversation"] : nullNode; + const JSONNode& jnLastMessage = jnItem ? jnItem["last_message"] : nullNode; + const JSONNode& jnChatSettings = jnConversation ? jnConversation["chat_settings"] : nullNode; if (jnLastMessage) { const JSONNode& jnAction = jnLastMessage["action"]; if (jnAction) { CMStringW wszActionType(jnAction["type"].as_mstring()); - if ((wszActionType == L"chat_kick_user") && (jnAction["member_id"].as_int() == m_myUserId)) { + if ((wszActionType == L"chat_kick_user") && (jnAction["member_id"].as_int() == m_myUserId)) return nullptr; - } } } @@ -58,7 +54,6 @@ CVkChatInfo* CVkProto::AppendConversationChat(int iChatId, const JSONNode& jnIte return nullptr; - CVkChatInfo* vkChatInfo = m_chats.find((CVkChatInfo*)&iChatId); if (vkChatInfo != nullptr) return vkChatInfo; @@ -96,7 +91,7 @@ CVkChatInfo* CVkProto::AppendConversationChat(int iChatId, const JSONNode& jnIte db_unset(si->hContact, m_szModuleName, "off"); - if (wszState != L"in") { + if (jnChatSettings && wszState != L"in") { setByte(si->hContact, "off", 1); m_chats.remove(vkChatInfo); return nullptr; @@ -184,7 +179,7 @@ void CVkProto::RetrieveChatInfo(CVkChatInfo *cc) Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/execute.RetrieveChatInfo", true, &CVkProto::OnReceiveChatInfo) << INT_PARAM("chatid", cc->m_iChatId) - << INT_PARAM("func_v", cc->m_bHistoryRead ? 1 : 2) + << INT_PARAM("func_v", cc->m_bHistoryRead ? 1 : 2 + VK_NEW_API) )->pUserInfo = cc; } @@ -203,6 +198,7 @@ void CVkProto::OnReceiveChatInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe if (m_chats.indexOf(cc) == -1) return; +#if (VK_NEW_API==1) const JSONNode &jnInfo = jnResponse["info"]; if (jnInfo) { if (jnInfo["title"]) @@ -216,7 +212,12 @@ void CVkProto::OnReceiveChatInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe cc->m_iAdminId = jnInfo["admin_id"].as_int(); } - const JSONNode &jnUsers = jnResponse["users"]; + + if (!jnResponse["users"]) + return; + + const JSONNode &jnUsers = jnResponse["users"]["profiles"]; + if (jnUsers) { for (auto &it : cc->m_users) it->m_bDel = true; @@ -302,6 +303,7 @@ void CVkProto::OnReceiveChatInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe const JSONNode &jnMsgs = jnResponse["msgs"]; const JSONNode &jnFUsers = jnResponse["fwd_users"]; + const JSONNode &jnGUsers = jnResponse["groups"]; if (jnMsgs) { const JSONNode &jnItems = jnMsgs["items"]; if (jnItems) { @@ -309,7 +311,7 @@ void CVkProto::OnReceiveChatInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe if (!jnMsg) break; - AppendChatMessage(cc->m_iChatId, jnMsg, jnFUsers, true); + AppendChatConversationMessage(cc->m_iChatId, jnMsg, jnFUsers, true); } cc->m_bHistoryRead = true; } @@ -319,6 +321,125 @@ void CVkProto::OnReceiveChatInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe AppendChatMessage(cc, p->m_uid, p->m_date, p->m_wszBody, p->m_bHistory, p->m_bIsAction); cc->m_msgs.destroy(); +#else + const JSONNode& jnInfo = jnResponse["info"]; + if (jnInfo) { + if (jnInfo["title"]) + SetChatTitle(cc, jnInfo["title"].as_mstring()); + + if (jnInfo["left"].as_bool() || jnInfo["kicked"].as_bool()) { + setByte(cc->m_hContact, "kicked", jnInfo["kicked"].as_bool()); + LeaveChat(cc->m_iChatId); + return; + } + cc->m_iAdminId = jnInfo["admin_id"].as_int(); + } + + const JSONNode& jnUsers = jnResponse["users"]; + if (jnUsers) { + for (auto& it : cc->m_users) + it->m_bDel = true; + + for (auto& jnUser : jnUsers) { + if (!jnUser) + break; + + LONG uid = jnUser["id"].as_int(); + bool bIsGroup = jnUser["type"].as_mstring() == L"group"; + if (bIsGroup) + uid *= -1; + + wchar_t wszId[20]; + _itow(uid, wszId, 10); + + bool bNew; + CVkChatUser* cu = cc->m_users.find((CVkChatUser*)&uid); + if (cu == nullptr) { + cc->m_users.insert(cu = new CVkChatUser(uid)); + bNew = true; + } + else + bNew = cu->m_bUnknown; + cu->m_bDel = false; + + CMStringW wszNick(ptrW(db_get_wsa(cc->m_hContact, m_szModuleName, CMStringA(FORMAT, "nick%d", cu->m_uid)))); + if (wszNick.IsEmpty()) + wszNick = bIsGroup ? + jnUser["name"].as_mstring() : + jnUser["first_name"].as_mstring().Trim() + L" " + jnUser["last_name"].as_mstring().Trim(); + + + cu->m_wszNick = mir_wstrdup(wszNick); + cu->m_bUnknown = false; + + if (bNew) { + GCEVENT gce = { m_szModuleName, 0, GC_EVENT_JOIN }; + gce.pszID.w = cc->m_wszId; + gce.bIsMe = uid == m_myUserId; + gce.pszUID.w = wszId; + gce.pszNick.w = wszNick; + gce.pszStatus.w = TranslateW(sttStatuses[uid == cc->m_iAdminId]); + gce.dwItemData = (INT_PTR)cu; + Chat_Event(&gce); + } + } + + for (auto& cu : cc->m_users.rev_iter()) { + if (!cu->m_bDel) + continue; + + wchar_t wszId[20]; + _itow(cu->m_uid, wszId, 10); + CMStringW wszNick(FORMAT, L"%s (%s)", cu->m_wszNick.get(), UserProfileUrl(cu->m_uid).c_str()); + + GCEVENT gce = { m_szModuleName, 0, GC_EVENT_PART }; + gce.pszID.w = cc->m_wszId; + gce.pszUID.w = wszId; + gce.dwFlags = GCEF_NOTNOTIFY; + gce.time = time(0); + gce.pszNick.w = wszNick; + Chat_Event(&gce); + + cc->m_users.removeItem(&cu); + } + } + + const JSONNode& jnMsgsUsers = jnResponse["msgs_users"]; + for (auto& jnUser : jnMsgsUsers) { + LONG uid = jnUser["id"].as_int(); + CVkChatUser* cu = cc->m_users.find((CVkChatUser*)&uid); + if (cu) + continue; + + MCONTACT hContact = FindUser(uid); + if (hContact) + continue; + + hContact = SetContactInfo(jnUser, true, VKContactType::vkContactMUCUser); + + } + + const JSONNode& jnMsgs = jnResponse["msgs"]; + const JSONNode& jnFUsers = jnResponse["fwd_users"]; + if (jnMsgs) { + const JSONNode& jnItems = jnMsgs["items"]; + if (jnItems) { + for (auto& jnMsg : jnItems) { + if (!jnMsg) + break; + + AppendChatMessage(cc->m_iChatId, jnMsg, jnFUsers, true); + } + cc->m_bHistoryRead = true; + } + } + + for (auto& p : cc->m_msgs) + AppendChatMessage(cc, p->m_uid, p->m_date, p->m_wszBody, p->m_bHistory, p->m_bIsAction); + + cc->m_msgs.destroy(); +#endif + } void CVkProto::SetChatTitle(CVkChatInfo *cc, LPCWSTR wszTopic) @@ -338,6 +459,141 @@ void CVkProto::SetChatTitle(CVkChatInfo *cc, LPCWSTR wszTopic) ///////////////////////////////////////////////////////////////////////////////////////// +void CVkProto::AppendChatConversationMessage(int id, const JSONNode& jnMsg, const JSONNode& jnFUsers, bool bIsHistory) +{ + debugLogA("CVkProto::AppendChatMessage"); + CVkChatInfo* cc = AppendConversationChat(id, nullNode); + if (cc == nullptr) + return; + + int mid = jnMsg["id"].as_int(); + int uid = jnMsg["from_id"].as_int(); + bool bIsAction = false; + + int msgTime = jnMsg["date"].as_int(); + time_t now = time(0); + if (!msgTime || msgTime > now) + msgTime = now; + + CMStringW wszBody(jnMsg["text"].as_mstring()); + + const JSONNode& jnFwdMessages = jnMsg["fwd_messages"]; + if (jnFwdMessages && !jnFwdMessages.empty()) { + CMStringW wszFwdMessages = GetFwdMessages(jnFwdMessages, jnFUsers, bbcNo); + if (!wszBody.IsEmpty()) + wszFwdMessages = L"\n" + wszFwdMessages; + wszBody += wszFwdMessages; + } + + const JSONNode& jnAttachments = jnMsg["attachments"]; + if (jnAttachments && !jnAttachments.empty()) { + CMStringW wszAttachmentDescr = GetAttachmentDescr(jnAttachments, bbcNo); + + if (wszAttachmentDescr == L"== FilterAudioMessages ==") + return; + + if (!wszBody.IsEmpty()) + wszAttachmentDescr = L"\n" + wszAttachmentDescr; + wszBody += wszAttachmentDescr; + } + + if (m_vkOptions.bAddMessageLinkToMesWAtt && ((jnAttachments && !jnAttachments.empty())||(jnFwdMessages && !jnFwdMessages.empty()))) + wszBody += SetBBCString(TranslateT("Message link"), bbcNo, vkbbcUrl, + CMStringW(FORMAT, L"https://vk.com/im?sel=c%d&msgid=%d", cc->m_iChatId, mid)); + + if (jnMsg["action"] && jnMsg["action"]["type"]) { + bIsAction = true; + CMStringW wszAction = jnMsg["action"]["type"].as_mstring(); + + if (wszAction == L"chat_create") { + CMStringW wszActionText = jnMsg["action"]["text"].as_mstring(); + wszBody.AppendFormat(L"%s \"%s\"", TranslateT("create chat"), wszActionText.IsEmpty() ? L" " : wszActionText.c_str()); + } + else if (wszAction == L"chat_kick_user") { + CMStringW wszActionMid = jnMsg["action"]["member_id"].as_mstring(); + if (wszActionMid.IsEmpty()) + wszBody = TranslateT("kick user"); + else { + CMStringW wszUid(FORMAT, L"%d", uid); + if (wszUid == wszActionMid) { + if (cc->m_bHistoryRead) + return; + wszBody.AppendFormat(L" (%s) %s", UserProfileUrl(uid).c_str(), TranslateT("left chat")); + } + else { + int a_uid = 0; + int iReadCount = swscanf(wszActionMid, L"%d", &a_uid); + if (iReadCount == 1) { + CVkChatUser* cu = cc->m_users.find((CVkChatUser*)&a_uid); + if (cu == nullptr) + wszBody.AppendFormat(L"%s (%s)", TranslateT("kick user"), UserProfileUrl(a_uid).c_str()); + else + wszBody.AppendFormat(L"%s %s (%s)", TranslateT("kick user"), cu->m_wszNick.get(), UserProfileUrl(a_uid).c_str()); + } + else wszBody = TranslateT("kick user"); + } + } + } + else if (wszAction == L"chat_invite_user" || wszAction == L"chat_invite_user_by_link") { + CMStringW wszActionMid = jnMsg["action"]["member_id"].as_mstring(); + if (wszActionMid.IsEmpty()) + wszBody = TranslateT("invite user"); + else { + CMStringW wszUid(FORMAT, L"%d", uid); + if (wszUid == wszActionMid) + wszBody.AppendFormat(L" (%s) %s", UserProfileUrl(uid).c_str(), TranslateT("returned to chat")); + else { + int a_uid = 0; + int iReadCount = swscanf(wszActionMid, L"%d", &a_uid); + if (iReadCount == 1) { + CVkChatUser* cu = cc->m_users.find((CVkChatUser*)&a_uid); + if (cu == nullptr) + wszBody.AppendFormat(L"%s (%s)", TranslateT("invite user"), UserProfileUrl(a_uid).c_str()); + else + wszBody.AppendFormat(L"%s %s (%s)", TranslateT("invite user"), cu->m_wszNick.get(), UserProfileUrl(a_uid).c_str()); + } + else wszBody = TranslateT("invite user"); + } + } + } + else if (wszAction == L"chat_title_update") { + CMStringW wszTitle = jnMsg["action"]["text"].as_mstring(); + wszBody.AppendFormat(L"%s \"%s\"", TranslateT("change chat title to"), wszTitle.IsEmpty() ? L" " : wszTitle.c_str()); + + if (!bIsHistory) + SetChatTitle(cc, wszTitle); + } + else if (wszAction == L"chat_pin_message") + wszBody = TranslateT("pin message"); + else if (wszAction == L"chat_unpin_message") + wszBody = TranslateT("unpin message"); + else if (wszAction == L"chat_photo_update") + wszBody.Replace(TranslateT("Attachments:"), TranslateT("changed chat cover:")); + else if (wszAction == L"chat_photo_remove") + wszBody = TranslateT("deleted chat cover"); + else + wszBody.AppendFormat(L": %s (%s)", TranslateT("chat action not supported"), wszAction.c_str()); + } + + wszBody.Replace(L"%", L"%%"); + + if (cc->m_bHistoryRead) { + AppendChatMessage(cc, uid, msgTime, wszBody, bIsHistory, bIsAction); + } + else { + CVkChatMessage* cm = cc->m_msgs.find((CVkChatMessage*)&mid); + if (cm == nullptr) + cc->m_msgs.insert(cm = new CVkChatMessage(mid)); + + cm->m_uid = uid; + cm->m_date = msgTime; + cm->m_wszBody = mir_wstrdup(wszBody); + cm->m_bHistory = bIsHistory; + cm->m_bIsAction = bIsAction; + } +} + + void CVkProto::AppendChatMessage(int id, const JSONNode &jnMsg, const JSONNode &jnFUsers, bool bIsHistory) { debugLogA("CVkProto::AppendChatMessage"); diff --git a/protocols/VKontakte/src/vk_history.cpp b/protocols/VKontakte/src/vk_history.cpp index 7695e33859..0fdf83b477 100644 --- a/protocols/VKontakte/src/vk_history.cpp +++ b/protocols/VKontakte/src/vk_history.cpp @@ -248,14 +248,20 @@ void CVkProto::OnReceiveHistoryMessages(NETLIBHTTPREQUEST *reply, AsyncHttpReque #if (VK_NEW_API == 1) CMStringW wszBody(jnMsg["text"].as_mstring()); int uid = jnMsg["peer_id"].as_int(); + + int iReadMsg = getDword(param->hContact, "in_read", 0); + int isRead = (uid <= iReadMsg); + + #else CMStringW wszBody(jnMsg["body"].as_mstring()); int uid = jnMsg["user_id"].as_int(); + int isRead = jnMsg["read_state"].as_int(); #endif int datetime = jnMsg["date"].as_int(); int isOut = jnMsg["out"].as_int(); - int isRead = jnMsg["read_state"].as_int(); + const JSONNode &jnFwdMessages = jnMsg["fwd_messages"]; if (jnFwdMessages && !jnFwdMessages.empty()) { @@ -279,7 +285,7 @@ void CVkProto::OnReceiveHistoryMessages(NETLIBHTTPREQUEST *reply, AsyncHttpReque wszBody += wszAttachmentDescr; } - if (m_vkOptions.bAddMessageLinkToMesWAtt && (jnAttachments || jnFwdMessages)) + if (m_vkOptions.bAddMessageLinkToMesWAtt && ((jnAttachments && !jnAttachments.empty()) || (jnFwdMessages && !jnFwdMessages.empty()))) wszBody += SetBBCString(TranslateT("Message link"), m_vkOptions.BBCForAttachments(), vkbbcUrl, CMStringW(FORMAT, L"https://vk.com/im?sel=%d&msgid=%d", uid, mid)); diff --git a/protocols/VKontakte/src/vk_messages.cpp b/protocols/VKontakte/src/vk_messages.cpp index bb020a3594..167be76ee7 100644 --- a/protocols/VKontakte/src/vk_messages.cpp +++ b/protocols/VKontakte/src/vk_messages.cpp @@ -187,10 +187,15 @@ void CVkProto::RetrieveMessagesByIds(const CMStringA &mids) debugLogA("CVkProto::RetrieveMessagesByIds"); if (!IsOnline() || mids.IsEmpty()) return; - +#if (VK_NEW_API == 1) + Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/execute.RetrieveMessagesConversationByIds", true, &CVkProto::OnReceiveMessages, AsyncHttpRequest::rpHigh) + << CHAR_PARAM("mids", mids) + ); +#else Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/execute.RetrieveMessagesByIds", true, &CVkProto::OnReceiveMessages, AsyncHttpRequest::rpHigh) << CHAR_PARAM("mids", mids) ); +#endif } void CVkProto::RetrieveUnreadMessages() @@ -226,12 +231,153 @@ void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe debugLogA("CVkProto::OnReceiveMessages numMessages = %d", numMessages); +#if (VK_NEW_API == 1) + for (auto& jnMsg : jnMsgs) { + if (!jnMsg) { + debugLogA("CVkProto::OnReceiveMessages pMsg == nullptr"); + break; + } + + + UINT mid = jnMsg["id"].as_int(); + CMStringW wszBody(jnMsg["text"].as_mstring()); + UINT datetime = jnMsg["date"].as_int(); + int isOut = jnMsg["out"].as_int(); + int isRead = jnMsg["read_state"].as_int(); + int uid = jnMsg["peer_id"].as_int(); + + MCONTACT hContact = 0; + + int chat_id = uid / VK_CHAT_FLAG ? uid % VK_CHAT_FLAG : 0; + if (chat_id == 0) + hContact = FindUser(uid, true); + + char szMid[40]; + _itoa(mid, szMid, 10); + if (m_vkOptions.iMarkMessageReadOn == MarkMsgReadOn::markOnReceive || chat_id != 0) { + if (!mids.IsEmpty()) + mids.AppendChar(','); + mids.Append(szMid); + } + + bool bUseServerReadFlag = m_vkOptions.bSyncReadMessageStatusFromServer ? true : !m_vkOptions.bMesAsUnread; + + if (chat_id != 0) { + debugLogA("CVkProto::OnReceiveMessages chat_id != 0"); + CMStringW action_chat = jnMsg["action"]["type"].as_mstring(); + int action_mid = _wtoi(jnMsg["action"]["member_id"].as_mstring()); + if ((action_chat == L"chat_kick_user") && (action_mid == m_myUserId)) + KickFromChat(chat_id, uid, jnMsg, jnFUsers); + else { + MCONTACT chatContact = FindChat(chat_id); + if (chatContact && getBool(chatContact, "kicked", true)) + db_unset(chatContact, m_szModuleName, "kicked"); + AppendChatConversationMessage(chat_id, jnMsg, jnFUsers, false); + } + continue; + } + + const JSONNode& jnFwdMessages = jnMsg["fwd_messages"]; + if (jnFwdMessages && !jnFwdMessages.empty()) { + CMStringW wszFwdMessages = GetFwdMessages(jnFwdMessages, jnFUsers, m_vkOptions.BBCForAttachments()); + if (!wszBody.IsEmpty()) + wszFwdMessages = L"\n" + wszFwdMessages; + wszBody += wszFwdMessages; + } + + CMStringW wszBodyNoAttachments = wszBody; + + + CMStringW wszAttachmentDescr; + const JSONNode& jnAttachments = jnMsg["attachments"]; + if (jnAttachments && !jnAttachments.empty()) { + wszAttachmentDescr = GetAttachmentDescr(jnAttachments, m_vkOptions.BBCForAttachments()); + + if (wszAttachmentDescr == L"== FilterAudioMessages ==") { + if (hContact && (mid > getDword(hContact, "lastmsgid", -1))) + setDword(hContact, "lastmsgid", mid); + continue; + } + + if (!wszBody.IsEmpty()) + wszBody += L"\n"; + wszBody += wszAttachmentDescr; + } + + if (m_vkOptions.bAddMessageLinkToMesWAtt && ((jnAttachments && !jnAttachments.empty()) || (jnFwdMessages && !jnFwdMessages.empty()))) + wszBody += SetBBCString(TranslateT("Message link"), m_vkOptions.BBCForAttachments(), vkbbcUrl, + CMStringW(FORMAT, L"https://vk.com/im?sel=%d&msgid=%d", uid, mid)); + + time_t update_time = (time_t)jnMsg["update_time"].as_int(); + bool bEdited = (update_time != 0); + + if (bEdited) { + wchar_t ttime[64]; + _locale_t locale = _create_locale(LC_ALL, ""); + _wcsftime_l(ttime, _countof(ttime), TranslateT("%x at %X"), localtime(&update_time), locale); + _free_locale(locale); + + wszBody = SetBBCString( + CMStringW(FORMAT, TranslateT("Edited message (updated %s):\n"), ttime), + m_vkOptions.BBCForAttachments(), vkbbcB) + + wszBody; + + CMStringW wszOldMsg; + if (GetMessageFromDb(mid, datetime, wszOldMsg)) + wszBody += SetBBCString(TranslateT("\nOriginal message:\n"), m_vkOptions.BBCForAttachments(), vkbbcB) + + wszOldMsg; + } + + PROTORECVEVENT recv = {}; + + if (isRead && bUseServerReadFlag) + recv.flags |= PREF_CREATEREAD; + + if (isOut) + recv.flags |= PREF_SENT; + else if (m_vkOptions.bUserForceInvisibleOnActivity && time(0) - datetime < 60 * m_vkOptions.iInvisibleInterval) + SetInvisible(hContact); + + T2Utf pszBody(wszBody); + recv.timestamp = bEdited ? datetime : (m_vkOptions.bUseLocalTime ? time(0) : datetime); + recv.szMessage = pszBody; + + debugLogA("CVkProto::OnReceiveMessages mid = %d, datetime = %d, isOut = %d, isRead = %d, uid = %d, Edited = %d", mid, datetime, isOut, isRead, uid, (int)bEdited); + + if (!IsMessageExist(mid, vkALL) || bEdited) { + debugLogA("CVkProto::OnReceiveMessages new or edited message"); + recv.szMsgId = szMid; + ProtoChainRecvMsg(hContact, &recv); + if (mid > getDword(hContact, "lastmsgid", -1)) + setDword(hContact, "lastmsgid", mid); + } + else if (m_vkOptions.bLoadSentAttachments && !wszAttachmentDescr.IsEmpty()) { + CMStringW wszOldMsg; + + if (GetMessageFromDb(mid, datetime, wszOldMsg) && (wszOldMsg == wszBody)) + continue; + + if (wszBodyNoAttachments != wszOldMsg) + continue; + + debugLogA("CVkProto::OnReceiveMessages add attachments"); + + T2Utf pszAttach(wszAttachmentDescr); + recv.timestamp = isOut ? time(0) : datetime; + recv.szMessage = pszAttach; + recv.szMsgId = strcat(szMid, "_"); + ProtoChainRecvMsg(hContact, &recv); + } + } + +#else for (auto &jnMsg : jnMsgs) { if (!jnMsg) { debugLogA("CVkProto::OnReceiveMessages pMsg == nullptr"); break; } + UINT mid = jnMsg["id"].as_int(); CMStringW wszBody(jnMsg["body"].as_mstring()); UINT datetime = jnMsg["date"].as_int(); @@ -361,6 +507,7 @@ void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe ProtoChainRecvMsg(hContact, &recv); } } +#endif if (!mids.IsEmpty()) MarkMessagesRead(mids); @@ -450,6 +597,9 @@ void CVkProto::OnReceiveDlgs(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) if (IsGroupUser(hContact)) szGroupIds.AppendFormat(szGroupIds.IsEmpty() ? "%d" : ",%d", -1 * iUserId); + setDword(hContact, "in_read", jnConversation["in_read"].as_int()); + setDword(hContact, "out_read", jnConversation["out_read"].as_int()); + /* if (g_bMessageState) { bool bIsOut = jnLastMessage["out"].as_bool(); diff --git a/protocols/VKontakte/src/vk_pollserver.cpp b/protocols/VKontakte/src/vk_pollserver.cpp index aaee82e5fa..81ec8fc83b 100644 --- a/protocols/VKontakte/src/vk_pollserver.cpp +++ b/protocols/VKontakte/src/vk_pollserver.cpp @@ -58,7 +58,7 @@ void CVkProto::OnReceivePollingInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest * m_pollingTs ? m_pollingTs.get() : "", m_pollingKey ? m_pollingKey.get() : "", m_pollingServer ? m_pollingServer.get() : ""); - + if (m_pollingTs != nullptr && m_pollingKey != nullptr && m_pollingServer != nullptr) { debugLogA("CVkProto::OnReceivePollingInfo PollingThread starting..."); m_hPollingThread = ForkThreadEx(&CVkProto::PollingThread, nullptr, nullptr); diff --git a/protocols/VKontakte/src/vk_proto.h b/protocols/VKontakte/src/vk_proto.h index 11602452ca..ca60dfdf5d 100644 --- a/protocols/VKontakte/src/vk_proto.h +++ b/protocols/VKontakte/src/vk_proto.h @@ -391,6 +391,7 @@ private: CVkChatInfo* AppendConversationChat(int iChatId, const JSONNode& jnItem); CVkChatInfo* AppendChat(int id, const JSONNode &jnNode); void SetChatTitle(CVkChatInfo *cc, LPCWSTR wszTopic); + void AppendChatConversationMessage(int id, const JSONNode& jnMsg, const JSONNode& jnFUsers, bool bIsHistory); void AppendChatMessage(int id, const JSONNode &jnMsg, const JSONNode &jnFUsers, bool bIsHistory); void AppendChatMessage(CVkChatInfo *cc, LONG uid, int msgTime, LPCWSTR pwszBody, bool bIsHistory, bool bIsAction = false); void RetrieveChatInfo(CVkChatInfo*); diff --git a/protocols/VKontakte/src/vkjs.js b/protocols/VKontakte/src/vkjs.js index 8741b09024..603fd7f692 100644 --- a/protocols/VKontakte/src/vkjs.js +++ b/protocols/VKontakte/src/vkjs.js @@ -169,6 +169,27 @@ var FUsers = API.users.get({ "user_ids": Uids, "name_case": "gen" }); return { "Msgs": Msgs, "fwd_users": FUsers }; // Stored procedure name: RetrieveMessagesByIds = End +// Stored procedure name: RetrieveMessagesConversationByIds = Begin +// Arguments: +// Args.mids + +var Msgs = API.messages.getById({ "message_ids": Args.mids }); +var FMsgs = Msgs.items@.fwd_messages; +var Idx = 0; +var Uids = []; +while (Idx < FMsgs.length) { + var Jdx = 0; + var CFMsgs = parseInt(FMsgs[Idx].length); + while (Jdx < CFMsgs) { + Uids.unshift(FMsgs[Idx][Jdx].from_id); + Jdx = Jdx + 1; + }; + Idx = Idx + 1; +}; +var FUsers = API.users.get({ "user_ids": Uids, "name_case": "gen" }); +return { "Msgs": Msgs, "fwd_users": FUsers }; +// Stored procedure name: RetrieveMessagesConversationByIds = End + // Stored procedure name: RetrieveUnreadMessages = Begin // Arguments: no @@ -310,6 +331,40 @@ var FUsers = API.users.get({ "user_ids": Uids, "name_case": "gen" }); var MsgUsers = API.users.get({ "user_ids": ChatMsg.items@.user_id, "fields":"id,first_name,last_name"}); return { "info": Info, "users": ChatUsers, "msgs": ChatMsg, "fwd_users": FUsers, "msgs_users": MsgUsers }; + + +// ver 3 +var Info = API.messages.getChat({ "chat_id": Args.chatid }); +var ChatUsers = API.messages.getConversationMembers({ "peer_id": 2000000000 + parseInt(Args.chatid), "fields": "id,first_name,last_name" }); +var ChatMsg = API.messages.getHistory({ "chat_id": Args.chatid, "count": 20, "rev": 0 }); +var UR = parseInt(ChatMsg.unread); +if (UR > 20) { + if (UR > 200) + UR = 200; + ChatMsg = API.messages.getHistory({ "chat_id": Args.chatid, "count": UR, "rev": 0 }); +}; +var FMsgs = ChatMsg.items@.fwd_messages; +var Idx = 0; +var Uids = []; +var GUids =[]; +while (Idx < FMsgs.length) { + var Jdx = 0; + var CFMsgs = parseInt(FMsgs[Idx].length); + while (Jdx < CFMsgs) { + if (FMsgs[Idx][Jdx].from_id>0) { + Uids.unshift(FMsgs[Idx][Jdx].from_id); + } else { + GUids.unshift(-1*FMsgs[Idx][Jdx].from_id); + }; + Jdx = Jdx + 1; + }; + Idx = Idx + 1; +}; +var FUsers = API.users.get({ "user_ids": Uids, "name_case": "gen" }); +var GUsers = API.groups.getById({ "group_ids": GUids }); +var MsgUsers = API.users.get({ "user_ids": ChatMsg.items@.from_id, "fields":"id,first_name,last_name"}); + +return { "info": Info, "users": ChatUsers, "msgs": ChatMsg, "fwd_users": FUsers + GUsers, "msgs_users": MsgUsers}; // Stored procedure name: RetrieveChatInfo = End // Stored procedure name: DestroyKickChat = Begin -- cgit v1.2.3