/soc/2015/koosha/main: cd0d929093ab: XMPP: add back-end support ...

Koosha Khajehmoogahi <[email protected]>
Newsgroups gmane.comp.gnome.gaim.cvs
Message-ID <[email protected]>
Changeset: cd0d929093abf2a2f5a61e84d1eccce5eb90b977
Author:	 Koosha Khajehmoogahi <[email protected]>
Date:	 2015-06-11 02:37 +0200
Branch:	 default
URL: https://hg.pidgin.im/soc/2015/koosha/main/rev/cd0d929093ab

Description:

XMPP: add back-end support for XEP-0184 "Message Delivery Receipts"

diffstat:

 libpurple/protocols/jabber/disco.c      |   2 +
 libpurple/protocols/jabber/jabber.c     |   1 +
 libpurple/protocols/jabber/jabber.h     |   2 +-
 libpurple/protocols/jabber/message.c    |  77 ++++++++++++++++++++++++++++++++-
 libpurple/protocols/jabber/message.h    |   2 +
 libpurple/protocols/jabber/namespaces.h |   3 +
 6 files changed, 85 insertions(+), 2 deletions(-)

diffs (202 lines):

diff --git a/libpurple/protocols/jabber/disco.c b/libpurple/protocols/jabber/disco.c
--- a/libpurple/protocols/jabber/disco.c
+++ b/libpurple/protocols/jabber/disco.c
@@ -302,6 +302,8 @@ static void jabber_disco_info_cb(JabberS
 					purple_debug_info("jabber", "remote supports IBB\n");
 					capabilities |= JABBER_CAP_IBB;
 				}
+				else if(!strcmp(var, NS_MSG_DELIVERY))
+					capabilities |= JABBER_MSG_DELIVERY;
 			}
 		}
 
diff --git a/libpurple/protocols/jabber/jabber.c b/libpurple/protocols/jabber/jabber.c
--- a/libpurple/protocols/jabber/jabber.c
+++ b/libpurple/protocols/jabber/jabber.c
@@ -3941,6 +3941,7 @@ jabber_do_init(void)
 	jabber_add_feature(NS_SI_FILE_TRANSFER, NULL);
 	jabber_add_feature(NS_XHTML_IM, NULL);
 	jabber_add_feature(NS_PING, NULL);
+	jabber_add_feature(NS_MSG_DELIVERY, NULL);
 
 	/* Buzz/Attention */
 	jabber_add_feature(NS_ATTENTION, jabber_buzz_isenabled);
diff --git a/libpurple/protocols/jabber/jabber.h b/libpurple/protocols/jabber/jabber.h
--- a/libpurple/protocols/jabber/jabber.h
+++ b/libpurple/protocols/jabber/jabber.h
@@ -50,7 +50,7 @@ typedef enum {
 	JABBER_CAP_ROSTER_VERSIONING = 1 << 15,
 
 	JABBER_CAP_FACEBOOK       = 1 << 16,
-
+	JABBER_MSG_DELIVERY       = 1 << 17,
 	JABBER_CAP_RETRIEVED      = 1 << 31
 } JabberCapabilities;
 
diff --git a/libpurple/protocols/jabber/message.c b/libpurple/protocols/jabber/message.c
--- a/libpurple/protocols/jabber/message.c
+++ b/libpurple/protocols/jabber/message.c
@@ -52,12 +52,54 @@ void jabber_message_free(JabberMessage *
 	g_free(jm->password);
 	g_free(jm->error);
 	g_free(jm->thread_id);
+	g_free(jm->receipt_id);
 	g_list_free(jm->etc);
 	g_list_free(jm->eventitems);
 
 	g_free(jm);
 }
 
+static GHashTable *pending_receipts;
+
+static void add_pending_receipt(JabberMessage *jm) {
+	if (!pending_receipts)
+        	pending_receipts = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
+
+	g_hash_table_insert(pending_receipts, g_strdup(jm->id), jm);
+}
+
+static gboolean remove_pending_receipt(JabberMessage *jm) {
+	JabberMessage *pending_msg;
+
+	if (!pending_receipts)
+		return FALSE;
+
+	pending_msg = (JabberMessage *) g_hash_table_lookup(pending_receipts, jm->id);
+	if (pending_msg != NULL) {
+		g_hash_table_remove(pending_receipts, jm->id);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void handle_receipt_request(JabberMessage *jm) {
+	JabberMessage *response;
+
+	response = g_new0(JabberMessage, 1);
+	response->type       = JABBER_MESSAGE_OTHER;
+	response->receipt    = TRUE;
+	response->delayed    = jm->delayed;
+	response->from       = g_strdup(jm->to);
+	response->to         = g_strdup(jm->from);
+	response->id         = jabber_get_next_id(jm->js);
+	response->receipt_id = g_strdup(jm->id);
+	response->chat_state = JM_STATE_NONE;
+	response->js         = g_memdup(jm->js, sizeof(*(jm->js)));
+
+	jabber_message_send(response);
+}
+
 static void handle_chat(JabberMessage *jm)
 {
 	JabberID *jid = jabber_id_new(jm->from);
@@ -152,6 +194,9 @@ static void handle_chat(JabberMessage *j
 			jbr->thread_id = g_strdup(jbr->thread_id);
 		}
 
+		if (jm->receipt)
+			handle_receipt_request(jm);
+
 		if (jm->js->googletalk && jm->xhtml == NULL) {
 			char *tmp = jm->body;
 			jm->body = jabber_google_format_to_html(jm->body);
@@ -552,7 +597,7 @@ void jabber_message_parse(JabberStream *
 {
 	JabberMessage *jm;
 	const char *id, *from, *to, *type;
-	PurpleXmlNode *child;
+	PurpleXmlNode *child, *sibling;
 	gboolean signal_return;
 
 	from = purple_xmlnode_get_attrib(packet, "from");
@@ -569,6 +614,7 @@ void jabber_message_parse(JabberStream *
 	jm->js = js;
 	jm->sent = time(NULL);
 	jm->delayed = FALSE;
+	jm->receipt = FALSE;
 	jm->chat_state = JM_STATE_NONE;
 
 	if(type) {
@@ -640,6 +686,19 @@ void jabber_message_parse(JabberStream *
 				char *msg = purple_xmlnode_get_data(child);
 				char *escaped = purple_markup_escape_text(msg, -1);
 				jm->body = purple_strdup_withhtml(escaped);
+				if (jm->type == JABBER_MESSAGE_NORMAL ||
+				    jm->type == JABBER_MESSAGE_CHAT)
+				{
+					for (sibling = packet->child; sibling; sibling = sibling->next) {
+						if (!strcmp(sibling->name, "request")) {
+							const char *sibling_xmlns = purple_xmlnode_get_namespace(sibling);
+							if (!strcmp(sibling_xmlns, "urn:xmpp:receipts")) {
+								jm->receipt = TRUE;
+								break;
+							}
+						}
+					}
+				}
 				g_free(escaped);
 				g_free(msg);
 			}
@@ -741,6 +800,10 @@ void jabber_message_parse(JabberStream *
 				jm->eventitems = g_list_append(jm->eventitems, items);
 		} else if(!strcmp(child->name, "attention") && !strcmp(xmlns, NS_ATTENTION)) {
 			jm->hasBuzz = TRUE;
+		} else if(!strcmp(child->name, "received") && !strcmp(xmlns, NS_MSG_DELIVERY)) {
+			const char *msg_id = purple_xmlnode_get_attrib(child, "id");
+			if (msg_id)
+				remove_pending_receipt(jm);
 		} else if(!strcmp(child->name, "delay") && !strcmp(xmlns, NS_DELAYED_DELIVERY)) {
 			const char *timestamp = purple_xmlnode_get_attrib(child, "stamp");
 			jm->delayed = TRUE;
@@ -1065,6 +1128,18 @@ void jabber_message_send(JabberMessage *
 	if(jm->body) {
 		child = purple_xmlnode_new_child(message, "body");
 		purple_xmlnode_insert_data(child, jm->body, -1);
+
+		if (jm->type == JABBER_MESSAGE_NORMAL || jm->type == JABBER_MESSAGE_CHAT) {
+			child = purple_xmlnode_new_child(message, "request");
+			purple_xmlnode_set_attrib(child, "xmlns", "urn:xmpp:receipts");
+		}
+	}
+
+	if (jm->receipt) {
+		child = purple_xmlnode_new_child(message, "received");
+		purple_xmlnode_set_attrib(child, "xmlns", "urn:xmpp:receipts");
+		purple_xmlnode_set_attrib(child, "id", jm->receipt_id);
+		add_pending_receipt(jm);
 	}
 
 	if(jm->xhtml) {
diff --git a/libpurple/protocols/jabber/message.h b/libpurple/protocols/jabber/message.h
--- a/libpurple/protocols/jabber/message.h
+++ b/libpurple/protocols/jabber/message.h
@@ -43,6 +43,7 @@ typedef struct _JabberMessage {
 	time_t sent;
 	gboolean delayed;
 	gboolean hasBuzz;
+	gboolean receipt;
 	char *id;
 	char *from;
 	char *to;
@@ -52,6 +53,7 @@ typedef struct _JabberMessage {
 	char *password;
 	char *error;
 	char *thread_id;
+	char *receipt_id;
 	enum {
 		JM_STATE_NONE,
 		JM_STATE_ACTIVE,
diff --git a/libpurple/protocols/jabber/namespaces.h b/libpurple/protocols/jabber/namespaces.h
--- a/libpurple/protocols/jabber/namespaces.h
+++ b/libpurple/protocols/jabber/namespaces.h
@@ -67,6 +67,9 @@
 /* XEP-0124 Bidirectional-streams Over Synchronous HTTP (BOSH) */
 #define NS_BOSH "http://jabber.org/protocol/httpbind"
 
+/* XEP-0184 Message Delivery Receipts */
+#define NS_MSG_DELIVERY "urn:xmpp:receipts"
+
 /* XEP-0191 Simple Communications Blocking */
 #define NS_SIMPLE_BLOCKING "urn:xmpp:blocking"
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.