# HG changeset patch # User Andreas Monitzer # Date 1182221604 0 # Node ID 43df079680003f7dca4215613f649ecf082087e3 # Parent 5f4dcaf1f8866ccaf219a0e3104248186ddd1e88 Implemented XEP-0050: Ad-Hoc Commands. Note that this XEP requires sending an initial command to the peer, which is not implemented in libpurple itself (since this requires a discovery browser or equivalent). diff -r 5f4dcaf1f886 -r 43df07968000 libpurple/protocols/jabber/adhoccommands.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/adhoccommands.c Tue Jun 19 02:53:24 2007 +0000 @@ -0,0 +1,130 @@ +/* + * purple - Jabber Protocol Plugin + * + * Copyright (C) 2007, Andreas Monitzer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "adhoccommands.h" +#include +#include +#include "internal.h" +#include "xdata.h" +#include "iq.h" +#include "request.h" + +static void do_adhoc_ignoreme(JabberStream *js, ...) { + /* we don't have to do anything */ +} + +typedef struct _JabberAdHocActionInfo { + char *sessionid; + char *who; + char *node; + GList *actionslist; +} JabberAdHocActionInfo; + +/*static void do_adhoc_parse_iq(JabberStream *js, xmlnode *packet, gpointer data) { + jabber_adhoc_parse(js, packet); +}*/ + +static void do_adhoc_action_cb(JabberStream *js, xmlnode *result, const char *actionhandle, gpointer user_data) { + xmlnode *command; + GList *action; + JabberAdHocActionInfo *actionInfo = user_data; + JabberIq *iq = jabber_iq_new(js, JABBER_IQ_SET); +/* jabber_iq_set_callback(iq, do_adhoc_parse_iq, NULL);*/ + + xmlnode_set_attrib(iq->node, "to", actionInfo->who); + command = xmlnode_new_child(iq->node,"command"); + xmlnode_set_namespace(command,"http://jabber.org/protocol/commands"); + xmlnode_set_attrib(command,"sessionid",actionInfo->sessionid); + xmlnode_set_attrib(command,"node",actionInfo->node); + if(actionhandle) + xmlnode_set_attrib(command,"action",actionhandle); + xmlnode_insert_child(command,result); + + for(action = actionInfo->actionslist; action; action = g_list_next(action)) { + char *handle = action->data; + g_free(handle); + } + g_list_free(actionInfo->actionslist); + g_free(actionInfo->sessionid); + g_free(actionInfo->who); + g_free(actionInfo->node); + + jabber_iq_send(iq); +} + +void jabber_adhoc_parse(JabberStream *js, xmlnode *packet) { + xmlnode *command = xmlnode_get_child_with_namespace(packet, "command", "http://jabber.org/protocol/commands"); + const char *status = xmlnode_get_attrib(command,"status"); + xmlnode *xdata = xmlnode_get_child_with_namespace(command,"x","jabber:x:data"); + + if(!status) + return; + + if(!strcmp(status,"completed")) { + /* display result */ + xmlnode *note = xmlnode_get_child(command,"note"); + + if(note) + purple_request_action(js, xmlnode_get_attrib(packet, "from"), xmlnode_get_data(note), NULL, 0, purple_connection_get_account(js->gc), xmlnode_get_attrib(packet, "from"), NULL, NULL, 1, _("OK"), do_adhoc_ignoreme); + + if(xdata) + jabber_x_data_request(js, xdata, (jabber_x_data_cb)do_adhoc_ignoreme, NULL); + return; + } + if(!strcmp(status,"executing")) { + /* this command needs more steps */ + xmlnode *actions, *action; + int actionindex = 0; + GList *actionslist = NULL; + JabberAdHocActionInfo *actionInfo; + if(!xdata) + return; /* shouldn't happen */ + + actions = xmlnode_get_child(command,"actions"); + if(!actions) { + JabberXDataAction *defaultaction = g_new0(JabberXDataAction, 1); + defaultaction->name = g_strdup(_("execute")); + defaultaction->handle = g_strdup("execute"); + actionslist = g_list_append(actionslist, defaultaction); + } else { + const char *defaultactionhandle = xmlnode_get_attrib(actions, "execute"); + int index = 0; + for(action = actions->child; action; action = action->next, ++index) { + if(action->type == XMLNODE_TYPE_TAG) { + JabberXDataAction *newaction = g_new0(JabberXDataAction, 1); + newaction->name = g_strdup(_(action->name)); + newaction->handle = g_strdup(action->name); + actionslist = g_list_append(actionslist, newaction); + if(defaultactionhandle && !strcmp(defaultactionhandle, action->name)) + actionindex = index; + } + } + } + + actionInfo = g_new0(JabberAdHocActionInfo, 1); + actionInfo->sessionid = g_strdup(xmlnode_get_attrib(command,"sessionid")); + actionInfo->who = g_strdup(xmlnode_get_attrib(packet,"from")); + actionInfo->node = g_strdup(xmlnode_get_attrib(command,"node")); + actionInfo->actionslist = actionslist; + + jabber_x_data_request_with_actions(js,xdata,actionslist,actionindex,do_adhoc_action_cb,actionInfo); + } +} diff -r 5f4dcaf1f886 -r 43df07968000 libpurple/protocols/jabber/adhoccommands.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/jabber/adhoccommands.h Tue Jun 19 02:53:24 2007 +0000 @@ -0,0 +1,31 @@ +/* + * purple - Jabber Protocol Plugin + * + * Copyright (C) 2007, Andreas Monitzer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef _PURPLE_JABBER_ADHOCCOMMANDS_H_ +#define _PURPLE_JABBER_ADHOCCOMMANDS_H_ + +#include "jabber.h" + +/* Implementation of XEP-0050 */ + +void jabber_adhoc_parse(JabberStream *js, xmlnode *packet); + +#endif /* _PURPLE_JABBER_ADHOCCOMMANDS_H_ */ diff -r 5f4dcaf1f886 -r 43df07968000 libpurple/protocols/jabber/iq.c --- a/libpurple/protocols/jabber/iq.c Mon Jun 18 15:05:39 2007 +0000 +++ b/libpurple/protocols/jabber/iq.c Tue Jun 19 02:53:24 2007 +0000 @@ -31,6 +31,7 @@ #include "roster.h" #include "si.h" #include "ping.h" +#include "adhoccommands.h" #ifdef _WIN32 #include "utsname.h" @@ -290,6 +291,11 @@ jabber_gmail_poke(js, packet); return; } + + if(xmlnode_get_child_with_namespace(packet, "command", "http://jabber.org/protocol/commands")) { + jabber_adhoc_parse(js, packet); + return; + } purple_debug_info("jabber", "jabber_iq_parse\n"); diff -r 5f4dcaf1f886 -r 43df07968000 libpurple/protocols/jabber/xdata.c --- a/libpurple/protocols/jabber/xdata.c Mon Jun 18 15:05:39 2007 +0000 +++ b/libpurple/protocols/jabber/xdata.c Tue Jun 19 02:53:24 2007 +0000 @@ -37,22 +37,39 @@ struct jabber_x_data_data { GHashTable *fields; GSList *values; - jabber_x_data_cb cb; + jabber_x_data_action_cb cb; gpointer user_data; JabberStream *js; + GList *actions; + PurpleRequestFieldGroup *actiongroup; }; static void jabber_x_data_ok_cb(struct jabber_x_data_data *data, PurpleRequestFields *fields) { xmlnode *result = xmlnode_new("x"); - jabber_x_data_cb cb = data->cb; + jabber_x_data_action_cb cb = data->cb; gpointer user_data = data->user_data; JabberStream *js = data->js; GList *groups, *flds; + char *actionhandle = NULL; + gboolean hasActions = (data->actions != NULL); xmlnode_set_namespace(result, "jabber:x:data"); xmlnode_set_attrib(result, "type", "submit"); for(groups = purple_request_fields_get_groups(fields); groups; groups = groups->next) { + if(groups->data == data->actiongroup) { + for(flds = purple_request_field_group_get_fields(groups->data); flds; flds = flds->next) { + PurpleRequestField *field = flds->data; + const char *id = purple_request_field_get_id(field); + int handleindex; + if(strcmp(id, "libpurple:jabber:xdata:actions")) + continue; + handleindex = purple_request_field_choice_get_value(field); + actionhandle = g_strdup(g_list_nth_data(data->actions, handleindex)); + break; + } + continue; + } for(flds = purple_request_field_group_get_fields(groups->data); flds; flds = flds->next) { xmlnode *fieldnode, *valuenode; PurpleRequestField *field = flds->data; @@ -127,31 +144,59 @@ g_free(data->values->data); data->values = g_slist_delete_link(data->values, data->values); } + if (data->actions) { + GList *action; + for(action = data->actions; action; action = g_list_next(action)) { + g_free(action->data); + } + g_list_free(data->actions); + } g_free(data); - cb(js, result, user_data); + if (hasActions) { + cb(js, result, actionhandle, user_data); + g_free(actionhandle); + } else + ((jabber_x_data_cb)cb)(js, result, user_data); } static void jabber_x_data_cancel_cb(struct jabber_x_data_data *data, PurpleRequestFields *fields) { xmlnode *result = xmlnode_new("x"); - jabber_x_data_cb cb = data->cb; + jabber_x_data_action_cb cb = data->cb; gpointer user_data = data->user_data; JabberStream *js = data->js; + gboolean hasActions = FALSE; g_hash_table_destroy(data->fields); while(data->values) { g_free(data->values->data); data->values = g_slist_delete_link(data->values, data->values); } + if (data->actions) { + hasActions = TRUE; + GList *action; + for(action = data->actions; action; action = g_list_next(action)) { + g_free(action->data); + } + g_list_free(data->actions); + } g_free(data); xmlnode_set_namespace(result, "jabber:x:data"); xmlnode_set_attrib(result, "type", "cancel"); - cb(js, result, user_data); + if (hasActions) + cb(js, result, NULL, user_data); + else + ((jabber_x_data_cb)cb)(js, result, user_data); } void *jabber_x_data_request(JabberStream *js, xmlnode *packet, jabber_x_data_cb cb, gpointer user_data) { + return jabber_x_data_request_with_actions(js, packet, NULL, 0, (jabber_x_data_action_cb)cb, user_data); +} + +void *jabber_x_data_request_with_actions(JabberStream *js, xmlnode *packet, GList *actions, int defaultaction, jabber_x_data_action_cb cb, gpointer user_data) +{ void *handle; xmlnode *fn, *x; PurpleRequestFields *fields; @@ -326,6 +371,23 @@ if(field && xmlnode_get_child(fn, "required")) purple_request_field_set_required(field,TRUE); } + + if(actions != NULL) { + PurpleRequestField *actionfield; + GList *action; + data->actiongroup = group = purple_request_field_group_new(_("Actions")); + purple_request_fields_add_group(fields, group); + actionfield = purple_request_field_choice_new("libpurple:jabber:xdata:actions", _("Select an action"), defaultaction); + + for(action = actions; action; action = g_list_next(action)) { + JabberXDataAction *a = action->data; + + purple_request_field_choice_add(actionfield, a->name); + data->actions = g_list_append(data->actions, g_strdup(a->handle)); + } + purple_request_field_set_required(actionfield,TRUE); + purple_request_field_group_add_field(group, actionfield); + } if((x = xmlnode_get_child(packet, "title"))) title = xmlnode_get_data(x); diff -r 5f4dcaf1f886 -r 43df07968000 libpurple/protocols/jabber/xdata.h --- a/libpurple/protocols/jabber/xdata.h Mon Jun 18 15:05:39 2007 +0000 +++ b/libpurple/protocols/jabber/xdata.h Tue Jun 19 02:53:24 2007 +0000 @@ -25,7 +25,14 @@ #include "jabber.h" #include "xmlnode.h" +typedef struct _JabberXDataAction { + char *name; + char *handle; +} JabberXDataAction; + typedef void (*jabber_x_data_cb)(JabberStream *js, xmlnode *result, gpointer user_data); +typedef void (*jabber_x_data_action_cb)(JabberStream *js, xmlnode *result, const char *actionhandle, gpointer user_data); void *jabber_x_data_request(JabberStream *js, xmlnode *packet, jabber_x_data_cb cb, gpointer user_data); +void *jabber_x_data_request_with_actions(JabberStream *js, xmlnode *packet, GList *actions, int defaultaction, jabber_x_data_action_cb cb, gpointer user_data); #endif /* _PURPLE_JABBER_XDATA_H_ */