diff options
author | George Hazan <ghazan@miranda.im> | 2022-10-23 13:01:28 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2022-10-23 13:01:28 +0300 |
commit | 8834935d6dbfd190b0a39ac8f30cce571f08750e (patch) | |
tree | d04ee1d79df3b535aa5b502b18933cd77c0ff467 /protocols | |
parent | ee4c113c7ce309a92b39e2d8f9fcb8c73877aa65 (diff) |
WhatsApp: sending acks & read receipts
Diffstat (limited to 'protocols')
-rw-r--r-- | protocols/WhatsApp/src/appsync.cpp | 1 | ||||
-rw-r--r-- | protocols/WhatsApp/src/iq.cpp | 35 | ||||
-rw-r--r-- | protocols/WhatsApp/src/main.cpp | 12 | ||||
-rw-r--r-- | protocols/WhatsApp/src/message.cpp | 8 | ||||
-rw-r--r-- | protocols/WhatsApp/src/proto.h | 6 | ||||
-rw-r--r-- | protocols/WhatsApp/src/server.cpp | 17 | ||||
-rw-r--r-- | protocols/WhatsApp/src/stdafx.h | 1 |
7 files changed, 78 insertions, 2 deletions
diff --git a/protocols/WhatsApp/src/appsync.cpp b/protocols/WhatsApp/src/appsync.cpp index 9785dbff65..3659917ea2 100644 --- a/protocols/WhatsApp/src/appsync.cpp +++ b/protocols/WhatsApp/src/appsync.cpp @@ -46,6 +46,7 @@ void WhatsAppProto::OnServerSync(const WANode &node) task.insert(new WACollection(it->getAttr("name"), it->getAttrInt("version"))); ResyncServer(task); + SendAck(node); } void WhatsAppProto::ResyncAll() diff --git a/protocols/WhatsApp/src/iq.cpp b/protocols/WhatsApp/src/iq.cpp index 258b466ac3..063a71264c 100644 --- a/protocols/WhatsApp/src/iq.cpp +++ b/protocols/WhatsApp/src/iq.cpp @@ -14,6 +14,8 @@ void WhatsAppProto::OnAccountSync(const WANode &node) for (auto &it : node.getChild("devices")->getChildren()) if (it->title == "device") m_arDevices.insert(new WADevice(it->getAttr("jid"), it->getAttrInt("key-index"))); + + SendAck(node); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -84,6 +86,7 @@ void WhatsAppProto::OnNotifyDevices(const WANode &node) { if (!mir_strcmp(node.getAttr("jid"), m_szJid)) debugLogA("received list of my own devices"); + SendAck(node); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -92,6 +95,7 @@ void WhatsAppProto::OnNotifyEncrypt(const WANode &node) { if (!mir_strcmp(node.getAttr("from"), S_WHATSAPP_NET)) OnIqCountPrekeys(node); + SendAck(node); } ///////////////////////////////////////////////////////////////////////////////////////// @@ -119,6 +123,36 @@ void WhatsAppProto::OnReceiveInfo(const WANode &node) ///////////////////////////////////////////////////////////////////////////////////////// +void WhatsAppProto::ProcessReceipt(MCONTACT hContact, const char *msgId, bool bRead) +{ + MEVENT hEvent = db_event_getById(m_szModuleName, msgId); + if (hEvent == 0) + return; + + if (g_plugin.bHasMessageState) + CallService(MS_MESSAGESTATE_UPDATE, hContact, bRead ? MRD_TYPE_READ : MRD_TYPE_DELIVERED); + + if (bRead) + db_event_markRead(hContact, hEvent); +} + +void WhatsAppProto::OnReceiveReceipt(const WANode &node) +{ + if (auto *pUser = FindUser(node.getAttr("from"))) { + bool bRead = mir_strcmp(node.getAttr("type"), "read") == 0; + ProcessReceipt(pUser->hContact, node.getAttr("id"), bRead); + + if (auto *pList = node.getChild("list")) + for (auto &it : pList->getChildren()) + if (it->title == "item") + ProcessReceipt(pUser->hContact, it->getAttr("id"), bRead); + } + + SendAck(node); +} + +///////////////////////////////////////////////////////////////////////////////////////// + void WhatsAppProto::OnStreamError(const WANode &node) { m_bTerminated = true; @@ -436,6 +470,7 @@ void WhatsAppProto::InitPersistentHandlers() m_arPersistent.insert(new WAPersistentHandler("ib", 0, 0, 0, &WhatsAppProto::OnReceiveInfo)); m_arPersistent.insert(new WAPersistentHandler("message", 0, 0, 0, &WhatsAppProto::OnReceiveMessage)); + m_arPersistent.insert(new WAPersistentHandler("receipt", 0, 0, 0, &WhatsAppProto::OnReceiveReceipt)); m_arPersistent.insert(new WAPersistentHandler("stream:error", 0, 0, 0, &WhatsAppProto::OnStreamError)); m_arPersistent.insert(new WAPersistentHandler("success", 0, 0, 0, &WhatsAppProto::OnSuccess)); diff --git a/protocols/WhatsApp/src/main.cpp b/protocols/WhatsApp/src/main.cpp index ffd3766719..99bf1e37f8 100644 --- a/protocols/WhatsApp/src/main.cpp +++ b/protocols/WhatsApp/src/main.cpp @@ -45,11 +45,19 @@ CMPlugin::CMPlugin() : ///////////////////////////////////////////////////////////////////////////////////////// // Load +static int OnPluginLoaded(WPARAM, LPARAM) +{ + g_plugin.bHasMessageState = ServiceExists(MS_MESSAGESTATE_UPDATE); + return 0; +} + int CMPlugin::Load() { - // InitIcons(); - // InitContactMenus(); + HookEvent(ME_SYSTEM_MODULELOAD, OnPluginLoaded); + HookEvent(ME_SYSTEM_MODULEUNLOAD, OnPluginLoaded); + OnPluginLoaded(0, 0); + // special netlib user for reading avatars, blobs etc via HTTP protocol NETLIBUSER nlu = {}; nlu.flags = NUF_INCOMING | NUF_OUTGOING | NUF_HTTPCONNS | NUF_UNICODE; nlu.szSettingsModule = "WhatsApp"; diff --git a/protocols/WhatsApp/src/message.cpp b/protocols/WhatsApp/src/message.cpp index 1952e57fc4..abaaa89faf 100644 --- a/protocols/WhatsApp/src/message.cpp +++ b/protocols/WhatsApp/src/message.cpp @@ -21,6 +21,14 @@ void WhatsAppProto::OnReceiveMessage(const WANode &node) return; } + MEVENT hEvent = db_event_getById(m_szModuleName, msgId); + if (hEvent) { + debugLogA("this message is already processed: %s", msgId); + return; + } + + SendAck(node); + WAMSG type; WAJid jid(msgFrom); CMStringA szAuthor, szChatId; diff --git a/protocols/WhatsApp/src/proto.h b/protocols/WhatsApp/src/proto.h index a5b6a60f57..35200ad61e 100644 --- a/protocols/WhatsApp/src/proto.h +++ b/protocols/WhatsApp/src/proto.h @@ -305,6 +305,8 @@ class WhatsAppProto : public PROTO<WhatsAppProto> CMStringA GenerateMessageId(); void ProcessMessage(WAMSG type, const proto::WebMessageInfo &msg); + void ProcessReceipt(MCONTACT hContact, const char *msgId, bool bRead); + bool WSReadPacket(const WSHeader &hdr, MBinBuffer &buf); int WSSend(const MessageLite &msg); int WSSendNode(WANode &node, WA_PKT_HANDLER = nullptr); @@ -317,6 +319,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto> void ServerThreadWorker(void); void ShutdownSession(void); + void SendAck(const WANode &node); void SendReceipt(const char *pszTo, const char *pszParticipant, const char *pszId, const char *pszType); void SendKeepAlive(); void SetServerStatus(int iStatus); @@ -350,6 +353,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto> void OnNotifyEncrypt(const WANode &node); void OnReceiveInfo(const WANode &node); void OnReceiveMessage(const WANode &node); + void OnReceiveReceipt(const WANode &node); void OnServerSync(const WANode &node); void OnStreamError(const WANode &node); void OnSuccess(const WANode &node); @@ -426,6 +430,8 @@ struct CMPlugin : public ACCPROTOPLUGIN<WhatsAppProto> HNETLIBCONN hAvatarConn = nullptr; bool SaveFile(const char *pszUrl, PROTO_AVATAR_INFORMATION &ai); + bool bHasMessageState = false; + CMPlugin(); int Load() override; diff --git a/protocols/WhatsApp/src/server.cpp b/protocols/WhatsApp/src/server.cpp index efe293c5b0..f5590a4e77 100644 --- a/protocols/WhatsApp/src/server.cpp +++ b/protocols/WhatsApp/src/server.cpp @@ -262,6 +262,23 @@ void WhatsAppProto::OnLoggedOut(void) setAllContactStatuses(ID_STATUS_OFFLINE, false); } +///////////////////////////////////////////////////////////////////////////////////////// +// Service packets sending + +void WhatsAppProto::SendAck(const WANode &node) +{ + WANode ack("ack"); + ack << CHAR_PARAM("to", node.getAttr("from")) << CHAR_PARAM("id", node.getAttr("id")) << CHAR_PARAM("class", node.title); + if (node.title != "message") + if (auto *param = node.getAttr("type")) + ack << CHAR_PARAM("type", param); + if (auto *param = node.getAttr("participant")) + ack << CHAR_PARAM("participant", param); + if (auto *param = node.getAttr("recipient")) + ack << CHAR_PARAM("recipient", param); + WSSendNode(ack); +} + void WhatsAppProto::SendKeepAlive() { time_t now = time(0); diff --git a/protocols/WhatsApp/src/stdafx.h b/protocols/WhatsApp/src/stdafx.h index 80d130a5ec..73fc82d435 100644 --- a/protocols/WhatsApp/src/stdafx.h +++ b/protocols/WhatsApp/src/stdafx.h @@ -46,6 +46,7 @@ Copyright © 2019-22 George Hazan #include <m_folders.h> #include <m_json.h> #include <m_gui.h> +#include <m_messagestate.h> #include <openssl/evp.h> #include <openssl/hmac.h> |