From f1375fe19db064fcebf00433ce73eab99be038ef Mon Sep 17 00:00:00 2001 From: James Bursa Date: Sat, 25 Oct 2003 00:35:49 +0000 Subject: [project @ 2003-10-25 00:35:49 by bursa] Split out and clean up form submit code. svn path=/import/netsurf/; revision=374 --- render/box.c | 164 ++++++++++++++++++++---------------------------------- render/box.h | 63 +-------------------- render/form.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ render/form.h | 89 +++++++++++++++++++++++++++++ 4 files changed, 328 insertions(+), 163 deletions(-) create mode 100644 render/form.c create mode 100644 render/form.h (limited to 'render') diff --git a/render/box.c b/render/box.c index 77fc99f00..3ad80ffad 100644 --- a/render/box.c +++ b/render/box.c @@ -18,6 +18,7 @@ #include "netsurf/css/css.h" #include "netsurf/render/box.h" #include "netsurf/render/font.h" +#include "netsurf/render/form.h" #include "netsurf/render/html.h" #ifdef riscos #include "netsurf/desktop/gui.h" @@ -70,7 +71,7 @@ static struct box *box_input_text(xmlNode *n, struct status *status, struct css_style *style, bool password); static struct result box_button(xmlNode *n, struct status *status, struct css_style *style); -static void add_option(xmlNode* n, struct gui_gadget* current_select, char *text); +static void add_option(xmlNode* n, struct form_control* current_select, char *text); static void box_normalise_block(struct box *block); static void box_normalise_table(struct box *table); void box_normalise_table_row_group(struct box *row_group, @@ -78,7 +79,7 @@ void box_normalise_table_row_group(struct box *row_group, void box_normalise_table_row(struct box *row, unsigned int **row_span, unsigned int *table_columns); static void box_normalise_inline_container(struct box *cont); -static void gadget_free(struct gui_gadget* g); +static void gadget_free(struct form_control* g); static void box_free_box(struct box *box); static struct result box_object(xmlNode *n, struct status *status, struct css_style *style); @@ -88,9 +89,8 @@ static struct result box_applet(xmlNode *n, struct status *status, struct css_style *style); static struct result box_iframe(xmlNode *n, struct status *status, struct css_style *style); -static struct form* create_form(xmlNode* n); static void add_form_element(struct page_elements* pe, struct form* f); -static void add_gadget_element(struct page_elements* pe, struct gui_gadget* g); +static void add_gadget_element(struct page_elements* pe, struct form_control* g); static bool plugin_decode(struct content* content, char* url, struct box* box, struct object_params* po); @@ -370,7 +370,7 @@ struct box * convert_xml_to_box(xmlNode * n, struct content *content, } box = box_create(parent_style, status.href, title); - box->text = text; + box->text = text; box->style_clone = 1; box->length = strlen(text); if (text[box->length - 1] == ' ') { @@ -653,7 +653,7 @@ struct css_style * box_get_style(struct content ** stylesheet, xmlFree(s); } } - + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "style"))) { struct css_style * astyle = xcalloc(1, sizeof(struct css_style)); memcpy(astyle, &css_empty_style, sizeof(struct css_style)); @@ -737,9 +737,27 @@ struct result box_image(xmlNode *n, struct status *status, struct result box_form(xmlNode *n, struct status *status, struct css_style *style) { + char* s; struct box *box; + struct form *form; + box = box_create(style, status->href, status->title); - status->current_form = create_form(n); + + status->current_form = form = xcalloc(1, sizeof(*form)); + + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "action"))) { + form->action = s; + } + + form->method = method_GET; + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "method"))) { + if (stricmp(s, "post") == 0) + form->method = method_POST; + xmlFree(s); + } + + form->controls = form->last_control = 0; + add_form_element(status->elements, status->current_form); return (struct result) {box, 1}; } @@ -752,10 +770,10 @@ struct result box_textarea(xmlNode *n, struct status *status, char* s; box = box_create(style, NULL, 0); - box->gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = xcalloc(1, sizeof(struct form_control)); box->gadget->box = box; box->gadget->type = GADGET_TEXTAREA; - box->gadget->form = status->current_form; + form_add_control(status->current_form, box->gadget); style->display = CSS_DISPLAY_INLINE_BLOCK; /* split the content at newlines and make an inline container with an @@ -800,12 +818,12 @@ struct result box_select(xmlNode *n, struct status *status, struct box *box; struct box *inline_container; struct box *inline_box; - struct gui_gadget *gadget = xcalloc(1, sizeof(struct gui_gadget)); + struct form_control *gadget = xcalloc(1, sizeof(struct form_control)); char* s; xmlNode *c, *c2; gadget->type = GADGET_SELECT; - gadget->form = status->current_form; + form_add_control(status->current_form, gadget); gadget->data.select.multiple = false; if ((s = (char *) xmlGetProp(n, (const xmlChar *) "multiple"))) { @@ -882,9 +900,9 @@ struct result box_select(xmlNode *n, struct status *status, return (struct result) {box, 0}; } -void add_option(xmlNode* n, struct gui_gadget* current_select, char *text) +void add_option(xmlNode* n, struct form_control* current_select, char *text) { - struct formoption *option = xcalloc(1, sizeof(struct formoption)); + struct form_option *option = xcalloc(1, sizeof(struct form_option)); char *s, *c; assert(current_select != 0); @@ -922,7 +940,7 @@ struct result box_input(xmlNode *n, struct status *status, struct css_style *style) { struct box* box = 0; - struct gui_gadget *gadget = 0; + struct form_control *gadget = 0; char *s, *type, *url; type = (char *) xmlGetProp(n, (const xmlChar *) "type"); @@ -943,16 +961,16 @@ struct result box_input(xmlNode *n, struct status *status, else if (stricmp(type, "hidden") == 0) { /* no box for hidden inputs */ - gadget = xcalloc(1, sizeof(struct gui_gadget)); + gadget = xcalloc(1, sizeof(struct form_control)); gadget->type = GADGET_HIDDEN; if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) - gadget->data.hidden.value = s; + gadget->value = s; } else if (stricmp(type, "checkbox") == 0 || stricmp(type, "radio") == 0) { box = box_create(style, NULL, 0); - box->gadget = gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = gadget = xcalloc(1, sizeof(struct form_control)); gadget->box = box; if (type[0] == 'c' || type[0] == 'C') gadget->type = GADGET_CHECKBOX; @@ -967,12 +985,8 @@ struct result box_input(xmlNode *n, struct status *status, xmlFree(s); } - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) { - if (gadget->type == GADGET_CHECKBOX) - gadget->data.checkbox.value = s; - else - gadget->data.radio.value = s; - } + if ((s = (char *) xmlGetProp(n, (const xmlChar *) "value"))) + gadget->value = s; } else if (stricmp(type, "submit") == 0 || stricmp(type, "reset") == 0) { @@ -998,33 +1012,21 @@ struct result box_input(xmlNode *n, struct status *status, else if (stricmp(type, "image") == 0) { box = box_create(style, NULL, 0); - box->gadget = gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = gadget = xcalloc(1, sizeof(struct form_control)); gadget->box = box; gadget->type = GADGET_IMAGE; - if ((s = (char *) xmlGetProp(n, (const xmlChar*) "name"))) { - gadget->data.image.n = s; - } - if ((s = (char *) xmlGetProp(n, (const xmlChar*) "width"))) { - gadget->data.image.width = (atoi(s)); - } - if ((s = (char *) xmlGetProp(n, (const xmlChar*) "height"))) { - gadget->data.image.height = (atoi(s)); - } if ((s = (char *) xmlGetProp(n, (const xmlChar*) "src"))) { - url = url_join(strdup(s), status->content->url); + url = url_join(s, status->content->url); html_fetch_object(status->content, url, box); + xmlFree(s); } - gadget->data.image.name = - xcalloc(strlen(gadget->data.image.n) + 5, sizeof(char)); - gadget->data.image.value = - xcalloc(strlen(gadget->data.image.n) + 20, sizeof(char)); } if (type != 0) xmlFree(type); if (gadget != 0) { - gadget->form = status->current_form; + form_add_control(status->current_form, gadget); gadget->name = (char *) xmlGetProp(n, (const xmlChar *) "name"); add_gadget_element(status->elements, gadget); } @@ -1041,7 +1043,7 @@ struct box *box_input_text(xmlNode *n, struct status *status, struct box *inline_container, *inline_box; style->display = CSS_DISPLAY_INLINE_BLOCK; - box->gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = xcalloc(1, sizeof(struct form_control)); box->gadget->box = box; box->gadget->maxlength = 100; @@ -1090,10 +1092,10 @@ struct result box_button(xmlNode *n, struct status *status, style->display = CSS_DISPLAY_INLINE_BLOCK; if (!type || strcasecmp(type, "submit") == 0) { - box->gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = xcalloc(1, sizeof(struct form_control)); box->gadget->type = GADGET_SUBMIT; } else if (strcasecmp(type, "reset") == 0) { - box->gadget = xcalloc(1, sizeof(struct gui_gadget)); + box->gadget = xcalloc(1, sizeof(struct form_control)); box->gadget->type = GADGET_RESET; } else { /* type="button" or unknown: just render the contents */ @@ -1104,7 +1106,7 @@ struct result box_button(xmlNode *n, struct status *status, if (type) xmlFree(type); - box->gadget->form = status->current_form; + form_add_control(status->current_form, box->gadget); box->gadget->box = box; box->gadget->name = (char *) xmlGetProp(n, (const xmlChar *) "name"); box->gadget->value = (char *) xmlGetProp(n, (const xmlChar *) "value"); @@ -1561,50 +1563,27 @@ void box_normalise_inline_container(struct box *cont) } -void gadget_free(struct gui_gadget* g) +void gadget_free(struct form_control* g) { - struct formoption *o, *o1; + struct form_option *o, *o1; if (g->name != 0) xmlFree(g->name); free(g->value); free(g->initial_value); - switch (g->type) - { - case GADGET_HIDDEN: - if (g->data.hidden.value != 0) - xmlFree(g->data.hidden.value); - break; - case GADGET_RADIO: - if (g->data.checkbox.value != 0) - xmlFree(g->data.radio.value); - break; - case GADGET_CHECKBOX: - if (g->data.checkbox.value != 0) - xmlFree(g->data.checkbox.value); - break; - case GADGET_IMAGE: - if (g->data.image.n != 0) - xmlFree(g->data.image.n); - if (g->data.image.name != 0) - xfree(g->data.image.name); - if (g->data.image.value != 0) - xfree(g->data.image.value); - break; - case GADGET_SELECT: - o = g->data.select.items; - while (o != NULL) - { - if (o->text != 0) - xmlFree(o->text); - if (o->value != 0) - xmlFree(o->value); - o1 = o->next; - xfree(o); - o = o1; - } - break; + if (g->type == GADGET_SELECT) { + o = g->data.select.items; + while (o != NULL) + { + if (o->text != 0) + xmlFree(o->text); + if (o->value != 0) + xmlFree(o->value); + o1 = o->next; + xfree(o); + o = o1; + } } } @@ -1649,27 +1628,6 @@ void box_free_box(struct box *box) * form helper functions */ -struct form* create_form(xmlNode* n) -{ - struct form* form; - char* s; - - form = xcalloc(1, sizeof(*form)); - - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "action"))) { - form->action = s; - } - - form->method = method_GET; - if ((s = (char *) xmlGetProp(n, (const xmlChar *) "method"))) { - if (stricmp(s, "post") == 0) - form->method = method_POST; - xmlFree(s); - } - - return form; -} - void add_form_element(struct page_elements* pe, struct form* f) { pe->forms = xrealloc(pe->forms, (pe->numForms + 1) * sizeof(struct form*)); @@ -1677,9 +1635,9 @@ void add_form_element(struct page_elements* pe, struct form* f) pe->numForms++; } -void add_gadget_element(struct page_elements* pe, struct gui_gadget* g) +void add_gadget_element(struct page_elements* pe, struct form_control* g) { - pe->gadgets = xrealloc(pe->gadgets, (pe->numGadgets + 1) * sizeof(struct gui_gadget*)); + pe->gadgets = xrealloc(pe->gadgets, (pe->numGadgets + 1) * sizeof(struct form_control*)); pe->gadgets[pe->numGadgets] = g; pe->numGadgets++; } diff --git a/render/box.h b/render/box.h index 76c9500c9..2c76f3ffd 100644 --- a/render/box.h +++ b/render/box.h @@ -33,59 +33,8 @@ struct column { unsigned long min, max, width; }; -struct formoption { - bool selected; - bool initial_selected; - char* value; - char* text; - struct formoption* next; -}; - struct box; -struct gui_gadget { - enum { GADGET_HIDDEN = 0, GADGET_TEXTBOX, GADGET_RADIO, GADGET_CHECKBOX, - GADGET_SELECT, GADGET_TEXTAREA, - GADGET_IMAGE, GADGET_PASSWORD, GADGET_SUBMIT, GADGET_RESET } type; - char *name; - char *value; - char *initial_value; - struct form *form; - struct box *box; - struct box *caret_inline_container; - struct box *caret_text_box; - int caret_char_offset; - unsigned int maxlength; - union { - struct { - char* value; - } hidden; - struct { - char* name; - char* value; - char* n; - int width, height; - int mx, my; - } image; - struct { - int num_items; - struct formoption *items, *last_item; - bool multiple; - int num_selected; - /** Currently selected item, if num_selected == 1. */ - struct formoption *current; - } select; - struct { - int selected; - char* value; - } checkbox; - struct { - int selected; - char* value; - } radio; - } data; -}; - /* parameters for and related elements */ struct object_params { char* data; @@ -137,28 +86,22 @@ struct box { struct box * next_float; struct column *col; struct font_data *font; - struct gui_gadget* gadget; + struct form_control* gadget; struct content* object; /* usually an image */ struct object_params *object_params; void* object_state; /* state of any object */ }; -struct form -{ - char* action; /* url */ - enum {method_GET, method_POST} method; -}; - struct formsubmit { struct form* form; - struct gui_gadget* items; + struct form_control* items; }; struct page_elements { struct form** forms; - struct gui_gadget** gadgets; + struct form_control** gadgets; struct img** images; int numForms; int numGadgets; diff --git a/render/form.c b/render/form.c new file mode 100644 index 000000000..f4ed0a9f8 --- /dev/null +++ b/render/form.c @@ -0,0 +1,175 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 James Bursa + * Copyright 2003 Phil Mellor + */ + +/** \file + * Form handling functions (implementation). + */ + +#include +#include +#include "curl/curl.h" +#include "netsurf/render/form.h" +#include "netsurf/utils/utils.h" + + +/** + * Add a control to the list of controls in a form. + */ + +void form_add_control(struct form *form, struct form_control *control) +{ + control->form = form; + if (form->controls) { + assert(form->last_control); + form->last_control->next = control; + control->next = 0; + form->last_control = control; + } else { + form->controls = form->last_control = control; + } +} + + +/** + * Identify 'successful' controls. + * + * See HTML 4.01 section 17.13.2. + */ + +struct form_successful_control *form_successful_controls(struct form *form, + struct form_control *submit_button) +{ + struct form_control *control; + struct form_option *option; + struct form_successful_control sentinel, *last_success; + last_success = &sentinel; + + for (control = form->controls; control; control = control->next) { + struct form_successful_control *success_new; + + /* ignore disabled controls */ + if (control->disabled) + continue; + + /* ignore controls with no name */ + if (!control->name) + continue; + + /* only the activated submit button is successful */ + if (control->type == GADGET_SUBMIT && control != submit_button) + continue; + + /* ignore checkboxes and radio buttons which aren't selected */ + if (control->type == GADGET_CHECKBOX && !control->data.checkbox.selected) + continue; + if (control->type == GADGET_RADIO && !control->data.radio.selected) + continue; + + /* select */ + if (control->type == GADGET_SELECT) { + for (option = control->data.select.items; option; + option = option->next) { + if (option->selected && option->value) { + success_new = xcalloc(1, sizeof(*success_new)); + success_new->name = xstrdup(control->name); + success_new->value = xstrdup(option->value); + success_new->next = 0; + last_success->next = success_new; + last_success = success_new; + } + } + continue; + } + + /* textarea */ + if (control->type == GADGET_TEXTAREA) { + /* TODO */ + continue; + } + + /* image */ + if (control->type == GADGET_IMAGE) { + int len = strlen(control->name) + 3; + /* x */ + success_new = xcalloc(1, sizeof(*success_new)); + success_new->name = xcalloc(1, len); + sprintf(success_new->name, "%s.x", control->name); + success_new->value = xcalloc(1, 20); + sprintf(success_new->value, "%i", control->data.image.mx); + success_new->next = 0; + last_success->next = success_new; + last_success = success_new; + /* y */ + success_new = xcalloc(1, sizeof(*success_new)); + success_new->name = xcalloc(1, len); + sprintf(success_new->name, "%s.y", control->name); + success_new->value = xcalloc(1, 20); + sprintf(success_new->value, "%i", control->data.image.my); + success_new->next = 0; + last_success->next = success_new; + last_success = success_new; + } + + /* ignore reset */ + if (control->type == GADGET_RESET) + continue; + + /* all others added if they have a value */ + if (control->value) { + success_new = xcalloc(1, sizeof(*success_new)); + success_new->name = xstrdup(control->name); + success_new->value = xstrdup(control->value); + success_new->next = 0; + last_success->next = success_new; + last_success = success_new; + } + } + + return sentinel.next; +} + + +/** + * Encode controls using application/x-www-form-urlencoded. + */ + +char *form_url_encode(struct form_successful_control *control) +{ + char *s = xcalloc(1, 0); + int len = 0, len1; + + for (; control; control = control->next) { + char *name = curl_escape(control->name, 0); + char *value = curl_escape(control->value, 0); + len1 = len + strlen(name) + strlen(value) + 2; + s = xrealloc(s, len1 + 1); + sprintf(s + len, "%s=%s&", name, value); + len = len1; + curl_free(name); + curl_free(value); + } + if (len) + s[len - 1] = 0; + return s; +} + + +/** + * Free a linked list of form_successful_control. + */ + +void form_free_successful(struct form_successful_control *control) +{ + struct form_successful_control *next; + for (; control; control = next) { + next = control->next; + free(control->name); + free(control->value); + free(control); + } +} diff --git a/render/form.h b/render/form.h new file mode 100644 index 000000000..b81abf01a --- /dev/null +++ b/render/form.h @@ -0,0 +1,89 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2003 Phil Mellor + * Copyright 2003 James Bursa + */ + +/** \file + * Form handling functions (interface). + */ + +#ifndef _NETSURF_RENDER_FORM_H_ +#define _NETSURF_RENDER_FORM_H_ + +#include +#include "netsurf/render/box.h" + +struct form_control; +struct form_option; + +/** HTML form. */ +struct form { + char *action; /* url */ + enum {method_GET, method_POST} method; + struct form_control *controls; /**< Linked list of controls. */ + struct form_control *last_control; /**< Last control in list. */ +}; + +/** Form control. */ +struct form_control { + enum { GADGET_HIDDEN, GADGET_TEXTBOX, GADGET_RADIO, GADGET_CHECKBOX, + GADGET_SELECT, GADGET_TEXTAREA, GADGET_IMAGE, + GADGET_PASSWORD, GADGET_SUBMIT, GADGET_RESET } type; + char *name; + char *value; + char *initial_value; + bool disabled; + struct form *form; + struct box *box; + struct box *caret_inline_container; + struct box *caret_text_box; + int caret_char_offset; + unsigned int maxlength; + union { + struct { + int mx, my; + } image; + struct { + int num_items; + struct form_option *items, *last_item; + bool multiple; + int num_selected; + /** Currently selected item, if num_selected == 1. */ + struct form_option *current; + } select; + struct { + int selected; + } checkbox; + struct { + int selected; + } radio; + } data; + struct form_control *next; /**< Next control in this form. */ +}; + +/** Option in a select. */ +struct form_option { + bool selected; + bool initial_selected; + char* value; + char* text; + struct form_option* next; +}; + +/** Successful control, as defined by HTML 4.01 17.13. */ +struct form_successful_control { + char *name; /**< Control name. */ + char *value; /**< Current value. */ + struct form_successful_control *next; /**< Next in linked list. */ +}; + +void form_add_control(struct form *form, struct form_control *control); +struct form_successful_control *form_successful_controls(struct form *form, + struct form_control *submit_button); +char *form_url_encode(struct form_successful_control *control); +void form_free_successful(struct form_successful_control *control); + +#endif -- cgit v1.2.3