diff options
author | George Hazan <ghazan@miranda.im> | 2021-04-23 16:29:57 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2021-04-23 16:29:57 +0300 |
commit | 2b49ffbabfb41a50a764cf666f9de226e89da856 (patch) | |
tree | 51bcccc9c70b7cdfffc58d52a98d81bc2ecac8ac | |
parent | 413700b665fcc1475410d2df2d92dff249b97bc2 (diff) |
perversion with XML -> JSON translation replaced with hand-made pseudo-XML WANode class
-rw-r--r-- | protocols/WhatsAppWeb/src/chats.cpp | 4 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/proto.cpp | 16 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/proto.h | 19 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/server.cpp | 74 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/stdafx.h | 3 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/utils.cpp | 107 | ||||
-rw-r--r-- | protocols/WhatsAppWeb/src/utils.h | 34 |
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(); }; |