diff --git a/src/xmpp/capabilities.c b/src/xmpp/capabilities.c index 1c6fc37d..6cdf0852 100644 --- a/src/xmpp/capabilities.c +++ b/src/xmpp/capabilities.c @@ -262,141 +262,6 @@ _caps_copy(EntityCapabilities *caps) return result; } -EntityCapabilities* -caps_create(xmpp_stanza_t *query) -{ - char *software = NULL; - char *software_version = NULL; - char *os = NULL; - char *os_version = NULL; - - xmpp_stanza_t *softwareinfo = xmpp_stanza_get_child_by_ns(query, STANZA_NS_DATA); - if (softwareinfo) { - DataForm *form = form_create(softwareinfo); - FormField *formField = NULL; - - char *form_type = form_get_form_type_field(form); - if (g_strcmp0(form_type, STANZA_DATAFORM_SOFTWARE) == 0) { - GSList *field = form->fields; - while (field) { - formField = field->data; - if (formField->values) { - if (strcmp(formField->var, "software") == 0) { - software = strdup(formField->values->data); - } else if (strcmp(formField->var, "software_version") == 0) { - software_version = strdup(formField->values->data); - } else if (strcmp(formField->var, "os") == 0) { - os = strdup(formField->values->data); - } else if (strcmp(formField->var, "os_version") == 0) { - os_version = strdup(formField->values->data); - } - } - field = g_slist_next(field); - } - } - - form_destroy(form); - } - - xmpp_stanza_t *child = xmpp_stanza_get_children(query); - GSList *identity_stanzas = NULL; - GSList *features = NULL; - while (child) { - if (g_strcmp0(xmpp_stanza_get_name(child), "feature") == 0) { - features = g_slist_append(features, strdup(xmpp_stanza_get_attribute(child, "var"))); - } - if (g_strcmp0(xmpp_stanza_get_name(child), "identity") == 0) { - identity_stanzas = g_slist_append(identity_stanzas, child); - } - - child = xmpp_stanza_get_next(child); - } - - // find identity by locale - const gchar* const *langs = g_get_language_names(); - int num_langs = g_strv_length((gchar**)langs); - xmpp_stanza_t *found = NULL; - GSList *curr_identity = identity_stanzas; - while (curr_identity) { - xmpp_stanza_t *id_stanza = curr_identity->data; - const char *stanza_lang = xmpp_stanza_get_attribute(id_stanza, "xml:lang"); - if (stanza_lang) { - int i = 0; - for (i = 0; i < num_langs; i++) { - if (g_strcmp0(langs[i], stanza_lang) == 0) { - found = id_stanza; - break; - } - } - } - if (found) { - break; - } - curr_identity = g_slist_next(curr_identity); - } - - // not lang match, use default with no lang - if (!found) { - curr_identity = identity_stanzas; - while (curr_identity) { - xmpp_stanza_t *id_stanza = curr_identity->data; - const char *stanza_lang = xmpp_stanza_get_attribute(id_stanza, "xml:lang"); - if (!stanza_lang) { - found = id_stanza; - break; - } - - curr_identity = g_slist_next(curr_identity); - } - } - - // no matching lang, no identity without lang, use first - if (!found) { - if (identity_stanzas) { - found = identity_stanzas->data; - } - } - - g_slist_free(identity_stanzas); - - const char *category = NULL; - const char *type = NULL; - const char *name = NULL; - if (found) { - category = xmpp_stanza_get_attribute(found, "category"); - type = xmpp_stanza_get_attribute(found, "type"); - name = xmpp_stanza_get_attribute(found, "name"); - } - - EntityCapabilities *new_caps = malloc(sizeof(struct entity_capabilities_t)); - - if (category || type || name) { - DiscoIdentity *identity = malloc(sizeof(struct disco_identity_t)); - identity->category = category ? strdup(category) : NULL; - identity->type = type ? strdup(type) : NULL; - identity->name = name ? strdup(name) : NULL; - new_caps->identity = identity; - } else { - new_caps->identity = NULL; - } - - if (software || software_version || os || os_version) { - SoftwareVersion *software_versionp = malloc(sizeof(struct software_version_t)); - software_versionp->software = software; - software_versionp->software_version = software_version; - software_versionp->os = os; - software_versionp->os_version = os_version; - } - - if (features) { - new_caps->features = features; - } else { - new_caps->features = NULL; - } - - return new_caps; -} - char* caps_get_my_sha1(xmpp_ctx_t *const ctx) { diff --git a/src/xmpp/capabilities.h b/src/xmpp/capabilities.h index ecf586b6..b4065825 100644 --- a/src/xmpp/capabilities.h +++ b/src/xmpp/capabilities.h @@ -53,10 +53,7 @@ void caps_add_by_ver(const char *const ver, EntityCapabilities *caps); void caps_add_by_jid(const char *const jid, EntityCapabilities *caps); void caps_map_jid_to_ver(const char *const jid, const char *const ver); gboolean caps_cache_contains(const char *const ver); - GList* caps_get_features(void); - -EntityCapabilities* caps_create(xmpp_stanza_t *query); char* caps_get_my_sha1(xmpp_ctx_t *const ctx); #endif diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index dd811ed6..345eefae 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -746,7 +746,7 @@ _caps_response_id_handler(xmpp_stanza_t *const stanza, void *const userdata) log_info("Capabilties already cached: %s", given_sha1); } else { log_info("Capabilities not cached: %s, storing", given_sha1); - EntityCapabilities *capabilities = caps_create(query); + EntityCapabilities *capabilities = stanza_create_caps_from_query_element(query); caps_add_by_ver(given_sha1, capabilities); caps_destroy(capabilities); } @@ -810,7 +810,7 @@ _caps_response_for_jid_id_handler(xmpp_stanza_t *const stanza, void *const userd } log_info("Associating capabilities with: %s", jid); - EntityCapabilities *capabilities = caps_create(query); + EntityCapabilities *capabilities = stanza_create_caps_from_query_element(query); caps_add_by_jid(jid, capabilities); free(jid); @@ -874,7 +874,7 @@ _caps_response_legacy_id_handler(xmpp_stanza_t *const stanza, void *const userda log_info("Capabilties already cached: %s", node); } else { log_info("Capabilities not cached: %s, storing", node); - EntityCapabilities *capabilities = caps_create(query); + EntityCapabilities *capabilities = stanza_create_caps_from_query_element(query); caps_add_by_ver(node, capabilities); caps_destroy(capabilities); } diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index fa7d9e52..f883d8ed 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -1723,6 +1723,141 @@ stanza_parse_caps(xmpp_stanza_t *const stanza) return caps; } +EntityCapabilities* +stanza_create_caps_from_query_element(xmpp_stanza_t *query) +{ + char *software = NULL; + char *software_version = NULL; + char *os = NULL; + char *os_version = NULL; + + xmpp_stanza_t *softwareinfo = xmpp_stanza_get_child_by_ns(query, STANZA_NS_DATA); + if (softwareinfo) { + DataForm *form = form_create(softwareinfo); + FormField *formField = NULL; + + char *form_type = form_get_form_type_field(form); + if (g_strcmp0(form_type, STANZA_DATAFORM_SOFTWARE) == 0) { + GSList *field = form->fields; + while (field) { + formField = field->data; + if (formField->values) { + if (strcmp(formField->var, "software") == 0) { + software = strdup(formField->values->data); + } else if (strcmp(formField->var, "software_version") == 0) { + software_version = strdup(formField->values->data); + } else if (strcmp(formField->var, "os") == 0) { + os = strdup(formField->values->data); + } else if (strcmp(formField->var, "os_version") == 0) { + os_version = strdup(formField->values->data); + } + } + field = g_slist_next(field); + } + } + + form_destroy(form); + } + + xmpp_stanza_t *child = xmpp_stanza_get_children(query); + GSList *identity_stanzas = NULL; + GSList *features = NULL; + while (child) { + if (g_strcmp0(xmpp_stanza_get_name(child), "feature") == 0) { + features = g_slist_append(features, strdup(xmpp_stanza_get_attribute(child, "var"))); + } + if (g_strcmp0(xmpp_stanza_get_name(child), "identity") == 0) { + identity_stanzas = g_slist_append(identity_stanzas, child); + } + + child = xmpp_stanza_get_next(child); + } + + // find identity by locale + const gchar* const *langs = g_get_language_names(); + int num_langs = g_strv_length((gchar**)langs); + xmpp_stanza_t *found = NULL; + GSList *curr_identity = identity_stanzas; + while (curr_identity) { + xmpp_stanza_t *id_stanza = curr_identity->data; + const char *stanza_lang = xmpp_stanza_get_attribute(id_stanza, "xml:lang"); + if (stanza_lang) { + int i = 0; + for (i = 0; i < num_langs; i++) { + if (g_strcmp0(langs[i], stanza_lang) == 0) { + found = id_stanza; + break; + } + } + } + if (found) { + break; + } + curr_identity = g_slist_next(curr_identity); + } + + // not lang match, use default with no lang + if (!found) { + curr_identity = identity_stanzas; + while (curr_identity) { + xmpp_stanza_t *id_stanza = curr_identity->data; + const char *stanza_lang = xmpp_stanza_get_attribute(id_stanza, "xml:lang"); + if (!stanza_lang) { + found = id_stanza; + break; + } + + curr_identity = g_slist_next(curr_identity); + } + } + + // no matching lang, no identity without lang, use first + if (!found) { + if (identity_stanzas) { + found = identity_stanzas->data; + } + } + + g_slist_free(identity_stanzas); + + const char *category = NULL; + const char *type = NULL; + const char *name = NULL; + if (found) { + category = xmpp_stanza_get_attribute(found, "category"); + type = xmpp_stanza_get_attribute(found, "type"); + name = xmpp_stanza_get_attribute(found, "name"); + } + + EntityCapabilities *new_caps = malloc(sizeof(struct entity_capabilities_t)); + + if (category || type || name) { + DiscoIdentity *identity = malloc(sizeof(struct disco_identity_t)); + identity->category = category ? strdup(category) : NULL; + identity->type = type ? strdup(type) : NULL; + identity->name = name ? strdup(name) : NULL; + new_caps->identity = identity; + } else { + new_caps->identity = NULL; + } + + if (software || software_version || os || os_version) { + SoftwareVersion *software_versionp = malloc(sizeof(struct software_version_t)); + software_versionp->software = software; + software_versionp->software_version = software_version; + software_versionp->os = os; + software_versionp->os_version = os_version; + } + + if (features) { + new_caps->features = features; + } else { + new_caps->features = NULL; + } + + return new_caps; +} + char* stanza_get_error_message(xmpp_stanza_t *stanza) { diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index a7de205b..806ba615 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -293,6 +293,7 @@ void stanza_attach_status(xmpp_ctx_t *const ctx, xmpp_stanza_t *const presence, xmpp_stanza_t* stanza_create_caps_query_element(xmpp_ctx_t *ctx); char* stanza_create_caps_sha1_from_query(xmpp_stanza_t *const query); +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);