void CVkProto::AppendChatMessage(int id, JSONNODE *pMsg, bool bIsHistory) { CVkChatInfo *cc = AppendChat(id, NULL); if (cc == NULL) return; int mid = json_as_int(json_get(pMsg, "mid")); int isOut = json_as_int(json_get(pMsg, "out")); int uid = json_as_int(json_get(pMsg, "uid")); int msgTime = json_as_int(json_get(pMsg, "date")); time_t now = time(NULL); if (!msgTime || msgTime > now) msgTime = now; 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)); if (cc->m_bHistoryRead) AppendChatMessage(cc, mid, uid, msgTime, tszBody, bIsHistory); else { CVkChatMessage *cm = cc->m_msgs.find((CVkChatMessage *)&mid); if (cm == NULL) cc->m_msgs.insert(cm = new CVkChatMessage(mid)); cm->m_uid = uid; cm->m_date = msgTime; cm->m_tszBody = tszBody.detouch(); cm->m_bHistory = bIsHistory; } }
void CVkProto::OnReceiveMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) { debugLogA("CVkProto::OnReceiveMessages %d", reply->resultCode); if (reply->resultCode != 200) return; JSONNode jnRoot; const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot); if (!jnResponse) return; if (!jnResponse["Msgs"]) return; CMStringA mids; int numMessages = jnResponse["Msgs"]["count"].as_int(); const JSONNode &jnMsgs = jnResponse["Msgs"]["items"]; const JSONNode &jnFUsers = jnResponse["fwd_users"]; debugLogA("CVkProto::OnReceiveMessages numMessages = %d", numMessages); for (auto it = jnMsgs.begin(); it != jnMsgs.end(); ++it) { const JSONNode &jnMsg = (*it); if (!jnMsg) { debugLogA("CVkProto::OnReceiveMessages pMsg == NULL"); break; } UINT mid = jnMsg["id"].as_int(); CMString tszBody(jnMsg["body"].as_mstring()); int datetime = jnMsg["date"].as_int(); int isOut = jnMsg["out"].as_int(); int isRead = jnMsg["read_state"].as_int(); int uid = jnMsg["user_id"].as_int(); const JSONNode &jnFwdMessages = jnMsg["fwd_messages"]; if (jnFwdMessages) { CMString tszFwdMessages = GetFwdMessages(jnFwdMessages, jnFUsers, m_vkOptions.BBCForAttachments()); if (!tszBody.IsEmpty()) tszFwdMessages = _T("\n") + tszFwdMessages; tszBody += tszFwdMessages; } CMString tszAttachmentDescr; const JSONNode &jnAttachments = jnMsg["attachments"]; if (jnAttachments) { tszAttachmentDescr = GetAttachmentDescr(jnAttachments, m_vkOptions.BBCForAttachments()); if (!tszBody.IsEmpty()) tszBody += _T("\n"); tszBody += tszAttachmentDescr; } MCONTACT hContact = NULL; int chat_id = jnMsg["chat_id"].as_int(); 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); } if (chat_id != 0) { debugLogA("CVkProto::OnReceiveMessages chat_id != 0"); CMString action_chat = jnMsg["action"].as_mstring(); int action_mid = _ttoi(jnMsg["action_mid"].as_mstring()); if ((action_chat == "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"); AppendChatMessage(chat_id, jnMsg, jnFUsers, false); } continue; } PROTORECVEVENT recv = { 0 }; bool bUseServerReadFlag = m_vkOptions.bSyncReadMessageStatusFromServer ? true : !m_vkOptions.bMesAsUnread; if (isRead && bUseServerReadFlag) recv.flags |= PREF_CREATEREAD; if (isOut) recv.flags |= PREF_SENT; else if (m_vkOptions.bUserForceInvisibleOnActivity && time(NULL) - datetime < 60 * m_vkOptions.iInvisibleInterval) SetInvisible(hContact); T2Utf pszBody(tszBody); recv.timestamp = m_vkOptions.bUseLocalTime ? time(NULL) : datetime; recv.szMessage = pszBody; recv.lParam = isOut; recv.pCustomData = szMid; recv.cbCustomDataSize = (int)mir_strlen(szMid); Sleep(100); debugLogA("CVkProto::OnReceiveMessages mid = %d, datetime = %d, isOut = %d, isRead = %d, uid = %d", 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); } else if (m_vkOptions.bLoadSentAttachments && !tszAttachmentDescr.IsEmpty() && isOut) { T2Utf pszAttach(tszAttachmentDescr); recv.timestamp = time(NULL); // only local time recv.szMessage = pszAttach; ProtoChainRecvMsg(hContact, &recv); } } if (!mids.IsEmpty()) MarkMessagesRead(mids); }
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; JSONNODE *pDlgs = json_as_array(json_get(pResponse, "dlgs")); if (pDlgs != NULL) { int numDialogs = json_as_int(json_at(pDlgs, 0)); for (int i = 1; i <= numDialogs; i++) { JSONNODE *pDlg = json_at(pDlgs, i); if (pDlg == NULL) continue; int chatid = json_as_int(json_get(pDlg, "chat_id")); if (chatid != 0) if (m_chats.find((CVkChatInfo*)&chatid) == NULL) { AppendChat(chatid, pDlg); } } } CMStringA mids, lmids; bool bDirectArray = false; JSONNODE *pMsgs = json_as_array(json_get(pResponse, "msgs")); if (pMsgs == NULL) { pMsgs = pResponse; bDirectArray = true; } int numMessages = json_as_int(json_at(pMsgs, 0)); for (int i = 1; i <= numMessages; i++) { JSONNODE *pMsg = json_at(pMsgs, i); if (pMsg == NULL) continue; char szMid[40]; int mid = json_as_int(json_get(pMsg, "mid")); _itoa(mid, szMid, 10); if (!mids.IsEmpty()) mids.AppendChar(','); mids.Append(szMid); int chat_id = json_as_int(json_get(pMsg, "chat_id")); if (chat_id != 0) { AppendChatMessage(chat_id, pMsg, false); continue; } // VK documentation lies: even if you specified preview_length=0, // long messages get cut out. So we need to retrieve them from scratch ptrT ptszBody(json_as_string(json_get(pMsg, "body"))); if (!bDirectArray && _tcslen(ptszBody) > 1000) { if (!lmids.IsEmpty()) lmids.AppendChar(','); lmids.Append(szMid); continue; } int datetime = json_as_int(json_get(pMsg, "date")); int isOut = json_as_int(json_get(pMsg, "out")); int uid = json_as_int(json_get(pMsg, "uid")); int isRead = json_as_int(json_get(pMsg, "read_state")); JSONNODE *pAttachments = json_get(pMsg, "attachments"); if (pAttachments != NULL) ptszBody = mir_tstrdup(CMString(ptszBody) + GetAttachmentDescr(pAttachments)); MCONTACT hContact = FindUser(uid, true); PROTORECVEVENT recv = { 0 }; recv.flags = PREF_TCHAR; if (isRead) recv.flags |= PREF_CREATEREAD; if (isOut) recv.flags |= PREF_SENT; recv.timestamp = datetime; recv.tszMessage = ptszBody; recv.lParam = isOut; recv.pCustomData = szMid; recv.cbCustomDataSize = (int)strlen(szMid); ProtoChainRecvMsg(hContact, &recv); } MarkMessagesRead(mids); RetrieveMessagesByIds(lmids); }
CVKNewsItem* CVkProto::GetVkNewsItem(const JSONNode &jnItem, OBJLIST<CVkUserInfo> &vkUsers, bool isRepost) { bool bPostLink = true; CVKNewsItem *vkNewsItem = new CVKNewsItem(); if (!jnItem) return vkNewsItem; LONG iSourceId = jnItem["source_id"].isnull() ? jnItem["owner_id"].as_int() : jnItem["source_id"].as_int(); LONG iPostId = jnItem["post_id"].as_int(); CMString tszText(jnItem["text"].as_mstring()); vkNewsItem->tszType = jnItem["type"].as_mstring(); vkNewsItem->vkUser = GetVkUserInfo(iSourceId, vkUsers); vkNewsItem->bIsGroup = vkNewsItem->vkUser->m_bIsGroup; vkNewsItem->tDate = jnItem["date"].as_int(); if (!tszText.IsEmpty()) tszText += _T("\n"); debugLog(_T("CVkProto::GetVkNewsItem %d %d %s"), iSourceId, iPostId, vkNewsItem->tszType); if (vkNewsItem->tszType == _T("photo_tag")) { bPostLink = false; const JSONNode &jnPhotos = jnItem["photo_tags"]; if (!jnPhotos.isnull()) { const JSONNode &jnPhotoItems = jnPhotos["items"]; if (!jnPhotoItems.isnull()) { tszText = TranslateT("User was tagged in these photos:"); for (auto it = jnPhotoItems.begin(); it != jnPhotoItems.end(); ++it) tszText += _T("\n") + GetVkPhotoItem((*it), m_iBBCForNews); } } } else if (vkNewsItem->tszType == _T("photo") || vkNewsItem->tszType == _T("wall_photo")) { bPostLink = false; const JSONNode &jnPhotos = jnItem["photos"]; int i = 0; if (!jnPhotos.isnull()) { const JSONNode &jnPhotoItems = jnPhotos["items"]; if (!jnPhotoItems.isnull()) for (auto it = jnPhotoItems.begin(); it != jnPhotoItems.end(); ++it) { const JSONNode &jnPhotoItem = (*it); tszText += GetVkPhotoItem(jnPhotoItem, m_iBBCForNews) + _T("\n"); if (i == 0 && vkNewsItem->tszType == _T("wall_photo")) { if (!jnPhotoItem["post_id"].isnull()) { bPostLink = true; iPostId = jnPhotoItem["post_id"].as_int(); break; // max 1 wall_photo when photo post_id !=0 } } i++; } } } else if (vkNewsItem->tszType == _T("post") || vkNewsItem->tszType.IsEmpty()) { bPostLink = true; const JSONNode &jnRepost = jnItem["copy_history"]; if (!jnRepost.isnull()) { CVKNewsItem *vkRepost = GetVkNewsItem((*jnRepost.begin()), vkUsers, true); vkRepost->tszText.Replace(_T("\n"), _T("\n\t")); tszText += vkRepost->tszText; tszText += _T("\n"); vkNewsItem->bIsRepost = true; delete vkRepost; } const JSONNode &jnAttachments = jnItem["attachments"]; if (!jnAttachments.isnull()) { if (!tszText.IsEmpty()) tszText.AppendChar(_T('\n')); tszText += GetAttachmentDescr(jnAttachments, m_bUseBBCOnAttacmentsAsNews ? m_iBBCForNews : m_iBBCForAttachments); } } CMString tszResFormat; if (!isRepost) tszResFormat = Translate("News from %s\n%s"); else { tszResFormat = Translate("\tRepost from %s\n%s"); bPostLink = false; } vkNewsItem->tszText.AppendFormat(tszResFormat, SetBBCString(vkNewsItem->vkUser->m_tszUserNick, m_iBBCForNews, vkbbcUrl, vkNewsItem->vkUser->m_tszLink), tszText); vkNewsItem->tszId.AppendFormat(_T("%d_%d"), vkNewsItem->vkUser->m_UserId, iPostId); if (bPostLink) { vkNewsItem->tszLink = CMString(_T("https://vk.com/wall")) + vkNewsItem->tszId; vkNewsItem->tszText.AppendChar(_T('\n')); vkNewsItem->tszText += SetBBCString(TranslateT("Link"), m_iBBCForNews, vkbbcUrl, vkNewsItem->tszLink); } debugLog(_T("CVkProto::GetVkNewsItem %d %d <\n%s\n>"), iSourceId, iPostId, vkNewsItem->tszText); return vkNewsItem; }
void CVkProto::OnReceiveHistoryMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) { debugLogA("CVkProto::OnReceiveHistoryMessages %d", reply->resultCode); if (reply->resultCode != 200 || !pReq->pUserInfo) return; JSONNode jnRoot; CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo; const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot); if (!jnResponse) { if (!pReq->bNeedsRestart || m_bTerminated) { delete param; pReq->pUserInfo = NULL; } return; } int iTime = jnResponse["datetime"].as_int(); const JSONNode &jnMsgs = jnResponse["items"]; const JSONNode &jnFUsers = jnResponse["fwd_users"]; int iLastMsgId = getDword(param->hContact, "lastmsgid", -1); time_t tLastReadMessageTime = 0; int count = 0; for (auto it = jnMsgs.rbegin(); it != jnMsgs.rend(); ++it) { const JSONNode &jnMsg = (*it); int mid = jnMsg["id"].as_int(); if (iLastMsgId < mid) iLastMsgId = mid; char szMid[40]; _itoa(mid, szMid, 10); CMString tszBody(jnMsg["body"].as_mstring()); int datetime = jnMsg["date"].as_int(); int isOut = jnMsg["out"].as_int(); int isRead = jnMsg["read_state"].as_int(); int uid = jnMsg["user_id"].as_int(); const JSONNode &jnFwdMessages = jnMsg["fwd_messages"]; if (jnFwdMessages) { CMString tszFwdMessages = GetFwdMessages(jnFwdMessages, jnFUsers, m_iBBCForAttachments); if (!tszBody.IsEmpty()) tszFwdMessages = _T("\n") + tszFwdMessages; tszBody += tszFwdMessages; } const JSONNode &jnAttachments = jnMsg["attachments"]; if (jnAttachments) { CMString tszAttachmentDescr = GetAttachmentDescr(jnAttachments, m_iBBCForAttachments); if (!tszBody.IsEmpty()) tszAttachmentDescr = _T("\n") + tszAttachmentDescr; tszBody += tszAttachmentDescr; } T2Utf pszBody(tszBody); MCONTACT hContact = FindUser(uid, true); PROTORECVEVENT recv = { 0 }; if (isRead) recv.flags |= PREF_CREATEREAD; if (isOut) recv.flags |= PREF_SENT; recv.timestamp = datetime; recv.szMessage = pszBody; recv.lParam = isOut; recv.pCustomData = szMid; recv.cbCustomDataSize = (int)mir_strlen(szMid); ProtoChainRecvMsg(hContact, &recv); if (isRead && isOut && datetime > tLastReadMessageTime) tLastReadMessageTime = datetime; count++; } setDword(param->hContact, "lastmsgid", iLastMsgId); if (ServiceExists(MS_MESSAGESTATE_UPDATE)) { MessageReadData data(tLastReadMessageTime, MRD_TYPE_MESSAGETIME); CallService(MS_MESSAGESTATE_UPDATE, param->hContact, (LPARAM)&data); } int once = jnResponse["once"].as_int(); int iRCount = jnResponse["rcount"].as_int(); if (count == iRCount && once == 0) GetServerHistory(param->hContact, param->iCount + count, iRCount, iTime, param->iMsgID); if (!pReq->bNeedsRestart || m_bTerminated) { delete param; pReq->pUserInfo = NULL; } }
void CVkProto::OnReceiveHistoryMessages(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) { debugLogA("CVkProto::OnReceiveHistoryMessages %d", reply->resultCode); if (reply->resultCode != 200 || !pReq->pUserInfo) { mir_cslock lck(m_csLoadHistoryTask); if (m_iLoadHistoryTask > 0) m_iLoadHistoryTask--; debugLog(_T("CVkProto::OnReceiveHistoryMessages error m_iLoadHistoryTask=%d"), m_iLoadHistoryTask); MsgPopup(NULL, TranslateT("Error loading message history from server"), TranslateT("Error"), true); if (m_iLoadHistoryTask == 0 && m_bNotifyForEndLoadingHistoryAllContact) { MsgPopup(NULL, TranslateT("Loading messages for all contacts is completed"), TranslateT("Loading history")); m_bNotifyForEndLoadingHistoryAllContact = m_bNotifyForEndLoadingHistory = false; } return; } JSONNode jnRoot; CVkSendMsgParam *param = (CVkSendMsgParam*)pReq->pUserInfo; const JSONNode &jnResponse = CheckJsonResponse(pReq, reply, jnRoot); if (!jnResponse) { if (!pReq->bNeedsRestart || m_bTerminated) { mir_cslock lck(m_csLoadHistoryTask); if (m_iLoadHistoryTask > 0) m_iLoadHistoryTask--; ptrT ptszNick(db_get_tsa(param->hContact, m_szModuleName, "Nick")); CMString str(FORMAT, _T("%s %s %s"), TranslateT("Error loading message history from server"), TranslateT("for"), ptszNick); MsgPopup(param->hContact, str, TranslateT("Error"), true); debugLog(_T("CVkProto::OnReceiveHistoryMessages error for %s m_iLoadHistoryTask=%d"), ptszNick, m_iLoadHistoryTask); if (m_iLoadHistoryTask == 0 && m_bNotifyForEndLoadingHistoryAllContact) { MsgPopup(NULL, TranslateT("Loading messages for all contacts is completed"), TranslateT("Loading history")); m_bNotifyForEndLoadingHistoryAllContact = m_bNotifyForEndLoadingHistory = false; } delete param; pReq->pUserInfo = NULL; } return; } int iTime = jnResponse["datetime"].as_int(); const JSONNode &jnMsgs = jnResponse["items"]; const JSONNode &jnFUsers = jnResponse["fwd_users"]; int iLastMsgId = getDword(param->hContact, "lastmsgid", -1); time_t tLastReadMessageTime = 0; int count = 0; for (auto it = jnMsgs.rbegin(); it != jnMsgs.rend(); ++it) { const JSONNode &jnMsg = (*it); int mid = jnMsg["id"].as_int(); if (iLastMsgId < mid) iLastMsgId = mid; char szMid[40]; _itoa(mid, szMid, 10); CMString tszBody(jnMsg["body"].as_mstring()); int datetime = jnMsg["date"].as_int(); int isOut = jnMsg["out"].as_int(); int isRead = jnMsg["read_state"].as_int(); int uid = jnMsg["user_id"].as_int(); const JSONNode &jnFwdMessages = jnMsg["fwd_messages"]; if (jnFwdMessages) { CMString tszFwdMessages = GetFwdMessages(jnFwdMessages, jnFUsers, m_vkOptions.BBCForAttachments()); if (!tszBody.IsEmpty()) tszFwdMessages = _T("\n") + tszFwdMessages; tszBody += tszFwdMessages; } const JSONNode &jnAttachments = jnMsg["attachments"]; if (jnAttachments) { CMString tszAttachmentDescr = GetAttachmentDescr(jnAttachments, m_vkOptions.BBCForAttachments()); if (!tszBody.IsEmpty()) tszAttachmentDescr = _T("\n") + tszAttachmentDescr; tszBody += tszAttachmentDescr; } T2Utf pszBody(tszBody); MCONTACT hContact = FindUser(uid, true); PROTORECVEVENT recv = { 0 }; if (isRead) recv.flags |= PREF_CREATEREAD; if (isOut) recv.flags |= PREF_SENT; recv.timestamp = datetime; recv.szMessage = pszBody; recv.lParam = isOut; recv.pCustomData = szMid; recv.cbCustomDataSize = (int)mir_strlen(szMid); ProtoChainRecvMsg(hContact, &recv); if (isRead && isOut && datetime > tLastReadMessageTime) tLastReadMessageTime = datetime; count++; } setDword(param->hContact, "lastmsgid", iLastMsgId); if (ServiceExists(MS_MESSAGESTATE_UPDATE)) { MessageReadData data(tLastReadMessageTime, MRD_TYPE_MESSAGETIME); CallService(MS_MESSAGESTATE_UPDATE, param->hContact, (LPARAM)&data); } int once = jnResponse["once"].as_int(); int iRCount = jnResponse["rcount"].as_int(); if (count == iRCount && once == 0) GetServerHistory(param->hContact, param->iCount + count, iRCount, iTime, param->iMsgID); else { mir_cslock lck(m_csLoadHistoryTask); if (m_iLoadHistoryTask > 0) m_iLoadHistoryTask--; ptrT ptszNick(db_get_tsa(param->hContact, m_szModuleName, "Nick")); CMString str(FORMAT, TranslateT("Loading messages for %s is completed"), ptszNick); debugLog(_T("CVkProto::OnReceiveHistoryMessages for %s m_iLoadHistoryTask=%d"), ptszNick, m_iLoadHistoryTask); if (m_bNotifyForEndLoadingHistory) MsgPopup(param->hContact, str, TranslateT("Loading history")); if (m_iLoadHistoryTask == 0 && m_bNotifyForEndLoadingHistoryAllContact) { MsgPopup(NULL, TranslateT("Loading messages for all contacts is completed"), TranslateT("Loading history")); m_bNotifyForEndLoadingHistoryAllContact = m_bNotifyForEndLoadingHistory = false; } } if (!pReq->bNeedsRestart || m_bTerminated) { delete param; pReq->pUserInfo = NULL; } }