summaryrefslogtreecommitdiff
path: root/protocols/WhatsApp
diff options
context:
space:
mode:
Diffstat (limited to 'protocols/WhatsApp')
-rw-r--r--protocols/WhatsApp/WhatsApp.vcxproj1
-rw-r--r--protocols/WhatsApp/WhatsApp.vcxproj.filters3
-rw-r--r--protocols/WhatsApp/src/appsync.cpp2
-rw-r--r--protocols/WhatsApp/src/generate.cpp293
-rw-r--r--protocols/WhatsApp/src/iq.cpp5
-rw-r--r--protocols/WhatsApp/src/message.cpp2
-rw-r--r--protocols/WhatsApp/src/protobuf-c/protobuf-c-util.h53
-rw-r--r--protocols/WhatsApp/src/utils.h2
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,