From b2f86045d3b3dc2a454f127f186429b60e493072 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Fri, 6 Feb 2015 23:36:02 +0000 Subject: merge from branch git-svn-id: http://svn.miranda-ng.org/main/trunk@12029 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- protocols/WhatsApp/WhatsApp_10.vcxproj | 4 - protocols/WhatsApp/WhatsApp_10.vcxproj.filters | 12 - protocols/WhatsApp/WhatsApp_12.vcxproj | 4 - protocols/WhatsApp/WhatsApp_12.vcxproj.filters | 12 - protocols/WhatsApp/res/add-user-to-group.ico | Bin 1150 -> 0 bytes protocols/WhatsApp/res/change-group-subject.ico | Bin 1150 -> 0 bytes protocols/WhatsApp/res/leave-group.ico | Bin 1150 -> 0 bytes protocols/WhatsApp/res/remove-user-from-group.ico | Bin 1150 -> 0 bytes protocols/WhatsApp/res/whatsapp.rc | 25 +- protocols/WhatsApp/src/WASocketConnection.cpp | 2 +- protocols/WhatsApp/src/WASocketConnection.h | 6 +- .../WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp | 8 +- .../WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.h | 4 +- protocols/WhatsApp/src/WhatsAPI++/ByteArray.cpp | 2 +- protocols/WhatsApp/src/WhatsAPI++/ByteArray.h | 2 +- protocols/WhatsApp/src/WhatsAPI++/FMessage.cpp | 4 +- protocols/WhatsApp/src/WhatsAPI++/FMessage.h | 2 +- protocols/WhatsApp/src/WhatsAPI++/KeyStream.cpp | 2 +- .../WhatsApp/src/WhatsAPI++/ProtocolTreeNode.h | 14 +- protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp | 435 +++++++++--------- protocols/WhatsApp/src/WhatsAPI++/WAConnection.h | 173 ++++--- protocols/WhatsApp/src/WhatsAPI++/WAException.h | 6 +- protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp | 12 +- protocols/WhatsApp/src/WhatsAPI++/WALogin.h | 4 +- protocols/WhatsApp/src/WhatsAPI++/utilities.cpp | 18 +- protocols/WhatsApp/src/WhatsAPI++/utilities.h | 16 +- protocols/WhatsApp/src/chat.cpp | 505 +++++++++++++++++++-- protocols/WhatsApp/src/common.h | 4 - protocols/WhatsApp/src/connection.cpp | 2 +- protocols/WhatsApp/src/contacts.cpp | 392 ++-------------- protocols/WhatsApp/src/dialogs.cpp | 141 +++--- protocols/WhatsApp/src/dialogs.h | 4 +- protocols/WhatsApp/src/messages.cpp | 51 +-- protocols/WhatsApp/src/proto.cpp | 31 +- protocols/WhatsApp/src/proto.h | 177 ++++---- protocols/WhatsApp/src/resource.h | 12 +- protocols/WhatsApp/src/theme.cpp | 171 +------ protocols/WhatsApp/src/utils.cpp | 22 +- protocols/WhatsApp/src/utils.h | 7 + protocols/WhatsApp/src/version.h | 2 +- 40 files changed, 1109 insertions(+), 1179 deletions(-) delete mode 100644 protocols/WhatsApp/res/add-user-to-group.ico delete mode 100644 protocols/WhatsApp/res/change-group-subject.ico delete mode 100644 protocols/WhatsApp/res/leave-group.ico delete mode 100644 protocols/WhatsApp/res/remove-user-from-group.ico diff --git a/protocols/WhatsApp/WhatsApp_10.vcxproj b/protocols/WhatsApp/WhatsApp_10.vcxproj index fcace9e0a4..1025f8a435 100644 --- a/protocols/WhatsApp/WhatsApp_10.vcxproj +++ b/protocols/WhatsApp/WhatsApp_10.vcxproj @@ -370,10 +370,6 @@ - - - - diff --git a/protocols/WhatsApp/WhatsApp_10.vcxproj.filters b/protocols/WhatsApp/WhatsApp_10.vcxproj.filters index eb0a64d9d5..e59297c958 100644 --- a/protocols/WhatsApp/WhatsApp_10.vcxproj.filters +++ b/protocols/WhatsApp/WhatsApp_10.vcxproj.filters @@ -227,17 +227,5 @@ Resources - - Resources - - - Resources - - - Resources - - - Resources - \ No newline at end of file diff --git a/protocols/WhatsApp/WhatsApp_12.vcxproj b/protocols/WhatsApp/WhatsApp_12.vcxproj index c38387e23a..f369f65cde 100644 --- a/protocols/WhatsApp/WhatsApp_12.vcxproj +++ b/protocols/WhatsApp/WhatsApp_12.vcxproj @@ -364,10 +364,6 @@ - - - - diff --git a/protocols/WhatsApp/WhatsApp_12.vcxproj.filters b/protocols/WhatsApp/WhatsApp_12.vcxproj.filters index 7511e22832..851eaa9000 100644 --- a/protocols/WhatsApp/WhatsApp_12.vcxproj.filters +++ b/protocols/WhatsApp/WhatsApp_12.vcxproj.filters @@ -224,18 +224,6 @@ Resources\Icons - - Resources\Icons - - - Resources\Icons - - - Resources\Icons - - - Resources\Icons - Resources\Icons diff --git a/protocols/WhatsApp/res/add-user-to-group.ico b/protocols/WhatsApp/res/add-user-to-group.ico deleted file mode 100644 index d99febc5a5..0000000000 Binary files a/protocols/WhatsApp/res/add-user-to-group.ico and /dev/null differ diff --git a/protocols/WhatsApp/res/change-group-subject.ico b/protocols/WhatsApp/res/change-group-subject.ico deleted file mode 100644 index 6a50c7581e..0000000000 Binary files a/protocols/WhatsApp/res/change-group-subject.ico and /dev/null differ diff --git a/protocols/WhatsApp/res/leave-group.ico b/protocols/WhatsApp/res/leave-group.ico deleted file mode 100644 index 1e7ea0d9db..0000000000 Binary files a/protocols/WhatsApp/res/leave-group.ico and /dev/null differ diff --git a/protocols/WhatsApp/res/remove-user-from-group.ico b/protocols/WhatsApp/res/remove-user-from-group.ico deleted file mode 100644 index d9a30dbda1..0000000000 Binary files a/protocols/WhatsApp/res/remove-user-from-group.ico and /dev/null differ diff --git a/protocols/WhatsApp/res/whatsapp.rc b/protocols/WhatsApp/res/whatsapp.rc index 3099411ab0..102202ff70 100644 --- a/protocols/WhatsApp/res/whatsapp.rc +++ b/protocols/WhatsApp/res/whatsapp.rc @@ -96,19 +96,19 @@ BEGIN CTEXT "-",IDC_STATIC,82,62,8,8 END -IDD_INPUTBOX DIALOGEX 0, 0, 300, 66 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_TOPMOST -CAPTION "WhatsApp" -FONT 8, "MS Shell Dlg", 400, 0, 0x0 +IDD_GROUPCHAT_INVITE DIALOGEX 0, 0, 215, 170 +STYLE DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU +CAPTION "Invite Users" +FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN - LTEXT "",IDC_TEXT,12,11,288,8 - EDITTEXT IDC_VALUE,12,24,282,12,ES_AUTOHSCROLL - PUSHBUTTON "Cancel",IDC_CANCEL,164,45,60,14 - PUSHBUTTON "OK",IDC_OK,228,45,66,14 + GROUPBOX "Choose an user",IDC_STATIC,4,2,208,130 + CONTROL "",IDC_CLIST,"CListControl",WS_TABSTOP | 0x1,12,12,192,112,WS_EX_CLIENTEDGE + LTEXT "Other user:",IDC_STATIC,4,138,55,8 + EDITTEXT IDC_NEWJID,60,136,152,12,ES_AUTOHSCROLL + DEFPUSHBUTTON "&Invite",IDOK,108,152,50,14 + PUSHBUTTON "Cancel",IDCANCEL,162,152,50,14 END - ///////////////////////////////////////////////////////////////////////////// // // Icon @@ -118,10 +118,7 @@ END // remains consistent on all systems. IDI_WHATSAPP ICON "whatsapp.ico" IDI_ADD_GROUP ICON "add-group.ico" -IDI_ADD_USER_TO_GROUP ICON "add-user-to-group.ico" -IDI_CHANGE_GROUP_SUBJECT ICON "change-group-subject.ico" -IDI_LEAVE_GROUP ICON "leave-group.ico" -IDI_REMOVE_USER_FROM_GROUP ICON "remove-user-from-group.ico" + #endif // German (Germany) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/protocols/WhatsApp/src/WASocketConnection.cpp b/protocols/WhatsApp/src/WASocketConnection.cpp index 2ff362b9bf..6852fb92dd 100644 --- a/protocols/WhatsApp/src/WASocketConnection.cpp +++ b/protocols/WhatsApp/src/WASocketConnection.cpp @@ -12,7 +12,7 @@ void WASocketConnection::quitNetwork() { } -WASocketConnection::WASocketConnection(const std::string& dir, int port) throw (WAException) +WASocketConnection::WASocketConnection(const std::string &dir, int port) throw (WAException) { NETLIBOPENCONNECTION noc = { sizeof(noc) }; noc.szHost = dir.c_str(); diff --git a/protocols/WhatsApp/src/WASocketConnection.h b/protocols/WhatsApp/src/WASocketConnection.h index 1f0034471b..e6dcc472a6 100644 --- a/protocols/WhatsApp/src/WASocketConnection.h +++ b/protocols/WhatsApp/src/WASocketConnection.h @@ -1,12 +1,8 @@ #if !defined(WASOCKETCONNECTION_H) #define WASOCKETCONNECTION_H -#include "common.h" #include "WhatsAPI++/ISocketConnection.h" -#include #include "WhatsAPI++/WAException.h" -#include "WhatsAPI++/WALogin.h" -#include class WASocketConnection : public ISocketConnection { @@ -21,7 +17,7 @@ private: HANDLE hConn; public: - WASocketConnection(const std::string& dir, int port) throw (WAException); + WASocketConnection(const std::string &dir, int port) throw (WAException); virtual ~WASocketConnection(); void write(int i); diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp index 035a3c9d39..00909b6855 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp @@ -134,7 +134,7 @@ void BinTreeNodeWriter::writeAttributes(std::map* attributes) } } -void BinTreeNodeWriter::writeString(const std::string& tag) +void BinTreeNodeWriter::writeString(const std::string &tag) { int token = WAConnection::tokenLookup(tag); if (token != -1) @@ -151,7 +151,7 @@ void BinTreeNodeWriter::writeString(const std::string& tag) } } -void BinTreeNodeWriter::writeJid(std::string* user, const std::string& server) +void BinTreeNodeWriter::writeJid(std::string* user, const std::string &server) { out->write(250); if (user != NULL && !user->empty()) @@ -265,12 +265,12 @@ void BinTreeNodeWriter::write(const ProtocolTreeNode &node, bool needsFlush) this->mutex->lock(); try { this->writeDummyHeader(); - #ifdef _DEBUG + if (bSecure) { string tmp = node.toString(); this->realOut->log(tmp.c_str()); } - #endif + if (node.tag.empty()) out->write(0); else diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.h b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.h index 5a43d660b1..9b59f26f03 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.h +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.h @@ -47,8 +47,8 @@ private: void writeInt16(int v, ByteArrayOutputStream* out); void writeInt16(int v); void writeAttributes(std::map* attributes); - void writeString(const std::string& tag); - void writeJid(std::string* user, const std::string& server); + void writeString(const std::string &tag); + void writeJid(std::string* user, const std::string &server); void writeToken(int intValue); void writeBytes(unsigned char* bytes, int length); void writeInt24(int v); diff --git a/protocols/WhatsApp/src/WhatsAPI++/ByteArray.cpp b/protocols/WhatsApp/src/WhatsAPI++/ByteArray.cpp index 7e98847cff..5df55f97ab 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/ByteArray.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/ByteArray.cpp @@ -51,7 +51,7 @@ void ByteArrayOutputStream::write(unsigned char* b, size_t len) write(b[i]); } -void ByteArrayOutputStream::write(const std::string& s) +void ByteArrayOutputStream::write(const std::string &s) { for (size_t i = 0; i < s.size(); i++) write((unsigned char)s[i]); diff --git a/protocols/WhatsApp/src/WhatsAPI++/ByteArray.h b/protocols/WhatsApp/src/WhatsAPI++/ByteArray.h index 5a3f90d221..d3375d1f3b 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/ByteArray.h +++ b/protocols/WhatsApp/src/WhatsAPI++/ByteArray.h @@ -26,7 +26,7 @@ public: void setPosition(size_t count); void write(int i); void write(unsigned char* c, size_t length); - void write(const std::string& s); + void write(const std::string &s); void setLength(size_t length); __forceinline size_t getCapacity() const { return buf.capacity(); } diff --git a/protocols/WhatsApp/src/WhatsAPI++/FMessage.cpp b/protocols/WhatsApp/src/WhatsAPI++/FMessage.cpp index 23461b30fc..8f5fd2dcc9 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/FMessage.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/FMessage.cpp @@ -57,7 +57,7 @@ FMessage::~FMessage() { } -Key::Key(const std::string& remote_jid, bool from_me, const std::string& id) +Key::Key(const std::string &remote_jid, bool from_me, const std::string &id) { this->remote_jid = remote_jid; this->from_me = from_me; @@ -70,7 +70,7 @@ std::string Key::toString() } -unsigned char FMessage::getMessage_WA_Type(const std::string& type) +unsigned char FMessage::getMessage_WA_Type(const std::string &type) { if (type.empty()) return WA_TYPE_UNDEFINED; diff --git a/protocols/WhatsApp/src/WhatsAPI++/FMessage.h b/protocols/WhatsApp/src/WhatsAPI++/FMessage.h index 9b6a29b038..0d55aa6804 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/FMessage.h +++ b/protocols/WhatsApp/src/WhatsAPI++/FMessage.h @@ -21,7 +21,7 @@ struct Key bool from_me; std::string id; - Key(const std::string& remote_jid, bool from_me, const std::string& id); + Key(const std::string &remote_jid, bool from_me, const std::string &id); std::string toString(); }; diff --git a/protocols/WhatsApp/src/WhatsAPI++/KeyStream.cpp b/protocols/WhatsApp/src/WhatsAPI++/KeyStream.cpp index d027cb9c86..c50e4cbbd1 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/KeyStream.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/KeyStream.cpp @@ -36,7 +36,7 @@ void KeyStream::init(unsigned char* _key, unsigned char* _keyMac) RC4(&this->rc4, sizeof(drop), drop, drop); } -void KeyStream::keyFromPasswordAndNonce(const std::string& pass, const std::vector& nonce, unsigned char *out) +void KeyStream::keyFromPasswordAndNonce(const std::string &pass, const std::vector& nonce, unsigned char *out) { size_t cbSize = nonce.size(); diff --git a/protocols/WhatsApp/src/WhatsAPI++/ProtocolTreeNode.h b/protocols/WhatsApp/src/WhatsAPI++/ProtocolTreeNode.h index aeb1b6e18e..50e0f4033d 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/ProtocolTreeNode.h +++ b/protocols/WhatsApp/src/WhatsAPI++/ProtocolTreeNode.h @@ -55,21 +55,21 @@ public: map *attributes; vector *children; - ProtocolTreeNode(const string& tag, ProtocolTreeNode* child); - ProtocolTreeNode(const string& tag, vector* data = NULL, vector *children = NULL); + ProtocolTreeNode(const string &tag, ProtocolTreeNode *child); + ProtocolTreeNode(const string &tag, vector *data = NULL, vector *children = NULL); ~ProtocolTreeNode(); string toString() const; - ProtocolTreeNode* getChild(const string& id); + ProtocolTreeNode* getChild(const string &id); ProtocolTreeNode* getChild(size_t id); - const string& getAttributeValue(const string& attribute); + const string& getAttributeValue(const string &attribute); vector getAllChildren(); - vector getAllChildren(const string& tag); + vector getAllChildren(const string &tag); std::string getDataAsString() const; - static bool tagEquals(ProtocolTreeNode *node, const string& tag); - static void require(ProtocolTreeNode *node, const string& tag); + static bool tagEquals(ProtocolTreeNode *node, const string &tag); + static void require(ProtocolTreeNode *node, const string &tag); }; ProtocolTreeNode& operator<<(ProtocolTreeNode&, const XATTR&); diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp index f1e671a4de..be44413c52 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp @@ -204,6 +204,8 @@ bool WAConnection::read() throw(WAException) parsePresense(node); else if (ProtocolTreeNode::tagEquals(node, "message")) parseMessage(node); + else if (ProtocolTreeNode::tagEquals(node, "notification")) + parseNotification(node); else if (ProtocolTreeNode::tagEquals(node, "ack")) parseAck(node); else if (ProtocolTreeNode::tagEquals(node, "receipt")) @@ -228,7 +230,7 @@ void WAConnection::readGroupList(ProtocolTreeNode *node, std::vectorgetAttributeValue("s_o"); const string &creation = groupNode->getAttributeValue("creation"); if (m_pGroupEventHandler != NULL) - m_pGroupEventHandler->onGroupInfoFromList(gjid, owner, subject, subject_owner, atoi(subject_t.c_str()), atoi(creation.c_str())); + m_pGroupEventHandler->onGroupInfo(gjid, owner, subject, subject_owner, atoi(subject_t.c_str()), atoi(creation.c_str())); groups.push_back(gjid); } } @@ -260,26 +262,10 @@ void WAConnection::parseAck(ProtocolTreeNode *node) throw(WAException) if (cls == "message" && m_pEventHandler != NULL) { FMessage msg(from, true, id); msg.status = FMessage::STATUS_RECEIVED_BY_SERVER; - m_pEventHandler->onMessageStatusUpdate(&msg); + m_pEventHandler->onMessageStatusUpdate(msg); } } -void WAConnection::parseReceipt(ProtocolTreeNode *node) throw(WAException) -{ - const string &from = node->getAttributeValue("from"); - const string &id = node->getAttributeValue("id"); - const string &ts = node->getAttributeValue("t"); - - if (m_pEventHandler != NULL) { - FMessage msg(from, false, id); - msg.status = FMessage::STATUS_RECEIVED_BY_TARGET; - m_pEventHandler->onMessageStatusUpdate(&msg); - } - - out.write(ProtocolTreeNode("ack") - << XATTR("to", from) << XATTR("id", id) << XATTR("type", "read") << XATTRI("t", time(0))); -} - void WAConnection::parseChatStates(ProtocolTreeNode *node) throw (WAException) { const string &from = node->getAttributeValue("from"); @@ -298,6 +284,99 @@ void WAConnection::parseChatStates(ProtocolTreeNode *node) throw (WAException) } } +void WAConnection::parseIq(ProtocolTreeNode *node) throw(WAException) +{ + const string &type = node->getAttributeValue("type"); + if (type.empty()) + throw WAException("missing 'type' attribute in iq stanza", WAException::CORRUPT_STREAM_EX, 0); + + const string &id = node->getAttributeValue("id"); + const string &from = node->getAttributeValue("from"); + + if (type == "result") { + if (id.empty()) + throw WAException("missing 'id' attribute in iq stanza", WAException::CORRUPT_STREAM_EX, 0); + + std::map::iterator it = this->pending_server_requests.find(id); + if (it != this->pending_server_requests.end()) { + it->second->parse(node, from); + delete it->second; + this->pending_server_requests.erase(id); + } + else if (id.compare(0, this->user.size(), this->user) == 0) { + ProtocolTreeNode *accountNode = node->getChild(0); + ProtocolTreeNode::require(accountNode, "account"); + const string &kind = accountNode->getAttributeValue("kind"); + if (kind == "paid") + this->account_kind = 1; + else if (kind == "free") + this->account_kind = 0; + else + this->account_kind = -1; + + const string &expiration = accountNode->getAttributeValue("expiration"); + if (expiration.empty()) + throw WAException("no expiration"); + + this->expire_date = atol(expiration.c_str()); + if (this->expire_date == 0) + throw WAException("invalid expire date: " + expiration); + if (m_pEventHandler != NULL) + m_pEventHandler->onAccountChange(this->account_kind, this->expire_date); + } + else { + ProtocolTreeNode *childNode = node->getChild(0); + if (ProtocolTreeNode::tagEquals(childNode, "leave")) { + std::vector nodes(childNode->getAllChildren("group")); + for (size_t i = 0; i < nodes.size(); i++) { + ProtocolTreeNode *groupNode = nodes[i]; + const string &gjid = groupNode->getAttributeValue("id"); + if (m_pGroupEventHandler != NULL) + m_pGroupEventHandler->onLeaveGroup(gjid); + } + } + } + } + else if (type == "error") { + std::map::iterator it = this->pending_server_requests.find(id); + if (it != this->pending_server_requests.end()) { + it->second->error(node); + delete it->second; + this->pending_server_requests.erase(id); + } + } + else if (type == "get") { + ProtocolTreeNode *childNode = node->getChild(0); + if (ProtocolTreeNode::tagEquals(childNode, "ping")) { + if (m_pEventHandler != NULL) + m_pEventHandler->onPing(id); + } + else if ((ProtocolTreeNode::tagEquals(childNode, "query") && !from.empty()) ? false : (ProtocolTreeNode::tagEquals(childNode, "relay")) && !from.empty()) { + const string &pin = childNode->getAttributeValue("pin"); + if (!pin.empty() && m_pEventHandler != NULL) { + int timeoutSeconds = atoi(childNode->getAttributeValue("timeout").c_str()); + m_pEventHandler->onRelayRequest(pin, timeoutSeconds, id); + } + } + } + else if (type == "set") { + ProtocolTreeNode *childNode = node->getChild(0); + if (ProtocolTreeNode::tagEquals(childNode, "query")) { + const string &xmlns = childNode->getAttributeValue("xmlns"); + if (xmlns == "jabber:iq:roster") { + std::vector itemNodes(childNode->getAllChildren("item")); + for (size_t i = 0; i < itemNodes.size(); i++) { + ProtocolTreeNode *itemNode = itemNodes[i]; + const string &jid = itemNode->getAttributeValue("jid"); + const string &subscription = itemNode->getAttributeValue("subscription"); + // ask = itemNode->getAttributeValue("ask"); + } + } + } + } + else throw WAException("unknown iq type attribute: " + type, WAException::CORRUPT_STREAM_EX, 0); +} + void WAConnection::parseMessage(ProtocolTreeNode *messageNode) throw (WAException) { const string &id = messageNode->getAttributeValue("id"); @@ -321,23 +400,7 @@ void WAConnection::parseMessage(ProtocolTreeNode *messageNode) throw (WAExceptio message.status = FMessage::STATUS_SERVER_BOUNCE; if (m_pEventHandler != NULL) - m_pEventHandler->onMessageError(&message, errorCode); - } - else if (typeAttribute == "subject") { - bool receiptRequested = false; - std::vector requestNodes(messageNode->getAllChildren("request")); - for (size_t i = 0; i < requestNodes.size(); i++) { - ProtocolTreeNode *requestNode = requestNodes[i]; - if (requestNode->getAttributeValue("xmlns") == "urn:xmpp:receipts") - receiptRequested = true; - } - - ProtocolTreeNode *bodyNode = messageNode->getChild("body"); - if (bodyNode != NULL&& m_pGroupEventHandler != NULL) - m_pGroupEventHandler->onGroupNewSubject(from, author, bodyNode->getDataAsString(), atoi(attribute_t.c_str())); - - if (receiptRequested) - sendSubjectReceived(from, id); + m_pEventHandler->onMessageError(message, errorCode); } else if (typeAttribute == "text") { ProtocolTreeNode *body = messageNode->getChild("body"); @@ -347,6 +410,7 @@ void WAConnection::parseMessage(ProtocolTreeNode *messageNode) throw (WAExceptio FMessage fmessage(from, false, id); fmessage.wants_receipt = false; fmessage.timestamp = atoi(attribute_t.c_str()); + fmessage.remote_resource = messageNode->getAttributeValue("participant"); fmessage.notifyname = messageNode->getAttributeValue("notify"); fmessage.data = body->getDataAsString(); fmessage.status = FMessage::STATUS_UNSENT; @@ -354,8 +418,13 @@ void WAConnection::parseMessage(ProtocolTreeNode *messageNode) throw (WAExceptio fmessage.timestamp = time(NULL); fmessage.offline = false; } - if (m_pEventHandler != NULL) - m_pEventHandler->onMessageForMe(&fmessage, false); + + if (fmessage.remote_resource.empty()) { + if (m_pEventHandler != NULL) + m_pEventHandler->onMessageForMe(fmessage); + } + else if (m_pGroupEventHandler != NULL) + m_pGroupEventHandler->onGroupMessage(fmessage); } else if (typeAttribute == "media") { if (from.empty() || id.empty()) @@ -421,120 +490,87 @@ void WAConnection::parseMessage(ProtocolTreeNode *messageNode) throw (WAExceptio } if (m_pEventHandler != NULL) - m_pEventHandler->onMessageForMe(&fmessage, false); - } - else if (typeAttribute == "notification") { - logData("Notification node %s", messageNode->toString().c_str()); - bool flag = false; - std::vector children(messageNode->getAllChildren()); - for (size_t i = 0; i < children.size(); i++) { - ProtocolTreeNode *child = children[i]; - if (ProtocolTreeNode::tagEquals(child, "notification")) { - const string &type = child->getAttributeValue("type"); - if (type == "picture" && m_pEventHandler != NULL) { - std::vector children2(child->getAllChildren()); - for (unsigned j = 0; j < children2.size(); j++) { - ProtocolTreeNode *child2 = children2[j]; - if (ProtocolTreeNode::tagEquals(child2, "set")) { - const string &id = child2->getAttributeValue("id"); - const string &author = child2->getAttributeValue("author"); - if (!id.empty()) - m_pEventHandler->onPictureChanged(from, author, true); - } - else if (ProtocolTreeNode::tagEquals(child2, "delete")) { - const string &author = child2->getAttributeValue("author"); - m_pEventHandler->onPictureChanged(from, author, false); - } - } - } - } - else if (ProtocolTreeNode::tagEquals(child, "request")) - flag = true; - } - if (flag) - this->sendNotificationReceived(from, id); + m_pEventHandler->onMessageForMe(fmessage); } } -void WAConnection::parseIq(ProtocolTreeNode *node) throw(WAException) +void WAConnection::parseNotification(ProtocolTreeNode *node) throw(WAException) { - const string &type = node->getAttributeValue("type"); - if (type.empty()) - throw WAException("missing 'type' attribute in iq stanza", WAException::CORRUPT_STREAM_EX, 0); - const string &id = node->getAttributeValue("id"); const string &from = node->getAttributeValue("from"); + const string &type = node->getAttributeValue("type"); + if (type.empty() || from.empty() || m_pEventHandler == NULL) + return; - if (type == "result") { - if (id.empty()) - throw WAException("missing 'id' attribute in iq stanza", WAException::CORRUPT_STREAM_EX, 0); + const string &participant = node->getAttributeValue("participant"); + int ts = atoi(node->getAttributeValue("t").c_str()); - std::map::iterator it = this->pending_server_requests.find(id); - if (it != this->pending_server_requests.end()) { - it->second->parse(node, from); - delete it->second; - this->pending_server_requests.erase(id); - } - else if (id.compare(0, this->user.size(), this->user) == 0) { - ProtocolTreeNode *accountNode = node->getChild(0); - ProtocolTreeNode::require(accountNode, "account"); - const string &kind = accountNode->getAttributeValue("kind"); - if (kind == "paid") - this->account_kind = 1; - else if (kind == "free") - this->account_kind = 0; - else - this->account_kind = -1; + if (type == "contacts") { + std::vector children(node->getAllChildren()); + for (size_t i = 0; i < children.size(); i++) { + ProtocolTreeNode *child = children[i]; - const string &expiration = accountNode->getAttributeValue("expiration"); - if (expiration.empty()) - throw WAException("no expiration"); + const string &jid = node->getAttributeValue("jid"); + if (jid.empty()) continue; - this->expire_date = atol(expiration.c_str()); - if (this->expire_date == 0) - throw WAException("invalid expire date: " + expiration); - if (m_pEventHandler != NULL) - m_pEventHandler->onAccountChange(this->account_kind, this->expire_date); + bool bAdded; + if (ProtocolTreeNode::tagEquals(child, "add")) + bAdded = true; + else if (ProtocolTreeNode::tagEquals(child, "delete")) + bAdded = false; + else + continue; + + m_pEventHandler->onContactChanged(jid, bAdded); } } - else if (type == "error") { - std::map::iterator it = this->pending_server_requests.find(id); - if (it != this->pending_server_requests.end()) { - it->second->error(node); - delete it->second; - this->pending_server_requests.erase(id); + else if (type == "picture") { + std::vector children2(node->getAllChildren()); + for (unsigned j = 0; j < children2.size(); j++) { + ProtocolTreeNode *child2 = children2[j]; + if (ProtocolTreeNode::tagEquals(child2, "set")) { + const string &id = child2->getAttributeValue("id"); + const string &jid = child2->getAttributeValue("jid"); + if (!id.empty()) + m_pEventHandler->onPictureChanged(jid, id, true); + } + else if (ProtocolTreeNode::tagEquals(child2, "delete")) { + const string &jid = child2->getAttributeValue("jid"); + m_pEventHandler->onPictureChanged(jid, id, false); + } } } - else if (type == "get") { - ProtocolTreeNode *childNode = node->getChild(0); - if (ProtocolTreeNode::tagEquals(childNode, "ping")) { - if (m_pEventHandler != NULL) - m_pEventHandler->onPing(id); + // group chats + else if (type == "participant") { + ProtocolTreeNode *subNode = node->getChild("add"); + if (subNode != NULL) { + const string &jid = subNode->getAttributeValue("jid"); + if (m_pGroupEventHandler) + m_pGroupEventHandler->onGroupAddUser(from, jid, ts); } - else if ((ProtocolTreeNode::tagEquals(childNode, "query") && !from.empty()) ? false : (ProtocolTreeNode::tagEquals(childNode, "relay")) && !from.empty()) { - const string &pin = childNode->getAttributeValue("pin"); - if (!pin.empty() && m_pEventHandler != NULL) { - int timeoutSeconds = atoi(childNode->getAttributeValue("timeout").c_str()); - m_pEventHandler->onRelayRequest(pin, timeoutSeconds, id); - } + else if ((subNode = node->getChild("remove")) != NULL) { + const string &jid = subNode->getAttributeValue("jid"); + if (m_pGroupEventHandler) + m_pGroupEventHandler->onGroupRemoveUser(from, jid, ts); } + else return; + } - else if (type == "set") { - ProtocolTreeNode *childNode = node->getChild(0); - if (ProtocolTreeNode::tagEquals(childNode, "query")) { - const string &xmlns = childNode->getAttributeValue("xmlns"); - if (xmlns == "jabber:iq:roster") { - std::vector itemNodes(childNode->getAllChildren("item")); - for (size_t i = 0; i < itemNodes.size(); i++) { - ProtocolTreeNode *itemNode = itemNodes[i]; - const string &jid = itemNode->getAttributeValue("jid"); - const string &subscription = itemNode->getAttributeValue("subscription"); - // ask = itemNode->getAttributeValue("ask"); - } - } - } + else if (type == "subject") { + ProtocolTreeNode *bodyNode = node->getChild("body"); + if (bodyNode != NULL && m_pGroupEventHandler != NULL) + m_pGroupEventHandler->onGroupNewSubject(from, participant, bodyNode->getDataAsString(), ts); + return; // don't set ack } - else throw WAException("unknown iq type attribute: " + type, WAException::CORRUPT_STREAM_EX, 0); + + ProtocolTreeNode sendNode("ack"); + sendNode << XATTR("to", from) << XATTR("id", id) << XATTR("type", type) << XATTR("class", "notification"); + const string &to = node->getAttributeValue("to"); + if (!to.empty()) + sendNode << XATTR("from", to); + if (!participant.empty()) + sendNode << XATTR("participant", participant); + out.write(sendNode); } void WAConnection::parsePresense(ProtocolTreeNode *node) throw(WAException) @@ -544,17 +580,18 @@ void WAConnection::parsePresense(ProtocolTreeNode *node) throw(WAException) if (from.empty()) return; + int ts = atoi(node->getAttributeValue("t").c_str()); if (xmlns == "w" && !from.empty()) { const string &add = node->getAttributeValue("add"); const string &remove = node->getAttributeValue("remove"); const string &status = node->getAttributeValue("status"); if (!add.empty()) { if (m_pGroupEventHandler != NULL) - m_pGroupEventHandler->onGroupAddUser(from, add); + m_pGroupEventHandler->onGroupAddUser(from, add, ts); } else if (!remove.empty()) { if (m_pGroupEventHandler != NULL) - m_pGroupEventHandler->onGroupRemoveUser(from, remove); + m_pGroupEventHandler->onGroupRemoveUser(from, remove, ts); } else if (status == "dirty") { std::map categories = parseCategories(node); @@ -575,6 +612,22 @@ void WAConnection::parsePresense(ProtocolTreeNode *node) throw(WAException) } } +void WAConnection::parseReceipt(ProtocolTreeNode *node) throw(WAException) +{ + const string &from = node->getAttributeValue("from"); + const string &id = node->getAttributeValue("id"); + const string &ts = node->getAttributeValue("t"); + + if (m_pEventHandler != NULL) { + FMessage msg(from, false, id); + msg.status = FMessage::STATUS_RECEIVED_BY_TARGET; + m_pEventHandler->onMessageStatusUpdate(msg); + } + + out.write(ProtocolTreeNode("ack") + << XATTR("to", from) << XATTR("id", id) << XATTR("type", "read") << XATTRI("t", time(0))); +} + std::vector* WAConnection::processGroupSettings(const std::vector& groups) { std::vector* result = new std::vector(groups.size()); @@ -650,29 +703,11 @@ void WAConnection::sendDeleteAccount() throw (WAException) void WAConnection::sendGetGroups() throw (WAException) { m_pMutex->lock(); - std::string id = makeId("get_groups_"); + std::string id = makeId("iq_"); this->pending_server_requests[id] = new IqResultGetGroupsHandler(this, "participating"); - sendGetGroups(id, "participating"); - m_pMutex->unlock(); -} - -void WAConnection::sendGetGroups(const std::string &id, const std::string &type) throw (WAException) -{ - ProtocolTreeNode *listNode = new ProtocolTreeNode("list") - << XATTR("xmlns", "w:g") << XATTR("type", type); - - out.write(ProtocolTreeNode("iq", listNode) - << XATTR("id", id) << XATTR("type", "get") << XATTR("to", "g.us")); -} - -void WAConnection::sendGetOwningGroups() throw (WAException) -{ - m_pMutex->lock(); - std::string id = makeId("get_owning_groups_"); - this->pending_server_requests[id] = new IqResultGetGroupsHandler(this, "owning"); - - sendGetGroups(id, "owning"); + out.write(ProtocolTreeNode("iq", new ProtocolTreeNode("list") << XATTR("type", "participating")) + << XATTR("xmlns", "w:g") << XATTR("id", id) << XATTR("type", "get") << XATTR("to", "g.us")); m_pMutex->unlock(); } @@ -702,10 +737,9 @@ void WAConnection::sendGetServerProperties() throw (WAException) std::string id = makeId("get_server_properties_"); this->pending_server_requests[id] = new IqResultServerPropertiesHandler(this); - ProtocolTreeNode *listNode = new ProtocolTreeNode("list") - << XATTR("xmlns", "w:g") << XATTR("type", "props"); + ProtocolTreeNode *listNode = new ProtocolTreeNode("list") << XATTR("type", "props"); - out.write(ProtocolTreeNode("iq", listNode) + out.write(ProtocolTreeNode("iq", listNode) << XATTR("xmlns", "w:g2") << XATTR("id", id) << XATTR("type", "get") << XATTR("to", "g.us")); } @@ -775,22 +809,14 @@ void WAConnection::sendMessageWithBody(FMessage* message) throw (WAException) delete n; } -void WAConnection::sendMessageReceived(FMessage* message) throw(WAException) +void WAConnection::sendMessageReceived(const FMessage &message) throw(WAException) { out.write(ProtocolTreeNode("receipt") << XATTR("type", "read") - << XATTR("to", message->key.remote_jid) << XATTR("id", message->key.id) << XATTRI("t", (int)time(0))); + << XATTR("to", message.key.remote_jid) << XATTR("id", message.key.id) << XATTRI("t", (int)time(0))); } ///////////////////////////////////////////////////////////////////////////////////////// -void WAConnection::sendNotificationReceived(const std::string &jid, const std::string &id) throw(WAException) -{ - ProtocolTreeNode *child = new ProtocolTreeNode("received") << XATTR("xmlns", "urn:xmpp:receipts"); - - out.write(ProtocolTreeNode("message", child) - << XATTR("id", id) << XATTR("type", "notification") << XATTR("to", jid)); -} - void WAConnection::sendPaused(const std::string &to) throw(WAException) { out.write(ProtocolTreeNode("chatstate", new ProtocolTreeNode("paused")) << XATTR("to", to)); @@ -851,34 +877,26 @@ void WAConnection::sendStatusUpdate(std::string& status) throw (WAException) delete n; } -void WAConnection::sendSubjectReceived(const std::string &to, const std::string &id)throw(WAException) -{ - ProtocolTreeNode *receivedNode = new ProtocolTreeNode("received") << XATTR("xmlns", "urn:xmpp:receipts"); - - out.write(ProtocolTreeNode("message", receivedNode) - << XATTR("to", to) << XATTR("type", "subject") << XATTR("id", id)); -} - ///////////////////////////////////////////////////////////////////////////////////////// // Group chats void WAConnection::sendGetGroupInfo(const std::string &gjid) throw (WAException) { - std::string id = makeId("get_g_info_"); + std::string id = makeId("iq_"); this->pending_server_requests[id] = new IqResultGetGroupInfoHandler(this); - ProtocolTreeNode *queryNode = new ProtocolTreeNode("query") << XATTR("xmlns", "w:g"); - out.write(ProtocolTreeNode("iq", queryNode) + ProtocolTreeNode *queryNode = new ProtocolTreeNode("query") << XATTR("request", "interactive"); + out.write(ProtocolTreeNode("iq", queryNode) << XATTR("xmlns", "w:g2") << XATTR("id", id) << XATTR("type", "get") << XATTR("to", gjid)); } void WAConnection::sendGetParticipants(const std::string &gjid) throw (WAException) { - std::string id = makeId("get_participants_"); + std::string id = makeId("iq_"); this->pending_server_requests[id] = new IqResultGetGroupParticipantsHandler(this); - ProtocolTreeNode *listNode = new ProtocolTreeNode("list") << XATTR("xmlns", "w:g"); - out.write(ProtocolTreeNode("iq", listNode) + ProtocolTreeNode *listNode = new ProtocolTreeNode("list"); + out.write(ProtocolTreeNode("iq", listNode) << XATTR("xmlns", "w:g") << XATTR("id", id) << XATTR("type", "get") << XATTR("to", gjid)); } @@ -895,24 +913,14 @@ void WAConnection::sendCreateGroupChat(const std::string &subject) throw (WAExce { logData("sending create group: %s", subject.c_str()); std::string id = makeId("create_group_"); - this->pending_server_requests[id] = new IqResultCreateGroupChatHandler(this); + this->pending_server_requests[id] = new IqResultCreateGroupChatHandler(this, subject); - ProtocolTreeNode *groupNode = new ProtocolTreeNode("group") - << XATTR("xmlns", "w:g") << XATTR("action", "create") << XATTR("subject", subject); + ProtocolTreeNode *groupNode = new ProtocolTreeNode("group") << XATTR("action", "create") << XATTR("subject", subject); - out.write(ProtocolTreeNode("iq", groupNode) + out.write(ProtocolTreeNode("iq", groupNode) << XATTR("xmlns", "w:g") << XATTR("id", id) << XATTR("type", "set") << XATTR("to", "g.us")); } -void WAConnection::sendEndGroupChat(const std::string &gjid) throw (WAException) -{ - std::string id = makeId("remove_group_"); - - ProtocolTreeNode *groupNode = new ProtocolTreeNode("group") << XATTR("xmlns", "w:g") << XATTR("action", "delete"); - out.write(ProtocolTreeNode("iq", groupNode) - << XATTR("id", id) << XATTR("type", "set") << XATTR("to", gjid)); -} - void WAConnection::sendClearDirty(const std::string &category) throw (WAException) { std::string id = makeId("clean_dirty_"); @@ -924,49 +932,48 @@ void WAConnection::sendClearDirty(const std::string &category) throw (WAExceptio << XATTR("id", id) << XATTR("type", "set") << XATTR("to", "s.whatsapp.net")); } -void WAConnection::sendLeaveGroup(const std::string &gjid) throw (WAException) +void WAConnection::sendJoinLeaveGroup(const char *gjid, bool bJoin) throw (WAException) { - std::string id = makeId("leave_group_"); + std::string id = makeId("iq_"); ProtocolTreeNode *groupNode = new ProtocolTreeNode("group") << XATTR("id", gjid); - ProtocolTreeNode *leaveNode = new ProtocolTreeNode("leave", groupNode) << XATTR("xmlns", "w:g"); - out.write(ProtocolTreeNode("iq", leaveNode) + ProtocolTreeNode *leaveNode = new ProtocolTreeNode((bJoin) ? "join" : "leave", groupNode); + out.write(ProtocolTreeNode("iq", leaveNode) << XATTR("xmlns", "w:g2") << XATTR("id", id) << XATTR("type", "set") << XATTR("to", "g.us")); } -void WAConnection::sendAddParticipants(const std::string &gjid, const std::vector& participants) throw (WAException) +void WAConnection::sendAddParticipants(const std::string &gjid, const std::vector &participants) throw (WAException) { - std::string id = makeId("add_group_participants_"); - this->sendVerbParticipants(gjid, participants, id, "add"); + sendVerbParticipants(gjid, participants, "add"); } -void WAConnection::sendRemoveParticipants(const std::string &gjid, const std::vector& participants) throw (WAException) +void WAConnection::sendRemoveParticipants(const std::string &gjid, const std::vector &participants) throw (WAException) { - std::string id = makeId("remove_group_participants_"); - this->sendVerbParticipants(gjid, participants, id, "remove"); + sendVerbParticipants(gjid, participants, "remove"); } -void WAConnection::sendVerbParticipants(const std::string &gjid, const std::vector& participants, const std::string &id, const std::string &inner_tag) throw (WAException) +void WAConnection::sendVerbParticipants(const std::string &gjid, const std::vector &participants, const std::string &inner_tag) throw (WAException) { + std::string id = makeId("iq_"); + size_t size = participants.size(); std::vector* children = new std::vector(size); for (size_t i = 0; i < size; i++) (*children)[i] = new ProtocolTreeNode("participant") << XATTR("jid", participants[i]); - ProtocolTreeNode *innerNode = new ProtocolTreeNode(inner_tag, NULL, children) - << XATTR("xmlns", "w:g"); + ProtocolTreeNode *innerNode = new ProtocolTreeNode(inner_tag, NULL, children); - out.write(ProtocolTreeNode("iq", innerNode) + out.write(ProtocolTreeNode("iq", innerNode) << XATTR("xmlns", "w:g") << XATTR("id", id) << XATTR("type", "set") << XATTR("to", gjid)); } void WAConnection::sendSetNewSubject(const std::string &gjid, const std::string &subject) throw (WAException) { - std::string id = this->makeId("set_group_subject_"); + std::string id = this->makeId("iq_"); - ProtocolTreeNode *subjectNode = new ProtocolTreeNode("subject") - << XATTR("xmlns", "w:g") << XATTR("value", subject); + std::vector *data = new std::vector(subject.begin(), subject.end()); + ProtocolTreeNode *subjectNode = new ProtocolTreeNode("subject", data); - out.write(ProtocolTreeNode("iq", subjectNode) + out.write(ProtocolTreeNode("iq", subjectNode) << XATTR("xmlns", "w:g2") << XATTR("id", id) << XATTR("type", "set") << XATTR("to", gjid)); } diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h index 6f4fb2b4f2..bddfe1ccd7 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h +++ b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h @@ -30,42 +30,41 @@ class BinTreeNodeReader; class WAListener { public: - virtual void onMessageForMe(FMessage* paramFMessage, bool paramBoolean) throw (WAException)=0; - virtual void onMessageStatusUpdate(FMessage* paramFMessage)=0; - virtual void onMessageError(FMessage* message, int paramInt)=0; - virtual void onPing(const std::string& paramString) throw (WAException)=0; - virtual void onPingResponseReceived()=0; - virtual void onAvailable(const std::string& paramString, bool paramBoolean)=0; - virtual void onClientConfigReceived(const std::string& paramString)=0; - virtual void onLastSeen(const std::string& paramString1, int paramInt, const string ¶mString2) = 0; - virtual void onIsTyping(const std::string& paramString, bool paramBoolean)=0; - virtual void onAccountChange(int paramInt, time_t paramLong)=0; - virtual void onPrivacyBlockListAdd(const std::string& paramString)=0; - virtual void onPrivacyBlockListClear()=0; - virtual void onDirty(const std::map& paramHashtable)=0; - virtual void onDirtyResponse(int paramHashtable)=0; - virtual void onRelayRequest(const std::string& paramString1, int paramInt, const std::string& paramString2)=0; - virtual void onSendGetPicture(const std::string& jid, const std::vector& data, const std::string& id)=0; - virtual void onPictureChanged(const std::string& from, const std::string& author, bool set)=0; - virtual void onDeleteAccount(bool result)=0; + virtual void onMessageForMe(const FMessage ¶mFMessage) throw (WAException) = 0; + virtual void onMessageStatusUpdate(const FMessage ¶mFMessage) = 0; + virtual void onMessageError(const FMessage &message, int paramInt) = 0; + virtual void onPing(const std::string ¶mString) throw (WAException) = 0; + virtual void onPingResponseReceived() = 0; + virtual void onAvailable(const std::string ¶mString, bool paramBoolean) = 0; + virtual void onClientConfigReceived(const std::string ¶mString) = 0; + virtual void onLastSeen(const std::string ¶mString1, int paramInt, const string ¶mString2) = 0; + virtual void onIsTyping(const std::string ¶mString, bool paramBoolean) = 0; + virtual void onAccountChange(int paramInt, time_t paramLong) = 0; + virtual void onPrivacyBlockListAdd(const std::string ¶mString) = 0; + virtual void onPrivacyBlockListClear() = 0; + virtual void onDirty(const std::map& paramHashtable) = 0; + virtual void onDirtyResponse(int paramHashtable) = 0; + virtual void onRelayRequest(const std::string ¶mString1, int paramInt, const std::string ¶mString2) = 0; + virtual void onSendGetPicture(const std::string &jid, const std::vector& data, const std::string &id) = 0; + virtual void onContactChanged(const std::string &jid, bool added) = 0; + virtual void onPictureChanged(const std::string &jid, const std::string &id, bool set) = 0; + virtual void onDeleteAccount(bool result) = 0; }; class WAGroupListener { public: - virtual void onGroupAddUser(const std::string& paramString1, const std::string& paramString2)=0; - virtual void onGroupRemoveUser(const std::string& paramString1, const std::string& paramString2)=0; - virtual void onGroupNewSubject(const std::string& from, const std::string& author, const std::string& newSubject, int paramInt)=0; - virtual void onServerProperties(std::map* nameValueMap)=0; - virtual void onGroupCreated(const std::string& paramString1, const std::string& paramString2)=0; - virtual void onGroupInfo(const std::string& paramString1, const std::string& paramString2, const std::string& paramString3, const std::string& paramString4, int paramInt1, int paramInt2)=0; - virtual void onGroupInfoFromList(const std::string& paramString1, const std::string& paramString2, const std::string& paramString3, const std::string& paramString4, int paramInt1, int paramInt2)=0; - virtual void onOwningGroups(const std::vector& paramVector)=0; - virtual void onSetSubject(const std::string& paramString)=0; - virtual void onAddGroupParticipants(const std::string& paramString, const std::vector& paramVector, int paramHashtable)=0; - virtual void onRemoveGroupParticipants(const std::string& paramString, const std::vector& paramVector, int paramHashtable)=0; - virtual void onGetParticipants(const std::string& gjid, const std::vector& participants)=0; - virtual void onParticipatingGroups(const std::vector& paramVector)=0; - virtual void onLeaveGroup(const std::string& paramString)=0; + virtual void onGroupAddUser(const std::string &gjid, const std::string &ujid, int ts) = 0; + virtual void onGroupRemoveUser(const std::string &gjid, const std::string &ujid, int ts) = 0; + virtual void onGroupNewSubject(const std::string &from, const std::string &author, const std::string &newSubject, int paramInt) = 0; + virtual void onGroupMessage(const FMessage ¶mFMessage) = 0; + virtual void onServerProperties(std::map* nameValueMap) = 0; + virtual void onGroupCreated(const std::string &gjid, const std::string &nick) = 0; + virtual void onGroupInfo(const std::string &jid, const std::string &owner, const std::string &subject, const std::string &subject_owner, int time_subject, int time_created) = 0; + virtual void onSetSubject(const std::string ¶mString) = 0; + virtual void onAddGroupParticipants(const std::string ¶mString, const std::vector ¶mVector, int paramHashtable) = 0; + virtual void onRemoveGroupParticipants(const std::string ¶mString, const std::vector ¶mVector, int paramHashtable) = 0; + virtual void onGetParticipants(const std::string &gjid, const std::vector &participants) = 0; + virtual void onLeaveGroup(const std::string ¶mString) = 0; }; class GroupSetting { @@ -88,7 +87,7 @@ class WAConnection WAConnection* con; public: IqResultHandler(WAConnection* con) {this->con = con;} - virtual void parse(ProtocolTreeNode* paramProtocolTreeNode, const std::string& paramString) throw (WAException)=0; + virtual void parse(ProtocolTreeNode* paramProtocolTreeNode, const std::string ¶mString) throw (WAException)=0; void error(ProtocolTreeNode* node, int code) { con->logData("WAConnection: error node %s: code = %d", node->getAttributeValue("id").c_str(), code); } @@ -112,7 +111,7 @@ class WAConnection class IqResultPingHandler: public IqResultHandler { public: IqResultPingHandler(WAConnection* con):IqResultHandler(con) {} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { if (this->con->m_pEventHandler != NULL) this->con->m_pEventHandler->onPingResponseReceived(); } @@ -127,23 +126,17 @@ class WAConnection private: std::string type; public: - IqResultGetGroupsHandler(WAConnection* con, const std::string& type ):IqResultHandler(con) {this->type = type;} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + IqResultGetGroupsHandler(WAConnection* con, const std::string &type ):IqResultHandler(con) {this->type = type;} + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { std::vector groups; this->con->readGroupList(node, groups); - if (this->con->m_pGroupEventHandler != NULL) { - if (this->type.compare("participating") == 0) - this->con->m_pGroupEventHandler->onParticipatingGroups(groups); - else if (this->type.compare("owning") == 0) - this->con->m_pGroupEventHandler->onOwningGroups(groups); - } } }; class IqResultServerPropertiesHandler: public IqResultHandler { public: IqResultServerPropertiesHandler(WAConnection* con):IqResultHandler(con) {} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { std::vector nodes(node->getAllChildren("prop")); std::map nameValueMap; for (size_t i = 0; i < nodes.size();i++) { @@ -161,7 +154,7 @@ class WAConnection class IqResultPrivayListHandler: public IqResultHandler { public: IqResultPrivayListHandler(WAConnection* con):IqResultHandler(con) {} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { ProtocolTreeNode* queryNode = node->getChild(0); ProtocolTreeNode::require(queryNode, "query"); ProtocolTreeNode* listNode = queryNode->getChild(0); @@ -185,7 +178,7 @@ class WAConnection class IqResultGetGroupInfoHandler: public IqResultHandler { public: IqResultGetGroupInfoHandler(WAConnection* con):IqResultHandler(con) {} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { ProtocolTreeNode* groupNode = node->getChild(0); ProtocolTreeNode::require(groupNode, "group"); const string &owner = groupNode->getAttributeValue("owner"); @@ -201,30 +194,34 @@ class WAConnection class IqResultGetGroupParticipantsHandler: public IqResultHandler { public: IqResultGetGroupParticipantsHandler(WAConnection* con):IqResultHandler(con) {} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { - std::vector participants; - this->con->readAttributeList(node, participants, "participant", "jid"); - if (this->con->m_pGroupEventHandler != NULL) + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { + if (this->con->m_pGroupEventHandler != NULL) { + std::vector participants; + this->con->readAttributeList(node, participants, "participant", "jid"); this->con->m_pGroupEventHandler->onGetParticipants(from, participants); + } } }; class IqResultCreateGroupChatHandler: public IqResultHandler { + std::string subject; public: - IqResultCreateGroupChatHandler(WAConnection* con):IqResultHandler(con) {} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + IqResultCreateGroupChatHandler(WAConnection* con, const std::string &_subject) : + IqResultHandler(con), + subject(_subject) {} + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { ProtocolTreeNode* groupNode = node->getChild(0); ProtocolTreeNode::require(groupNode, "group"); const string &groupId = groupNode->getAttributeValue("id"); if (!groupId.empty() && con->m_pGroupEventHandler != NULL) - this->con->m_pGroupEventHandler->onGroupCreated(from, groupId); + this->con->m_pGroupEventHandler->onGroupCreated(groupId + "@" + from, subject); } }; class IqResultQueryLastOnlineHandler: public IqResultHandler { public: IqResultQueryLastOnlineHandler(WAConnection* con):IqResultHandler(con) {} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { ProtocolTreeNode* firstChild = node->getChild(0); ProtocolTreeNode::require(firstChild, "query"); const string &seconds = firstChild->getAttributeValue("seconds"); @@ -241,10 +238,10 @@ class WAConnection std::string oldId; std::string newId; public: - IqResultGetPhotoHandler(WAConnection* con, const std::string& jid):IqResultHandler(con) { + IqResultGetPhotoHandler(WAConnection* con, const std::string &jid):IqResultHandler(con) { this->jid = jid; } - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { const string &attributeValue = node->getAttributeValue("type"); if (!attributeValue.empty() && attributeValue == "result" && this->con->m_pEventHandler != NULL) { @@ -272,8 +269,8 @@ class WAConnection private: std::string jid; public: - IqResultSetPhotoHandler(WAConnection* con, const std::string& jid):IqResultHandler(con) {this->jid = jid;} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + IqResultSetPhotoHandler(WAConnection* con, const std::string &jid):IqResultHandler(con) {this->jid = jid;} + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { if (this->con->m_pEventHandler != NULL) { ProtocolTreeNode* child = node->getChild("picture"); if (child != NULL) @@ -287,7 +284,7 @@ class WAConnection class IqResultSendDeleteAccount: public IqResultHandler { public: IqResultSendDeleteAccount(WAConnection* con):IqResultHandler(con) {} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { if (this->con->m_pEventHandler != NULL) this->con->m_pEventHandler->onDeleteAccount(true); } @@ -301,14 +298,14 @@ class WAConnection class IqResultClearDirtyHandler: public IqResultHandler { public: IqResultClearDirtyHandler(WAConnection* con):IqResultHandler(con) {} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { } }; class IqSendClientConfigHandler: public IqResultHandler { public: IqSendClientConfigHandler(WAConnection* con):IqResultHandler(con) {} - virtual void parse(ProtocolTreeNode* node, const std::string& from) throw (WAException) { + virtual void parse(ProtocolTreeNode* node, const std::string &from) throw (WAException) { con->logData("Clientconfig response %s", node->toString().c_str()); } @@ -334,25 +331,25 @@ private: void parseChatStates(ProtocolTreeNode *node) throw (WAException); void parseIq(ProtocolTreeNode *node) throw(WAException); void parseMessage(ProtocolTreeNode* node) throw(WAException); + void parseNotification(ProtocolTreeNode *node) throw(WAException); void parsePresense(ProtocolTreeNode*) throw(WAException); void parseReceipt(ProtocolTreeNode *node) throw (WAException); std::map parseCategories(ProtocolTreeNode* node) throw(WAException); void sendMessageWithMedia(FMessage* message) throw(WAException); void sendMessageWithBody(FMessage* message) throw(WAException); - ProtocolTreeNode* getReceiptAck(const std::string& to, const std::string& id, const std::string& receiptType) throw(WAException); - std::string makeId(const std::string& prefix); - void sendGetGroups(const std::string& id, const std::string& type) throw (WAException); + ProtocolTreeNode* getReceiptAck(const std::string &to, const std::string &id, const std::string &receiptType) throw(WAException); + std::string makeId(const std::string &prefix); void readGroupList(ProtocolTreeNode* node, std::vector& groups) throw (WAException); - std::string gidToGjid(const std::string& gid); - void readAttributeList(ProtocolTreeNode* node, std::vector& vector, const std::string& tag, const std::string& attribute) throw (WAException); - void sendVerbParticipants(const std::string& gjid, const std::vector& participants, const std::string& id, const std::string& inner_tag) throw (WAException); + std::string gidToGjid(const std::string &gid); + void readAttributeList(ProtocolTreeNode* node, std::vector &vector, const std::string &tag, const std::string &attribute) throw (WAException); + void sendVerbParticipants(const std::string &gjid, const std::vector &participants, const std::string &inner_tag) throw (WAException); bool supportsReceiptAcks(); static ProtocolTreeNode* getMessageNode(FMessage* message, ProtocolTreeNode* node); std::vector* processGroupSettings(const std::vector& gruops); public: - WAConnection(const std::string& user, const std::string& resource, IMutex* mutex, IMutex *write_mutex, ISocketConnection *conn, WAListener* m_pEventHandler, WAGroupListener* m_pGroupEventHandler); + WAConnection(const std::string &user, const std::string &resource, IMutex* mutex, IMutex *write_mutex, ISocketConnection *conn, WAListener* m_pEventHandler, WAGroupListener* m_pGroupEventHandler); virtual ~WAConnection(); std::string user; @@ -374,7 +371,7 @@ public: void logData(const char *format, ...); - static std::string removeResourceFromJid(const std::string& jid); + static std::string removeResourceFromJid(const std::string &jid); void setLogin(WALogin *login); void setVerboseId(bool b); @@ -384,36 +381,32 @@ public: bool read() throw(WAException); void sendPing() throw(WAException); - void sendQueryLastOnline(const std::string& jid) throw (WAException); - void sendPong(const std::string& id) throw(WAException); - void sendComposing(const std::string& to) throw(WAException); + void sendQueryLastOnline(const std::string &jid) throw (WAException); + void sendPong(const std::string &id) throw(WAException); + void sendComposing(const std::string &to) throw(WAException); void sendActive() throw(WAException); void sendInactive() throw(WAException); - void sendPaused(const std::string& to) throw(WAException); - void sendSubjectReceived(const std::string& to, const std::string& id) throw(WAException); - void sendMessageReceived(FMessage* message) throw(WAException); - void sendPresenceSubscriptionRequest(const std::string& to) throw (WAException); - void sendClientConfig(const std::string& sound, const std::string& pushID, bool preview, const std::string& platform) throw(WAException); - void sendClientConfig(const std::string& pushID, bool preview, const std::string& platform, bool defaultSettings, bool groupSettings, const std::vector& groups) throw(WAException); + void sendPaused(const std::string &to) throw(WAException); + void sendMessageReceived(const FMessage &message) throw(WAException); + void sendPresenceSubscriptionRequest(const std::string &to) throw (WAException); + void sendClientConfig(const std::string &sound, const std::string &pushID, bool preview, const std::string &platform) throw(WAException); + void sendClientConfig(const std::string &pushID, bool preview, const std::string &platform, bool defaultSettings, bool groupSettings, const std::vector& groups) throw(WAException); void sendClose() throw (WAException); void sendAvailable() throw (WAException); // U.H. void sendGetPrivacyList() throw (WAException); void sendGetServerProperties() throw (WAException); void sendGetGroups() throw (WAException); - void sendGetOwningGroups() throw (WAException); - void sendCreateGroupChat(const std::string& subject) throw (WAException); - void sendEndGroupChat(const std::string& gjid) throw (WAException); - void sendGetGroupInfo(const std::string& gjid) throw (WAException); - void sendGetParticipants(const std::string& gjid) throw (WAException); - void sendClearDirty(const std::string& category) throw (WAException); - void sendLeaveGroup(const std::string& gjid) throw (WAException); - void sendAddParticipants(const std::string& gjid, const std::vector& participants) throw (WAException); - void sendRemoveParticipants(const std::string& gjid, const std::vector& participants) throw (WAException); - void sendSetNewSubject(const std::string& gjid, const std::string& subject) throw (WAException); + void sendCreateGroupChat(const std::string &subject) throw (WAException); + void sendGetGroupInfo(const std::string &gjid) throw (WAException); + void sendGetParticipants(const std::string &gjid) throw (WAException); + void sendClearDirty(const std::string &category) throw (WAException); + void sendJoinLeaveGroup(const char *gjid, bool bJoin) throw (WAException); + void sendAddParticipants(const std::string &gjid, const std::vector &participants) throw (WAException); + void sendRemoveParticipants(const std::string &gjid, const std::vector &participant) throw (WAException); + void sendSetNewSubject(const std::string &gjid, const std::string &subject) throw (WAException); void sendStatusUpdate(std::string& status) throw (WAException); - void sendGetPicture(const std::string& jid, const std::string& type) throw (WAException); - void sendSetPicture(const std::string& jid, std::vector* data, std::vector* preview) throw (WAException); - void sendNotificationReceived(const std::string& from, const std::string& id) throw(WAException); + void sendGetPicture(const std::string &jid, const std::string &type) throw (WAException); + void sendSetPicture(const std::string &jid, std::vector* data, std::vector* preview) throw (WAException); void sendDeleteAccount() throw(WAException); }; diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAException.h b/protocols/WhatsApp/src/WhatsAPI++/WAException.h index 47d5cdfaf7..4255850ffc 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WAException.h +++ b/protocols/WhatsApp/src/WhatsAPI++/WAException.h @@ -32,9 +32,9 @@ public: static const int SOCKET_EX_SEND = 3; static const int SOCKET_EX_RECV = 4; - WAException(const std::string& err): runtime_error(err) {this->type = 0; this->subtype = 0; this->expire_date = 0;}; - WAException(const std::string& err, int type, int subtype): runtime_error(err), type(type), subtype(subtype), expire_date(0) {}; - WAException(const std::string& err, int type, int subtype, time_t expireDate): runtime_error(err), type(type), subtype(subtype), expire_date(expireDate) {}; + WAException(const std::string &err): runtime_error(err) {this->type = 0; this->subtype = 0; this->expire_date = 0;}; + WAException(const std::string &err, int type, int subtype): runtime_error(err), type(type), subtype(subtype), expire_date(0) {}; + WAException(const std::string &err, int type, int subtype, time_t expireDate): runtime_error(err), type(type), subtype(subtype), expire_date(expireDate) {}; }; #endif /* WAEXCEPTION_H_ */ diff --git a/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp b/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp index edec990dfa..80be5402ed 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/WALogin.cpp @@ -8,7 +8,6 @@ #include "WALogin.h" #include "ByteArray.h" #include "ProtocolTreeNode.h" -#include "WAException.h" #include #include #include @@ -18,7 +17,7 @@ using namespace Utilities; -WALogin::WALogin(WAConnection* connection, const std::string& password) +WALogin::WALogin(WAConnection* connection, const std::string &password) { m_pConnection = connection; m_szPassword = password; @@ -97,12 +96,9 @@ std::vector* WALogin::getAuthBlob(const std::vector WALogin::readFeaturesUntilChallengeOrSuccess() { while (ProtocolTreeNode *root = m_pConnection->in.nextTree()) { - #ifdef _DEBUG - { - string tmp = root->toString(); - m_pConnection->logData(tmp.c_str()); - } - #endif + string tmp = root->toString(); + m_pConnection->logData(tmp.c_str()); + if (ProtocolTreeNode::tagEquals(root, "stream:features")) { m_pConnection->supports_receipt_acks = root->getChild("receipt_acks") != NULL; delete root; diff --git a/protocols/WhatsApp/src/WhatsAPI++/WALogin.h b/protocols/WhatsApp/src/WhatsAPI++/WALogin.h index 30c5937810..0d4d30af5b 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WALogin.h +++ b/protocols/WhatsApp/src/WhatsAPI++/WALogin.h @@ -35,7 +35,7 @@ public: void init(unsigned char *_key, unsigned char *_keyMac); - static void keyFromPasswordAndNonce(const std::string& pass, const std::vector& nonce, unsigned char *out); + static void keyFromPasswordAndNonce(const std::string &pass, const std::vector& nonce, unsigned char *out); void decodeMessage(unsigned char* buffer, int macOffset, int offset, const int length); void encodeMessage(unsigned char* buffer, int macOffset, int offset, const int length); }; @@ -58,7 +58,7 @@ public: int m_iAccountKind; std::string m_szPassword; - WALogin(WAConnection* connection, const std::string& password); + WALogin(WAConnection* connection, const std::string &password); ~WALogin(); std::vector login(const std::vector &blob); diff --git a/protocols/WhatsApp/src/WhatsAPI++/utilities.cpp b/protocols/WhatsApp/src/WhatsAPI++/utilities.cpp index 0734c34210..1c6f28e009 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/utilities.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/utilities.cpp @@ -14,7 +14,7 @@ const static char digits[] = { 'u', 'v', 'w', 'x', 'y', 'z' }; -std::string reverseString(const std::string& str) +std::string reverseString(const std::string &str) { return std::string(str.rbegin(), str.rend()); } @@ -51,7 +51,7 @@ std::string itoa(int value, unsigned int base) } -std::string processIdentity(const std::string& id) +std::string processIdentity(const std::string &id) { std::string buffer_str = reverseString(id); @@ -69,7 +69,7 @@ std::string processIdentity(const std::string& id) return buffer_str; } -void debug(const std::string& msg) +void debug(const std::string &msg) { #ifdef _LOGWIN32 cout << "DEBUG: " << msg << endl; @@ -153,7 +153,7 @@ time_t parseBBDate(const string& s) return mktime(&timeinfo); } -long long parseLongLong(const std::string& str) +long long parseLongLong(const std::string &str) { std::stringstream sstr(str); long long val; @@ -235,7 +235,7 @@ vector* loadFileToBytes(const string& path) return bytes; } -bool fileExists(const std::string& path) +bool fileExists(const std::string &path) { return _access(path.c_str(), 0) == 0; } @@ -260,7 +260,7 @@ string removeWaDomainFromJid(const string& jid) return jid; } -string getNameFromPath(const std::string& path) +string getNameFromPath(const std::string &path) { size_t i = path.rfind('/'); if (i == string::npos) @@ -270,17 +270,17 @@ string getNameFromPath(const std::string& path) return path.substr(i); } -vector* getChallengeData(const std::string& challengeFile) +vector* getChallengeData(const std::string &challengeFile) { return loadFileToBytes(challengeFile); } -bool saveChallengeData(const std::vector& data, const std::string& challengeFile) +bool saveChallengeData(const std::vector& data, const std::string &challengeFile) { return saveBytesToFile(data, challengeFile); } -std::string utf8_to_utf16(const std::string& utf8) +std::string utf8_to_utf16(const std::string &utf8) { std::vector unicode; size_t i = 0; diff --git a/protocols/WhatsApp/src/WhatsAPI++/utilities.h b/protocols/WhatsApp/src/WhatsAPI++/utilities.h index 4df6fde13d..5f5dd5713a 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/utilities.h +++ b/protocols/WhatsApp/src/WhatsAPI++/utilities.h @@ -38,20 +38,20 @@ using namespace std; // these functions must be declared somewhere in the same linking module std::string base64_encode(void*, size_t); -void md5_string(const std::string& data, unsigned char digest[16]); +void md5_string(const std::string &data, unsigned char digest[16]); namespace Utilities{ string getMcc(); string getMnc(); string reverseString(const string& str); - string processIdentity(const std::string& password); + string processIdentity(const std::string &password); int64_t randLong(); int64_t absLong(int64_t num); string str(int64_t number, int radix); std::string itoa(int value, unsigned int base); std::string intToStr(int i); std::string doubleToStr(double d); - long long parseLongLong(const std::string& str); + long long parseLongLong(const std::string &str); time_t parseBBDate(const string& s); long long getCurrentTimeMillis(); std::string bytesToHex(unsigned char* bytes, int length); @@ -60,11 +60,11 @@ namespace Utilities{ bool saveBytesToFile(const string& data, const string& filePath); bool saveBytesToFile(const std::vector& data, const string& filePath); string removeWaDomainFromJid(const string& jid); - string getNameFromPath(const std::string& path); + string getNameFromPath(const std::string &path); vector* loadFileToBytes(const string& path); - bool fileExists(const std::string& path); - std::vector* getChallengeData(const std::string& file); - bool saveChallengeData(const std::vector& data, const std::string& file); - std::string utf8_to_utf16(const std::string& utf8); + bool fileExists(const std::string &path); + std::vector* getChallengeData(const std::string &file); + bool saveChallengeData(const std::vector& data, const std::string &file); + std::string utf8_to_utf16(const std::string &utf8); } #endif diff --git a/protocols/WhatsApp/src/chat.cpp b/protocols/WhatsApp/src/chat.cpp index 361da25850..1f855f9b55 100644 --- a/protocols/WhatsApp/src/chat.cpp +++ b/protocols/WhatsApp/src/chat.cpp @@ -1,64 +1,485 @@ #include "common.h" -// #TODO Remove, as we are not using the chat-module for groups anymore +static const TCHAR *sttStatuses[] = { LPGENT("Members"), LPGENT("Owners") }; -INT_PTR WhatsAppProto::OnJoinChat(WPARAM, LPARAM) +enum { - return 0; -} + IDM_CANCEL, + + IDM_INVITE, IDM_LEAVE, IDM_TOPIC, -INT_PTR WhatsAppProto::OnLeaveChat(WPARAM, LPARAM) + IDM_MESSAGE, IDM_KICK, + IDM_CPY_NICK, IDM_CPY_TOPIC, + IDM_ADD_RJID, IDM_CPY_RJID +}; + +///////////////////////////////////////////////////////////////////////////////////////// +// protocol menu handler - create a new group + +INT_PTR __cdecl WhatsAppProto::OnCreateGroup(WPARAM wParam, LPARAM lParam) { - return 0; + ENTER_STRING es = { 0 }; + es.cbSize = sizeof(es); + es.type = ESF_MULTILINE; + es.caption = _T("Enter a subject for new group"); + es.szModuleName = m_szModuleName; + if (EnterString(&es)) { + if (isOnline()) { + std::string groupName(ptrA(mir_utf8encodeT(es.ptszResult))); + m_pConnection->sendCreateGroupChat(groupName); + } + mir_free(es.ptszResult); + } + + return FALSE; } -int WhatsAppProto::OnChatOutgoing(WPARAM wParam, LPARAM lParam) +///////////////////////////////////////////////////////////////////////////////////////// +// handler to pass events from SRMM to WAConnection + +int WhatsAppProto::onGroupChatEvent(WPARAM wParam, LPARAM lParam) { - GCHOOK *hook = reinterpret_cast(lParam); - char *text; + GCHOOK *gch = (GCHOOK*)lParam; + if (mir_strcmp(gch->pDest->pszModule, m_szModuleName)) + return 0; - if (strcmp(hook->pDest->pszModule, m_szModuleName)) + std::string chat_id(ptrA(mir_utf8encodeT(gch->pDest->ptszID))); + WAChatInfo *pInfo = SafeGetChat(chat_id); + if (pInfo == NULL) return 0; - switch (hook->pDest->iType) { + switch (gch->pDest->iType) { + case GC_USER_LEAVE: + case GC_SESSION_TERMINATE: + break; + + case GC_USER_LOGMENU: + ChatLogMenuHook(pInfo, gch); + break; + + case GC_USER_NICKLISTMENU: + NickListMenuHook(pInfo, gch); + break; + case GC_USER_MESSAGE: - text = mir_t2a_cp(hook->ptszText, CP_UTF8); - { - std::string msg = text; - - char *id = mir_t2a_cp(hook->pDest->ptszID, CP_UTF8); - std::string chat_id = id; - - mir_free(text); - mir_free(id); - - if (isOnline()) { - MCONTACT hContact = this->ContactIDToHContact(chat_id); - if (hContact) { - debugLogA("**Chat - Outgoing message: %s", text); - this->SendMsg(hContact, IS_CHAT, msg.c_str()); - - GCDEST gcd = { m_szModuleName, hook->pDest->ptszID, GC_EVENT_MESSAGE }; - GCEVENT gce = { sizeof(gce), &gcd }; - gce.dwFlags = GCEF_ADDTOLOG; - gce.ptszNick = mir_a2t(m_szNick.c_str()); - gce.ptszUID = mir_a2t(m_szJid.c_str()); - gce.time = time(NULL); - gce.ptszText = hook->ptszText; - gce.bIsMe = TRUE; - CallServiceSync(MS_GC_EVENT, 0, (LPARAM)&gce); - - mir_free((void*)gce.ptszUID); - mir_free((void*)gce.ptszNick); - } + if (isOnline()) { + std::string msg(ptrA(mir_utf8encodeT(gch->ptszText))); + + try { + int msgId = GetSerial(); + time_t now = time(NULL); + std::string id = Utilities::intToStr(now) + "-" + Utilities::intToStr(msgId); + + FMessage fmsg(chat_id, true, id); + fmsg.timestamp = now; + fmsg.data = msg; + m_pConnection->sendMessage(&fmsg); + + pInfo->m_unsentMsgs[id] = gch->ptszText; } + CODE_BLOCK_CATCH_ALL } break; + } - case GC_USER_LEAVE: - case GC_SESSION_TERMINATE: + return 0; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// chat log menu event handler + +static gc_item sttLogListItems[] = +{ + { LPGENT("&Invite a user"), IDM_INVITE, MENU_ITEM }, + { NULL, 0, MENU_SEPARATOR }, + { LPGENT("&Room options"), 0, MENU_NEWPOPUP }, + { LPGENT("View/change &topic"), IDM_TOPIC, MENU_POPUPITEM }, + { LPGENT("&Leave chat session"), IDM_LEAVE, MENU_POPUPITEM }, + { NULL, 0, MENU_SEPARATOR }, + { LPGENT("Copy room &JID"), IDM_CPY_RJID, MENU_ITEM }, + { LPGENT("Copy room topic"), IDM_CPY_TOPIC, MENU_ITEM }, +}; + +void WhatsAppProto::ChatLogMenuHook(WAChatInfo *pInfo, struct GCHOOK *gch) +{ + switch (gch->dwData) { + case IDM_INVITE: + InviteChatUser(pInfo); break; + + case IDM_TOPIC: + EditChatSubject(pInfo); + break; + + case IDM_CPY_RJID: + utils::copyText(pcli->hwndContactList, pInfo->tszJid); + break; + + case IDM_CPY_TOPIC: + utils::copyText(pcli->hwndContactList, pInfo->tszNick); + break; + + case IDM_LEAVE: + if (isOnline()) + m_pConnection->sendJoinLeaveGroup(_T2A(pInfo->tszJid), false); + break; + } +} + +void WhatsAppProto::EditChatSubject(WAChatInfo *pInfo) +{ + CMString title(FORMAT, TranslateT("Set new subject for %s"), pInfo->tszNick); + ptrT tszOldValue(getTStringA(pInfo->hContact, "Nick")); + + ENTER_STRING es = { 0 }; + es.cbSize = sizeof(es); + es.type = ESF_RICHEDIT; + es.szModuleName = m_szModuleName; + es.ptszInitVal = tszOldValue; + es.caption = title; + es.szDataPrefix = "setSubject_"; + if (EnterString(&es)) { + ptrA gjid(mir_utf8encodeT(pInfo->tszJid)); + ptrA gsubject(mir_utf8encodeT(es.ptszResult)); + m_pConnection->sendSetNewSubject(std::string(gjid), std::string(gsubject)); + mir_free(es.ptszResult); + } +} + +void WhatsAppProto::InviteChatUser(WAChatInfo *pInfo) +{ + if (TRUE != DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_GROUPCHAT_INVITE), NULL, InviteDialogProc, (LPARAM)this)) + return; + + if (isOnline()) { + m_pConnection->sendAddParticipants((char*)_T2A(pInfo->tszJid), m_szInviteJids); + m_szInviteJids.clear(); + } +} + +///////////////////////////////////////////////////////////////////////////////////////// +// nicklist menu event handler + +static gc_item sttListItems[] = +{ + { LPGENT("&Add to roster"), IDM_ADD_RJID, MENU_POPUPITEM }, + { NULL, 0, MENU_SEPARATOR }, + { LPGENT("&Kick"), IDM_KICK, MENU_ITEM }, + { NULL, 0, MENU_SEPARATOR }, + { LPGENT("Copy &nickname"), IDM_CPY_NICK, MENU_ITEM }, + { LPGENT("Copy real &JID"), IDM_CPY_RJID, MENU_ITEM }, +}; + +void WhatsAppProto::NickListMenuHook(WAChatInfo *pInfo, struct GCHOOK *gch) +{ + switch (gch->dwData) { + case IDM_ADD_RJID: + AddChatUser(pInfo, gch->ptszUID); + break; + + case IDM_KICK: + KickChatUser(pInfo, gch->ptszUID); + break; + + case IDM_CPY_NICK: + utils::copyText(pcli->hwndContactList, GetChatUserNick(std::string((char*)_T2A(gch->ptszUID)))); + break; + + case IDM_CPY_RJID: + utils::copyText(pcli->hwndContactList, gch->ptszUID); + break; + } +} + +void WhatsAppProto::AddChatUser(WAChatInfo *pInfo, const TCHAR *ptszJid) +{ + std::string jid((char*)_T2A(ptszJid)); + MCONTACT hContact = ContactIDToHContact(jid); + if (hContact && !db_get_b(hContact, "CList", "NotInList", 0)) + return; + + PROTOSEARCHRESULT sr = { 0 }; + sr.cbSize = sizeof(sr); + sr.flags = PSR_TCHAR; + sr.id = (TCHAR*)ptszJid; + sr.nick = GetChatUserNick(jid); + + ADDCONTACTSTRUCT acs = { 0 }; + acs.handleType = HANDLE_SEARCHRESULT; + acs.szProto = m_szModuleName; + acs.psr = (PROTOSEARCHRESULT*)&sr; + CallService(MS_ADDCONTACT_SHOW, (WPARAM)CallService(MS_CLUI_GETHWND, 0, 0), (LPARAM)&acs); +} + +void WhatsAppProto::KickChatUser(WAChatInfo *pInfo, const TCHAR *ptszJid) +{ + if (!isOnline()) + return; + + std::string gjid((char*)_T2A(pInfo->tszJid)); + std::vector jids(1); + jids[0] = (char*)_T2A(ptszJid); + m_pConnection->sendRemoveParticipants(gjid, jids); +} + +///////////////////////////////////////////////////////////////////////////////////////// +// handler to customize chat menus + +int WhatsAppProto::OnChatMenu(WPARAM wParam, LPARAM lParam) +{ + GCMENUITEMS *gcmi = (GCMENUITEMS*)lParam; + if (gcmi == NULL) + return 0; + + if (mir_strcmpi(gcmi->pszModule, m_szModuleName)) + return 0; + + if (gcmi->Type == MENU_ON_LOG) { + gcmi->nItems = SIZEOF(sttLogListItems); + gcmi->Item = sttLogListItems; + } + else if (gcmi->Type == MENU_ON_NICKLIST) { + gcmi->nItems = SIZEOF(sttListItems); + gcmi->Item = sttListItems; } return 0; } + +/////////////////////////////////////////////////////////////////////////////// +// chat helpers + +WAChatInfo* WhatsAppProto::InitChat(const std::string &jid, const std::string &nick) +{ + TCHAR *ptszJid = str2t(jid), *ptszNick = str2t(nick); + + WAChatInfo *pInfo = new WAChatInfo(ptszJid, ptszNick); + m_chats[jid] = pInfo; + + GCSESSION gcw = { sizeof(GCSESSION) }; + gcw.iType = GCW_CHATROOM; + gcw.pszModule = m_szModuleName; + gcw.ptszName = ptszNick; + gcw.ptszID = ptszJid; + CallServiceSync(MS_GC_NEWSESSION, NULL, (LPARAM)&gcw); + + pInfo->hContact = ContactIDToHContact(jid); + + GCDEST gcd = { m_szModuleName, ptszJid, GC_EVENT_ADDGROUP }; + GCEVENT gce = { sizeof(gce), &gcd }; + for (int i = SIZEOF(sttStatuses) - 1; i >= 0; i--) { + gce.ptszStatus = TranslateTS(sttStatuses[i]); + CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); + } + + gcd.iType = GC_EVENT_CONTROL; + CallServiceSync(MS_GC_EVENT, (m_pConnection) ? WINDOW_HIDDEN : SESSION_INITDONE, (LPARAM)&gce); + CallServiceSync(MS_GC_EVENT, SESSION_ONLINE, (LPARAM)&gce); + + if (m_pConnection) + m_pConnection->sendGetParticipants(jid); + + return pInfo; +} + +TCHAR* WhatsAppProto::GetChatUserNick(const std::string &jid) +{ + if (m_szJid == jid) + return str2t(m_szNick); + + MCONTACT hContact = ContactIDToHContact(jid); + return (hContact == 0) ? utils::removeA(str2t(jid)) : mir_tstrdup(pcli->pfnGetContactDisplayName(hContact, 0)); +} + +WAChatInfo* WhatsAppProto::SafeGetChat(const std::string &jid) +{ + mir_cslock lck(m_csChats); + return m_chats[jid]; +} + +/////////////////////////////////////////////////////////////////////////////// +// WAGroupListener members + +void WhatsAppProto::onGroupInfo(const std::string &jid, const std::string &owner, const std::string &subject, const std::string &subject_owner, int time_subject, int time_created) +{ + WAChatInfo *pInfo = SafeGetChat(jid); + if (pInfo == NULL) { + pInfo = InitChat(jid, subject); + pInfo->bActive = true; + } + + if (!subject.empty()) { + pInfo->tszOwner = str2t(owner); + + onGroupNewSubject(jid, subject_owner, subject, time_subject); + } + + GCDEST gcd = { m_szModuleName, pInfo->tszJid, GC_EVENT_CONTROL }; + GCEVENT gce = { sizeof(gce), &gcd }; + CallServiceSync(MS_GC_EVENT, SESSION_INITDONE, (LPARAM)&gce); +} + +void WhatsAppProto::onGroupMessage(const FMessage &msg) +{ + WAChatInfo *pInfo = SafeGetChat(msg.key.remote_jid); + if (pInfo == NULL) { + pInfo = InitChat(msg.key.remote_jid, ""); + pInfo->bActive = true; + } + + ptrT tszText(str2t(msg.data)); + ptrT tszUID(str2t(msg.remote_resource)); + ptrT tszNick(GetChatUserNick(msg.remote_resource)); + + GCDEST gcd = { m_szModuleName, pInfo->tszJid, GC_EVENT_MESSAGE }; + + GCEVENT gce = { sizeof(gce), &gcd }; + gce.dwFlags = GCEF_ADDTOLOG; + gce.ptszUID = tszUID; + gce.ptszNick = tszNick; + gce.time = msg.timestamp; + gce.ptszText = tszText; + gce.bIsMe = m_szJid == msg.remote_resource; + CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); + + if (isOnline()) + m_pConnection->sendMessageReceived(msg); +} + +void WhatsAppProto::onGroupNewSubject(const std::string &gjid, const std::string &author, const std::string &newSubject, int ts) +{ + WAChatInfo *pInfo = SafeGetChat(gjid); + if (pInfo == NULL) + return; + + ptrT tszUID(str2t(author)); + ptrT tszNick(GetChatUserNick(author)); + ptrT tszText(str2t(newSubject)); + + GCDEST gcd = { m_szModuleName, pInfo->tszJid, GC_EVENT_TOPIC }; + + GCEVENT gce = { sizeof(gce), &gcd }; + gce.dwFlags = GCEF_ADDTOLOG; + gce.ptszUID = tszUID; + gce.ptszNick = tszNick; + gce.time = ts; + gce.ptszText = tszText; + CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); + + setTString(pInfo->hContact, "Nick", tszText); +} + +void WhatsAppProto::onGroupAddUser(const std::string &gjid, const std::string &ujid, int ts) +{ + WAChatInfo *pInfo = SafeGetChat(gjid); + if (pInfo == NULL) + return; + + ptrT tszUID(str2t(ujid)); + ptrT tszNick(GetChatUserNick(ujid)); + + GCDEST gcd = { m_szModuleName, pInfo->tszJid, GC_EVENT_JOIN }; + + GCEVENT gce = { sizeof(gce), &gcd }; + gce.dwFlags = GCEF_ADDTOLOG; + gce.ptszUID = tszUID; + gce.ptszNick = tszNick; + gce.time = ts; + CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); +} + +void WhatsAppProto::onGroupRemoveUser(const std::string &gjid, const std::string &ujid, int ts) +{ + WAChatInfo *pInfo = SafeGetChat(gjid); + if (pInfo == NULL) + return; + + ptrT tszUID(str2t(ujid)); + ptrT tszNick(GetChatUserNick(ujid)); + + GCDEST gcd = { m_szModuleName, pInfo->tszJid, GC_EVENT_PART }; + + GCEVENT gce = { sizeof(gce), &gcd }; + gce.dwFlags = GCEF_ADDTOLOG; + gce.ptszUID = tszUID; + gce.ptszNick = tszNick; + gce.time = ts; + CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); +} + +void WhatsAppProto::onLeaveGroup(const std::string &gjid) +{ + WAChatInfo *pInfo = SafeGetChat(gjid); + if (pInfo == NULL) + return; + + GCDEST gcd = { m_szModuleName, pInfo->tszJid, GC_EVENT_CONTROL }; + + GCEVENT gce = { sizeof(gce), &gcd }; + gce.ptszUID = pInfo->tszJid; + CallServiceSync(MS_GC_EVENT, SESSION_TERMINATE, (LPARAM)&gce); + + CallService(MS_DB_CONTACT_DELETE, pInfo->hContact, 0); + m_chats.erase((char*)_T2A(pInfo->tszJid)); +} + +void WhatsAppProto::onGetParticipants(const std::string &gjid, const std::vector &participants) +{ + mir_cslock lck(m_csChats); + + WAChatInfo *pInfo = m_chats[gjid]; + if (pInfo == NULL) + return; + + for (size_t i = 0; i < participants.size(); i++) { + std::string curr = participants[i]; + + ptrT ujid(str2t(curr)), nick(GetChatUserNick(curr)); + bool bIsOwner = !mir_tstrcmp(ujid, pInfo->tszOwner); + + GCDEST gcd = { m_szModuleName, pInfo->tszJid, GC_EVENT_JOIN }; + + GCEVENT gce = { sizeof(gce), &gcd }; + gce.ptszNick = nick; + gce.ptszUID = utils::removeA(ujid); + gce.ptszStatus = (bIsOwner) ? _T("Owners") : _T("Members"); + CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); + } +} + +void WhatsAppProto::onGroupCreated(const std::string &gjid, const std::string &subject) +{ + WAChatInfo *pInfo = InitChat(gjid, subject); + pInfo->tszOwner = str2t(m_szJid); + + // also set new subject if it's present + if (!subject.empty()) + onGroupNewSubject(gjid, "Server", subject, time(0)); +} + +void WhatsAppProto::onGroupMessageReceived(const FMessage &msg) +{ + WAChatInfo *pInfo = SafeGetChat(msg.key.remote_jid); + if (pInfo == NULL) + return; + + auto p = pInfo->m_unsentMsgs.find(msg.key.id); + if (p == pInfo->m_unsentMsgs.end()) + return; + + ptrT tszUID(str2t(m_szJid)); + ptrT tszNick(str2t(m_szNick)); + + GCDEST gcd = { m_szModuleName, pInfo->tszJid, GC_EVENT_MESSAGE }; + + GCEVENT gce = { sizeof(gce), &gcd }; + gce.dwFlags = GCEF_ADDTOLOG; + gce.ptszUID = tszUID; + gce.ptszNick = tszNick; + gce.time = msg.timestamp; + gce.ptszText = p->second.c_str(); + gce.bIsMe = m_szJid == msg.remote_resource; + CallServiceSync(MS_GC_EVENT, NULL, (LPARAM)&gce); + + pInfo->m_unsentMsgs.erase(p); +} diff --git a/protocols/WhatsApp/src/common.h b/protocols/WhatsApp/src/common.h index 41a9dc1866..338b4578ca 100644 --- a/protocols/WhatsApp/src/common.h +++ b/protocols/WhatsApp/src/common.h @@ -70,10 +70,6 @@ Copyright #include #include -#include "WhatsAPI++/WAConnection.h" - -class WhatsAppProto; - #include "constants.h" #include "utils.h" #include "db.h" diff --git a/protocols/WhatsApp/src/connection.cpp b/protocols/WhatsApp/src/connection.cpp index c0710e626e..5ad51e788c 100644 --- a/protocols/WhatsApp/src/connection.cpp +++ b/protocols/WhatsApp/src/connection.cpp @@ -134,7 +134,7 @@ void WhatsAppProto::sentinelLoop(void*) debugLogA("Exiting sentinel loop"); } -void WhatsAppProto::onPing(const std::string& id) +void WhatsAppProto::onPing(const std::string &id) { if (isOnline()) { try { diff --git a/protocols/WhatsApp/src/contacts.cpp b/protocols/WhatsApp/src/contacts.cpp index f3c93204e6..e1a3a33bf1 100644 --- a/protocols/WhatsApp/src/contacts.cpp +++ b/protocols/WhatsApp/src/contacts.cpp @@ -1,55 +1,39 @@ #include "common.h" -bool WhatsAppProto::IsMyContact(MCONTACT hContact, bool include_chat) -{ - const char *proto = GetContactProto(hContact); - if (proto && strcmp(m_szModuleName, proto) == 0) { - if (include_chat) - return true; - - return !isChatRoom(hContact); - } - - return false; -} - -MCONTACT WhatsAppProto::AddToContactList(const std::string& jid, BYTE , bool dont_check, const char *new_name, bool isChatRoom, bool isHidden) +MCONTACT WhatsAppProto::AddToContactList(const std::string &jid, const char *new_name) { if (jid == m_szJid) return NULL; - if (!dont_check) { - // First, check if this contact exists - MCONTACT hContact = ContactIDToHContact(jid); - if (hContact) { - if (new_name != NULL) { - DBVARIANT dbv; - string oldName; - if (db_get_utf(hContact, m_szModuleName, WHATSAPP_KEY_NICK, &dbv)) - oldName = jid.c_str(); - else { - oldName = dbv.pszVal; - db_free(&dbv); - } - - if (oldName.compare(string(new_name)) != 0) { - db_set_utf(hContact, m_szModuleName, WHATSAPP_KEY_NICK, new_name); - - CMString tmp(FORMAT, TranslateT("is now known as '%s'"), ptrT(mir_utf8decodeT(new_name))); - this->NotifyEvent(_A2T(oldName.c_str()), tmp, hContact, WHATSAPP_EVENT_OTHER); - } + // First, check if this contact exists + MCONTACT hContact = ContactIDToHContact(jid); + if (hContact) { + if (new_name != NULL) { + DBVARIANT dbv; + string oldName; + if (db_get_utf(hContact, m_szModuleName, WHATSAPP_KEY_NICK, &dbv)) + oldName = jid.c_str(); + else { + oldName = dbv.pszVal; + db_free(&dbv); } - if (db_get_b(hContact, "CList", "Hidden", 0) > 0) - db_unset(hContact, "CList", "Hidden"); + if (oldName.compare(string(new_name)) != 0) { + db_set_utf(hContact, m_szModuleName, WHATSAPP_KEY_NICK, new_name); - return hContact; + CMString tmp(FORMAT, TranslateT("is now known as '%s'"), ptrT(mir_utf8decodeT(new_name))); + this->NotifyEvent(_A2T(oldName.c_str()), tmp, hContact, WHATSAPP_EVENT_OTHER); + } } + + if (db_get_b(hContact, "CList", "Hidden", 0) > 0) + db_unset(hContact, "CList", "Hidden"); + + return hContact; } // If not, make a new contact! - MCONTACT hContact = CallService(MS_DB_CONTACT_ADD, 0, 0); - if (hContact == 0) + if ((hContact = CallService(MS_DB_CONTACT_ADD, 0, 0)) == 0) return INVALID_CONTACT_ID; CallService(MS_PROTO_ADDTOCONTACT, (WPARAM)hContact, (LPARAM)m_szModuleName); @@ -66,13 +50,10 @@ MCONTACT WhatsAppProto::AddToContactList(const std::string& jid, BYTE , bool don if (new_name != NULL) db_set_utf(hContact, m_szModuleName, WHATSAPP_KEY_NICK, new_name); - if (isChatRoom) - setByte(hContact, "SimpleChatRoom", 1); - return hContact; } -MCONTACT WhatsAppProto::ContactIDToHContact(const std::string& phoneNumber) +MCONTACT WhatsAppProto::ContactIDToHContact(const std::string &phoneNumber) { // Cache std::map::iterator it = this->hContactByJid.find(phoneNumber); @@ -132,10 +113,7 @@ void WhatsAppProto::ProcessBuddyList(void*) ptrA jid(getStringA(hContact, WHATSAPP_KEY_ID)); if (jid) { try { - if (getByte(hContact, "SimpleChatRoom", 0) == 0) { - m_pConnection->sendQueryLastOnline((char*)jid); - m_pConnection->sendPresenceSubscriptionRequest((char*)jid); - } + m_pConnection->sendQueryLastOnline(std::string(jid)); } CODE_BLOCK_CATCH_ALL } @@ -143,14 +121,13 @@ void WhatsAppProto::ProcessBuddyList(void*) try { m_pConnection->sendGetGroups(); - m_pConnection->sendGetOwningGroups(); } CODE_BLOCK_CATCH_ALL } -void WhatsAppProto::onAvailable(const std::string& paramString, bool paramBoolean) +void WhatsAppProto::onAvailable(const std::string ¶mString, bool paramBoolean) { - MCONTACT hContact = this->AddToContactList(paramString, 0, false); + MCONTACT hContact = this->AddToContactList(paramString); if (hContact != NULL) { if (paramBoolean) setWord(hContact, "Status", ID_STATUS_ONLINE); @@ -164,9 +141,9 @@ void WhatsAppProto::onAvailable(const std::string& paramString, bool paramBoolea this->UpdateStatusMsg(hContact); } -void WhatsAppProto::onLastSeen(const std::string& paramString1, int paramInt, const string ¶mString2) +void WhatsAppProto::onLastSeen(const std::string ¶mString1, int paramInt, const string ¶mString2) { - MCONTACT hContact = this->AddToContactList(paramString1, 0, false); + MCONTACT hContact = this->AddToContactList(paramString1); setDword(hContact, WHATSAPP_KEY_LAST_SEEN, paramInt); this->UpdateStatusMsg(hContact); @@ -187,16 +164,17 @@ void WhatsAppProto::UpdateStatusMsg(MCONTACT hContact) db_set_ws(hContact, "CList", "StatusMsg", ss.str().c_str()); } -void WhatsAppProto::onPictureChanged(const std::string& from, const std::string& author, bool set) +void WhatsAppProto::onContactChanged(const std::string &jid, bool added) { - if (this->isOnline()) { - vector ids; - ids.push_back(from); - m_pConnection->sendGetPicture(from, "image"); - } } -void WhatsAppProto::onSendGetPicture(const std::string& jid, const std::vector& data, const std::string& id) +void WhatsAppProto::onPictureChanged(const std::string &jid, const std::string &id, bool set) +{ + if (isOnline()) + m_pConnection->sendGetPicture(jid, "image"); +} + +void WhatsAppProto::onSendGetPicture(const std::string &jid, const std::vector& data, const std::string &id) { MCONTACT hContact = this->ContactIDToHContact(jid); if (hContact) { @@ -230,299 +208,3 @@ TCHAR* WhatsAppProto::GetContactDisplayName(const string& jid) MCONTACT hContact = this->ContactIDToHContact(jid); return (hContact) ? pcli->pfnGetContactDisplayName(hContact, 0) : _T("none"); } - -// Group contacts -------------------------- - -void WhatsAppProto::SendGetGroupInfoWorker(void* data) -{ - if (this->isOnline()) - m_pConnection->sendGetGroupInfo(*((std::string*) data)); -} - -void WhatsAppProto::onGroupInfo(const std::string& gjid, const std::string& ownerJid, const std::string& subject, const std::string& createrJid, int paramInt1, int paramInt2) -{ - debugLogA("'%s', '%s', '%s', '%s'", gjid.c_str(), ownerJid.c_str(), subject.c_str(), createrJid.c_str()); - MCONTACT hContact = ContactIDToHContact(gjid); - if (!hContact) { - debugLogA("Group info requested for non existing contact '%s'", gjid.c_str()); - return; - } - setByte(hContact, "SimpleChatRoom", ownerJid.compare(m_szJid) == 0 ? 2 : 1); - if (this->isOnline()) - m_pConnection->sendGetParticipants(gjid); -} - -void WhatsAppProto::onGroupInfoFromList(const std::string& paramString1, const std::string& paramString2, const std::string& paramString3, const std::string& paramString4, int paramInt1, int paramInt2) -{ - // Called before onOwningGroups() or onParticipatingGroups() is called! -} - -void WhatsAppProto::onGroupNewSubject(const std::string& from, const std::string& author, const std::string& newSubject, int paramInt) -{ - debugLogA("'%s', '%s', '%s'", from.c_str(), author.c_str(), newSubject.c_str()); - MCONTACT hContact = this->AddToContactList(from, 0, false, newSubject.c_str(), true); -} - -void WhatsAppProto::onGroupAddUser(const std::string& paramString1, const std::string& paramString2) -{ - debugLogA("%s - user: %s", paramString1.c_str(), paramString2.c_str()); - MCONTACT hContact = this->AddToContactList(paramString1); - TCHAR *ptszGroupName = pcli->pfnGetContactDisplayName(hContact, 0); - - if (paramString2.compare(m_szJid) == 0) { - this->NotifyEvent(ptszGroupName, TranslateT("You have been added to the group"), hContact, WHATSAPP_EVENT_OTHER); - setByte(hContact, "IsGroupMember", 1); - } - else { - CMString tmp(FORMAT, TranslateT("User '%s' has been added to the group"), this->GetContactDisplayName(paramString2)); - this->NotifyEvent(ptszGroupName, tmp, hContact, WHATSAPP_EVENT_OTHER); - } - - if (this->isOnline()) - m_pConnection->sendGetGroupInfo(paramString1); -} - -void WhatsAppProto::onGroupRemoveUser(const std::string ¶mString1, const std::string ¶mString2) -{ - debugLogA("%s - user: %s", paramString1.c_str(), paramString2.c_str()); - MCONTACT hContact = this->ContactIDToHContact(paramString1); - if (!hContact) - return; - - TCHAR *ptszGroupName = pcli->pfnGetContactDisplayName(hContact, 0); - - if (paramString2.compare(m_szJid) == 0) { - //db_set_b(hContact, "CList", "Hidden", 1); - setByte(hContact, "IsGroupMember", 0); - - this->NotifyEvent(ptszGroupName, TranslateT("You have been removed from the group"), hContact, WHATSAPP_EVENT_OTHER); - } - else if (this->isOnline()) { - CMString tmp(FORMAT, TranslateT("User '%s' has been removed from the group"), this->GetContactDisplayName(paramString2)); - this->NotifyEvent(ptszGroupName, tmp, hContact, WHATSAPP_EVENT_OTHER); - - m_pConnection->sendGetGroupInfo(paramString1); - } -} - -void WhatsAppProto::onLeaveGroup(const std::string ¶mString) -{ - // Won't be called for unknown reasons! - debugLogA("%s", this->GetContactDisplayName(paramString)); - MCONTACT hContact = this->ContactIDToHContact(paramString); - if (hContact) - setByte(hContact, "IsGroupMember", 0); -} - -void WhatsAppProto::onGetParticipants(const std::string& gjid, const std::vector& participants) -{ - debugLogA("%s", this->GetContactDisplayName(gjid)); - - MCONTACT hUserContact, hContact = this->ContactIDToHContact(gjid); - if (!hContact) - return; - - if (db_get_b(hContact, "CList", "Hidden", 0) == 1) - return; - - bool isHidden = true; - bool isOwningGroup = getByte(hContact, "SimpleChatRoom", 0) == 2; - - if (isOwningGroup) - this->isMemberByGroupContact[hContact].clear(); - - for (std::vector::const_iterator it = participants.begin(); it != participants.end(); ++it) { - // Hide, if we are not member of the group - // Sometimes the group is shown shortly after hiding it again, due to other threads which stored the contact - // in a cache before it has been removed (E.g. picture-id list in processBuddyList) - if (isHidden && m_szJid.compare(*it) == 0) { - isHidden = false; - if (!isOwningGroup) { - // Break, as we don't need to collect group-members - break; - } - } - - // #TODO Slow for big count of participants - // #TODO If a group is hidden it has been deleted from the local contact list - // => don't allow to add users anymore - if (isOwningGroup) { - hUserContact = this->ContactIDToHContact(*it); - if (hUserContact) { - this->isMemberByGroupContact[hContact][hUserContact] = true; - } - } - } - if (isHidden) { - //db_set_b(hContact, "CList", "Hidden", 1); - // #TODO Check if it's possible to reach this point at all - setByte(hContact, "IsGroupMember", 0); - } -} - -// Menu handler -INT_PTR __cdecl WhatsAppProto::OnAddContactToGroup(WPARAM wParam, LPARAM, LPARAM lParam) -{ - TCHAR *a = pcli->pfnGetContactDisplayName((MCONTACT)wParam, 0); - TCHAR *b = pcli->pfnGetContactDisplayName((MCONTACT)lParam, 0); - debugLogA("Request add user %S to group %S", a, b); - - if (!this->isOnline()) - return NULL; - - DBVARIANT dbv; - if (getString((MCONTACT)wParam, "ID", &dbv)) - return NULL; - - std::vector participants; - participants.push_back(string(dbv.pszVal)); - db_free(&dbv); - - if (getString((MCONTACT)lParam, "ID", &dbv)) - return NULL; - - m_pConnection->sendAddParticipants(string(dbv.pszVal), participants); - - db_free(&dbv); - return NULL; -} - -// Menu handler -INT_PTR __cdecl WhatsAppProto::OnRemoveContactFromGroup(WPARAM wParam, LPARAM, LPARAM lParam) -{ - TCHAR *a = pcli->pfnGetContactDisplayName((MCONTACT)wParam, 0); - TCHAR *b = pcli->pfnGetContactDisplayName((MCONTACT)lParam, 0); - debugLogA("Request remove user %S from group %S", a, b); - - if (!this->isOnline()) - return NULL; - - DBVARIANT dbv; - if (getString((MCONTACT)lParam, "ID", &dbv)) - return NULL; - - std::vector participants; - participants.push_back(string(dbv.pszVal)); - db_free(&dbv); - - if (getString((MCONTACT)wParam, "ID", &dbv)) - return NULL; - - m_pConnection->sendRemoveParticipants(string(dbv.pszVal), participants); - - db_free(&dbv); - return NULL; -} - -void WhatsAppProto::onOwningGroups(const std::vector& paramVector) -{ - this->HandleReceiveGroups(paramVector, true); -} - -void WhatsAppProto::onParticipatingGroups(const std::vector& paramVector) -{ - this->HandleReceiveGroups(paramVector, false); -} - -void WhatsAppProto::HandleReceiveGroups(const std::vector& groups, bool isOwned) -{ - MCONTACT hContact; - map isMember; // at the moment, only members of owning groups are stored - - // This could take long time if there are many new groups which aren't - // yet stored to the database. But that should be a rare case - for (std::vector::const_iterator it = groups.begin(); it != groups.end(); ++it) { - hContact = this->AddToContactList(*it, 0, false, NULL, true); - setByte(hContact, "IsGroupMember", 1); - if (isOwned) { - this->isMemberByGroupContact[hContact]; // []-operator creates entry, if it doesn't exist - setByte(hContact, "SimpleChatRoom", 2); - m_pConnection->sendGetParticipants(*it); - } - else isMember[hContact] = true; - } - - // Mark as non-meber if group only exists locally - if (!isOwned) - for (hContact = db_find_first(m_szModuleName); hContact; hContact = db_find_next(hContact, m_szModuleName)) - if (!isChatRoom(hContact) && getByte(hContact, "SimpleChatRoom", 0) > 0) - setByte(hContact, "IsGroupMember", isMember.find(hContact) == isMember.end() ? 0 : 1); -} - -void WhatsAppProto::onGroupCreated(const std::string& paramString1, const std::string& paramString2) -{ - // Must be received after onOwningGroups() :/ - debugLogA("%s / %s", paramString1.c_str(), paramString2.c_str()); - string jid = paramString2 + string("@") + paramString1; - MCONTACT hContact = this->AddToContactList(jid, 0, false, NULL, true); - setByte(hContact, "SimpleChatRoom", 2); -} - -// Menu-handler -INT_PTR __cdecl WhatsAppProto::OnCreateGroup(WPARAM wParam, LPARAM lParam) -{ - input_box* ib = new input_box; - ib->defaultValue = _T(""); - ib->limit = WHATSAPP_GROUP_NAME_LIMIT; - ib->proto = this; - ib->text = _T("Enter group subject"); - ib->title = _T("WhatsApp - Create Group"); - ib->thread = &WhatsAppProto::SendCreateGroupWorker; - HWND hDlg = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_INPUTBOX), 0, WhatsAppInputBoxProc, LPARAM(ib)); - ShowWindow(hDlg, SW_SHOW); - return FALSE; -} - -void __cdecl WhatsAppProto::SendSetGroupNameWorker(void* data) -{ - input_box_ret* ibr(static_cast(data)); - string groupName(ibr->value); - mir_free(ibr->value); - - ptrA jid(getStringA(*((MCONTACT*)ibr->userData), WHATSAPP_KEY_ID)); - if (jid && this->isOnline()) - m_pConnection->sendSetNewSubject((char*)jid, groupName); - - delete ibr->userData; - delete ibr; -} - -void __cdecl WhatsAppProto::SendCreateGroupWorker(void* data) -{ - input_box_ret* ibr(static_cast(data)); - string groupName(ibr->value); - mir_free(ibr->value); - if (this->isOnline()) - m_pConnection->sendCreateGroupChat(groupName); -} - -INT_PTR __cdecl WhatsAppProto::OnChangeGroupSubject(WPARAM hContact, LPARAM lParam) -{ - input_box* ib = new input_box; - - ptrT szNick(getTStringA(hContact, WHATSAPP_KEY_NICK)); - if (szNick != NULL) - ib->defaultValue = szNick; - - ib->limit = WHATSAPP_GROUP_NAME_LIMIT; - ib->text = _T("Enter new group subject"); - ib->title = _T("WhatsApp - Change Group Subject"); - ib->thread = &WhatsAppProto::SendSetGroupNameWorker; - ib->proto = this; - MCONTACT *hContactPtr = new MCONTACT(hContact); - ib->userData = (void*)hContactPtr; - - HWND hDlg = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_INPUTBOX), 0, WhatsAppInputBoxProc, LPARAM(ib)); - ShowWindow(hDlg, SW_SHOW); - return 0; -} - -INT_PTR __cdecl WhatsAppProto::OnLeaveGroup(WPARAM hContact, LPARAM) -{ - ptrA jid(getStringA(hContact, WHATSAPP_KEY_ID)); - if (jid && this->isOnline()) { - setByte(hContact, "IsGroupMember", 0); - m_pConnection->sendLeaveGroup((char*)jid); - } - return 0; -} diff --git a/protocols/WhatsApp/src/dialogs.cpp b/protocols/WhatsApp/src/dialogs.cpp index 0550dc4102..0d93fd2afd 100644 --- a/protocols/WhatsApp/src/dialogs.cpp +++ b/protocols/WhatsApp/src/dialogs.cpp @@ -3,16 +3,16 @@ #define szAskSendSms LPGEN("An SMS with registration code will be sent to your mobile phone.\nNotice that you are not able to use the real WhatsApp and this plugin simultaneously!\nContinue?") #define szPasswordSet LPGEN("Your password has been set automatically. You can proceed with login now") -INT_PTR CALLBACK WhatsAppAccountProc(HWND hwndDlg, UINT message, WPARAM wparam, LPARAM lparam) +INT_PTR CALLBACK WhatsAppAccountProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - WhatsAppProto *proto; + WhatsAppProto *proto = (WhatsAppProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - switch (message) { + switch (uMsg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); - proto = reinterpret_cast(lparam); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lparam); + proto = (WhatsAppProto*)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); SendDlgItemMessage(hwndDlg, IDC_PW, EM_LIMITTEXT, 3, 0); SendDlgItemMessage(hwndDlg, IDC_PW2, EM_LIMITTEXT, 3, 0); CheckDlgButton(hwndDlg, IDC_SSL, db_get_b(NULL, proto->m_szModuleName, WHATSAPP_KEY_SSL, 0) ? BST_CHECKED : BST_UNCHECKED); @@ -42,16 +42,14 @@ INT_PTR CALLBACK WhatsAppAccountProc(HWND hwndDlg, UINT message, WPARAM wparam, return TRUE; case WM_COMMAND: - if (LOWORD(wparam) == IDC_BUTTON_REQUEST_CODE || LOWORD(wparam) == IDC_BUTTON_REGISTER) { - proto = reinterpret_cast(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); - + if (LOWORD(wParam) == IDC_BUTTON_REQUEST_CODE || LOWORD(wParam) == IDC_BUTTON_REGISTER) { string password; char cc[5]; char number[128]; GetDlgItemTextA(hwndDlg, IDC_CC, cc, SIZEOF(cc)); GetDlgItemTextA(hwndDlg, IDC_LOGIN, number, SIZEOF(number)); - if (LOWORD(wparam) == IDC_BUTTON_REQUEST_CODE) { + if (LOWORD(wParam) == IDC_BUTTON_REQUEST_CODE) { if (IDYES == MessageBox(NULL, TranslateT(szAskSendSms), PRODUCT_NAME, MB_YESNO)) { if (proto->Register(REG_STATE_REQ_CODE, string(cc), string(number), string(), password)) { if (!password.empty()) { @@ -65,7 +63,7 @@ INT_PTR CALLBACK WhatsAppAccountProc(HWND hwndDlg, UINT message, WPARAM wparam, } } } - else if (LOWORD(wparam) == IDC_BUTTON_REGISTER) { + else if (LOWORD(wParam) == IDC_BUTTON_REGISTER) { HWND hwnd1 = GetDlgItem(hwndDlg, IDC_PW), hwnd2 = GetDlgItem(hwndDlg, IDC_PW2); if (GetWindowTextLength(hwnd1) != 3 || GetWindowTextLength(hwnd2) != 3) { MessageBox(NULL, TranslateT("Please correctly specify your registration code received by SMS"), PRODUCT_NAME, MB_ICONEXCLAMATION); @@ -83,8 +81,8 @@ INT_PTR CALLBACK WhatsAppAccountProc(HWND hwndDlg, UINT message, WPARAM wparam, } } - if (HIWORD(wparam) == EN_CHANGE && reinterpret_cast(lparam) == GetFocus()) { - switch (LOWORD(wparam)) { + if (HIWORD(wParam) == EN_CHANGE && reinterpret_cast(lParam) == GetFocus()) { + switch (LOWORD(wParam)) { case IDC_CC: case IDC_LOGIN: case IDC_NICK: @@ -97,8 +95,7 @@ INT_PTR CALLBACK WhatsAppAccountProc(HWND hwndDlg, UINT message, WPARAM wparam, break; case WM_NOTIFY: - if (reinterpret_cast(lparam)->code == PSN_APPLY) { - proto = reinterpret_cast(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); + if (reinterpret_cast(lParam)->code == PSN_APPLY) { char str[128]; GetDlgItemTextA(hwndDlg, IDC_CC, str, SIZEOF(str)); @@ -114,68 +111,88 @@ INT_PTR CALLBACK WhatsAppAccountProc(HWND hwndDlg, UINT message, WPARAM wparam, return TRUE; } break; - } return FALSE; } -INT_PTR CALLBACK WhatsAppInputBoxProc(HWND hwndDlg, UINT message, WPARAM wparam, LPARAM lparam) +///////////////////////////////////////////////////////////////////////////////////////// +// Invite dialog + +static void InitList(HWND hwndClist, WhatsAppProto *ppro) +{ + SetWindowLongPtr(hwndClist, GWL_STYLE, + GetWindowLongPtr(hwndClist, GWL_STYLE) | CLS_CHECKBOXES | CLS_HIDEEMPTYGROUPS | CLS_USEGROUPS | CLS_GREYALTERNATE); + SendMessage(hwndClist, CLM_SETEXSTYLE, CLS_EX_DISABLEDRAGDROP | CLS_EX_TRACKSELECT, 0); + SendMessage(hwndClist, CLM_SETBKBITMAP, 0, 0); + SendMessage(hwndClist, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0); + SendMessage(hwndClist, CLM_SETGREYOUTFLAGS, 0, 0); + SendMessage(hwndClist, CLM_SETLEFTMARGIN, 4, 0); + SendMessage(hwndClist, CLM_SETINDENT, 10, 0); + SendMessage(hwndClist, CLM_SETBKBITMAP, 0, 0); + SendMessage(hwndClist, CLM_SETHIDEEMPTYGROUPS, TRUE, 0); + SendMessage(hwndClist, CLM_SETHIDEOFFLINEROOT, TRUE, 0); + + for (int i = 0; i <= FONTID_MAX; i++) + SendMessage(hwndClist, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT)); + + for (MCONTACT hContact = db_find_first(); hContact; hContact = db_find_next(hContact)) { + char *proto = GetContactProto(hContact); + if (mir_strcmp(proto, ppro->m_szModuleName) || ppro->isChatRoom(hContact)) + if (MCONTACT hItem = SendMessage(hwndClist, CLM_FINDCONTACT, hContact, 0)) + SendMessage(hwndClist, CLM_DELETEITEM, hItem, 0); + } +} + +INT_PTR CALLBACK InviteDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - input_box* ib; + WhatsAppProto *proto = (WhatsAppProto*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); - switch (message) { + switch (uMsg) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); - ib = reinterpret_cast(lparam); - SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lparam); - SendDlgItemMessage(hwndDlg, IDC_VALUE, EM_LIMITTEXT, ib->limit, 0); - SetDlgItemText(hwndDlg, IDC_VALUE, ib->defaultValue.c_str()); - SetDlgItemText(hwndDlg, IDC_TEXT, ib->text.c_str()); - - SetWindowText(hwndDlg, ib->title.c_str()); - - EnableWindow(GetDlgItem(hwndDlg, IDC_OK), FALSE); - return TRUE; + proto = (WhatsAppProto*)lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + InitList(GetDlgItem(hwndDlg, IDC_CLIST), proto); + return 1; + case WM_COMMAND: - if (LOWORD(wparam) == IDC_VALUE && HIWORD(wparam) == EN_CHANGE) { - ib = reinterpret_cast(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); - size_t len = SendDlgItemMessage(hwndDlg, IDC_VALUE, WM_GETTEXTLENGTH, 0, 0); - TCHAR str[4]; - mir_sntprintf(str, SIZEOF(str), TEXT("%d"), ib->limit - len); - //SetDlgItemText(hwndDlg,IDC_CHARACTERS,str); - - EnableWindow(GetDlgItem(hwndDlg, IDC_OK), len > 0); - return TRUE; - } - - if (LOWORD(wparam) == IDC_OK) { - ib = reinterpret_cast(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); - TCHAR* value = new TCHAR[ib->limit + 1]; - - GetDlgItemText(hwndDlg, IDC_VALUE, value, ib->limit + 1); - ShowWindow(hwndDlg, SW_HIDE); + switch (LOWORD(wParam)) { + case IDCANCEL: + EndDialog(hwndDlg, 0); + break; + + case IDOK: + proto->m_szInviteJids.clear(); + + // invite users from clist + for (MCONTACT hContact = db_find_first(proto->m_szModuleName); hContact; hContact = db_find_next(hContact, proto->m_szModuleName)) { + if (proto->isChatRoom(hContact)) + continue; + + HWND hwndList = GetDlgItem(hwndDlg, IDC_CLIST); + if (int hItem = SendMessage(hwndList, CLM_FINDCONTACT, hContact, 0)) { + if (SendMessage(hwndList, CLM_GETCHECKMARK, (WPARAM)hItem, 0)) { + ptrA jid(proto->getStringA(hContact, "ID")); + if (jid != NULL) + proto->m_szInviteJids.push_back((char*)jid); + } + } + } - input_box_ret* ret = new input_box_ret; - ret->userData = ib->userData; - ret->value = mir_utf8encodeT(value); - delete value; - ib->proto->ForkThread(ib->thread, ret); - EndDialog(hwndDlg, wparam); - delete ib; - return TRUE; - } + HWND hwndEntry = GetDlgItem(hwndDlg, IDC_NEWJID); + int len = GetWindowTextLength(hwndEntry); + if (len > 0) { + std::string szOther; szOther.resize(len + 1); + GetWindowTextA(hwndEntry, (char*)szOther.data(), len); + proto->m_szInviteJids.push_back(szOther); + } - if (LOWORD(wparam) == IDC_CANCEL) { - EndDialog(hwndDlg, wparam); - ib = reinterpret_cast(GetWindowLongPtr(hwndDlg, GWLP_USERDATA)); - delete ib; - return TRUE; + EndDialog(hwndDlg, 1); } - break; } - return FALSE; -} \ No newline at end of file + return 0; +} diff --git a/protocols/WhatsApp/src/dialogs.h b/protocols/WhatsApp/src/dialogs.h index 3284755496..f31cc322c6 100644 --- a/protocols/WhatsApp/src/dialogs.h +++ b/protocols/WhatsApp/src/dialogs.h @@ -1,7 +1,7 @@ #if !defined(DIALOGS_H) #define DIALOGS_H -INT_PTR CALLBACK WhatsAppAccountProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); -INT_PTR CALLBACK WhatsAppInputBoxProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); +INT_PTR CALLBACK InviteDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam); +INT_PTR CALLBACK WhatsAppAccountProc(HWND hwndDlg, UINT uMsg, WPARAM wparam, LPARAM lParam); #endif \ No newline at end of file diff --git a/protocols/WhatsApp/src/messages.cpp b/protocols/WhatsApp/src/messages.cpp index f1ad83d252..dd32451850 100644 --- a/protocols/WhatsApp/src/messages.cpp +++ b/protocols/WhatsApp/src/messages.cpp @@ -7,11 +7,11 @@ int WhatsAppProto::RecvMsg(MCONTACT hContact, PROTORECVEVENT *pre) return Proto_RecvMessage(hContact, pre); } -void WhatsAppProto::onMessageForMe(FMessage *pMsg, bool paramBoolean) +void WhatsAppProto::onMessageForMe(const FMessage &pMsg) { // someone sent us a contact. launch contact addition dialog - if (pMsg->media_wa_type == FMessage::WA_TYPE_CONTACT) { - MCONTACT hContact = AddToContactList(pMsg->remote_resource, 0, false, pMsg->media_name.c_str()); + if (pMsg.media_wa_type == FMessage::WA_TYPE_CONTACT) { + MCONTACT hContact = AddToContactList(pMsg.remote_resource, pMsg.media_name.c_str()); ADDCONTACTSTRUCT acs = { 0 }; acs.handleType = HANDLE_CONTACT; @@ -20,29 +20,24 @@ void WhatsAppProto::onMessageForMe(FMessage *pMsg, bool paramBoolean) CallServiceSync(MS_ADDCONTACT_SHOW, 0, (LPARAM)&acs); } else { - bool isChatRoom = !pMsg->remote_resource.empty(); - - std::string msg(pMsg->data); - if (!pMsg->media_url.empty()) { + std::string msg(pMsg.data); + if (!pMsg.media_url.empty()) { if (!msg.empty()) msg.append("\n"); - msg += pMsg->media_url; + msg += pMsg.media_url; } - if (isChatRoom) - msg.insert(0, std::string("[").append(pMsg->notifyname).append("]: ")); - - MCONTACT hContact = this->AddToContactList(pMsg->key.remote_jid, 0, false, - isChatRoom ? NULL : pMsg->notifyname.c_str(), isChatRoom); + MCONTACT hContact = this->AddToContactList(pMsg.key.remote_jid, pMsg.notifyname.c_str()); PROTORECVEVENT recv = { 0 }; recv.flags = PREF_UTF; recv.szMessage = const_cast(msg.c_str()); - recv.timestamp = pMsg->timestamp; + recv.timestamp = pMsg.timestamp; ProtoChainRecvMsg(hContact, &recv); } - m_pConnection->sendMessageReceived(pMsg); + if (isOnline()) + m_pConnection->sendMessageReceived(pMsg); } int WhatsAppProto::SendMsg(MCONTACT hContact, int flags, const char *msg) @@ -56,11 +51,6 @@ int WhatsAppProto::SendMsg(MCONTACT hContact, int flags, const char *msg) return 0; } - if (getByte(hContact, "SimpleChatRoom", 0) > 0 && getByte(hContact, "IsGroupMember", 0) == 0) { - debugLogA("not a group member"); - return 0; - } - int msgId = GetSerial(); try { time_t now = time(NULL); @@ -84,9 +74,9 @@ int WhatsAppProto::SendMsg(MCONTACT hContact, int flags, const char *msg) return msgId; } -void WhatsAppProto::onIsTyping(const std::string& paramString, bool paramBoolean) +void WhatsAppProto::onIsTyping(const std::string ¶mString, bool paramBoolean) { - MCONTACT hContact = this->AddToContactList(paramString, 0, false); + MCONTACT hContact = this->AddToContactList(paramString); if (hContact != NULL) { CallService(MS_PROTO_CONTACTISTYPING, (WPARAM)hContact, (LPARAM) paramBoolean ? PROTOTYPE_CONTACTTYPING_INFINITE : PROTOTYPE_CONTACTTYPING_OFF); @@ -108,28 +98,33 @@ int WhatsAppProto::UserIsTyping(MCONTACT hContact, int type) return 0; } -void WhatsAppProto::onMessageStatusUpdate(FMessage* fmsg) +void WhatsAppProto::onMessageStatusUpdate(const FMessage &fmsg) { - MCONTACT hContact = this->ContactIDToHContact(fmsg->key.remote_jid); + MCONTACT hContact = this->ContactIDToHContact(fmsg.key.remote_jid); if (hContact == 0) return; + if (isChatRoom(hContact)) { + onGroupMessageReceived(fmsg); + return; + } + const TCHAR *ptszBy; - switch (fmsg->status) { + switch (fmsg.status) { case FMessage::STATUS_RECEIVED_BY_SERVER: ptszBy = TranslateT("server"); break; case FMessage::STATUS_RECEIVED_BY_TARGET: ptszBy = pcli->pfnGetContactDisplayName(hContact, 0); break; default: return; } - size_t delim = fmsg->key.id.find('-'); + size_t delim = fmsg.key.id.find('-'); if (delim == string::npos) return; - int msgId = atoi(fmsg->key.id.substr(delim+1).c_str()); + int msgId = atoi(fmsg.key.id.substr(delim+1).c_str()); ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)msgId, 0); - time_t timestamp = atol(fmsg->key.id.substr(0, delim).c_str()); + time_t timestamp = atol(fmsg.key.id.substr(0, delim).c_str()); TCHAR ttime[64]; _tcsftime(ttime, SIZEOF(ttime), _T("%X"), localtime(×tamp)); diff --git a/protocols/WhatsApp/src/proto.cpp b/protocols/WhatsApp/src/proto.cpp index 42ec1990eb..ca412a77e8 100644 --- a/protocols/WhatsApp/src/proto.cpp +++ b/protocols/WhatsApp/src/proto.cpp @@ -17,9 +17,10 @@ WhatsAppProto::WhatsAppProto(const char* proto_name, const TCHAR* username) : { update_loop_lock_ = CreateEvent(NULL, false, false, NULL); + db_set_resident(m_szModuleName, "Status"); + db_set_resident(m_szModuleName, "StatusMsg"); + CreateProtoService(PS_CREATEACCMGRUI, &WhatsAppProto::SvcCreateAccMgrUI); - CreateProtoService(PS_JOINCHAT, &WhatsAppProto::OnJoinChat); - CreateProtoService(PS_LEAVECHAT, &WhatsAppProto::OnLeaveChat); CreateProtoService(PS_GETAVATARINFOT, &WhatsAppProto::GetAvatarInfo); CreateProtoService(PS_GETAVATARCAPS, &WhatsAppProto::GetAvatarCaps); @@ -27,11 +28,8 @@ WhatsAppProto::WhatsAppProto(const char* proto_name, const TCHAR* username) : CreateProtoService(PS_SETMYAVATART, &WhatsAppProto::SetMyAvatar); HookProtoEvent(ME_OPT_INITIALISE, &WhatsAppProto::OnOptionsInit); - HookProtoEvent(ME_SYSTEM_MODULESLOADED, &WhatsAppProto::OnModulesLoaded); HookProtoEvent(ME_CLIST_PREBUILDSTATUSMENU, &WhatsAppProto::OnBuildStatusMenu); - this->InitContactMenus(); - // Create standard network connection TCHAR descr[512]; mir_sntprintf(descr, SIZEOF(descr), TranslateT("%s server connection"), m_tszUserName); @@ -59,16 +57,19 @@ WhatsAppProto::~WhatsAppProto() CloseHandle(update_loop_lock_); } -int WhatsAppProto::OnModulesLoaded(WPARAM wParam, LPARAM lParam) +int WhatsAppProto::OnEvent(PROTOEVENTTYPE evType, WPARAM wParam, LPARAM lParam) { - // Register group chat - GCREGISTER gcr = { sizeof(gcr) }; - gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR; - gcr.ptszDispName = m_tszUserName; - gcr.pszModule = m_szModuleName; - CallServiceSync(MS_GC_REGISTER, 0, (LPARAM)&gcr); - - HookProtoEvent(ME_GC_EVENT, &WhatsAppProto::OnChatOutgoing); + if (evType == EV_PROTO_ONLOAD) { + // Register group chat + GCREGISTER gcr = { sizeof(gcr) }; + gcr.dwFlags = GC_TYPNOTIF | GC_CHANMGR; + gcr.ptszDispName = m_tszUserName; + gcr.pszModule = m_szModuleName; + CallServiceSync(MS_GC_REGISTER, 0, (LPARAM)&gcr); + + HookProtoEvent(ME_GC_EVENT, &WhatsAppProto::onGroupChatEvent); + HookProtoEvent(ME_GC_BUILDMENU, &WhatsAppProto::OnChatMenu); + } return 0; } @@ -165,7 +166,7 @@ MCONTACT WhatsAppProto::AddToList(int flags, PROTOSEARCHRESULT* psr) std::string phone(ptrA(mir_utf8encodeT(psr->id))); std::string jid(phone + "@s.whatsapp.net"); - MCONTACT hContact = AddToContactList(jid, 0, false, phone.c_str()); + MCONTACT hContact = AddToContactList(jid, phone.c_str()); if (!(flags & PALF_TEMPORARY)) db_unset(hContact, "CList", "NotOnList"); diff --git a/protocols/WhatsApp/src/proto.h b/protocols/WhatsApp/src/proto.h index b0c5c8a6bf..b07d8aed87 100644 --- a/protocols/WhatsApp/src/proto.h +++ b/protocols/WhatsApp/src/proto.h @@ -3,11 +3,28 @@ class WASocketConnection; +#include "WhatsAPI++/WAConnection.h" + +struct WAChatInfo +{ + WAChatInfo(TCHAR *_jid, TCHAR *_nick) : + tszJid(_jid), tszNick(_nick) + { + bActive = false; + } + + map m_unsentMsgs; + ptrT tszJid, tszNick, tszOwner; + bool bActive; + + MCONTACT hContact; +}; + class WhatsAppProto : public PROTO, public WAListener, public WAGroupListener { public: WhatsAppProto(const char *proto_name, const TCHAR *username); - ~WhatsAppProto( ); + ~WhatsAppProto(); inline bool isOnline() const { return (m_pConnection != NULL); @@ -21,20 +38,20 @@ public: { return (m_iStatus == ID_STATUS_INVISIBLE); } - // PROTO_INTERFACE + // PROTO_INTERFACE /////////////////////////////////////////////////////////////////// - virtual MCONTACT __cdecl AddToList(int flags, PROTOSEARCHRESULT* psr); - virtual MCONTACT __cdecl AddToListByEvent(int flags, int iContact, MEVENT hDbEvent) { return NULL; } + virtual MCONTACT __cdecl AddToList(int flags, PROTOSEARCHRESULT* psr); + virtual MCONTACT __cdecl AddToListByEvent(int flags, int iContact, MEVENT hDbEvent) { return NULL; } - virtual int __cdecl Authorize(MEVENT hDbEvent); - virtual int __cdecl AuthDeny(MEVENT hDbEvent, const PROTOCHAR* szReason) { return 1; } - virtual int __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT*) { return 1; } - virtual int __cdecl AuthRequest(MCONTACT hContact, const PROTOCHAR* szMessage); + virtual int __cdecl Authorize(MEVENT hDbEvent); + virtual int __cdecl AuthDeny(MEVENT hDbEvent, const PROTOCHAR* szReason) { return 1; } + virtual int __cdecl AuthRecv(MCONTACT hContact, PROTORECVEVENT*) { return 1; } + virtual int __cdecl AuthRequest(MCONTACT hContact, const PROTOCHAR* szMessage); - virtual HANDLE __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szPath) { return NULL; } - virtual int __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer) { return 1; } - virtual int __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szReason) { return 1; } - virtual int __cdecl FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename) { return 1; } + virtual HANDLE __cdecl FileAllow(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szPath) { return NULL; } + virtual int __cdecl FileCancel(MCONTACT hContact, HANDLE hTransfer) { return 1; } + virtual int __cdecl FileDeny(MCONTACT hContact, HANDLE hTransfer, const PROTOCHAR* szReason) { return 1; } + virtual int __cdecl FileResume(HANDLE hTransfer, int* action, const PROTOCHAR** szFilename) { return 1; } virtual DWORD_PTR __cdecl GetCaps(int type, MCONTACT hContact = NULL); virtual int __cdecl GetInfo(MCONTACT hContact, int infoType) { return 1; } @@ -65,86 +82,76 @@ public: virtual int __cdecl UserIsTyping(MCONTACT hContact, int type); - virtual int __cdecl OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam) { return 1; } + virtual int __cdecl OnEvent(PROTOEVENTTYPE iEventType, WPARAM wParam, LPARAM lParam); - ////////////////////////////////////////////////////////////////////////////////////// - // Services + // Services ////////////////////////////////////////////////////////////////////////// INT_PTR __cdecl SvcCreateAccMgrUI(WPARAM, LPARAM); - INT_PTR __cdecl OnJoinChat(WPARAM, LPARAM); - INT_PTR __cdecl OnLeaveChat(WPARAM, LPARAM); - INT_PTR __cdecl OnCreateGroup(WPARAM, LPARAM); - ////////////////////////////////////////////////////////////////////////////////////// - // Events + // Events //////////////////////////////////////////////////////////////////////////// int __cdecl OnOptionsInit(WPARAM, LPARAM); - int __cdecl OnModulesLoaded(WPARAM, LPARAM); int __cdecl OnBuildStatusMenu(WPARAM, LPARAM); - int __cdecl OnChatOutgoing(WPARAM, LPARAM); - int __cdecl OnPrebuildContactMenu(WPARAM, LPARAM); - INT_PTR __cdecl OnAddContactToGroup(WPARAM, LPARAM, LPARAM); - INT_PTR __cdecl OnRemoveContactFromGroup(WPARAM, LPARAM, LPARAM); - INT_PTR __cdecl OnChangeGroupSubject(WPARAM, LPARAM); - INT_PTR __cdecl OnLeaveGroup(WPARAM, LPARAM); + // Worker Threads //////////////////////////////////////////////////////////////////// - // Loops - bool NegotiateConnection(); void __cdecl stayConnectedLoop(void*); void __cdecl sentinelLoop(void*); - ////////////////////////////////////////////////////////////////////////////////////// - // Processing Threads + // Processing Threads //////////////////////////////////////////////////////////////// void __cdecl ProcessBuddyList(void*); void __cdecl SearchAckThread(void*); - ////////////////////////////////////////////////////////////////////////////////////// - // Worker Threads - - void __cdecl SendGetGroupInfoWorker(void*); - void __cdecl SendSetGroupNameWorker(void*); - void __cdecl SendCreateGroupWorker(void*); + // Contacts handling ///////////////////////////////////////////////////////////////// - ////////////////////////////////////////////////////////////////////////////////////// - // Contacts handling + MCONTACT AddToContactList(const std::string &jid, const char *new_name = NULL); - MCONTACT AddToContactList(const std::string &jid, BYTE type = 0, bool dont_check = false, - const char *new_name = NULL, bool isChatRoom = false, bool isHidden = false); - - bool IsMyContact(MCONTACT hContact, bool include_chat = false); MCONTACT ContactIDToHContact(const std::string&); void SetAllContactStatuses(int status, bool reset_client = false); void UpdateStatusMsg(MCONTACT hContact); TCHAR* GetContactDisplayName(const string &jid); - void InitContactMenus(); - void HandleReceiveGroups(const std::vector &groups, bool isOwned); void RequestFriendship(MCONTACT hContact); - bool IsGroupChat(MCONTACT hC, bool checkIsAdmin = false) - { - return getByte(hC, "SimpleChatRoom", 0) > (checkIsAdmin ? 1 : 0); - } + // Group chats /////////////////////////////////////////////////////////////////////// + + std::vector m_szInviteJids; + map m_chats; + mir_cs m_csChats; + + void ChatLogMenuHook(WAChatInfo *pInfo, GCHOOK *gch); + void NickListMenuHook(WAChatInfo *pInfo, GCHOOK *gch); + + void AddChatUser(WAChatInfo *pInfo, const TCHAR *ptszJid); + void EditChatSubject(WAChatInfo *pInfo); + void InviteChatUser(WAChatInfo *pInfo); + void KickChatUser(WAChatInfo *pInfo, const TCHAR *ptszJid); + TCHAR* GetChatUserNick(const std::string &jid); + + void onGroupMessageReceived(const FMessage &fmsg); - LONG GetSerial(); + WAChatInfo* InitChat(const std::string &jidjid, const std::string &nick); + WAChatInfo* SafeGetChat(const std::string &jid); - ////////////////////////////////////////////////////////////////////////////////////// - // Registration + int __cdecl onGroupChatEvent(WPARAM, LPARAM); + int __cdecl OnChatMenu(WPARAM, LPARAM); + INT_PTR __cdecl OnCreateGroup(WPARAM, LPARAM); + + // Registration ////////////////////////////////////////////////////////////////////// bool Register(int state, const string &cc, const string &number, const string &code, string &password); private: - - ////////////////////////////////////////////////////////////////////////////////////// - // Helpers + // Helpers ////////////////////////////////////////////////////////////////////////// LONG m_iSerial; + __forceinline LONG GetSerial() + { return ::_InterlockedIncrement(&m_iSerial); + } void ToggleStatusMenuItems(BOOL bEnable); - ////////////////////////////////////////////////////////////////////////////////////// - // Avatars + /// Avatars ////////////////////////////////////////////////////////////////////////// std::tstring GetAvatarFileName(MCONTACT); std::tstring m_tszAvatarFolder; @@ -154,14 +161,11 @@ private: INT_PTR __cdecl GetMyAvatar(WPARAM, LPARAM); INT_PTR __cdecl SetMyAvatar(WPARAM, LPARAM); - ////////////////////////////////////////////////////////////////////////////////////// - // Handles, Locks - + // Private data ////////////////////////////////////////////////////////////////////// + HGENMENU m_hMenuRoot; HANDLE m_hMenuCreateGroup; - HANDLE signon_lock_; - HANDLE log_lock_; HANDLE update_loop_lock_; WASocketConnection *conn; @@ -170,18 +174,16 @@ private: time_t m_tLastWriteTime; std::vector m_Challenge; - string m_szPhoneNumber; - string m_szJid, m_szNick; + std::string m_szPhoneNumber; + std::string m_szJid, m_szNick; std::map hContactByJid; map> isMemberByGroupContact; - ////////////////////////////////////////////////////////////////////////////////////// - // WhatsApp Events - protected: - virtual void onMessageForMe(FMessage *paramFMessage, bool paramBoolean); - virtual void onMessageStatusUpdate(FMessage *paramFMessage); - virtual void onMessageError(FMessage *message, int paramInt) { ; } + // WAListener methods //////////////////////////////////////////////////////////////// + virtual void onMessageForMe(const FMessage ¶mFMessage); + virtual void onMessageStatusUpdate(const FMessage ¶mFMessage); + virtual void onMessageError(const FMessage &message, int paramInt) { ; } virtual void onPing(const std::string &id) throw (WAException); virtual void onPingResponseReceived() { } virtual void onAvailable(const std::string ¶mString, bool paramBoolean); @@ -195,29 +197,28 @@ protected: virtual void onDirtyResponse(int paramHashtable) { } virtual void onRelayRequest(const std::string ¶mString1, int paramInt, const std::string ¶mString2) { } virtual void onSendGetPicture(const std::string &jid, const std::vector& data, const std::string &id); - virtual void onPictureChanged(const std::string &from, const std::string &author, bool set); - virtual void onDeleteAccount(bool result) { } - - virtual void onGroupAddUser(const std::string ¶mString1, const std::string ¶mString2); - virtual void onGroupRemoveUser(const std::string ¶mString1, const std::string ¶mString2); - virtual void onGroupNewSubject(const std::string &from, const std::string &author, const std::string &newSubject, int paramInt); - virtual void onServerProperties(std::map* nameValueMap) { } - virtual void onGroupCreated(const std::string ¶mString1, const std::string ¶mString2); - virtual void onGroupInfo(const std::string ¶mString1, const std::string ¶mString2, const std::string ¶mString3, const std::string ¶mString4, int paramInt1, int paramInt2); - virtual void onGroupInfoFromList(const std::string ¶mString1, const std::string ¶mString2, const std::string ¶mString3, const std::string ¶mString4, int paramInt1, int paramInt2); - virtual void onOwningGroups(const std::vector& paramVector); + virtual void onPictureChanged(const std::string &jid, const std::string &id, bool set); + virtual void onContactChanged(const std::string &jid, bool added); + virtual void onDeleteAccount(bool result) {} + + // WAGroupListener methods /////////////////////////////////////////////////////////// + virtual void onGroupAddUser(const std::string &gjid, const std::string &ujid, int ts); + virtual void onGroupRemoveUser(const std::string &gjid, const std::string &ujid, int ts); + virtual void onGroupNewSubject(const std::string &from, const std::string &author, const std::string &newSubject, int ts); + virtual void onGroupMessage(const FMessage ¶mFMessage); + virtual void onServerProperties(std::map* nameValueMap) {} + virtual void onGroupCreated(const std::string &gjid, const std::string &nick); + virtual void onGroupInfo(const std::string &jid, const std::string &owner, const std::string &subject, const std::string &subject_owner, int time_subject, int time_created); virtual void onSetSubject(const std::string ¶mString) { } - virtual void onAddGroupParticipants(const std::string ¶mString, const std::vector& paramVector, int paramHashtable) { } - virtual void onRemoveGroupParticipants(const std::string ¶mString, const std::vector& paramVector, int paramHashtable) { } - virtual void onGetParticipants(const std::string &gjid, const std::vector& participants); - virtual void onParticipatingGroups(const std::vector& paramVector); + virtual void onAddGroupParticipants(const std::string ¶mString, const std::vector ¶mVector, int paramHashtable) { } + virtual void onRemoveGroupParticipants(const std::string ¶mString, const std::vector ¶mVector, int paramHashtable) { } + virtual void onGetParticipants(const std::string &gjid, const std::vector &participants); virtual void onLeaveGroup(const std::string ¶mString); - ////////////////////////////////////////////////////////////////////////////////////// - // Information providing + // Information providing ///////////////////////////////////////////////////////////// void NotifyEvent(const TCHAR *title, const TCHAR *info, MCONTACT contact, DWORD flags, TCHAR *url = NULL); void NotifyEvent(const std::string &title, const std::string &info, MCONTACT contact, DWORD flags, TCHAR *url = NULL); }; -#endif \ No newline at end of file +#endif diff --git a/protocols/WhatsApp/src/resource.h b/protocols/WhatsApp/src/resource.h index c9872322c0..ebab688804 100644 --- a/protocols/WhatsApp/src/resource.h +++ b/protocols/WhatsApp/src/resource.h @@ -5,13 +5,12 @@ #define IDD_INPUTBOX 102 #define IDR_REGISTERUTILITY 103 #define IDD_WHATSAPOPTIONS 104 +#define IDD_GROUPCHAT_INVITE 105 #define IDI_WHATSAPP 203 #define IDI_ADD_GROUP 206 -#define IDI_ADD_USER_TO_GROUP 207 #define IDI_RENAME_GROUP 208 -#define IDI_CHANGE_GROUP_SUBJECT 209 -#define IDI_LEAVE_GROUP 210 -#define IDI_REMOVE_USER_FROM_GROUP 211 +#define IDC_CLIST 1001 +#define IDC_NEWJID 1002 #define IDC_LOGIN 1003 #define IDC_PW 1004 #define IDC_SSL 1005 @@ -24,14 +23,15 @@ #define IDC_OK 1012 #define IDC_PW2 1013 #define IDC_TEXT 1014 +#define IDC_INVITE 1015 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 +#define _APS_NEXT_RESOURCE_VALUE 106 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1015 +#define _APS_NEXT_CONTROL_VALUE 1016 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/protocols/WhatsApp/src/theme.cpp b/protocols/WhatsApp/src/theme.cpp index 94e46e8b14..b95e7649b2 100644 --- a/protocols/WhatsApp/src/theme.cpp +++ b/protocols/WhatsApp/src/theme.cpp @@ -5,12 +5,7 @@ extern OBJLIST g_Instances; static IconItem icons[] = { { LPGEN("WhatsApp icon"), "whatsApp", IDI_WHATSAPP }, - { LPGEN("Add to group"), "addContactToGroup", IDI_ADD_USER_TO_GROUP}, - { LPGEN("Create chat group"), "createGroup", IDI_ADD_GROUP }, - { LPGEN("Remove from chat group"), "removeContactFromGroup", IDI_REMOVE_USER_FROM_GROUP }, - { LPGEN("Leave and delete group"), "leaveAndDeleteGroup", IDI_LEAVE_GROUP }, - { LPGEN("Leave group"), "leaveGroup", IDI_LEAVE_GROUP }, - { LPGEN("Change group subject"), "changeGroupSubject", IDI_CHANGE_GROUP_SUBJECT } + { LPGEN("Create chat group"), "createGroup", IDI_ADD_GROUP } }; void InitIcons(void) @@ -36,9 +31,6 @@ char* GetIconDescription(const char* name) return ""; } -// Contact List menu stuff -HGENMENU g_hContactMenuItems[CMITEMS_COUNT]; - // Helper functions static WhatsAppProto* GetInstanceByHContact(MCONTACT hContact) { @@ -53,163 +45,6 @@ static WhatsAppProto* GetInstanceByHContact(MCONTACT hContact) return 0; } -template -INT_PTR GlobalService(WPARAM wParam, LPARAM lParam) -{ - WhatsAppProto *proto = GetInstanceByHContact(MCONTACT(wParam)); - return proto ? (proto->*Fcn)(wParam, lParam) : 0; -} - -template -INT_PTR GlobalServiceParam(WPARAM wParam, LPARAM lParam, LPARAM lParam2) -{ - WhatsAppProto *proto = GetInstanceByHContact(MCONTACT(wParam)); - return proto ? (proto->*Fcn)(wParam, lParam, lParam2) : 0; -} - -static int PrebuildContactMenu(WPARAM wParam, LPARAM lParam) -{ - for (size_t i = 0; i < SIZEOF(g_hContactMenuItems); i++) - Menu_ShowItem(g_hContactMenuItems[i], false); - - WhatsAppProto *proto = GetInstanceByHContact(MCONTACT(wParam)); - return proto ? proto->OnPrebuildContactMenu(wParam, lParam) : 0; -} - -void WhatsAppProto::InitContactMenus() -{ - ::HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PrebuildContactMenu); - - CLISTMENUITEM mi = { sizeof(mi) }; - mi.position = -2000006100; - mi.icolibItem = GetIconHandle("leaveGroup"); - mi.pszName = GetIconDescription("leaveGroup"); - mi.pszService = "WhatsAppProto/LeaveGroup"; - CreateServiceFunction(mi.pszService, GlobalService<&WhatsAppProto::OnLeaveGroup>); - g_hContactMenuItems[CMI_LEAVE_GROUP] = Menu_AddContactMenuItem(&mi); - - mi.position = -2000006100; - mi.icolibItem = GetIconHandle("leaveAndDeleteGroup"); - mi.pszName = GetIconDescription("leaveAndDeleteGroup"); - g_hContactMenuItems[CMI_REMOVE_GROUP] = Menu_AddContactMenuItem(&mi); - - mi.position = -2000006099; - mi.icolibItem = GetIconHandle("changeGroupSubject"); - mi.pszName = GetIconDescription("changeGroupSubject"); - mi.pszService = "WhatsAppProto/ChangeGroupSubject"; - CreateServiceFunction(mi.pszService, GlobalService<&WhatsAppProto::OnChangeGroupSubject>); - g_hContactMenuItems[CMI_CHANGE_GROUP_SUBJECT] = Menu_AddContactMenuItem(&mi); -} - -int WhatsAppProto::OnPrebuildContactMenu(WPARAM wParam, LPARAM lParam) -{ - MCONTACT hContact = MCONTACT(wParam); - if (hContact) - debugLog(pcli->pfnGetContactDisplayName(hContact, 0)); - else - debugLogA("No contact found"); - - if (g_hContactMenuItems[CMI_ADD_CONTACT_TO_GROUP] != NULL) - CallService("CList/RemoveContactMenuItem", (WPARAM)g_hContactMenuItems[CMI_ADD_CONTACT_TO_GROUP], (LPARAM)0); - - if (g_hContactMenuItems[CMI_REMOVE_CONTACT_FROM_GROUP] != NULL) - CallService("CList/RemoveContactMenuItem", (WPARAM)g_hContactMenuItems[CMI_REMOVE_CONTACT_FROM_GROUP], (LPARAM)0); - - int chatType = getByte(hContact, "SimpleChatRoom", 0); - - CLISTMENUITEM mi = { sizeof(mi) }; - - if (chatType == 0) { - mi.flags = CMIF_CHILDPOPUP; - mi.position = -2000006102; - mi.icolibItem = GetIconHandle("addContactToGroup"); - mi.pszName = GetIconDescription("addContactToGroup"); - mi.pszService = NULL; - g_hContactMenuItems[CMI_ADD_CONTACT_TO_GROUP] = Menu_AddContactMenuItem(&mi); - - if (!isOnline()) { - Menu_ShowItem(g_hContactMenuItems[CMI_ADD_CONTACT_TO_GROUP], false); - return 0; - } - - mi.hParentMenu = (HGENMENU)g_hContactMenuItems[CMI_ADD_CONTACT_TO_GROUP]; - mi.flags = CMIF_ROOTHANDLE | CMIF_TCHAR; - - int iGrpCount = 0; - string fullSvcName; - string svcName = m_szModuleName; - svcName += "/AddContactToGroup_"; - DBVARIANT dbv; - - for (map>::iterator it = this->isMemberByGroupContact.begin(); - it != this->isMemberByGroupContact.end(); ++it) { - map::iterator memberIt = it->second.find(hContact); - // Only, if current contact is not already member of this group - if ((memberIt == it->second.end() || memberIt->second == false) && !getString(it->first, "ID", &dbv)) { - fullSvcName = svcName + dbv.pszVal; - mi.pszService = (char*)fullSvcName.c_str(); - mi.ptszName = pcli->pfnGetContactDisplayName(it->first, 0); - CreateServiceFunctionParam(mi.pszService, GlobalServiceParam<&WhatsAppProto::OnAddContactToGroup>, (LPARAM)it->first); - Menu_AddContactMenuItem(&mi); - db_free(&dbv); - iGrpCount++; - } - } - if (!iGrpCount) - Menu_ShowItem(g_hContactMenuItems[CMI_ADD_CONTACT_TO_GROUP], false); - } - else if (chatType == 1) { - mi.flags = CMIM_FLAGS; - if (!isOnline() || getByte(hContact, "IsGroupMember", 0) == 0) - mi.flags |= CMIF_GRAYED; - CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)g_hContactMenuItems[CMI_LEAVE_GROUP], (LPARAM)&mi); - } - else if (chatType == 2) { - // owning chat/group - mi.flags = CMIF_CHILDPOPUP; - mi.position = -2000006102; - mi.icolibItem = GetIconHandle("removeContactFromGroup"); - mi.pszName = GetIconDescription("removeContactFromGroup"); - mi.pszService = NULL; - g_hContactMenuItems[CMI_REMOVE_CONTACT_FROM_GROUP] = Menu_AddContactMenuItem(&mi); - - bool bShow = false; - if (isOnline() && getByte(hContact, "IsGroupMember", 0) == 1) { - map>::iterator groupsIt = this->isMemberByGroupContact.find(hContact); - if (groupsIt == this->isMemberByGroupContact.end()) - debugLogA("Group exists only on contact list"); - else { - mi.hParentMenu = (HGENMENU)g_hContactMenuItems[CMI_REMOVE_CONTACT_FROM_GROUP]; - mi.flags = CMIF_ROOTHANDLE | CMIF_TCHAR; - - string fullSvcName; - string svcName = m_szModuleName; - svcName += "/RemoveContactFromGroup_"; - DBVARIANT dbv; - - for (map::iterator it = groupsIt->second.begin(); it != groupsIt->second.end(); ++it) { - if (!getString(it->first, "ID", &dbv)) { - fullSvcName = svcName + dbv.pszVal; - mi.pszService = (char*)fullSvcName.c_str(); - mi.ptszName = pcli->pfnGetContactDisplayName(it->first, 0); - CreateServiceFunctionParam(mi.pszService, - GlobalServiceParam<&WhatsAppProto::OnRemoveContactFromGroup>, (LPARAM)it->first); - Menu_AddContactMenuItem(&mi); - db_free(&dbv); - bShow = true; - } - } - } - } - else Menu_ShowItem(g_hContactMenuItems[CMI_REMOVE_CONTACT_FROM_GROUP], false); - - Menu_ShowItem(g_hContactMenuItems[CMI_REMOVE_GROUP], bShow); - Menu_ShowItem(g_hContactMenuItems[CMI_CHANGE_GROUP_SUBJECT], bShow); - } - - return 0; -} - int WhatsAppProto::OnBuildStatusMenu(WPARAM wParam, LPARAM lParam) { char text[200]; @@ -223,7 +58,7 @@ int WhatsAppProto::OnBuildStatusMenu(WPARAM wParam, LPARAM lParam) if (hRoot == NULL) { mi.popupPosition = 500085000; mi.hParentMenu = HGENMENU_ROOT; - mi.flags = CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED | (this->isOnline() ? 0 : CMIF_GRAYED); + mi.flags = CMIF_ROOTPOPUP | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED | (isOnline() ? 0 : CMIF_GRAYED); mi.icolibItem = GetIconHandle("whatsApp"); mi.ptszName = m_tszUserName; hRoot = m_hMenuRoot = Menu_AddProtoMenuItem(&mi); @@ -234,7 +69,7 @@ int WhatsAppProto::OnBuildStatusMenu(WPARAM wParam, LPARAM lParam) m_hMenuRoot = NULL; } - mi.flags = CMIF_CHILDPOPUP | (this->isOnline() ? 0 : CMIF_GRAYED); + mi.flags = CMIF_CHILDPOPUP | (isOnline() ? 0 : CMIF_GRAYED); mi.position = 201001; CreateProtoService("/CreateGroup", &WhatsAppProto::OnCreateGroup); diff --git a/protocols/WhatsApp/src/utils.cpp b/protocols/WhatsApp/src/utils.cpp index 2b9ebd2b2f..652a9c7c4a 100644 --- a/protocols/WhatsApp/src/utils.cpp +++ b/protocols/WhatsApp/src/utils.cpp @@ -1,8 +1,26 @@ #include "common.h" -LONG WhatsAppProto::GetSerial() +TCHAR* utils::removeA(TCHAR *str) { - return ::_InterlockedIncrement(&m_iSerial); + if (str == NULL) + return NULL; + + TCHAR *p = _tcschr(str, '@'); + if (p) *p = 0; + return str; +} + +void utils::copyText(HWND hwnd, const TCHAR *text) +{ + if (!hwnd || !text) return; + + OpenClipboard(hwnd); + EmptyClipboard(); + HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, sizeof(TCHAR)*(mir_tstrlen(text) + 1)); + mir_tstrcpy((TCHAR*)GlobalLock(hMem), text); + GlobalUnlock(hMem); + SetClipboardData(CF_UNICODETEXT, hMem); + CloseClipboard(); } std::string getLastErrorMsg() diff --git a/protocols/WhatsApp/src/utils.h b/protocols/WhatsApp/src/utils.h index a14a707a14..d9a1218312 100644 --- a/protocols/WhatsApp/src/utils.h +++ b/protocols/WhatsApp/src/utils.h @@ -27,8 +27,15 @@ public: std::string getLastErrorMsg(); +__forceinline TCHAR* str2t(const std::string &str) +{ return mir_utf8decodeT(str.c_str()); +} + namespace utils { + TCHAR* removeA(TCHAR *str); + void copyText(HWND hwnd, const TCHAR *text); + void setStatusMessage(MCONTACT hContact, const TCHAR *ptszMessage); BYTE* md5string(const BYTE*, int, BYTE* digest); diff --git a/protocols/WhatsApp/src/version.h b/protocols/WhatsApp/src/version.h index 5d83753125..6f591420cd 100644 --- a/protocols/WhatsApp/src/version.h +++ b/protocols/WhatsApp/src/version.h @@ -1,7 +1,7 @@ #define __MAJOR_VERSION 0 #define __MINOR_VERSION 1 #define __RELEASE_NUM 2 -#define __BUILD_NUM 6 +#define __BUILD_NUM 7 #include -- cgit v1.2.3