about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/command/command.c33
-rw-r--r--src/contact_list.c24
-rw-r--r--src/contact_list.h1
-rw-r--r--src/profanity.c8
-rw-r--r--src/profanity.h2
-rw-r--r--src/ui/ui.h2
-rw-r--r--src/ui/windows.c19
-rw-r--r--src/xmpp/iq.c52
-rw-r--r--src/xmpp/stanza.c19
-rw-r--r--src/xmpp/stanza.h1
-rw-r--r--src/xmpp/xmpp.h3
11 files changed, 163 insertions, 1 deletions
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",
@@ -1939,6 +1951,27 @@ _cmd_caps(gchar **args, struct cmd_help_t help)
 }
 
 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)
 {
     jabber_conn_status_t conn_status = jabber_get_connection_status();
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 <glib.h>
 
 #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
@@ -1206,6 +1206,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)
 {
     PContact pcontact = contact_list_get_contact(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)
@@ -161,6 +175,44 @@ _iq_handle_roster_result(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
 }
 
 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
@@ -140,6 +140,25 @@ stanza_create_presence(xmpp_ctx_t * const ctx)
 }
 
 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)
 {
     xmpp_stanza_t *iq = xmpp_stanza_new(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);