changeset 1602:f4a2c6f767d1

Message Receipts support (XEP-0184)
author franky
date Wed, 24 Sep 2008 11:41:29 +0200
parents 3efc92a48945
children 54029aba9452
files mcabber/src/commands.c mcabber/src/hbuf.c mcabber/src/hbuf.h mcabber/src/histolog.c mcabber/src/hooks.c mcabber/src/hooks.h mcabber/src/otr.c mcabber/src/screen.c mcabber/src/screen.h mcabber/src/xmpp.c mcabber/src/xmpp.h mcabber/src/xmpp_defines.h mcabber/src/xmpp_helper.c
diffstat 13 files changed, 107 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/mcabber/src/commands.c	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/commands.c	Wed Sep 24 11:41:29 2008 +0200
@@ -1114,6 +1114,7 @@
   gint crypted;
   gint retval = 0;
   int isroom;
+  gpointer xep184 = NULL;
 
   if (!lm_connection_is_authenticated(lconnection)) {
     scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
@@ -1162,7 +1163,7 @@
 
   // Network part
   xmpp_send_msg(fjid, msg, (isroom ? ROSTER_TYPE_ROOM : ROSTER_TYPE_USER),
-                subj, FALSE, &crypted, type_overwrite);
+                subj, FALSE, &crypted, type_overwrite, &xep184);
 
   if (crypted == -1) {
     scr_LogPrint(LPRINT_LOGNORM, "Encryption error.  Message was not sent.");
@@ -1172,7 +1173,7 @@
 
   // Hook
   if (!isroom)
-    hk_message_out(bare_jid, rp, 0, hmsg, crypted);
+    hk_message_out(bare_jid, rp, 0, hmsg, crypted, xep184);
 
 send_message_to_return:
   if (hmsg != msg) g_free(hmsg);
@@ -2630,7 +2631,7 @@
   arg = to_utf8(arg);
   // Set the topic
   xmpp_send_msg(buddy_getjid(bud), NULL, ROSTER_TYPE_ROOM, arg ? arg : "",
-                FALSE, NULL, LM_MESSAGE_SUB_TYPE_NOT_SET);
+                FALSE, NULL, LM_MESSAGE_SUB_TYPE_NOT_SET, NULL);
   g_free(arg);
 }
 
--- a/mcabber/src/hbuf.c	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/hbuf.c	Wed Sep 24 11:41:29 2008 +0200
@@ -44,6 +44,7 @@
     time_t timestamp;
     unsigned mucnicklen;
     guint  flags;
+    gpointer xep184;
   } prefix;
 } hbuf_block;
 
@@ -123,7 +124,7 @@
 // Note 2: width does not include the ending \0.
 void hbuf_add_line(GList **p_hbuf, const char *text, time_t timestamp,
         guint prefix_flags, guint width, guint maxhbufblocks,
-        unsigned mucnicklen)
+        unsigned mucnicklen, gpointer xep184)
 {
   GList *curr_elt;
   char *line;
@@ -132,6 +133,8 @@
 
   if (!text) return;
 
+  prefix_flags |= (xep184 ? HBB_PREFIX_RECEIPT : 0);
+
   textlen = strlen(text);
   hbb_blocksize = MAX(textlen+1, HBB_BLOCKSIZE);
 
@@ -139,6 +142,7 @@
   hbuf_block_elt->prefix.timestamp  = timestamp;
   hbuf_block_elt->prefix.flags      = prefix_flags;
   hbuf_block_elt->prefix.mucnicklen = mucnicklen;
+  hbuf_block_elt->prefix.xep184     = xep184;
   if (!*p_hbuf) {
     hbuf_block_elt->ptr  = g_new(char, hbb_blocksize);
     if (!hbuf_block_elt->ptr) {
@@ -474,6 +478,26 @@
   return;
 }
 
+//  hbuf_remove_receipt(hbuf, xep184)
+// Remove the Receipt Flag for the message with the given xep184 id
+// Returns TRUE if it was found and removed, otherwise FALSE
+gboolean hbuf_remove_receipt(GList *hbuf, gpointer xep184)
+{
+  hbuf_block *blk;
+
+  hbuf = g_list_first(hbuf);
+
+  for ( ; hbuf; hbuf = g_list_next(hbuf)) {
+    blk = (hbuf_block*)(hbuf->data);
+    if (blk->prefix.xep184 == xep184) {
+      blk->prefix.xep184 = NULL;
+      blk->prefix.flags ^= HBB_PREFIX_RECEIPT;
+      return TRUE;
+    }
+  }
+  return FALSE;
+}
+
 //  hbuf_get_blocks_number()
 // Returns the number of allocated hbuf_block's.
 guint hbuf_get_blocks_number(GList *hbuf)
--- a/mcabber/src/hbuf.h	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/hbuf.h	Wed Sep 24 11:41:29 2008 +0200
@@ -28,6 +28,7 @@
 #define HBB_PREFIX_PGPCRYPT   (1U<<11)
 #define HBB_PREFIX_OTRCRYPT   (1U<<12)
 #define HBB_PREFIX_CONT       (1U<<13)
+#define HBB_PREFIX_RECEIPT    (1U<<14)
 
 typedef struct {
   time_t timestamp;
@@ -38,7 +39,7 @@
 
 void hbuf_add_line(GList **p_hbuf, const char *text, time_t timestamp,
         guint prefix_flags, guint width, guint maxhbufblocks,
-        unsigned mucnicklen);
+        unsigned mucnicklen, gpointer xep184);
 void hbuf_free(GList **p_hbuf);
 void hbuf_rebuild(GList **p_hbuf, unsigned int width);
 GList *hbuf_previous_persistent(GList *l_line);
@@ -47,6 +48,7 @@
 GList *hbuf_search(GList *hbuf, int direction, const char *string);
 GList *hbuf_jump_date(GList *hbuf, time_t t);
 GList *hbuf_jump_percent(GList *hbuf, int pc);
+gboolean hbuf_remove_receipt(GList *hbuf, gpointer xep184);
 
 void hbuf_dump_to_file(GList *hbuf, const char *filename);
 
--- a/mcabber/src/histolog.c	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/histolog.c	Wed Sep 24 11:41:29 2008 +0200
@@ -335,7 +335,7 @@
       if (converted) {
         xtext = ut_expand_tabs(converted); // Expand tabs
         hbuf_add_line(p_buddyhbuf, xtext, timestamp, prefix_flags, width,
-                      max_num_of_blocks, 0);
+                      max_num_of_blocks, 0, NULL);
         if (xtext != converted)
           g_free(xtext);
         g_free(converted);
--- a/mcabber/src/hooks.c	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/hooks.c	Wed Sep 24 11:41:29 2008 +0200
@@ -251,7 +251,8 @@
 // nick should be set for private messages in a chat room, and null for
 // normal messages.
 void hk_message_out(const char *bjid, const char *nick,
-                           time_t timestamp, const char *msg, guint encrypted)
+                    time_t timestamp, const char *msg,
+                    guint encrypted, gpointer xep184)
 {
   char *wmsg = NULL, *bmsg = NULL, *mmsg = NULL;
   guint cryptflag = 0;
@@ -280,7 +281,7 @@
     cryptflag = HBB_PREFIX_PGPCRYPT;
   else if (encrypted == ENCRYPTED_OTR)
     cryptflag = HBB_PREFIX_OTRCRYPT;
-  scr_WriteOutgoingMessage(bjid, wmsg, cryptflag);
+  scr_WriteOutgoingMessage(bjid, wmsg, cryptflag, xep184);
 
   // We don't log private messages
   if (!nick)
--- a/mcabber/src/hooks.h	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/hooks.h	Wed Sep 24 11:41:29 2008 +0200
@@ -14,7 +14,8 @@
                    time_t timestamp, const char *msg, LmMessageSubType type,
                    guint encrypted);
 void hk_message_out(const char *bjid, const char *nickname,
-                           time_t timestamp, const char *msg, guint encrypted);
+                    time_t timestamp, const char *msg,
+                    guint encrypted,  gpointer xep184);
 void hk_statuschange(const char *bjid, const char *resname, gchar prio,
                      time_t timestamp, enum imstatus status,
                      char const *status_msg);
--- a/mcabber/src/otr.c	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/otr.c	Wed Sep 24 11:41:29 2008 +0200
@@ -645,7 +645,7 @@
 {
   if (roster_gettype(recipient) == ROSTER_TYPE_USER)
     xmpp_send_msg(recipient, message, ROSTER_TYPE_USER, "", TRUE, NULL,
-                  LM_MESSAGE_SUB_TYPE_NOT_SET);
+                  LM_MESSAGE_SUB_TYPE_NOT_SET, NULL);
 }
 
 /* Display a notification message for a particular
--- a/mcabber/src/screen.c	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/screen.c	Wed Sep 24 11:41:29 2008 +0200
@@ -159,7 +159,7 @@
 
 void scr_WriteInWindow(const char *winId, const char *text, time_t timestamp,
                        unsigned int prefix_flags, int force_show,
-                       unsigned mucnicklen);
+                       unsigned mucnicklen, gpointer xep184);
 
 void scr_WriteMessage(const char *bjid, const char *text,
                       time_t timestamp, guint prefix_flags,
@@ -909,12 +909,12 @@
       wprintw(logWnd, "\n%s", buffer_locale);
       update_panels();
       scr_WriteInWindow(NULL, buf_specialwindow, timestamp,
-                        HBB_PREFIX_SPECIAL, FALSE, 0);
+                        HBB_PREFIX_SPECIAL, FALSE, 0, NULL);
     } else {
       printf("%s\n", buffer_locale);
       // ncurses are not initialized yet, so we call directly hbuf routine
       hbuf_add_line(&statushbuf, buf_specialwindow, timestamp,
-        HBB_PREFIX_SPECIAL, 0, 0, 0);
+        HBB_PREFIX_SPECIAL, 0, 0, 0, NULL);
     }
 
     g_free(convbuf1);
@@ -1038,14 +1038,18 @@
         cryptflag = '=';
       g_snprintf(pref, preflen, "%s<%c= ", date, cryptflag);
     } else if (line->flags & HBB_PREFIX_OUT) {
-      char cryptflag;
+      char cryptflag, receiptflag;
       if (line->flags & HBB_PREFIX_PGPCRYPT)
         cryptflag = '~';
       else if (line->flags & HBB_PREFIX_OTRCRYPT)
         cryptflag = 'O';
       else
         cryptflag = '-';
-      g_snprintf(pref, preflen, "%s-%c> ", date, cryptflag);
+      if (line->flags & HBB_PREFIX_RECEIPT)
+        receiptflag = 'r';
+      else
+        receiptflag = '-';
+      g_snprintf(pref, preflen, "%s%c%c> ", date, receiptflag, cryptflag);
     } else if (line->flags & HBB_PREFIX_SPECIAL) {
       strftime(date, 30, getspectprefix(), localtime(&line->timestamp));
       g_snprintf(pref, preflen, "%s   ", date);
@@ -1295,7 +1299,7 @@
 // If this window doesn't exist, it is created.
 void scr_WriteInWindow(const char *winId, const char *text, time_t timestamp,
                        unsigned int prefix_flags, int force_show,
-                       unsigned mucnicklen)
+                       unsigned mucnicklen, gpointer xep184)
 {
   winbuf *win_entry;
   char *text_locale;
@@ -1342,7 +1346,7 @@
   }
   hbuf_add_line(&win_entry->bd->hbuf, text_locale, timestamp, prefix_flags,
                 maxX - Roster_Width - scr_getprefixwidth(), num_history_blocks,
-                mucnicklen);
+                mucnicklen, xep184);
   g_free(text_locale);
 
   if (win_entry->bd->cleared) {
@@ -2053,7 +2057,7 @@
 
 void scr_WriteMessage(const char *bjid, const char *text,
                       time_t timestamp, guint prefix_flags,
-                      unsigned mucnicklen)
+                      unsigned mucnicklen, gpointer xep184)
 {
   char *xtext;
 
@@ -2061,7 +2065,8 @@
 
   xtext = ut_expand_tabs(text); // Expand tabs and filter out some chars
 
-  scr_WriteInWindow(bjid, xtext, timestamp, prefix_flags, FALSE, mucnicklen);
+  scr_WriteInWindow(bjid, xtext, timestamp, prefix_flags, FALSE, mucnicklen,
+                    xep184);
 
   if (xtext != (char*)text)
     g_free(xtext);
@@ -2080,23 +2085,34 @@
   if (url_regex)
     scr_LogUrls(text);
 #endif
-  scr_WriteMessage(jidfrom, text, timestamp, prefix, mucnicklen);
+  scr_WriteMessage(jidfrom, text, timestamp, prefix, mucnicklen, NULL);
 }
 
-void scr_WriteOutgoingMessage(const char *jidto, const char *text, guint prefix)
+void scr_WriteOutgoingMessage(const char *jidto, const char *text, guint prefix,
+                              gpointer xep184)
 {
   GSList *roster_elt;
   roster_elt = roster_find(jidto, jidsearch,
                            ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_ROOM);
 
   scr_WriteMessage(jidto, text,
-                   0, prefix|HBB_PREFIX_OUT|HBB_PREFIX_HLIGHT_OUT, 0);
+                   0, prefix|HBB_PREFIX_OUT|HBB_PREFIX_HLIGHT_OUT, 0, xep184);
 
   // Show jidto's buffer unless the buddy is not in the buddylist
   if (roster_elt && g_list_position(buddylist, roster_elt->data) != -1)
     scr_ShowWindow(jidto, FALSE);
 }
 
+void scr_RemoveReceiptFlag(const char *bjid, gpointer xep184)
+{
+  winbuf *win_entry = scr_SearchWindow(bjid, FALSE);
+  if (win_entry) {
+    hbuf_remove_receipt(win_entry->bd->hbuf, xep184);
+    if (chatmode && (buddy_search_jid(bjid) == current_buddy))
+      scr_UpdateBuddyWindow();
+  }
+}
+
 static inline void set_autoaway(bool setaway)
 {
   static enum imstatus oldstatus;
--- a/mcabber/src/screen.h	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/screen.h	Wed Sep 24 11:41:29 2008 +0200
@@ -100,7 +100,8 @@
                               time_t timestamp, guint prefix,
                               unsigned mucnicklen);
 void scr_WriteOutgoingMessage(const char *jidto,   const char *text,
-                              guint prefix);
+                              guint prefix, gpointer xep184);
+void scr_RemoveReceiptFlag(const char *jidto, gpointer xep184);
 void scr_ShowBuddyWindow(void);
 int  scr_BuddyBufferExists(const char *jid);
 void scr_UpdateBuddyWindow(void);
--- a/mcabber/src/xmpp.c	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/xmpp.c	Wed Sep 24 11:41:29 2008 +0200
@@ -314,6 +314,15 @@
   g_slist_free(resources);
 }
 
+static LmHandlerResult cb_xep184(LmMessageHandler *h, LmConnection *c,
+                                 LmMessage *m, gpointer user_data)
+{
+  char *from = jidtodisp(lm_message_get_from(m));
+  scr_RemoveReceiptFlag(from, h);
+  g_free(from);
+  return LM_HANDLER_RESULT_REMOVE_MESSAGE;
+}
+
 //  xmpp_send_msg(jid, text, type, subject,
 //                otrinject, *encrypted, type_overwrite)
 // When encrypted is not NULL, the function set *encrypted to 1 if the
@@ -321,7 +330,7 @@
 // encryption fails, *encrypted is set to -1.
 void xmpp_send_msg(const char *fjid, const char *text, int type,
                    const char *subject, gboolean otrinject, gint *encrypted,
-                   LmMessageSubType type_overwrite)
+                   LmMessageSubType type_overwrite, gpointer *xep184)
 {
   LmMessage *x;
   LmMessageSubType subtype;
@@ -433,6 +442,16 @@
     g_free(enc);
   }
 
+  //XEP-0184: Message Receipts
+  if (sl_buddy && rname && xep184 &&
+      caps_has_feature(buddy_resource_getcaps(sl_buddy->data, rname),
+                       NS_RECEIPTS)) {
+    lm_message_node_set_attribute
+            (lm_message_node_add_child(x->node, "request", NULL),
+             "xmlns", NS_RECEIPTS);
+    *xep184 = lm_message_handler_new(cb_xep184, NULL, NULL);
+  }
+
 #if defined JEP0022 || defined JEP0085
   // If typing notifications are disabled, we can skip all this stuff...
   if (chatstates_disabled || type == ROSTER_TYPE_ROOM)
@@ -492,7 +511,11 @@
 xmpp_send_msg_no_chatstates:
   if (mystatus != invisible)
     update_last_use();
-  lm_connection_send(lconnection, x, NULL);
+  if (xep184 && *xep184) {
+    lm_connection_send_with_reply(lconnection, x, *xep184, NULL);
+    lm_message_handler_unref(*xep184);
+  } else
+    lm_connection_send(lconnection, x, NULL);
   lm_message_unref(x);
 }
 
@@ -1243,6 +1266,16 @@
   if (from && (body || subject))
     gotmessage(lm_message_get_sub_type(m), from, body, enc, subject, timestamp,
                lm_message_node_find_xmlns(m->node, NS_SIGNED));
+  //report received message if message receipt was requested
+  if (lm_message_node_get_child(m->node, "request")) {
+    LmMessage *rcvd = lm_message_new(from, LM_MESSAGE_TYPE_MESSAGE);
+    lm_message_node_set_attribute(rcvd->node, "id", lm_message_get_id(m));
+    lm_message_node_set_attribute
+            (lm_message_node_add_child(rcvd->node, "received", NULL),
+             "xmlns", NS_RECEIPTS);
+    lm_connection_send(connection, rcvd, NULL);
+    lm_message_unref(rcvd);
+  }
 
   if (from) {
     x = lm_message_node_find_xmlns(m->node,
--- a/mcabber/src/xmpp.h	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/xmpp.h	Wed Sep 24 11:41:29 2008 +0200
@@ -49,7 +49,7 @@
 
 void xmpp_send_msg(const char *fjid, const char *text, int type,
                    const char *subject, gboolean otrinject, gint *encrypted,
-                   LmMessageSubType type_overwrite);
+                   LmMessageSubType type_overwrite, gpointer *xep184);
 
 void xmpp_send_s10n(const char *bjid, LmMessageSubType type);
 
--- a/mcabber/src/xmpp_defines.h	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/xmpp_defines.h	Wed Sep 24 11:41:29 2008 +0200
@@ -54,6 +54,7 @@
 #define NS_XMPP_DELAY "urn:xmpp:delay"
 #define NS_XMPP_TIME  "urn:xmpp:time"
 #define NS_PING       "urn:xmpp:ping"
+#define NS_RECEIPTS   "urn:xmpp:receipts"
 
 #define NS_JABBERD_STOREDPRESENCE "http://jabberd.org/ns/storedpresence"
 #define NS_JABBERD_HISTORY "http://jabberd.org/ns/history"
--- a/mcabber/src/xmpp_helper.c	Sun Oct 11 15:59:20 2009 +0200
+++ b/mcabber/src/xmpp_helper.c	Wed Sep 24 11:41:29 2008 +0200
@@ -151,6 +151,7 @@
   caps_add_feature("", NS_VERSION);
   caps_add_feature("", NS_PING);
   caps_add_feature("", NS_COMMANDS);
+  caps_add_feature("", NS_RECEIPTS);
   if (!settings_opt_get_int("iq_last_disable") &&
       (!settings_opt_get_int("iq_last_disable_when_notavail") ||
        status != notavail))