diff options
author | James Booth <boothj5@gmail.com> | 2014-09-06 22:40:57 +0100 |
---|---|---|
committer | James Booth <boothj5@gmail.com> | 2014-09-06 22:40:57 +0100 |
commit | 2599c43d66915854d6f8658d95ce79eeb1123c35 (patch) | |
tree | 4ae99b2e4feb635259b18125b2769dbdec989612 /src | |
parent | 157a1b5ff75d706d5dda11c4208b05daa1552791 (diff) | |
download | profani-tty-2599c43d66915854d6f8658d95ce79eeb1123c35.tar.gz |
Rewrite form parser
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 1 | ||||
-rw-r--r-- | src/server_events.c | 7 | ||||
-rw-r--r-- | src/xmpp/capabilities.c | 8 | ||||
-rw-r--r-- | src/xmpp/form.c | 268 | ||||
-rw-r--r-- | src/xmpp/iq.c | 3 | ||||
-rw-r--r-- | src/xmpp/xmpp.h | 14 |
6 files changed, 227 insertions, 74 deletions
diff --git a/src/main.c b/src/main.c index 898cdaf3..e4643d2e 100644 --- a/src/main.c +++ b/src/main.c @@ -63,6 +63,7 @@ _init_modules(void) message_init_module(); presence_init_module(); roster_init_module(); + form_init_module(); ui_init_module(); console_init_module(); diff --git a/src/server_events.c b/src/server_events.c index 2fe6ace1..3cf299ab 100644 --- a/src/server_events.c +++ b/src/server_events.c @@ -467,11 +467,6 @@ void handle_room_configure(const char * const room, DataForm *form) { cons_show("Recieved configuration form for %s", room); - if (form->form_type != NULL) { - cons_show("Form type: %s", form->form_type); - } else { - cons_show("No form type specified"); - } GSList *fields = form->fields; GSList *curr = fields; @@ -492,6 +487,8 @@ handle_room_configure(const char * const room, DataForm *form) curr = g_slist_next(curr); } + + form_destroy(form); } void diff --git a/src/xmpp/capabilities.c b/src/xmpp/capabilities.c index c0c46ab7..942d0697 100644 --- a/src/xmpp/capabilities.c +++ b/src/xmpp/capabilities.c @@ -172,8 +172,9 @@ caps_create_sha1_str(xmpp_stanza_t * const query) } else if (g_strcmp0(xmpp_stanza_get_name(child), STANZA_NAME_X) == 0) { if (strcmp(xmpp_stanza_get_ns(child), STANZA_NS_DATA) == 0) { form = form_create(child); - form_names = g_slist_insert_sorted(form_names, g_strdup(form->form_type), (GCompareFunc)strcmp); - g_hash_table_insert(forms, g_strdup(form->form_type), form); + char *form_type = form_get_field_by_var(form, "FORM_TYPE"); + form_names = g_slist_insert_sorted(form_names, g_strdup(form_type), (GCompareFunc)strcmp); + g_hash_table_insert(forms, g_strdup(form_type), form); } } child = xmpp_stanza_get_next(child); @@ -195,7 +196,8 @@ caps_create_sha1_str(xmpp_stanza_t * const query) curr = form_names; while (curr != NULL) { form = g_hash_table_lookup(forms, curr->data); - g_string_append(s, form->form_type); + char *form_type = form_get_field_by_var(form, "FORM_TYPE"); + g_string_append(s, form_type); g_string_append(s, "<"); GSList *curr_field = form->fields; diff --git a/src/xmpp/form.c b/src/xmpp/form.c index 237cbdd7..f352feab 100644 --- a/src/xmpp/form.c +++ b/src/xmpp/form.c @@ -36,109 +36,249 @@ #include <stdlib.h> #include <strophe.h> +#include <glib.h> +#include "log.h" #include "xmpp/xmpp.h" +#include "xmpp/stanza.h" #include "xmpp/connection.h" -static int _field_compare(FormField *f1, FormField *f2); +static gboolean +_is_valid_form_element(xmpp_stanza_t *stanza) +{ + char *name = xmpp_stanza_get_name(stanza); + if (g_strcmp0(name, STANZA_NAME_X) != 0) { + log_error("Error parsing form, root element not <x/>."); + return FALSE; + } -DataForm * -form_create(xmpp_stanza_t * const stanza) + char *ns = xmpp_stanza_get_ns(stanza); + if (g_strcmp0(ns, STANZA_NS_DATA) != 0) { + log_error("Error parsing form, namespace not %s.", STANZA_NS_DATA); + return FALSE; + } + + char *type = xmpp_stanza_get_attribute(stanza, STANZA_ATTR_TYPE); + if ((g_strcmp0(type, "form") != 0) && + (g_strcmp0(type, "submit") != 0) && + (g_strcmp0(type, "cancel") != 0) && + (g_strcmp0(type, "result") != 0)) { + log_error("Error parsing form, unknown type."); + return FALSE; + } + + return TRUE; +} + +static DataForm * +_form_new(void) { - DataForm *result = NULL; + DataForm *form = malloc(sizeof(DataForm)); + form->type = NULL; + form->title = NULL; + form->instructions = NULL; + form->fields = NULL; + + return form; +} + +static FormField * +_field_new(void) +{ + FormField *field = malloc(sizeof(FormField)); + field->label = NULL; + field->type = NULL; + field->var = NULL; + field->description = NULL; + field->required = FALSE; + field->values = NULL; + field->options = NULL; + + return field; +} + +static char * +_get_property(xmpp_stanza_t * const stanza, const char * const property) +{ + char *result = NULL; xmpp_ctx_t *ctx = connection_get_ctx(); - xmpp_stanza_t *child = xmpp_stanza_get_children(stanza); + xmpp_stanza_t *child = xmpp_stanza_get_child_by_name(stanza, property); + if (child != NULL) { + char *child_text = xmpp_stanza_get_text(child); + if (child_text != NULL) { + result = strdup(child_text); + xmpp_free(ctx, child_text); + } + } + + return result; +} + +static char * +_get_attr(xmpp_stanza_t * const stanza, const char * const attr) +{ + char *result = xmpp_stanza_get_attribute(stanza, attr); + if (result != NULL) { + return strdup(result); + } else { + return NULL; + } +} +static gboolean +_is_required(xmpp_stanza_t * const stanza) +{ + xmpp_stanza_t *child = xmpp_stanza_get_child_by_name(stanza, "required"); if (child != NULL) { - result = malloc(sizeof(DataForm)); - result->form_type = NULL; - result->fields = NULL; + return TRUE; + } else { + return FALSE; } +} - //handle fields - while (child != NULL) { - char *label = xmpp_stanza_get_attribute(child, "label"); - char *type = xmpp_stanza_get_attribute(child, "type"); - char *var = xmpp_stanza_get_attribute(child, "var"); - - // handle FORM_TYPE - if (g_strcmp0(var, "FORM_TYPE") == 0) { - xmpp_stanza_t *value = xmpp_stanza_get_child_by_name(child, "value"); - char *value_text = xmpp_stanza_get_text(value); - if (value_text != NULL) { - result->form_type = strdup(value_text); - xmpp_free(ctx, value_text); - } +DataForm * +form_create(xmpp_stanza_t * const form_stanza) +{ + xmpp_ctx_t *ctx = connection_get_ctx(); - // handle regular fields - } else { - FormField *field = malloc(sizeof(FormField)); - field->label = NULL; - field->type = NULL; - field->var = NULL; + if (!_is_valid_form_element(form_stanza)) { + return NULL; + } - if (label != NULL) { - field->label = strdup(label); - } - if (type != NULL) { - field->type = strdup(type); - } - if (var != NULL) { - field->var = strdup(var); - } + DataForm *form = _form_new(); + form->type = _get_attr(form_stanza, "type"); + form->title = _get_property(form_stanza, "title"); + form->instructions = _get_property(form_stanza, "instructions"); + + // get fields + xmpp_stanza_t *form_child = xmpp_stanza_get_children(form_stanza); + while (form_child != NULL) { + char *child_name = xmpp_stanza_get_name(form_child); + if (g_strcmp0(child_name, "field") == 0) { + xmpp_stanza_t *field_stanza = form_child; + + FormField *field = _field_new(); + field->label = _get_attr(field_stanza, "label"); + field->type = _get_attr(field_stanza, "type"); + field->var = _get_attr(field_stanza, "var"); + field->description = _get_property(field_stanza, "desc"); + field->required = _is_required(field_stanza); + + // handle repeated field children + xmpp_stanza_t *field_child = xmpp_stanza_get_children(field_stanza); + while (field_child != NULL) { + // handle values + if (g_strcmp0(child_name, "value") == 0) { + char *value = xmpp_stanza_get_text(field_child); + if (value != NULL) { + field->values = g_slist_append(field->values, value); + xmpp_free(ctx, value); + } + + // handle options + } else if (g_strcmp0(child_name, "option") == 0) { + FormOption *option = malloc(sizeof(FormOption)); + option->label = _get_attr(field_child, "label"); + option->value = _get_property(field_child, "value"); - // handle values - field->values = NULL; - xmpp_stanza_t *value = xmpp_stanza_get_children(child); - while (value != NULL) { - char *text = xmpp_stanza_get_text(value); - if (text != NULL) { - field->values = g_slist_insert_sorted(field->values, strdup(text), (GCompareFunc)strcmp); - xmpp_free(ctx, text); + field->options = g_slist_append(field->options, option); } - value = xmpp_stanza_get_next(value); + + field_child = xmpp_stanza_get_next(field_child); } - result->fields = g_slist_insert_sorted(result->fields, field, (GCompareFunc)_field_compare); + form->fields = g_slist_append(form->fields, field); } - child = xmpp_stanza_get_next(child); + form_child = xmpp_stanza_get_next(form_child); } - return result; + return form; } -void +static void +_free_option(FormOption *option) +{ + if (option != NULL) { + if (option->label != NULL) { + free(option->label); + } + if (option->value != NULL) { + free(option->value); + } + + free(option); + } +} + +static void +_free_field(FormField *field) +{ + if (field != NULL) { + if (field->label != NULL) { + free(field->label); + } + if (field->type != NULL) { + free(field->type); + } + if (field->var != NULL) { + free(field->var); + } + if (field->description != NULL) { + free(field->description); + } + if (field->values != NULL) { + g_slist_free_full(field->values, free); + } + if (field->options != NULL) { + g_slist_free_full(field->options, (GDestroyNotify)_free_option); + } + + free(field); + } +} + +static void _form_destroy(DataForm *form) { if (form != NULL) { + if (form->type != NULL) { + free(form->type); + } + if (form->title != NULL) { + free(form->title); + } + if (form->instructions != NULL) { + free(form->instructions); + } + if (form->fields != NULL) { - GSList *curr_field = form->fields; - while (curr_field != NULL) { - FormField *field = curr_field->data; - free(field->var); - if ((field->values) != NULL) { - g_slist_free_full(field->values, free); - } - curr_field = curr_field->next; - } - g_slist_free_full(form->fields, free); + g_slist_free_full(form->fields, (GDestroyNotify)_free_field); } - free(form->form_type); free(form); } } -static int -_field_compare(FormField *f1, FormField *f2) +static char * +_form_get_field_by_var(DataForm *form, const char * const var) { - return strcmp(f1->var, f2->var); + GSList *curr = form->fields; + while (curr != NULL) { + FormField *field = curr->data; + if (g_strcmp0(field->var, var) == 0) { + return field->values->data; + } + curr = g_slist_next(curr); + } + + return NULL; } void form_init_module(void) { form_destroy = _form_destroy; + form_get_field_by_var = _form_get_field_by_var; } diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index cff0da1b..2431f151 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -770,7 +770,8 @@ _disco_info_result_handler(xmpp_conn_t * const conn, xmpp_stanza_t * const stanz DataForm *form = form_create(softwareinfo); FormField *formField = NULL; - if (g_strcmp0(form->form_type, STANZA_DATAFORM_SOFTWARE) == 0) { + char *form_type = form_get_field_by_var(form, "FORM_TYPE"); + if (g_strcmp0(form_type, STANZA_DATAFORM_SOFTWARE) == 0) { GSList *field = form->fields; while (field != NULL) { formField = field->data; diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 063062a0..6510a50e 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -86,15 +86,25 @@ typedef struct disco_identity_t { char *category; } DiscoIdentity; +typedef struct form_option_t { + char *label; + char *value; +} FormOption; + typedef struct form_field_t { char *label; char *type; char *var; + char *description; + gboolean required; GSList *values; + GSList *options; } FormField; typedef struct data_form_t { - char *form_type; + char *type; + char *title; + char *instructions; GSList *fields; } DataForm; @@ -105,6 +115,7 @@ void iq_init_module(void); void message_init_module(void); void presence_init_module(void); void roster_init_module(void); +void form_init_module(void); // connection functions void (*jabber_init)(const int disable_tls); @@ -176,5 +187,6 @@ void (*roster_send_add_new)(const char * const barejid, const char * const name) void (*roster_send_remove)(const char * const barejid); void (*form_destroy)(DataForm *form); +char * (*form_get_field_by_var)(DataForm *form, const char * const var); #endif |