about summary refs log tree commit diff stats
path: root/src/xmpp
diff options
context:
space:
mode:
authorPaul Fariello <paul@fariello.eu>2019-06-17 06:23:40 +0200
committerPaul Fariello <paul@fariello.eu>2019-06-20 14:30:42 +0200
commit44d16e91411da44a945b0ac44c0253c1dac5e5f3 (patch)
tree7a21bb18db2b611932a3a5c8e6efdb1ae460294e /src/xmpp
parent3bb3cc625d1714fd5e81ef0adba61a5172c3212d (diff)
downloadprofani-tty-44d16e91411da44a945b0ac44c0253c1dac5e5f3.tar.gz
Add prof_message_t to wrap all message attributes
Probably missing copy of body to plain in carbon and privmessage.
Only covers the incoming message path because goal is OMEMO decryption
of untrusted message.
Cover some of the log functions but not all.
Diffstat (limited to 'src/xmpp')
-rw-r--r--src/xmpp/message.c250
-rw-r--r--src/xmpp/message.h28
2 files changed, 164 insertions, 114 deletions
diff --git a/src/xmpp/message.c b/src/xmpp/message.c
index 424c59ca..19657da0 100644
--- a/src/xmpp/message.c
+++ b/src/xmpp/message.c
@@ -75,6 +75,7 @@ typedef struct p_message_handle_t {
 } ProfMessageHandler;
 
 static int _message_handler(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const userdata);
+static void _private_chat_handler(xmpp_stanza_t *const stanza);
 
 static void _handle_error(xmpp_stanza_t *const stanza);
 static void _handle_groupchat(xmpp_stanza_t *const stanza);
@@ -178,6 +179,53 @@ message_handlers_init(void)
     pubsub_event_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, free, free);
 }
 
+prof_message_t *
+message_init(void)
+{
+    prof_message_t *message = malloc(sizeof(prof_message_t));
+
+    message->jid = NULL;
+    message->id = NULL;
+    message->body = NULL;
+    message->encrypted = NULL;
+    message->plain = NULL;
+    message->enc = PROF_MSG_ENC_PLAIN;
+    message->timestamp = NULL;
+
+    return message;
+}
+
+void
+message_free(prof_message_t *message)
+{
+    xmpp_ctx_t *ctx = connection_get_ctx();
+    if (message->jid) {
+        jid_destroy(message->jid);
+    }
+
+    if (message->id) {
+        xmpp_free(ctx, message->id);
+    }
+
+    if (message->body) {
+        xmpp_free(ctx, message->body);
+    }
+
+    if (message->encrypted) {
+        xmpp_free(ctx, message->encrypted);
+    }
+
+    if (message->plain) {
+        free(message->plain);
+    }
+
+    if (message->timestamp) {
+        g_date_time_unref(message->timestamp);
+    }
+
+    free(message);
+}
+
 void
 message_handlers_clear(void)
 {
@@ -696,8 +744,6 @@ static void
 _handle_groupchat(xmpp_stanza_t *const stanza)
 {
     xmpp_ctx_t *ctx = connection_get_ctx();
-    int flags = 0;
-    char *message = NULL;
 
     const char *id = xmpp_stanza_get_id(stanza);
 
@@ -712,9 +758,10 @@ _handle_groupchat(xmpp_stanza_t *const stanza)
     // handle room subject
     xmpp_stanza_t *subject = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_SUBJECT);
     if (subject) {
-        message = xmpp_stanza_get_text(subject);
-        sv_ev_room_subject(jid->barejid, jid->resourcepart, message);
-        xmpp_free(ctx, message);
+        char *subject_text;
+        subject_text = xmpp_stanza_get_text(subject);
+        sv_ev_room_subject(jid->barejid, jid->resourcepart, subject_text);
+        xmpp_free(ctx, subject_text);
 
         jid_destroy(jid);
         return;
@@ -722,14 +769,15 @@ _handle_groupchat(xmpp_stanza_t *const stanza)
 
     // handle room broadcasts
     if (!jid->resourcepart) {
-        message = xmpp_message_get_body(stanza);
-        if (!message) {
+        char *broadcast;
+        broadcast = xmpp_message_get_body(stanza);
+        if (!broadcast) {
             jid_destroy(jid);
             return;
         }
 
-        sv_ev_room_broadcast(room_jid, message);
-        xmpp_free(ctx, message);
+        sv_ev_room_broadcast(room_jid, broadcast);
+        xmpp_free(ctx, broadcast);
 
         jid_destroy(jid);
         return;
@@ -748,37 +796,29 @@ _handle_groupchat(xmpp_stanza_t *const stanza)
         return;
     }
 
+    prof_message_t *message = message_init();
+    message->jid = jid;
+    message->id = strdup(id);
+
     // check omemo encryption
 #ifdef HAVE_OMEMO
-    gboolean trusted = FALSE;
-    message = omemo_receive_message(stanza, &trusted);
-    if (message != NULL) {
-        flags |= MSG_ENC_OMEMO;
-        if (trusted) {
-            flags |= MSG_TRUSTED;
-        }
+    message->plain = omemo_receive_message(stanza, &message->trusted);
+    if (message->plain != NULL) {
+        message->enc = PROF_MSG_ENC_OMEMO;
     }
 #endif
 
-    if (!message) {
-        message = xmpp_message_get_body(stanza);
-        if (!message) {
-            jid_destroy(jid);
-            return;
-        }
-    }
+    message->body = xmpp_message_get_body(stanza);
 
     // determine if the notifications happened whilst offline
-    GDateTime *timestamp = stanza_get_delay(stanza);
-    if (timestamp) {
-        sv_ev_room_history(jid->barejid, jid->resourcepart, timestamp, message, flags);
-        g_date_time_unref(timestamp);
+    message->timestamp = stanza_get_delay(stanza);
+    if (message->timestamp) {
+        sv_ev_room_history(message);
     } else {
-        sv_ev_room_message(jid->barejid, jid->resourcepart, message, id, flags);
+        sv_ev_room_message(message);
     }
 
-    xmpp_free(ctx, message);
-    jid_destroy(jid);
+    message_free(message);
 }
 
 void
@@ -854,31 +894,38 @@ _receipt_request_handler(xmpp_stanza_t *const stanza)
     jid_destroy(jid);
 }
 
-void
-_private_chat_handler(xmpp_stanza_t *const stanza, const char *const fulljid)
+static void
+_private_chat_handler(xmpp_stanza_t *const stanza)
 {
-    char *message = xmpp_message_get_body(stanza);
-    if (!message) {
-        return;
+    // standard chat message, use jid without resource
+    prof_message_t *message = message_init();
+
+    const gchar *from = xmpp_stanza_get_from(stanza);
+    message->jid = jid_create(from);
+
+    // check omemo encryption
+#ifdef HAVE_OMEMO
+    message->plain = omemo_receive_message(stanza, &message->trusted);
+    if (message->plain != NULL) {
+        message->enc = PROF_MSG_ENC_OMEMO;
     }
+#endif
+
+    message->timestamp = stanza_get_delay(stanza);
+    message->body = xmpp_message_get_body(stanza);
 
-    GDateTime *timestamp = stanza_get_delay(stanza);
-    if (timestamp) {
-        sv_ev_delayed_private_message(fulljid, message, timestamp);
-        g_date_time_unref(timestamp);
+    if (message->timestamp) {
+        sv_ev_delayed_private_message(message);
     } else {
-        sv_ev_incoming_private_message(fulljid, message);
+        sv_ev_incoming_private_message(message);
     }
 
-    xmpp_ctx_t *ctx = connection_get_ctx();
-    xmpp_free(ctx, message);
+    message_free(message);
 }
 
 static gboolean
 _handle_carbons(xmpp_stanza_t *const stanza)
 {
-    char *message_txt = NULL;
-    int flags = 0;
     xmpp_stanza_t *carbons = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CARBONS);
     if (!carbons) {
         return FALSE;
@@ -906,32 +953,12 @@ _handle_carbons(xmpp_stanza_t *const stanza)
         return TRUE;
     }
 
-    xmpp_stanza_t *message = xmpp_stanza_get_child_by_name(forwarded, STANZA_NAME_MESSAGE);
-    if (!message) {
+    xmpp_stanza_t *message_stanza = xmpp_stanza_get_child_by_name(forwarded, STANZA_NAME_MESSAGE);
+    if (!message_stanza) {
         log_warning("Carbon received with no message element");
         return TRUE;
     }
 
-    // check omemo encryption
-#ifdef HAVE_OMEMO
-    gboolean trusted = FALSE;
-    message_txt = omemo_receive_message(message, &trusted);
-    if (message_txt != NULL) {
-        flags != MSG_ENC_OMEMO;
-        if (trusted) {
-            flags |= MSG_TRUSTED;
-        }
-    }
-#endif
-
-    if (!message_txt) {
-        message_txt = xmpp_message_get_body(message);
-        if (!message_txt) {
-            log_warning("Carbon received with no message.");
-            return TRUE;
-        }
-    }
-
     Jid *my_jid = jid_create(connection_get_fulljid());
     const char *const stanza_from = xmpp_stanza_get_from(stanza);
     if (g_strcmp0(my_jid->barejid, stanza_from) != 0) {
@@ -939,8 +966,20 @@ _handle_carbons(xmpp_stanza_t *const stanza)
         return TRUE;
     }
 
-    const gchar *to = xmpp_stanza_get_to(message);
-    const gchar *from = xmpp_stanza_get_from(message);
+    prof_message_t *message = message_init();
+
+    // check omemo encryption
+#ifdef HAVE_OMEMO
+    message->plain = omemo_receive_message(message_stanza, &message->trusted);
+    if (message->plain != NULL) {
+        message->enc = PROF_MSG_ENC_OMEMO;
+    }
+#endif
+
+    message->body = xmpp_message_get_body(message_stanza);
+
+    const gchar *to = xmpp_stanza_get_to(message_stanza);
+    const gchar *from = xmpp_stanza_get_from(message_stanza);
 
     // happens when receive a carbon of a self sent message
     if (!to) to = from;
@@ -949,27 +988,25 @@ _handle_carbons(xmpp_stanza_t *const stanza)
     Jid *jid_to = jid_create(to);
 
     // check for pgp encrypted message
-    char *enc_message = NULL;
-    xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(message, STANZA_NS_ENCRYPTED);
+    xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(message_stanza, STANZA_NS_ENCRYPTED);
     if (x) {
-        enc_message = xmpp_stanza_get_text(x);
+        message->encrypted = xmpp_stanza_get_text(x);
     }
 
     // if we are the recipient, treat as standard incoming message
     if (g_strcmp0(my_jid->barejid, jid_to->barejid) == 0) {
-        sv_ev_incoming_carbon(jid_from->barejid, jid_from->resourcepart, message_txt, enc_message, flags);
+        jid_destroy(jid_to);
+        message->jid = jid_from;
+        sv_ev_incoming_carbon(message);
 
     // else treat as a sent message
     } else {
-        sv_ev_outgoing_carbon(jid_to->barejid, message_txt, enc_message, flags);
+        jid_destroy(jid_from);
+        message->jid = jid_to;
+        sv_ev_outgoing_carbon(message);
     }
 
-    xmpp_ctx_t *ctx = connection_get_ctx();
-    xmpp_free(ctx, message_txt);
-    xmpp_free(ctx, enc_message);
-
-    jid_destroy(jid_from);
-    jid_destroy(jid_to);
+    message_free(message);
     jid_destroy(my_jid);
 
     return TRUE;
@@ -978,7 +1015,6 @@ _handle_carbons(xmpp_stanza_t *const stanza)
 static void
 _handle_chat(xmpp_stanza_t *const stanza)
 {
-    char *message = NULL;
     // ignore if type not chat or absent
     const char *type = xmpp_stanza_get_type(stanza);
     if (!(g_strcmp0(type, "chat") == 0 || type == NULL)) {
@@ -991,14 +1027,6 @@ _handle_chat(xmpp_stanza_t *const stanza)
         return;
     }
 
-    // check omemo encryption
-    gboolean omemo = FALSE;
-    gboolean trusted = FALSE;
-#ifdef HAVE_OMEMO
-    message = omemo_receive_message(stanza, &trusted);
-    omemo = message != NULL;
-#endif
-
     // ignore handled namespaces
     xmpp_stanza_t *conf = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CONFERENCE);
     xmpp_stanza_t *captcha = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_CAPTCHA);
@@ -1020,38 +1048,41 @@ _handle_chat(xmpp_stanza_t *const stanza)
 
     // private message from chat room use full jid (room/nick)
     if (muc_active(jid->barejid)) {
-        _private_chat_handler(stanza, jid->fulljid);
+        _private_chat_handler(stanza);
         jid_destroy(jid);
         return;
     }
 
     // standard chat message, use jid without resource
-    xmpp_ctx_t *ctx = connection_get_ctx();
-    GDateTime *timestamp = stanza_get_delay(stanza);
-    if (!message && body) {
-        message = xmpp_stanza_get_text(body);
+    prof_message_t *message = message_init();
+    message->jid = jid;
+
+    message->timestamp = stanza_get_delay(stanza);
+    if (body) {
+        message->body = xmpp_stanza_get_text(body);
     }
 
-    if (message) {
-        char *enc_message = NULL;
-        xmpp_stanza_t *x = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_ENCRYPTED);
-        if (x) {
-            enc_message = xmpp_stanza_get_text(x);
-        }
-        sv_ev_incoming_message(jid->barejid, jid->resourcepart, message, enc_message, timestamp, omemo, trusted);
-        xmpp_free(ctx, enc_message);
+    // check omemo encryption
+#ifdef HAVE_OMEMO
+    message->plain = omemo_receive_message(stanza, &message->trusted);
+    if (message->plain != NULL) {
+        message->enc = PROF_MSG_ENC_OMEMO;
+    }
+#endif
 
-        _receipt_request_handler(stanza);
+    xmpp_stanza_t *encrypted = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_ENCRYPTED);
+    if (encrypted) {
+        message->encrypted = xmpp_stanza_get_text(encrypted);
+    }
 
-        if (omemo) {
-            free(message);
-        } else {
-            xmpp_free(ctx, message);
-        }
+    if (message->plain || message->body || message->encrypted) {
+        sv_ev_incoming_message(message);
+
+        _receipt_request_handler(stanza);
     }
 
     // handle chat sessions and states
-    if (!timestamp && jid->resourcepart) {
+    if (!message->timestamp && jid->resourcepart) {
         gboolean gone = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_GONE) != NULL;
         gboolean typing = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_COMPOSING) != NULL;
         gboolean paused = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_PAUSED) != NULL;
@@ -1071,8 +1102,7 @@ _handle_chat(xmpp_stanza_t *const stanza)
         }
     }
 
-    if (timestamp) g_date_time_unref(timestamp);
-    jid_destroy(jid);
+    message_free(message);
 }
 
 static void
diff --git a/src/xmpp/message.h b/src/xmpp/message.h
index b73406a0..f4861378 100644
--- a/src/xmpp/message.h
+++ b/src/xmpp/message.h
@@ -35,14 +35,34 @@
 #ifndef XMPP_MESSAGE_H
 #define XMPP_MESSAGE_H
 
-#define PROF_MSG_ENC_OTR     1
-#define PROF_MSG_ENC_PGP     2
-#define PROF_MSG_ENC_OMEMO   4
-#define PROF_MSG_TRUSTED     8
+#include "xmpp/xmpp.h"
+
+typedef enum {
+    PROF_MSG_ENC_PLAIN,
+    PROF_MSG_ENC_OTR,
+    PROF_MSG_ENC_PGP,
+    PROF_MSG_ENC_OMEMO
+} prof_enc_t;
+
+typedef struct {
+   Jid *jid;
+   char *id;
+   /* The raw body from xmpp message, either plaintext or OTR encrypted text */
+   char *body;
+   /* The encrypted message as for PGP */
+   char *encrypted;
+   /* The message that will be printed on screen and logs */
+   char *plain;
+   GDateTime *timestamp;
+   prof_enc_t enc;
+   gboolean trusted;
+} prof_message_t;
 
 typedef int(*ProfMessageCallback)(xmpp_stanza_t *const stanza, void *const userdata);
 typedef void(*ProfMessageFreeCallback)(void *userdata);
 
+prof_message_t *message_init(void);
+void message_free(prof_message_t *message);
 void message_handlers_init(void);
 void message_handlers_clear(void);
 void message_pubsub_event_handler_add(const char *const node, ProfMessageCallback func, ProfMessageFreeCallback free_func, void *userdata);