From e8a450bc177d989700f882cd7cce33c931f6d5cd Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 21 Sep 2014 21:43:42 +0100 Subject: [PATCH] Sort form fields for sha-1 caps hash --- TODO_CAPS | 5 ++ src/xmpp/capabilities.c | 35 +++++++----- src/xmpp/form.c | 122 ++++++++++++++++++++++++++-------------- src/xmpp/xmpp.h | 3 + 4 files changed, 111 insertions(+), 54 deletions(-) create mode 100644 TODO_CAPS diff --git a/TODO_CAPS b/TODO_CAPS new file mode 100644 index 00000000..05f0e1ab --- /dev/null +++ b/TODO_CAPS @@ -0,0 +1,5 @@ +Generate own hash only once +Handle legacy capabilities +Merge caps and disco info commands, keep disco info +Use filesystem cache + diff --git a/src/xmpp/capabilities.c b/src/xmpp/capabilities.c index 5c93976d..51ba6a98 100644 --- a/src/xmpp/capabilities.c +++ b/src/xmpp/capabilities.c @@ -45,6 +45,7 @@ #include #include "common.h" +#include "log.h" #include "xmpp/xmpp.h" #include "xmpp/stanza.h" #include "xmpp/form.h" @@ -115,10 +116,9 @@ caps_create_sha1_str(xmpp_stanza_t * const query) FormField *field = NULL; GHashTable *forms = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)form_destroy); - GString *s = g_string_new(""); xmpp_stanza_t *child = xmpp_stanza_get_children(query); - while (child != NULL) { + while (child) { if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_IDENTITY) == 0) { category = xmpp_stanza_get_attribute(child, "category"); type = xmpp_stanza_get_attribute(child, "type"); @@ -127,15 +127,15 @@ caps_create_sha1_str(xmpp_stanza_t * const query) GString *identity_str = g_string_new(category); g_string_append(identity_str, "/"); - if (type != NULL) { + if (type) { g_string_append(identity_str, type); } g_string_append(identity_str, "/"); - if (lang != NULL) { + if (lang) { g_string_append(identity_str, lang); } g_string_append(identity_str, "/"); - if (name != NULL) { + if (name) { g_string_append(identity_str, name); } g_string_append(identity_str, "<"); @@ -145,7 +145,7 @@ caps_create_sha1_str(xmpp_stanza_t * const query) feature_str = xmpp_stanza_get_attribute(child, "var"); features = g_slist_insert_sorted(features, g_strdup(feature_str), (GCompareFunc)strcmp); } else if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_X) == 0) { - if (strcmp(xmpp_stanza_get_ns(child), STANZA_NS_DATA) == 0) { + if (g_strcmp0(xmpp_stanza_get_ns(child), STANZA_NS_DATA) == 0) { form = form_create(child); char *form_type = form_get_form_type_field(form); form_names = g_slist_insert_sorted(form_names, g_strdup(form_type), (GCompareFunc)strcmp); @@ -155,44 +155,53 @@ caps_create_sha1_str(xmpp_stanza_t * const query) child = xmpp_stanza_get_next(child); } + GString *s = g_string_new(""); + GSList *curr = identities; - while (curr != NULL) { + while (curr) { g_string_append(s, curr->data); curr = g_slist_next(curr); } curr = features; - while (curr != NULL) { + while (curr) { g_string_append(s, curr->data); g_string_append(s, "<"); curr = g_slist_next(curr); } curr = form_names; - while (curr != NULL) { + while (curr) { form = g_hash_table_lookup(forms, curr->data); char *form_type = form_get_form_type_field(form); g_string_append(s, form_type); g_string_append(s, "<"); - GSList *curr_field = form->fields; - while (curr_field != NULL) { + GSList *sorted_fields = form_get_non_form_type_fields_sorted(form); + GSList *curr_field = sorted_fields; + while (curr_field) { field = curr_field->data; g_string_append(s, field->var); g_string_append(s, "<"); - GSList *curr_value = field->values; - while (curr_value != NULL) { + + GSList *sorted_values = form_get_field_values_sorted(field); + GSList *curr_value = sorted_values; + while (curr_value) { g_string_append(s, curr_value->data); g_string_append(s, "<"); curr_value = g_slist_next(curr_value); } + g_slist_free(sorted_values); curr_field = g_slist_next(curr_field); } + g_slist_free(sorted_fields); curr = g_slist_next(curr); } + log_debug("Generating capabilities hash for: %s", s->str); char *result = p_sha1_hash(s->str); + log_debug("Hash: %s", result); g_string_free(s, TRUE); g_slist_free_full(identities, g_free); diff --git a/src/xmpp/form.c b/src/xmpp/form.c index 25a704d9..7a3baad2 100644 --- a/src/xmpp/form.c +++ b/src/xmpp/form.c @@ -107,9 +107,9 @@ _get_property(xmpp_stanza_t * const stanza, const char * const property) xmpp_ctx_t *ctx = connection_get_ctx(); xmpp_stanza_t *child = xmpp_stanza_get_child_by_name(stanza, property); - if (child != NULL) { + if (child) { char *child_text = xmpp_stanza_get_text(child); - if (child_text != NULL) { + if (child_text) { result = strdup(child_text); xmpp_free(ctx, child_text); } @@ -122,7 +122,7 @@ static char * _get_attr(xmpp_stanza_t * const stanza, const char * const attr) { char *result = xmpp_stanza_get_attribute(stanza, attr); - if (result != NULL) { + if (result) { return strdup(result); } else { return NULL; @@ -133,7 +133,7 @@ static gboolean _is_required(xmpp_stanza_t * const stanza) { xmpp_stanza_t *child = xmpp_stanza_get_child_by_name(stanza, "required"); - if (child != NULL) { + if (child) { return TRUE; } else { return FALSE; @@ -198,7 +198,7 @@ form_create(xmpp_stanza_t * const form_stanza) // get fields xmpp_stanza_t *form_child = xmpp_stanza_get_children(form_stanza); - while (form_child != NULL) { + while (form_child) { char *child_name = xmpp_stanza_get_name(form_child); if (g_strcmp0(child_name, "field") == 0) { xmpp_stanza_t *field_stanza = form_child; @@ -226,13 +226,13 @@ form_create(xmpp_stanza_t * const form_stanza) // handle repeated field children xmpp_stanza_t *field_child = xmpp_stanza_get_children(field_stanza); int value_index = 1; - while (field_child != NULL) { + while (field_child) { child_name = xmpp_stanza_get_name(field_child); // handle values if (g_strcmp0(child_name, "value") == 0) { char *value = xmpp_stanza_get_text(field_child); - if (value != NULL) { + if (value) { field->values = g_slist_append(field->values, strdup(value)); if (field->type_t == FIELD_TEXT_MULTI) { @@ -284,7 +284,7 @@ form_create_submission(DataForm *form) xmpp_stanza_set_type(x, "submit"); GSList *curr_field = form->fields; - while (curr_field != NULL) { + while (curr_field) { FormField *field = curr_field->data; xmpp_stanza_t *field_stanza = xmpp_stanza_new(ctx); @@ -304,8 +304,8 @@ form_create_submission(DataForm *form) case FIELD_JID_SINGLE: value_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_name(value_stanza, "value"); - if (field->values != NULL) { - if (field->values->data != NULL) { + if (field->values) { + if (field->values->data) { xmpp_stanza_t *text_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_text(text_stanza, field->values->data); xmpp_stanza_add_child(value_stanza, text_stanza); @@ -321,12 +321,12 @@ form_create_submission(DataForm *form) case FIELD_LIST_MULTI: case FIELD_JID_MULTI: curr_value = field->values; - while (curr_value != NULL) { + while (curr_value) { char *value = curr_value->data; value_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_name(value_stanza, "value"); - if (value != NULL) { + if (value) { xmpp_stanza_t *text_stanza = xmpp_stanza_new(ctx); xmpp_stanza_set_text(text_stanza, value); xmpp_stanza_add_child(value_stanza, text_stanza); @@ -355,7 +355,7 @@ form_create_submission(DataForm *form) static void _free_option(FormOption *option) { - if (option != NULL) { + if (option) { free(option->label); free(option->value); free(option); @@ -365,7 +365,7 @@ _free_option(FormOption *option) static void _free_field(FormField *field) { - if (field != NULL) { + if (field) { free(field->label); free(field->type); free(field->var); @@ -380,7 +380,7 @@ _free_field(FormField *field) static void _form_destroy(DataForm *form) { - if (form != NULL) { + if (form) { free(form->type); free(form->title); free(form->instructions); @@ -392,11 +392,49 @@ _form_destroy(DataForm *form) } } +static int +_field_compare_by_var(FormField *a, FormField *b) +{ + return g_strcmp0(a->var, b->var); +} + +static GSList * +_form_get_non_form_type_fields_sorted(DataForm *form) +{ + GSList *sorted = NULL; + GSList *curr = form->fields; + while (curr) { + FormField *field = curr->data; + if (g_strcmp0(field->var, "FORM_TYPE") != 0) { + sorted = g_slist_insert_sorted(sorted, field, (GCompareFunc)_field_compare_by_var); + } + curr = g_slist_next(curr); + } + + return sorted; +} + +static GSList * +_form_get_field_values_sorted(FormField *field) +{ + GSList *sorted = NULL; + GSList *curr = field->values; + while (curr) { + char *value = curr->data; + if (value) { + sorted = g_slist_insert_sorted(sorted, value, (GCompareFunc)g_strcmp0); + } + curr = g_slist_next(curr); + } + + return sorted; +} + static char * _form_get_form_type_field(DataForm *form) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, "FORM_TYPE") == 0) { return field->values->data; @@ -412,7 +450,7 @@ _form_tag_exists(DataForm *form, const char * const tag) { GList *tags = g_hash_table_get_keys(form->tag_to_var); GList *curr = tags; - while (curr != NULL) { + while (curr) { if (g_strcmp0(curr->data, tag) == 0) { return TRUE; } @@ -425,9 +463,9 @@ static form_field_type_t _form_get_field_type(DataForm *form, const char * const tag) { char *var = g_hash_table_lookup(form->tag_to_var, tag); - if (var != NULL) { + if (var) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { return field->type_t; @@ -442,9 +480,9 @@ static void _form_set_value(DataForm *form, const char * const tag, char *value) { char *var = g_hash_table_lookup(form->tag_to_var, tag); - if (var != NULL) { + if (var) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { if (g_slist_length(field->values) == 0) { @@ -467,9 +505,9 @@ static void _form_add_value(DataForm *form, const char * const tag, char *value) { char *var = g_hash_table_lookup(form->tag_to_var, tag); - if (var != NULL) { + if (var) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { field->values = g_slist_append(field->values, strdup(value)); @@ -492,13 +530,13 @@ static gboolean _form_add_unique_value(DataForm *form, const char * const tag, char *value) { char *var = g_hash_table_lookup(form->tag_to_var, tag); - if (var != NULL) { + if (var) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { GSList *curr_value = field->values; - while (curr_value != NULL) { + while (curr_value) { if (g_strcmp0(curr_value->data, value) == 0) { return FALSE; } @@ -523,13 +561,13 @@ static gboolean _form_remove_value(DataForm *form, const char * const tag, char *value) { char *var = g_hash_table_lookup(form->tag_to_var, tag); - if (var != NULL) { + if (var) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { GSList *found = g_slist_find_custom(field->values, value, (GCompareFunc)g_strcmp0); - if (found != NULL) { + if (found) { free(found->data); found->data = NULL; field->values = g_slist_delete_link(field->values, found); @@ -554,13 +592,13 @@ _form_remove_text_multi_value(DataForm *form, const char * const tag, int index) { index--; char *var = g_hash_table_lookup(form->tag_to_var, tag); - if (var != NULL) { + if (var) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { GSList *item = g_slist_nth(field->values, index); - if (item != NULL) { + if (item) { free(item->data); item->data = NULL; field->values = g_slist_delete_link(field->values, item); @@ -585,9 +623,9 @@ static int _form_get_value_count(DataForm *form, const char * const tag) { char *var = g_hash_table_lookup(form->tag_to_var, tag); - if (var != NULL) { + if (var) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { if ((g_slist_length(field->values) == 1) && (field->values->data == NULL)) { @@ -607,13 +645,13 @@ static gboolean _form_field_contains_option(DataForm *form, const char * const tag, char *value) { char *var = g_hash_table_lookup(form->tag_to_var, tag); - if (var != NULL) { + if (var) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { GSList *curr_option = field->options; - while (curr_option != NULL) { + while (curr_option) { FormOption *option = curr_option->data; if (g_strcmp0(option->value, value) == 0) { return TRUE; @@ -632,9 +670,9 @@ static FormField * _form_get_field_by_tag(DataForm *form, const char * const tag) { char *var = g_hash_table_lookup(form->tag_to_var, tag); - if (var != NULL) { + if (var) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { return field; @@ -649,9 +687,9 @@ static Autocomplete _form_get_value_ac(DataForm *form, const char * const tag) { char *var = g_hash_table_lookup(form->tag_to_var, tag); - if (var != NULL) { + if (var) { GSList *curr = form->fields; - while (curr != NULL) { + while (curr) { FormField *field = curr->data; if (g_strcmp0(field->var, var) == 0) { return field->value_ac; @@ -691,4 +729,6 @@ form_init_module(void) form_get_value_ac = _form_get_value_ac; form_get_field_by_tag = _form_get_field_by_tag; form_reset_autocompleters = _form_reset_autocompleters; + form_get_non_form_type_fields_sorted = _form_get_non_form_type_fields_sorted; + form_get_field_values_sorted = _form_get_field_values_sorted; } diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 1d5a45a9..0e93bd32 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -226,4 +226,7 @@ FormField* (*form_get_field_by_tag)(DataForm *form, const char * const tag); Autocomplete (*form_get_value_ac)(DataForm *form, const char * const tag); void (*form_reset_autocompleters)(DataForm *form); +GSList * (*form_get_non_form_type_fields_sorted)(DataForm *form); +GSList * (*form_get_field_values_sorted)(FormField *field); + #endif