summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2018-12-24 23:18:05 +0300
committerGeorge Hazan <ghazan@miranda.im>2018-12-24 23:18:05 +0300
commit3a83739020479978041031e566b5269fbef5de9f (patch)
treef945a1dabe2445eb5b9a5c715f708f460f176c85
parent6e439e6cab64aaefc5220facac6df88cccef6cf7 (diff)
Icq10:
- now we can send messages & sort dups out; - code reorganizing
-rw-r--r--protocols/Icq10/src/http.cpp18
-rw-r--r--protocols/Icq10/src/http.h2
-rw-r--r--protocols/Icq10/src/proto.cpp22
-rw-r--r--protocols/Icq10/src/proto.h20
-rw-r--r--protocols/Icq10/src/server.cpp43
5 files changed, 84 insertions, 21 deletions
diff --git a/protocols/Icq10/src/http.cpp b/protocols/Icq10/src/http.cpp
index 15835d7052..c7a183fa3c 100644
--- a/protocols/Icq10/src/http.cpp
+++ b/protocols/Icq10/src/http.cpp
@@ -44,7 +44,7 @@ void __cdecl CIcqProto::ServerThread(void*)
m_szSessionKey = getMStringA("SessionKey");
if (m_szAToken.IsEmpty() || m_szSessionKey.IsEmpty()) {
auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, "https://api.login.icq.net/auth/clientLogin", &CIcqProto::OnCheckPassword);
- pReq << CHAR_PARAM("clientName", "Miranda NG") << CHAR_PARAM("clientVersion", mirVer) << CHAR_PARAM("devId", "ic1nmMjqg7Yu-0hL")
+ pReq << CHAR_PARAM("clientName", "Miranda NG") << CHAR_PARAM("clientVersion", mirVer) << CHAR_PARAM("devId", ICQ_APP_ID)
<< CHAR_PARAM("f", "json") << CHAR_PARAM("tokenType", "longTerm") << INT_PARAM("s", uin) << CHAR_PARAM("pwd", szPassword);
pReq->flags |= NLHRF_NODUMPSEND;
Push(pReq);
@@ -98,7 +98,14 @@ AsyncHttpRequest::AsyncHttpRequest(IcqConnection conn, int iType, const char *sz
requestType = iType;
m_szUrl = szUrl;
m_pFunc = pFunc;
- UuidCreate(&m_reqId);
+
+ GUID packetId;
+ UuidCreate(&packetId);
+
+ RPC_CSTR szId;
+ UuidToStringA(&packetId, &szId);
+ strncpy_s(m_reqId, (char*)szId, _TRUNCATE);
+ RpcStringFreeA(&szId);
if (iType == REQUEST_POST) {
AddHeader("Content-Type", "application/x-www-form-urlencoded");
@@ -129,9 +136,7 @@ void CIcqProto::ExecuteRequest(AsyncHttpRequest *pReq)
pReq->nlc = m_ConnPool[pReq->m_conn];
}
- RPC_CSTR szId;
- UuidToStringA(&pReq->m_reqId, &szId);
- debugLogA("Executing request %s:\n%s", (char*)szId, pReq->szUrl);
+ debugLogA("Executing request %s:\n%s", pReq->m_reqId, pReq->szUrl);
NETLIBHTTPREQUEST *reply = Netlib_HttpTransaction(m_hNetlibUser, pReq);
if (reply != nullptr) {
@@ -144,7 +149,7 @@ void CIcqProto::ExecuteRequest(AsyncHttpRequest *pReq)
Netlib_FreeHttpRequest(reply);
}
else {
- debugLogA("Request %s failed", (char*)szId);
+ debugLogA("Request %s failed", pReq->m_reqId);
if (pReq->m_conn != CONN_NONE) {
if (IsStatusConnecting(m_iStatus))
@@ -153,7 +158,6 @@ void CIcqProto::ExecuteRequest(AsyncHttpRequest *pReq)
}
}
- RpcStringFreeA(&szId);
delete pReq;
}
diff --git a/protocols/Icq10/src/http.h b/protocols/Icq10/src/http.h
index 574ed55130..374836ad7c 100644
--- a/protocols/Icq10/src/http.h
+++ b/protocols/Icq10/src/http.h
@@ -9,7 +9,7 @@ enum IcqConnection
struct AsyncHttpRequest : public MTHttpRequest<CIcqProto>
{
IcqConnection m_conn;
- GUID m_reqId;
+ char m_reqId[50];
AsyncHttpRequest(IcqConnection, int type, const char *szUrl, MTHttpRequestHandler pFunc = nullptr);
};
diff --git a/protocols/Icq10/src/proto.cpp b/protocols/Icq10/src/proto.cpp
index 2bf99132f6..89a9cd8006 100644
--- a/protocols/Icq10/src/proto.cpp
+++ b/protocols/Icq10/src/proto.cpp
@@ -36,6 +36,7 @@
CIcqProto::CIcqProto(const char* aProtoName, const wchar_t* aUserName) :
PROTO<CIcqProto>(aProtoName, aUserName),
m_arHttpQueue(10),
+ m_arOwnIds(1),
m_arCache(20, NumericKeySortT),
m_evRequestsQueue(CreateEvent(nullptr, FALSE, FALSE, nullptr))
{
@@ -57,8 +58,6 @@ CIcqProto::CIcqProto(const char* aProtoName, const wchar_t* aUserName) :
CIcqProto::~CIcqProto()
{
- m_arCache.destroy();
- m_arHttpQueue.destroy();
::CloseHandle(m_evRequestsQueue);
}
@@ -176,7 +175,7 @@ INT_PTR CIcqProto::GetCaps(int type, MCONTACT hContact)
PF2_FREECHAT | PF2_INVISIBLE;
case PFLAGNUM_4:
- nReturn = PF4_SUPPORTIDLE | PF4_IMSENDOFFLINE | PF4_INFOSETTINGSVC | PF4_SUPPORTTYPING | PF4_AVATARS;
+ nReturn = PF4_SUPPORTIDLE | PF4_IMSENDOFFLINE | PF4_INFOSETTINGSVC | PF4_SUPPORTTYPING | PF4_AVATARS | PF4_SERVERMSGID;
break;
case PFLAGNUM_5:
@@ -260,9 +259,22 @@ HANDLE CIcqProto::SendFile(MCONTACT hContact, const wchar_t* szDescription, wcha
////////////////////////////////////////////////////////////////////////////////////////
// PS_SendMessage - sends a message
-int CIcqProto::SendMsg(MCONTACT hContact, int, const char* pszSrc)
+int CIcqProto::SendMsg(MCONTACT hContact, int, const char *pszSrc)
{
- return NULL;
+ DWORD dwUin = getDword(hContact, "UIN");
+ if (dwUin == 0)
+ return 0;
+
+ int id = InterlockedIncrement(&m_msgId);
+ auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/im/sendIM", &CIcqProto::OnSendMessage);
+ pReq->pUserInfo = new IcqOwnMessage(hContact, id, pReq->m_reqId);
+
+ pReq << CHAR_PARAM("a", m_szAToken) << CHAR_PARAM("aimsid", m_aimsid) << CHAR_PARAM("f", "json") << CHAR_PARAM("k", ICQ_APP_ID)
+ << CHAR_PARAM("mentions", "") << CHAR_PARAM("message", pszSrc) << CHAR_PARAM("nonce", pReq->m_reqId) << CHAR_PARAM("offlineIM", "true")
+ << INT_PARAM("t", dwUin) << INT_PARAM("ts", time(0));
+
+ Push(pReq);
+ return id;
}
////////////////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/Icq10/src/proto.h b/protocols/Icq10/src/proto.h
index 3239d4b7a1..8bf9cbfb91 100644
--- a/protocols/Icq10/src/proto.h
+++ b/protocols/Icq10/src/proto.h
@@ -33,6 +33,9 @@
#include "m_system.h"
#include "m_protoint.h"
+#define ICQ_API_SERVER "https://api.icq.net"
+#define ICQ_APP_ID "ic1nmMjqg7Yu-0hL"
+
struct IcqCacheItem
{
IcqCacheItem(DWORD _uin, MCONTACT _contact) :
@@ -45,6 +48,19 @@ struct IcqCacheItem
bool m_bInList = false;
};
+struct IcqOwnMessage
+{
+ IcqOwnMessage(MCONTACT _hContact, int _msgid, const char *guid)
+ : m_hContact(_hContact), m_msgid(_msgid)
+ {
+ strncpy_s(m_guid, guid, _TRUNCATE);
+ }
+
+ MCONTACT m_hContact;
+ int m_msgid;
+ char m_guid[50];
+};
+
class CIcqProto : public PROTO<CIcqProto>
{
bool m_bOnline = false, m_bTerminated = false;
@@ -58,6 +74,7 @@ class CIcqProto : public PROTO<CIcqProto>
void OnCheckPassword(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnFetchEvents(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnReceiveAvatar(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
+ void OnSendMessage(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void OnStartSession(NETLIBHTTPREQUEST*, AsyncHttpRequest*);
void ProcessBuddyList(const JSONNode&);
@@ -72,6 +89,9 @@ class CIcqProto : public PROTO<CIcqProto>
CMStringA m_szAToken;
CMStringA m_fetchBaseURL;
CMStringA m_aimsid;
+ LONG m_msgId = 1;
+
+ OBJLIST<IcqOwnMessage> m_arOwnIds;
//////////////////////////////////////////////////////////////////////////////////////
// http queue
diff --git a/protocols/Icq10/src/server.cpp b/protocols/Icq10/src/server.cpp
index 3743e983a1..e8cf0b0d48 100644
--- a/protocols/Icq10/src/server.cpp
+++ b/protocols/Icq10/src/server.cpp
@@ -95,16 +95,13 @@ void CIcqProto::StartSession()
int ts = time(0);
CMStringA nonce(FORMAT, "%d-2", ts);
- auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, "https://api.icq.net/aim/startSession", &CIcqProto::OnStartSession);
-
- RPC_CSTR szId;
- UuidToStringA(&pReq->m_reqId, &szId);
+ auto *pReq = new AsyncHttpRequest(CONN_MAIN, REQUEST_POST, ICQ_API_SERVER "/aim/startSession", &CIcqProto::OnStartSession);
pReq << CHAR_PARAM("a", m_szAToken) << INT_PARAM("activeTimeout", 180) << CHAR_PARAM("assertCaps", CAPS)
<< INT_PARAM("buildNumber", __BUILD_NUM) << CHAR_PARAM("deviceId", szDeviceId) << CHAR_PARAM("events", EVENTS)
<< CHAR_PARAM("f", "json") << CHAR_PARAM("imf", "plain") << CHAR_PARAM("inactiveView", "offline")
<< CHAR_PARAM("includePresenceFields", FIELDS) << CHAR_PARAM("invisible", "false")
- << CHAR_PARAM("k", "ic1nmMjqg7Yu-0hL") << INT_PARAM("mobile", 0) << CHAR_PARAM("nonce", nonce) << CHAR_PARAM("r", (char*)szId)
+ << CHAR_PARAM("k", ICQ_APP_ID) << INT_PARAM("mobile", 0) << CHAR_PARAM("nonce", nonce) << CHAR_PARAM("r", pReq->m_reqId)
<< INT_PARAM("rawMsg", 0) << INT_PARAM("sessionTimeout", 7776000) << INT_PARAM("ts", ts) << CHAR_PARAM("view", "online");
CMStringA hashData(FORMAT, "POST&%s&%s", ptrA(mir_urlEncode(pReq->m_szUrl)), ptrA(mir_urlEncode(pReq->m_szParam)));
@@ -114,7 +111,6 @@ void CIcqProto::StartSession()
pReq << CHAR_PARAM("sig_sha256", ptrA(mir_base64_encode(hashOut, sizeof(hashOut))));
Push(pReq);
- RpcStringFreeA(&szId);
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -206,6 +202,23 @@ void CIcqProto::OnReceiveAvatar(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pRe
else ProtoBroadcastAck(hContact, ACKTYPE_AVATAR, ACKRESULT_FAILED, HANDLE(&ai), 0);
}
+void CIcqProto::OnSendMessage(NETLIBHTTPREQUEST *pReply, AsyncHttpRequest *pReq)
+{
+ IcqOwnMessage *ownMsg = (IcqOwnMessage*)pReq->pUserInfo;
+
+ JsonReply root(pReply);
+ if (root.error() != 200) {
+ ProtoBroadcastAck(ownMsg->m_hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)ownMsg->m_msgid, 0);
+ delete ownMsg;
+ return;
+ }
+
+ JSONNode &data = root.data();
+ CMStringA msgId(data["msgId"].as_mstring());
+ strncpy_s(ownMsg->m_guid, msgId, _TRUNCATE);
+ m_arOwnIds.insert(ownMsg);
+}
+
/////////////////////////////////////////////////////////////////////////////////////////
void CIcqProto::ProcessBuddyList(const JSONNode &ev)
@@ -298,8 +311,22 @@ void CIcqProto::ProcessHistData(const JSONNode &ev)
if (type != "text")
continue;
+ // ignore duplicates
MEVENT hDbEvent = db_event_getById(m_szModuleName, msgId);
- if (hDbEvent == 0) {
+ 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;
+ ProtoBroadcastAck(ownMsg->m_hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)ownMsg->m_msgid, (LPARAM)msgId.c_str());
+ break;
+ }
+
+ if (!bSkipped) {
bool bIsOutgoing = it["outgoing"].as_bool();
ptrA szUtf(mir_utf8encodeW(it["text"].as_mstring()));
@@ -386,4 +413,4 @@ void __cdecl CIcqProto::PollThread(void*)
debugLogA("Polling thread ended");
m_hPollThread = nullptr;
-} \ No newline at end of file
+}