From b156c043fbf64ff4451c5e59c4724c6ff5182909 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sun, 6 Jan 2019 23:14:03 +0200 Subject: ICQ10: - fixes #1693 (Miranda doesn't mark read messages as read) - fixes #1728 (massive socket leak) --- protocols/Icq10/src/main.cpp | 5 ++++ protocols/Icq10/src/proto.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++ protocols/Icq10/src/proto.h | 7 +++++- protocols/Icq10/src/server.cpp | 31 ++++++++++++------------ protocols/Icq10/src/stdafx.h | 2 ++ 5 files changed, 81 insertions(+), 17 deletions(-) (limited to 'protocols') diff --git a/protocols/Icq10/src/main.cpp b/protocols/Icq10/src/main.cpp index 3a5267f444..0f1888952d 100644 --- a/protocols/Icq10/src/main.cpp +++ b/protocols/Icq10/src/main.cpp @@ -22,6 +22,8 @@ bool g_bPopupService; +HWND g_hwndHeartbeat; + ///////////////////////////////////////////////////////////////////////////////////////// static PLUGININFOEX pluginInfoEx = { @@ -60,6 +62,8 @@ int ModuleLoad(WPARAM, LPARAM) int CMPlugin::Load() { + g_hwndHeartbeat = CreateWindowEx(0, L"STATIC", nullptr, 0, 0, 0, 0, 0, nullptr, nullptr, nullptr, nullptr); + HookEvent(ME_SYSTEM_MODULELOAD, ModuleLoad); HookEvent(ME_SYSTEM_MODULEUNLOAD, ModuleLoad); ModuleLoad(0, 0); @@ -68,5 +72,6 @@ int CMPlugin::Load() int CMPlugin::Unload() { + DestroyWindow(g_hwndHeartbeat); return 0; } diff --git a/protocols/Icq10/src/proto.cpp b/protocols/Icq10/src/proto.cpp index 78d1961d46..21573a9595 100644 --- a/protocols/Icq10/src/proto.cpp +++ b/protocols/Icq10/src/proto.cpp @@ -38,6 +38,7 @@ CIcqProto::CIcqProto(const char* aProtoName, const wchar_t* aUserName) : m_arHttpQueue(10), m_arOwnIds(1), m_arCache(20, NumericKeySortT), + arMarkReadQueue(10, NumericKeySortT), m_evRequestsQueue(CreateEvent(nullptr, FALSE, FALSE, nullptr)), m_dwUin(this, DB_KEY_UIN, 0), m_szPassword(this, "Password") @@ -51,6 +52,7 @@ CIcqProto::CIcqProto(const char* aProtoName, const wchar_t* aUserName) : // events HookProtoEvent(ME_OPT_INITIALISE, &CIcqProto::OnOptionsInit); + HookProtoEvent(ME_DB_EVENT_MARKED_READ, &CIcqProto::OnDbEventRead); // netlib handle CMStringW descr(FORMAT, TranslateT("%s server connection"), m_tszUserName); @@ -95,6 +97,57 @@ void CIcqProto::OnContactDeleted(MCONTACT hContact) Push(pReq); } +///////////////////////////////////////////////////////////////////////////////////////// + +void CIcqProto::MarkReadTimerProc(HWND hwnd, UINT, UINT_PTR id, DWORD) +{ + CIcqProto *ppro = (CIcqProto*)id; + + mir_cslock lck(ppro->csMarkReadQueue); + while (ppro->arMarkReadQueue.getCount()) { + IcqCacheItem *pUser = ppro->arMarkReadQueue[0]; + + char buf[100]; + itoa(ppro->getDword(pUser->m_hContact, DB_KEY_UIN), buf, 10); + + auto *pReq = new AsyncHttpRequest(CONN_RAPI, REQUEST_POST, ICQ_ROBUST_SERVER); + JSONNode request, params; params.set_name("params"); + params << CHAR_PARAM("sn", buf) << INT64_PARAM("lastRead", ppro->getId(pUser->m_hContact, DB_KEY_LASTMSGID)); + request << CHAR_PARAM("method", "setDlgStateWim") << CHAR_PARAM("reqId", pReq->m_reqId) + << CHAR_PARAM("authToken", ppro->m_szRToken) << INT_PARAM("clientId", ppro->m_iRClientId) << params; + pReq->m_szParam = ptrW(json_write(&request)); + ppro->Push(pReq); + + ppro->arMarkReadQueue.remove(0); + } + KillTimer(hwnd, id); +} + +int CIcqProto::OnDbEventRead(WPARAM, LPARAM hDbEvent) +{ + MCONTACT hContact = db_event_getContact(hDbEvent); + if (!hContact) + return 0; + + // filter out only events of my protocol + const char *szProto = GetContactProto(hContact); + if (mir_strcmp(szProto, m_szModuleName)) + return 0; + + if (m_bOnline) { + SetTimer(g_hwndHeartbeat, UINT_PTR(this), 200, &CIcqProto::MarkReadTimerProc); + + IcqCacheItem *pCache = FindContactByUIN(getDword(hContact, DB_KEY_UIN)); + if (pCache) { + mir_cslock lck(csMarkReadQueue); + if (arMarkReadQueue.indexOf(pCache) == -1) + arMarkReadQueue.insert(pCache); + } + } + return 0; +} + + //////////////////////////////////////////////////////////////////////////////////////// // PS_AddToList - adds a contact to the contact list diff --git a/protocols/Icq10/src/proto.h b/protocols/Icq10/src/proto.h index da724224d8..425830b85a 100644 --- a/protocols/Icq10/src/proto.h +++ b/protocols/Icq10/src/proto.h @@ -76,13 +76,17 @@ class CIcqProto : public PROTO void OnLoggedIn(void); void OnLoggedOut(void); MCONTACT ParseBuddyInfo(const JSONNode &buddy); - void ParseMessage(MCONTACT hContact, const JSONNode &msg); + void ParseMessage(MCONTACT hContact, __int64 &lastMsgId, const JSONNode &msg); void RetrieveUserHistory(MCONTACT, __int64 startMsgId, __int64 endMsgId); void RetrieveUserInfo(MCONTACT); void SetServerStatus(int iNewStatus); void ShutdownSession(void); void StartSession(void); + mir_cs csMarkReadQueue; + LIST arMarkReadQueue; + static void CALLBACK MarkReadTimerProc(HWND hwnd, UINT, UINT_PTR id, DWORD); + __int64 getId(MCONTACT hContact, const char *szSetting); void setId(MCONTACT hContact, const char *szSetting, __int64 iValue); @@ -168,6 +172,7 @@ class CIcqProto : public PROTO //////////////////////////////////////////////////////////////////////////////////////// // events + int __cdecl OnDbEventRead(WPARAM, LPARAM); int __cdecl OnOptionsInit(WPARAM, LPARAM); //////////////////////////////////////////////////////////////////////////////////////// diff --git a/protocols/Icq10/src/server.cpp b/protocols/Icq10/src/server.cpp index d67b2924a5..b868d2ff5d 100644 --- a/protocols/Icq10/src/server.cpp +++ b/protocols/Icq10/src/server.cpp @@ -187,21 +187,25 @@ MCONTACT CIcqProto::ParseBuddyInfo(const JSONNode &buddy) return hContact; } -void CIcqProto::ParseMessage(MCONTACT hContact, const JSONNode &it) +void CIcqProto::ParseMessage(MCONTACT hContact, __int64 &lastMsgId, const JSONNode &it) { - CMStringA msgId(it["msgId"].as_mstring()); + CMStringA szMsgId(it["msgId"].as_mstring()); + __int64 msgId = _atoi64(szMsgId); + if (msgId > lastMsgId) + lastMsgId = msgId; + CMStringW type(it["mediaType"].as_mstring()); if (type != "text" && !type.IsEmpty()) return; // ignore duplicates - MEVENT hDbEvent = db_event_getById(m_szModuleName, msgId); + MEVENT hDbEvent = db_event_getById(m_szModuleName, szMsgId); if (hDbEvent != 0) return; // skip own messages, just set the server msgid CMStringA reqId(it["reqId"].as_mstring()); - if (CheckOwnMessage(reqId, msgId, true)) + if (CheckOwnMessage(reqId, szMsgId, true)) return; bool bIsOutgoing = it["outgoing"].as_bool(); @@ -209,7 +213,7 @@ void CIcqProto::ParseMessage(MCONTACT hContact, const JSONNode &it) PROTORECVEVENT pre = {}; pre.flags = (bIsOutgoing) ? PREF_SENT : 0; - pre.szMsgId = msgId; + pre.szMsgId = szMsgId; pre.timestamp = it["time"].as_int(); pre.szMessage = szUtf; ProtoChainRecvMsg(hContact, &pre); @@ -452,13 +456,8 @@ void CIcqProto::OnGetUserHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pR __int64 lastMsgId = getId(hContact, DB_KEY_LASTMSGID); const JSONNode &results = root.results(); - for (auto &it : results["messages"]) { - ParseMessage(hContact, it); - - __int64 msgId = _wtoi64(it["msgId"].as_mstring()); - if (msgId > lastMsgId) - lastMsgId = msgId; - } + for (auto &it : results["messages"]) + ParseMessage(hContact, lastMsgId, it); setId(hContact, DB_KEY_LASTMSGID, lastMsgId); } @@ -642,7 +641,6 @@ void CIcqProto::ProcessHistData(const JSONNode &ev) DWORD dwUin = _wtol(ev["sn"].as_mstring()); MCONTACT hContact = CreateContact(dwUin, true); - __int64 lastMsgId = getId(hContact, DB_KEY_LASTMSGID); __int64 srvlastId = _wtoi64(ev["lastMsgId"].as_mstring()); @@ -650,11 +648,12 @@ void CIcqProto::ProcessHistData(const JSONNode &ev) if (lastMsgId == 0) setId(hContact, DB_KEY_LASTMSGID, srvlastId); // or load missing messages if any - else if (srvlastId > lastMsgId) + else if (ev["unreadCnt"].as_int() > 0) RetrieveUserHistory(hContact, srvlastId, lastMsgId); - + for (auto &it : ev["tail"]["messages"]) - ParseMessage(hContact, it); + ParseMessage(hContact, lastMsgId, it); + setId(hContact, DB_KEY_LASTMSGID, lastMsgId); } void CIcqProto::ProcessImState(const JSONNode &ev) diff --git a/protocols/Icq10/src/stdafx.h b/protocols/Icq10/src/stdafx.h index 8e8ec110a4..a6636ebf84 100644 --- a/protocols/Icq10/src/stdafx.h +++ b/protocols/Icq10/src/stdafx.h @@ -89,3 +89,5 @@ #include "proto.h" int StatusFromString(const CMStringW&); + +extern HWND g_hwndHeartbeat; \ No newline at end of file -- cgit v1.2.3