about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/xmpp/iq.c202
-rw-r--r--src/xmpp/presence.c14
-rw-r--r--src/xmpp/xmpp.h2
3 files changed, 185 insertions, 33 deletions
diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c
index 1138620d..2292e9c4 100644
--- a/src/xmpp/iq.c
+++ b/src/xmpp/iq.c
@@ -96,6 +96,10 @@ static int _ping_timed_handler(xmpp_conn_t * const conn,
     void * const userdata);
 static int _caps_response_handler(xmpp_conn_t *const conn,
     xmpp_stanza_t * const stanza, void * const userdata);
+static int _caps_response_handler_for_jid(xmpp_conn_t *const conn,
+    xmpp_stanza_t * const stanza, void * const userdata);
+static int _caps_response_handler_legacy(xmpp_conn_t *const conn,
+    xmpp_stanza_t * const stanza, void * const userdata);
 
 void
 iq_add_handlers(void)
@@ -201,7 +205,7 @@ _iq_send_caps_request_for_jid(const char * const to, const char * const id,
     xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, to, node_str->str);
     g_string_free(node_str, TRUE);
 
-    xmpp_id_handler_add(conn, _caps_response_handler, id, strdup(to));
+    xmpp_id_handler_add(conn, _caps_response_handler_for_jid, id, strdup(to));
 
     xmpp_send(conn, iq);
     xmpp_stanza_release(iq);
@@ -235,6 +239,33 @@ _iq_send_caps_request(const char * const to, const char * const id,
 }
 
 static void
+_iq_send_caps_request_legacy(const char * const to, const char * const id,
+    const char * const node, const char * const ver)
+{
+    xmpp_conn_t * const conn = connection_get_conn();
+    xmpp_ctx_t * const ctx = connection_get_ctx();
+
+    if (!node) {
+        log_error("Could not create caps request, no node");
+        return;
+    }
+    if (!ver) {
+        log_error("Could not create caps request, no ver");
+        return;
+    }
+
+    GString *node_str = g_string_new("");
+    g_string_printf(node_str, "%s#%s", node, ver);
+    xmpp_stanza_t *iq = stanza_create_disco_info_iq(ctx, id, to, node_str->str);
+
+    xmpp_id_handler_add(conn, _caps_response_handler_legacy, id, node_str->str);
+    g_string_free(node_str, FALSE);
+
+    xmpp_send(conn, iq);
+    xmpp_stanza_release(iq);
+}
+
+static void
 _iq_disco_items_request(gchar *jid)
 {
     xmpp_conn_t * const conn = connection_get_conn();
@@ -521,40 +552,154 @@ _caps_response_handler(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza,
         return 0;
     }
 
-    if (userdata) {
-        char *jid = (char *)userdata;
-        log_info("Associating capabilities with: %s", jid);
-        Capabilities *capabilities = caps_create(query);
-        caps_add_by_jid(jid, capabilities);
+    // validate sha1
+    gchar **split = g_strsplit(node, "#", -1);
+    char *given_sha1 = split[1];
+    char *generated_sha1 = caps_create_sha1_str(query);
+
+    if (g_strcmp0(given_sha1, generated_sha1) != 0) {
+        log_warning("Generated sha-1 does not match given:");
+        log_warning("Generated : %s", generated_sha1);
+        log_warning("Given     : %s", given_sha1);
     } else {
-        // validate sha1
-        gchar **split = g_strsplit(node, "#", -1);
-        char *given_sha1 = split[1];
-        char *generated_sha1 = caps_create_sha1_str(query);
-
-        if (g_strcmp0(given_sha1, generated_sha1) != 0) {
-            log_warning("Generated sha-1 does not match given:");
-            log_warning("Generated : %s", generated_sha1);
-            log_warning("Given     : %s", given_sha1);
+        log_info("Valid SHA-1 hash found: %s", given_sha1);
+
+        if (caps_contains(given_sha1)) {
+            log_info("Capabilties already cached: %s", given_sha1);
         } else {
-            log_info("Valid SHA-1 hash found: %s", given_sha1);
-
-            if (caps_contains(given_sha1)) {
-                log_info("Capabilties already cached: %s", given_sha1);
-            } else {
-                log_info("Capabilities not cached: %s, storing", given_sha1);
-                Capabilities *capabilities = caps_create(query);
-                caps_add_by_ver(given_sha1, capabilities);
-                caps_destroy(capabilities);
-            }
+            log_info("Capabilities not cached: %s, storing", given_sha1);
+            Capabilities *capabilities = caps_create(query);
+            caps_add_by_ver(given_sha1, capabilities);
+            caps_destroy(capabilities);
+        }
+
+        caps_map_jid_to_ver(from, given_sha1);
+    }
 
-            caps_map_jid_to_ver(from, given_sha1);
+    g_free(generated_sha1);
+    g_strfreev(split);
+
+    return 0;
+}
+
+static int
+_caps_response_handler_for_jid(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza,
+    void * const userdata)
+{
+    const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID);
+    xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY);
+
+    char *type = xmpp_stanza_get_type(stanza);
+    // ignore non result
+    if ((g_strcmp0(type, "get") == 0) || (g_strcmp0(type, "set") == 0)) {
+        return 1;
+    }
+
+    if (id) {
+        log_info("Capabilities response handler fired for id %s", id);
+    } else {
+        log_info("Capabilities response handler fired");
+    }
+
+    const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM);
+    if (!from) {
+        log_info("No from attribute");
+        return 0;
+    }
+
+    // handle error responses
+    if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) {
+        char *error_message = stanza_get_error_message(stanza);
+        log_warning("Error received for capabilities response from %s: ", from, error_message);
+        free(error_message);
+        return 0;
+    }
+
+    if (query == NULL) {
+        log_warning("No query element found.");
+        return 0;
+    }
+
+    char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE);
+    if (node == NULL) {
+        log_warning("No node attribute found");
+        return 0;
+    }
+
+    char *jid = (char *)userdata;
+    log_info("Associating capabilities with: %s", jid);
+    Capabilities *capabilities = caps_create(query);
+    caps_add_by_jid(jid, capabilities);
+
+    return 0;
+}
+
+static int
+_caps_response_handler_legacy(xmpp_conn_t *const conn, xmpp_stanza_t * const stanza,
+    void * const userdata)
+{
+    const char *id = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_ID);
+    xmpp_stanza_t *query = xmpp_stanza_get_child_by_name(stanza, STANZA_NAME_QUERY);
+
+    char *type = xmpp_stanza_get_type(stanza);
+    // ignore non result
+    if ((g_strcmp0(type, "get") == 0) || (g_strcmp0(type, "set") == 0)) {
+        return 1;
+    }
+
+    if (id) {
+        log_info("Capabilities response handler fired for id %s", id);
+    } else {
+        log_info("Capabilities response handler fired");
+    }
+
+    const char *from = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_FROM);
+    if (!from) {
+        log_info("No from attribute");
+        return 0;
+    }
+
+    // handle error responses
+    if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) {
+        char *error_message = stanza_get_error_message(stanza);
+        log_warning("Error received for capabilities response from %s: ", from, error_message);
+        free(error_message);
+        return 0;
+    }
+
+    if (query == NULL) {
+        log_warning("No query element found.");
+        return 0;
+    }
+
+    char *node = xmpp_stanza_get_attribute(query, STANZA_ATTR_NODE);
+    if (node == NULL) {
+        log_warning("No node attribute found");
+        return 0;
+    }
+
+    char *expected_node = (char *)userdata;
+
+    // nodes match
+    if (g_strcmp0(expected_node, node) == 0) {
+        log_info("Legacy capabilities, nodes match %s", node);
+        if (caps_contains(node)) {
+            log_info("Capabilties already cached: %s", node);
+        } else {
+            log_info("Capabilities not cached: %s, storing", node);
+            Capabilities *capabilities = caps_create(query);
+            caps_add_by_ver(node, capabilities);
+            caps_destroy(capabilities);
         }
 
-        g_free(generated_sha1);
-        g_strfreev(split);
+        caps_map_jid_to_ver(from, node);
+
+    // node match fail
+    } else {
+        log_info("Legacy Capabilities nodes do not match, expeceted %s, given %s.", expected_node, node);
     }
 
+    free(expected_node);
     return 0;
 }
 
@@ -1295,6 +1440,7 @@ iq_init_module(void)
     iq_submit_room_config = _iq_submit_room_config;
     iq_send_caps_request = _iq_send_caps_request;
     iq_send_caps_request_for_jid = _iq_send_caps_request_for_jid;
+    iq_send_caps_request_legacy = _iq_send_caps_request_legacy;
     iq_room_info_request = _iq_room_info_request;
     iq_room_affiliation_set = _iq_room_affiliation_set;
     iq_room_affiliation_list = _iq_room_affiliation_list;
diff --git a/src/xmpp/presence.c b/src/xmpp/presence.c
index 5acec9da..9e24c7ac 100644
--- a/src/xmpp/presence.c
+++ b/src/xmpp/presence.c
@@ -502,7 +502,7 @@ _unavailable_handler(xmpp_conn_t * const conn,
 static void
 _handle_caps(char *jid, XMPPCaps *caps)
 {
-    // hash supported xep-0115
+    // hash supported, xep-0115, cache against ver
     if (g_strcmp0(caps->hash, "sha-1") == 0) {
         log_info("Hash %s supported", caps->hash);
         if (caps->ver) {
@@ -517,17 +517,21 @@ _handle_caps(char *jid, XMPPCaps *caps)
             }
         }
 
-    // unsupported hash
+    // unsupported hash, xep-0115, assoiciate with JID, no cache
     } else if (caps->hash) {
         log_info("Hash %s not supported: %s, sending service discovery request", caps->hash, jid);
         char *id = create_unique_id("caps");
         iq_send_caps_request_for_jid(jid, id, caps->node, caps->ver);
         free(id);
 
-    // no hash
+   // no hash, legacy caps, cache against node#ver
+   } else if (caps->node && caps->ver) {
+        log_info("No hash specified: %s, legacy request made for %s#%s", jid, caps->node, caps->ver);
+        char *id = create_unique_id("caps");
+        iq_send_caps_request_legacy(jid, id, caps->node, caps->ver);
+        free(id);
     } else {
-        log_info("No hash specified: %s, not sending service discovery request", jid);
-        // do legacy
+        log_info("No hash specified: %s, could not create ver string, not sending service disovery request.", jid);
     }
 }
 
diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h
index 349f8638..f300e84f 100644
--- a/src/xmpp/xmpp.h
+++ b/src/xmpp/xmpp.h
@@ -194,6 +194,8 @@ void (*iq_send_caps_request)(const char * const to, const char * const id,
     const char * const node, const char * const ver);
 void (*iq_send_caps_request_for_jid)(const char * const to, const char * const id,
     const char * const node, const char * const ver);
+void (*iq_send_caps_request_legacy)(const char * const to, const char * const id,
+    const char * const node, const char * const ver);
 void (*iq_room_info_request)(gchar *room);
 void (*iq_room_affiliation_list)(const char * const room, char *affiliation);
 void (*iq_room_affiliation_set)(const char * const room, const char * const jid, char *affiliation,