From a71cdc522c320ad0c18317e8f0a2127f8eddecf7 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Thu, 9 Jan 2014 17:58:37 +0000 Subject: VK: version of chats that reads a nicklist & message history git-svn-id: http://svn.miranda-ng.org/main/trunk@7570 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/VKontakte/src/vk_chats.cpp | 178 +++++++++++++++++++++++++++++++--- protocols/VKontakte/src/vk_proto.h | 19 ++-- protocols/VKontakte/src/vk_thread.cpp | 132 ++++++++++++++----------- 3 files changed, 249 insertions(+), 80 deletions(-) (limited to 'protocols') diff --git a/protocols/VKontakte/src/vk_chats.cpp b/protocols/VKontakte/src/vk_chats.cpp index bdbe536d1f..d7865e3f00 100644 --- a/protocols/VKontakte/src/vk_chats.cpp +++ b/protocols/VKontakte/src/vk_chats.cpp @@ -17,25 +17,26 @@ along with this program. If not, see . #include "stdafx.h" -void CVkProto::AppendChat(int id, JSONNODE *pDlg) -{ - CVkChatInfo *c = new CVkChatInfo(id); +static LPCTSTR sttStatuses[] = { LPGENT("Participants"), LPGENT("Owners") }; - ptrT tszTitle(json_as_string(json_get(pDlg, "title"))); - c->m_tszTitle = mir_tstrdup((tszTitle != NULL) ? tszTitle : _T("")); +CVkChatInfo* CVkProto::AppendChat(int id, JSONNODE *pDlg) +{ + if (id == 0) + return NULL; - CMString ids = ptrT(json_as_string(json_get(pDlg, "chat_active"))); - for (int iStart = 0;;) { - CMString uid = ids.Tokenize(_T(","), iStart); - if (iStart == -1) - break; + CVkChatInfo *c = m_chats.find((CVkChatInfo*)&id); + if (c != NULL) + return c; - CVkChatUser *cu = new CVkChatUser(); - cu->userid = _ttoi(uid); - c->m_users.insert(cu); + ptrT tszTitle; + c = new CVkChatInfo(id); + if (pDlg != NULL) { + tszTitle = json_as_string(json_get(pDlg, "title")); + c->m_tszTitle = mir_tstrdup((tszTitle != NULL) ? tszTitle : _T("")); } CMString sid; sid.Format(_T("%S_%d"), m_szModuleName, id); + c->m_tszId = mir_tstrdup(sid); GCSESSION gcw = { sizeof(gcw) }; gcw.iType = GCW_CHATROOM; @@ -52,8 +53,153 @@ void CVkProto::AppendChat(int id, JSONNODE *pDlg) c->m_hContact = gci.hContact; m_chats.insert(c); - GCDEST gcd = { m_szModuleName, sid.GetBuffer(), GC_EVENT_CONTROL }; - GCEVENT gce = { sizeof(GCEVENT), &gcd }; + GCDEST gcd = { m_szModuleName, sid.GetBuffer(), GC_EVENT_ADDGROUP }; + GCEVENT gce = { sizeof(gce), &gcd }; + for (int i = SIZEOF(sttStatuses)-1; i >= 0; i--) { + gce.ptszStatus = TranslateTS(sttStatuses[i]); + CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); + } + + gcd.iType = GC_EVENT_CONTROL; + gce.ptszStatus = 0; CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce); - // CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce); + CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce); + + RetrieveChatInfo(c); + return c; +} + +///////////////////////////////////////////////////////////////////////////////////////// + +void CVkProto::RetrieveChatInfo(CVkChatInfo *cc) +{ + CMStringA szQuery("return { "); + + // retrieve title if empty + if (!lstrlen(cc->m_tszTitle)) + szQuery.AppendFormat("\"info\": API.messages.getChat({\"chat_id\":%d}),", cc->m_chatid); + + // retrieve users + szQuery.AppendFormat("\"users\": API.messages.getChatUsers({\"chat_id\":%d, \"fields\":\"uid,first_name,last_name,photo\"})", cc->m_chatid); + + if (!cc->m_bHistoryRead) { + cc->m_bHistoryRead = true; + szQuery.AppendFormat(",\"msgs\": API.messages.getHistory({\"chat_id\":%d, \"count\":\"20\", \"rev\":\"0\"})", cc->m_chatid); + } + + szQuery.Append("};"); + + debugLogA("CVkProto::RetrieveChantInfo(%d)", cc->m_chatid); + + HttpParam params[] = { + { "code", szQuery }, + { "access_token", m_szAccessToken } + }; + AsyncHttpRequest *pReq = PushAsyncHttpRequest(REQUEST_GET, "/method/execute.json", true, &CVkProto::OnReceiveChatInfo, SIZEOF(params), params); + pReq->pUserInfo = cc; +} + +void CVkProto::OnReceiveChatInfo(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) +{ + debugLogA("CVkProto::OnReceiveChatInfo %d", reply->resultCode); + if (reply->resultCode != 200) + return; + + JSONROOT pRoot; + JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); + if (pResponse == NULL) + return; + + CVkChatInfo *cc = (CVkChatInfo*)pReq->pUserInfo; + if (m_chats.indexOf(cc) == -1) + return; + + JSONNODE *info = json_get(pResponse, "info"); + if (info != NULL) { + ptrT tszTitle(json_as_string(json_get(info, "title"))); + cc->m_tszTitle = mir_tstrdup(tszTitle); + + cc->m_admin_id = json_as_int(json_get(info, "admin_id")); + + JSONNODE *userids = json_as_array(json_get(info, "users")); + if (userids) { + for (int i = 0;; i++) { + int uid = json_as_int(json_at(userids, i)); + if (uid == 0) + break; + + CVkChatUser *cu = cc->m_users.find((CVkChatUser*)&uid); + if (cu == NULL) + cc->m_users.insert(cu = new CVkChatUser(uid)); + } + } + } + + JSONNODE *users = json_as_array(json_get(pResponse, "users")); + if (users != NULL) { + for (int i = 0;; i++) { + JSONNODE *pUser = json_at(users, i); + if (pUser == NULL) + break; + + int uid = json_as_int(json_get(pUser, "uid")); + TCHAR tszId[20]; + _itot(uid, tszId, 10); + + CVkChatUser *cu = cc->m_users.find((CVkChatUser*)&uid); + if (cu == NULL) + cc->m_users.insert(cu = new CVkChatUser(uid)); + + ptrT fName(json_as_string(json_get(pUser, "first_name"))); + ptrT lName(json_as_string(json_get(pUser, "last_name"))); + CMString tszNick = CMString(fName).Trim() + _T(" ") + CMString(lName).Trim(); + cu->m_tszTitle = mir_tstrdup(tszNick); + + cu->m_tszImage = json_as_string(json_get(pUser, "photo")); + + GCDEST gcd = { m_szModuleName, cc->m_tszId, GC_EVENT_JOIN }; + GCEVENT gce = { sizeof(GCEVENT), &gcd }; + gce.bIsMe = uid == m_myUserId; + gce.ptszUID = tszId; + gce.ptszNick = tszNick; + gce.ptszStatus = TranslateTS(sttStatuses[uid == cc->m_admin_id]); + gce.dwItemData = (INT_PTR)cu; + CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); + } + } + + JSONNODE *msgs = json_as_array(json_get(pResponse, "msgs")); + if (msgs != NULL) { + for (int i = 1;; i++) { + JSONNODE *pMsg = json_at(msgs, i); + if (pMsg == NULL) + break; + + int uid = json_as_int(json_get(pMsg, "from_id")); + TCHAR tszId[20]; + _itot(uid, tszId, 10); + + CVkChatUser *cu = cc->m_users.find((CVkChatUser*)&uid); + if (cu == NULL) { + cc->m_users.insert(cu = new CVkChatUser(uid)); + cu->m_tszTitle = mir_tstrdup(TranslateT("Uknown")); + } + + int iDate = json_as_int(json_get(pMsg, "date")); + ptrT tszBody(json_as_string(json_get(pMsg, "body"))); + + JSONNODE *pAttachments = json_get(pMsg, "attachments"); + if (pAttachments != NULL) + tszBody = mir_tstrdup(CMString(tszBody) + GetAttachmentDescr(pAttachments)); + + GCDEST gcd = { m_szModuleName, cc->m_tszId, GC_EVENT_MESSAGE }; + GCEVENT gce = { sizeof(GCEVENT), &gcd }; + gce.bIsMe = uid == m_myUserId; + gce.ptszUID = tszId; + gce.time = iDate; + gce.ptszNick = cu->m_tszTitle; + gce.ptszText = tszBody; + CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); + } + } } diff --git a/protocols/VKontakte/src/vk_proto.h b/protocols/VKontakte/src/vk_proto.h index 32f597d939..1cff543e4f 100644 --- a/protocols/VKontakte/src/vk_proto.h +++ b/protocols/VKontakte/src/vk_proto.h @@ -33,19 +33,22 @@ struct AsyncHttpRequest : public NETLIBHTTPREQUEST, public MZeroedObject struct CVkChatUser { - int userid; - ptrT tszTitle, tszImage; + CVkChatUser(int _id) : m_uid(_id) {} + + int m_uid; + ptrT m_tszTitle, m_tszImage; }; -struct CVkChatInfo +struct CVkChatInfo : public MZeroedObject { CVkChatInfo(int _id) : m_users(10, NumericKeySortT), m_chatid(_id) {} - int m_chatid; - ptrT m_tszTitle; + int m_chatid, m_admin_id; + bool m_bHistoryRead; + ptrT m_tszTitle, m_tszId; HANDLE m_hContact; OBJLIST m_users; }; @@ -223,5 +226,9 @@ private: static INT_PTR CALLBACK OptionsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); OBJLIST m_chats; - void AppendChat(int id, JSONNODE *pNode); + CVkChatInfo* AppendChat(int id, JSONNODE *pNode); + void RetrieveChatInfo(CVkChatInfo*); + void OnReceiveChatInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + + CMString GetAttachmentDescr(JSONNODE*); }; diff --git a/protocols/VKontakte/src/vk_thread.cpp b/protocols/VKontakte/src/vk_thread.cpp index 9d7fc28a48..6df0321fd2 100644 --- a/protocols/VKontakte/src/vk_thread.cpp +++ b/protocols/VKontakte/src/vk_thread.cpp @@ -452,64 +452,8 @@ void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pRe int isRead = json_as_int(json_get(pMsg, "read_state")); JSONNODE *pAttachments = json_get(pMsg, "attachments"); - if (pAttachments != NULL) { - CMString tszBody(ptszBody); - tszBody.AppendChar('\n'); - tszBody += TranslateT("Attachments:"); - tszBody.AppendChar('\n'); - JSONNODE *pAttach; - for (int k = 0; (pAttach = json_at(pAttachments, k)) != NULL; k++) { - tszBody.AppendChar('\t'); - ptrT ptszType(json_as_string(json_get(pAttach, "type"))); - if (!lstrcmp(ptszType, _T("photo"))) { - JSONNODE *pPhoto = json_get(pAttach, "photo"); - if (pPhoto == NULL) continue; - - ptrT ptszLink; - for (int i = 0; i < SIZEOF(szImageTypes); i++) - if ((ptszLink = json_as_string(json_get(pPhoto, szImageTypes[i]))) != NULL) - break; - - int iWidth = json_as_int(json_get(pPhoto, "width")); - int iHeight = json_as_int(json_get(pPhoto, "height")); - tszBody.AppendFormat(_T("%s: %s (%dx%d)"), TranslateT("Photo"), ptszLink, iWidth, iHeight); - } - else if (!lstrcmp(ptszType, _T("audio"))) { - JSONNODE *pAudio = json_get(pAttach, "audio"); - if (pAudio == NULL) continue; - - int aid = json_as_int(json_get(pAudio, "aid")); - int ownerID = json_as_int(json_get(pAudio, "owner_id")); - ptrT ptszArtist(json_as_string(json_get(pAudio, "artist"))); - ptrT ptszTitle(json_as_string(json_get(pAudio, "title"))); - tszBody.AppendFormat(_T("%s: (%s - %s) - http://vk.com/audio%d_%d"), - TranslateT("Audio"), ptszArtist, ptszTitle, ownerID, aid); - } - else if (!lstrcmp(ptszType, _T("video"))) { - JSONNODE *pVideo = json_get(pAttach, "video"); - if (pVideo == NULL) continue; - - ptrT ptszTitle(json_as_string(json_get(pVideo, "title"))); - int vid = json_as_int(json_get(pVideo, "vid")); - int ownerID = json_as_int(json_get(pVideo, "owner_id")); - tszBody.AppendFormat(_T("%s: %s - http://vk.com/video%d_%d"), - TranslateT("Video"), ptszTitle, ownerID, vid); - } - else if (!lstrcmp(ptszType, _T("doc"))) { - JSONNODE *pDoc = json_get(pAttach, "doc"); - if (pDoc == NULL) continue; - - ptrT ptszTitle(json_as_string(json_get(pDoc, "title"))); - ptrT ptszUrl(json_as_string(json_get(pDoc, "url"))); - tszBody.AppendFormat(_T("%s: (%s) - %s"), - TranslateT("Document"), ptszTitle, ptszUrl); - } - else tszBody.AppendFormat(TranslateT("Unsupported or unknown attachment type: %s"), ptszType); - - tszBody.AppendChar('\n'); - } - ptszBody = mir_tstrdup(tszBody); - } + if (pAttachments != NULL) + ptszBody = mir_tstrdup(CMString(ptszBody) + GetAttachmentDescr(pAttachments)); HANDLE hContact = FindUser(uid, true); @@ -608,6 +552,13 @@ void CVkProto::PollUpdates(JSONNODE *pUpdates) if ((hContact = FindUser(uid)) != NULL) CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, 5); break; + + case VKPOLL_CHAT_CHANGED: + int chatid = json_as_int(json_at(pChild, 1)); + int isSelf = json_as_int(json_at(pChild, 2)); + if (!isSelf) + AppendChat(chatid, NULL); + break; } } @@ -667,3 +618,68 @@ void CVkProto::PollingThread(void*) m_pollingConn = NULL; debugLogA("CVkProto::PollingThread: leaving"); } + +CMString CVkProto::GetAttachmentDescr(JSONNODE *pAttachments) +{ + CMString res; + res.AppendChar('\n'); + res += TranslateT("Attachments:"); + res.AppendChar('\n'); + JSONNODE *pAttach; + for (int k = 0; (pAttach = json_at(pAttachments, k)) != NULL; k++) { + res.AppendChar('\t'); + ptrT ptszType(json_as_string(json_get(pAttach, "type"))); + if (!lstrcmp(ptszType, _T("photo"))) { + JSONNODE *pPhoto = json_get(pAttach, "photo"); + if (pPhoto == NULL) continue; + + ptrT ptszLink; + for (int i = 0; i < SIZEOF(szImageTypes); i++) { + JSONNODE *n = json_get(pPhoto, szImageTypes[i]); + if (n != NULL) { + ptszLink = json_as_string(n); + break; + } + } + + int iWidth = json_as_int(json_get(pPhoto, "width")); + int iHeight = json_as_int(json_get(pPhoto, "height")); + res.AppendFormat(_T("%s: %s (%dx%d)"), TranslateT("Photo"), ptszLink, iWidth, iHeight); + } + else if (!lstrcmp(ptszType, _T("audio"))) { + JSONNODE *pAudio = json_get(pAttach, "audio"); + if (pAudio == NULL) continue; + + int aid = json_as_int(json_get(pAudio, "aid")); + int ownerID = json_as_int(json_get(pAudio, "owner_id")); + ptrT ptszArtist(json_as_string(json_get(pAudio, "artist"))); + ptrT ptszTitle(json_as_string(json_get(pAudio, "title"))); + res.AppendFormat(_T("%s: (%s - %s) - http://vk.com/audio%d_%d"), + TranslateT("Audio"), ptszArtist, ptszTitle, ownerID, aid); + } + else if (!lstrcmp(ptszType, _T("video"))) { + JSONNODE *pVideo = json_get(pAttach, "video"); + if (pVideo == NULL) continue; + + ptrT ptszTitle(json_as_string(json_get(pVideo, "title"))); + int vid = json_as_int(json_get(pVideo, "vid")); + int ownerID = json_as_int(json_get(pVideo, "owner_id")); + res.AppendFormat(_T("%s: %s - http://vk.com/video%d_%d"), + TranslateT("Video"), ptszTitle, ownerID, vid); + } + else if (!lstrcmp(ptszType, _T("doc"))) { + JSONNODE *pDoc = json_get(pAttach, "doc"); + if (pDoc == NULL) continue; + + ptrT ptszTitle(json_as_string(json_get(pDoc, "title"))); + ptrT ptszUrl(json_as_string(json_get(pDoc, "url"))); + res.AppendFormat(_T("%s: (%s) - %s"), + TranslateT("Document"), ptszTitle, ptszUrl); + } + else res.AppendFormat(TranslateT("Unsupported or unknown attachment type: %s"), ptszType); + + res.AppendChar('\n'); + } + + return res; +} -- cgit v1.2.3