2 * purple - Jabber Protocol Plugin
4 * Purple is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 #include "adhoccommands.h"
33 static void do_adhoc_ignoreme(JabberStream
*js
, ...) {
34 /* we don't have to do anything */
37 typedef struct _JabberAdHocActionInfo
{
42 } JabberAdHocActionInfo
;
45 jabber_adhoc_got_buddy_list(JabberStream
*js
, const char *from
, PurpleXmlNode
*query
)
49 JabberBuddyResource
*jbr
= NULL
;
52 if ((jid
= jabber_id_new(from
))) {
53 if (jid
->resource
&& (jb
= jabber_buddy_find(js
, from
, TRUE
)))
54 jbr
= jabber_buddy_find_resource(jb
, jid
->resource
);
62 /* since the list we just received is complete, wipe the old one */
63 while(jbr
->commands
) {
64 JabberAdHocCommands
*cmd
= jbr
->commands
->data
;
69 jbr
->commands
= g_list_delete_link(jbr
->commands
, jbr
->commands
);
73 for(item
= query
->child
; item
; item
= item
->next
) {
74 JabberAdHocCommands
*cmd
;
75 if(item
->type
!= PURPLE_XMLNODE_TYPE_TAG
)
77 if(strcmp(item
->name
, "item"))
79 cmd
= g_new0(JabberAdHocCommands
, 1);
81 cmd
->jid
= g_strdup(purple_xmlnode_get_attrib(item
,"jid"));
82 cmd
->node
= g_strdup(purple_xmlnode_get_attrib(item
,"node"));
83 cmd
->name
= g_strdup(purple_xmlnode_get_attrib(item
,"name"));
85 jbr
->commands
= g_list_append(jbr
->commands
,cmd
);
90 jabber_adhoc_disco_result_cb(JabberStream
*js
, const char *from
,
91 JabberIqType type
, const char *id
,
92 PurpleXmlNode
*packet
, gpointer data
)
97 if (type
== JABBER_IQ_ERROR
)
100 query
= purple_xmlnode_get_child_with_namespace(packet
, "query", NS_DISCO_ITEMS
);
103 node
= purple_xmlnode_get_attrib(query
, "node");
104 if (!purple_strequal(node
, "http://jabber.org/protocol/commands"))
107 jabber_adhoc_got_buddy_list(js
, from
, query
);
110 static void jabber_adhoc_parse(JabberStream
*js
, const char *from
,
111 JabberIqType type
, const char *id
,
112 PurpleXmlNode
*packet
, gpointer data
);
114 static void do_adhoc_action_cb(JabberStream
*js
, PurpleXmlNode
*result
, const char *actionhandle
, gpointer user_data
) {
115 PurpleXmlNode
*command
;
117 JabberAdHocActionInfo
*actionInfo
= user_data
;
118 JabberIq
*iq
= jabber_iq_new(js
, JABBER_IQ_SET
);
119 jabber_iq_set_callback(iq
, jabber_adhoc_parse
, NULL
);
121 purple_xmlnode_set_attrib(iq
->node
, "to", actionInfo
->who
);
122 command
= purple_xmlnode_new_child(iq
->node
,"command");
123 purple_xmlnode_set_namespace(command
,"http://jabber.org/protocol/commands");
124 purple_xmlnode_set_attrib(command
,"sessionid",actionInfo
->sessionid
);
125 purple_xmlnode_set_attrib(command
,"node",actionInfo
->node
);
127 /* cancel is handled differently on ad-hoc commands than regular forms */
128 if (purple_strequal(purple_xmlnode_get_namespace(result
), "jabber:x:data") &&
129 purple_strequal(purple_xmlnode_get_attrib(result
, "type"), "cancel")) {
130 purple_xmlnode_set_attrib(command
,"action","cancel");
133 purple_xmlnode_set_attrib(command
,"action",actionhandle
);
134 purple_xmlnode_insert_child(command
,result
);
137 for(action
= actionInfo
->actionslist
; action
; action
= g_list_next(action
)) {
138 char *handle
= action
->data
;
141 g_list_free(actionInfo
->actionslist
);
142 g_free(actionInfo
->sessionid
);
143 g_free(actionInfo
->who
);
144 g_free(actionInfo
->node
);
150 jabber_adhoc_parse(JabberStream
*js
, const char *from
,
151 JabberIqType type
, const char *id
,
152 PurpleXmlNode
*packet
, gpointer data
)
154 PurpleXmlNode
*command
= purple_xmlnode_get_child_with_namespace(packet
, "command", "http://jabber.org/protocol/commands");
155 const char *status
= purple_xmlnode_get_attrib(command
,"status");
156 PurpleXmlNode
*xdata
= purple_xmlnode_get_child_with_namespace(command
,"x","jabber:x:data");
158 if (type
== JABBER_IQ_ERROR
) {
159 char *msg
= jabber_parse_error(js
, packet
, NULL
);
161 msg
= g_strdup(_("Unknown Error"));
163 purple_notify_error(NULL
, _("Ad-Hoc Command Failed"),
164 _("Ad-Hoc Command Failed"), msg
,
165 purple_request_cpar_from_connection(js
->gc
));
173 if(!strcmp(status
,"completed")) {
175 PurpleXmlNode
*note
= purple_xmlnode_get_child(command
,"note");
178 char *data
= purple_xmlnode_get_data(note
);
179 purple_notify_info(NULL
, from
, data
, NULL
,
180 purple_request_cpar_from_connection(js
->gc
));
185 jabber_x_data_request(js
, xdata
, (jabber_x_data_cb
)do_adhoc_ignoreme
, NULL
);
188 if(!strcmp(status
,"executing")) {
189 /* this command needs more steps */
190 PurpleXmlNode
*actions
, *action
;
192 GList
*actionslist
= NULL
;
193 JabberAdHocActionInfo
*actionInfo
;
195 return; /* shouldn't happen */
197 actions
= purple_xmlnode_get_child(command
,"actions");
199 JabberXDataAction
*defaultaction
= g_new0(JabberXDataAction
, 1);
200 defaultaction
->name
= g_strdup(_("execute"));
201 defaultaction
->handle
= g_strdup("execute");
202 actionslist
= g_list_append(actionslist
, defaultaction
);
204 const char *defaultactionhandle
= purple_xmlnode_get_attrib(actions
, "execute");
206 for(action
= actions
->child
; action
; action
= action
->next
, ++index
) {
207 if(action
->type
== PURPLE_XMLNODE_TYPE_TAG
) {
208 JabberXDataAction
*newaction
= g_new0(JabberXDataAction
, 1);
209 newaction
->name
= g_strdup(_(action
->name
));
210 newaction
->handle
= g_strdup(action
->name
);
211 actionslist
= g_list_append(actionslist
, newaction
);
212 if(defaultactionhandle
&& !strcmp(defaultactionhandle
, action
->name
))
218 actionInfo
= g_new0(JabberAdHocActionInfo
, 1);
219 actionInfo
->sessionid
= g_strdup(purple_xmlnode_get_attrib(command
,"sessionid"));
220 actionInfo
->who
= g_strdup(from
);
221 actionInfo
->node
= g_strdup(purple_xmlnode_get_attrib(command
,"node"));
222 actionInfo
->actionslist
= actionslist
;
224 jabber_x_data_request_with_actions(js
,xdata
,actionslist
,actionindex
,do_adhoc_action_cb
,actionInfo
);
228 void jabber_adhoc_execute_action(PurpleBlistNode
*node
, gpointer data
) {
229 if (PURPLE_IS_BUDDY(node
)) {
230 JabberAdHocCommands
*cmd
= data
;
231 PurpleBuddy
*buddy
= (PurpleBuddy
*) node
;
232 PurpleAccount
*account
= purple_buddy_get_account(buddy
);
233 PurpleConnection
*gc
= purple_account_get_connection(account
);
234 JabberStream
*js
= purple_connection_get_protocol_data(gc
);
236 jabber_adhoc_execute(js
, cmd
);
241 jabber_adhoc_got_server_list(JabberStream
*js
, const char *from
, PurpleXmlNode
*query
)
248 /* clean current list (just in case there is one) */
249 while(js
->commands
) {
250 JabberAdHocCommands
*cmd
= js
->commands
->data
;
255 js
->commands
= g_list_delete_link(js
->commands
, js
->commands
);
259 for(item
= query
->child
; item
; item
= item
->next
) {
260 JabberAdHocCommands
*cmd
;
261 if(item
->type
!= PURPLE_XMLNODE_TYPE_TAG
)
263 if(strcmp(item
->name
, "item"))
265 cmd
= g_new0(JabberAdHocCommands
, 1);
266 cmd
->jid
= g_strdup(purple_xmlnode_get_attrib(item
,"jid"));
267 cmd
->node
= g_strdup(purple_xmlnode_get_attrib(item
,"node"));
268 cmd
->name
= g_strdup(purple_xmlnode_get_attrib(item
,"name"));
270 js
->commands
= g_list_append(js
->commands
,cmd
);
273 if (js
->state
== JABBER_STREAM_CONNECTED
)
274 purple_protocol_got_account_actions(purple_connection_get_account(js
->gc
));
278 jabber_adhoc_server_got_list_cb(JabberStream
*js
, const char *from
,
279 JabberIqType type
, const char *id
,
280 PurpleXmlNode
*packet
, gpointer data
)
282 PurpleXmlNode
*query
= purple_xmlnode_get_child_with_namespace(packet
, "query",
285 jabber_adhoc_got_server_list(js
, from
, query
);
289 void jabber_adhoc_got_list(JabberStream
*js
, const char *from
, PurpleXmlNode
*query
)
291 if (purple_strequal(from
, js
->user
->domain
)) {
292 jabber_adhoc_got_server_list(js
, from
, query
);
294 jabber_adhoc_got_buddy_list(js
, from
, query
);
298 void jabber_adhoc_server_get_list(JabberStream
*js
) {
299 JabberIq
*iq
= jabber_iq_new_query(js
, JABBER_IQ_GET
, NS_DISCO_ITEMS
);
300 PurpleXmlNode
*query
= purple_xmlnode_get_child_with_namespace(iq
->node
, "query",
303 purple_xmlnode_set_attrib(iq
->node
,"to",js
->user
->domain
);
304 purple_xmlnode_set_attrib(query
,"node","http://jabber.org/protocol/commands");
306 jabber_iq_set_callback(iq
,jabber_adhoc_server_got_list_cb
,NULL
);
310 void jabber_adhoc_execute(JabberStream
*js
, JabberAdHocCommands
*cmd
) {
311 JabberIq
*iq
= jabber_iq_new(js
, JABBER_IQ_SET
);
312 PurpleXmlNode
*command
= purple_xmlnode_new_child(iq
->node
,"command");
313 purple_xmlnode_set_attrib(iq
->node
,"to",cmd
->jid
);
314 purple_xmlnode_set_namespace(command
,"http://jabber.org/protocol/commands");
315 purple_xmlnode_set_attrib(command
,"node",cmd
->node
);
316 purple_xmlnode_set_attrib(command
,"action","execute");
318 jabber_iq_set_callback(iq
,jabber_adhoc_parse
,NULL
);
323 static void jabber_adhoc_server_execute(PurpleProtocolAction
*action
) {
324 JabberAdHocCommands
*cmd
= action
->user_data
;
326 PurpleConnection
*gc
= (PurpleConnection
*) action
->connection
;
327 JabberStream
*js
= purple_connection_get_protocol_data(gc
);
329 jabber_adhoc_execute(js
, cmd
);
333 void jabber_adhoc_init_server_commands(JabberStream
*js
, GList
**m
) {
337 /* also add commands for other clients connected to the same account on another resource */
338 char *accountname
= g_strdup_printf("%s@%s", js
->user
->node
, js
->user
->domain
);
339 if((jb
= jabber_buddy_find(js
, accountname
, TRUE
))) {
341 for(iter
= jb
->resources
; iter
; iter
= g_list_next(iter
)) {
342 JabberBuddyResource
*jbr
= iter
->data
;
344 for(riter
= jbr
->commands
; riter
; riter
= g_list_next(riter
)) {
345 JabberAdHocCommands
*cmd
= riter
->data
;
346 char *cmdname
= g_strdup_printf("%s (%s)",cmd
->name
,jbr
->name
);
347 PurpleProtocolAction
*act
= purple_protocol_action_new(cmdname
, jabber_adhoc_server_execute
);
348 act
->user_data
= cmd
;
349 *m
= g_list_append(*m
, act
);
356 /* now add server commands */
357 for(cmdlst
= js
->commands
; cmdlst
; cmdlst
= g_list_next(cmdlst
)) {
358 JabberAdHocCommands
*cmd
= cmdlst
->data
;
359 PurpleProtocolAction
*act
= purple_protocol_action_new(cmd
->name
, jabber_adhoc_server_execute
);
360 act
->user_data
= cmd
;
361 *m
= g_list_append(*m
, act
);