From ca022ec75e12d28e6ce71447fe877b90518de310 Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Wed, 21 Mar 2018 18:00:11 +0100 Subject: Add command command Initial commit to test commands API --- src/xmpp/stanza.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/xmpp/stanza.h') diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index bd161616..40461637 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -99,6 +99,7 @@ #define STANZA_NAME_PUT "put" #define STANZA_NAME_GET "get" #define STANZA_NAME_URL "url" +#define STANZA_NAME_COMMAND "command" // error conditions #define STANZA_NAME_BAD_REQUEST "bad-request" @@ -186,6 +187,7 @@ #define STANZA_NS_HTTP_UPLOAD "urn:xmpp:http:upload" #define STANZA_NS_X_OOB "jabber:x:oob" #define STANZA_NS_BLOCKING "urn:xmpp:blocking" +#define STANZA_NS_COMMAND "http://jabber.org/protocol/commands" #define STANZA_DATAFORM_SOFTWARE "urn:xmpp:dataforms:softwareinfo" @@ -278,6 +280,8 @@ xmpp_stanza_t* stanza_create_room_subject_message(xmpp_ctx_t *ctx, const char *c xmpp_stanza_t* stanza_create_room_kick_iq(xmpp_ctx_t *const ctx, const char *const room, const char *const nick, const char *const reason); +xmpp_stanza_t* stanza_create_command_iq(xmpp_ctx_t *ctx, const char *const target, const char *const node); + int stanza_get_idle_time(xmpp_stanza_t *const stanza); void stanza_attach_priority(xmpp_ctx_t *const ctx, xmpp_stanza_t *const presence, const int pri); -- cgit 1.4.1-2-gfad0 From c9f6a78f574ce2a90ae7871a08a5ddcfb9ab7270 Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Thu, 22 Mar 2018 04:47:52 +0220 Subject: Add command subcommands: list and exec Also handle list result --- src/command/cmd_defs.c | 21 ++++++---- src/command/cmd_funcs.c | 29 ++++++++++++-- src/command/cmd_funcs.h | 3 +- src/ui/ui.h | 2 + src/ui/window.c | 28 +++++++++++++ src/xmpp/iq.c | 85 +++++++++++++++++++++++++++++++++++----- src/xmpp/stanza.c | 7 +++- src/xmpp/stanza.h | 4 +- src/xmpp/xmpp.h | 3 +- tests/unittests/xmpp/stub_xmpp.c | 2 + 10 files changed, 158 insertions(+), 26 deletions(-) (limited to 'src/xmpp/stanza.h') diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index c3ab395d..14e49b47 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2300,19 +2300,24 @@ static struct cmd_t command_defs[] = "/export ~/contacts.csv") }, - { "/command", - parse_args, 1, 1, NULL, - CMD_NOSUBFUNCS - CMD_MAINFUNC(cmd_command) + { "/cmd", + parse_args, 1, 3, NULL, + CMD_SUBFUNCS( + { "list", cmd_command_list }, + { "exec", cmd_command_exec }) + CMD_NOMAINFUNC CMD_NOTAGS CMD_SYN( - "/command ") + "/otr list", + "/otr exec ") CMD_DESC( - "Execute an ad hoc command") + "Execute ad hoc commands.") CMD_ARGS( - { "", "Command to be executed" }) + { "list", "List supported ad hoc commands." }, + { "exec ", "Execute a command." }) CMD_EXAMPLES( - "/command ping") + "/cmd list", + "/cmd exec ping") } }; diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 048bdd6c..2e606ef5 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -7470,7 +7470,7 @@ cmd_encwarn(ProfWin *window, const char *const command, gchar **args) } gboolean -cmd_command(ProfWin *window, const char *const command, gchar **args) +cmd_command_list(ProfWin *window, const char *const command, gchar **args) { jabber_conn_status_t conn_status = connection_get_status(); @@ -7479,14 +7479,37 @@ cmd_command(ProfWin *window, const char *const command, gchar **args) return TRUE; } - if (args[0] == NULL && connection_supports(XMPP_FEATURE_COMMANDS) == FALSE) { + if (connection_supports(XMPP_FEATURE_COMMANDS) == FALSE) { cons_show("Server does not support ad hoc commands."); return TRUE; } ProfMucWin *mucwin = (ProfMucWin*)window; - iq_send_command(mucwin->roomjid, args[0]); + iq_command_list(mucwin->roomjid); + + cons_show("List available ad hoc commands"); + return TRUE; +} + +gboolean +cmd_command_exec(ProfWin *window, const char *const command, gchar **args) +{ + jabber_conn_status_t conn_status = connection_get_status(); + + if (conn_status != JABBER_CONNECTED) { + cons_show("You are not currently connected."); + return TRUE; + } + + if (connection_supports(XMPP_FEATURE_COMMANDS) == FALSE) { + cons_show("Server does not support ad hoc commands."); + return TRUE; + } + + ProfMucWin *mucwin = (ProfMucWin*)window; + + iq_command_exec(mucwin->roomjid, args[0]); cons_show("Execute %s...", args[0]); return TRUE; diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index 089d8227..5b909fed 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -158,7 +158,8 @@ gboolean cmd_script(ProfWin *window, const char *const command, gchar **args); gboolean cmd_export(ProfWin *window, const char *const command, gchar **args); gboolean cmd_charset(ProfWin *window, const char *const command, gchar **args); gboolean cmd_console(ProfWin *window, const char *const command, gchar **args); -gboolean cmd_command(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_command_list(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_command_exec(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins(ProfWin *window, const char *const command, gchar **args); gboolean cmd_plugins_sourcepath(ProfWin *window, const char *const command, gchar **args); diff --git a/src/ui/ui.h b/src/ui/ui.h index d344f855..f1d8161f 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -377,6 +377,8 @@ void win_show_info(ProfWin *window, PContact contact); void win_clear(ProfWin *window); char* win_get_tab_identifier(ProfWin *window); char* win_to_string(ProfWin *window); +void win_command_list_error(ProfWin *window, const char *const error); +void win_handle_command_list(ProfWin *window, GSList *cmds); // desktop notifications void notifier_initialise(void); diff --git a/src/ui/window.c b/src/ui/window.c index 5543707d..3ba6b387 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1724,3 +1724,31 @@ win_sub_newline_lazy(WINDOW *win) wmove(win, cury+1, 0); } } + +void +win_command_list_error(ProfWin *window, const char *const error) +{ + assert(window != NULL); + + win_println(window, THEME_ERROR, '!', "Error retrieving command list: %s", error); +} + +void +win_handle_command_list(ProfWin *window, GSList *cmds) +{ + assert(window != NULL); + + if (cmds) { + win_println(window, THEME_DEFAULT, '!', "Ad hoc commands:"); + GSList *curr_cmd = cmds; + while (curr_cmd) { + const char *cmd = curr_cmd->data; + win_println(window, THEME_DEFAULT, '!', " %s", cmd); + curr_cmd = g_slist_next(curr_cmd); + } + win_println(window, THEME_DEFAULT, '!', ""); + } else { + win_println(window, THEME_DEFAULT, '!', "No commands found"); + win_println(window, THEME_DEFAULT, '!', ""); + } +} diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 33400912..ad7ef54d 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -120,7 +120,8 @@ static int _caps_response_for_jid_id_handler(xmpp_stanza_t *const stanza, void * static int _caps_response_legacy_id_handler(xmpp_stanza_t *const stanza, void *const userdata); static int _auto_pong_id_handler(xmpp_stanza_t *const stanza, void *const userdata); static int _room_list_id_handler(xmpp_stanza_t *const stanza, void *const userdata); -static int _command_response_handler(xmpp_stanza_t *const stanza, void *const userdata); +static int _command_list_result_handler(xmpp_stanza_t *const stanza, void *const userdata); +static int _command_exec_response_handler(xmpp_stanza_t *const stanza, void *const userdata); static void _iq_free_room_data(ProfRoomInfoData *roominfo); static void _iq_free_affiliation_set(ProfPrivilegeSet *affiliation_set); @@ -320,7 +321,7 @@ iq_room_list_request(gchar *conferencejid, gchar *filter) xmpp_ctx_t * const ctx = connection_get_ctx(); char *id = connection_create_stanza_id("confreq"); - xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, id, conferencejid); + xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, id, conferencejid, NULL); iq_id_handler_add(id, _room_list_id_handler, NULL, filter); @@ -522,7 +523,7 @@ void iq_disco_items_request(gchar *jid) { xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, "discoitemsreq", jid); + xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, "discoitemsreq", jid, NULL); iq_send_stanza(iq); xmpp_stanza_release(iq); } @@ -531,7 +532,7 @@ void iq_disco_items_request_onconnect(gchar *jid) { xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, "discoitemsreq_onconnect", jid); + xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, "discoitemsreq_onconnect", jid, NULL); iq_send_stanza(iq); xmpp_stanza_release(iq); } @@ -698,13 +699,26 @@ iq_send_ping(const char *const target) } void -iq_send_command(const char *const target, const char *const command) +iq_command_list(const char *const target) { xmpp_ctx_t * const ctx = connection_get_ctx(); - xmpp_stanza_t *iq = stanza_create_command_iq(ctx, target, command); + const char *id = connection_create_stanza_id("cmdlist"); + xmpp_stanza_t *iq = stanza_create_disco_items_iq(ctx, id, target, STANZA_NS_COMMAND); + + iq_id_handler_add(id, _command_list_result_handler, NULL, NULL); + + iq_send_stanza(iq); + xmpp_stanza_release(iq); +} + +void +iq_command_exec(const char *const target, const char *const command) +{ + xmpp_ctx_t * const ctx = connection_get_ctx(); + xmpp_stanza_t *iq = stanza_create_command_exec_iq(ctx, target, command); const char *id = xmpp_stanza_get_id(iq); - iq_id_handler_add(id, _command_response_handler, free, strdup(command)); + iq_id_handler_add(id, _command_exec_response_handler, free, strdup(command)); iq_send_stanza(iq); xmpp_stanza_release(iq); @@ -1026,9 +1040,62 @@ _room_list_id_handler(xmpp_stanza_t *const stanza, void *const userdata) } static int -_command_response_handler(xmpp_stanza_t *const stanza, void *const userdata) +_command_list_result_handler(xmpp_stanza_t *const stanza, void *const userdata) +{ + const char *id = xmpp_stanza_get_id(stanza); + const char *type = xmpp_stanza_get_type(stanza); + char *from = strdup(xmpp_stanza_get_from(stanza)); + + if (id) { + log_debug("IQ command list result handler fired, id: %s.", id); + } else { + log_debug("IQ command list result handler fired."); + } + + // handle error responses + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + char *error_message = stanza_get_error_message(stanza); + log_debug("Error retrieving command list for %s: %s", from, error_message); + ProfWin *win = wins_get_by_string(from); + if (win) { + win_command_list_error(win, error_message); + } + free(error_message); + free(from); + return 0; + } + + GSList *cmds = NULL; + + xmpp_stanza_t *query = xmpp_stanza_get_child_by_ns(stanza, XMPP_NS_DISCO_ITEMS); + if (query) { + xmpp_stanza_t *child = xmpp_stanza_get_children(query); + while (child) { + const char *name = xmpp_stanza_get_name(child); + if (g_strcmp0(name, "item") == 0) { + const char *node = xmpp_stanza_get_attribute(child, STANZA_ATTR_NODE); + if (node) { + cmds = g_slist_insert_sorted(cmds, (gpointer)node, (GCompareFunc)g_strcmp0); + } + } + child = xmpp_stanza_get_next(child); + } + } + + ProfWin *win = wins_get_by_string(from); + if (win) { + win_handle_command_list(win, cmds); + } + g_slist_free(cmds); + free(from); + + return 0; +} + +static int +_command_exec_response_handler(xmpp_stanza_t *const stanza, void *const userdata) { - cons_show("Plop", NULL); + cons_show("%s", NULL, __func__); return 0; } diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index ef4f8af4..cc842ff6 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -924,7 +924,7 @@ stanza_create_disco_info_iq(xmpp_ctx_t *ctx, const char *const id, const char *c xmpp_stanza_t* stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char *const id, - const char *const jid) + const char *const jid, const char *const node) { xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_GET, id); xmpp_stanza_set_to(iq, jid); @@ -932,6 +932,9 @@ stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char *const id, xmpp_stanza_t *query = xmpp_stanza_new(ctx); xmpp_stanza_set_name(query, STANZA_NAME_QUERY); xmpp_stanza_set_ns(query, XMPP_NS_DISCO_ITEMS); + if (node) { + xmpp_stanza_set_attribute(query, STANZA_ATTR_NODE, node); + } xmpp_stanza_add_child(iq, query); xmpp_stanza_release(query); @@ -2039,7 +2042,7 @@ stanza_parse_presence(xmpp_stanza_t *stanza, int *err) } xmpp_stanza_t* -stanza_create_command_iq(xmpp_ctx_t *ctx, const char *const target, +stanza_create_command_exec_iq(xmpp_ctx_t *ctx, const char *const target, const char *const node) { char *id = create_unique_id("command"); diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 40461637..a3cf2c4c 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -280,7 +280,7 @@ xmpp_stanza_t* stanza_create_room_subject_message(xmpp_ctx_t *ctx, const char *c xmpp_stanza_t* stanza_create_room_kick_iq(xmpp_ctx_t *const ctx, const char *const room, const char *const nick, const char *const reason); -xmpp_stanza_t* stanza_create_command_iq(xmpp_ctx_t *ctx, const char *const target, const char *const node); +xmpp_stanza_t* stanza_create_command_exec_iq(xmpp_ctx_t *ctx, const char *const target, const char *const node); int stanza_get_idle_time(xmpp_stanza_t *const stanza); @@ -296,7 +296,7 @@ EntityCapabilities* stanza_create_caps_from_query_element(xmpp_stanza_t *query); const char* stanza_get_presence_string_from_type(resource_presence_t presence_type); xmpp_stanza_t* stanza_create_software_version_iq(xmpp_ctx_t *ctx, const char *const fulljid); -xmpp_stanza_t* stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char *const id, const char *const jid); +xmpp_stanza_t* stanza_create_disco_items_iq(xmpp_ctx_t *ctx, const char *const id, const char *const jid, const char *const node); char* stanza_get_status(xmpp_stanza_t *stanza, char *def); char* stanza_get_show(xmpp_stanza_t *stanza, char *def); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 2e7d1a25..c0e1477d 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -183,7 +183,8 @@ void iq_room_role_set(const char *const room, const char *const nick, char *role void iq_room_role_list(const char * const room, char *role); void iq_autoping_check(void); void iq_http_upload_request(HTTPUpload *upload); -void iq_send_command(const char *const target, const char *const command); +void iq_command_list(const char *const target); +void iq_command_exec(const char *const target, const char *const command); EntityCapabilities* caps_lookup(const char *const jid); void caps_close(void); diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c index 45db6649..5590a8e1 100644 --- a/tests/unittests/xmpp/stub_xmpp.c +++ b/tests/unittests/xmpp/stub_xmpp.c @@ -205,6 +205,8 @@ void iq_room_role_list(const char * const room, char *role) {} void iq_last_activity_request(gchar *jid) {} void iq_autoping_check(void) {} void iq_rooms_cache_clear(void) {} +void iq_command_list(const char *const target) {} +void iq_command_exec(const char *const target, const char *const command) {} // caps functions void caps_add_feature(char *feature) {} -- cgit 1.4.1-2-gfad0 From 925cd488c1397c960bc1eec0e441f073d887162e Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Thu, 22 Mar 2018 22:21:15 +0220 Subject: Handle simple execution Tested with ping from biboumi --- src/command/cmd_funcs.c | 4 ++-- src/ui/ui.h | 1 + src/ui/window.c | 7 +++++++ src/xmpp/iq.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- src/xmpp/stanza.c | 2 +- src/xmpp/stanza.h | 1 + 6 files changed, 60 insertions(+), 4 deletions(-) (limited to 'src/xmpp/stanza.h') diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 2e606ef5..dc112d85 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -7509,9 +7509,9 @@ cmd_command_exec(ProfWin *window, const char *const command, gchar **args) ProfMucWin *mucwin = (ProfMucWin*)window; - iq_command_exec(mucwin->roomjid, args[0]); + iq_command_exec(mucwin->roomjid, args[1]); - cons_show("Execute %s...", args[0]); + cons_show("Execute %s...", args[1]); return TRUE; } diff --git a/src/ui/ui.h b/src/ui/ui.h index f1d8161f..fa8f948a 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -379,6 +379,7 @@ char* win_get_tab_identifier(ProfWin *window); char* win_to_string(ProfWin *window); void win_command_list_error(ProfWin *window, const char *const error); void win_handle_command_list(ProfWin *window, GSList *cmds); +void win_handle_command_exec_result_note(ProfWin *window, const char *const type, const char *const value); // desktop notifications void notifier_initialise(void); diff --git a/src/ui/window.c b/src/ui/window.c index 3ba6b387..f38127d7 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1752,3 +1752,10 @@ win_handle_command_list(ProfWin *window, GSList *cmds) win_println(window, THEME_DEFAULT, '!', ""); } } + +void +win_handle_command_exec_result_note(ProfWin *window, const char *const type, const char *const value) +{ + assert(window != NULL); + win_println(window, THEME_DEFAULT, '!', value); +} diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index ad7ef54d..8702d1a1 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -1095,7 +1095,54 @@ _command_list_result_handler(xmpp_stanza_t *const stanza, void *const userdata) static int _command_exec_response_handler(xmpp_stanza_t *const stanza, void *const userdata) { - cons_show("%s", NULL, __func__); + const char *id = xmpp_stanza_get_id(stanza); + const char *type = xmpp_stanza_get_type(stanza); + char *from = strdup(xmpp_stanza_get_from(stanza)); + const char *const command = userdata; + + if (id) { + log_debug("IQ command exec response handler fired, id: %s.", id); + } else { + log_debug("IQ command exec response handler fired."); + } + + // handle error responses + if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { + char *error_message = stanza_get_error_message(stanza); + log_debug("Error executing command %s for %s: %s", command, from, error_message); + ProfWin *win = wins_get_by_string(from); + if (win) { + win_command_list_error(win, error_message); + } + free(error_message); + free(from); + return 0; + } + + xmpp_stanza_t *cmd = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_COMMAND); + if (!cmd) { + /* TODO */ + } + + ProfWin *win = wins_get_by_string(from); + + const char *status = xmpp_stanza_get_attribute(cmd, STANZA_ATTR_STATUS); + if (g_strcmp0(status, "completed") == 0) { + if (win) { + xmpp_stanza_t *note = xmpp_stanza_get_child_by_name(cmd, "note"); + if (note) { + const char *type = xmpp_stanza_get_attribute(note, "type"); + const char *value = xmpp_stanza_get_text(note); + win_handle_command_exec_result_note(win, type, value); + } + } + } else if (g_strcmp0(status, "executing") == 0) { + } else if (g_strcmp0(status, "canceled") == 0) { + } else { + /* TODO */ + } + + free(from); return 0; } diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index cc842ff6..537fbf96 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -2045,7 +2045,7 @@ xmpp_stanza_t* stanza_create_command_exec_iq(xmpp_ctx_t *ctx, const char *const target, const char *const node) { - char *id = create_unique_id("command"); + char *id = connection_create_stanza_id("cmdexec"); xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); free(id); xmpp_stanza_set_to(iq, target); diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index a3cf2c4c..5f8203a2 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -157,6 +157,7 @@ #define STANZA_ATTR_REASON "reason" #define STANZA_ATTR_AUTOJOIN "autojoin" #define STANZA_ATTR_PASSWORD "password" +#define STANZA_ATTR_STATUS "status" #define STANZA_TEXT_AWAY "away" #define STANZA_TEXT_DND "dnd" -- cgit 1.4.1-2-gfad0 From 233e076be95baf13a23e9dbefac208d424a57e5d Mon Sep 17 00:00:00 2001 From: Paul Fariello Date: Wed, 20 Jun 2018 19:30:44 +0320 Subject: Add support for command config execution --- src/ui/ui.h | 2 +- src/ui/win_types.h | 1 + src/ui/window.c | 3 ++- src/ui/window_list.c | 4 ++-- src/ui/window_list.h | 2 +- src/xmpp/iq.c | 44 +++++++++++++++++++++++++++++++++++++++++--- src/xmpp/stanza.c | 25 +++++++++++++++++++++++++ src/xmpp/stanza.h | 1 + tests/unittests/ui/stub_ui.c | 2 +- 9 files changed, 75 insertions(+), 9 deletions(-) (limited to 'src/xmpp/stanza.h') diff --git a/src/ui/ui.h b/src/ui/ui.h index 1bcc20fc..136a5e98 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -346,7 +346,7 @@ ProfWin* win_create_console(void); ProfWin* win_create_xmlconsole(void); ProfWin* win_create_chat(const char *const barejid); ProfWin* win_create_muc(const char *const roomjid); -ProfWin* win_create_config(const char *const title, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel); +ProfWin* win_create_config(const char *const title, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel, const void *userdata); ProfWin* win_create_private(const char *const fulljid); ProfWin* win_create_plugin(const char *const plugin_name, const char *const tag); void win_update_virtual(ProfWin *window); diff --git a/src/ui/win_types.h b/src/ui/win_types.h index c9dc623b..eb453cd0 100644 --- a/src/ui/win_types.h +++ b/src/ui/win_types.h @@ -182,6 +182,7 @@ struct prof_conf_win_t { unsigned long memcheck; ProfConfWinCallback submit; ProfConfWinCallback cancel; + const void *userdata; }; typedef struct prof_private_win_t { diff --git a/src/ui/window.c b/src/ui/window.c index f34e354e..5ad354f2 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -203,7 +203,7 @@ win_create_muc(const char *const roomjid) } ProfWin* -win_create_config(const char *const roomjid, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel) +win_create_config(const char *const roomjid, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel, const void *userdata) { ProfConfWin *new_win = malloc(sizeof(ProfConfWin)); new_win->window.type = WIN_CONFIG; @@ -212,6 +212,7 @@ win_create_config(const char *const roomjid, DataForm *form, ProfConfWinCallback new_win->form = form; new_win->submit = submit; new_win->cancel = cancel; + new_win->userdata = userdata; new_win->memcheck = PROFCONFWIN_MEMCHECK; diff --git a/src/ui/window_list.c b/src/ui/window_list.c index 8f886b54..a12dc7cb 100644 --- a/src/ui/window_list.c +++ b/src/ui/window_list.c @@ -657,12 +657,12 @@ wins_new_muc(const char *const roomjid) } ProfWin* -wins_new_config(const char *const roomjid, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel) +wins_new_config(const char *const roomjid, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel, const void *userdata) { GList *keys = g_hash_table_get_keys(windows); int result = _wins_get_next_available_num(keys); g_list_free(keys); - ProfWin *newwin = win_create_config(roomjid, form, submit, cancel); + ProfWin *newwin = win_create_config(roomjid, form, submit, cancel, userdata); g_hash_table_insert(windows, GINT_TO_POINTER(result), newwin); return newwin; } diff --git a/src/ui/window_list.h b/src/ui/window_list.h index f427a6d7..b47ee79f 100644 --- a/src/ui/window_list.h +++ b/src/ui/window_list.h @@ -42,7 +42,7 @@ void wins_init(void); ProfWin* wins_new_xmlconsole(void); ProfWin* wins_new_chat(const char *const barejid); ProfWin* wins_new_muc(const char *const roomjid); -ProfWin* wins_new_config(const char *const roomjid, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel); +ProfWin* wins_new_config(const char *const roomjid, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel, const void *userdata); ProfWin* wins_new_private(const char *const fulljid); ProfWin* wins_new_plugin(const char *const plugin_name, const char *const tag); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 8e7ecc0b..337701bc 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -88,6 +88,11 @@ typedef struct privilege_set_t { char *privilege; } ProfPrivilegeSet; +typedef struct command_config_data_t { + char *sessionid; + char *command; +} CommandConfigData; + static int _iq_handler(xmpp_conn_t *const conn, xmpp_stanza_t *const stanza, void *const userdata); static void _error_handler(xmpp_stanza_t *const stanza); @@ -724,6 +729,36 @@ iq_command_exec(const char *const target, const char *const command) xmpp_stanza_release(iq); } +void +iq_submit_command_config(ProfConfWin *confwin) +{ + xmpp_ctx_t * const ctx = connection_get_ctx(); + CommandConfigData *data = (CommandConfigData *)confwin->userdata; + xmpp_stanza_t *iq = stanza_create_command_config_submit_iq(ctx, confwin->roomjid, data->command, data->sessionid, confwin->form); + + const char *id = xmpp_stanza_get_id(iq); + iq_id_handler_add(id, _command_exec_response_handler, NULL, NULL); + + iq_send_stanza(iq); + xmpp_stanza_release(iq); + free(data->sessionid); + free(data->command); + free(data); +} + +void +iq_cancel_command_config(ProfConfWin *confwin) +{ + xmpp_ctx_t * const ctx = connection_get_ctx(); + CommandConfigData *data = (CommandConfigData *)confwin->userdata; + xmpp_stanza_t *iq = stanza_create_room_config_cancel_iq(ctx, confwin->roomjid); + iq_send_stanza(iq); + xmpp_stanza_release(iq); + free(data->sessionid); + free(data->command); + free(data); +} + static void _error_handler(xmpp_stanza_t *const stanza) { @@ -1098,7 +1133,7 @@ _command_exec_response_handler(xmpp_stanza_t *const stanza, void *const userdata const char *id = xmpp_stanza_get_id(stanza); const char *type = xmpp_stanza_get_type(stanza); const char *from = xmpp_stanza_get_from(stanza); - const char *const command = userdata; + char *command = userdata; if (id) { log_debug("IQ command exec response handler fired, id: %s.", id); @@ -1156,7 +1191,10 @@ _command_exec_response_handler(xmpp_stanza_t *const stanza, void *const userdata } DataForm *form = form_create(x); - ProfConfWin *confwin = (ProfConfWin*)wins_new_config(from, form, NULL, NULL); + CommandConfigData *data = malloc(sizeof(CommandConfigData)); + data->sessionid = strdup(xmpp_stanza_get_attribute(cmd, "sessionid")); + data->command = command; + ProfConfWin *confwin = (ProfConfWin*)wins_new_config(from, form, iq_submit_command_config, iq_cancel_command_config, data); confwin_handle_configuration(confwin, form); } else if (g_strcmp0(status, "canceled") == 0) { win_handle_command_exec_status(win, command, "canceled"); @@ -1703,7 +1741,7 @@ _room_config_id_handler(xmpp_stanza_t *const stanza, void *const userdata) } DataForm *form = form_create(x); - ProfConfWin *confwin = (ProfConfWin*)wins_new_config(from, form, iq_submit_room_config, iq_room_config_cancel); + ProfConfWin *confwin = (ProfConfWin*)wins_new_config(from, form, iq_submit_room_config, iq_room_config_cancel, NULL); confwin_handle_configuration(confwin, form); return 0; diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 537fbf96..68919710 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -2063,6 +2063,31 @@ stanza_create_command_exec_iq(xmpp_ctx_t *ctx, const char *const target, return iq; } +xmpp_stanza_t* +stanza_create_command_config_submit_iq(xmpp_ctx_t *ctx, const char *const room, + const char *const node, const char *const sessionid, DataForm *form) +{ + char *id = connection_create_stanza_id("commandconf_submit"); + xmpp_stanza_t *iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); + free(id); + xmpp_stanza_set_to(iq, room); + + xmpp_stanza_t *command = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(command, STANZA_NAME_COMMAND); + xmpp_stanza_set_ns(command, STANZA_NS_COMMAND); + xmpp_stanza_set_attribute(command, "node", node); + xmpp_stanza_set_attribute(command, "sessionid", sessionid); + + xmpp_stanza_t *x = form_create_submission(form); + xmpp_stanza_add_child(command, x); + xmpp_stanza_release(x); + + xmpp_stanza_add_child(iq, command); + xmpp_stanza_release(command); + + return iq; +} + static void _stanza_add_unique_id(xmpp_stanza_t *stanza, char *prefix) { diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 5f8203a2..696f60da 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -282,6 +282,7 @@ xmpp_stanza_t* stanza_create_room_kick_iq(xmpp_ctx_t *const ctx, const char *con const char *const reason); xmpp_stanza_t* stanza_create_command_exec_iq(xmpp_ctx_t *ctx, const char *const target, const char *const node); +xmpp_stanza_t* stanza_create_command_config_submit_iq(xmpp_ctx_t *ctx, const char *const room, const char *const node, const char *const sessionid, DataForm *form); int stanza_get_idle_time(xmpp_stanza_t *const stanza); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index cee0ddd9..855dca22 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -494,7 +494,7 @@ ProfWin* win_create_muc(const char * const roomjid) { return NULL; } -ProfWin* win_create_config(const char * const title, DataForm *form) +ProfWin* win_create_config(const char *const title, DataForm *form, ProfConfWinCallback submit, ProfConfWinCallback cancel, const void *userdata) { return NULL; } -- cgit 1.4.1-2-gfad0