changeset 17883:9a19c46adf66

The server's ad-hoc commands are now listed in the account's action menu. Note that this requires an additional field in the _PurplePluginAction struct. There's no other way, since there was no way to supply user_data, and dynamically created functions are not supported by C. This should be fine, since that struct is only malloced in purple_plugin_action_new, which is part of the core. Applications have to either pass the struct unmodified, or restore the user_data pointer if the action is recreated when necessary (as is the case in Adium).
author Andreas Monitzer <pidgin@monitzer.com>
date Mon, 25 Jun 2007 19:08:16 +0000
parents f88b3a093cba
children feac55968392
files libpurple/plugin.h libpurple/protocols/jabber/adhoccommands.c libpurple/protocols/jabber/adhoccommands.h libpurple/protocols/jabber/disco.c libpurple/protocols/jabber/jabber.c libpurple/protocols/jabber/jabber.h
diffstat 6 files changed, 101 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/plugin.h	Sat Jun 23 02:57:21 2007 +0000
+++ b/libpurple/plugin.h	Mon Jun 25 19:08:16 2007 +0000
@@ -184,6 +184,8 @@
 	/** NULL for plugin actions menu, set to the PurpleConnection for
 	    account actions menu */
 	gpointer context;
+	
+	gpointer user_data;
 };
 
 #define PURPLE_PLUGIN_HAS_ACTIONS(plugin) \
--- a/libpurple/protocols/jabber/adhoccommands.c	Sat Jun 23 02:57:21 2007 +0000
+++ b/libpurple/protocols/jabber/adhoccommands.c	Mon Jun 25 19:08:16 2007 +0000
@@ -199,3 +199,76 @@
 	}
 }
 
+static void jabber_adhoc_server_got_list_cb(JabberStream *js, xmlnode *packet, gpointer data) {
+	xmlnode *query = xmlnode_get_child_with_namespace(packet, "query", "http://jabber.org/protocol/disco#items");
+	xmlnode *item;
+	
+	if(!query)
+		return;
+
+	/* clean current list (just in case there is one) */
+	while(js->commands) {
+		JabberAdHocCommands *cmd = js->commands->data;
+		g_free(cmd->jid);
+		g_free(cmd->node);
+		g_free(cmd->node);
+		g_free(cmd);
+		js->commands = g_list_delete_link(js->commands, js->commands);
+	}
+	
+	/* re-fill list */
+	for(item = query->child; item; item = item->next) {
+		JabberAdHocCommands *cmd;
+		if(item->type != XMLNODE_TYPE_TAG)
+			continue;
+		if(strcmp(item->name, "item"))
+			continue;
+		cmd = g_new0(JabberAdHocCommands, 1);
+		cmd->jid = g_strdup(xmlnode_get_attrib(item,"jid"));
+		cmd->node = g_strdup(xmlnode_get_attrib(item,"node"));
+		cmd->name = g_strdup(xmlnode_get_attrib(item,"name"));
+		
+		js->commands = g_list_append(js->commands,cmd);
+	}
+}
+
+void jabber_adhoc_server_get_list(JabberStream *js) {
+	JabberIq *iq = jabber_iq_new_query(js,JABBER_IQ_GET,"http://jabber.org/protocol/disco#items");
+	xmlnode *query = xmlnode_get_child_with_namespace(iq->node,"query","http://jabber.org/protocol/disco#items");
+	
+	xmlnode_set_attrib(iq->node,"to",js->user->domain);
+	xmlnode_set_attrib(query,"node","http://jabber.org/protocol/commands");
+	
+	jabber_iq_set_callback(iq,jabber_adhoc_server_got_list_cb,NULL);
+	jabber_iq_send(iq);
+}
+
+void jabber_adhoc_server_execute(PurplePluginAction *action) {
+	JabberAdHocCommands *cmd = action->user_data;
+	if(cmd) {
+		PurpleConnection *gc = (PurpleConnection *) action->context;
+		JabberStream *js = gc->proto_data;
+		
+		JabberIq *iq = jabber_iq_new(js, JABBER_IQ_SET);
+		xmlnode *command = xmlnode_new_child(iq->node,"command");
+		xmlnode_set_attrib(iq->node,"to",cmd->jid);
+		xmlnode_set_namespace(command,"http://jabber.org/protocol/commands");
+		xmlnode_set_attrib(command,"node",cmd->node);
+		xmlnode_set_attrib(command,"action","execute");
+		
+		/* we don't need to set a callback, since jabber_adhoc_parse is run for all replies */
+		
+		jabber_iq_send(iq);
+	}
+}
+
+void jabber_adhoc_init_server_commands(JabberStream *js, GList **m) {
+	GList *cmdlst;
+	
+	for(cmdlst = js->commands; cmdlst; cmdlst = g_list_next(cmdlst)) {
+		JabberAdHocCommands *cmd = cmdlst->data;
+		PurplePluginAction *act = purple_plugin_action_new(cmd->name, jabber_adhoc_server_execute);
+		act->user_data = cmd;
+		*m = g_list_append(*m, act);
+	}
+}
--- a/libpurple/protocols/jabber/adhoccommands.h	Sat Jun 23 02:57:21 2007 +0000
+++ b/libpurple/protocols/jabber/adhoccommands.h	Mon Jun 25 19:08:16 2007 +0000
@@ -32,4 +32,8 @@
 
 void jabber_adhoc_execute(PurpleBlistNode *node, gpointer data);
 
+void jabber_adhoc_server_get_list(JabberStream *js);
+
+void jabber_adhoc_init_server_commands(JabberStream *js, GList **m);
+
 #endif /* _PURPLE_JABBER_ADHOCCOMMANDS_H_ */
--- a/libpurple/protocols/jabber/disco.c	Sat Jun 23 02:57:21 2007 +0000
+++ b/libpurple/protocols/jabber/disco.c	Mon Jun 25 19:08:16 2007 +0000
@@ -281,6 +281,11 @@
 	gpresence = purple_account_get_presence(js->gc->account);
 	status = purple_presence_get_active_status(gpresence);
 	jabber_presence_send(js->gc->account, status);
+	
+	if (js->server_caps & JABBER_CAP_ADHOC) {
+		/* The server supports ad-hoc commands, so let's request the list */
+		jabber_adhoc_server_get_list(js);
+	}
 }
 
 static void
@@ -346,6 +351,8 @@
 		} else if (!strcmp("google:roster", var)) {
 			js->server_caps |= JABBER_CAP_GOOGLE_ROSTER;
 			jabber_google_roster_init(js);
+		} else if (!strcmp("http://jabber.org/protocol/commands", var)) {
+			js->server_caps |= JABBER_CAP_ADHOC;
 		}
 	}
 
--- a/libpurple/protocols/jabber/jabber.c	Sat Jun 23 02:57:21 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.c	Mon Jun 25 19:08:16 2007 +0000
@@ -55,6 +55,7 @@
 #include "si.h"
 #include "xdata.h"
 #include "pep.h"
+#include "adhoccommands.h"
 
 #include <assert.h>
 
@@ -1115,6 +1116,14 @@
 #endif
 	if(js->serverFQDN)
 		g_free(js->serverFQDN);
+	while(js->commands) {
+		JabberAdHocCommands *cmd = js->commands->data;
+		g_free(cmd->jid);
+		g_free(cmd->node);
+		g_free(cmd->node);
+		g_free(cmd);
+		js->commands = g_list_delete_link(js->commands, js->commands);
+	}
 	g_free(js->server_name);
 	g_free(js->gmail_last_time);
 	g_free(js->gmail_last_tid);
@@ -1632,6 +1641,9 @@
 
 	if(js->pep)
 		jabber_pep_init_actions(&m);
+	
+	if(js->commands)
+		jabber_adhoc_init_server_commands(js, &m);
 
 	return m;
 }
--- a/libpurple/protocols/jabber/jabber.h	Sat Jun 23 02:57:21 2007 +0000
+++ b/libpurple/protocols/jabber/jabber.h	Mon Jun 25 19:08:16 2007 +0000
@@ -158,6 +158,9 @@
 	/* does the local server support PEP? */
 	gboolean pep;
 	
+	/* A list of JabberAdHocCommands supported by the server */
+	GList *commands;
+	
 	/* last presence update to check for differences */
 	JabberBuddyState old_state;
 	char *old_msg;