diff options
author | George Hazan <ghazan@miranda.im> | 2019-01-03 22:08:25 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2019-01-03 22:08:25 +0300 |
commit | 411df60e2845f9ddfe3e68043d603d64c3bf62a5 (patch) | |
tree | 635f5705deb63379b4b30f6aa21414778b086228 | |
parent | ca6eff4cc054b80e91b98ad25a30515a54084c3e (diff) |
fixes #1670 (ICQ10: server history loading)
-rw-r--r-- | protocols/Icq10/src/proto.h | 6 | ||||
-rw-r--r-- | protocols/Icq10/src/server.cpp | 125 | ||||
-rw-r--r-- | protocols/Icq10/src/utils.cpp | 21 |
3 files changed, 118 insertions, 34 deletions
diff --git a/protocols/Icq10/src/proto.h b/protocols/Icq10/src/proto.h index 634689ad99..30f0d7b7fd 100644 --- a/protocols/Icq10/src/proto.h +++ b/protocols/Icq10/src/proto.h @@ -74,16 +74,22 @@ class CIcqProto : public PROTO<CIcqProto> void OnLoggedIn(void); void OnLoggedOut(void); MCONTACT ParseBuddyInfo(const JSONNode &buddy); + void ParseMessage(MCONTACT hContact, const JSONNode &msg); + void RetrieveUserHistory(MCONTACT, __int64 startMsgId, __int64 endMsgId); void RetrieveUserInfo(MCONTACT); void SetServerStatus(int iNewStatus); void ShutdownSession(void); void StartSession(void); + __int64 getId(MCONTACT hContact, const char *szSetting); + void setId(MCONTACT hContact, const char *szSetting, __int64 iValue); + void OnAddBuddy(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnAddClient(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnCheckPassword(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnCheckPhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnFetchEvents(NETLIBHTTPREQUEST*, AsyncHttpRequest*); + void OnGetUserHistory(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnGetUserInfo(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnLoginViaPhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*); void OnNormalizePhone(NETLIBHTTPREQUEST*, AsyncHttpRequest*); diff --git a/protocols/Icq10/src/server.cpp b/protocols/Icq10/src/server.cpp index a25b2fe4fb..5e091d6921 100644 --- a/protocols/Icq10/src/server.cpp +++ b/protocols/Icq10/src/server.cpp @@ -165,6 +165,44 @@ MCONTACT CIcqProto::ParseBuddyInfo(const JSONNode &buddy) return hContact; } +void CIcqProto::ParseMessage(MCONTACT hContact, const JSONNode &it) +{ + CMStringA msgId(it["msgId"].as_mstring()); + CMStringW type(it["mediaType"].as_mstring()); + if (type != "text" && !type.IsEmpty()) + return; + + // ignore duplicates + MEVENT hDbEvent = db_event_getById(m_szModuleName, msgId); + if (hDbEvent != 0) + return; + + // skip own messages, just set the server msgid + bool bSkipped = false; + CMStringA reqId(it["reqId"].as_mstring()); + for (auto &ownMsg : m_arOwnIds) + if (!mir_strcmp(reqId, ownMsg->m_guid)) { + bSkipped = true; + if (m_bSlowSend) + ProtoBroadcastAck(ownMsg->m_hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)ownMsg->m_msgid, (LPARAM)msgId.c_str()); + m_arOwnIds.remove(m_arOwnIds.indexOf(&ownMsg)); + break; + } + + if (bSkipped) + return; + + bool bIsOutgoing = it["outgoing"].as_bool(); + ptrA szUtf(mir_utf8encodeW(it["text"].as_mstring())); + + PROTORECVEVENT pre = {}; + pre.flags = (bIsOutgoing) ? PREF_SENT : 0; + pre.szMsgId = msgId; + pre.timestamp = it["time"].as_int(); + pre.szMessage = szUtf; + ProtoChainRecvMsg(hContact, &pre); +} + bool CIcqProto::RefreshRobustToken() { if (!m_szRToken.IsEmpty()) @@ -221,6 +259,31 @@ void CIcqProto::RetrieveUserInfo(MCONTACT hContact) Push(pReq); } +void CIcqProto::RetrieveUserHistory(MCONTACT hContact, __int64 startMsgId, __int64 endMsgId) +{ + if (startMsgId == 0) + startMsgId = -1; + if (endMsgId == 0) + endMsgId = -1; + + auto *pReq = new AsyncHttpRequest(CONN_RAPI, REQUEST_POST, ICQ_ROBUST_SERVER, &CIcqProto::OnGetUserHistory); + //pReq->flags |= NLHRF_NODUMPSEND; + pReq->pUserInfo = (void*)hContact; + + char buf[100]; + itoa(getDword(hContact, DB_KEY_UIN), buf, 10); + + JSONNode request, params; params.set_name("params"); + params << CHAR_PARAM("sn", buf) << INT64_PARAM("fromMsgId", startMsgId); + if (endMsgId != -1) + params << INT64_PARAM("tillMsgId", endMsgId); + params << INT_PARAM("count", -1000) << CHAR_PARAM("aimSid", m_aimsid) << CHAR_PARAM("patchVersion", "1") << CHAR_PARAM("language", "ru-ru"); + request << CHAR_PARAM("method", "getHistory") << CHAR_PARAM("reqId", pReq->m_reqId) << CHAR_PARAM("authToken", m_szRToken) + << INT_PARAM("clientId", m_iRClientId) << params; + pReq->m_szParam = ptrW(json_write(&request)); + Push(pReq); +} + void CIcqProto::SetServerStatus(int iStatus) { const char *szStatus = "online"; @@ -366,6 +429,28 @@ void CIcqProto::OnCheckPassword(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest*) StartSession(); } +void CIcqProto::OnGetUserHistory(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) +{ + MCONTACT hContact = (MCONTACT)pReq->pUserInfo; + + RobustReply root(pReply); + if (root.error() != 20000) + return; + + __int64 lastMsgId = getId(hContact, "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; + } + + setId(hContact, "LastMsgId", lastMsgId); +} + void CIcqProto::OnGetUserInfo(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq) { MCONTACT hContact = (MCONTACT)pReq->pUserInfo; @@ -536,41 +621,13 @@ void CIcqProto::ProcessHistData(const JSONNode &ev) MCONTACT hContact = CreateContact(dwUin, true); - for (auto &it : ev["tail"]["messages"]) { - CMStringA msgId(it["msgId"].as_mstring()); - CMStringW type(it["mediaType"].as_mstring()); - if (type != "text") - continue; - - // ignore duplicates - MEVENT hDbEvent = db_event_getById(m_szModuleName, msgId); - if (hDbEvent != 0) - continue; - - // skip own messages, just set the server msgid - bool bSkipped = false; - CMStringA reqId(it["reqId"].as_mstring()); - for (auto &ownMsg : m_arOwnIds) - if (!mir_strcmp(reqId, ownMsg->m_guid)) { - bSkipped = true; - if (m_bSlowSend) - ProtoBroadcastAck(ownMsg->m_hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)ownMsg->m_msgid, (LPARAM)msgId.c_str()); - m_arOwnIds.remove(m_arOwnIds.indexOf(&ownMsg)); - break; - } - - if (!bSkipped) { - bool bIsOutgoing = it["outgoing"].as_bool(); - ptrA szUtf(mir_utf8encodeW(it["text"].as_mstring())); + __int64 lastMsgId = getId(hContact, "LastMsgId"); + __int64 srvlastId = _wtoi64(ev["lastMsgId"].as_mstring()); + if (srvlastId > lastMsgId) + RetrieveUserHistory(hContact, srvlastId, lastMsgId); - PROTORECVEVENT pre = {}; - pre.flags = (bIsOutgoing) ? PREF_SENT : 0; - pre.szMsgId = msgId; - pre.timestamp = it["time"].as_int(); - pre.szMessage = szUtf; - ProtoChainRecvMsg(hContact, &pre); - } - } + for (auto &it : ev["tail"]["messages"]) + ParseMessage(hContact, it); } void CIcqProto::ProcessMyInfo(const JSONNode &ev) diff --git a/protocols/Icq10/src/utils.cpp b/protocols/Icq10/src/utils.cpp index f745387742..17f5510142 100644 --- a/protocols/Icq10/src/utils.cpp +++ b/protocols/Icq10/src/utils.cpp @@ -202,3 +202,24 @@ int StatusFromString(const CMStringW &wszStatus) return ID_STATUS_OFFLINE; } + +///////////////////////////////////////////////////////////////////////////////////////// + +__int64 CIcqProto::getId(MCONTACT hContact, const char *szSetting) +{ + DBVARIANT dbv; + dbv.type = DBVT_BLOB; + if (db_get(hContact, m_szModuleName, szSetting, &dbv)) + return 0; + + __int64 result = (dbv.cpbVal == sizeof(__int64)) ? *(__int64*)dbv.pbVal : 0; + db_free(&dbv); + return result; +} + +void CIcqProto::setId(MCONTACT hContact, const char *szSetting, __int64 iValue) +{ + __int64 oldVal = getId(hContact, szSetting); + if (oldVal != iValue) + db_set_blob(hContact, m_szModuleName, szSetting, &iValue, sizeof(iValue)); +} |