From adb5cfe67a86c7340e337124c0b03d53c0d24fbb Mon Sep 17 00:00:00 2001 From: Sergey Bolhovskoy Date: Fri, 27 Feb 2015 08:21:24 +0000 Subject: VKontakte: code reorganisation git-svn-id: http://svn.miranda-ng.org/main/trunk@12277 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/VKontakte/src/vk_messages.cpp | 346 +++++++++++++++++++++++ protocols/VKontakte/src/vk_pollserver.cpp | 239 ++++++++++++++++ protocols/VKontakte/src/vk_proto.cpp | 107 ------- protocols/VKontakte/src/vk_thread.cpp | 444 ------------------------------ protocols/VKontakte/vk_10.vcxproj | 2 + protocols/VKontakte/vk_10.vcxproj.filters | 6 + protocols/VKontakte/vk_12.vcxproj | 2 + protocols/VKontakte/vk_12.vcxproj.filters | 6 + 8 files changed, 601 insertions(+), 551 deletions(-) create mode 100644 protocols/VKontakte/src/vk_messages.cpp create mode 100644 protocols/VKontakte/src/vk_pollserver.cpp (limited to 'protocols') diff --git a/protocols/VKontakte/src/vk_messages.cpp b/protocols/VKontakte/src/vk_messages.cpp new file mode 100644 index 0000000000..b54c28fd73 --- /dev/null +++ b/protocols/VKontakte/src/vk_messages.cpp @@ -0,0 +1,346 @@ +/* +Copyright (c) 2013-15 Miranda NG project (http://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdafx.h" + +////////////////////////////////////////////////////////////////////////////// + +int CVkProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT *pre) +{ + debugLogA("CVkProto::RecvMsg"); + Proto_RecvMessage(hContact, pre); + return 0; +} + +////////////////////////////////////////////////////////////////////////////// + +void CVkProto::SendMsgAck(void *param) +{ + debugLogA("CVkProto::SendMsgAck"); + TFakeAckParams *ack = (TFakeAckParams*)param; + Sleep(100); + ProtoBroadcastAck(ack->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)ack->msgid, 0); + delete ack; +} + +int CVkProto::SendMsg(MCONTACT hContact, int flags, const char *msg) +{ + debugLogA("CVkProto::SendMsg"); + if (!IsOnline()) + return 0; + LONG userID = getDword(hContact, "ID", -1); + if (userID == -1 || userID == VK_FEED_USER) { + ForkThread(&CVkProto::SendMsgAck, new TFakeAckParams(hContact, 0)); + return 0; + } + + ptrA szMsg; + if (flags & PREF_UTF) + szMsg = mir_strdup(msg); + else if (flags & PREF_UNICODE) + szMsg = mir_utf8encodeW((wchar_t*)&msg[mir_strlen(msg) + 1]); + else + szMsg = mir_utf8encode(msg); + + int StickerId = 0; + ptrA retMsg(GetStickerId(szMsg, StickerId)); + + ULONG msgId = ::InterlockedIncrement(&m_msgId); + AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, &CVkProto::OnSendMessage) + << INT_PARAM("user_id", userID) + << VER_API; + + if (StickerId != 0) + pReq << INT_PARAM("sticker_id", StickerId); + else + pReq << CHAR_PARAM("message", szMsg); + + pReq->AddHeader("Content-Type", "application/x-www-form-urlencoded"); + pReq->pUserInfo = new CVkSendMsgParam(hContact, msgId); + Push(pReq); + + if (!m_bServerDelivery) + ForkThread(&CVkProto::SendMsgAck, new TFakeAckParams(hContact, msgId)); + + if (retMsg) { + int _flags = flags | PREF_UTF; + Sleep(330); + SendMsg(hContact, _flags, retMsg); + } + return msgId; +} + +void CVkProto::OnSendMessage(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) +{ + int iResult = ACKRESULT_FAILED; + if (pReq->pUserInfo == NULL) { + debugLogA("CVkProto::OnSendMessage failed! (pUserInfo == NULL)"); + return; + } + CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo; + + debugLogA("CVkProto::OnSendMessage %d", reply->resultCode); + if (reply->resultCode == 200) { + JSONROOT pRoot; + JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); + if (pResponse != NULL) { + UINT mid = json_as_int(pResponse); + if (param->iMsgID != -1) + m_sendIds.insert((HANDLE)mid); + if (mid > getDword(param->hContact, "lastmsgid", 0)) + setDword(param->hContact, "lastmsgid", mid); + if (m_iMarkMessageReadOn >= markOnReply) + MarkMessagesRead(param->hContact); + iResult = ACKRESULT_SUCCESS; + } + } + + if (param->iMsgID == -1) { + CVkFileUploadParam *fup = (CVkFileUploadParam *)param->iCount; + ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, iResult, (HANDLE)fup, 0); + if (!pReq->bNeedsRestart) + delete fup; + return; + } + else if (m_bServerDelivery) + ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, iResult, HANDLE(param->iMsgID), 0); + if (!pReq->bNeedsRestart) { + delete param; + pReq->pUserInfo = NULL; + } +} + +///////////////////////////////////////////////////////////////////////////////////////// + +int CVkProto::OnDbEventRead(WPARAM hContact, LPARAM) +{ + debugLogA("CVkProto::OnDbEventRead"); + if (m_iMarkMessageReadOn == markOnRead) + MarkMessagesRead(hContact); + return 0; +} + +void CVkProto::MarkMessagesRead(const CMStringA &mids) +{ + debugLogA("CVkProto::MarkMessagesRead (mids)"); + if (!IsOnline()) + return; + if (mids.IsEmpty()) + return; + + Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.markAsRead.json", true, &CVkProto::OnReceiveSmth) + << CHAR_PARAM("message_ids", mids) + << VER_API); +} + +void CVkProto::MarkMessagesRead(const MCONTACT hContact) +{ + debugLogA("CVkProto::MarkMessagesRead (hContact)"); + if (!IsOnline()) + return; + LONG userID = getDword(hContact, "ID", -1); + if (userID == -1 || userID == VK_FEED_USER) + return; + + Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.markAsRead.json", true, &CVkProto::OnReceiveSmth) + << INT_PARAM("peer_id", userID) + << VER_API); +} + +void CVkProto::RetrieveMessagesByIds(const CMStringA &mids) +{ + debugLogA("CVkProto::RetrieveMessagesByIds"); + if (!IsOnline()) + return; + if (mids.IsEmpty()) + return; + + Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.getById.json", true, &CVkProto::OnReceiveMessages) + << CHAR_PARAM("message_ids", mids) + << VER_API); +} + +void CVkProto::RetrieveUnreadMessages() +{ + debugLogA("CVkProto::RetrieveUnreadMessages"); + if (!IsOnline()) + return; + Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.getDialogs.json", true, &CVkProto::OnReceiveDlgs) + << VER_API); +} + +void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) +{ + debugLogA("CVkProto::OnReceiveMessages %d", reply->resultCode); + if (reply->resultCode != 200) + return; + + JSONROOT pRoot; + JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); + if (pResponse == NULL) + return; + + CMStringA mids; + int numMessages = json_as_int(json_get(pResponse, "count")); + JSONNODE *pMsgs = json_get(pResponse, "items"); + + debugLogA("CVkProto::OnReceiveMessages numMessages = %d", numMessages); + + for (int i = 0; i < numMessages; i++) { + JSONNODE *pMsg = json_at(pMsgs, i); + if (pMsg == NULL) { + debugLogA("CVkProto::OnReceiveMessages pMsg == NULL"); + break; + } + + UINT mid = json_as_int(json_get(pMsg, "id")); + ptrT ptszBody(json_as_string(json_get(pMsg, "body"))); + int datetime = json_as_int(json_get(pMsg, "date")); + int isOut = json_as_int(json_get(pMsg, "out")); + int isRead = json_as_int(json_get(pMsg, "read_state")); + int uid = json_as_int(json_get(pMsg, "user_id")); + + JSONNODE *pFwdMessages = json_get(pMsg, "fwd_messages"); + if (pFwdMessages != NULL){ + CMString tszFwdMessages = GetFwdMessages(pFwdMessages, m_iBBCForAttachments); + if (!IsEmpty(ptszBody)) + tszFwdMessages = _T("\n") + tszFwdMessages; + ptszBody = mir_tstrdup(CMString(ptszBody) + tszFwdMessages); + } + + JSONNODE *pAttachments = json_get(pMsg, "attachments"); + if (pAttachments != NULL){ + CMString tszAttachmentDescr = GetAttachmentDescr(pAttachments, m_iBBCForAttachments); + if (!IsEmpty(ptszBody)) + tszAttachmentDescr = _T("\n") + tszAttachmentDescr; + ptszBody = mir_tstrdup(CMString(ptszBody) + tszAttachmentDescr); + } + + MCONTACT hContact = NULL; + int chat_id = json_as_int(json_get(pMsg, "chat_id")); + if (chat_id == 0) + hContact = FindUser(uid, true); + + char szMid[40]; + _itoa(mid, szMid, 10); + if (m_iMarkMessageReadOn == markOnReceive || chat_id != 0) { + if (!mids.IsEmpty()) + mids.AppendChar(','); + mids.Append(szMid); + } + + if (chat_id != 0) { + debugLogA("CVkProto::OnReceiveMessages chat_id != 0"); + CMString action_chat = json_as_CMString(json_get(pMsg, "action")); + int action_mid = _ttoi(json_as_CMString(json_get(pMsg, "action_mid"))); + if ((action_chat == "chat_kick_user") && (action_mid == m_myUserId)) + KickFromChat(chat_id, uid, pMsg); + else + AppendChatMessage(chat_id, pMsg, false); + continue; + } + + PROTORECVEVENT recv = { 0 }; + recv.flags = PREF_TCHAR; + if (isRead && !m_bMesAsUnread) + recv.flags |= PREF_CREATEREAD; + if (isOut) + recv.flags |= PREF_SENT; + else if (m_bUserForceOnlineOnActivity) + SetInvisible(hContact); + + recv.timestamp = m_bUseLocalTime ? time(NULL) : datetime; + recv.tszMessage = ptszBody; + recv.lParam = isOut; + recv.pCustomData = szMid; + recv.cbCustomDataSize = (int)mir_strlen(szMid); + Sleep(100); + + debugLogA("CVkProto::OnReceiveMessages i = %d, mid = %d, datetime = %d, isOut = %d, isRead = %d, uid = %d", i, mid, datetime, isOut, isRead, uid); + + if (!CheckMid(m_sendIds, mid)) { + debugLogA("CVkProto::OnReceiveMessages ProtoChainRecvMsg"); + ProtoChainRecvMsg(hContact, &recv); + if (mid > getDword(hContact, "lastmsgid", -1)) + setDword(hContact, "lastmsgid", mid); + if (!isOut) + m_incIds.insert((HANDLE)mid); + } + } + + if (!mids.IsEmpty()) + MarkMessagesRead(mids); +} + +void CVkProto::OnReceiveDlgs(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) +{ + debugLogA("CVkProto::OnReceiveDlgs %d", reply->resultCode); + if (reply->resultCode != 200) + return; + + JSONROOT pRoot; + JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); + if (pResponse == NULL) + return; + + int numDlgs = json_as_int(json_get(pResponse, "count")); + JSONNODE *pDlgs = json_get(pResponse, "items"); + + if (pDlgs == NULL) + return; + + for (int i = 0; i < numDlgs; i++) { + JSONNODE *pDlg = json_at(pDlgs, i); + if (pDlg == NULL) + break; + + int numUnread = json_as_int(json_get(pDlg, "unread")); + + pDlg = json_get(pDlg, "message"); + if (pDlg == NULL) + break; + + int chatid = json_as_int(json_get(pDlg, "chat_id")); + if (chatid != 0) { + debugLogA("CVkProto::OnReceiveDlgs chatid = %d", chatid); + if (m_chats.find((CVkChatInfo*)&chatid) == NULL) + AppendChat(chatid, pDlg); + } + else if (m_iSyncHistoryMetod) { + int mid = json_as_int(json_get(pDlg, "id")); + int uid = json_as_int(json_get(pDlg, "user_id")); + MCONTACT hContact = FindUser(uid, true); + + if (getDword(hContact, "lastmsgid", -1) == -1 && numUnread) + GetServerHistory(hContact, 0, numUnread, 0, 0, true); + else + GetHistoryDlg(hContact, mid); + + if (m_iMarkMessageReadOn == markOnReceive && numUnread) + MarkMessagesRead(hContact); + } + else if (numUnread) { + int uid = json_as_int(json_get(pDlg, "user_id")); + MCONTACT hContact = FindUser(uid, true); + GetServerHistory(hContact, 0, numUnread, 0, 0, true); + + if (m_iMarkMessageReadOn == markOnReceive) + MarkMessagesRead(hContact); + } + } + RetrieveUsersInfo(); +} diff --git a/protocols/VKontakte/src/vk_pollserver.cpp b/protocols/VKontakte/src/vk_pollserver.cpp new file mode 100644 index 0000000000..e4ea16302f --- /dev/null +++ b/protocols/VKontakte/src/vk_pollserver.cpp @@ -0,0 +1,239 @@ +/* +Copyright (c) 2013-15 Miranda NG project (http://miranda-ng.org) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation version 2 +of the License. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +#include "stdafx.h" + +void CVkProto::RetrievePollingInfo() +{ + debugLogA("CVkProto::RetrievePollingInfo"); + if (!IsOnline()) + return; + Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.getLongPollServer.json", true, &CVkProto::OnReceivePollingInfo) + << INT_PARAM("use_ssl", 1) + << VER_API); +} + +void CVkProto::OnReceivePollingInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) +{ + debugLogA("CVkProto::OnReceivePollingInfo %d", reply->resultCode); + if (reply->resultCode != 200) + return; + + JSONROOT pRoot; + JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); + if (pResponse == NULL) + return; + + m_pollingTs = mir_t2a(ptrT(json_as_string(json_get(pResponse, "ts")))); + m_pollingKey = mir_t2a(ptrT(json_as_string(json_get(pResponse, "key")))); + m_pollingServer = mir_t2a(ptrT(json_as_string(json_get(pResponse, "server")))); + if (!m_hPollingThread) { + debugLogA("CVkProto::OnReceivePollingInfo m_hPollingThread is NULL"); + debugLogA("CVkProto::OnReceivePollingInfo m_pollingTs = \'%s' m_pollingKey = \'%s\' m_pollingServer = \'%s\'", + m_pollingTs ? m_pollingTs : "", + m_pollingKey ? m_pollingKey : "", + m_pollingServer ? m_pollingServer : ""); + if (m_pollingTs != NULL && m_pollingKey != NULL && m_pollingServer != NULL) { + debugLogA("CVkProto::OnReceivePollingInfo PollingThread starting..."); + m_hPollingThread = ForkThreadEx(&CVkProto::PollingThread, NULL, NULL); + } + else { + debugLogA("CVkProto::OnReceivePollingInfo PollingThread not start"); + m_pollingConn = NULL; + ShutdownSession(); + return; + } + } + else + debugLogA("CVkProto::OnReceivePollingInfo m_hPollingThread is not NULL"); +} + +void CVkProto::PollUpdates(JSONNODE *pUpdates) +{ + debugLogA("CVkProto::PollUpdates"); + CMStringA mids; + int msgid, uid, flags, platform; + MCONTACT hContact; + + JSONNODE *pChild; + for (int i = 0; (pChild = json_at(pUpdates, i)) != NULL; i++) { + switch (json_as_int(json_at(pChild, 0))) { + case VKPOLL_MSG_DELFLAGS: + msgid = json_as_int(json_at(pChild, 1)); + flags = json_as_int(json_at(pChild, 2)); + uid = json_as_int(json_at(pChild, 3)); + hContact = FindUser(uid); + + if (hContact != NULL && (flags & VKFLAG_MSGUNREAD) && !CheckMid(m_incIds, msgid)) { + setDword(hContact, "LastMsgReadTime", time(NULL)); + SetSrmmReadStatus(hContact); + if (m_bUserForceOnlineOnActivity) + SetInvisible(hContact); + } + break; + + case VKPOLL_MSG_ADDED: // new message + msgid = json_as_int(json_at(pChild, 1)); + + // skip outgoing messages sent from a client + flags = json_as_int(json_at(pChild, 2)); + if (flags & VKFLAG_MSGOUTBOX && !(flags & VKFLAG_MSGCHAT)) + if (CheckMid(m_sendIds, msgid)) + break; + + if (!mids.IsEmpty()) + mids.AppendChar(','); + mids.AppendFormat("%d", msgid); + break; + + case VKPOLL_READ_ALL_OUT: + uid = json_as_int(json_at(pChild, 1)); + hContact = FindUser(uid); + if (hContact != NULL) { + setDword(hContact, "LastMsgReadTime", time(NULL)); + SetSrmmReadStatus(hContact); + if (m_bUserForceOnlineOnActivity) + SetInvisible(hContact); + } + break; + + case VKPOLL_USR_ONLINE: + uid = -json_as_int(json_at(pChild, 1)); + if ((hContact = FindUser(uid)) != NULL) { + setWord(hContact, "Status", ID_STATUS_ONLINE); + platform = json_as_int(json_at(pChild, 2)); + SetMirVer(hContact, platform); + } + break; + + case VKPOLL_USR_OFFLINE: + uid = -json_as_int(json_at(pChild, 1)); + if ((hContact = FindUser(uid)) != NULL) { + setWord(hContact, "Status", ID_STATUS_OFFLINE); + db_unset(hContact, m_szModuleName, "ListeningTo"); + SetMirVer(hContact, -1); + } + break; + + case VKPOLL_USR_UTN: + uid = json_as_int(json_at(pChild, 1)); + hContact = FindUser(uid); + if (hContact != NULL) { + ForkThread(&CVkProto::ContactTypingThread, (void *)hContact); + if (m_bUserForceOnlineOnActivity) + SetInvisible(hContact); + } + break; + + case VKPOLL_CHAT_CHANGED: + int chat_id = json_as_int(json_at(pChild, 1)); + CVkChatInfo *cc = m_chats.find((CVkChatInfo*)&chat_id); + if (cc) + RetrieveChatInfo(cc); + break; + } + } + + RetrieveMessagesByIds(mids); +} + +int CVkProto::PollServer() +{ + debugLogA("CVkProto::PollServer"); + if (!IsOnline()) { + debugLogA("CVkProto::PollServer is dead (not online)"); + m_pollingConn = NULL; + ShutdownSession(); + return 0; + } + + debugLogA("CVkProto::PollServer (online)"); + int iPollConnRetry = MAX_RETRIES; + NETLIBHTTPREQUEST *reply; + CMStringA szReqUrl; + szReqUrl.AppendFormat("https://%s?act=a_check&key=%s&ts=%s&wait=25&access_token=%s&mode=%d", m_pollingServer, m_pollingKey, m_pollingTs, m_szAccessToken, 106); + // see mode parametr description on https://vk.com/dev/using_longpoll (Russian version) + NETLIBHTTPREQUEST req = { sizeof(req) }; + req.requestType = REQUEST_GET; + req.szUrl = mir_strdup(szReqUrl.GetBuffer()); + req.flags = VK_NODUMPHEADERS | NLHRF_PERSISTENT | NLHRF_HTTP11; + req.timeout = 30000; + req.nlc = m_pollingConn; + + while ((reply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)&req)) == NULL) { + debugLogA("CVkProto::PollServer is dead"); + m_pollingConn = NULL; + if (iPollConnRetry && !m_bTerminated) { + iPollConnRetry--; + debugLogA("CVkProto::PollServer restarting %d", MAX_RETRIES - iPollConnRetry); + Sleep(1000); + } + else { + debugLogA("CVkProto::PollServer => ShutdownSession"); + mir_free(req.szUrl); + ShutdownSession(); + return 0; + } + } + + mir_free(req.szUrl); + + int retVal = 0; + if (reply->resultCode == 200) { + JSONROOT pRoot(reply->pData); + JSONNODE *pFailed = json_get(pRoot, "failed"); + if (pFailed != NULL && json_as_int(pFailed) == 2) { + RetrievePollingInfo(); + retVal = -1; + debugLogA("Polling key expired, restarting polling thread"); + } + else if (CheckJsonResult(NULL, pRoot)) { + m_pollingTs = mir_t2a(ptrT(json_as_string(json_get(pRoot, "ts")))); + JSONNODE *pUpdates = json_get(pRoot, "updates"); + if (pUpdates != NULL) + PollUpdates(pUpdates); + retVal = 1; + } + } + else if ((reply->resultCode >= 400 && reply->resultCode <= 417) + || (reply->resultCode >= 500 && reply->resultCode <= 509)) { + debugLogA("CVkProto::PollServer is dead. Error code - %d", reply->resultCode); + m_pollingConn = NULL; + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)reply); + ShutdownSession(); + return 0; + } + + m_pollingConn = reply->nlc; + + CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)reply); + debugLogA("CVkProto::PollServer return %d", retVal); + return retVal; +} + +void CVkProto::PollingThread(void*) +{ + debugLogA("CVkProto::PollingThread: entering"); + + while (!m_bTerminated) + if (PollServer() == -1) + break; + + m_hPollingThread = NULL; + m_pollingConn = NULL; + debugLogA("CVkProto::PollingThread: leaving"); +} \ No newline at end of file diff --git a/protocols/VKontakte/src/vk_proto.cpp b/protocols/VKontakte/src/vk_proto.cpp index a73b2e8267..a1b13558ad 100644 --- a/protocols/VKontakte/src/vk_proto.cpp +++ b/protocols/VKontakte/src/vk_proto.cpp @@ -453,113 +453,6 @@ DWORD_PTR CVkProto::GetCaps(int type, MCONTACT) ////////////////////////////////////////////////////////////////////////////// -int CVkProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT *pre) -{ - debugLogA("CVkProto::RecvMsg"); - Proto_RecvMessage(hContact, pre); - return 0; -} - -////////////////////////////////////////////////////////////////////////////// - -void CVkProto::SendMsgAck(void *param) -{ - debugLogA("CVkProto::SendMsgAck"); - TFakeAckParams *ack = (TFakeAckParams*)param; - Sleep(100); - ProtoBroadcastAck(ack->hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)ack->msgid, 0); - delete ack; -} - -int CVkProto::SendMsg(MCONTACT hContact, int flags, const char *msg) -{ - debugLogA("CVkProto::SendMsg"); - if (!IsOnline()) - return 0; - LONG userID = getDword(hContact, "ID", -1); - if (userID == -1 || userID == VK_FEED_USER) { - ForkThread(&CVkProto::SendMsgAck, new TFakeAckParams(hContact, 0)); - return 0; - } - - ptrA szMsg; - if (flags & PREF_UTF) - szMsg = mir_strdup(msg); - else if (flags & PREF_UNICODE) - szMsg = mir_utf8encodeW((wchar_t*)&msg[mir_strlen(msg)+1]); - else - szMsg = mir_utf8encode(msg); - - int StickerId = 0; - ptrA retMsg(GetStickerId(szMsg, StickerId)); - - ULONG msgId = ::InterlockedIncrement(&m_msgId); - AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, &CVkProto::OnSendMessage) - << INT_PARAM("user_id", userID) - << VER_API; - - if (StickerId != 0) - pReq << INT_PARAM("sticker_id", StickerId); - else - pReq << CHAR_PARAM("message", szMsg); - - pReq->AddHeader("Content-Type", "application/x-www-form-urlencoded"); - pReq->pUserInfo = new CVkSendMsgParam(hContact, msgId); - Push(pReq); - - if (!m_bServerDelivery) - ForkThread(&CVkProto::SendMsgAck, new TFakeAckParams(hContact, msgId)); - - if (retMsg) { - int _flags = flags | PREF_UTF; - Sleep(330); - SendMsg(hContact, _flags, retMsg); - } - return msgId; -} - -void CVkProto::OnSendMessage(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) -{ - int iResult = ACKRESULT_FAILED; - if (pReq->pUserInfo == NULL) { - debugLogA("CVkProto::OnSendMessage failed! (pUserInfo == NULL)"); - return; - } - CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo; - - debugLogA("CVkProto::OnSendMessage %d", reply->resultCode); - if (reply->resultCode == 200) { - JSONROOT pRoot; - JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); - if (pResponse != NULL) { - UINT mid = json_as_int(pResponse); - if (param->iMsgID != -1) - m_sendIds.insert((HANDLE)mid); - if (mid > getDword(param->hContact, "lastmsgid", 0)) - setDword(param->hContact, "lastmsgid", mid); - if (m_iMarkMessageReadOn >= markOnReply) - MarkMessagesRead(param->hContact); - iResult = ACKRESULT_SUCCESS; - } - } - - if (param->iMsgID == -1) { - CVkFileUploadParam *fup = (CVkFileUploadParam *)param->iCount; - ProtoBroadcastAck(fup->hContact, ACKTYPE_FILE, iResult, (HANDLE)fup, 0); - if (!pReq->bNeedsRestart) - delete fup; - return; - } - else if (m_bServerDelivery) - ProtoBroadcastAck(param->hContact, ACKTYPE_MESSAGE, iResult, HANDLE(param->iMsgID), 0); - if (!pReq->bNeedsRestart) { - delete param; - pReq->pUserInfo = NULL; - } -} - -////////////////////////////////////////////////////////////////////////////// - int CVkProto::OnEvent(PROTOEVENTTYPE event, WPARAM wParam, LPARAM lParam) { switch (event) { diff --git a/protocols/VKontakte/src/vk_thread.cpp b/protocols/VKontakte/src/vk_thread.cpp index 306fda8600..cd02bc11e1 100644 --- a/protocols/VKontakte/src/vk_thread.cpp +++ b/protocols/VKontakte/src/vk_thread.cpp @@ -536,450 +536,6 @@ void CVkProto::OnReceiveFriends(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq ///////////////////////////////////////////////////////////////////////////////////////// -int CVkProto::OnDbEventRead(WPARAM hContact, LPARAM) -{ - debugLogA("CVkProto::OnDbEventRead"); - if (m_iMarkMessageReadOn == markOnRead) - MarkMessagesRead(hContact); - return 0; -} - -void CVkProto::MarkMessagesRead(const CMStringA &mids) -{ - debugLogA("CVkProto::MarkMessagesRead (mids)"); - if (!IsOnline()) - return; - if (mids.IsEmpty()) - return; - - Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.markAsRead.json", true, &CVkProto::OnReceiveSmth) - << CHAR_PARAM("message_ids", mids) - << VER_API); -} - -void CVkProto::MarkMessagesRead(const MCONTACT hContact) -{ - debugLogA("CVkProto::MarkMessagesRead (hContact)"); - if (!IsOnline()) - return; - LONG userID = getDword(hContact, "ID", -1); - if (userID == -1 || userID == VK_FEED_USER) - return; - - Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.markAsRead.json", true, &CVkProto::OnReceiveSmth) - << INT_PARAM("peer_id", userID) - << VER_API); -} - -void CVkProto::RetrieveMessagesByIds(const CMStringA &mids) -{ - debugLogA("CVkProto::RetrieveMessagesByIds"); - if (!IsOnline()) - return; - if (mids.IsEmpty()) - return; - - Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.getById.json", true, &CVkProto::OnReceiveMessages) - << CHAR_PARAM("message_ids", mids) - << VER_API); -} - -void CVkProto::RetrieveUnreadMessages() -{ - debugLogA("CVkProto::RetrieveUnreadMessages"); - if (!IsOnline()) - return; - Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.getDialogs.json", true, &CVkProto::OnReceiveDlgs) - << VER_API); -} - -void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) -{ - debugLogA("CVkProto::OnReceiveMessages %d", reply->resultCode); - if (reply->resultCode != 200) - return; - - JSONROOT pRoot; - JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); - if (pResponse == NULL) - return; - - CMStringA mids; - int numMessages = json_as_int(json_get(pResponse, "count")); - JSONNODE *pMsgs = json_get(pResponse, "items"); - - debugLogA("CVkProto::OnReceiveMessages numMessages = %d", numMessages); - - for (int i = 0; i < numMessages; i++) { - JSONNODE *pMsg = json_at(pMsgs, i); - if (pMsg == NULL) { - debugLogA("CVkProto::OnReceiveMessages pMsg == NULL"); - break; - } - - UINT mid = json_as_int(json_get(pMsg, "id")); - ptrT ptszBody(json_as_string(json_get(pMsg, "body"))); - int datetime = json_as_int(json_get(pMsg, "date")); - int isOut = json_as_int(json_get(pMsg, "out")); - int isRead = json_as_int(json_get(pMsg, "read_state")); - int uid = json_as_int(json_get(pMsg, "user_id")); - - JSONNODE *pFwdMessages = json_get(pMsg, "fwd_messages"); - if (pFwdMessages != NULL){ - CMString tszFwdMessages = GetFwdMessages(pFwdMessages, m_iBBCForAttachments); - if (!IsEmpty(ptszBody)) - tszFwdMessages = _T("\n") + tszFwdMessages; - ptszBody = mir_tstrdup(CMString(ptszBody) + tszFwdMessages); - } - - JSONNODE *pAttachments = json_get(pMsg, "attachments"); - if (pAttachments != NULL){ - CMString tszAttachmentDescr = GetAttachmentDescr(pAttachments, m_iBBCForAttachments); - if (!IsEmpty(ptszBody)) - tszAttachmentDescr = _T("\n") + tszAttachmentDescr; - ptszBody = mir_tstrdup(CMString(ptszBody) + tszAttachmentDescr); - } - - MCONTACT hContact = NULL; - int chat_id = json_as_int(json_get(pMsg, "chat_id")); - if (chat_id == 0) - hContact = FindUser(uid, true); - - char szMid[40]; - _itoa(mid, szMid, 10); - if (m_iMarkMessageReadOn == markOnReceive || chat_id != 0) { - if (!mids.IsEmpty()) - mids.AppendChar(','); - mids.Append(szMid); - } - - if (chat_id != 0) { - debugLogA("CVkProto::OnReceiveMessages chat_id != 0"); - CMString action_chat = json_as_CMString(json_get(pMsg, "action")); - int action_mid = _ttoi(json_as_CMString(json_get(pMsg, "action_mid"))); - if ((action_chat == "chat_kick_user") && (action_mid == m_myUserId)) - KickFromChat(chat_id, uid, pMsg); - else - AppendChatMessage(chat_id, pMsg, false); - continue; - } - - PROTORECVEVENT recv = { 0 }; - recv.flags = PREF_TCHAR; - if (isRead && !m_bMesAsUnread) - recv.flags |= PREF_CREATEREAD; - if (isOut) - recv.flags |= PREF_SENT; - else if (m_bUserForceOnlineOnActivity) - SetInvisible(hContact); - - recv.timestamp = m_bUseLocalTime ? time(NULL) : datetime; - recv.tszMessage = ptszBody; - recv.lParam = isOut; - recv.pCustomData = szMid; - recv.cbCustomDataSize = (int)mir_strlen(szMid); - Sleep(100); - - debugLogA("CVkProto::OnReceiveMessages i = %d, mid = %d, datetime = %d, isOut = %d, isRead = %d, uid = %d", i, mid, datetime, isOut, isRead, uid); - - if (!CheckMid(m_sendIds, mid)) { - debugLogA("CVkProto::OnReceiveMessages ProtoChainRecvMsg"); - ProtoChainRecvMsg(hContact, &recv); - if (mid > getDword(hContact, "lastmsgid", -1)) - setDword(hContact, "lastmsgid", mid); - if (!isOut) - m_incIds.insert((HANDLE)mid); - } - } - - if (!mids.IsEmpty()) - MarkMessagesRead(mids); -} - -void CVkProto::OnReceiveDlgs(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) -{ - debugLogA("CVkProto::OnReceiveDlgs %d", reply->resultCode); - if (reply->resultCode != 200) - return; - - JSONROOT pRoot; - JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); - if (pResponse == NULL) - return; - - int numDlgs = json_as_int(json_get(pResponse, "count")); - JSONNODE *pDlgs = json_get(pResponse, "items"); - - if (pDlgs == NULL) - return; - - for (int i = 0; i < numDlgs; i++) { - JSONNODE *pDlg = json_at(pDlgs, i); - if (pDlg == NULL) - break; - - int numUnread = json_as_int(json_get(pDlg, "unread")); - - pDlg = json_get(pDlg, "message"); - if (pDlg == NULL) - break; - - int chatid = json_as_int(json_get(pDlg, "chat_id")); - if (chatid != 0) { - debugLogA("CVkProto::OnReceiveDlgs chatid = %d", chatid); - if (m_chats.find((CVkChatInfo*)&chatid) == NULL) - AppendChat(chatid, pDlg); - } - else if (m_iSyncHistoryMetod) { - int mid = json_as_int(json_get(pDlg, "id")); - int uid = json_as_int(json_get(pDlg, "user_id")); - MCONTACT hContact = FindUser(uid, true); - - if (getDword(hContact, "lastmsgid", -1) == -1 && numUnread) - GetServerHistory(hContact, 0, numUnread, 0, 0, true); - else - GetHistoryDlg(hContact, mid); - - if (m_iMarkMessageReadOn == markOnReceive && numUnread) - MarkMessagesRead(hContact); - } - else if (numUnread) { - int uid = json_as_int(json_get(pDlg, "user_id")); - MCONTACT hContact = FindUser(uid, true); - GetServerHistory(hContact, 0, numUnread, 0, 0, true); - - if (m_iMarkMessageReadOn == markOnReceive) - MarkMessagesRead(hContact); - } - } - RetrieveUsersInfo(); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -void CVkProto::RetrievePollingInfo() -{ - debugLogA("CVkProto::RetrievePollingInfo"); - if (!IsOnline()) - return; - Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/messages.getLongPollServer.json", true, &CVkProto::OnReceivePollingInfo) - << INT_PARAM("use_ssl", 1) - << VER_API); -} - -void CVkProto::OnReceivePollingInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) -{ - debugLogA("CVkProto::OnReceivePollingInfo %d", reply->resultCode); - if (reply->resultCode != 200) - return; - - JSONROOT pRoot; - JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); - if (pResponse == NULL) - return; - - m_pollingTs = mir_t2a(ptrT(json_as_string(json_get(pResponse, "ts")))); - m_pollingKey = mir_t2a(ptrT(json_as_string(json_get(pResponse, "key")))); - m_pollingServer = mir_t2a(ptrT(json_as_string(json_get(pResponse, "server")))); - if (!m_hPollingThread) { - debugLogA("CVkProto::OnReceivePollingInfo m_hPollingThread is NULL"); - debugLogA("CVkProto::OnReceivePollingInfo m_pollingTs = \'%s' m_pollingKey = \'%s\' m_pollingServer = \'%s\'", - m_pollingTs ? m_pollingTs : "", - m_pollingKey ? m_pollingKey : "", - m_pollingServer ? m_pollingServer : ""); - if (m_pollingTs != NULL && m_pollingKey != NULL && m_pollingServer != NULL) { - debugLogA("CVkProto::OnReceivePollingInfo PollingThread starting..."); - m_hPollingThread = ForkThreadEx(&CVkProto::PollingThread, NULL, NULL); - } - else { - debugLogA("CVkProto::OnReceivePollingInfo PollingThread not start"); - m_pollingConn = NULL; - ShutdownSession(); - return; - } - } - else - debugLogA("CVkProto::OnReceivePollingInfo m_hPollingThread is not NULL"); -} - -void CVkProto::PollUpdates(JSONNODE *pUpdates) -{ - debugLogA("CVkProto::PollUpdates"); - CMStringA mids; - int msgid, uid, flags, platform; - MCONTACT hContact; - - JSONNODE *pChild; - for (int i = 0; (pChild = json_at(pUpdates, i)) != NULL; i++) { - switch (json_as_int(json_at(pChild, 0))) { - case VKPOLL_MSG_DELFLAGS: - msgid = json_as_int(json_at(pChild, 1)); - flags = json_as_int(json_at(pChild, 2)); - uid = json_as_int(json_at(pChild, 3)); - hContact = FindUser(uid); - - if (hContact != NULL && (flags & VKFLAG_MSGUNREAD) && !CheckMid(m_incIds, msgid)) { - setDword(hContact, "LastMsgReadTime", time(NULL)); - SetSrmmReadStatus(hContact); - if (m_bUserForceOnlineOnActivity) - SetInvisible(hContact); - } - break; - - case VKPOLL_MSG_ADDED: // new message - msgid = json_as_int(json_at(pChild, 1)); - - // skip outgoing messages sent from a client - flags = json_as_int(json_at(pChild, 2)); - if (flags & VKFLAG_MSGOUTBOX && !(flags & VKFLAG_MSGCHAT)) - if (CheckMid(m_sendIds, msgid)) - break; - - if (!mids.IsEmpty()) - mids.AppendChar(','); - mids.AppendFormat("%d", msgid); - break; - - case VKPOLL_READ_ALL_OUT: - uid = json_as_int(json_at(pChild, 1)); - hContact = FindUser(uid); - if (hContact != NULL) { - setDword(hContact, "LastMsgReadTime", time(NULL)); - SetSrmmReadStatus(hContact); - if (m_bUserForceOnlineOnActivity) - SetInvisible(hContact); - } - break; - - case VKPOLL_USR_ONLINE: - uid = -json_as_int(json_at(pChild, 1)); - if ((hContact = FindUser(uid)) != NULL) { - setWord(hContact, "Status", ID_STATUS_ONLINE); - platform = json_as_int(json_at(pChild, 2)); - SetMirVer(hContact, platform); - } - break; - - case VKPOLL_USR_OFFLINE: - uid = -json_as_int(json_at(pChild, 1)); - if ((hContact = FindUser(uid)) != NULL) { - setWord(hContact, "Status", ID_STATUS_OFFLINE); - db_unset(hContact, m_szModuleName, "ListeningTo"); - SetMirVer(hContact, -1); - } - break; - - case VKPOLL_USR_UTN: - uid = json_as_int(json_at(pChild, 1)); - hContact = FindUser(uid); - if (hContact != NULL) { - ForkThread(&CVkProto::ContactTypingThread, (void *)hContact); - if (m_bUserForceOnlineOnActivity) - SetInvisible(hContact); - } - break; - - case VKPOLL_CHAT_CHANGED: - int chat_id = json_as_int(json_at(pChild, 1)); - CVkChatInfo *cc = m_chats.find((CVkChatInfo*)&chat_id); - if (cc) - RetrieveChatInfo(cc); - break; - } - } - - RetrieveMessagesByIds(mids); -} - -int CVkProto::PollServer() -{ - debugLogA("CVkProto::PollServer"); - if (!IsOnline()) { - debugLogA("CVkProto::PollServer is dead (not online)"); - m_pollingConn = NULL; - ShutdownSession(); - return 0; - } - - debugLogA("CVkProto::PollServer (online)"); - int iPollConnRetry = MAX_RETRIES; - NETLIBHTTPREQUEST *reply; - CMStringA szReqUrl; - szReqUrl.AppendFormat("https://%s?act=a_check&key=%s&ts=%s&wait=25&access_token=%s&mode=%d", m_pollingServer, m_pollingKey, m_pollingTs, m_szAccessToken, 106); - // see mode parametr description on https://vk.com/dev/using_longpoll (Russian version) - NETLIBHTTPREQUEST req = { sizeof(req) }; - req.requestType = REQUEST_GET; - req.szUrl = mir_strdup(szReqUrl.GetBuffer()); - req.flags = VK_NODUMPHEADERS | NLHRF_PERSISTENT | NLHRF_HTTP11; - req.timeout = 30000; - req.nlc = m_pollingConn; - - while ((reply = (NETLIBHTTPREQUEST*)CallService(MS_NETLIB_HTTPTRANSACTION, (WPARAM)m_hNetlibUser, (LPARAM)&req)) == NULL) { - debugLogA("CVkProto::PollServer is dead"); - m_pollingConn = NULL; - if (iPollConnRetry && !m_bTerminated) { - iPollConnRetry--; - debugLogA("CVkProto::PollServer restarting %d", MAX_RETRIES - iPollConnRetry); - Sleep(1000); - } - else { - debugLogA("CVkProto::PollServer => ShutdownSession"); - mir_free(req.szUrl); - ShutdownSession(); - return 0; - } - } - - mir_free(req.szUrl); - - int retVal = 0; - if (reply->resultCode == 200) { - JSONROOT pRoot(reply->pData); - JSONNODE *pFailed = json_get(pRoot, "failed"); - if (pFailed != NULL && json_as_int(pFailed) == 2) { - RetrievePollingInfo(); - retVal = -1; - debugLogA("Polling key expired, restarting polling thread"); - } - else if (CheckJsonResult(NULL, pRoot)) { - m_pollingTs = mir_t2a(ptrT(json_as_string(json_get(pRoot, "ts")))); - JSONNODE *pUpdates = json_get(pRoot, "updates"); - if (pUpdates != NULL) - PollUpdates(pUpdates); - retVal = 1; - } - } - else if ((reply->resultCode >= 400 && reply->resultCode <= 417) - || (reply->resultCode >= 500 && reply->resultCode <= 509)) { - debugLogA("CVkProto::PollServer is dead. Error code - %d", reply->resultCode); - m_pollingConn = NULL; - CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)reply); - ShutdownSession(); - return 0; - } - - m_pollingConn = reply->nlc; - - CallService(MS_NETLIB_FREEHTTPREQUESTSTRUCT, 0, (LPARAM)reply); - debugLogA("CVkProto::PollServer return %d", retVal); - return retVal; -} - -void CVkProto::PollingThread(void*) -{ - debugLogA("CVkProto::PollingThread: entering"); - - while (!m_bTerminated) - if (PollServer() == -1) - break; - - m_hPollingThread = NULL; - m_pollingConn = NULL; - debugLogA("CVkProto::PollingThread: leaving"); -} - -///////////////////////////////////////////////////////////////////////////////////////// - INT_PTR __cdecl CVkProto::SvcAddAsFriend(WPARAM hContact, LPARAM) { debugLogA("CVkProto::SvcAddAsFriend"); diff --git a/protocols/VKontakte/vk_10.vcxproj b/protocols/VKontakte/vk_10.vcxproj index b4d79e134d..0a4ad33b08 100644 --- a/protocols/VKontakte/vk_10.vcxproj +++ b/protocols/VKontakte/vk_10.vcxproj @@ -186,7 +186,9 @@ + + diff --git a/protocols/VKontakte/vk_10.vcxproj.filters b/protocols/VKontakte/vk_10.vcxproj.filters index c16159b9b3..8127a6664d 100644 --- a/protocols/VKontakte/vk_10.vcxproj.filters +++ b/protocols/VKontakte/vk_10.vcxproj.filters @@ -63,6 +63,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/protocols/VKontakte/vk_12.vcxproj b/protocols/VKontakte/vk_12.vcxproj index f476303ed3..0676ebf4ab 100644 --- a/protocols/VKontakte/vk_12.vcxproj +++ b/protocols/VKontakte/vk_12.vcxproj @@ -187,7 +187,9 @@ + + diff --git a/protocols/VKontakte/vk_12.vcxproj.filters b/protocols/VKontakte/vk_12.vcxproj.filters index 9d5568ee1a..194a5b0c0d 100644 --- a/protocols/VKontakte/vk_12.vcxproj.filters +++ b/protocols/VKontakte/vk_12.vcxproj.filters @@ -63,6 +63,12 @@ Source Files + + Source Files + + + Source Files + -- cgit v1.2.3