From ab7e0b08fa8c31cf1d468ab4b3c660e2b1836811 Mon Sep 17 00:00:00 2001 From: Fishbone Date: Sun, 2 Jun 2013 16:19:21 +0000 Subject: Added WhatsApp-protocol git-svn-id: http://svn.miranda-ng.org/main/trunk@4861 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- .../WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp | 267 +++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp (limited to 'protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp') diff --git a/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp new file mode 100644 index 0000000000..dd35f6a8e7 --- /dev/null +++ b/protocols/WhatsApp/src/WhatsAPI++/BinTreeNodeWriter.cpp @@ -0,0 +1,267 @@ +/* + * BinTreeNodeWriter.cpp + * + * Created on: 26/06/2012 + * Author: Antonio + */ +#include "stdafx.h" +#include "BinTreeNodeWriter.h" +#include +#include "utilities.h" + +BinTreeNodeWriter::BinTreeNodeWriter(WAConnection* conn, ISocketConnection* connection, + const char** dictionary, const int dictionarysize, IMutex* mutex) { + this->mutex = mutex; + this->conn = conn; + this->out = new ByteArrayOutputStream(2048); + this->realOut = connection; + for (int i = 0; i < dictionarysize; i++) { + std::string token(dictionary[i]); + if (token.compare("") != 0) + this->tokenMap[token] = i; + } + this->dataBegin = 0; +} + +void BinTreeNodeWriter::writeDummyHeader() +{ + int num = 3; + this->dataBegin = this->out->getPosition(); + int num2 = this->dataBegin + num; + this->out->setLength(num2); + this->out->setPosition(num2); +} + + +void BinTreeNodeWriter::processBuffer() +{ + bool flag = this->conn->outputKey != NULL; + unsigned int num = 0u; + if (flag) + { + long num2 = this->out->getLength() + 4L; + this->out->setLength(num2); + this->out->setPosition(num2); + num |= 1u; + } + long num3 = this->out->getLength() - 3L - (long) this->dataBegin; + if (num3 >= 1048576L) + { + throw WAException("Buffer too large: " + num3, WAException::CORRUPT_STREAM_EX, 0); + } + + std::vector* buffer = this->out->getBuffer(); + if (flag) + { + int num4 = (int)num3 - 4; + this->conn->outputKey->encodeMessage(buffer->data(), this->dataBegin + 3 + num4, this->dataBegin + 3, num4); + } + (*buffer)[this->dataBegin] = (unsigned char)((unsigned long)((unsigned long)num << 4) | (unsigned long)((num3 & 16711680L) >> 16)); + (*buffer)[this->dataBegin + 1] = (unsigned char)((num3 & 65280L) >> 8); + (*buffer)[this->dataBegin + 2] = (unsigned char)(num3 & 255L); +} + +void BinTreeNodeWriter::streamStart(std::string domain, std::string resource) { + this->mutex->lock(); + try { + this->out->setPosition(0); + this->out->setLength(0); + this->out->write(87); + this->out->write(65); + this->out->write(1); + this->out->write(2); + + std::map attributes; + attributes["to"] = domain; + attributes["resource"] = resource; + this->writeDummyHeader(); + this->writeListStart(attributes.size() * 2 + 1); + this->out->write(1); + this->writeAttributes(&attributes); + this->processBuffer(); + this->flushBuffer(true, 0); + } catch (exception& ex) { + this->mutex->unlock(); + throw ex; + } + this->mutex->unlock(); +} + +void BinTreeNodeWriter::writeListStart(int i) { + if (i == 0) { + this->out->write(0); + } else if (i < 256) { + this->out->write(248); + writeInt8(i); + } else { + this->out->write(249); + writeInt16(i); + } +} + +void BinTreeNodeWriter::writeInt8(int v) { + this->out->write(v & 0xFF); +} + +void BinTreeNodeWriter::writeInt16(int v, ISocketConnection* o) { + o->write((v & 0xFF00) >> 8); + o->write((v & 0xFF) >> 0); +} + +void BinTreeNodeWriter::writeInt16(int v) { + writeInt16(v, this->out); +} + +void BinTreeNodeWriter::writeInt16(int v, ByteArrayOutputStream* o) { + o->write((v & 0xFF00) >> 8); + o->write((v & 0xFF) >> 0); +} + +void BinTreeNodeWriter::writeAttributes(std::map* attributes) { + if (attributes != NULL) { + std::map::iterator ii; + for (ii = attributes->begin(); ii != attributes->end(); ii++) { + writeString(ii->first); + writeString(ii->second); + } + } +} + +void BinTreeNodeWriter::writeString(const std::string& tag) { + std::map::iterator it = this->tokenMap.find(tag); + if (it != this->tokenMap.end()) { + writeToken(it->second); + } else { + unsigned int atIndex = tag.find('@'); + if (atIndex == 0 || atIndex == string::npos) { + writeBytes((unsigned char*) tag.data(), tag.length()); + } else { + std::string server = tag.substr(atIndex + 1); + std::string user = tag.substr(0, atIndex); + writeJid(&user, server); + } + } +} + +void BinTreeNodeWriter::writeJid(std::string* user, const std::string& server) { + this->out->write(250); + if (user != NULL && !user->empty()) { + writeString(*user); + } else { + writeToken(0); + } + writeString(server); + +} + +void BinTreeNodeWriter::writeToken(int intValue) { + if (intValue < 245) + this->out->write(intValue); + else if (intValue <= 500) { + this->out->write(254); + this->out->write(intValue - 245); + } +} + +void BinTreeNodeWriter::writeBytes(unsigned char* bytes, int length) { + if (length >= 256) { + this->out->write(253); + writeInt24(length); + } else { + this->out->write(252); + writeInt8(length); + } + this->out->write(bytes, length); +} + +void BinTreeNodeWriter::writeInt24(int v) { + this->out->write((v & 0xFF0000) >> 16); + this->out->write((v & 0xFF00) >> 8); + this->out->write(v & 0xFF); +} + +void BinTreeNodeWriter::writeInternal(ProtocolTreeNode* node) { + writeListStart( + 1 + (node->attributes == NULL ? 0 : node->attributes->size() * 2) + + (node->children == NULL ? 0 : 1) + + (node->data == NULL ? 0 : 1)); + writeString(node->tag); + writeAttributes(node->attributes); + if (node->data != NULL) { + writeBytes((unsigned char*) node->data->data(), node->data->size()); + } + if (node->children != NULL && !node->children->empty()) { + writeListStart(node->children->size()); + for (size_t a = 0; a < node->children->size(); a++) { + writeInternal((*node->children)[a]); + } + } +} + +void BinTreeNodeWriter::flushBuffer(bool flushNetwork) +{ + this->flushBuffer(flushNetwork, this->dataBegin); +} + +void BinTreeNodeWriter::flushBuffer(bool flushNetwork, int startingOffset) { + try { + this->processBuffer(); + } catch (WAException& ex) { + this->out->setPosition(0); + this->out->setLength(0); + throw ex; + } + + // _LOGDATA("buffer size %d, buffer position %d, dataBegin %d", this->out->getLength(), this->out->getPosition(), this->dataBegin); + + std::vector buffer(this->out->getBuffer()->begin(), this->out->getBuffer()->end()); + int num = (int)(this->out->getLength() - (long)startingOffset); + if (flushNetwork && ((long)this->out->getCapacity() - this->out->getLength() < 3L || this->out->getLength() > 4096L)) + { + delete this->out; + this->out = new ByteArrayOutputStream(4096); + } + + if (flushNetwork) + this->realOut->write(buffer, startingOffset, num); +} + +void BinTreeNodeWriter::streamEnd() { + this->mutex->lock(); + try { + writeListStart(1); + this->out->write(2); + flushBuffer(true); + } catch (exception& ex) { + this->mutex->unlock(); + throw ex; + } + this->mutex->unlock(); +} + +void BinTreeNodeWriter::write(ProtocolTreeNode* node) { + write(node, true); +} + +void BinTreeNodeWriter::write(ProtocolTreeNode* node, bool needsFlush) { + this->mutex->lock(); + try { + this->writeDummyHeader(); + if (node == NULL) + this->out->write(0); + else { + writeInternal(node); + } + flushBuffer(needsFlush); + } catch (exception& ex) { + this->mutex->unlock(); + throw WAException(ex.what()); + } + this->mutex->unlock(); +} + +BinTreeNodeWriter::~BinTreeNodeWriter() { + if (this->out != NULL) + delete this->out; +} + -- cgit v1.2.3