/* 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::AddFeedSpecialUser() { bool bSpecialContact = m_bNewsEnabled || m_bNotificationsEnabled || m_bSpecialContactAlwaysEnabled; MCONTACT hContact = FindUser(VK_FEED_USER); if (!bSpecialContact) { if (hContact) CallService(MS_DB_CONTACT_DELETE, (WPARAM)hContact, 0); return; } if (!hContact) { hContact = FindUser(VK_FEED_USER, true); setTString(hContact, "Nick", TranslateT("VKontakte")); CMString tszUrl = _T("https://vk.com/press/Simple.png"); SetAvatarUrl(hContact, tszUrl); ReloadAvatarInfo(hContact); setTString(hContact, "domain", _T("feed")); setTString(hContact, "Homepage", _T("https://vk.com/feed")); } if (getWord(hContact, "Status", 0) != ID_STATUS_ONLINE) setWord(hContact, "Status", ID_STATUS_ONLINE); SetMirVer(hContact, 7); } void CVkProto::AddFeedEvent(CMString& tszBody, time_t tTime) { if (tszBody.IsEmpty()) { debugLogA("CVkProto::AddFeedEvent %d", tTime); return; } MCONTACT hContact = FindUser(VK_FEED_USER, true); T2Utf pszBody(tszBody); PROTORECVEVENT recv = { 0 }; recv.timestamp = tTime; recv.szMessage = pszBody; recv.lParam = 0; recv.pCustomData = NULL; recv.cbCustomDataSize = 0; ProtoChainRecvMsg(hContact, &recv); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// CVkUserInfo* CVkProto::GetVkUserInfo(LONG iUserId, OBJLIST &vkUsers) { debugLogA("CVkProto::GetVkUserInfo %d", iUserId); if (iUserId == 0) return NULL; bool bIsGroup = (iUserId < 0); CVkUserInfo * vkUser = vkUsers.find((CVkUserInfo *)&iUserId); if (vkUser == NULL) { CMString tszNick = TranslateT("Unknown"); CMString tszLink = _T("https://vk.com/"); if (iUserId) { tszLink += bIsGroup ? "club" : "id"; tszLink.AppendFormat(_T("%d"), bIsGroup ? -iUserId : iUserId); } vkUser = new CVkUserInfo(iUserId, bIsGroup, tszNick, tszLink, bIsGroup ? NULL : FindUser(iUserId)); vkUsers.insert(vkUser); } return vkUser; } void CVkProto::CreateVkUserInfoList(OBJLIST &vkUsers, JSONNODE *pResponse) { debugLogA("CVkProto::CreateVkUserInfoList"); if (pResponse == NULL) return; JSONNODE *pProfiles = json_get(pResponse, "profiles"); JSONNODE *pProfile; if (pProfiles != NULL) for (size_t i = 0; (pProfile = json_at(pProfiles, i)) != NULL; i++) { LONG UserId = json_as_int(json_get(pProfile, "id")); if (!UserId) continue; CMString tszNick = json_as_CMString(json_get(pProfile, "first_name")); tszNick.AppendChar(' '); tszNick += json_as_CMString(json_get(pProfile, "last_name")); CMString tszLink = _T("https://vk.com/"); CMString tszScreenName = json_as_CMString(json_get(pProfile, "screen_name")); if (tszScreenName.IsEmpty()) tszScreenName.AppendFormat(_T("id%d"), UserId); tszLink += tszScreenName; CVkUserInfo * vkUser = new CVkUserInfo(UserId, false, tszNick, tszLink, FindUser(UserId)); vkUsers.insert(vkUser); } JSONNODE *pGroups = json_get(pResponse, "groups"); if (pGroups != NULL) for (size_t i = 0; (pProfile = json_at(pGroups, i)) != NULL; i++) { LONG UserId = -json_as_int(json_get(pProfile, "id")); if (!UserId) continue; CMString tszNick = json_as_CMString(json_get(pProfile, "name")); CMString tszLink = _T("https://vk.com/"); tszLink += json_as_CMString(json_get(pProfile, "screen_name")); CVkUserInfo * vkUser = new CVkUserInfo(UserId, true, tszNick, tszLink); vkUsers.insert(vkUser); } } ////////////////////////////////////////////////////////////////////////////////////////////////////////// CVKNewsItem* CVkProto::GetVkNewsItem(JSONNODE *pItem, OBJLIST &vkUsers, bool isRepost) { bool bPostLink = true; CVKNewsItem *vkNewsItem = new CVKNewsItem(); if (pItem == NULL) return vkNewsItem; LONG iSourceId = json_as_int(json_get(pItem, "source_id")); iSourceId = iSourceId ? iSourceId : json_as_int(json_get(pItem, "owner_id")); LONG iPostId = json_as_int(json_get(pItem, "post_id")); CMString tszText = json_as_CMString(json_get(pItem, "text")); vkNewsItem->tszType = json_as_CMString(json_get(pItem, "type")); vkNewsItem->vkUser = GetVkUserInfo(iSourceId, vkUsers); vkNewsItem->bIsGroup = vkNewsItem->vkUser->m_bIsGroup; vkNewsItem->tDate = json_as_int(json_get(pItem, "date")); if (!tszText.IsEmpty()) tszText += _T("\n"); debugLog(_T("CVkProto::GetVkNewsItem %d %d %s <%s>"), iSourceId, iPostId, vkNewsItem->tszType.GetBuffer(), tszText.GetBuffer()); if (vkNewsItem->tszType == _T("photo_tag")) { bPostLink = false; JSONNODE *pPhotos = json_get(pItem, "photo_tags"); if (pPhotos) { JSONNODE *pPhotoItems = json_get(pPhotos, "items"); if (pPhotoItems) { JSONNODE *pPhotoItem; tszText = TranslateT("User was tagged in these photos:"); for (size_t i = 0; (pPhotoItem = json_at(pPhotoItems, i)) != NULL; i++) tszText += _T("\n") + GetVkPhotoItem(pPhotoItem, m_iBBCForNews); } } } else if (vkNewsItem->tszType == _T("photo") || vkNewsItem->tszType == _T("wall_photo")) { bPostLink = false; JSONNODE *pPhotos = json_get(pItem, "photos"); if (pPhotos) { JSONNODE *pPhotoItems = json_get(pPhotos, "items"), *pPhotoItem; if (pPhotoItems) for (size_t i = 0; (pPhotoItem = json_at(pPhotoItems, i)) != NULL; i++) { tszText += GetVkPhotoItem(pPhotoItem, m_iBBCForNews) + _T("\n"); if (i == 0 && vkNewsItem->tszType == _T("wall_photo")) { LONG iPhotoPostId = json_as_int(json_get(pPhotoItem, "post_id")); if (iPhotoPostId) { bPostLink = true; iPostId = iPhotoPostId; break; // max 1 wall_photo when photo post_id !=0 } } } } } else if (vkNewsItem->tszType == _T("post") || vkNewsItem->tszType.IsEmpty()) { bPostLink = true; JSONNODE * pRepost = json_get(pItem, "copy_history"); if (pRepost) { CVKNewsItem *vkRepost = GetVkNewsItem(json_at(pRepost, 0), vkUsers, true); vkRepost->tszText.Replace(_T("\n"), _T("\n\t")); tszText += vkRepost->tszText; tszText += _T("\n"); vkNewsItem->bIsRepost = true; delete vkRepost; } JSONNODE *pAttachments = json_get(pItem, "attachments"); if (pAttachments){ if (!tszText.IsEmpty()) tszText.AppendChar(_T('\n')); tszText += GetAttachmentDescr(pAttachments, 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.GetBuffer(), m_iBBCForNews, vkbbcUrl, vkNewsItem->vkUser->m_tszLink.GetBuffer()), tszText.GetBuffer()); 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.GetBuffer()); } debugLog(_T("CVkProto::GetVkNewsItem %d %d <%s> <%s>"), iSourceId, iPostId, vkNewsItem->tszText.GetBuffer(), tszText.GetBuffer()); return vkNewsItem; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// CMString CVkProto::GetVkFeedback(JSONNODE *pFeedback, VKObjType vkFeedbackType, OBJLIST &vkUsers, CVkUserInfo *vkUser) { debugLogA("CVkProto::GetVkFeedback"); CMString tszRes; if (!pFeedback || !vkFeedbackType) return tszRes; CMString tszFormat; LONG iUserId = 0; if (vkFeedbackType == vkComment) { iUserId = json_as_int(json_get(pFeedback, "from_id")); tszFormat = _T("%s %%s %%s\n%s"); } else if (vkFeedbackType == vkPost) { iUserId = json_as_int(json_get(pFeedback, "owner_id ")); tszFormat = _T("%s %%s %%s\n%s"); } else if (vkFeedbackType == VKObjType::vkUsers || vkFeedbackType == vkCopy) { JSONNODE *pUsers = json_get(pFeedback, "items"), *pUserItem; CMString tszUsers; for (int i = 0; (pUserItem = json_at(pUsers, i)) != NULL; i++) { iUserId = json_as_int(json_get(pUserItem, "from_id")); if (iUserId == 0) continue; vkUser = GetVkUserInfo(iUserId, vkUsers); if (!tszUsers.IsEmpty()) tszUsers += _T(", "); tszUsers += SetBBCString(vkUser->m_tszUserNick.GetBuffer(), m_iBBCForNews, vkbbcUrl, vkUser->m_tszLink.GetBuffer()); } tszRes.AppendFormat(_T("%s %%s %%s"), tszUsers.GetBuffer()); vkUser = NULL; iUserId = 0; } if (iUserId) { vkUser = GetVkUserInfo(iUserId, vkUsers); CMString tszText = json_as_CMString(json_get(pFeedback, "text")); tszText.Replace(_T("%"), _T("%%")); tszRes.AppendFormat(tszFormat, SetBBCString(vkUser->m_tszUserNick.GetBuffer(), m_iBBCForNews, vkbbcUrl, vkUser->m_tszLink.GetBuffer()), ClearFormatNick(tszText).GetBuffer()); } return tszRes; } CVKNewsItem* CVkProto::GetVkParent(JSONNODE *pParent, VKObjType vkParentType, TCHAR *ptszReplyText, TCHAR *ptszReplyLink) { debugLogA("CVkProto::GetVkParent"); CMString tszRes; if (!pParent || !vkParentType) return NULL; CVKNewsItem * vkNotificationItem = new CVKNewsItem(); if (vkParentType == vkPhoto) { CMString tszPhoto = GetVkPhotoItem(pParent, m_iBBCForNews); LONG iOwnerId = json_as_int(json_get(pParent, "owner_id")); LONG iId = json_as_int(json_get(pParent, "id")); vkNotificationItem->tszId.AppendFormat(_T("%d_%d"), iOwnerId, iId); vkNotificationItem->tszLink.AppendFormat(_T("https://vk.com/photo%s"), vkNotificationItem->tszId.GetBuffer()); vkNotificationItem->tszText.AppendFormat(_T("\n%s"), tszPhoto.GetBuffer()); if (ptszReplyText) vkNotificationItem->tszText.AppendFormat(_T("\n>> %s"), SetBBCString(ptszReplyText, m_iBBCForNews, vkbbcI).GetBuffer()); vkNotificationItem->tszText.AppendFormat(_T("\n%s"), SetBBCString(TranslateT("Link"), m_iBBCForNews, vkbbcUrl, vkNotificationItem->tszLink.GetBuffer()).GetBuffer()); } else if (vkParentType == vkVideo) { LONG iOwnerId = json_as_int(json_get(pParent, "owner_id")); LONG iId = json_as_int(json_get(pParent, "id")); CMString tszTitle = json_as_CMString(json_get(pParent, "title")); vkNotificationItem->tszId.AppendFormat(_T("%d_%d"), iOwnerId, iId); vkNotificationItem->tszLink.AppendFormat(_T("https://vk.com/video%s"), vkNotificationItem->tszId.GetBuffer()); CMString tszText = json_as_CMString(json_get(pParent, "text")); ClearFormatNick(tszText); if (!tszText.IsEmpty()) vkNotificationItem->tszText.AppendFormat(_T("\n%s: %s"), SetBBCString(TranslateT("Video description:"), m_iBBCForNews, vkbbcB), SetBBCString(tszText.GetBuffer(), m_iBBCForNews, vkbbcI).GetBuffer()); if (ptszReplyText) vkNotificationItem->tszText.AppendFormat(_T("\n>> %s"), SetBBCString(ptszReplyText, m_iBBCForNews, vkbbcI).GetBuffer()); vkNotificationItem->tszText.AppendFormat(_T("\n%s"), SetBBCString(tszTitle.GetBuffer(), m_iBBCForNews, vkbbcUrl, vkNotificationItem->tszLink.GetBuffer()).GetBuffer()); } else if (vkParentType == vkPost) { LONG iOwnerId = json_as_int(json_get(pParent, "from_id")); LONG iId = json_as_int(json_get(pParent, "id")); vkNotificationItem->tszId.AppendFormat(_T("%d_%d"), iOwnerId, iId); vkNotificationItem->tszLink.AppendFormat(_T("https://vk.com/wall%s%s"), vkNotificationItem->tszId.GetBuffer(), ptszReplyLink ? ptszReplyLink : _T("")); CMString tszText = json_as_CMString(json_get(pParent, "text")); ClearFormatNick(tszText); if (!tszText.IsEmpty()) vkNotificationItem->tszText.AppendFormat(_T("\n%s: %s"), SetBBCString(TranslateT("Post text:"), m_iBBCForNews, vkbbcB), SetBBCString(tszText.GetBuffer(), m_iBBCForNews, vkbbcI).GetBuffer()); if (ptszReplyText) vkNotificationItem->tszText.AppendFormat(_T("\n>> %s"), SetBBCString(ptszReplyText, m_iBBCForNews, vkbbcI).GetBuffer()); vkNotificationItem->tszText.AppendFormat(_T("\n%s"), SetBBCString(TranslateT("Link"), m_iBBCForNews, vkbbcUrl, vkNotificationItem->tszLink.GetBuffer()).GetBuffer()); } else if (vkParentType == vkTopic) { LONG iOwnerId = json_as_int(json_get(pParent, "owner_id")); LONG iId = json_as_int(json_get(pParent, "id")); CMString tszTitle = json_as_CMString(json_get(pParent, "title")); vkNotificationItem->tszId.AppendFormat(_T("%d_%d"), iOwnerId, iId); vkNotificationItem->tszLink.AppendFormat(_T("https://vk.com/topic%s%s"), vkNotificationItem->tszId.GetBuffer(), ptszReplyLink ? ptszReplyLink : _T("")); CMString tszText = json_as_CMString(json_get(pParent, "text")); ClearFormatNick(tszText); if (!tszText.IsEmpty()) vkNotificationItem->tszText.AppendFormat(_T("\n%s: %s"), SetBBCString(TranslateT("Topic text:"), m_iBBCForNews, vkbbcB), SetBBCString(tszText.GetBuffer(), m_iBBCForNews, vkbbcI).GetBuffer()); if (ptszReplyText) vkNotificationItem->tszText.AppendFormat(_T("\n>> %s"), SetBBCString(ptszReplyText, m_iBBCForNews, vkbbcI).GetBuffer()); vkNotificationItem->tszText.AppendFormat(_T("\n%s"), SetBBCString(tszTitle.GetBuffer(), m_iBBCForNews, vkbbcUrl, vkNotificationItem->tszLink.GetBuffer()).GetBuffer()); } else if (vkParentType == vkComment) { CMString tszText = json_as_CMString(json_get(pParent, "text")); ClearFormatNick(tszText); JSONNODE *pNode = json_get(pParent, "photo"); if (pNode) { delete vkNotificationItem; return GetVkParent(pNode, vkPhoto, tszText.IsEmpty() ? NULL : tszText.GetBuffer()); } pNode = json_get(pParent, "video"); if (pNode) { delete vkNotificationItem; return GetVkParent(pNode, vkVideo, tszText.IsEmpty() ? NULL : tszText.GetBuffer()); } LONG iId = json_as_int(json_get(pParent, "id")); pNode = json_get(pParent, "post"); if (pNode) { CMString tszRepl; tszRepl.AppendFormat(_T("?reply=%d"), iId); delete vkNotificationItem; return GetVkParent(pNode, vkPost, tszText.IsEmpty() ? NULL : tszText.GetBuffer(), tszRepl.GetBuffer()); } pNode = json_get(pParent, "topic"); if (pNode) { CMString tszRepl; tszRepl.AppendFormat(_T("?reply=%d"), iId); delete vkNotificationItem; return GetVkParent(pNode, vkTopic, tszText.IsEmpty() ? NULL : tszText.GetBuffer(), tszRepl.GetBuffer()); } } return vkNotificationItem; } CVKNewsItem* CVkProto::GetVkNotificationsItem(JSONNODE *pItem, OBJLIST &vkUsers) { debugLogA("CVkProto::GetVkNotificationsItem"); if (pItem == NULL) return NULL; CMString tszType = json_as_CMString(json_get(pItem, "type")); VKObjType vkFeedbackType = vkNull, vkParentType = vkNull; CMString tszNotificationTranslate = SpanVKNotificationType(tszType, vkFeedbackType, vkParentType); JSONNODE *pFeedback = json_get(pItem, "feedback"); if (!pFeedback) return NULL; CVkUserInfo *vkUser = NULL; CMString tszFeedback = GetVkFeedback(pFeedback, vkFeedbackType, vkUsers, vkUser); JSONNODE *pParent = json_get(pItem, "parent"); if (!pParent) return NULL; CVKNewsItem* vkNotification = GetVkParent(pParent, vkParentType); if (!vkNotification) return NULL; if (vkNotification && !tszFeedback.IsEmpty()) { CMString tszNotificaton; tszNotificaton.AppendFormat(tszFeedback, tszNotificationTranslate.GetBuffer(), vkNotification->tszText.GetBuffer()); vkNotification->tszText = tszNotificaton; vkNotification->tszType = tszType; vkNotification->tDate = json_as_int(json_get(pItem, "date")); vkNotification->vkFeedbackType = vkFeedbackType; vkNotification->vkParentType = vkParentType; vkNotification->vkUser = vkUser; return vkNotification; } delete vkNotification; return NULL; } CVKNewsItem* CVkProto::GetVkGroupInvates(JSONNODE *pItem, OBJLIST &vkUsers) { debugLogA("CVkProto::GetVkGroupInvates"); if (pItem == NULL) return NULL; CMString tszType = json_as_CMString(json_get(pItem, "type")); VKObjType vkFeedbackType = vkNull, vkParentType = vkNull; CMString tszNotificationTranslate = SpanVKNotificationType(tszType, vkFeedbackType, vkParentType); LONG iGroupId = json_as_int(json_get(pItem, "id")); if (iGroupId == 0) return NULL; CMString tszId; tszId.AppendFormat(_T("%d,"), iGroupId); CMString tszIds = ptrT(db_get_tsa(NULL, m_szModuleName, "InviteGroupIds")); if (tszIds.Find(tszId, 0) != -1) return NULL; LONG iUserId = json_as_int(json_get(pItem, "invited_by")); CVKNewsItem *vkNotification = new CVKNewsItem(); vkNotification->tDate = time(NULL); vkNotification->vkUser = GetVkUserInfo(iUserId, vkUsers); vkNotification->tszType = tszType; vkNotification->tszId = tszId; vkNotification->vkFeedbackType = vkFeedbackType; vkNotification->vkParentType = vkParentType; CMString tszGroupName, tszGName, tszGLink; tszGName = json_as_CMString(json_get(pItem, "name")); tszGLink.AppendFormat(_T("https://vk.com/%s"), json_as_CMString(json_get(pItem, "screen_name")).GetBuffer()); tszGroupName = SetBBCString(tszGName.GetBuffer(), m_iBBCForNews, vkbbcUrl, tszGLink.GetBuffer()); CMString tszUsers = SetBBCString(vkNotification->vkUser->m_tszUserNick.GetBuffer(), m_iBBCForNews, vkbbcUrl, vkNotification->vkUser->m_tszLink.GetBuffer()); vkNotification->tszText.AppendFormat(_T("%s %s %s"), tszUsers.GetBuffer(), tszNotificationTranslate.GetBuffer(), tszGroupName.GetBuffer()); tszIds += tszId; setTString("InviteGroupIds", tszIds); return vkNotification; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// void CVkProto::RetrieveUnreadNews(time_t tLastNewsTime) { debugLogA("CVkProto::RetrieveUnreadNews"); if (!IsOnline()) return; CMStringA szFilter; szFilter = m_bNewsFilterPosts ? "post" : ""; szFilter += szFilter.IsEmpty() ? "" : ","; szFilter += m_bNewsFilterPhotos ? "photo" : ""; szFilter += szFilter.IsEmpty() ? "" : ","; szFilter += m_bNewsFilterTags ? "photo_tag" : ""; szFilter += szFilter.IsEmpty() ? "" : ","; szFilter += m_bNewsFilterWallPhotos ? "wall_photo" : ""; if (szFilter.IsEmpty()) { debugLogA("CVkProto::RetrieveUnreadNews szFilter empty"); return; } CMStringA szSource; szSource = m_bNewsSourceFriends ? "friends" : ""; szSource += szSource.IsEmpty() ? "" : ","; szSource += m_bNewsSourceGroups ? "groups" : ""; szSource += szSource.IsEmpty() ? "" : ","; szSource += m_bNewsSourcePages ? "pages" : ""; szSource += szSource.IsEmpty() ? "" : ","; szSource += m_bNewsSourceFollowing ? "following" : ""; if (szSource.IsEmpty()) { debugLogA("CVkProto::RetrieveUnreadNews szSource empty"); return; } Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/newsfeed.get.json", true, &CVkProto::OnReceiveUnreadNews) << INT_PARAM("count", 100) << INT_PARAM("return_banned", m_bNewsSourceIncludeBanned ? 1 : 0) << INT_PARAM("max_photos", m_iMaxLoadNewsPhoto) << INT_PARAM("start_time", tLastNewsTime + 1) << CHAR_PARAM("filters", szFilter.GetBuffer()) << CHAR_PARAM("source_ids", szSource.GetBuffer()) << VER_API); } static int sttCompareVKNewsItems(const CVKNewsItem *p1, const CVKNewsItem *p2) { return p1->tszId.Compare(p2->tszId) ? (LONG)p1->tDate - (LONG)p2->tDate : 0; } void CVkProto::OnReceiveUnreadNews(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) { debugLogA("CVkProto::OnReceiveUnreadNews %d", reply->resultCode); if (reply->resultCode != 200) return; JSONROOT pRoot; JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); if (pResponse == NULL) return; OBJLIST vkUsers(5, NumericKeySortT); CreateVkUserInfoList(vkUsers, pResponse); JSONNODE *pItems = json_get(pResponse, "items"); JSONNODE *pItem; OBJLIST vkNews(5, sttCompareVKNewsItems); if (pItems != NULL) for (int i = 0; (pItem = json_at(pItems, i)) != NULL; i++) { CVKNewsItem *vkNewsItem = GetVkNewsItem(pItem, vkUsers); if (!vkNewsItem) continue; if (vkNews.find(vkNewsItem) == NULL) vkNews.insert(vkNewsItem); else delete vkNewsItem; } for (int i = 0; i < vkNews.getCount(); i++) if (!(m_bNewsSourceNoReposts && vkNews[i].bIsRepost)) AddFeedEvent(vkNews[i].tszText, vkNews[i].tDate); setDword("LastNewsTime", time(NULL)); vkNews.destroy(); vkUsers.destroy(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// void CVkProto::RetrieveUnreadNotifications(time_t tLastNotificationsTime) { debugLogA("CVkProto::RetrieveUnreadNotifications"); if (!IsOnline()) return; CMString code; code.AppendFormat(_T("return{\"notifications\":API.notifications.get({\"count\": 100, \"start_time\":%d})%s"), (LONG)(tLastNotificationsTime + 1), m_bNotificationFilterInvites ? _T(",\"groupinvates\":API.groups.getInvites({\"extended\":1})};") : _T("};")); Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/execute.json", true, &CVkProto::OnReceiveUnreadNotifications) << TCHAR_PARAM("code", code.GetBuffer()) << VER_API); } bool CVkProto::FilterNotification(CVKNewsItem* vkNotificationItem, bool& isCommented) { isCommented = false; if (vkNotificationItem->vkParentType == vkNull) return false; if (vkNotificationItem->tszType == _T("mention_comments") || vkNotificationItem->tszType == _T("mention_comment_photo") || vkNotificationItem->tszType == _T("mention_comment_video")){ isCommented = true; return m_bNotificationFilterMentions; } bool result = (vkNotificationItem->vkFeedbackType == vkUsers && m_bNotificationFilterLikes); result = (vkNotificationItem->vkFeedbackType == vkCopy && m_bNotificationFilterReposts) || result; result = (vkNotificationItem->vkFeedbackType == vkComment && m_bNotificationFilterComments) || result; result = (vkNotificationItem->vkParentType == vkInvite && m_bNotificationFilterInvites) || result; isCommented = (vkNotificationItem->vkFeedbackType == vkComment); return result; } void CVkProto::NotificationMarkAsViewed() { debugLogA("CVkProto::NotificationMarkAsViewed"); if (!IsOnline()) return; Push(new AsyncHttpRequest(this, REQUEST_GET, "/method/notifications.markAsViewed.json", true, &CVkProto::OnReceiveSmth) << VER_API); } void CVkProto::OnReceiveUnreadNotifications(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *pReq) { debugLogA("CVkProto::OnReceiveUnreadNotifications %d", reply->resultCode); if (reply->resultCode != 200) return; JSONROOT pRoot; JSONNODE *pResponse = CheckJsonResponse(pReq, reply, pRoot); if (pResponse == NULL) return; JSONNODE *pNotifications = json_get(pResponse, "notifications"); JSONNODE *pGroupInvates = json_get(pResponse, "groupinvates"); OBJLIST vkUsers(5, NumericKeySortT); OBJLIST vkNotification(5, sttCompareVKNewsItems); CreateVkUserInfoList(vkUsers, pNotifications); CreateVkUserInfoList(vkUsers, pGroupInvates); JSONNODE *pItems, *pItem; if (pNotifications != NULL) { pItems = json_get(pNotifications, "items"); if (pItems != NULL) for (int i = 0; (pItem = json_at(pItems, i)) != NULL; i++) { CVKNewsItem *vkNotificationItem = GetVkNotificationsItem(pItem, vkUsers); if (!vkNotificationItem) continue; if (vkNotification.find(vkNotificationItem) == NULL) vkNotification.insert(vkNotificationItem); else delete vkNotificationItem; } } if (pGroupInvates != NULL) { pItems = json_get(pGroupInvates, "items"); if (pItems != NULL) for (int i = 0; (pItem = json_at(pItems, i)) != NULL; i++) { CVKNewsItem *vkNotificationItem = GetVkGroupInvates(pItem, vkUsers); if (!vkNotificationItem) continue; if (vkNotification.find(vkNotificationItem) == NULL) vkNotification.insert(vkNotificationItem); else delete vkNotificationItem; } } bool bNotificationCommentAdded = false; bool bNotificationComment = false; for (int i = 0; i < vkNotification.getCount(); i++) if (FilterNotification(&vkNotification[i], bNotificationComment)) { AddFeedEvent(vkNotification[i].tszText, vkNotification[i].tDate); bNotificationCommentAdded = bNotificationComment || bNotificationCommentAdded; } setDword("LastNotificationsTime", time(NULL)); if (m_bNotificationsMarkAsViewed && bNotificationCommentAdded) NotificationMarkAsViewed(); vkNotification.destroy(); vkUsers.destroy(); } void CVkProto::RetrieveUnreadEvents() { debugLogA("CVkProto::RetrieveUnreadEvents"); if (!IsOnline() || (!m_bNotificationsEnabled && !m_bNewsEnabled)) return; time_t tLastNotificationsTime = getDword("LastNotificationsTime", time(NULL) - 24 * 60 * 60); if (time(NULL) - tLastNotificationsTime - m_iNotificationsInterval * 60 >= -3 && m_bNotificationsEnabled) RetrieveUnreadNotifications(tLastNotificationsTime); time_t tLastNewsTime = getDword("LastNewsTime", time(NULL) - 24 * 60 * 60); if (time(NULL) - tLastNewsTime - m_iNewsInterval * 60 >= -3 && m_bNewsEnabled) RetrieveUnreadNews(tLastNewsTime); NewsClearHistory(); } INT_PTR CVkProto::SvcLoadVKNews(WPARAM, LPARAM) { debugLogA("CVkProto::SvcLoadVKNews"); if (!IsOnline()) return 1; if (!m_bNewsEnabled && !m_bNotificationsEnabled) { m_bSpecialContactAlwaysEnabled = true; AddFeedSpecialUser(); } time_t tLastNewsTime = getDword("LastNewsTime", time(NULL) - 24 * 60 * 60); RetrieveUnreadNews(tLastNewsTime); return 0; } void CVkProto::NewsClearHistory() { debugLogA("CVkProto::NewsClearHistory"); MCONTACT hContact = FindUser(VK_FEED_USER); if (hContact == NULL || !m_bNewsAutoClearHistory) return; time_t tTime = time(NULL) - m_iNewsAutoClearHistoryInterval; MEVENT hDBEvent = db_event_first(hContact); while (hDBEvent) { MEVENT hDBEventNext = db_event_next(hContact, hDBEvent); DBEVENTINFO dbei = { sizeof(dbei) }; db_event_get(hDBEvent, &dbei); if (dbei.timestamp < tTime) db_event_delete(hContact, hDBEvent); hDBEvent = hDBEventNext; } }