From 0acc48076d8b2148d60d8a2532753c1eb06de276 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Mon, 26 Jan 2015 20:54:25 +0000 Subject: fix for sending messages git-svn-id: http://svn.miranda-ng.org/main/trunk@11919 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- .../WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp | 6 + protocols/WhatsApp/src/WhatsAPI++/FMessage.h | 49 +- protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp | 936 ++++++++++----------- protocols/WhatsApp/src/WhatsAPI++/WAConnection.h | 20 +- protocols/WhatsApp/src/contacts.cpp | 6 - protocols/WhatsApp/src/db.h | 3 - protocols/WhatsApp/src/messages.cpp | 110 +-- protocols/WhatsApp/src/proto.cpp | 6 +- protocols/WhatsApp/src/proto.h | 65 +- protocols/WhatsApp/src/utils.cpp | 5 - 10 files changed, 565 insertions(+), 641 deletions(-) (limited to 'protocols/WhatsApp') diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp index 7ec854878a..e9b6377879 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp @@ -260,6 +260,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 writeInternal(node); flushBuffer(needsFlush); } diff --git a/protocols/WhatsApp/src/WhatsAPI++/FMessage.h b/protocols/WhatsApp/src/WhatsAPI++/FMessage.h index 3d9c8438f5..fb523d9c8e 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/FMessage.h +++ b/protocols/WhatsApp/src/WhatsAPI++/FMessage.h @@ -51,29 +51,32 @@ public: double latitude; double longitude; - static const unsigned char WA_TYPE_UNDEFINED = 0; - static const unsigned char WA_TYPE_IMAGE = 1; - static const unsigned char WA_TYPE_AUDIO = 2; - static const unsigned char WA_TYPE_VIDEO = 3; - static const unsigned char WA_TYPE_CONTACT = 4; - static const unsigned char WA_TYPE_LOCATION = 5; - static const unsigned char WA_TYPE_SYSTEM = 7; - - static const int STATUS_UNSENT = 0; - static const int STATUS_UPLOADING = 1; - static const int STATUS_UPLOADED = 2; - static const int STATUS_SENT_BY_CLIENT = 3; - static const int STATUS_RECEIVED_BY_SERVER = 4; - static const int STATUS_RECEIVED_BY_TARGET = 5; - static const int STATUS_NEVER_SEND = 6; - static const int STATUS_SERVER_BOUNCE = 7; - - static const int STATUS_USER_ADDED = 191; - static const int STATUS_USER_REMOVED = 192; - static const int STATUS_SUBJECT_CHANGED = 193; - static const int STATUS_PICTURE_CHANGED_SET = 194; - static const int STATUS_PICTURE_CHANGED_DELETE = 195; - + enum { + WA_TYPE_UNDEFINED = 0, + WA_TYPE_IMAGE = 1, + WA_TYPE_AUDIO = 2, + WA_TYPE_VIDEO = 3, + WA_TYPE_CONTACT = 4, + WA_TYPE_LOCATION = 5, + WA_TYPE_SYSTEM = 7 + }; + + enum { + STATUS_UNSENT = 0, + STATUS_UPLOADING = 1, + STATUS_UPLOADED = 2, + STATUS_SENT_BY_CLIENT = 3, + STATUS_RECEIVED_BY_SERVER = 4, + STATUS_RECEIVED_BY_TARGET = 5, + STATUS_NEVER_SEND = 6, + STATUS_SERVER_BOUNCE = 7, + + STATUS_USER_ADDED = 191, + STATUS_USER_REMOVED = 192, + STATUS_SUBJECT_CHANGED = 193, + STATUS_PICTURE_CHANGED_SET = 194, + STATUS_PICTURE_CHANGED_DELETE = 195 + }; static std::string getMessage_WA_Type_StrValue(unsigned char type); static std::string nextKeyIdNumber(); diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp index d5533577bb..7ae18a30d5 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp +++ b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.cpp @@ -137,57 +137,55 @@ void WAConnection::init(IMutex *mutex, ISocketConnection *conn) out = new BinTreeNodeWriter(this, conn, mutex); } -void WAConnection::setLogin(WALogin* login) +std::string WAConnection::gidToGjid(const std::string& gid) { - if (login->expire_date != 0L) - this->expire_date = login->expire_date; + return gid + "@g.us"; +} - if (login->account_kind != -1) - this->account_kind = login->account_kind; +std::string WAConnection::makeId(const std::string& prefix) +{ + this->iqid++; + std::string id; + if (this->verbose) + id = prefix + Utilities::intToStr(this->iqid); + else + id = Utilities::itoa(this->iqid, 16); + + return id; } -void WAConnection::sendMessageWithMedia(FMessage* message) throw (WAException) +ProtocolTreeNode* WAConnection::getReceiptAck(const std::string& to, const std::string& id, const std::string& receiptType) throw(WAException) { - logData("Send message with media %s %d", message->media_name.c_str(), message->media_size); - logData("media-url:%s", message->media_url.c_str()); - if (message->media_wa_type == FMessage::WA_TYPE_SYSTEM) - throw new WAException("Cannot send system message over the network"); - - ProtocolTreeNode *mediaNode; - if (message->media_wa_type == FMessage::WA_TYPE_CONTACT && !message->media_name.empty()) { - ProtocolTreeNode* vcardNode = new ProtocolTreeNode("vcard", new std::vector(message->data.begin(), message->data.end())) - << XATTR("name", message->media_name); - mediaNode = new ProtocolTreeNode("media", vcardNode); - } - else { - mediaNode = new ProtocolTreeNode("media", new std::vector(message->data.begin(), message->data.end()), NULL) - << XATTR("encoding", "text"); - } + ProtocolTreeNode *ackNode = new ProtocolTreeNode("ack") + << XATTR("xmlns", "urn:xmpp:receipts") << XATTR("type", receiptType); - mediaNode << XATTR("xmlns", "urn:xmpp:whatsapp:mms") << XATTR("type", FMessage::getMessage_WA_Type_StrValue(message->media_wa_type)); + return new ProtocolTreeNode("message", ackNode) << XATTR("to", to) << XATTR("type", "chat") << XATTR("id", id); +} - if (message->media_wa_type == FMessage::WA_TYPE_LOCATION) - mediaNode << XATTR("latitude", Utilities::doubleToStr(message->latitude)) << XATTR("longitude", Utilities::doubleToStr(message->longitude)); - else { - mediaNode << XATTR("file", message->media_name) << XATTRI("size", message->media_size) << XATTR("url", message->media_url); - if (message->media_wa_type == FMessage::WA_TYPE_CONTACT || message->media_name.empty() || message->media_url.empty() || message->media_size <= 0) - mediaNode << XATTRI("seconds", message->media_duration_seconds); - } +bool WAConnection::supportsReceiptAcks() +{ + return supports_receipt_acks; +} - ProtocolTreeNode *n = WAConnection::getMessageNode(message, mediaNode); - this->out->write(*n); - delete n; +std::string WAConnection::removeResourceFromJid(const std::string& jid) +{ + size_t slashidx = jid.find('/'); + if (slashidx == std::string::npos) + return jid; + + return jid.substr(0, slashidx + 1); } -void WAConnection::sendMessageWithBody(FMessage* message) throw (WAException) +void WAConnection::setLogin(WALogin* login) { - ProtocolTreeNode* bodyNode = new ProtocolTreeNode("body", new std::vector(message->data.begin(), message->data.end())); - ProtocolTreeNode *n = WAConnection::getMessageNode(message, bodyNode); - this->out->write(*n); - delete n; + if (login->expire_date != 0L) + this->expire_date = login->expire_date; + + if (login->account_kind != -1) + this->account_kind = login->account_kind; } -ProtocolTreeNode* WAConnection::getMessageNode(FMessage* message, ProtocolTreeNode* child) +ProtocolTreeNode* WAConnection::getMessageNode(FMessage* message, ProtocolTreeNode *child) { std::vector* messageChildren = new std::vector(); messageChildren->push_back(new ProtocolTreeNode("x", new ProtocolTreeNode("server")) << XATTR("xmlns", "jabber:x:event")); @@ -197,27 +195,14 @@ ProtocolTreeNode* WAConnection::getMessageNode(FMessage* message, ProtocolTreeNo XATTR("to", message->key->remote_jid) << XATTR("type", "chat") << XATTR("id", message->key->id); } -void WAConnection::sendMessage(FMessage* message) throw(WAException) -{ - if (message->media_wa_type != 0) - sendMessageWithMedia(message); - else - sendMessageWithBody(message); -} - void WAConnection::setVerboseId(bool b) { this->verbose = b; } -void WAConnection::sendAvailableForChat() throw(WAException) -{ - this->out->write(ProtocolTreeNode("presence") << XATTR("name", this->nick)); -} - bool WAConnection::read() throw(WAException) { - ProtocolTreeNode* node; + ProtocolTreeNode *node; try { node = this->in->nextTree(); this->lastTreeRead = time(NULL); @@ -236,281 +221,89 @@ bool WAConnection::read() throw(WAException) } #endif - if (ProtocolTreeNode::tagEquals(node, "iq")) { - 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 (this->event_handler != NULL) - this->event_handler->onAccountChange(this->account_kind, this->expire_date); - } - } - 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 (this->event_handler != NULL) - this->event_handler->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() && this->event_handler != NULL) { - int timeoutSeconds = atoi(childNode->getAttributeValue("timeout").c_str()); - this->event_handler->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); - } - else if (ProtocolTreeNode::tagEquals(node, "presence")) { - const string &xmlns = node->getAttributeValue("xmlns"); - const string &from = node->getAttributeValue("from"); - if (xmlns == "urn:xmpp" && !from.empty()) { - const string &type = node->getAttributeValue("type"); - if (type == "unavailable") { - if (this->event_handler != NULL) - this->event_handler->onAvailable(from, false); - } - else if (type == "available") { - if (this->event_handler != NULL) - this->event_handler->onAvailable(from, true); - } - } - else 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 (this->group_event_handler != NULL) - this->group_event_handler->onGroupAddUser(from, add); - } - else if (!remove.empty()) { - if (this->group_event_handler != NULL) - this->group_event_handler->onGroupRemoveUser(from, remove); - } - else if (status == "dirty") { - std::map* categories = parseCategories(node); - if (this->event_handler != NULL) - this->event_handler->onDirty(*categories); - delete categories; - } - } - } - else if (ProtocolTreeNode::tagEquals(node, "message")) { - parseMessageInitialTagAlreadyChecked(node); - } + if (ProtocolTreeNode::tagEquals(node, "iq")) + parseIq(node); + else if (ProtocolTreeNode::tagEquals(node, "presence")) + parsePresense(node); + else if (ProtocolTreeNode::tagEquals(node, "message")) + parseMessage(node); + else if (ProtocolTreeNode::tagEquals(node, "ack")) + parseAck(node); + else if (ProtocolTreeNode::tagEquals(node, "chatstates")) + parseChatStates(node); delete node; return true; } -void WAConnection::sendPing() throw(WAException) -{ - std::string id = makeId("ping_"); - this->pending_server_requests[id] = new IqResultPingHandler(this); - - ProtocolTreeNode* pingNode = new ProtocolTreeNode("ping") << XATTR("xmlns", "w:p"); - this->out->write(ProtocolTreeNode("iq", pingNode) << XATTR("id", id) << XATTR("type", "get")); -} - -void WAConnection::sendPong(const std::string& id) throw(WAException) -{ - this->out->write(ProtocolTreeNode("iq") - << XATTR("type", "result") << XATTR("to", this->domain) << XATTR("id", id)); -} - -void WAConnection::sendComposing(const std::string& to) throw(WAException) -{ - ProtocolTreeNode* composingNode = new ProtocolTreeNode("composing") - << XATTR("xmlns", "http://jabber.org/protocol/chatstates"); - - this->out->write(ProtocolTreeNode("message", composingNode) - << XATTR("to", to) << XATTR("type", "chat")); -} - -void WAConnection::sendActive() throw(WAException) -{ - this->out->write(ProtocolTreeNode("presence") << XATTR("type", "active")); -} - -void WAConnection::sendInactive() throw(WAException) -{ - this->out->write(ProtocolTreeNode("presence") << XATTR("type", "inactive")); -} - -void WAConnection::sendPaused(const std::string& to) throw(WAException) -{ - ProtocolTreeNode* pausedNode = new ProtocolTreeNode("paused"); - *pausedNode << XATTR("xmlns", "http://jabber.org/protocol/chatstates"); - - this->out->write(ProtocolTreeNode("message", pausedNode) << XATTR("to", to) << XATTR("type", "chat")); -} - -void WAConnection::sendSubjectReceived(const std::string& to, const std::string& id)throw(WAException) -{ - ProtocolTreeNode* receivedNode = new ProtocolTreeNode("received") << XATTR("xmlns", "urn:xmpp:receipts"); - - this->out->write(ProtocolTreeNode("message", receivedNode) - << XATTR("to", to) << XATTR("type", "subject") << XATTR("id", id)); -} - -void WAConnection::sendMessageReceived(FMessage* message) throw(WAException) -{ - ProtocolTreeNode* receivedNode = new ProtocolTreeNode("received") - << XATTR("xmlns", "urn:xmpp:receipts"); - - this->out->write(ProtocolTreeNode("message", receivedNode) - << XATTR("to", message->key->remote_jid) << XATTR("type", "chat") << XATTR("id", message->key->id)); -} - -void WAConnection::sendDeliveredReceiptAck(const std::string& to, const std::string& id) throw(WAException) -{ - ProtocolTreeNode *n = getReceiptAck(to, id, "delivered"); - this->out->write(*n); - delete n; -} - -void WAConnection::sendVisibleReceiptAck(const std::string& to, const std::string& id) throw (WAException) -{ - ProtocolTreeNode *n = getReceiptAck(to, id, "visible"); - this->out->write(*n); - delete n; -} - -void WAConnection::sendPresenceSubscriptionRequest(const std::string& to) throw(WAException) -{ - this->out->write(ProtocolTreeNode("presence") << XATTR("type", "subscribe") << XATTR("to", to)); -} - -void WAConnection::sendClientConfig(const std::string& sound, const std::string& pushID, bool preview, const std::string& platform) throw(WAException) -{ - ProtocolTreeNode* configNode = new ProtocolTreeNode("config") - << XATTR("xmlns", "urn:xmpp:whatsapp:push") << XATTR("sound", sound) << XATTR("id", pushID) << XATTR("preview", preview ? "1" : "0") << XATTR("platform", platform); - - std::string id = makeId("config_"); - this->pending_server_requests[id] = new IqSendClientConfigHandler(this); - - this->out->write(ProtocolTreeNode("iq", configNode) - << XATTR("id", id) << XATTR("type", "set") << XATTR("to", this->domain)); -} - -void WAConnection::sendClientConfig(const std::string& pushID, bool preview, const std::string& platform, bool defaultSettings, bool groupSettings, const std::vector& groups) throw(WAException) +void WAConnection::readGroupList(ProtocolTreeNode *node, std::vector& groups) throw (WAException) { - ProtocolTreeNode* configNode = new ProtocolTreeNode("config", NULL, this->processGroupSettings(groups)) - << XATTR("xmlns", "urn:xmpp:whatsapp:push") << XATTR("id", pushID) << XATTR("lg", "en") << XATTR("lc", "US") << XATTR("clear", "0") - << XATTR("preview", preview ? "1" : "0") << XATTR("platform", platform) - << XATTR("default", defaultSettings ? "1" : "0") << XATTR("groups", groupSettings ? "1" : "0"); - - std::string id = makeId("config_"); - this->out->write(ProtocolTreeNode("iq", configNode) << XATTR("id", id) << XATTR("type", "set") << XATTR("to", this->domain)); + std::vector nodes(node->getAllChildren("group")); + for (size_t i = 0; i < nodes.size(); i++) { + ProtocolTreeNode *groupNode = nodes[i]; + const string &gid = groupNode->getAttributeValue("id"); + string gjid = gidToGjid(gid); + const string &owner = groupNode->getAttributeValue("owner"); + const string &subject = groupNode->getAttributeValue("subject"); + const string &subject_t = groupNode->getAttributeValue("s_t"); + const string &subject_owner = groupNode->getAttributeValue("s_o"); + const string &creation = groupNode->getAttributeValue("creation"); + if (this->group_event_handler != NULL) + this->group_event_handler->onGroupInfoFromList(gjid, owner, subject, subject_owner, atoi(subject_t.c_str()), atoi(creation.c_str())); + groups.push_back(gjid); + } } -std::vector* WAConnection::processGroupSettings(const std::vector& groups) +std::map WAConnection::parseCategories(ProtocolTreeNode *dirtyNode) throw (WAException) { - std::vector* result = new std::vector(groups.size()); - if (!groups.empty()) { - time_t now = time(NULL); - for (size_t i = 0; i < groups.size(); i++) { - (*result)[i] = new ProtocolTreeNode("item") - << XATTR("jid", groups[i].jid) << XATTR("notify", (groups[i].enabled ? "1" : "0")) - << XATTRI("mute", (groups[i].muteExpiry > now) ? groups[i].muteExpiry - now : 0); + std::map categories; + if (dirtyNode->children != NULL) { + for (size_t i = 0; i < dirtyNode->children->size(); i++) { + ProtocolTreeNode *childNode = (*dirtyNode->children)[i]; + if (ProtocolTreeNode::tagEquals(childNode, "category")) { + const string &categoryName = childNode->getAttributeValue("name"); + const string ×tamp = childNode->getAttributeValue("timestamp"); + categories[categoryName] = timestamp; + } } } - return result; + return categories; } -std::string WAConnection::makeId(const std::string& prefix) +void WAConnection::parseAck(ProtocolTreeNode *node) throw(WAException) { - this->iqid++; - std::string id; - if (this->verbose) - id = prefix + Utilities::intToStr(this->iqid); - else - id = Utilities::itoa(this->iqid, 16); + const string &from = node->getAttributeValue("from"); + const string &cls = node->getAttributeValue("class"); + const string &id = node->getAttributeValue("id"); + const string &ts = node->getAttributeValue("t"); - return id; + if (this->event_handler != NULL) { + FMessage msg(new Key(from, true, id)); + msg.status = FMessage::STATUS_RECEIVED_BY_SERVER; + this->event_handler->onMessageStatusUpdate(&msg); + } } -ProtocolTreeNode* WAConnection::getReceiptAck(const std::string& to, const std::string& id, const std::string& receiptType) throw(WAException) +void WAConnection::parseChatStates(ProtocolTreeNode *node) throw (WAException) { - ProtocolTreeNode* ackNode = new ProtocolTreeNode("ack") - << XATTR("xmlns", "urn:xmpp:receipts") << XATTR("type", receiptType); - - return new ProtocolTreeNode("message", ackNode) << XATTR("to", to) << XATTR("type", "chat") << XATTR("id", id); -} + const string &from = node->getAttributeValue("from"); -std::map* WAConnection::parseCategories(ProtocolTreeNode* dirtyNode) throw (WAException) -{ - std::map* categories = new std::map(); - if (dirtyNode->children != NULL) { - for (size_t i = 0; i < dirtyNode->children->size(); i++) { - ProtocolTreeNode* childNode = (*dirtyNode->children)[i]; - if (ProtocolTreeNode::tagEquals(childNode, "category")) { - const string &categoryName = childNode->getAttributeValue("name"); - const string ×tamp = childNode->getAttributeValue("timestamp"); - (*categories)[categoryName] = timestamp; - } + std::vector messageChildren(node->getAllChildren()); + for (size_t i = 0; i < messageChildren.size(); i++) { + ProtocolTreeNode *childNode = messageChildren[i]; + if (ProtocolTreeNode::tagEquals(childNode, "composing")) { + if (this->event_handler != NULL) + this->event_handler->onIsTyping(from, true); + } + else if (ProtocolTreeNode::tagEquals(childNode, "paused")) { + if (this->event_handler != NULL) + this->event_handler->onIsTyping(from, false); } } - - return categories; } -void WAConnection::parseMessageInitialTagAlreadyChecked(ProtocolTreeNode* messageNode) throw (WAException) +void WAConnection::parseMessage(ProtocolTreeNode *messageNode) throw (WAException) { const string &id = messageNode->getAttributeValue("id"); const string &attribute_t = messageNode->getAttributeValue("t"); @@ -546,7 +339,7 @@ void WAConnection::parseMessageInitialTagAlreadyChecked(ProtocolTreeNode* messag receiptRequested = true; } - ProtocolTreeNode* bodyNode = messageNode->getChild("body"); + ProtocolTreeNode *bodyNode = messageNode->getChild("body"); if (bodyNode != NULL&& this->group_event_handler != NULL) this->group_event_handler->onGroupNewSubject(from, author, bodyNode->getDataAsString(), atoi(attribute_t.c_str())); @@ -560,16 +353,8 @@ void WAConnection::parseMessageInitialTagAlreadyChecked(ProtocolTreeNode* messag std::vector messageChildren(messageNode->getAllChildren()); for (size_t i = 0; i < messageChildren.size(); i++) { - ProtocolTreeNode* childNode = messageChildren[i]; - if (ProtocolTreeNode::tagEquals(childNode, "composing")) { - if (this->event_handler != NULL) - this->event_handler->onIsTyping(from, true); - } - else if (ProtocolTreeNode::tagEquals(childNode, "paused")) { - if (this->event_handler != NULL) - this->event_handler->onIsTyping(from, false); - } - else if (ProtocolTreeNode::tagEquals(childNode, "body")) { + ProtocolTreeNode *childNode = messageChildren[i]; + if (ProtocolTreeNode::tagEquals(childNode, "body")) { Key* key = new Key(from, false, id); fmessage->key = key; fmessage->remote_resource = author; @@ -596,7 +381,7 @@ void WAConnection::parseMessageInitialTagAlreadyChecked(ProtocolTreeNode* messag } if (fmessage->media_wa_type == FMessage::WA_TYPE_CONTACT) { - ProtocolTreeNode* contactChildNode = childNode->getChild(0); + ProtocolTreeNode *contactChildNode = childNode->getChild(0); if (contactChildNode != NULL) { fmessage->media_name = contactChildNode->getAttributeValue("name"); fmessage->data = contactChildNode->getDataAsString(); @@ -616,45 +401,6 @@ void WAConnection::parseMessageInitialTagAlreadyChecked(ProtocolTreeNode* messag fmessage->key = key; fmessage->remote_resource = author; } - else if (!ProtocolTreeNode::tagEquals(childNode, "active")) { - if (ProtocolTreeNode::tagEquals(childNode, "request")) { - fmessage->wants_receipt = true; - } - else if (ProtocolTreeNode::tagEquals(childNode, "notify")) { - fmessage->notifyname = childNode->getAttributeValue("name"); - } - else if (ProtocolTreeNode::tagEquals(childNode, "x")) { - const string &xmlns = childNode->getAttributeValue("xmlns"); - if (xmlns == "jabber:x:event" && !id.empty()) { - Key* key = new Key(from, true, id); - FMessage* message = new FMessage(key); - message->status = FMessage::STATUS_RECEIVED_BY_SERVER; - if (this->event_handler != NULL) - this->event_handler->onMessageStatusUpdate(message); - delete message; - } - } - else if (ProtocolTreeNode::tagEquals(childNode, "received")) { - Key* key = new Key(from, true, id); - FMessage* message = new FMessage(key); - message->status = FMessage::STATUS_RECEIVED_BY_TARGET; - if (this->event_handler != NULL) - this->event_handler->onMessageStatusUpdate(message); - delete message; - if (this->supportsReceiptAcks()) { - const string &receipt_type = childNode->getAttributeValue("type"); - if (receipt_type == "delivered") - sendDeliveredReceiptAck(from, id); - else if (receipt_type == "visible") - sendVisibleReceiptAck(from, id); - } - } - else if (ProtocolTreeNode::tagEquals(childNode, "offline")) { - if (!attribute_t.empty()) - fmessage->timestamp = atoi(attribute_t.c_str()); - fmessage->offline = true; - } - } } if (fmessage->timestamp == 0) { @@ -672,13 +418,13 @@ void WAConnection::parseMessageInitialTagAlreadyChecked(ProtocolTreeNode* messag bool flag = false; std::vector children(messageNode->getAllChildren()); for (size_t i = 0; i < children.size(); i++) { - ProtocolTreeNode* child = children[i]; + ProtocolTreeNode *child = children[i]; if (ProtocolTreeNode::tagEquals(child, "notification")) { const string &type = child->getAttributeValue("type"); if (type == "picture" && this->event_handler != NULL) { std::vector children2(child->getAllChildren()); for (unsigned j = 0; j < children2.size(); j++) { - ProtocolTreeNode* child2 = children2[j]; + ProtocolTreeNode *child2 = children2[j]; if (ProtocolTreeNode::tagEquals(child2, "set")) { const string &id = child2->getAttributeValue("id"); const string &author = child2->getAttributeValue("author"); @@ -700,17 +446,174 @@ void WAConnection::parseMessageInitialTagAlreadyChecked(ProtocolTreeNode* messag } } -bool WAConnection::supportsReceiptAcks() +void WAConnection::parseIq(ProtocolTreeNode *node) throw(WAException) { - return supports_receipt_acks; -} + const string &type = node->getAttributeValue("type"); + if (type.empty()) + throw WAException("missing 'type' attribute in iq stanza", WAException::CORRUPT_STREAM_EX, 0); -void WAConnection::sendNotificationReceived(const std::string& jid, const std::string& id) throw(WAException) + 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 (this->event_handler != NULL) + this->event_handler->onAccountChange(this->account_kind, this->expire_date); + } + } + 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 (this->event_handler != NULL) + this->event_handler->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() && this->event_handler != NULL) { + int timeoutSeconds = atoi(childNode->getAttributeValue("timeout").c_str()); + this->event_handler->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::parsePresense(ProtocolTreeNode *node) throw(WAException) { - ProtocolTreeNode* child = new ProtocolTreeNode("received") << XATTR("xmlns", "urn:xmpp:receipts"); + const string &xmlns = node->getAttributeValue("xmlns"); + const string &from = node->getAttributeValue("from"); + if (from.empty()) + return; - this->out->write(ProtocolTreeNode("message", child) - << XATTR("id", id) << XATTR("type", "notification") << XATTR("to", jid)); + 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 (this->group_event_handler != NULL) + this->group_event_handler->onGroupAddUser(from, add); + } + else if (!remove.empty()) { + if (this->group_event_handler != NULL) + this->group_event_handler->onGroupRemoveUser(from, remove); + } + else if (status == "dirty") { + std::map categories = parseCategories(node); + if (this->event_handler != NULL) + this->event_handler->onDirty(categories); + } + return; + } + + const string &type = node->getAttributeValue("type"); + if (type == "unavailable") { + if (this->event_handler != NULL) + this->event_handler->onAvailable(from, false); + } + else if (type == "available" || type == "") { + if (this->event_handler != NULL) + this->event_handler->onAvailable(from, true); + } +} + +std::vector* WAConnection::processGroupSettings(const std::vector& groups) +{ + std::vector* result = new std::vector(groups.size()); + if (!groups.empty()) { + time_t now = time(NULL); + for (size_t i = 0; i < groups.size(); i++) { + (*result)[i] = new ProtocolTreeNode("item") + << XATTR("jid", groups[i].jid) << XATTR("notify", (groups[i].enabled ? "1" : "0")) + << XATTRI("mute", (groups[i].muteExpiry > now) ? groups[i].muteExpiry - now : 0); + } + } + + return result; +} + +///////////////////////////////////////////////////////////////////////////////////////// +// Send* functions + +void WAConnection::sendActive() throw(WAException) +{ + this->out->write(ProtocolTreeNode("presence") << XATTR("type", "active")); +} + +void WAConnection::sendAvailableForChat() throw(WAException) +{ + this->out->write(ProtocolTreeNode("presence") << XATTR("name", this->nick)); +} + +void WAConnection::sendClientConfig(const std::string& sound, const std::string& pushID, bool preview, const std::string& platform) throw(WAException) +{ + ProtocolTreeNode *configNode = new ProtocolTreeNode("config") + << XATTR("xmlns", "urn:xmpp:whatsapp:push") << XATTR("sound", sound) << XATTR("id", pushID) << XATTR("preview", preview ? "1" : "0") << XATTR("platform", platform); + + std::string id = makeId("config_"); + this->pending_server_requests[id] = new IqSendClientConfigHandler(this); + + this->out->write(ProtocolTreeNode("iq", configNode) + << XATTR("id", id) << XATTR("type", "set") << XATTR("to", this->domain)); +} + +void WAConnection::sendClientConfig(const std::string& pushID, bool preview, const std::string& platform, bool defaultSettings, bool groupSettings, const std::vector& groups) throw(WAException) +{ + ProtocolTreeNode *configNode = new ProtocolTreeNode("config", NULL, this->processGroupSettings(groups)) + << XATTR("xmlns", "urn:xmpp:whatsapp:push") << XATTR("id", pushID) << XATTR("lg", "en") << XATTR("lc", "US") << XATTR("clear", "0") + << XATTR("preview", preview ? "1" : "0") << XATTR("platform", platform) + << XATTR("default", defaultSettings ? "1" : "0") << XATTR("groups", groupSettings ? "1" : "0"); + + std::string id = makeId("config_"); + this->out->write(ProtocolTreeNode("iq", configNode) << XATTR("id", id) << XATTR("type", "set") << XATTR("to", this->domain)); } void WAConnection::sendClose() throw(WAException) @@ -719,26 +622,19 @@ void WAConnection::sendClose() throw(WAException) this->out->streamEnd(); } -void WAConnection::sendGetPrivacyList() throw (WAException) +void WAConnection::sendComposing(const std::string& to) throw(WAException) { - std::string id = makeId("privacylist_"); - this->pending_server_requests[id] = new IqResultPrivayListHandler(this); - - ProtocolTreeNode* listNode = new ProtocolTreeNode("list") << XATTR("name", "default"); - ProtocolTreeNode* queryNode = new ProtocolTreeNode("query", listNode) << XATTR("xmlns", "jabber:iq:privacy"); - this->out->write(ProtocolTreeNode("iq", queryNode) << XATTR("id", id) << XATTR("type", "get")); + this->out->write(ProtocolTreeNode("chatstate", new ProtocolTreeNode("composing")) << XATTR("to", to)); } -void WAConnection::sendGetServerProperties() throw (WAException) +void WAConnection::sendDeleteAccount() 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"); + std::string id = makeId("del_acct_"); + this->pending_server_requests[id] = new IqResultSendDeleteAccount(this); - this->out->write(ProtocolTreeNode("iq", listNode) - << XATTR("id", id) << XATTR("type", "get") << XATTR("to", "g.us")); + ProtocolTreeNode *node1 = new ProtocolTreeNode("remove") << XATTR("xmlns", "urn:xmpp:whatsapp:account"); + this->out->write(ProtocolTreeNode("iq", node1) + << XATTR("id", id) << XATTR("type", "get") << XATTR("to", "s.whatsapp.net")); } void WAConnection::sendGetGroups() throw (WAException) @@ -751,6 +647,15 @@ void WAConnection::sendGetGroups() throw (WAException) this->mutex->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); + + this->out->write(ProtocolTreeNode("iq", listNode) + << XATTR("id", id) << XATTR("type", "get") << XATTR("to", "g.us")); +} + void WAConnection::sendGetOwningGroups() throw (WAException) { this->mutex->lock(); @@ -761,36 +666,149 @@ void WAConnection::sendGetOwningGroups() throw (WAException) this->mutex->unlock(); } -void WAConnection::sendGetGroups(const std::string& id, const std::string& type) throw (WAException) +void WAConnection::sendGetPicture(const std::string& jid, const std::string& type, const std::string& oldId, const std::string& newId) throw (WAException) { - ProtocolTreeNode* listNode = new ProtocolTreeNode("list") - << XATTR("xmlns", "w:g") << XATTR("type", type); + std::string id = makeId("get_picture_"); + this->pending_server_requests[id] = new IqResultGetPhotoHandler(this, jid, oldId, newId); + + ProtocolTreeNode *listNode = new ProtocolTreeNode("picture") + << XATTR("xmlns", "w:profile:picture") << XATTR("type", type); + + this->out->write(ProtocolTreeNode("iq", listNode) + << XATTR("id", id) << XATTR("to", jid) << XATTR("type", "get")); +} + +void WAConnection::sendGetPictureIds(const std::vector& jids) throw (WAException) +{ + std::string id = makeId("get_picture_ids_"); + this->pending_server_requests[id] = new IqResultGetPictureIdsHandler(this); + + std::vector* children = new std::vector(); + for (size_t i = 0; i < jids.size(); i++) { + ProtocolTreeNode *child = new ProtocolTreeNode("user") << XATTR("jid", jids[i]); + children->push_back(child); + } + + ProtocolTreeNode *queryNode = new ProtocolTreeNode("list", NULL, children) << XATTR("xmlns", "w:profile:picture"); + this->out->write(ProtocolTreeNode("iq", queryNode) << XATTR("id", id) << XATTR("type", "get")); +} + +void WAConnection::sendGetPrivacyList() throw (WAException) +{ + std::string id = makeId("privacylist_"); + this->pending_server_requests[id] = new IqResultPrivayListHandler(this); + + ProtocolTreeNode *listNode = new ProtocolTreeNode("list") << XATTR("name", "default"); + ProtocolTreeNode *queryNode = new ProtocolTreeNode("query", listNode) << XATTR("xmlns", "jabber:iq:privacy"); + this->out->write(ProtocolTreeNode("iq", queryNode) << XATTR("id", id) << XATTR("type", "get")); +} + +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"); this->out->write(ProtocolTreeNode("iq", listNode) << XATTR("id", id) << XATTR("type", "get") << XATTR("to", "g.us")); } -void WAConnection::readGroupList(ProtocolTreeNode* node, std::vector& groups) throw (WAException) +void WAConnection::sendInactive() throw(WAException) { - std::vector nodes(node->getAllChildren("group")); - for (size_t i = 0; i < nodes.size(); i++) { - ProtocolTreeNode* groupNode = nodes[i]; - const string &gid = groupNode->getAttributeValue("id"); - string gjid = gidToGjid(gid); - const string &owner = groupNode->getAttributeValue("owner"); - const string &subject = groupNode->getAttributeValue("subject"); - const string &subject_t = groupNode->getAttributeValue("s_t"); - const string &subject_owner = groupNode->getAttributeValue("s_o"); - const string &creation = groupNode->getAttributeValue("creation"); - if (this->group_event_handler != NULL) - this->group_event_handler->onGroupInfoFromList(gjid, owner, subject, subject_owner, atoi(subject_t.c_str()), atoi(creation.c_str())); - groups.push_back(gjid); + this->out->write(ProtocolTreeNode("presence") << XATTR("type", "inactive")); +} + +void WAConnection::sendMessage(FMessage* message) throw(WAException) +{ + if (message->media_wa_type != 0) + sendMessageWithMedia(message); + else + sendMessageWithBody(message); +} + +void WAConnection::sendMessageWithMedia(FMessage* message) throw (WAException) +{ + logData("Send message with media %s %d", message->media_name.c_str(), message->media_size); + logData("media-url:%s", message->media_url.c_str()); + if (message->media_wa_type == FMessage::WA_TYPE_SYSTEM) + throw new WAException("Cannot send system message over the network"); + + ProtocolTreeNode *mediaNode; + if (message->media_wa_type == FMessage::WA_TYPE_CONTACT && !message->media_name.empty()) { + ProtocolTreeNode *vcardNode = new ProtocolTreeNode("vcard", new std::vector(message->data.begin(), message->data.end())) + << XATTR("name", message->media_name); + mediaNode = new ProtocolTreeNode("media", vcardNode); + } + else { + mediaNode = new ProtocolTreeNode("media", new std::vector(message->data.begin(), message->data.end()), NULL) + << XATTR("encoding", "text"); } + + mediaNode << XATTR("xmlns", "urn:xmpp:whatsapp:mms") << XATTR("type", FMessage::getMessage_WA_Type_StrValue(message->media_wa_type)); + + if (message->media_wa_type == FMessage::WA_TYPE_LOCATION) + mediaNode << XATTR("latitude", Utilities::doubleToStr(message->latitude)) << XATTR("longitude", Utilities::doubleToStr(message->longitude)); + else { + mediaNode << XATTR("file", message->media_name) << XATTRI("size", message->media_size) << XATTR("url", message->media_url); + if (message->media_wa_type == FMessage::WA_TYPE_CONTACT || message->media_name.empty() || message->media_url.empty() || message->media_size <= 0) + mediaNode << XATTRI("seconds", message->media_duration_seconds); + } + + ProtocolTreeNode *n = WAConnection::getMessageNode(message, mediaNode); + this->out->write(*n); + delete n; } -std::string WAConnection::gidToGjid(const std::string& gid) +void WAConnection::sendMessageWithBody(FMessage* message) throw (WAException) { - return gid + "@g.us"; + ProtocolTreeNode *bodyNode = new ProtocolTreeNode("body", new std::vector(message->data.begin(), message->data.end())); + ProtocolTreeNode *n = WAConnection::getMessageNode(message, bodyNode); + this->out->write(*n); + delete n; +} + +void WAConnection::sendMessageReceived(FMessage* message) throw(WAException) +{ + ProtocolTreeNode *receivedNode = new ProtocolTreeNode("received") + << XATTR("xmlns", "urn:xmpp:receipts"); + + this->out->write(ProtocolTreeNode("message", receivedNode) + << XATTR("to", message->key->remote_jid) << XATTR("type", "chat") << XATTR("id", message->key->id)); +} + +void WAConnection::sendNotificationReceived(const std::string& jid, const std::string& id) throw(WAException) +{ + ProtocolTreeNode *child = new ProtocolTreeNode("received") << XATTR("xmlns", "urn:xmpp:receipts"); + + this->out->write(ProtocolTreeNode("message", child) + << XATTR("id", id) << XATTR("type", "notification") << XATTR("to", jid)); +} + +void WAConnection::sendPaused(const std::string& to) throw(WAException) +{ + this->out->write(ProtocolTreeNode("chatstate", new ProtocolTreeNode("paused")) << XATTR("to", to)); +} + +void WAConnection::sendPing() throw(WAException) +{ + std::string id = makeId("ping_"); + this->pending_server_requests[id] = new IqResultPingHandler(this); + + ProtocolTreeNode *pingNode = new ProtocolTreeNode("ping") << XATTR("xmlns", "w:p"); + this->out->write(ProtocolTreeNode("iq", pingNode) << XATTR("id", id) << XATTR("type", "get")); +} + +void WAConnection::sendPong(const std::string& id) throw(WAException) +{ + this->out->write(ProtocolTreeNode("iq") + << XATTR("type", "result") << XATTR("to", this->domain) << XATTR("id", id)); +} + +void WAConnection::sendPresenceSubscriptionRequest(const std::string& to) throw(WAException) +{ + this->out->write(ProtocolTreeNode("presence") << XATTR("type", "subscribe") << XATTR("to", to)); } void WAConnection::sendQueryLastOnline(const std::string& jid) throw (WAException) @@ -798,17 +816,49 @@ void WAConnection::sendQueryLastOnline(const std::string& jid) throw (WAExceptio std::string id = makeId("last_"); this->pending_server_requests[id] = new IqResultQueryLastOnlineHandler(this); - ProtocolTreeNode* queryNode = new ProtocolTreeNode("query") << XATTR("xmlns", "jabber:iq:last"); + ProtocolTreeNode *queryNode = new ProtocolTreeNode("query") << XATTR("xmlns", "jabber:iq:last"); this->out->write(ProtocolTreeNode("iq", queryNode) << XATTR("id", id) << XATTR("type", "get") << XATTR("to", jid)); } +void WAConnection::sendSetPicture(const std::string& jid, std::vector* data) throw (WAException) +{ + std::string id = this->makeId("set_photo_"); + this->pending_server_requests[id] = new IqResultSetPhotoHandler(this, jid); + + ProtocolTreeNode *listNode = new ProtocolTreeNode("picture", data, NULL) << XATTR("xmlns", "w:profile:picture"); + this->out->write(ProtocolTreeNode("iq", listNode) + << XATTR("id", id) << XATTR("type", "set") << XATTR("to", jid)); +} + +void WAConnection::sendStatusUpdate(std::string& status) throw (WAException) +{ + std::string id = this->makeId(Utilities::intToStr((int)time(NULL))); + FMessage *message = new FMessage(new Key("s.us", true, id)); + ProtocolTreeNode *body = new ProtocolTreeNode("body", new std::vector(status.begin(), status.end()), NULL); + ProtocolTreeNode *n = getMessageNode(message, body); + this->out->write(*n); + delete n; + delete message; +} + +void WAConnection::sendSubjectReceived(const std::string& to, const std::string& id)throw(WAException) +{ + ProtocolTreeNode *receivedNode = new ProtocolTreeNode("received") << XATTR("xmlns", "urn:xmpp:receipts"); + + this->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_"); this->pending_server_requests[id] = new IqResultGetGroupInfoHandler(this); - ProtocolTreeNode* queryNode = new ProtocolTreeNode("query") << XATTR("xmlns", "w:g"); + ProtocolTreeNode *queryNode = new ProtocolTreeNode("query") << XATTR("xmlns", "w:g"); this->out->write(ProtocolTreeNode("iq", queryNode) << XATTR("id", id) << XATTR("type", "get") << XATTR("to", gjid)); } @@ -818,16 +868,16 @@ void WAConnection::sendGetParticipants(const std::string& gjid) throw (WAExcepti std::string id = makeId("get_participants_"); this->pending_server_requests[id] = new IqResultGetGroupParticipantsHandler(this); - ProtocolTreeNode* listNode = new ProtocolTreeNode("list") << XATTR("xmlns", "w:g"); + ProtocolTreeNode *listNode = new ProtocolTreeNode("list") << XATTR("xmlns", "w:g"); this->out->write(ProtocolTreeNode("iq", listNode) << XATTR("id", id) << XATTR("type", "get") << XATTR("to", gjid)); } -void WAConnection::readAttributeList(ProtocolTreeNode* node, std::vector& vector, const std::string& tag, const std::string& attribute) throw (WAException) +void WAConnection::readAttributeList(ProtocolTreeNode *node, std::vector& vector, const std::string& tag, const std::string& attribute) throw (WAException) { std::vector nodes(node->getAllChildren(tag)); for (size_t i = 0; i < nodes.size(); i++) { - ProtocolTreeNode* tagNode = nodes[i]; + ProtocolTreeNode *tagNode = nodes[i]; vector.push_back(tagNode->getAttributeValue(attribute)); } } @@ -838,7 +888,7 @@ void WAConnection::sendCreateGroupChat(const std::string& subject) throw (WAExce std::string id = makeId("create_group_"); this->pending_server_requests[id] = new IqResultCreateGroupChatHandler(this); - ProtocolTreeNode* groupNode = new ProtocolTreeNode("group") + ProtocolTreeNode *groupNode = new ProtocolTreeNode("group") << XATTR("xmlns", "w:g") << XATTR("action", "create") << XATTR("subject", subject); this->out->write(ProtocolTreeNode("iq", groupNode) @@ -849,7 +899,7 @@ 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"); + ProtocolTreeNode *groupNode = new ProtocolTreeNode("group") << XATTR("xmlns", "w:g") << XATTR("action", "delete"); this->out->write(ProtocolTreeNode("iq", groupNode) << XATTR("id", id) << XATTR("type", "set") << XATTR("to", gjid)); } @@ -859,8 +909,8 @@ void WAConnection::sendClearDirty(const std::string& category) throw (WAExceptio std::string id = makeId("clean_dirty_"); this->pending_server_requests[id] = new IqResultClearDirtyHandler(this); - ProtocolTreeNode* categoryNode = new ProtocolTreeNode("category") << XATTR("name", category); - ProtocolTreeNode* cleanNode = new ProtocolTreeNode("clean", categoryNode) << XATTR("xmlns", "urn:xmpp:whatsapp:dirty"); + ProtocolTreeNode *categoryNode = new ProtocolTreeNode("category") << XATTR("name", category); + ProtocolTreeNode *cleanNode = new ProtocolTreeNode("clean", categoryNode) << XATTR("xmlns", "urn:xmpp:whatsapp:dirty"); this->out->write(ProtocolTreeNode("iq", cleanNode) << XATTR("id", id) << XATTR("type", "set") << XATTR("to", "s.whatsapp.net")); } @@ -869,8 +919,8 @@ void WAConnection::sendLeaveGroup(const std::string& gjid) throw (WAException) { std::string id = makeId("leave_group_"); - ProtocolTreeNode* groupNode = new ProtocolTreeNode("group") << XATTR("id", gjid); - ProtocolTreeNode* leaveNode = new ProtocolTreeNode("leave", groupNode) << XATTR("xmlns", "w:g"); + ProtocolTreeNode *groupNode = new ProtocolTreeNode("group") << XATTR("id", gjid); + ProtocolTreeNode *leaveNode = new ProtocolTreeNode("leave", groupNode) << XATTR("xmlns", "w:g"); this->out->write(ProtocolTreeNode("iq", leaveNode) << XATTR("id", id) << XATTR("type", "set") << XATTR("to", "g.us")); } @@ -894,7 +944,7 @@ void WAConnection::sendVerbParticipants(const std::string& gjid, const std::vect 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) + ProtocolTreeNode *innerNode = new ProtocolTreeNode(inner_tag, NULL, children) << XATTR("xmlns", "w:g"); this->out->write(ProtocolTreeNode("iq", innerNode) @@ -905,76 +955,10 @@ void WAConnection::sendSetNewSubject(const std::string& gjid, const std::string& { std::string id = this->makeId("set_group_subject_"); - ProtocolTreeNode* subjectNode = new ProtocolTreeNode("subject") + ProtocolTreeNode *subjectNode = new ProtocolTreeNode("subject") << XATTR("xmlns", "w:g") << XATTR("value", subject); this->out->write(ProtocolTreeNode("iq", subjectNode) << XATTR("id", id) << XATTR("type", "set") << XATTR("to", gjid)); } -std::string WAConnection::removeResourceFromJid(const std::string& jid) -{ - size_t slashidx = jid.find('/'); - if (slashidx == std::string::npos) - return jid; - - return jid.substr(0, slashidx + 1); -} - -void WAConnection::sendStatusUpdate(std::string& status) throw (WAException) -{ - std::string id = this->makeId(Utilities::intToStr((int)time(NULL))); - FMessage *message = new FMessage(new Key("s.us", true, id)); - ProtocolTreeNode *body = new ProtocolTreeNode("body", new std::vector(status.begin(), status.end()), NULL); - ProtocolTreeNode *n = getMessageNode(message, body); - this->out->write(*n); - delete n; - delete message; -} - -void WAConnection::sendSetPicture(const std::string& jid, std::vector* data) throw (WAException) -{ - std::string id = this->makeId("set_photo_"); - this->pending_server_requests[id] = new IqResultSetPhotoHandler(this, jid); - - ProtocolTreeNode* listNode = new ProtocolTreeNode("picture", data, NULL) << XATTR("xmlns", "w:profile:picture"); - this->out->write(ProtocolTreeNode("iq", listNode) - << XATTR("id", id) << XATTR("type", "set") << XATTR("to", jid)); -} - -void WAConnection::sendGetPicture(const std::string& jid, const std::string& type, const std::string& oldId, const std::string& newId) throw (WAException) -{ - std::string id = makeId("get_picture_"); - this->pending_server_requests[id] = new IqResultGetPhotoHandler(this, jid, oldId, newId); - - ProtocolTreeNode* listNode = new ProtocolTreeNode("picture") - << XATTR("xmlns", "w:profile:picture") << XATTR("type", type); - - this->out->write(ProtocolTreeNode("iq", listNode) - << XATTR("id", id) << XATTR("to", jid) << XATTR("type", "get")); -} - -void WAConnection::sendGetPictureIds(const std::vector& jids) throw (WAException) -{ - std::string id = makeId("get_picture_ids_"); - this->pending_server_requests[id] = new IqResultGetPictureIdsHandler(this); - - std::vector* children = new std::vector(); - for (size_t i = 0; i < jids.size(); i++) { - ProtocolTreeNode* child = new ProtocolTreeNode("user") << XATTR("jid", jids[i]); - children->push_back(child); - } - - ProtocolTreeNode* queryNode = new ProtocolTreeNode("list", NULL, children) << XATTR("xmlns", "w:profile:picture"); - this->out->write(ProtocolTreeNode("iq", queryNode) << XATTR("id", id) << XATTR("type", "get")); -} - -void WAConnection::sendDeleteAccount() throw (WAException) -{ - std::string id = makeId("del_acct_"); - this->pending_server_requests[id] = new IqResultSendDeleteAccount(this); - - ProtocolTreeNode* node1 = new ProtocolTreeNode("remove") << XATTR("xmlns", "urn:xmpp:whatsapp:account"); - this->out->write(ProtocolTreeNode("iq", node1) - << XATTR("id", id) << XATTR("type", "get") << XATTR("to", "s.whatsapp.net")); -} diff --git a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h index 91164a824f..bbdad6c0e6 100644 --- a/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h +++ b/protocols/WhatsApp/src/WhatsAPI++/WAConnection.h @@ -365,10 +365,15 @@ private: std::map pending_server_requests; IMutex *mutex; + void parseAck(ProtocolTreeNode *node) throw (WAException); + void parseChatStates(ProtocolTreeNode *node) throw (WAException); + void parseIq(ProtocolTreeNode *node) throw(WAException); + void parseMessage(ProtocolTreeNode* node) throw(WAException); + void parsePresense(ProtocolTreeNode*) throw(WAException); + std::map parseCategories(ProtocolTreeNode* node) throw(WAException); + void sendMessageWithMedia(FMessage* message) throw(WAException); void sendMessageWithBody(FMessage* message) throw(WAException); - std::map* parseCategories(ProtocolTreeNode* node) throw(WAException); - void parseMessageInitialTagAlreadyChecked(ProtocolTreeNode* node) 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); @@ -391,6 +396,8 @@ public: std::string jid; std::string nick; + KeyStream inputKey, outputKey; + int msg_id; bool retry; bool supports_receipt_acks; @@ -403,16 +410,15 @@ public: void logData(const char *format, ...); - static MessageStore* message_store; - KeyStream inputKey, outputKey; - static std::string removeResourceFromJid(const std::string& jid); - void setLogin(WALogin* login); + void setLogin(WALogin *login); void setVerboseId(bool b); void sendMessage(FMessage* message) throw(WAException); void sendAvailableForChat() throw(WAException); + bool read() throw(WAException); + void sendPing() throw(WAException); void sendQueryLastOnline(const std::string& jid) throw (WAException); void sendPong(const std::string& id) throw(WAException); @@ -422,8 +428,6 @@ public: 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 sendDeliveredReceiptAck(const std::string& to, const std::string& id) throw(WAException); - void sendVisibleReceiptAck(const std::string& to, const std::string& id) 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); diff --git a/protocols/WhatsApp/src/contacts.cpp b/protocols/WhatsApp/src/contacts.cpp index 271c038622..39b7c48849 100644 --- a/protocols/WhatsApp/src/contacts.cpp +++ b/protocols/WhatsApp/src/contacts.cpp @@ -191,12 +191,6 @@ void WhatsAppProto::UpdateStatusMsg(MCONTACT hContact) ss << stzLastSeen; } - int state = getDword(hContact, WHATSAPP_KEY_LAST_MSG_STATE, 2); - if (state < 2 && lastSeen != -1) - ss << _T(" - "); - for (; state < 2; ++state) - ss << _T("\u2713"); - db_set_ws(hContact, "CList", "StatusMsg", ss.str().c_str()); } diff --git a/protocols/WhatsApp/src/db.h b/protocols/WhatsApp/src/db.h index 615d0d8608..228a25bde2 100644 --- a/protocols/WhatsApp/src/db.h +++ b/protocols/WhatsApp/src/db.h @@ -10,9 +10,6 @@ #define WHATSAPP_KEY_NAME "RealName" #define WHATSAPP_KEY_PUSH_NAME "Nick" #define WHATSAPP_KEY_LAST_SEEN "LastSeen" -#define WHATSAPP_KEY_LAST_MSG_ID_HEADER "LastMsgIdHeader" -#define WHATSAPP_KEY_LAST_MSG_ID "LastMsgId" -#define WHATSAPP_KEY_LAST_MSG_STATE "LastMsgState" #define WHATSAPP_KEY_AVATAR_ID "AvatarId" #define WHATSAPP_KEY_SYSTRAY_NOTIFY "UseSystrayNotify" #define WHATSAPP_KEY_DEF_GROUP "DefaultGroup" diff --git a/protocols/WhatsApp/src/messages.cpp b/protocols/WhatsApp/src/messages.cpp index d86f5c017d..9fe33b121c 100644 --- a/protocols/WhatsApp/src/messages.cpp +++ b/protocols/WhatsApp/src/messages.cpp @@ -40,72 +40,39 @@ void WhatsAppProto::onMessageForMe(FMessage* paramFMessage, bool paramBoolean) int WhatsAppProto::SendMsg(MCONTACT hContact, int flags, const char *msg) { - int msgId = ++(this->msgId); + ptrA jid(getStringA(hContact, "ID")); + if (jid == NULL) + return 0; - ForkThread(&WhatsAppProto::SendMsgWorker, new send_direct(hContact, msg, (HANDLE)msgId, flags & IS_CHAT)); - return this->msgIdHeader + msgId; -} - -void WhatsAppProto::SendMsgWorker(void* p) -{ - if (p == NULL) - return; - - DBVARIANT dbv; - send_direct *data = static_cast(p); + if (m_pConnection != NULL) { + debugLogA("No connection"); + return 0; + } - if (getByte(data->hContact, "SimpleChatRoom", 0) > 0 && getByte(data->hContact, "IsGroupMember", 0) == 0) { + if (getByte(hContact, "SimpleChatRoom", 0) > 0 && getByte(hContact, "IsGroupMember", 0) == 0) { debugLogA("not a group member"); - ProtoBroadcastAck(data->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, - (HANDLE)(this->msgIdHeader + this->msgId), (LPARAM) "You cannot send messages to groups if you are not a member."); + return 0; } - else if (!getString(data->hContact, "ID", &dbv) && m_pConnection != NULL) { - try { - setDword(data->hContact, WHATSAPP_KEY_LAST_MSG_STATE, 2); - setDword(data->hContact, WHATSAPP_KEY_LAST_MSG_ID_HEADER, this->msgIdHeader); - setDword(data->hContact, WHATSAPP_KEY_LAST_MSG_ID, this->msgId); - - std::stringstream ss; - ss << this->msgIdHeader << "-" << this->msgId; - Key* key = new Key(Key(dbv.pszVal, true, ss.str())); // deleted by FMessage - FMessage fmsg(key); - fmsg.data = data->msg; - fmsg.timestamp = time(NULL); - - db_free(&dbv); - - m_pConnection->sendMessage(&fmsg); - } - catch (exception &e) { - debugLogA("exception: %s", e.what()); - ProtoBroadcastAck(data->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, - (HANDLE)(this->msgIdHeader + this->msgId), (LPARAM)e.what()); - } - catch (...) { - debugLogA("unknown exception"); - ProtoBroadcastAck(data->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, - (HANDLE)(this->msgIdHeader + this->msgId), (LPARAM) "Failed sending message"); - } + + int msgId = this->m_pConnection->msg_id++; + try { + std::string id = "msg" + Utilities::intToStr(msgId); + FMessage fmsg(new Key((const char*)jid, true, id)); + fmsg.data = msg; + fmsg.timestamp = time(NULL); + + m_pConnection->sendMessage(&fmsg); } - else { - debugLogA("No connection"); - ProtoBroadcastAck(data->hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, - (HANDLE)(this->msgIdHeader + this->msgId), (LPARAM) "You cannot send messages when you are offline."); + catch (exception &e) { + debugLogA("exception: %s", e.what()); + ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)msgId, (LPARAM)e.what()); + } + catch (...) { + debugLogA("unknown exception"); + ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_FAILED, (HANDLE)msgId, (LPARAM)"Failed sending message"); } - delete data; -} - -void WhatsAppProto::RecvMsgWorker(void *p) -{ - if (p == NULL) - return; - - //WAConnection.cpp l1225 - message will be deleted. We cannot send the ack inside a thread! - //FMessage *fmsg = static_cast(p); - //m_pConnection->sendMessageReceived(fmsg); - - //delete fmsg; + return msgId; } void WhatsAppProto::onIsTyping(const std::string& paramString, bool paramBoolean) @@ -153,27 +120,8 @@ void WhatsAppProto::onMessageStatusUpdate(FMessage* fmsg) if (hContact == 0) return; - int state = 5 - fmsg->status; - if (state != 0 && state != 1) - return; - - int header; - int id; - size_t delimPos = fmsg->key->id.find("-"); - - std::stringstream ss; - ss << fmsg->key->id.substr(0, delimPos); - ss >> header; - - ss.clear(); - ss << fmsg->key->id.substr(delimPos + 1); - ss >> id; - - if (state == 1) - ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)(header + id), 0); - - if (getDword(hContact, WHATSAPP_KEY_LAST_MSG_ID_HEADER, 0) == header && getDword(hContact, WHATSAPP_KEY_LAST_MSG_ID, -1) == id) { - setDword(hContact, WHATSAPP_KEY_LAST_MSG_STATE, state); - this->UpdateStatusMsg(hContact); + if (fmsg->status == FMessage::STATUS_RECEIVED_BY_SERVER) { + int msgId = atoi(fmsg->key->id.substr(3).c_str()); + ProtoBroadcastAck(hContact, ACKTYPE_MESSAGE, ACKRESULT_SUCCESS, (HANDLE)msgId, 0); } } diff --git a/protocols/WhatsApp/src/proto.cpp b/protocols/WhatsApp/src/proto.cpp index 10b933b955..bf54fa6e5f 100644 --- a/protocols/WhatsApp/src/proto.cpp +++ b/protocols/WhatsApp/src/proto.cpp @@ -16,9 +16,7 @@ WhatsAppProto::WhatsAppProto(const char* proto_name, const TCHAR* username) : PROTO(proto_name, username) { this->challenge = new std::vector < unsigned char > ; - this->msgId = 0; - this->msgIdHeader = time(NULL); - + update_loop_lock_ = CreateEvent(NULL, false, false, NULL); FMessage::generating_lock = new Mutex(); @@ -211,7 +209,7 @@ HANDLE WhatsAppProto::SearchBasic(const PROTOCHAR* id) return 0; // fake - we always accept search - SearchParam *param = new SearchParam(id, GetSerial()); + SearchParam *param = new SearchParam(id, m_pConnection->msg_id++); ForkThread(&WhatsAppProto::SearchAckThread, param); return (HANDLE)param->id; } diff --git a/protocols/WhatsApp/src/proto.h b/protocols/WhatsApp/src/proto.h index 44dde4958b..7293245831 100644 --- a/protocols/WhatsApp/src/proto.h +++ b/protocols/WhatsApp/src/proto.h @@ -104,7 +104,6 @@ public: // Worker Threads void __cdecl SendMsgWorker(void*); - void __cdecl RecvMsgWorker(void*); void __cdecl SendTypingWorker(void*); void __cdecl SendGetGroupInfoWorker(void*); void __cdecl SendSetGroupNameWorker(void*); @@ -115,6 +114,7 @@ public: 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); @@ -134,12 +134,13 @@ public: bool Register(int state, const string &cc, const string &number, const string &code, string &password); +private: + ////////////////////////////////////////////////////////////////////////////////////// // Helpers std::tstring GetAvatarFolder(); void ToggleStatusMenuItems(BOOL bEnable); - LONG GetSerial(void); ////////////////////////////////////////////////////////////////////////////////////// // Handles, Locks @@ -153,61 +154,55 @@ public: std::tstring def_avatar_folder_; - WASocketConnection* conn; - WAConnection* m_pConnection; + WASocketConnection *conn; + WAConnection *m_pConnection; Mutex connMutex; int lastPongTime; - std::vector* challenge; - int msgId; - int msgIdHeader; + std::vector *challenge; string phoneNumber; - string jid; - string nick; + string jid, nick; std::map hContactByJid; map> isMemberByGroupContact; -private: - LONG m_serial; - ////////////////////////////////////////////////////////////////////////////////////// // WhatsApp Events protected: - virtual void onMessageForMe(FMessage* paramFMessage, bool paramBoolean); - virtual void onMessageStatusUpdate(FMessage* paramFMessage); - virtual void onMessageError(FMessage* message, int paramInt) { ; } - virtual void onPing(const std::string& id) throw (WAException); + virtual void onMessageForMe(FMessage *paramFMessage, bool paramBoolean); + virtual void onMessageStatusUpdate(FMessage *paramFMessage); + virtual void onMessageError(FMessage *message, int paramInt) { ; } + virtual void onPing(const std::string &id) throw (WAException); virtual void onPingResponseReceived() { } - virtual void onAvailable(const std::string& paramString, bool paramBoolean); - virtual void onClientConfigReceived(const std::string& paramString) { } - virtual void onLastSeen(const std::string& paramString1, int paramInt, const std::string& paramString2); - virtual void onIsTyping(const std::string& paramString, bool paramBoolean); + virtual void onAvailable(const std::string ¶mString, bool paramBoolean); + virtual void onClientConfigReceived(const std::string ¶mString) { } + virtual void onLastSeen(const std::string ¶mString1, int paramInt, const std::string ¶mString2); + virtual void onIsTyping(const std::string ¶mString, bool paramBoolean); virtual void onAccountChange(int paramInt, time_t expire_date) { } - virtual void onPrivacyBlockListAdd(const std::string& paramString) { } + virtual void onPrivacyBlockListAdd(const std::string ¶mString) { } virtual void onPrivacyBlockListClear() { } virtual void onDirty(const std::map& paramHashtable) { } virtual void onDirtyResponse(int paramHashtable) { } - virtual void onRelayRequest(const std::string& paramString1, int paramInt, const std::string& paramString2) { } + virtual void onRelayRequest(const std::string ¶mString1, int paramInt, const std::string ¶mString2) { } virtual void onSendGetPictureIds(std::map* ids); - virtual void onSendGetPicture(const std::string& jid, const std::vector& data, const std::string& oldId, const std::string& newId); - virtual void onPictureChanged(const std::string& from, const std::string& author, bool set); + virtual void onSendGetPicture(const std::string &jid, const std::vector& data, const std::string &oldId, const std::string &newId); + virtual void onPictureChanged(const std::string &from, const std::string &author, bool set); virtual void onDeleteAccount(bool result) { } - virtual void onGroupAddUser(const std::string& paramString1, const std::string& paramString2); - virtual void onGroupRemoveUser(const std::string& paramString1, const std::string& paramString2); - virtual void onGroupNewSubject(const std::string& from, const std::string& author, const std::string& newSubject, int paramInt); + 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& paramString1, const std::string& paramString2); - virtual void onGroupInfo(const std::string& paramString1, const std::string& paramString2, const std::string& paramString3, const std::string& paramString4, int paramInt1, int paramInt2); - virtual void onGroupInfoFromList(const std::string& paramString1, const std::string& paramString2, const std::string& paramString3, const std::string& paramString4, int paramInt1, int paramInt2); + 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 onSetSubject(const std::string& paramString) { } - virtual void onAddGroupParticipants(const std::string& paramString, const std::vector& paramVector, int paramHashtable) { } - virtual void onRemoveGroupParticipants(const std::string& paramString, const std::vector& paramVector, int paramHashtable) { } - virtual void onGetParticipants(const std::string& gjid, const std::vector& participants); + 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 onLeaveGroup(const std::string& paramString); + virtual void onLeaveGroup(const std::string ¶mString); ////////////////////////////////////////////////////////////////////////////////////// // Information providing diff --git a/protocols/WhatsApp/src/utils.cpp b/protocols/WhatsApp/src/utils.cpp index 0155ba2206..0aa95f1a16 100644 --- a/protocols/WhatsApp/src/utils.cpp +++ b/protocols/WhatsApp/src/utils.cpp @@ -1,10 +1,5 @@ #include "common.h" -LONG WhatsAppProto::GetSerial(void) -{ - return ::InterlockedIncrement(&m_serial); -} - std::string getLastErrorMsg() { // Retrieve the system error message for the last-error code -- cgit v1.2.3