From 97ba0b94c5da04f0d03945baa21c338c77c9dc20 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sun, 25 Jan 2015 22:07:28 +0000 Subject: - correct writing of tokens, especially extended - further code optimizations git-svn-id: http://svn.miranda-ng.org/main/trunk@11911 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- .../WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp | 13 ++-- .../WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp | 20 ++---- .../WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.h | 1 - protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp | 82 +++++++++++++--------- protocols/WhatsApp/src/WhatsAPI++/WAConnection.h | 23 +++--- protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp | 35 +++------ protocols/WhatsApp/src/WhatsAPI++/WALogin.h | 10 +-- protocols/WhatsApp/src/connection.cpp | 9 +-- 8 files changed, 90 insertions(+), 103 deletions(-) diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp index 492dde1027..99c186f126 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeReader.cpp @@ -12,6 +12,8 @@ #include "ProtocolTreeNode.h" #include "utilities.h" +extern const char *dictionary[], *extended_dict[]; + BinTreeNodeReader::BinTreeNodeReader(WAConnection *conn, ISocketConnection *connection) : buf(BUFFER_SIZE) { @@ -145,15 +147,12 @@ ReadData* BinTreeNodeReader::readString(int token) int bSize; ReadData *ret = new ReadData(); - if (token > 2 && token <= WAConnection::DICTIONARY_LEN) { - if (token != WAConnection::DICTIONARY_LEN) - ret->data = new std::string(WAConnection::dictionary[token]); + if (token > 2 && token <= 236) { + if (token != 236) + ret->data = new std::string(dictionary[token]); else { token = readInt8(this->in); - if (token >= WAConnection::EXTDICTIONARY_LEN) - throw WAException("invalid token/length in getToken", WAException::CORRUPT_STREAM_EX, 0); - - ret->data = new std::string(WAConnection::extended_dict[token]); + ret->data = new std::string(extended_dict[token]); } ret->type = STRING; diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp index a4f79baf17..227857a522 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp @@ -17,11 +17,6 @@ BinTreeNodeWriter::BinTreeNodeWriter(WAConnection* conn, ISocketConnection* conn this->conn = conn; this->out = new ByteArrayOutputStream(2048); this->realOut = connection; - for (int i = 0; i < WAConnection::DICTIONARY_LEN; i++) { - std::string token(WAConnection::dictionary[i]); - if (token.compare("") != 0) - this->tokenMap[token] = i; - } this->dataBegin = 0; } @@ -135,9 +130,9 @@ void BinTreeNodeWriter::writeAttributes(std::map* attributes) void BinTreeNodeWriter::writeString(const std::string& tag) { - std::map::iterator it = this->tokenMap.find(tag); - if (it != this->tokenMap.end()) - writeToken(it->second); + int token = WAConnection::tokenLookup(tag); + if (token != -1) + writeToken(token); else { size_t atIndex = tag.find('@'); if (atIndex == 0 || atIndex == string::npos) @@ -164,12 +159,11 @@ void BinTreeNodeWriter::writeJid(std::string* user, const std::string& server) void BinTreeNodeWriter::writeToken(int intValue) { - if (intValue < 245) - this->out->write(intValue); - else if (intValue <= 500) { - this->out->write(254); - this->out->write(intValue - 245); + if (intValue & 0x100) { + this->out->write(236); + this->out->write(intValue & 0xFF); } + else this->out->write(intValue); } void BinTreeNodeWriter::writeBytes(unsigned char* bytes, int length) diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.h b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.h index e4a771f231..66d9cbb991 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.h +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.h @@ -35,7 +35,6 @@ class WAConnection; class BinTreeNodeWriter { private: WAConnection* conn; - map tokenMap; ISocketConnection *realOut; ByteArrayOutputStream *out; IMutex* mutex; diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp index 48300ad530..270c329085 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp @@ -10,7 +10,7 @@ #include "ProtocolTreeNode.h" #include "utilities.h" -const char* WAConnection::dictionary[] = { +const char* dictionary[] = { "", "", "", "account", "ack", "action", "active", "add", "after", "all", "allow", "apple", "auth", "author", "available", "bad-protocol", "bad-request", "before", "body", "broadcast", "cancel", "category", "challenge", "chat", "clean", "code", "composing", "config", "contacts", "count", "create", "creation", "debug", "default", "delete", "delivery", "delta", "deny", @@ -34,9 +34,7 @@ const char* WAConnection::dictionary[] = { "adpcm", "amrnb", "amrwb", "mp3", "pcm", "qcelp", "wma", "h263", "h264", "jpeg" }; -const int WAConnection::DICTIONARY_LEN = _countof(WAConnection::dictionary); - -const char* WAConnection::extended_dict[] = { +const char* extended_dict[] = { "mpeg4", "wmv", "audio/3gpp", "audio/aac", "audio/amr", "audio/mp4", "audio/mpeg", "audio/ogg", "audio/qcelp", "audio/wav", "audio/webm", "audio/x-caf", "audio/x-ms-wma", "image/gif", "image/jpeg", "image/png", "video/3gpp", "video/avi", "video/mp4", "video/mpeg", "video/quicktime", "video/x-flv", "video/x-ms-asf", "302", "400", "401", "402", "403", "404", "405", "406", "407", @@ -60,41 +58,71 @@ const char* WAConnection::extended_dict[] = { "archive", "adm", "plaintext_size", "compressed_size", "delivered", "msg", "pkmsg", "everyone", "v", "transport", "call-id" }; -const int WAConnection::EXTDICTIONARY_LEN = _countof(WAConnection::extended_dict); - -///////////////////////////////////////////////////////////////////////////////////////// +static map tokenMap1, tokenMap2; -WAConnection::WAConnection(IMutex* mutex, WAListener* event_handler, WAGroupListener* group_event_handler) +void WAConnection::globalInit() { - this->init(event_handler, group_event_handler, mutex); + for (int i = 0; i < _countof(dictionary); i++) + if (*dictionary[i] != 0) + tokenMap1[dictionary[i]] = i; + + for (int i = 0; i < _countof(extended_dict); i++) + tokenMap2[extended_dict[i]] = i; } -WAConnection::~WAConnection() +int WAConnection::tokenLookup(const std::string &str) { - delete this->in; - delete this->out; - std::map::iterator it; - for (it = this->pending_server_requests.begin(); it != this->pending_server_requests.end(); it++) - delete it->second; + std::map::iterator it = tokenMap1.find(str); + if (it != tokenMap1.end()) + return it->second; + + it = tokenMap2.find(str); + if (it != tokenMap2.end()) + return it->second + 0x100; + + return -1; } -void WAConnection::init(WAListener* event_handler, WAGroupListener* group_event_handler, IMutex* mutex) +///////////////////////////////////////////////////////////////////////////////////////// + +WAConnection::WAConnection(const std::string &user, const std::string &resource, IMutex *mutex, WAListener *event_handler, WAGroupListener *group_event_handler) { + this->mutex = mutex; this->event_handler = event_handler; this->group_event_handler = group_event_handler; + this->in = NULL; this->out = NULL; this->msg_id = 0; this->retry = true; + this->user = user; + this->resource = resource; + this->domain = "s.whatsapp.net"; + this->jid = user + "@" + domain; + this->supports_receipt_acks = false; this->iqid = 0; this->verbose = true; this->lastTreeRead = 0; this->expire_date = 0L; this->account_kind = -1; - this->mutex = mutex; +} + +WAConnection::~WAConnection() +{ + delete this->in; + delete this->out; + std::map::iterator it; + for (it = this->pending_server_requests.begin(); it != this->pending_server_requests.end(); it++) + delete it->second; +} + +void WAConnection::init(IMutex *mutex, WASocketConnection *conn) +{ + in = new BinTreeNodeReader(this, conn); + out = new BinTreeNodeWriter(this, conn, mutex); } void WAConnection::setLogin(WALogin* login) @@ -104,11 +132,6 @@ void WAConnection::setLogin(WALogin* login) if (login->account_kind != -1) this->account_kind = login->account_kind; - - this->jid = user + "@" + domain; - - this->in = login->getTreeNodeReader(); - this->out = login->getTreeNodeWriter(); } void WAConnection::sendMessageWithMedia(FMessage* message) throw (WAException) @@ -118,7 +141,7 @@ void WAConnection::sendMessageWithMedia(FMessage* message) throw (WAException) if (message->media_wa_type == FMessage::WA_TYPE_SYSTEM) throw new WAException("Cannot send system message over the network"); - ProtocolTreeNode* mediaNode; + ProtocolTreeNode *mediaNode; if (message->media_wa_type == FMessage::WA_TYPE_CONTACT && !message->media_name.empty()) { ProtocolTreeNode* vcardNode = new ProtocolTreeNode("vcard", new std::vector(message->data.begin(), message->data.end())) << XATTR("name", message->media_name); @@ -131,17 +154,12 @@ void WAConnection::sendMessageWithMedia(FMessage* message) throw (WAException) mediaNode << XATTR("xmlns", "urn:xmpp:whatsapp:mms") << XATTR("type", FMessage::getMessage_WA_Type_StrValue(message->media_wa_type)); - if (message->media_wa_type == FMessage::WA_TYPE_LOCATION) { + if (message->media_wa_type == FMessage::WA_TYPE_LOCATION) mediaNode << XATTR("latitude", Utilities::doubleToStr(message->latitude)) << XATTR("longitude", Utilities::doubleToStr(message->longitude)); - } else { - if (message->media_wa_type != FMessage::WA_TYPE_CONTACT && !message->media_name.empty() && !message->media_url.empty() && message->media_size > 0L) { - mediaNode << XATTR("file", message->media_name) << XATTRI("size", message->media_size) << XATTR("url", message->media_url); - } - else { - mediaNode << XATTR("file", message->media_name) << XATTRI("size", message->media_size) - << XATTR("url", message->media_url) << XATTRI("seconds", message->media_duration_seconds); - } + mediaNode << XATTR("file", message->media_name) << XATTRI("size", message->media_size) << XATTR("url", message->media_url); + if (message->media_wa_type == FMessage::WA_TYPE_CONTACT || message->media_name.empty() || message->media_url.empty() || message->media_size <= 0) + mediaNode << XATTRI("seconds", message->media_duration_seconds); } this->out->write(WAConnection::getMessageNode(message, mediaNode)); diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h index 983cb4e4bc..697542e32c 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h +++ b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h @@ -24,6 +24,7 @@ #pragma warning(disable : 4290) class WALogin; +class WASocketConnection; class KeyStream; class BinTreeNodeReader; @@ -351,18 +352,18 @@ class WAConnection { } }; + friend class WALogin; private: - BinTreeNodeReader* in; - BinTreeNodeWriter* out; - WAListener* event_handler; - WAGroupListener* group_event_handler; + BinTreeNodeReader *in; + BinTreeNodeWriter *out; + WAListener *event_handler; + WAGroupListener *group_event_handler; bool verbose; int iqid; std::map pending_server_requests; - IMutex* mutex; + IMutex *mutex; - void init(WAListener* event_handler, WAGroupListener* group_event_handler, IMutex* mutex); void sendMessageWithMedia(FMessage* message) throw(WAException); void sendMessageWithBody(FMessage* message) throw(WAException); std::map* parseCategories(ProtocolTreeNode* node) throw(WAException); @@ -379,8 +380,9 @@ private: std::vector* processGroupSettings(const std::vector& gruops); public: - WAConnection(IMutex* mutex, WAListener* event_handler = NULL, WAGroupListener* group_event_handler = NULL); + WAConnection(const std::string& user, const std::string& resource, IMutex* mutex, WAListener* event_handler, WAGroupListener* group_event_handler); virtual ~WAConnection(); + void init(IMutex* mutex, WASocketConnection*); std::string user; std::string domain; @@ -395,11 +397,8 @@ public: int account_kind; time_t lastTreeRead; - static const int DICTIONARY_LEN; - static const char* dictionary[]; - - static const int EXTDICTIONARY_LEN; - static const char* extended_dict[]; + static void globalInit(void); + static int tokenLookup(const std::string&); static MessageStore* message_store; KeyStream inputKey, outputKey; diff --git a/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp b/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp index c833d30ffe..e009968b59 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp @@ -20,19 +20,17 @@ using namespace Utilities; const std::string WALogin::NONCE_KEY = "nonce=\""; -WALogin::WALogin(WAConnection* connection, BinTreeNodeReader *reader, BinTreeNodeWriter *writer, const std::string& password) +WALogin::WALogin(WAConnection* connection, const std::string& password) { this->connection = connection; this->password = password; - this->inn = reader; - this->out = writer; this->account_kind = -1; this->expire_date = 0L; } std::vector* WALogin::login(const std::vector& authBlob) { - this->out->streamStart(connection->domain, connection->resource); + connection->out->streamStart(connection->domain, connection->resource); _LOGDATA("sent stream start"); @@ -44,27 +42,17 @@ std::vector* WALogin::login(const std::vector& aut _LOGDATA("send auth, auth blob size %d", authBlob.size()); - this->inn->streamStart(); + connection->in->streamStart(); _LOGDATA("read stream start"); return this->readFeaturesUntilChallengeOrSuccess(); } -BinTreeNodeReader* WALogin::getTreeNodeReader() -{ - return this->inn; -} - -BinTreeNodeWriter* WALogin::getTreeNodeWriter() -{ - return this->out; -} - void WALogin::sendResponse(const std::vector& challengeData) { std::vector* authBlob = this->getAuthBlob(challengeData); - this->out->write(ProtocolTreeNode("response", authBlob)); + connection->out->write(ProtocolTreeNode("response", authBlob)); } void WALogin::sendFeatures() @@ -76,7 +64,7 @@ void WALogin::sendFeatures() ProtocolTreeNode* pictureChild = new ProtocolTreeNode("w:profile:picture") << XATTR("type", "all"); children->push_back(pictureChild); - this->out->write(ProtocolTreeNode("stream:features", NULL, children), true); + connection->out->write(ProtocolTreeNode("stream:features", NULL, children), true); } void WALogin::sendAuth(const std::vector& existingChallenge) @@ -85,7 +73,7 @@ void WALogin::sendAuth(const std::vector& existingChallenge) if (!existingChallenge.empty()) data = this->getAuthBlob(existingChallenge); - this->out->write(ProtocolTreeNode("auth", data) << + connection->out->write(ProtocolTreeNode("auth", data) << XATTR("mechanism", "WAUTH-2") << XATTR("user", connection->user), true); } @@ -110,15 +98,13 @@ std::vector* WALogin::getAuthBlob(const std::vector* WALogin::readFeaturesUntilChallengeOrSuccess() { - while (ProtocolTreeNode *root = this->inn->nextTree()) { + while (ProtocolTreeNode *root = connection->in->nextTree()) { if (ProtocolTreeNode::tagEquals(root, "stream:features")) { connection->supports_receipt_acks = root->getChild("receipt_acks") != NULL; delete root; continue; } if (ProtocolTreeNode::tagEquals(root, "challenge")) { - // base64_decode(*root->data); - // _LOGDATA("Challenge data %s (%d)", root->data->c_str(), root->data->length()); std::vector challengedata(root->data->begin(), root->data->end()); delete root; this->sendResponse(challengedata); @@ -128,7 +114,6 @@ std::vector* WALogin::readFeaturesUntilChallengeOrSuccess() return new std::vector(data.begin(), data.end()); } if (ProtocolTreeNode::tagEquals(root, "success")) { - // base64_decode(*root->data); std::vector* ret = new std::vector(root->data->begin(), root->data->end()); this->parseSuccessNode(root); delete root; @@ -140,6 +125,8 @@ std::vector* WALogin::readFeaturesUntilChallengeOrSuccess() void WALogin::parseSuccessNode(ProtocolTreeNode* node) { + connection->out->setLoggedIn(); + const string &expiration = node->getAttributeValue("expiration"); if (!expiration.empty()) { this->expire_date = atol(expiration.c_str()); @@ -158,7 +145,7 @@ void WALogin::parseSuccessNode(ProtocolTreeNode* node) std::vector WALogin::readSuccess() { - ProtocolTreeNode *node = this->inn->nextTree(); + ProtocolTreeNode *node = connection->in->nextTree(); if (ProtocolTreeNode::tagEquals(node, "failure")) { delete node; @@ -181,8 +168,6 @@ std::vector WALogin::readSuccess() } else this->account_kind = -1; - this->out->setLoggedIn(); - std::vector data = *node->data; delete node; return data; diff --git a/protocols/WhatsApp/src/WhatsAPI++/WALogin.h b/protocols/WhatsApp/src/WhatsAPI++/WALogin.h index ab1e13472b..440f34f71b 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WALogin.h +++ b/protocols/WhatsApp/src/WhatsAPI++/WALogin.h @@ -44,16 +44,14 @@ public: class WALogin { private: static const std::string NONCE_KEY; - WAConnection* connection; - BinTreeNodeReader* inn; - BinTreeNodeWriter* out; + WAConnection *connection; std::vector* getAuthBlob(const std::vector& nonce); void sendResponse(const std::vector& challengeData); void sendFeatures(); void sendAuth(const std::vector& nonce); std::vector* readFeaturesUntilChallengeOrSuccess(); - void parseSuccessNode(ProtocolTreeNode* node); + void parseSuccessNode(ProtocolTreeNode *node); std::vector readSuccess(); public: @@ -61,12 +59,10 @@ public: int account_kind; std::string password; - WALogin(WAConnection* connection, BinTreeNodeReader *reader, BinTreeNodeWriter *writer, const std::string& password); + WALogin(WAConnection* connection, const std::string& password); ~WALogin(); std::vector* login(const std::vector& blobLength); - BinTreeNodeReader *getTreeNodeReader(); - BinTreeNodeWriter *getTreeNodeWriter(); }; #endif /* WALOGIN_H_ */ diff --git a/protocols/WhatsApp/src/connection.cpp b/protocols/WhatsApp/src/connection.cpp index 2acc8a89fa..8c1f16c456 100644 --- a/protocols/WhatsApp/src/connection.cpp +++ b/protocols/WhatsApp/src/connection.cpp @@ -118,13 +118,10 @@ void WhatsAppProto::stayConnectedLoop(void*) portNumber = 5222, resource += "-5222"; this->conn = new WASocketConnection("c.whatsapp.net", portNumber); - this->connection = new WAConnection(&this->connMutex, this, this); - - this->connection->domain = "s.whatsapp.net"; - this->connection->user = this->phoneNumber; - this->connection->resource = resource; + this->connection = new WAConnection(this->phoneNumber, resource, &this->connMutex, this, this); + this->connection->init(&writerMutex, this->conn); { - WALogin login(connection, new BinTreeNodeReader(connection, conn), new BinTreeNodeWriter(connection, conn, &writerMutex), password); + WALogin login(connection, password); std::vector* nextChallenge = login.login(*this->challenge); delete this->challenge; -- cgit v1.2.3