changeset 26870:92565c8e1e3a

Add jabber signals for IQ, Message, and Presence stanzas. Lightly tested (it doesn't crash [Prove me wrong!]) and as you'll note, I refer to documentation that doesn't yet exist.
author Paul Aurich <paul@darkrain42.org>
date Tue, 12 May 2009 05:49:34 +0000
parents 329f5a43b68a
children f47f6f6ba439
files ChangeLog.API libpurple/protocols/jabber/iq.c libpurple/protocols/jabber/iq.h libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/jabber.h libpurple/protocols/jabber/libxmpp.c libpurple/protocols/jabber/message.c libpurple/protocols/jabber/presence.c
diffstat 8 files changed, 161 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog.API	Mon May 11 22:05:00 2009 +0000
+++ b/ChangeLog.API	Tue May 12 05:49:34 2009 +0000
@@ -15,6 +15,7 @@
 			* account-destroying
 		* blist-node-added and blist-node-removed signals (see
 		  blist-signals.dox)
+		* Jabber plugin signals (see jabber-signals.dox)
 		* purple_buddy_destroy
 		* purple_buddy_get_protocol_data
 		* purple_buddy_set_protocol_data
--- a/libpurple/protocols/jabber/iq.c	Mon May 11 22:05:00 2009 +0000
+++ b/libpurple/protocols/jabber/iq.c	Tue May 12 05:49:34 2009 +0000
@@ -42,7 +42,7 @@
 #endif
 
 GHashTable *iq_handlers = NULL;
-
+GHashTable *signal_iq_handlers = NULL;
 
 JabberIq *jabber_iq_new(JabberStream *js, JabberIqType type)
 {
@@ -289,6 +289,16 @@
 	const char *xmlns;
 	const char *iq_type, *id, *from;
 	JabberIqType type = JABBER_IQ_NONE;
+	gboolean signal_return;
+
+	from = xmlnode_get_attrib(packet, "from");
+	id = xmlnode_get_attrib(packet, "id");
+	iq_type = xmlnode_get_attrib(packet, "type");
+
+	signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin,
+			"jabber-receiving-iq", js->gc, iq_type, id, from, packet));
+	if (signal_return)
+		return;
 
 	/*
 	 * child will be either the first tag child or NULL if there is no child.
@@ -301,10 +311,6 @@
 			break;
 	}
 
-	iq_type = xmlnode_get_attrib(packet, "type");
-	from = xmlnode_get_attrib(packet, "from");
-	id = xmlnode_get_attrib(packet, "id");
-
 	if (iq_type) {
 		if (!strcmp(iq_type, "get"))
 			type = JABBER_IQ_GET;
@@ -361,12 +367,23 @@
 		}
 	}
 
-	/* Apparently not, so lets see if we have a pre-defined handler */
+	/*
+	 * Apparently not, so let's see if we have a pre-defined handler
+	 * or if an outside plugin is interested.
+	 */
 	if(child && (xmlns = xmlnode_get_namespace(child))) {
 		char *key = g_strdup_printf("%s %s", child->name, xmlns);
 		JabberIqHandler *jih = g_hash_table_lookup(iq_handlers, key);
+		int signal_ref = GPOINTER_TO_INT(g_hash_table_lookup(signal_iq_handlers, key));
 		g_free(key);
 
+		if (signal_ref > 0) {
+			signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin, "jabber-watched-iq",
+					js->gc, iq_type, id, from, child));
+			if (signal_return)
+				return;
+		}
+
 		if(jih) {
 			jih(js, from, type, id, child);
 			return;
@@ -408,9 +425,48 @@
 	g_hash_table_replace(iq_handlers, key, handlerfunc);
 }
 
+void jabber_iq_signal_register(const gchar *node, const gchar *xmlns)
+{
+	gchar *key;
+	int ref;
+
+	g_return_if_fail(node != NULL && *node != '\0');
+	g_return_if_fail(xmlns != NULL && *xmlns != '\0');
+
+	key = g_strdup_printf("%s %s", node, xmlns);
+	ref = GPOINTER_TO_INT(g_hash_table_lookup(signal_iq_handlers, key));
+	if (ref == 0) {
+		g_hash_table_insert(signal_iq_handlers, key, GINT_TO_POINTER(1));
+	} else {
+		g_hash_table_insert(signal_iq_handlers, key, GINT_TO_POINTER(ref + 1));
+		g_free(key);
+	}
+}
+
+void jabber_iq_signal_unregister(const gchar *node, const gchar *xmlns)
+{
+	gchar *key;
+	int ref;
+
+	g_return_if_fail(node != NULL && *node != '\0');
+	g_return_if_fail(xmlns != NULL && *xmlns != '\0');
+
+	key = g_strdup_printf("%s %s", node, xmlns);
+	ref = GPOINTER_TO_INT(g_hash_table_lookup(signal_iq_handlers, key));
+
+	if (ref == 1) {
+		g_hash_table_remove(signal_iq_handlers, key);
+	} else if (ref > 1) {
+		g_hash_table_insert(signal_iq_handlers, key, GINT_TO_POINTER(ref - 1));
+	}
+
+	g_free(key);
+}
+
 void jabber_iq_init(void)
 {
 	iq_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
+	signal_iq_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
 
 	jabber_iq_register_handler("jingle", JINGLE, jingle_parse);
 	jabber_iq_register_handler("mailbox", "google:mail:notify",
@@ -446,5 +502,6 @@
 void jabber_iq_uninit(void)
 {
 	g_hash_table_destroy(iq_handlers);
-	iq_handlers = NULL;
+	g_hash_table_destroy(signal_iq_handlers);
+	iq_handlers = signal_iq_handlers = NULL;
 }
--- a/libpurple/protocols/jabber/iq.h	Mon May 11 22:05:00 2009 +0000
+++ b/libpurple/protocols/jabber/iq.h	Tue May 12 05:49:34 2009 +0000
@@ -31,6 +31,7 @@
 } JabberIqType;
 
 #include "jabber.h"
+#include "connection.h"
 
 typedef struct _JabberIq JabberIq;
 
@@ -106,4 +107,8 @@
 void jabber_iq_register_handler(const char *node, const char *xmlns,
                                 JabberIqHandler *func);
 
+/* Connected to namespace-handler registration signals */
+void jabber_iq_signal_register(const gchar *node, const gchar *xmlns);
+void jabber_iq_signal_unregister(const gchar *node, const gchar *xmlns);
+
 #endif /* PURPLE_JABBER_IQ_H_ */
--- a/libpurple/protocols/jabber/jabber.c	Mon May 11 22:05:00 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Tue May 12 05:49:34 2009 +0000
@@ -3380,6 +3380,7 @@
 							 purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_ACCOUNT),
 							 purple_value_new(PURPLE_TYPE_STRING),
 							 purple_value_new(PURPLE_TYPE_STRING));
+
 	purple_plugin_ipc_register(plugin, "add_feature", PURPLE_CALLBACK(jabber_ipc_add_feature),
 							 purple_marshal_VOID__POINTER,
 							 NULL, 1,
@@ -3389,6 +3390,8 @@
 void
 jabber_uninit_plugin(void)
 {
+	purple_plugin_ipc_unregister_all(jabber_plugin);
+
 	jabber_features_destroy();
 	jabber_identities_destroy();
 }
--- a/libpurple/protocols/jabber/jabber.h	Mon May 11 22:05:00 2009 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Tue May 12 05:49:34 2009 +0000
@@ -75,6 +75,8 @@
 /* Index into attention_types list */
 #define JABBER_BUZZ 0
 
+PurplePlugin *jabber_plugin;
+
 typedef enum {
 	JABBER_STREAM_OFFLINE,
 	JABBER_STREAM_CONNECTING,
--- a/libpurple/protocols/jabber/libxmpp.c	Mon May 11 22:05:00 2009 +0000
+++ b/libpurple/protocols/jabber/libxmpp.c	Tue May 12 05:49:34 2009 +0000
@@ -46,6 +46,8 @@
 #include "data.h"
 #include "ibb.h"
 
+PurplePlugin *jabber_plugin = NULL;
+
 static PurplePluginProtocolInfo prpl_info =
 {
 	OPT_PROTO_CHAT_TOPIC | OPT_PROTO_UNIQUE_CHATNAME | OPT_PROTO_MAIL_CHECK |
@@ -125,6 +127,8 @@
 
 static gboolean load_plugin(PurplePlugin *plugin)
 {
+	jabber_plugin = plugin;
+
 	purple_signal_register(plugin, "jabber-receiving-xmlnode",
 			purple_marshal_VOID__POINTER_POINTER, NULL, 2,
 			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
@@ -140,16 +144,65 @@
 			     purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
 			     purple_value_new_outgoing(PURPLE_TYPE_STRING));
 
+	purple_signal_register(plugin, "jabber-receiving-message",
+			purple_marshal_BOOLEAN__POINTER_POINTER_POINTER,
+			purple_value_new(PURPLE_TYPE_BOOLEAN), 6,
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			purple_value_new(PURPLE_TYPE_STRING), /* type */
+			purple_value_new(PURPLE_TYPE_STRING), /* id */
+			purple_value_new(PURPLE_TYPE_STRING), /* from */
+			purple_value_new(PURPLE_TYPE_STRING), /* to */
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE));
+
+	purple_signal_register(plugin, "jabber-receiving-iq",
+			purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
+			purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			purple_value_new(PURPLE_TYPE_STRING), /* type */
+			purple_value_new(PURPLE_TYPE_STRING), /* id */
+			purple_value_new(PURPLE_TYPE_STRING), /* from */
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE));
+
+	purple_signal_register(plugin, "jabber-watched-iq",
+			purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER_POINTER,
+			purple_value_new(PURPLE_TYPE_BOOLEAN), 5,
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			purple_value_new(PURPLE_TYPE_STRING), /* type */
+			purple_value_new(PURPLE_TYPE_STRING), /* id */
+			purple_value_new(PURPLE_TYPE_STRING), /* from */
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE)); /* child */
+
+	purple_signal_register(plugin, "jabber-register-namespace-watcher",
+			purple_marshal_VOID__POINTER_POINTER_POINTER,
+			NULL, 2,
+			purple_value_new(PURPLE_TYPE_STRING),  /* node */
+			purple_value_new(PURPLE_TYPE_STRING)); /* namespace */
+
+	purple_signal_register(plugin, "jabber-unregister-namespace-watcher",
+			purple_marshal_VOID__POINTER_POINTER_POINTER,
+			NULL, 2,
+			purple_value_new(PURPLE_TYPE_STRING),  /* node */
+			purple_value_new(PURPLE_TYPE_STRING)); /* namespace */
+
+	purple_signal_connect(plugin, "jabber-register-namespace-watcher",
+			plugin, PURPLE_CALLBACK(jabber_iq_signal_register), NULL);
+	purple_signal_connect(plugin, "jabber-unregister-namespace-watcher",
+			plugin, PURPLE_CALLBACK(jabber_iq_signal_unregister), NULL);
+
+	purple_signal_register(plugin, "jabber-receiving-presence",
+			purple_marshal_BOOLEAN__POINTER_POINTER_POINTER_POINTER,
+			purple_value_new(PURPLE_TYPE_BOOLEAN), 4,
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_CONNECTION),
+			purple_value_new(PURPLE_TYPE_STRING), /* type */
+			purple_value_new(PURPLE_TYPE_STRING), /* from */
+			purple_value_new(PURPLE_TYPE_SUBTYPE, PURPLE_SUBTYPE_XMLNODE));
+
 	return TRUE;
 }
 
 static gboolean unload_plugin(PurplePlugin *plugin)
 {
-	purple_signal_unregister(plugin, "jabber-receiving-xmlnode");
-
-	purple_signal_unregister(plugin, "jabber-sending-xmlnode");
-
-	purple_signal_unregister(plugin, "jabber-sending-text");
+	purple_signals_unregister_by_instance(plugin);
 
 	/* reverse order of init_plugin */
 	jabber_bosh_uninit();
@@ -166,6 +219,8 @@
 	/* Stay on target...stay on target... Almost there... */
 	jabber_uninit_plugin();
 
+	jabber_plugin = NULL;
+
 	return TRUE;
 }
 
--- a/libpurple/protocols/jabber/message.c	Mon May 11 22:05:00 2009 +0000
+++ b/libpurple/protocols/jabber/message.c	Tue May 12 05:49:34 2009 +0000
@@ -532,16 +532,25 @@
 void jabber_message_parse(JabberStream *js, xmlnode *packet)
 {
 	JabberMessage *jm;
-	const char *type;
+	const char *id, *from, *to, *type;
 	xmlnode *child;
+	gboolean signal_return;
+
+	from = xmlnode_get_attrib(packet, "from");
+	id   = xmlnode_get_attrib(packet, "id");
+	to   = xmlnode_get_attrib(packet, "to");
+	type = xmlnode_get_attrib(packet, "type");
+
+	signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin,
+			"jabber-receiving-message", js->gc, type, id, from, to, packet));
+	if (signal_return)
+		return;
 
 	jm = g_new0(JabberMessage, 1);
 	jm->js = js;
 	jm->sent = time(NULL);
 	jm->delayed = FALSE;
 
-	type = xmlnode_get_attrib(packet, "type");
-
 	if(type) {
 		if(!strcmp(type, "normal"))
 			jm->type = JABBER_MESSAGE_NORMAL;
@@ -559,9 +568,9 @@
 		jm->type = JABBER_MESSAGE_NORMAL;
 	}
 
-	jm->from = g_strdup(xmlnode_get_attrib(packet, "from"));
-	jm->to = g_strdup(xmlnode_get_attrib(packet, "to"));
-	jm->id = g_strdup(xmlnode_get_attrib(packet, "id"));
+	jm->from = g_strdup(from);
+	jm->to   = g_strdup(to);
+	jm->id   = g_strdup(id);
 
 	for(child = packet->child; child; child = child->next) {
 		const char *xmlns = xmlnode_get_namespace(child);
--- a/libpurple/protocols/jabber/presence.c	Mon May 11 22:05:00 2009 +0000
+++ b/libpurple/protocols/jabber/presence.c	Tue May 12 05:49:34 2009 +0000
@@ -446,8 +446,8 @@
 
 void jabber_presence_parse(JabberStream *js, xmlnode *packet)
 {
-	const char *from = xmlnode_get_attrib(packet, "from");
-	const char *type = xmlnode_get_attrib(packet, "type");
+	const char *from;
+	const char *type;
 	const char *real_jid = NULL;
 	const char *affiliation = NULL;
 	const char *role = NULL;
@@ -469,10 +469,19 @@
 	xmlnode *caps = NULL;
 	int idle = 0;
 	gchar *nickname = NULL;
+	gboolean signal_return;
+
+	from = xmlnode_get_attrib(packet, "from");
+	type = xmlnode_get_attrib(packet, "type");
 
 	if(!(jb = jabber_buddy_find(js, from, TRUE)))
 		return;
 
+	signal_return = GPOINTER_TO_INT(purple_signal_emit_return_1(jabber_plugin,
+			"jabber-receiving-presence", js->gc, type, from, packet));
+	if (signal_return)
+		return;
+
 	if(!(jid = jabber_id_new(from)))
 		return;