summaryrefslogtreecommitdiff
path: root/protocols
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2022-10-23 13:01:28 +0300
committerGeorge Hazan <ghazan@miranda.im>2022-10-23 13:01:28 +0300
commit8834935d6dbfd190b0a39ac8f30cce571f08750e (patch)
treed04ee1d79df3b535aa5b502b18933cd77c0ff467 /protocols
parentee4c113c7ce309a92b39e2d8f9fcb8c73877aa65 (diff)
WhatsApp: sending acks & read receipts
Diffstat (limited to 'protocols')
-rw-r--r--protocols/WhatsApp/src/appsync.cpp1
-rw-r--r--protocols/WhatsApp/src/iq.cpp35
-rw-r--r--protocols/WhatsApp/src/main.cpp12
-rw-r--r--protocols/WhatsApp/src/message.cpp8
-rw-r--r--protocols/WhatsApp/src/proto.h6
-rw-r--r--protocols/WhatsApp/src/server.cpp17
-rw-r--r--protocols/WhatsApp/src/stdafx.h1
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>