From 676c1d3d4bc2d6a52cc71ec14ef7e7b8b9817564 Mon Sep 17 00:00:00 2001 From: Sergey Bolhovskoy Date: Fri, 23 Oct 2015 09:18:49 +0000 Subject: VKontakte: popup & sound support for newsfeed add hidden option for return chat message version bump git-svn-id: http://svn.miranda-ng.org/main/trunk@15600 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/VKontakte/src/misc.cpp | 79 +++++++++++++++++++++++ protocols/VKontakte/src/version.h | 2 +- protocols/VKontakte/src/vk_chats.cpp | 3 +- protocols/VKontakte/src/vk_feed.cpp | 122 ++++++++++++++++++++++++++++------- protocols/VKontakte/src/vk_proto.cpp | 30 +++++++++ protocols/VKontakte/src/vk_proto.h | 6 +- protocols/VKontakte/src/vk_struct.h | 2 + 7 files changed, 216 insertions(+), 28 deletions(-) (limited to 'protocols/VKontakte') diff --git a/protocols/VKontakte/src/misc.cpp b/protocols/VKontakte/src/misc.cpp index 28b44fcd01..48eec5377a 100644 --- a/protocols/VKontakte/src/misc.cpp +++ b/protocols/VKontakte/src/misc.cpp @@ -1147,4 +1147,83 @@ void CVkProto::SetInvisible(MCONTACT hContact) debugLogA("CVkProto::SetInvisible %d set ID_STATUS_INVISIBLE", getDword(hContact, "ID", -1)); } setDword(hContact, "InvisibleTS", time(NULL)); +} + +CMString CVkProto::RemoveBBC(CMString& tszSrc) +{ + static const TCHAR* tszSimpleBBCodes[][2] = { + { _T("[b]"), _T("[/b]") }, + { _T("[u]"), _T("[/u]") }, + { _T("[i]"), _T("[/i]") }, + { _T("[s]"), _T("[/s]") }, + }; + + static const TCHAR* tszParamBBCodes[][2] = { + { _T("[url="), _T("[/url]") }, + { _T("[color="), _T("[/color]") }, + }; + + CMString tszRes(tszSrc); + CMString tszLow(tszSrc); + tszLow.MakeLower(); + + for (int i = 0; i < _countof(tszSimpleBBCodes); i++) { + CMString tszOpenTag(tszSimpleBBCodes[i][0]); + CMString tszCloseTag(tszSimpleBBCodes[i][1]); + + int lenOpen = tszOpenTag.GetLength(); + int lenClose = tszCloseTag.GetLength(); + + int posOpen = 0; + int posClose = 0; + + while (true) { + if ((posOpen = tszLow.Find(tszOpenTag, posOpen)) < 0) + break; + + if ((posClose = tszLow.Find(tszCloseTag, posOpen + lenOpen)) < 0) + break; + + tszLow.Delete(posOpen, lenOpen); + tszLow.Delete(posClose - lenOpen, lenClose); + + tszRes.Delete(posOpen, lenOpen); + tszRes.Delete(posClose - lenOpen, lenClose); + + } + } + + for (int i = 0; i < _countof(tszParamBBCodes); i++) { + CMString tszOpenTag(tszParamBBCodes[i][0]); + CMString tszCloseTag(tszParamBBCodes[i][1]); + + int lenOpen = tszOpenTag.GetLength(); + int lenClose = tszCloseTag.GetLength(); + + int posOpen = 0; + int posOpen2 = 0; + int posClose = 0; + + while (true) { + if ((posOpen = tszLow.Find(tszOpenTag, posOpen)) < 0) + break; + + if ((posOpen2 = tszLow.Find(_T("]"), posOpen + lenOpen)) < 0) + break; + + if ((posClose = tszLow.Find(tszCloseTag, posOpen2 + 1)) < 0) + break; + + tszLow.Delete(posOpen, posOpen2 - posOpen + 1); + tszLow.Delete(posClose - posOpen2 + posOpen - 1, lenClose); + + tszRes.Delete(posOpen, posOpen2 - posOpen + 1); + tszRes.Delete(posClose - posOpen2 + posOpen - 1, lenClose); + + } + + } + + return tszRes; + } \ No newline at end of file diff --git a/protocols/VKontakte/src/version.h b/protocols/VKontakte/src/version.h index 74a6f915af..8a0a366134 100644 --- a/protocols/VKontakte/src/version.h +++ b/protocols/VKontakte/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 #define __MINOR_VERSION 1 #define __RELEASE_NUM 1 -#define __BUILD_NUM 16 +#define __BUILD_NUM 17 #include diff --git a/protocols/VKontakte/src/vk_chats.cpp b/protocols/VKontakte/src/vk_chats.cpp index d5b58469e2..7c13e27038 100644 --- a/protocols/VKontakte/src/vk_chats.cpp +++ b/protocols/VKontakte/src/vk_chats.cpp @@ -659,9 +659,10 @@ INT_PTR __cdecl CVkProto::OnJoinChat(WPARAM hContact, LPARAM) if (chat_id == -1) return 1; + CMString tszReturnChatMessage(ptrT(getTStringA("ReturnChatMessage"))); AsyncHttpRequest *pReq = new AsyncHttpRequest(this, REQUEST_POST, "/method/messages.send.json", true, &CVkProto::OnSendChatMsg, AsyncHttpRequest::rpHigh) << INT_PARAM("chat_id", chat_id) - << TCHAR_PARAM("message", TranslateT("I'm back")) + << TCHAR_PARAM("message", tszReturnChatMessage.IsEmpty() ? TranslateT("I'm back") : tszReturnChatMessage) << VER_API; pReq->AddHeader("Content-Type", "application/x-www-form-urlencoded"); Push(pReq); diff --git a/protocols/VKontakte/src/vk_feed.cpp b/protocols/VKontakte/src/vk_feed.cpp index b9dee95b9f..8494f8fba1 100644 --- a/protocols/VKontakte/src/vk_feed.cpp +++ b/protocols/VKontakte/src/vk_feed.cpp @@ -46,23 +46,41 @@ void CVkProto::AddFeedSpecialUser() } -void CVkProto::AddFeedEvent(CMString& tszBody, time_t tTime) +void CVkProto::AddFeedEvent(CVKNewsItem& vkNewsItem) { - if (tszBody.IsEmpty()) { - debugLogA("CVkProto::AddFeedEvent %d", tTime); + if (vkNewsItem.tszText.IsEmpty()) return; - } - + MCONTACT hContact = FindUser(VK_FEED_USER, true); - T2Utf pszBody(tszBody); + T2Utf pszBody(vkNewsItem.tszText); PROTORECVEVENT recv = { 0 }; - recv.timestamp = tTime; + recv.timestamp = vkNewsItem.tDate; recv.szMessage = pszBody; recv.lParam = 0; recv.pCustomData = NULL; recv.cbCustomDataSize = 0; + recv.flags = PREF_CREATEREAD; ProtoChainRecvMsg(hContact, &recv); + MsgPopup(hContact, vkNewsItem.tszPopupText, vkNewsItem.tszPopupTitle); +} + +void CVkProto::AddCListEvent(bool bNews) +{ + MCONTACT hContact = FindUser(VK_FEED_USER, true); + + CLISTEVENT cle = { sizeof(cle) }; + cle.hIcon = IcoLib_GetIconByHandle(GetIconHandle(IDI_NOTIFICATION)); + cle.pszService = "SRMsg/ReadMessage"; + cle.flags = CLEF_URGENT | CLEF_TCHAR; + cle.hContact = hContact; + cle.hDbEvent = NULL; + TCHAR toolTip[255]; + mir_sntprintf(toolTip, TranslateT("New %s"), bNews ? TranslateT("news") : TranslateT("notifications")); + cle.ptszTooltip = toolTip; + + CallService(MS_CLIST_ADDEVENT, 0, (LPARAM)&cle); + SkinPlaySound("NewsFeed"); } ////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -145,6 +163,7 @@ CVKNewsItem* CVkProto::GetVkNewsItem(const JSONNode &jnItem, OBJLISTtszType = jnItem["type"].as_mstring(); vkNewsItem->vkUser = GetVkUserInfo(iSourceId, vkUsers); @@ -163,6 +182,7 @@ CVKNewsItem* CVkProto::GetVkNewsItem(const JSONNode &jnItem, OBJLISTtszType == _T("post") || vkNewsItem->tszType.IsEmpty()) { @@ -197,6 +219,11 @@ CVKNewsItem* CVkProto::GetVkNewsItem(const JSONNode &jnItem, OBJLISTtszText.Replace(_T("\n"), _T("\n\t")); tszText += vkRepost->tszText; tszText += _T("\n"); + + tszPopupText += _T("\t"); + tszPopupText += vkRepost->tszPopupTitle; + tszPopupText += _T("\n\t"); + tszPopupText += vkRepost->tszPopupText; vkNewsItem->bIsRepost = true; delete vkRepost; } @@ -205,23 +232,31 @@ CVKNewsItem* CVkProto::GetVkNewsItem(const JSONNode &jnItem, OBJLISTtszText.AppendFormat(tszResFormat, SetBBCString(vkNewsItem->vkUser->m_tszUserNick, m_iBBCForNews, vkbbcUrl, vkNewsItem->vkUser->m_tszLink), tszText); - + vkNewsItem->tszPopupTitle.AppendFormat(tszTitleFormat, vkNewsItem->vkUser->m_tszUserNick); + vkNewsItem->tszPopupText = tszPopupText; + vkNewsItem->tszId.AppendFormat(_T("%d_%d"), vkNewsItem->vkUser->m_UserId, iPostId); if (bPostLink) { vkNewsItem->tszLink = CMString(_T("https://vk.com/wall")) + vkNewsItem->tszId; @@ -299,9 +334,11 @@ CVKNewsItem* CVkProto::GetVkParent(const JSONNode &jnParent, VKObjType vkParentT vkNotificationItem->tszId.AppendFormat(_T("%d_%d"), iOwnerId, iId); vkNotificationItem->tszLink.AppendFormat(_T("https://vk.com/photo%s"), vkNotificationItem->tszId); vkNotificationItem->tszText.AppendFormat(_T("\n%s"), tszPhoto); - - if (ptszReplyText) + + if (ptszReplyText) { vkNotificationItem->tszText.AppendFormat(_T("\n>> %s"), SetBBCString(ptszReplyText, m_iBBCForNews, vkbbcI)); + vkNotificationItem->tszPopupText.AppendFormat(_T(">> %s"), ptszReplyText); + } vkNotificationItem->tszText.AppendFormat(_T("\n%s"), SetBBCString(TranslateT("Link"), m_iBBCForNews, vkbbcUrl, vkNotificationItem->tszLink)); } @@ -318,8 +355,10 @@ CVKNewsItem* CVkProto::GetVkParent(const JSONNode &jnParent, VKObjType vkParentT if (!tszText.IsEmpty()) vkNotificationItem->tszText.AppendFormat(_T("\n%s: %s"), SetBBCString(TranslateT("Video description:"), m_iBBCForNews, vkbbcB), SetBBCString(tszText, m_iBBCForNews, vkbbcI)); - if (ptszReplyText) + if (ptszReplyText) { vkNotificationItem->tszText.AppendFormat(_T("\n>> %s"), SetBBCString(ptszReplyText, m_iBBCForNews, vkbbcI)); + vkNotificationItem->tszPopupText.AppendFormat(_T(">> %s"), ptszReplyText); + } vkNotificationItem->tszText.AppendFormat(_T("\n%s"), SetBBCString(tszTitle, m_iBBCForNews, vkbbcUrl, vkNotificationItem->tszLink)); } @@ -332,11 +371,17 @@ CVKNewsItem* CVkProto::GetVkParent(const JSONNode &jnParent, VKObjType vkParentT CMString tszText(jnParent["text"].as_mstring()); ClearFormatNick(tszText); - if (!tszText.IsEmpty()) + if (!tszText.IsEmpty()) { vkNotificationItem->tszText.AppendFormat(_T("\n%s: %s"), SetBBCString(TranslateT("Post text:"), m_iBBCForNews, vkbbcB), SetBBCString(tszText, m_iBBCForNews, vkbbcI)); + vkNotificationItem->tszPopupText.AppendFormat(_T("%s: %s"), TranslateT("Post text:"), tszText); + } - if (ptszReplyText) + if (ptszReplyText) { vkNotificationItem->tszText.AppendFormat(_T("\n>> %s"), SetBBCString(ptszReplyText, m_iBBCForNews, vkbbcI)); + if (!vkNotificationItem->tszPopupText.IsEmpty()) + vkNotificationItem->tszPopupText += _T("\n"); + vkNotificationItem->tszPopupText.AppendFormat(_T(">> %s"), ptszReplyText); + } vkNotificationItem->tszText.AppendFormat(_T("\n%s"), SetBBCString(TranslateT("Link"), m_iBBCForNews, vkbbcUrl, vkNotificationItem->tszLink)); } @@ -346,16 +391,22 @@ CVKNewsItem* CVkProto::GetVkParent(const JSONNode &jnParent, VKObjType vkParentT CMString tszTitle(jnParent["title"].as_mstring()); vkNotificationItem->tszId.AppendFormat(_T("%d_%d"), iOwnerId, iId); vkNotificationItem->tszLink.AppendFormat(_T("https://vk.com/topic%s%s"), - vkNotificationItem->tszId, ptszReplyLink ? ptszReplyLink : _T("")); + vkNotificationItem->tszId, ptszReplyLink ? ptszReplyLink : _T("")); CMString tszText(jnParent["text"].as_mstring()); ClearFormatNick(tszText); - if (!tszText.IsEmpty()) - vkNotificationItem->tszText.AppendFormat(_T("\n%s: %s"), SetBBCString(TranslateT("Topic text:"), m_iBBCForNews, vkbbcB), SetBBCString(tszText, m_iBBCForNews, vkbbcI)); + if (!tszText.IsEmpty()) { + vkNotificationItem->tszText.AppendFormat(_T("\n%s %s"), SetBBCString(TranslateT("Topic text:"), m_iBBCForNews, vkbbcB), SetBBCString(tszText, m_iBBCForNews, vkbbcI)); + vkNotificationItem->tszPopupText.AppendFormat(_T("%s %s"), TranslateT("Topic text:"), tszText); + } - if (ptszReplyText) + if (ptszReplyText) { vkNotificationItem->tszText.AppendFormat(_T("\n>> %s"), SetBBCString(ptszReplyText, m_iBBCForNews, vkbbcI)); + if (!vkNotificationItem->tszPopupText.IsEmpty()) + vkNotificationItem->tszPopupText += _T("\n"); + vkNotificationItem->tszPopupText.AppendFormat(_T(">> %s"), ptszReplyText); + } vkNotificationItem->tszText.AppendFormat(_T("\n%s"), SetBBCString(tszTitle, m_iBBCForNews, vkbbcUrl, vkNotificationItem->tszLink)); } @@ -422,6 +473,17 @@ CVKNewsItem* CVkProto::GetVkNotificationsItem(const JSONNode &jnItem, OBJLISTtszText); vkNotification->tszText = tszNotificaton; + + tszFeedback = RemoveBBC(tszFeedback); + int idx = tszFeedback.Find(_T(" %s %s")); + + vkNotification->tszPopupTitle.AppendFormat(_T("%s %s"), tszFeedback.Mid(0, idx), tszNotificationTranslate); + if (tszFeedback.GetLength() > idx + 7) { + if (!vkNotification->tszPopupText.IsEmpty()) + vkNotification->tszPopupText += _T("\n>> "); + vkNotification->tszPopupText += tszFeedback.Mid(idx + 7, tszFeedback.GetLength() - idx - 7); + } + vkNotification->tszType = tszType; vkNotification->tDate = jnItem["date"].as_int(); vkNotification->vkFeedbackType = vkFeedbackType; @@ -471,6 +533,7 @@ CVKNewsItem* CVkProto::GetVkGroupInvates(const JSONNode &jnItem, OBJLISTvkUser->m_tszUserNick : TranslateT("Unknown"), m_iBBCForNews, vkbbcUrl, iUserId ? vkNotification->vkUser->m_tszLink : _T("https://vk.com/")); vkNotification->tszText.AppendFormat(_T("%s %s %s"), tszUsers, tszNotificationTranslate, tszGroupName); + vkNotification->tszPopupTitle.AppendFormat(_T("%s %s %s"), iUserId ? vkNotification->vkUser->m_tszUserNick : TranslateT("Unknown"), tszNotificationTranslate, tszGName); tszIds += tszId; setTString("InviteGroupIds", tszIds); @@ -588,9 +651,15 @@ void CVkProto::OnReceiveUnreadNews(NETLIBHTTPREQUEST *reply, AsyncHttpRequest *p delete vkNewsItem; } + bool bNewsAdded = false; for (int i = 0; i < vkNews.getCount(); i++) - if (!(m_bNewsSourceNoReposts && vkNews[i].bIsRepost)) - AddFeedEvent(vkNews[i].tszText, vkNews[i].tDate); + if (!(m_bNewsSourceNoReposts && vkNews[i].bIsRepost)) { + AddFeedEvent(vkNews[i]); + bNewsAdded = true; + } + + if (bNewsAdded) + AddCListEvent(true); setDword("LastNewsTime", time(NULL)); @@ -708,12 +777,17 @@ void CVkProto::OnReceiveUnreadNotifications(NETLIBHTTPREQUEST *reply, AsyncHttpR bool bNotificationCommentAdded = false; bool bNotificationComment = false; + bool bNotificationAdded = false; for (int i = 0; i < vkNotification.getCount(); i++) if (FilterNotification(&vkNotification[i], bNotificationComment)) { - AddFeedEvent(vkNotification[i].tszText, vkNotification[i].tDate); + AddFeedEvent(vkNotification[i]); + bNotificationAdded = true; bNotificationCommentAdded = bNotificationComment || bNotificationCommentAdded; } + if (bNotificationAdded) + AddCListEvent(false); + setDword("LastNotificationsTime", time(NULL)); if (m_bNotificationsMarkAsViewed && bNotificationCommentAdded) NotificationMarkAsViewed(); diff --git a/protocols/VKontakte/src/vk_proto.cpp b/protocols/VKontakte/src/vk_proto.cpp index f0f2de1357..e1cfb32c3f 100644 --- a/protocols/VKontakte/src/vk_proto.cpp +++ b/protocols/VKontakte/src/vk_proto.cpp @@ -171,6 +171,8 @@ int CVkProto::OnModulesLoaded(WPARAM, LPARAM) HookProtoEvent(ME_MSG_WINDOWEVENT, &CVkProto::OnProcessSrmmEvent); HookProtoEvent(ME_DB_EVENT_MARKED_READ, &CVkProto::OnDbEventRead); HookProtoEvent(ME_DB_CONTACT_SETTINGCHANGED, &CVkProto::OnDbSettingChanged); + //Sounds + SkinAddNewSoundExT("NewsFeed", m_tszUserName, LPGENT("VKontakte newsfeed & notification event")); InitPopups(); InitMenus(); @@ -397,12 +399,39 @@ void CVkProto::UnInitMenus() ///////////////////////////////////////////////////////////////////////////////////////// // PopUp support +LRESULT CALLBACK PopupDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_COMMAND: + case WM_CONTEXTMENU: + { + CVkSendMsgParam *pd = (CVkSendMsgParam *)PUGetPluginData(hwnd); + if (pd != NULL && pd->hContact != NULL) + CallServiceSync(MS_MSG_SENDMESSAGE, (WPARAM)pd->hContact, 0); + PUDeletePopup(hwnd); + } + break; + case UM_FREEPLUGINDATA: + { + CVkSendMsgParam *pd = (CVkSendMsgParam *)PUGetPluginData(hwnd); + delete pd; + } + return FALSE; + default: + break; + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + void CVkProto::InitPopups(void) { TCHAR desc[256]; char name[256]; POPUPCLASS ppc = { sizeof(ppc) }; ppc.flags = PCF_TCHAR; + ppc.PluginWindowProc = PopupDlgProc; + ppc.lParam = APF_RETURN_HWND; mir_sntprintf(desc, _T("%s %s"), m_tszUserName, TranslateT("Errors")); mir_snprintf(name, "%s_%s", m_szModuleName, "Error"); @@ -435,6 +464,7 @@ void CVkProto::MsgPopup(MCONTACT hContact, const TCHAR *szMsg, const TCHAR *szTi ppd.ptszText = szMsg; ppd.pszClassName = name; ppd.hContact = hContact; + ppd.PluginData = new CVkSendMsgParam(hContact); mir_snprintf(name, "%s_%s", m_szModuleName, err ? "Error" : "Notification"); CallService(MS_POPUP_ADDPOPUPCLASS, 0, (LPARAM)&ppd); diff --git a/protocols/VKontakte/src/vk_proto.h b/protocols/VKontakte/src/vk_proto.h index cbf172d314..16f0a2b8c0 100644 --- a/protocols/VKontakte/src/vk_proto.h +++ b/protocols/VKontakte/src/vk_proto.h @@ -145,8 +145,9 @@ struct CVkProto : public PROTO //==== Feed ========================================================================== void AddFeedSpecialUser(); - void AddFeedEvent(CMString& tszBody, time_t tTime); - + void AddFeedEvent(CVKNewsItem& vkNewsItem); + void AddCListEvent(bool bNews); + CVkUserInfo* GetVkUserInfo(LONG iUserId, OBJLIST &vkUsers); void CreateVkUserInfoList(OBJLIST &vkUsers, const JSONNode &jnResponse); @@ -212,6 +213,7 @@ struct CVkProto : public PROTO CMString GetFwdMessages(const JSONNode &jnMessages, const JSONNode &jnFUsers, BBCSupport iBBC = bbcNo); void SetInvisible(MCONTACT hContact); + CMString RemoveBBC(CMString& tszSrc); //==================================================================================== diff --git a/protocols/VKontakte/src/vk_struct.h b/protocols/VKontakte/src/vk_struct.h index 4f8e0ac1d7..649d3f1acd 100644 --- a/protocols/VKontakte/src/vk_struct.h +++ b/protocols/VKontakte/src/vk_struct.h @@ -212,6 +212,8 @@ struct CVKNewsItem : public MZeroedObject { CMString tszText; CMString tszLink; CMString tszType; + CMString tszPopupTitle; + CMString tszPopupText; VKObjType vkFeedbackType, vkParentType; bool bIsGroup; bool bIsRepost; -- cgit v1.2.3