summaryrefslogtreecommitdiff
path: root/protocols/WhatsAppWeb
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/WhatsAppWeb')
-rw-r--r--protocols/WhatsAppWeb/src/chats.cpp4
-rw-r--r--protocols/WhatsAppWeb/src/proto.cpp16
-rw-r--r--protocols/WhatsAppWeb/src/proto.h19
-rw-r--r--protocols/WhatsAppWeb/src/server.cpp74
-rw-r--r--protocols/WhatsAppWeb/src/stdafx.h3
-rw-r--r--protocols/WhatsAppWeb/src/utils.cpp107
-rw-r--r--protocols/WhatsAppWeb/src/utils.h34
7 files changed, 176 insertions, 81 deletions
diff --git a/protocols/WhatsAppWeb/src/chats.cpp b/protocols/WhatsAppWeb/src/chats.cpp
index d8837aff43..e5d4fa89a4 100644
--- a/protocols/WhatsAppWeb/src/chats.cpp
+++ b/protocols/WhatsAppWeb/src/chats.cpp
@@ -7,9 +7,9 @@ Copyright © 2019 George Hazan
#include "stdafx.h"
-void WhatsAppProto::InitChat(WAUser *pUser, const JSONNode &pRoot)
+void WhatsAppProto::InitChat(WAUser *pUser, const WANode *pRoot)
{
- CMStringW wszId(pRoot["jid"].as_mstring()), wszNick(pRoot["name"].as_mstring());
+ CMStringW wszId(Utf2T(pRoot->getAttr("jid"))), wszNick(Utf2T(pRoot->getAttr("name")));
setWString(pUser->hContact, "Nick", wszNick);
diff --git a/protocols/WhatsAppWeb/src/proto.cpp b/protocols/WhatsAppWeb/src/proto.cpp
index 5b83cc647c..d1117846aa 100644
--- a/protocols/WhatsAppWeb/src/proto.cpp
+++ b/protocols/WhatsAppWeb/src/proto.cpp
@@ -191,10 +191,10 @@ int WhatsAppProto::SetStatus(int new_status)
return 0;
}
-int WhatsAppProto::SendMsg(MCONTACT hContact, int, const char *)
+int WhatsAppProto::SendMsg(MCONTACT hContact, int, const char *pszMsg)
{
ptrA jid(getStringA(hContact, DBKEY_ID));
- if (jid == NULL)
+ if (jid == nullptr || pszMsg == nullptr)
return 0;
if (!isOnline()) {
@@ -202,6 +202,18 @@ int WhatsAppProto::SendMsg(MCONTACT hContact, int, const char *)
return 0;
}
+ auto *key = new proto::MessageKey();
+ key->set_remotejid(jid);
+ key->set_fromme(true);
+
+ proto::WebMessageInfo msg;
+ msg.set_allocated_key(key);
+ msg.mutable_message()->set_conversation(pszMsg);
+ msg.set_messagetimestamp(_time64(0));
+
+ size_t cbBinaryLen = msg.ByteSizeLong();
+ mir_ptr<BYTE> pBuf((BYTE *)mir_alloc(cbBinaryLen));
+ msg.SerializeToArray(pBuf, (int)cbBinaryLen);
return 0;
}
diff --git a/protocols/WhatsAppWeb/src/proto.h b/protocols/WhatsAppWeb/src/proto.h
index 3157fd2331..16ce1bb30f 100644
--- a/protocols/WhatsAppWeb/src/proto.h
+++ b/protocols/WhatsAppWeb/src/proto.h
@@ -38,17 +38,6 @@ struct WAUser
DWORD m_time1 = 0, m_time2 = 0;
};
-struct WAMessage
-{
- bool bFromTo;
- BYTE iMsgType;
- ptrA szShit;
- ptrA szJid;
- ptrA szMsgId;
- ptrA szBody;
- __int64 timestamp;
-};
-
class WhatsAppProto : public PROTO<WhatsAppProto>
{
class CWhatsAppProtoImpl
@@ -90,7 +79,7 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
// Group chats /////////////////////////////////////////////////////////////////////////
- void InitChat(WAUser *pUser, const JSONNode &chat);
+ void InitChat(WAUser *pUser, const WANode *pNode);
// UI //////////////////////////////////////////////////////////////////////////////////
@@ -129,9 +118,9 @@ class WhatsAppProto : public PROTO<WhatsAppProto>
// binary packets
void ProcessBinaryPacket(const MBinBuffer &buf);
- void ProcessAdd(const CMStringA &type, const JSONNode &node);
- void ProcessChats(const JSONNode &node);
- void ProcessContacts(const JSONNode &node);
+ void ProcessAdd(const CMStringA &type, const WANode *node);
+ void ProcessChats(const WANode *node);
+ void ProcessContacts(const WANode *node);
// text packets
void ProcessPacket(const JSONNode &node);
diff --git a/protocols/WhatsAppWeb/src/server.cpp b/protocols/WhatsAppWeb/src/server.cpp
index 316d9499fb..60eb227c97 100644
--- a/protocols/WhatsAppWeb/src/server.cpp
+++ b/protocols/WhatsAppWeb/src/server.cpp
@@ -436,41 +436,37 @@ bool WhatsAppProto::ServerThreadWorker()
void WhatsAppProto::ProcessBinaryPacket(const MBinBuffer &buf)
{
WAReader reader(buf.data(), buf.length());
-
- JSONNode root;
- if (!reader.readNode(root))
+ WANode *pRoot = reader.readNode();
+ if (pRoot == nullptr) // smth went wrong
return;
- debugLogA("packed JSON: %s", root.write().c_str());
+ CMStringA szText;
+ pRoot->print(szText);
+ debugLogA("packed JSON: %s", szText.c_str());
- CMStringA szType = root["type"].as_mstring();
+ CMStringA szType = pRoot->getAttr("type");
if (szType == "contacts")
- ProcessContacts(root["$list$"]);
+ ProcessContacts(pRoot);
else if (szType == "chat")
- ProcessChats(root["$list$"]);
+ ProcessChats(pRoot);
else {
- CMStringA szAdd = root["add"].as_mstring();
+ CMStringA szAdd = pRoot->getAttr("add");
if (!szAdd.IsEmpty())
- ProcessAdd(szAdd, root["$list$"]);
+ ProcessAdd(szAdd, pRoot);
}
+
+ delete pRoot;
}
/////////////////////////////////////////////////////////////////////////////////////////
-void WhatsAppProto::ProcessAdd(const CMStringA &type, const JSONNode &list)
+void WhatsAppProto::ProcessAdd(const CMStringA &type, const WANode *root)
{
- for (auto &it : list) {
- std::string buf = it["$bin$"].as_string();
-
- size_t resLen;
- ptrA pRes((char*)mir_base64_decode(buf.c_str(), &resLen));
- if (pRes == nullptr)
- continue;
-
+ for (auto &p: root->children) {
proto::WebMessageInfo payLoad;
- if (!payLoad.ParseFromArray(pRes, (int)resLen)) {
+ if (!payLoad.ParseFromArray(p->content.data(), (int)p->content.length())) {
debugLogA("Error: message failed to decode by protobuf!");
- Netlib_Dump(m_hServerConn, pRes, resLen, false, 0);
+ Netlib_Dump(m_hServerConn, p->content.data(), p->content.length(), false, 0);
continue;
}
@@ -523,53 +519,53 @@ void WhatsAppProto::ProcessAdd(const CMStringA &type, const JSONNode &list)
}
}
-void WhatsAppProto::ProcessChats(const JSONNode &list)
+void WhatsAppProto::ProcessChats(const WANode *root)
{
- for (auto &it : list) {
- CMStringW jid(it["jid"].as_mstring());
- auto *pUser = AddUser(T2Utf(jid), false);
+ for (auto &p: root->children) {
+ CMStringA jid = p->getAttr("jid");
+ auto *pUser = AddUser(jid, false);
- DWORD dwLastId = it["t"].as_int();
+ DWORD dwLastId = atoi(p->getAttr("t"));
setDword(pUser->hContact, "LastWriteTime", dwLastId);
- pUser->dwModifyTag = it["modify_tag"].as_int();
+ pUser->dwModifyTag = atoi(p->getAttr("modify_tag"));
if (pUser->si) {
- DWORD dwMute = _wtoi(it["mute"].as_mstring());
+ DWORD dwMute = atoi(p->getAttr("mute"));
Chat_Mute(pUser->si, dwMute ? CHATMODE_MUTE : CHATMODE_NORMAL);
}
}
}
-void WhatsAppProto::ProcessContacts(const JSONNode &list)
+void WhatsAppProto::ProcessContacts(const WANode *root)
{
- for (auto &it : list) {
- CMStringW jid(it["jid"].as_mstring());
- auto *pUser = AddUser(T2Utf(jid), false);
+ for (auto &p: root->children) {
+ CMStringA jid(p->getAttr("jid"));
+ auto *pUser = AddUser(jid, false);
if (strstr(pUser->szId, "@g.us")) {
- InitChat(pUser, it);
+ InitChat(pUser, p);
continue;
}
- CMStringW wszNick(it["notify"].as_mstring());
+ CMStringA wszNick(p->getAttr("notify"));
if (wszNick.IsEmpty()) {
int idx = jid.Find('@');
wszNick = (idx == -1) ? jid : jid.Left(idx);
}
- setWString(pUser->hContact, "Nick", wszNick);
+ setUString(pUser->hContact, "Nick", wszNick);
- CMStringW wszFullName(it["name"].as_mstring());
+ CMStringA wszFullName(p->getAttr("name"));
wszFullName.TrimRight();
if (!wszFullName.IsEmpty()) {
- setWString(pUser->hContact, "FullName", wszFullName);
+ setUString(pUser->hContact, "FullName", wszFullName);
- CMStringW wszShort(it["short"].as_mstring());
+ CMStringA wszShort(p->getAttr("short"));
wszShort.TrimRight();
if (!wszShort.IsEmpty()) {
- setWString(pUser->hContact, "FirstName", wszShort);
+ setUString(pUser->hContact, "FirstName", wszShort);
if (wszShort.GetLength()+1 < wszFullName.GetLength())
- setWString(pUser->hContact, "LastName", wszFullName.c_str() + 1 + wszShort.GetLength());
+ setUString(pUser->hContact, "LastName", wszFullName.c_str() + 1 + wszShort.GetLength());
}
}
}
diff --git a/protocols/WhatsAppWeb/src/stdafx.h b/protocols/WhatsAppWeb/src/stdafx.h
index cdfe2a866e..75d1dd0485 100644
--- a/protocols/WhatsAppWeb/src/stdafx.h
+++ b/protocols/WhatsAppWeb/src/stdafx.h
@@ -12,6 +12,9 @@ Copyright © 2019-21 George Hazan
#include <time.h>
#include <windows.h>
+#include <list>
+#include <string>
+
#include <newpluginapi.h>
#include <m_avatars.h>
#include <m_chat_int.h>
diff --git a/protocols/WhatsAppWeb/src/utils.cpp b/protocols/WhatsAppWeb/src/utils.cpp
index 47ab78b189..4631b32fcd 100644
--- a/protocols/WhatsAppWeb/src/utils.cpp
+++ b/protocols/WhatsAppWeb/src/utils.cpp
@@ -84,8 +84,72 @@ bool WhatsAppProto::decryptBinaryMessage(size_t cbSize, const void *buf, MBinBuf
}
/////////////////////////////////////////////////////////////////////////////////////////
+// WANode members
-bool WAReader::readAttributes(JSONNode &ret, int count)
+WANode::WANode()
+{}
+
+WANode::~WANode()
+{
+ for (auto &p: attrs)
+ delete p;
+
+ for (auto &p: children)
+ delete p;
+}
+
+CMStringA WANode::getAttr(const char *pszFieldName) const
+{
+ for (auto &p: attrs)
+ if (p->name == pszFieldName)
+ return p->value;
+
+ return "";
+}
+
+void WANode::addAttr(const char *pszName, const char *pszValue)
+{
+ attrs.push_back(new Attr(pszName, pszValue));
+}
+
+void WANode::print(CMStringA &dest, int level) const
+{
+ for (int i = 0; i < level; i++)
+ dest.Append(" ");
+
+ dest.AppendFormat("<%s ", title.c_str());
+ for (auto &p: attrs)
+ dest.AppendFormat("%s=\"%s\" ", p->name.c_str(), p->value.c_str());
+ dest.Truncate(dest.GetLength() - 1);
+
+ if (content.isEmpty() && children.empty()) {
+ dest.Append("/>\n");
+ return;
+ }
+
+ dest.Append(">");
+ if (!content.isEmpty()) {
+ ptrA tmp((char *)mir_alloc(content.length() * 2 + 1));
+ bin2hex(content.data(), content.length(), tmp);
+ dest.AppendFormat("%s", tmp.get());
+ }
+
+ if (!children.empty()) {
+ dest.Append("\n");
+
+ for (auto &p : children)
+ p->print(dest, level + 1);
+
+ for (int i = 0; i < level; i++)
+ dest.Append(" ");
+ }
+
+ dest.AppendFormat("</%s>\n", title.c_str());
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+bool WAReader::readAttributes(WANode *pNode, int count)
{
if (count == 0)
return true;
@@ -99,7 +163,7 @@ bool WAReader::readAttributes(JSONNode &ret, int count)
if (value.IsEmpty())
return false;
- ret << CHAR_PARAM(name, value);
+ pNode->addAttr(name, value);
}
return true;
}
@@ -125,21 +189,19 @@ uint32_t WAReader::readIntN(int n)
return res;
}
-bool WAReader::readList(JSONNode &parent, int tag)
+bool WAReader::readList(WANode *pParent, int tag)
{
int size = readListSize(tag);
if (size == -1)
return false;
- JSONNode list(JSON_ARRAY); list.set_name("$list$");
for (int i = 0; i < size; i++) {
- JSONNode tmp;
- if (!readNode(tmp))
+ WANode *pNew = readNode();
+ if (pNew == nullptr)
return false;
- list << tmp;
+ pParent->children.push_back(pNew);
}
- parent << list;
return true;
}
@@ -156,31 +218,33 @@ int WAReader::readListSize(int tag)
return -1;
}
-bool WAReader::readNode(JSONNode &ret)
+WANode* WAReader::readNode()
{
int listSize = readListSize(readInt8());
if (listSize == -1)
- return false;
+ return nullptr;
int descrTag = readInt8();
if (descrTag == STREAM_END)
- return false;
+ return nullptr;
CMStringA name = readString(descrTag);
if (name.IsEmpty())
- return false;
- ret.set_name(name.c_str());
+ return nullptr;
- if (!readAttributes(ret, (listSize-1)>>1))
- return false;
+ std::unique_ptr<WANode> ret(new WANode());
+ ret->title = name.c_str();
+
+ if (!readAttributes(ret.get(), (listSize-1)>>1))
+ return nullptr;
if ((listSize % 2) == 1)
- return true;
+ return ret.release();
int size, tag = readInt8();
switch (tag) {
case LIST_EMPTY: case LIST_8: case LIST_16:
- readList(ret, tag);
+ readList(ret.get(), tag);
break;
case BINARY_8:
@@ -190,7 +254,7 @@ LBL_Binary:
if (m_limit - m_buf < size)
return false;
- ret << CHAR_PARAM("$bin$", ptrA(mir_base64_encode(m_buf, size)));
+ ret->content.assign((void*)m_buf, size);
m_buf += size;
break;
@@ -203,10 +267,11 @@ LBL_Binary:
goto LBL_Binary;
default:
- ret << CHAR_PARAM("$str$", readString(tag).c_str());
+ CMStringA str = readString(tag);
+ ret->content.assign(str.GetBuffer(), str.GetLength() + 1);
}
- return true;
+ return ret.release();
}
/////////////////////////////////////////////////////////////////////////////////////////
@@ -256,6 +321,8 @@ CMStringA WAReader::readPacked(int tag)
ret.AppendChar(higher);
}
+ if (bTrim && !ret.IsEmpty())
+ ret.Truncate(ret.GetLength() - 1);
return ret;
}
diff --git a/protocols/WhatsAppWeb/src/utils.h b/protocols/WhatsAppWeb/src/utils.h
index d37c8fb187..c2a5d90ca3 100644
--- a/protocols/WhatsAppWeb/src/utils.h
+++ b/protocols/WhatsAppWeb/src/utils.h
@@ -20,6 +20,34 @@ Copyright © 2019-21 George Hazan
#define BINARY_32 254
#define NIBBLE_8 255
+class WANode // kinda XML
+{
+ struct Attr
+ {
+ Attr(const char *pszName, const char *pszValue) :
+ name(pszName),
+ value(pszValue)
+ {}
+
+ CMStringA name, value;
+ };
+
+ std::list<Attr*> attrs;
+
+public:
+ WANode();
+ ~WANode();
+
+ void addAttr(const char *pszName, const char *pszValue);
+ CMStringA getAttr(const char *pszFieldValue) const;
+
+ void print(CMStringA &dest, int level = 0) const;
+
+ CMStringA title;
+ MBinBuffer content;
+ std::list<WANode*> children;
+};
+
class WAReader
{
const BYTE *m_buf, *m_limit;
@@ -37,11 +65,11 @@ public:
__forceinline uint32_t readInt16() { return readIntN(2); }
__forceinline uint32_t readInt32() { return readIntN(4); }
- bool readAttributes(JSONNode &node, int count);
+ bool readAttributes(WANode *node, int count);
uint32_t readInt20();
- bool readList(JSONNode &node, int tag);
+ bool readList(WANode *pParent, int tag);
int readListSize(int tag);
CMStringA readPacked(int tag);
CMStringA readString(int tag);
- bool readNode(JSONNode&);
+ WANode* readNode();
};