summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--protocols/WhatsApp/src/iq.cpp43
-rw-r--r--protocols/WhatsApp/src/message.cpp46
-rw-r--r--protocols/WhatsApp/src/proto.cpp1
-rw-r--r--protocols/WhatsApp/src/proto.h18
-rw-r--r--protocols/WhatsApp/src/server.cpp4
-rw-r--r--protocols/WhatsApp/src/signal.cpp10
6 files changed, 72 insertions, 50 deletions
diff --git a/protocols/WhatsApp/src/iq.cpp b/protocols/WhatsApp/src/iq.cpp
index c3f4ba2a38..ccc9ad6f1a 100644
--- a/protocols/WhatsApp/src/iq.cpp
+++ b/protocols/WhatsApp/src/iq.cpp
@@ -9,12 +9,14 @@ Copyright © 2019-22 George Hazan
void WhatsAppProto::OnAccountSync(const WANode &node)
{
- m_arDevices.destroy();
+ if (auto *pList = node.getChild("devices")) {
+ auto *pUser = FindUser(m_szJid);
+ pUser->arDevices.destroy();
- if (auto *pList = node.getChild("devices"))
for (auto &it : pList->getChildren())
if (it->title == "device")
- m_arDevices.insert(new WAJid(it->getAttr("jid"), it->getAttrInt("key-index")));
+ pUser->arDevices.insert(new WAJid(it->getAttr("jid"), it->getAttrInt("key-index")));
+ }
if (auto *pList = node.getChild("blocklist"))
for (auto &it : pList->getChildren())
@@ -94,35 +96,42 @@ void WhatsAppProto::OnIqGetKeys(const WANode &node, void *pUserInfo)
{
for (auto &it : node.getChild("list")->getChildren())
if (it->title == "user")
- m_signalStore.injectSession(it);
+ m_signalStore.injectSession(it->getAttr("jid"), it, it);
// don't forget to send delayed message when all keys are retrieved
if (pUserInfo)
- SendTask((WASendTask *)pUserInfo);
+ FinishTask((WASendTask *)pUserInfo);
}
/////////////////////////////////////////////////////////////////////////////////////////
-void WhatsAppProto::OnIqGetUsync(const WANode &node)
+void WhatsAppProto::OnIqGetUsync(const WANode &node, void *pUserInfo)
{
- m_arDevices.destroy();
-
if (auto *nUser = node.getChild("usync")->getChild("list")->getChild("user")) {
auto *pszJid = nUser->getAttr("jid");
+
+ auto *pUser = AddUser(pszJid, false);
+ pUser->bDeviceInit = true;
+ pUser->arDevices.destroy();
+
if (auto *pList = nUser->getChild("devices")->getChild("device-list"))
for (auto &it : pList->getChildren())
if (it->title == "device")
- m_arDevices.insert(new WAJid(pszJid, it->getAttrInt("id")));
+ pUser->arDevices.insert(new WAJid(pszJid, it->getAttrInt("id")));
WANodeIq iq(IQ::GET, "encrypt");
auto *pKey = iq.addChild("key");
- for (auto &it : m_arDevices) {
+ for (auto &it : pUser->arDevices) {
auto blob = getBlob(MSignalSession(it->user, it->device).getSetting());
if (blob.isEmpty())
pKey->addChild("user")->addAttr("jid", it->toString());
}
+
if (pKey->getChildren().getCount() > 0)
- WSSendNode(iq, &WhatsAppProto::OnIqGetKeys, nullptr);
+ WSSendNode(iq, &WhatsAppProto::OnIqGetKeys, pUserInfo);
+ else if (pUserInfo)
+ FinishTask((WASendTask *)pUserInfo);
+
}
}
@@ -460,8 +469,9 @@ void WhatsAppProto::OnReceiveInfo(const WANode &node)
if (!m_bUpdatedPrekeys)
WSSendNode(WANodeIq(IQ::GET, "encrypt") << XCHILD("count"), &WhatsAppProto::OnIqCountPrekeys);
- if (m_arDevices.getCount() == 0)
- SendUsync(m_szJid);
+ auto *pUser = FindUser(m_szJid);
+ if (pUser->arDevices.getCount() == 0)
+ SendUsync(m_szJid, nullptr);
for (auto &it : m_arCollections) {
if (it->version == 0) {
@@ -491,6 +501,13 @@ void WhatsAppProto::ProcessReceipt(MCONTACT hContact, const char *msgId, bool bR
void WhatsAppProto::OnReceiveReceipt(const WANode &node)
{
+ if (!mir_strcmp(node.getAttr("type"), "retry")) {
+ for (auto &it : node.getChildren())
+ if (it->title == "keys")
+ m_signalStore.injectSession(node.getAttr("from"), &node, it);
+ return;
+ }
+
if (auto *pUser = FindUser(node.getAttr("from"))) {
bool bRead = mir_strcmp(node.getAttr("type"), "read") == 0;
ProcessReceipt(pUser->hContact, node.getAttr("id"), bRead);
diff --git a/protocols/WhatsApp/src/message.cpp b/protocols/WhatsApp/src/message.cpp
index 41b5cf92a6..2c9149c45b 100644
--- a/protocols/WhatsApp/src/message.cpp
+++ b/protocols/WhatsApp/src/message.cpp
@@ -200,7 +200,8 @@ void WhatsAppProto::ProcessMessage(WAMSG type, const Wa__WebMessageInfo &msg)
else
chatId = (participant) ? participant : key->remotejid;
- WAUser *pUser = AddUser(chatId, false);
+ WAJid jidFrom(chatId); jidFrom.device = 0;
+ WAUser *pUser = AddUser(jidFrom.toString(), false);
if (!key->fromme && msg.pushname && pUser && !pUser->bIsGroupChat)
setUString(pUser->hContact, "Nick", msg.pushname);
@@ -373,6 +374,7 @@ int WhatsAppProto::SendTextMessage(const char *jid, const char *pszMsg)
Wa__Message body;
body.extendedtextmessage = &extMessage;
+ bool bNeedsCheck = false;
if (toJid.isGroup()) {
MBinBuffer encodedMsg(proto::Serialize(&body));
padBuffer16(encodedMsg);
@@ -410,24 +412,22 @@ int WhatsAppProto::SendTextMessage(const char *jid, const char *pszMsg)
pTask->content.append(proto::Serialize(&msg));
- pTask->arDest.insert(new WAJid(toJid));
+ if (auto *pUser = FindUser(jid)) {
+ if (pUser->bDeviceInit) {
+ for (auto &it : pUser->arDevices)
+ pTask->arDest.insert(new WAJid(*it));
+ }
+ else bNeedsCheck = true;
+ }
}
padBuffer16(pTask->content);
- for (auto &it : m_arDevices)
+ auto *pOwnUser = FindUser(m_szJid);
+ for (auto &it : pOwnUser->arDevices)
if (it->device != (int)getDword(DBKEY_DEVICE_ID))
pTask->arDest.insert(new WAJid(*it));
- // check session presence first
- LIST<WAJid> missingKeys(1);
- for (auto &it : pTask->arDest) {
- MSignalSession tmp(it->user, it->device);
- auto blob = getBlob(tmp.getSetting());
- if (blob.isEmpty())
- missingKeys.insert(it);
- }
-
// generate & reserve packet id
int pktId;
{
@@ -437,19 +437,23 @@ int WhatsAppProto::SendTextMessage(const char *jid, const char *pszMsg)
}
// if some keys are missing, schedule task for execution & retrieve keys
- if (missingKeys.getCount()) {
- WANodeIq iq(IQ::GET, "encrypt");
- auto *pKey = iq.addChild("key");
- for (auto &it: missingKeys)
- pKey->addChild("user")->addAttr("jid", it->toString());
- WSSendNode(iq, &WhatsAppProto::OnIqGetKeys, pTask);
- }
- // otherwise simply execute the task
- else SendTask(pTask);
+ if (bNeedsCheck)
+ SendUsync(jid, pTask);
+ else // otherwise simply execute the task
+ SendTask(pTask);
return pktId;
}
+void WhatsAppProto::FinishTask(WASendTask *pTask)
+{
+ if (auto *pUser = FindUser(pTask->payLoad.getAttr("to")))
+ for (auto &it : pUser->arDevices)
+ pTask->arDest.insert(new WAJid(*it));
+
+ SendTask(pTask);
+}
+
void WhatsAppProto::SendTask(WASendTask *pTask)
{
// pack all data and send the whole payload
diff --git a/protocols/WhatsApp/src/proto.cpp b/protocols/WhatsApp/src/proto.cpp
index ac6562450c..235b610817 100644
--- a/protocols/WhatsApp/src/proto.cpp
+++ b/protocols/WhatsApp/src/proto.cpp
@@ -44,7 +44,6 @@ WhatsAppProto::WhatsAppProto(const char *proto_name, const wchar_t *username) :
m_szJid(getMStringA(DBKEY_ID)),
m_tszDefaultGroup(getWStringA(DBKEY_DEF_GROUP)),
m_arUsers(10, CompareUsers),
- m_arDevices(1),
m_arOwnMsgs(1, CompareOwnMsgs),
m_arPersistent(1),
m_arPacketQueue(10, CompareRequests),
diff --git a/protocols/WhatsApp/src/proto.h b/protocols/WhatsApp/src/proto.h
index a699c91481..b192696410 100644
--- a/protocols/WhatsApp/src/proto.h
+++ b/protocols/WhatsApp/src/proto.h
@@ -107,7 +107,8 @@ struct WAUser
WAUser(MCONTACT _1, const char *_2, bool _3 = false) :
hContact(_1),
szId(mir_strdup(_2)),
- bIsGroupChat(_3)
+ bIsGroupChat(_3),
+ arDevices(1)
{
}
@@ -119,8 +120,9 @@ struct WAUser
MCONTACT hContact;
DWORD dwModifyTag = 0;
char *szId;
- bool bInited = false, bIsGroupChat;
+ bool bInited = false, bIsGroupChat, bDeviceInit = false;
SESSION_INFO *si = 0;
+ OBJLIST<WAJid> arDevices;
time_t m_timer1 = 0, m_timer2 = 0;
};
@@ -236,7 +238,7 @@ public:
MSignalSession* createSession(const CMStringA &szName, int deviceId);
MSignalSession* getSession(const signal_protocol_address *address);
- void injectSession(const WANode *pNode);
+ void injectSession(const char *szJid, const WANode *pNode, const WANode *pKey);
MBinBuffer decryptSignalProto(const CMStringA &from, const char *pszType, const MBinBuffer &encrypted);
MBinBuffer decryptGroupSignalProto(const CMStringA &from, const CMStringA &author, const MBinBuffer &encrypted);
@@ -315,8 +317,6 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
mir_cs m_csOwnMessages;
OBJLIST<WAOwnMessage> m_arOwnMsgs;
- OBJLIST<WAJid> m_arDevices;
-
WAUser* FindUser(const char *szId);
WAUser* AddUser(const char *szId, bool bTemporary);
@@ -372,11 +372,13 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
void SendAck(const WANode &node);
void SendReceipt(const char *pszTo, const char *pszParticipant, const char *pszId, const char *pszType);
void SendKeepAlive();
- void SendTask(WASendTask *pTask);
int SendTextMessage(const char *jid, const char *pszMsg);
- void SendUsync(const char *jid);
+ void SendUsync(const char *jid, void *pUserInfo);
void SetServerStatus(int iStatus);
+ void FinishTask(WASendTask *pTask);
+ void SendTask(WASendTask *pTask);
+
/// Popups /////////////////////////////////////////////////////////////////////////////
HANDLE m_hPopupClass;
@@ -397,7 +399,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
void OnIqGcGetAllMetadata(const WANode &node);
void OnIqGetAvatar(const WANode &node);
void OnIqGetKeys(const WANode &node, void *pUserInfo);
- void OnIqGetUsync(const WANode &node);
+ void OnIqGetUsync(const WANode &node, void *pUserInfo);
void OnIqPairDevice(const WANode &node);
void OnIqPairSuccess(const WANode &node);
void OnIqResult(const WANode &node);
diff --git a/protocols/WhatsApp/src/server.cpp b/protocols/WhatsApp/src/server.cpp
index 1fce9ed3a7..df9e3ec86e 100644
--- a/protocols/WhatsApp/src/server.cpp
+++ b/protocols/WhatsApp/src/server.cpp
@@ -399,7 +399,7 @@ void WhatsAppProto::SetServerStatus(int iStatus)
&WhatsAppProto::OnIqDoNothing);
}
-void WhatsAppProto::SendUsync(const char *jid)
+void WhatsAppProto::SendUsync(const char *jid, void *pUserInfo)
{
WANodeIq iq(IQ::GET, "usync");
@@ -410,7 +410,7 @@ void WhatsAppProto::SendUsync(const char *jid)
pNode1->addChild("query")->addChild("devices")->addAttr("version", "2");
pNode1->addChild("list")->addChild("user")->addAttr("jid", jid);
- WSSendNode(iq, &WhatsAppProto::OnIqGetUsync);
+ WSSendNode(iq, &WhatsAppProto::OnIqGetUsync, pUserInfo);
}
/////////////////////////////////////////////////////////////////////////////////////////
diff --git a/protocols/WhatsApp/src/signal.cpp b/protocols/WhatsApp/src/signal.cpp
index 3da969a722..b94a3452e4 100644
--- a/protocols/WhatsApp/src/signal.cpp
+++ b/protocols/WhatsApp/src/signal.cpp
@@ -542,12 +542,12 @@ void MSignalStore::importPublicKey(ec_public_key **result, MBinBuffer &buf)
curve_decode_point(result, buf.data(), buf.length(), m_pContext);
}
-void MSignalStore::injectSession(const WANode *pNode)
+void MSignalStore::injectSession(const char *szJid, const WANode *pNode, const WANode *pKey)
{
- WAJid jid(pNode->getAttr("jid"));
- auto *signedKey = pNode->getChild("skey");
- auto *key = pNode->getChild("key");
- auto *identity = pNode->getChild("identity");
+ WAJid jid(szJid);
+ auto *signedKey = pKey->getChild("skey");
+ auto *key = pKey->getChild("key");
+ auto *identity = pKey->getChild("identity");
auto *registration = pNode->getChild("registration");
if (!signedKey || !key || !identity || !registration) {
pProto->debugLogA("Bad key data for %s", jid.toString().c_str());