diff options
-rw-r--r-- | protocols/WhatsApp/WhatsApp.vcxproj | 1 | ||||
-rw-r--r-- | protocols/WhatsApp/WhatsApp.vcxproj.filters | 3 | ||||
-rw-r--r-- | protocols/WhatsApp/src/appsync.cpp | 2 | ||||
-rw-r--r-- | protocols/WhatsApp/src/generate.cpp | 293 | ||||
-rw-r--r-- | protocols/WhatsApp/src/iq.cpp | 5 | ||||
-rw-r--r-- | protocols/WhatsApp/src/message.cpp | 2 | ||||
-rw-r--r-- | protocols/WhatsApp/src/protobuf-c/protobuf-c-util.h | 53 | ||||
-rw-r--r-- | protocols/WhatsApp/src/utils.h | 2 |
8 files changed, 359 insertions, 2 deletions
diff --git a/protocols/WhatsApp/WhatsApp.vcxproj b/protocols/WhatsApp/WhatsApp.vcxproj index 9c8f33b9e4..a01e4af187 100644 --- a/protocols/WhatsApp/WhatsApp.vcxproj +++ b/protocols/WhatsApp/WhatsApp.vcxproj @@ -65,6 +65,7 @@ <ClCompile Include="src\avatars.cpp" /> <ClCompile Include="src\chats.cpp" /> <ClCompile Include="src\crypt.cpp" /> + <ClCompile Include="src\generate.cpp" /> <ClCompile Include="src\iq.cpp" /> <ClCompile Include="src\main.cpp" /> <ClCompile Include="src\message.cpp" /> diff --git a/protocols/WhatsApp/WhatsApp.vcxproj.filters b/protocols/WhatsApp/WhatsApp.vcxproj.filters index 5e8be82d87..f772f56201 100644 --- a/protocols/WhatsApp/WhatsApp.vcxproj.filters +++ b/protocols/WhatsApp/WhatsApp.vcxproj.filters @@ -59,6 +59,9 @@ <ClCompile Include="src\protobuf-c\protobuf-c.c"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="src\generate.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="src\db.h"> diff --git a/protocols/WhatsApp/src/appsync.cpp b/protocols/WhatsApp/src/appsync.cpp index 034c51cab6..fa204c00f3 100644 --- a/protocols/WhatsApp/src/appsync.cpp +++ b/protocols/WhatsApp/src/appsync.cpp @@ -191,7 +191,7 @@ void WhatsAppProto::ParsePatch(WACollection *pColl, const Wa__SyncdRecord *rec, proto::SyncActionData data(unpadBuffer16(decoded)); - // debugLogA("Applying patch for %s{%d}: %s", pColl->szName.get(), data.version, data.Utf8DebugString().c_str()); + debugLogA("Applying patch for %s{%d}: %s", pColl->szName.get(), data->version, protobuf_c_text_to_string(data).c_str()); if (bSet) { JSONNode jsonRoot = JSONNode::parse((char*)data->index.data); diff --git a/protocols/WhatsApp/src/generate.cpp b/protocols/WhatsApp/src/generate.cpp new file mode 100644 index 0000000000..1be7d0f7e2 --- /dev/null +++ b/protocols/WhatsApp/src/generate.cpp @@ -0,0 +1,293 @@ +/** \file + * Routines to generate text format protobufs. + * + * This file contains the internal support functions as well as the + * exported functions which are used to generate text format protobufs + * from C protobuf data types. + * + * \author Kevin Lyda <kevin@ie.suberic.net> + * \date March 2014 + */ + +#include "stdafx.h" + +#include <stdio.h> +#include <varargs.h> + +#include "protobuf-c/protobuf-c-util.h" + +/** Internal function to back API function. + * + * Has a few extra params to better enable recursion. This function gets + * called for each nested message as the \c ProtobufCMessage struct is + * traversed. + * + * \param[in,out] rs The string being built up for the text format protobuf. + * \param[in] level Indent level - increments in 2's. + * \param[in] m The \c ProtobufCMessage being serialised. + * \param[in] d The descriptor for the \c ProtobufCMessage. + * \param[in] allocator allocator functions. + */ + +static void +protobuf_c_text_to_string_internal(CMStringA &str, + int level, + const ProtobufCMessage *m, + const ProtobufCMessageDescriptor *d) +{ + int i; + size_t j, quantifier_offset; + double float_var; + const ProtobufCFieldDescriptor *f; + ProtobufCEnumDescriptor *enumd; + const ProtobufCEnumValue *enumv; + + f = d->fields; + for (i = 0; i < d->n_fields; i++) { + /* Decide if something needs to be done for this field. */ + switch (f[i].label) { + case PROTOBUF_C_LABEL_OPTIONAL: + if (f[i].type == PROTOBUF_C_TYPE_STRING) { + if (!STRUCT_MEMBER(char *, m, f[i].offset) + || (STRUCT_MEMBER(char *, m, f[i].offset) + == (char *)f[i].default_value)) { + continue; + } + } + else if (f[i].type == PROTOBUF_C_TYPE_MESSAGE) { + if (!STRUCT_MEMBER(char *, m, f[i].offset)) { + continue; + } + } + else { + if (!STRUCT_MEMBER(protobuf_c_boolean, m, f[i].quantifier_offset)) { + continue; + } + } + break; + case PROTOBUF_C_LABEL_REPEATED: + if (!STRUCT_MEMBER(size_t, m, f[i].quantifier_offset)) { + continue; + } + break; + } + + quantifier_offset = STRUCT_MEMBER(size_t, m, f[i].quantifier_offset); + /* Field exists and has data, dump it. */ + switch (f[i].type) { + case PROTOBUF_C_TYPE_INT32: + case PROTOBUF_C_TYPE_UINT32: + case PROTOBUF_C_TYPE_FIXED32: + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; j < quantifier_offset; j++) { + str.AppendFormat( + "%*s%s: %u\n", + level, "", f[i].name, + STRUCT_MEMBER(uint32_t *, m, f[i].offset)[j]); + } + } + else { + str.AppendFormat( + "%*s%s: %u\n", + level, "", f[i].name, + STRUCT_MEMBER(uint32_t, m, f[i].offset)); + } + break; + case PROTOBUF_C_TYPE_SINT32: + case PROTOBUF_C_TYPE_SFIXED32: + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; j < quantifier_offset; j++) { + str.AppendFormat( + "%*s%s: %d\n", + level, "", f[i].name, + STRUCT_MEMBER(int32_t *, m, f[i].offset)[j]); + } + } + else { + str.AppendFormat( + "%*s%s: %d\n", + level, "", f[i].name, + STRUCT_MEMBER(int32_t, m, f[i].offset)); + } + break; + case PROTOBUF_C_TYPE_INT64: + case PROTOBUF_C_TYPE_UINT64: + case PROTOBUF_C_TYPE_FIXED64: + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; j < quantifier_offset; j++) { + str.AppendFormat( + "%*s%s: %lu\n", + level, "", f[i].name, + STRUCT_MEMBER(uint64_t *, m, f[i].offset)[j]); + } + } + else { + str.AppendFormat( + "%*s%s: %lu\n", + level, "", f[i].name, + STRUCT_MEMBER(uint64_t, m, f[i].offset)); + } + break; + case PROTOBUF_C_TYPE_SINT64: + case PROTOBUF_C_TYPE_SFIXED64: + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; j < quantifier_offset; j++) { + str.AppendFormat( + "%*s%s: %ld\n", + level, "", f[i].name, + STRUCT_MEMBER(int64_t *, m, f[i].offset)[j]); + } + } + else { + str.AppendFormat( + "%*s%s: %ld\n", + level, "", f[i].name, + STRUCT_MEMBER(int64_t, m, f[i].offset)); + } + break; + case PROTOBUF_C_TYPE_FLOAT: + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; j < quantifier_offset; j++) { + float_var = STRUCT_MEMBER(float *, m, f[i].offset)[j]; + str.AppendFormat( + "%*s%s: %g\n", + level, "", f[i].name, + float_var); + } + } + else { + float_var = STRUCT_MEMBER(float, m, f[i].offset); + str.AppendFormat( + "%*s%s: %g\n", + level, "", f[i].name, + float_var); + } + break; + case PROTOBUF_C_TYPE_DOUBLE: + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; j < quantifier_offset; j++) { + str.AppendFormat( + "%*s%s: %g\n", + level, "", f[i].name, + STRUCT_MEMBER(double *, m, f[i].offset)[j]); + } + } + else { + str.AppendFormat( + "%*s%s: %g\n", + level, "", f[i].name, + STRUCT_MEMBER(double, m, f[i].offset)); + } + break; + case PROTOBUF_C_TYPE_BOOL: + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; j < quantifier_offset; j++) { + str.AppendFormat( + "%*s%s: %s\n", + level, "", f[i].name, + STRUCT_MEMBER(protobuf_c_boolean *, m, f[i].offset)[j] ? + "true" : "false"); + } + } + else { + str.AppendFormat( + "%*s%s: %s\n", + level, "", f[i].name, + STRUCT_MEMBER(protobuf_c_boolean, m, f[i].offset) ? + "true" : "false"); + } + break; + case PROTOBUF_C_TYPE_ENUM: + enumd = (ProtobufCEnumDescriptor *)f[i].descriptor; + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; j < quantifier_offset; j++) { + enumv = protobuf_c_enum_descriptor_get_value( + enumd, STRUCT_MEMBER(int *, m, f[i].offset)[j]); + str.AppendFormat( + "%*s%s: %s\n", + level, "", f[i].name, + enumv ? enumv->name : "unknown"); + } + } + else { + enumv = protobuf_c_enum_descriptor_get_value( + enumd, STRUCT_MEMBER(int, m, f[i].offset)); + str.AppendFormat( + "%*s%s: %s\n", + level, "", f[i].name, + enumv ? enumv->name : "unknown"); + } + break; + case PROTOBUF_C_TYPE_STRING: + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; j < quantifier_offset; j++) { + str.AppendFormat( + "%*s%s: \"%s\"\n", level, "", f[i].name, STRUCT_MEMBER(unsigned char **, m, f[i].offset)[j]); + } + } + else { + str.AppendFormat( + "%*s%s: \"%s\"\n", level, "", f[i].name, STRUCT_MEMBER(unsigned char *, m, f[i].offset)); + } + break; + case PROTOBUF_C_TYPE_BYTES: + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; j < quantifier_offset; j++) { + ProtobufCBinaryData &pData = STRUCT_MEMBER(ProtobufCBinaryData *, m, f[i].offset)[j]; + ptrA tmp((char *)mir_alloc(pData.len * 2 + 1)); + bin2hex(pData.data, pData.len, tmp); + str.AppendFormat( + "%*s%s: \"%s\"\n", level, "", f[i].name, tmp.get()); + } + } + else { + ProtobufCBinaryData &pData = STRUCT_MEMBER(ProtobufCBinaryData, m, f[i].offset); + ptrA tmp((char *)mir_alloc(pData.len * 2 + 1)); + bin2hex(pData.data, pData.len, tmp); + str.AppendFormat( + "%*s%s: \"%s\"\n", level, "", f[i].name, tmp.get()); + } + break; + + case PROTOBUF_C_TYPE_MESSAGE: + if (f[i].label == PROTOBUF_C_LABEL_REPEATED) { + for (j = 0; + j < STRUCT_MEMBER(size_t, m, f[i].quantifier_offset); + j++) { + str.AppendFormat( + "%*s%s {\n", level, "", f[i].name); + protobuf_c_text_to_string_internal(str, level + 2, + STRUCT_MEMBER(ProtobufCMessage **, m, f[i].offset)[j], + (ProtobufCMessageDescriptor *)f[i].descriptor); + str.AppendFormat( + "%*s}\n", level, ""); + } + } + else { + str.AppendFormat( + "%*s%s {\n", level, "", f[i].name); + protobuf_c_text_to_string_internal(str, level + 2, + STRUCT_MEMBER(ProtobufCMessage *, m, f[i].offset), + (ProtobufCMessageDescriptor *)f[i].descriptor); + str.AppendFormat( + "%*s}\n", level, ""); + } + break; + + default: + return; + } + + } +} + +/** @} */ /* End of generate group. */ + +/* See .h file for API docs. */ + +CMStringA protobuf_c_text_to_string(const ProtobufCMessage *m) +{ + CMStringA res; + protobuf_c_text_to_string_internal(res, 0, m, m->descriptor); + return res; +} diff --git a/protocols/WhatsApp/src/iq.cpp b/protocols/WhatsApp/src/iq.cpp index f2a8fce306..2a038cb61a 100644 --- a/protocols/WhatsApp/src/iq.cpp +++ b/protocols/WhatsApp/src/iq.cpp @@ -271,6 +271,11 @@ void WhatsAppProto::OnNotifyEncrypt(const WANode &node) void WhatsAppProto::OnNotifyPicture(const WANode &node) { + if (auto *pszFrom = node.getAttr("from")) + if (m_szJid != pszFrom) + if (auto *pszUser = FindUser(pszFrom)) + ServerFetchAvatar(pszFrom); + SendAck(node); } diff --git a/protocols/WhatsApp/src/message.cpp b/protocols/WhatsApp/src/message.cpp index bdf0bc9c7a..0a9a1e557e 100644 --- a/protocols/WhatsApp/src/message.cpp +++ b/protocols/WhatsApp/src/message.cpp @@ -190,7 +190,7 @@ void WhatsAppProto::ProcessMessage(WAMSG type, const Wa__WebMessageInfo &msg) auto *body = getBody(msg.message); bool bFromMe = key->fromme; - // debugLogA("Got a message: %s", msg.Utf8DebugString().c_str()); + debugLogA("Got a message: %s", protobuf_c_text_to_string(&msg).c_str()); uint32_t timestamp = msg.messagetimestamp; auto *participant = key->participant; diff --git a/protocols/WhatsApp/src/protobuf-c/protobuf-c-util.h b/protocols/WhatsApp/src/protobuf-c/protobuf-c-util.h new file mode 100644 index 0000000000..09bb226aea --- /dev/null +++ b/protocols/WhatsApp/src/protobuf-c/protobuf-c-util.h @@ -0,0 +1,53 @@ +#ifndef PROTOBUF_C_UTIL_H +#define PROTOBUF_C_UTIL_H + +/** \file + * Internal utility header file. + * Macros used by the generator and parser parts of the library. + * + * \author Kevin Lyda <kevin@ie.suberic.net> + * \date March 2014 + */ + +/** \defgroup internal Internal API + * + * These are the functions and data structures used internally. They are + * not exported and are not useable by users of \c libprotobuf-c-text. + */ + +/* These are lifted from the protobuf-c lib */ + +/** Used to define STRUCT_MEMBER() and STRUCT_MEMBER_PTR(). */ +#define STRUCT_MEMBER_P(struct_p, struct_offset) \ + ((void *) ((uint8_t *) (struct_p) + (struct_offset))) + +/** Return a field from a message based on offset and type. */ +#define STRUCT_MEMBER(member_type, struct_p, struct_offset) \ + (*(member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) + +/** Return a pointer to a field in a message based on offset and type. */ +#define STRUCT_MEMBER_PTR(member_type, struct_p, struct_offset) \ + ((member_type *) STRUCT_MEMBER_P((struct_p), (struct_offset))) + +/** Free possibly using the pbc allocator. */ +#define PBC_FREE(ptr) (allocator? allocator->free(allocator->allocator_data, \ + ptr): free(ptr)) + +/** Allocate possibly using the pbc allocator. */ +#define PBC_ALLOC(size) (allocator? \ + allocator->alloc(allocator->allocator_data, size): \ + malloc(size)) + +/** Free possibly using the pbc allocator (state members). */ +#define ST_FREE(ptr) (state->allocator? \ + state->allocator->free(state->allocator-> \ + allocator_data, ptr): \ + free(ptr)) + +/** Allocate possibly using the pbc allocator (state members). */ +#define ST_ALLOC(size) (state->allocator? \ + state->allocator->alloc(state->allocator-> \ + allocator_data, size): \ + malloc(size)) + +#endif /* PROTOBUF_C_UTIL_H */ diff --git a/protocols/WhatsApp/src/utils.h b/protocols/WhatsApp/src/utils.h index 75b60767b7..375104f865 100644 --- a/protocols/WhatsApp/src/utils.h +++ b/protocols/WhatsApp/src/utils.h @@ -208,6 +208,8 @@ MBinBuffer decodeBufStr(const std::string &buf); void padBuffer16(MBinBuffer &buf); MBinBuffer unpadBuffer16(const MBinBuffer &buf); +CMStringA protobuf_c_text_to_string(const ProtobufCMessage *m); + MBinBuffer aesDecrypt( const EVP_CIPHER *cipher, const uint8_t *key, |