diff --git a/src/ui/core.c b/src/ui/core.c
index bbaebe31..9cbd873a 100644
--- a/src/ui/core.c
+++ b/src/ui/core.c
@@ -2792,6 +2792,24 @@ ui_hide_roster(void)
}
}
+void
+ui_handle_software_version_error(const char * const roomjid, const char * const message)
+{
+ GString *message_str = g_string_new("");
+
+ ProfWin *window = wins_get_console();
+ g_string_printf(message_str, "Could not get software version");
+
+ if (message) {
+ g_string_append(message_str, ": ");
+ g_string_append(message_str, message);
+ }
+
+ win_print(window, '-', 0, NULL, 0, THEME_ERROR, "", message_str->str);
+
+ g_string_free(message_str, TRUE);
+}
+
static void
_win_show_history(ProfChatWin *chatwin, const char * const contact)
{
diff --git a/src/ui/ui.h b/src/ui/ui.h
index fd81f68a..d22a5c7f 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -203,6 +203,7 @@ void ui_redraw_all_room_rosters(void);
void ui_show_all_room_rosters(void);
void ui_hide_all_room_rosters(void);
gboolean ui_chat_win_exists(const char * const barejid);
+void ui_handle_software_version_error(const char * const roomjid, const char * const message);
gboolean ui_tidy_wins(void);
void ui_prune_wins(void);
diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c
index 18abad36..a07fbf73 100644
--- a/src/xmpp/iq.c
+++ b/src/xmpp/iq.c
@@ -67,10 +67,10 @@ typedef struct p_room_info_data_t {
static int _error_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
static int _ping_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
static int _version_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
+static int _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
static int _disco_info_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
static int _disco_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
static int _room_info_response_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
-static int _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
static int _disco_items_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
static int _disco_items_get_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
static int _destroy_room_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza, void * const userdata);
@@ -103,7 +103,6 @@ iq_add_handlers(void)
HANDLE(XMPP_NS_DISCO_ITEMS, STANZA_TYPE_RESULT, _disco_items_result_handler);
HANDLE(STANZA_NS_VERSION, STANZA_TYPE_GET, _version_get_handler);
- HANDLE(STANZA_NS_VERSION, STANZA_TYPE_RESULT, _version_result_handler);
HANDLE(STANZA_NS_PING, STANZA_TYPE_GET, _ping_get_handler);
@@ -301,6 +300,10 @@ 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);
+
+ char *id = xmpp_stanza_get_id(iq);
+ xmpp_id_handler_add(conn, _version_result_handler, id, strdup(fulljid));
+
xmpp_send(conn, iq);
xmpp_stanza_release(iq);
}
@@ -836,16 +839,34 @@ _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
log_debug("IQ version result handler fired.");
}
+ char *type = xmpp_stanza_get_type(stanza);
+ char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM);
+
+ if (g_strcmp0(type, STANZA_TYPE_RESULT) != 0) {
+ if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) {
+ char *error_message = stanza_get_error_message(stanza);
+ ui_handle_software_version_error(from, error_message);
+ free(error_message);
+ } else {
+ ui_handle_software_version_error(from, "unknown error");
+ log_error("Software version result with unrecognised type attribute.");
+ }
+
+ return 0;
+ }
+
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;
+ log_error("Software version result recieved with no query element.");
+ return 0;
}
char *ns = xmpp_stanza_get_ns(query);
if (g_strcmp0(ns, STANZA_NS_VERSION) != 0) {
- return 1;
+ log_error("Software version result recieved without namespace.");
+ return 0;
}
char *name_str = NULL;
@@ -865,7 +886,11 @@ _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
os_str = xmpp_stanza_get_text(os);
}
- Jid *jidp = jid_create(jid);
+ if (g_strcmp0(jid, (char*)userdata) != 0) {
+ log_warning("From attribute specified different JID, using original JID.");
+ }
+
+ Jid *jidp = jid_create((char*)userdata);
const char *presence = NULL;
if (muc_active(jidp->barejid)) {
Occupant *occupant = muc_roster_item(jidp->barejid, jidp->resourcepart);
@@ -873,14 +898,19 @@ _version_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanza,
} else {
PContact contact = roster_get_contact(jidp->barejid);
Resource *resource = p_contact_get_resource(contact, jidp->resourcepart);
+ if (!resource) {
+ ui_handle_software_version_error(jidp->fulljid, "Unknown resource");
+ return 0;
+ }
presence = string_from_resource_presence(resource->presence);
}
- cons_show_software_version(jid, presence, name_str, version_str, os_str);
+ cons_show_software_version(jidp->fulljid, presence, name_str, version_str, os_str);
jid_destroy(jidp);
+ free(userdata);
- return 1;
+ return 0;
}
static int
@@ -1567,4 +1597,4 @@ _disco_items_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stan
g_slist_free_full(items, (GDestroyNotify)_item_destroy);
return 1;
-}
\ No newline at end of file
+}
diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c
index be85c330..bb32932a 100644
--- a/src/xmpp/stanza.c
+++ b/src/xmpp/stanza.c
@@ -877,7 +877,11 @@ 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");
+
+ char *id = create_unique_id("sv");
+ xmpp_stanza_set_id(iq, id);
+ free(id);
+
xmpp_stanza_set_attribute(iq, "to", fulljid);
xmpp_stanza_t *query = xmpp_stanza_new(ctx);
diff --git a/tests/functionaltests/functionaltests.c b/tests/functionaltests/functionaltests.c
index 34362df0..08f71faf 100644
--- a/tests/functionaltests/functionaltests.c
+++ b/tests/functionaltests/functionaltests.c
@@ -85,6 +85,8 @@ int main(int argc, char* argv[]) {
PROF_FUNC_TEST(send_software_version_request),
PROF_FUNC_TEST(display_software_version_result),
+ PROF_FUNC_TEST(shows_message_when_software_version_error),
+ PROF_FUNC_TEST(display_software_version_result_when_from_domainpart),
};
return run_tests(all_tests);
diff --git a/tests/functionaltests/test_presence.c b/tests/functionaltests/test_presence.c
index 24bbfd3e..7e28a8b6 100644
--- a/tests/functionaltests/test_presence.c
+++ b/tests/functionaltests/test_presence.c
@@ -251,6 +251,7 @@ presence_received(void **state)
assert_true(prof_output_exact("Buddy1 (mobile) is online, \"I'm here\""));
}
+// Typical use case for gateways that don't support resources
void
presence_missing_resource_defaults(void **state)
{
diff --git a/tests/functionaltests/test_software.c b/tests/functionaltests/test_software.c
index aeb3f8f5..08c3edff 100644
--- a/tests/functionaltests/test_software.c
+++ b/tests/functionaltests/test_software.c
@@ -57,3 +57,56 @@ display_software_version_result(void **state)
prof_output_exact("Name : Profanity");
prof_output_exact("Version : 0.4.7dev.master.2cb2f83");
}
+
+void
+shows_message_when_software_version_error(void **state)
+{
+ prof_connect();
+ stbbr_send(
+ ""
+ "10"
+ "I'm here"
+ ""
+ );
+ prof_output_exact("Buddy1 (mobile) is online, \"I'm here\"");
+
+ stbbr_for_query("jabber:iq:version",
+ ""
+ ""
+ ""
+ ""
+ ""
+ ""
+ );
+ prof_input("/software buddy1@localhost/laptop");
+
+ prof_output_exact("Could not get software version: service-unavailable");
+}
+
+// Typical use case for gateways that don't support resources
+void
+display_software_version_result_when_from_domainpart(void **state)
+{
+ prof_connect();
+ stbbr_send(
+ ""
+ "10"
+ "I'm here"
+ ""
+ );
+ prof_output_exact("Buddy1 is online, \"I'm here\"");
+
+ stbbr_for_query("jabber:iq:version",
+ ""
+ ""
+ "Some Gateway"
+ "1.0"
+ ""
+ ""
+ );
+ prof_input("/software buddy1@localhost/__prof_default");
+
+ prof_output_exact("buddy1@localhost/__prof_default:");
+ prof_output_exact("Name : Some Gateway");
+ prof_output_exact("Version : 1.0");
+}
diff --git a/tests/functionaltests/test_software.h b/tests/functionaltests/test_software.h
index b031e264..6d75f049 100644
--- a/tests/functionaltests/test_software.h
+++ b/tests/functionaltests/test_software.h
@@ -1,3 +1,5 @@
void send_software_version_request(void **state);
void display_software_version_result(void **state);
+void shows_message_when_software_version_error(void **state);
+void display_software_version_result_when_from_domainpart(void **state);