From bced3d4b36c2080b6dee2c2aa14b64c8cf405cc5 Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 17 Feb 2013 02:10:56 +0000 Subject: [PATCH] Added autocomplete for /software command --- src/command/command.c | 33 +++++++++++++++++++++++++++ src/contact_list.c | 24 +++++++++++++++++++- src/contact_list.h | 1 + src/profanity.c | 8 +++++++ src/profanity.h | 2 ++ src/ui/ui.h | 2 ++ src/ui/windows.c | 19 ++++++++++++++++ src/xmpp/iq.c | 52 +++++++++++++++++++++++++++++++++++++++++++ src/xmpp/stanza.c | 19 ++++++++++++++++ src/xmpp/stanza.h | 1 + src/xmpp/xmpp.h | 3 +++ 11 files changed, 163 insertions(+), 1 deletion(-) diff --git a/src/command/command.c b/src/command/command.c index 58868334..6dd6b46e 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -126,6 +126,7 @@ static gboolean _cmd_chat(gchar **args, struct cmd_help_t help); static gboolean _cmd_xa(gchar **args, struct cmd_help_t help); static gboolean _cmd_info(gchar **args, struct cmd_help_t help); static gboolean _cmd_caps(gchar **args, struct cmd_help_t help); +static gboolean _cmd_software(gchar **args, struct cmd_help_t help); static gboolean _cmd_wins(gchar **args, struct cmd_help_t help); static gboolean _cmd_nick(gchar **args, struct cmd_help_t help); static gboolean _cmd_theme(gchar **args, struct cmd_help_t help); @@ -279,6 +280,15 @@ static struct cmd_t main_commands[] = "The command output is similar to the /info command, but shows the capabilities of each available resource.", NULL } } }, + { "/software", + _cmd_software, parse_args, 0, 1, + { "/software [jid|nick]", "Find out a software version information about a contacts resource.", + { "/software [jid|nick]", + "--------------------", + "Find out a contact, or room members software version information.", + "If in a chat window the parameter is not required, the current recipient will be used.", + NULL } } }, + { "/status", _cmd_status, parse_args, 0, 1, { "/status [jid|nick]", "Find out a contacts presence information.", @@ -987,6 +997,8 @@ _cmd_complete_parameters(char *input, int *size) contact_list_find_contact); _parameter_autocomplete(input, size, "/status", contact_list_find_contact); + _parameter_autocomplete(input, size, "/software", + contact_list_find_resource); } _parameter_autocomplete(input, size, "/connect", @@ -1938,6 +1950,27 @@ _cmd_caps(gchar **args, struct cmd_help_t help) return TRUE; } +static gboolean +_cmd_software(gchar **args, struct cmd_help_t help) +{ + jabber_conn_status_t conn_status = jabber_get_connection_status(); + + if (conn_status != JABBER_CONNECTED) { + cons_show("You are not currently connected."); + return TRUE; + } + + Jid *jid = jid_create(args[0]); + + if (jid->fulljid == NULL) { + cons_show("You must provide a full jid to the /software command."); + return TRUE; + } else { + iq_send_software_version(jid->fulljid); + return TRUE; + } +} + static gboolean _cmd_join(gchar **args, struct cmd_help_t help) { diff --git a/src/contact_list.c b/src/contact_list.c index be454cb7..47986646 100644 --- a/src/contact_list.c +++ b/src/contact_list.c @@ -26,9 +26,11 @@ #include #include "contact.h" +#include "jid.h" #include "tools/autocomplete.h" static Autocomplete ac; +static Autocomplete resource_ac; static GHashTable *contacts; static gboolean _key_equals(void *key1, void *key2); @@ -38,6 +40,7 @@ void contact_list_init(void) { ac = autocomplete_new(); + resource_ac = autocomplete_new(); contacts = g_hash_table_new_full(g_str_hash, (GEqualFunc)_key_equals, g_free, (GDestroyNotify)p_contact_free); } @@ -46,6 +49,7 @@ void contact_list_clear(void) { autocomplete_clear(ac); + autocomplete_clear(resource_ac); g_hash_table_destroy(contacts); contacts = g_hash_table_new_full(g_str_hash, (GEqualFunc)_key_equals, g_free, (GDestroyNotify)p_contact_free); @@ -55,12 +59,14 @@ void contact_list_free() { autocomplete_free(ac); + autocomplete_free(resource_ac); } void contact_list_reset_search_attempts(void) { autocomplete_reset(ac); + autocomplete_reset(resource_ac); } gboolean @@ -104,6 +110,9 @@ contact_list_update_presence(const char * const barejid, Resource *resource, p_contact_set_last_activity(contact, last_activity); } p_contact_set_presence(contact, resource); + Jid *jid = jid_create_from_bare_and_resource(barejid, resource->name); + autocomplete_add(resource_ac, strdup(jid->fulljid)); + jid_destroy(jid); return TRUE; } @@ -119,7 +128,14 @@ contact_list_contact_offline(const char * const barejid, if (resource == NULL) { return TRUE; } else { - return p_contact_remove_resource(contact, resource); + gboolean result = p_contact_remove_resource(contact, resource); + if (result == TRUE) { + Jid *jid = jid_create_from_bare_and_resource(barejid, resource); + autocomplete_remove(resource_ac, jid->fulljid); + jid_destroy(jid); + } + + return result; } } @@ -179,6 +195,12 @@ contact_list_find_contact(char *search_str) return autocomplete_complete(ac, search_str); } +char * +contact_list_find_resource(char *search_str) +{ + return autocomplete_complete(resource_ac, search_str); +} + PContact contact_list_get_contact(const char const *barejid) { diff --git a/src/contact_list.h b/src/contact_list.h index eb15a6ab..73dac250 100644 --- a/src/contact_list.h +++ b/src/contact_list.h @@ -42,6 +42,7 @@ void contact_list_update_subscription(const char * const barejid, gboolean contact_list_has_pending_subscriptions(void); GSList * get_contact_list(void); char * contact_list_find_contact(char *search_str); +char * contact_list_find_resource(char *search_str); PContact contact_list_get_contact(const char const *barejid); gboolean contact_list_contact_offline(const char * const barejid, const char * const resource, const char * const status); diff --git a/src/profanity.c b/src/profanity.c index 0052679b..e17d2dc7 100644 --- a/src/profanity.c +++ b/src/profanity.c @@ -391,6 +391,14 @@ prof_handle_activity(void) } } +void +prof_handle_version_result(const char * const jid, const char * const name, + const char * const version, const char * const os) +{ + cons_show_software_version(jid, name, version, os); + win_current_page_off(); +} + /* * Take a line of input and process it, return TRUE if profanity is to * continue, FALSE otherwise diff --git a/src/profanity.h b/src/profanity.h index 366188e1..177b4e91 100644 --- a/src/profanity.h +++ b/src/profanity.h @@ -68,5 +68,7 @@ void prof_handle_room_broadcast(const char *const room_jid, const char * const message); void prof_handle_idle(void); void prof_handle_activity(void); +void prof_handle_version_result(const char * const jid, const char * const name, + const char * const version, const char * const os); #endif diff --git a/src/ui/ui.h b/src/ui/ui.h index 378cea69..14d03ef0 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -168,6 +168,8 @@ void cons_show_info(PContact pcontact); void cons_show_caps(PContact pcontact); void cons_show_themes(GSList *themes); void cons_show_login_success(ProfAccount *account); +void cons_show_software_version(const char * const jid, const char * const name, + const char * const version, const char * const os); // status bar actions void status_bar_refresh(void); diff --git a/src/ui/windows.c b/src/ui/windows.c index a7bf5eec..7a34b17a 100644 --- a/src/ui/windows.c +++ b/src/ui/windows.c @@ -1205,6 +1205,25 @@ cons_show_caps(PContact pcontact) } } +void +cons_show_software_version(const char * const jid, const char * const name, + const char * const version, const char * const os) +{ + if ((name != NULL) || (version != NULL) || (os != NULL)) { + cons_show(""); + cons_show("%s:", jid); + } + if (name != NULL) { + cons_show(" Name : %s", name); + } + if (version != NULL) { + cons_show(" Version : %s", version); + } + if (os != NULL) { + cons_show(" OS : %s", os); + } +} + void cons_show_status(const char * const contact) { diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 070fefba..b98d3bc6 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -30,6 +30,7 @@ #include "common.h" #include "contact_list.h" #include "log.h" +#include "profanity.h" #include "xmpp/capabilities.h" #include "xmpp/connection.h" #include "xmpp/iq.h" @@ -52,6 +53,8 @@ static int _iq_handle_discoinfo_get(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); static int _iq_handle_discoinfo_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata); +static int _iq_handle_version_result(xmpp_conn_t * const conn, + xmpp_stanza_t * const stanza, void * const userdata); void iq_add_handlers(void) @@ -64,6 +67,7 @@ iq_add_handlers(void) HANDLE(XMPP_NS_DISCO_INFO, STANZA_TYPE_GET, _iq_handle_discoinfo_get); HANDLE(XMPP_NS_DISCO_INFO, STANZA_TYPE_RESULT, _iq_handle_discoinfo_result); HANDLE(STANZA_NS_VERSION, STANZA_TYPE_GET, _iq_handle_version_get); + HANDLE(STANZA_NS_VERSION, STANZA_TYPE_RESULT, _iq_handle_version_result); HANDLE(STANZA_NS_PING, STANZA_TYPE_GET, _iq_handle_ping_get); } @@ -77,6 +81,16 @@ iq_roster_request(void) xmpp_stanza_release(iq); } +void +iq_send_software_version(const char * const fulljid) +{ + xmpp_conn_t * const conn = connection_get_conn(); + xmpp_ctx_t * const ctx = connection_get_ctx(); + xmpp_stanza_t *iq = stanza_create_software_version_iq(ctx, fulljid); + xmpp_send(conn, iq); + xmpp_stanza_release(iq); +} + static int _iq_handle_error(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) @@ -160,6 +174,44 @@ _iq_handle_roster_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, return 1; } +static int +_iq_handle_version_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, + void * const userdata) +{ + const char *jid = xmpp_stanza_get_attribute(stanza, "from"); + + xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY); + if (query == NULL) { + return 1; + } + + char *ns = xmpp_stanza_get_ns(query); + if (g_strcmp0(ns, STANZA_NS_VERSION) != 0) { + return 1; + } + + char *name_str = NULL; + char *version_str = NULL; + char *os_str = NULL; + xmpp_stanza_t *name = xmpp_stanza_get_child_by_name(query, "name"); + xmpp_stanza_t *version = xmpp_stanza_get_child_by_name(query, "version"); + xmpp_stanza_t *os = xmpp_stanza_get_child_by_name(query, "os"); + + if (name != NULL) { + name_str = xmpp_stanza_get_text(name); + } + if (version != NULL) { + version_str = xmpp_stanza_get_text(version); + } + if (os != NULL) { + os_str = xmpp_stanza_get_text(os); + } + + prof_handle_version_result(jid, name_str, version_str, os_str); + + return 1; +} + static int _iq_handle_ping_get(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata) diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 40076939..8e023430 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -139,6 +139,25 @@ stanza_create_presence(xmpp_ctx_t * const ctx) return presence; } +xmpp_stanza_t * +stanza_create_software_version_iq(xmpp_ctx_t *ctx, const char * const fulljid) +{ + xmpp_stanza_t *iq = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(iq, STANZA_NAME_IQ); + xmpp_stanza_set_type(iq, STANZA_TYPE_GET); + xmpp_stanza_set_id(iq, "sv"); + xmpp_stanza_set_attribute(iq, "to", fulljid); + + xmpp_stanza_t *query = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(query, STANZA_NAME_QUERY); + xmpp_stanza_set_ns(query, STANZA_NS_VERSION); + + xmpp_stanza_add_child(iq, query); + xmpp_stanza_release(query); + + return iq; +} + xmpp_stanza_t * stanza_create_roster_iq(xmpp_ctx_t *ctx) { diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 2f3e0216..d07568a7 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -162,5 +162,6 @@ void stanza_attach_status(xmpp_ctx_t * const ctx, xmpp_stanza_t * const presence const char * const status); 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); #endif diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 5edd253e..44f89407 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -88,6 +88,9 @@ void presence_leave_chat_room(const char * const room_jid); void presence_update(resource_presence_t status, const char * const msg, int idle); +// iq functions +void iq_send_software_version(const char * const fulljid); + // caps functions Capabilities* caps_get(const char * const caps_str); void caps_close(void);