summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-01-03 22:08:25 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-01-03 22:08:25 +0300
commit411df60e2845f9ddfe3e68043d603d64c3bf62a5 (patch)
tree635f5705deb63379b4b30f6aa21414778b086228
parentca6eff4cc054b80e91b98ad25a30515a54084c3e (diff)
fixes #1670 (ICQ10: server history loading)
-rw-r--r--protocols/Icq10/src/proto.h6
-rw-r--r--protocols/Icq10/src/server.cpp125
-rw-r--r--protocols/Icq10/src/utils.cpp21
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));
+}