Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
  3.  *
  4.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  5.  *
  6.  * NetSurf is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; version 2 of the License.
  9.  *
  10.  * NetSurf is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19.  
  20. #include "render/form.h"
  21. #include "render/html_internal.h"
  22. #include "utils/corestrings.h"
  23.  
  24. #include "utils/log.h"
  25.  
  26. /**
  27.  * process form element from dom
  28.  */
  29. static struct form *
  30. parse_form_element(const char *docenc, dom_node *node)
  31. {
  32.         dom_string *ds_action = NULL;
  33.         dom_string *ds_charset = NULL;
  34.         dom_string *ds_target = NULL;
  35.         dom_string *ds_method = NULL;
  36.         dom_string *ds_enctype = NULL;
  37.         char *action = NULL, *charset = NULL, *target = NULL;
  38.         form_method method;
  39.         dom_html_form_element *formele = (dom_html_form_element *)(node);
  40.         struct form * ret = NULL;
  41.  
  42.         /* Retrieve the attributes from the node */
  43.         if (dom_html_form_element_get_action(formele,
  44.                         &ds_action) != DOM_NO_ERR)
  45.                 goto out;
  46.  
  47.         if (dom_html_form_element_get_accept_charset(formele,
  48.                         &ds_charset) != DOM_NO_ERR)
  49.                 goto out;
  50.  
  51.         if (dom_html_form_element_get_target(formele,
  52.                         &ds_target) != DOM_NO_ERR)
  53.                 goto out;
  54.  
  55.         if (dom_html_form_element_get_method(formele,
  56.                         &ds_method) != DOM_NO_ERR)
  57.                 goto out;
  58.  
  59.         if (dom_html_form_element_get_enctype(formele,
  60.                         &ds_enctype) != DOM_NO_ERR)
  61.                 goto out;
  62.  
  63.         /* Extract the plain attributes ready for use.  We have to do this
  64.          * because we cannot guarantee that the dom_strings are NULL terminated
  65.          * and thus we copy them.
  66.          */
  67.         if (ds_action != NULL)
  68.                 action = strndup(dom_string_data(ds_action),
  69.                                  dom_string_byte_length(ds_action));
  70.  
  71.         if (ds_charset != NULL)
  72.                 charset = strndup(dom_string_data(ds_charset),
  73.                                   dom_string_byte_length(ds_charset));
  74.  
  75.         if (ds_target != NULL)
  76.                 target = strndup(dom_string_data(ds_target),
  77.                                  dom_string_byte_length(ds_target));
  78.  
  79.         /* Determine the method */
  80.         method = method_GET;
  81.         if (ds_method != NULL) {
  82.                 if (dom_string_caseless_lwc_isequal(ds_method,
  83.                                 corestring_lwc_post)) {
  84.                         method = method_POST_URLENC;
  85.                         if (ds_enctype != NULL) {
  86.                                 if (dom_string_caseless_lwc_isequal(ds_enctype,
  87.                                         corestring_lwc_multipart_form_data)) {
  88.  
  89.                                         method = method_POST_MULTIPART;
  90.                                 }
  91.                         }
  92.                 }
  93.         }
  94.  
  95.         /* Construct the form object */
  96.         ret = form_new(node, action, target, method, charset, docenc);
  97.  
  98. out:
  99.         if (ds_action != NULL)
  100.                 dom_string_unref(ds_action);
  101.         if (ds_charset != NULL)
  102.                 dom_string_unref(ds_charset);
  103.         if (ds_target != NULL)
  104.                 dom_string_unref(ds_target);
  105.         if (ds_method != NULL)
  106.                 dom_string_unref(ds_method);
  107.         if (ds_enctype != NULL)
  108.                 dom_string_unref(ds_enctype);
  109.         if (action != NULL)
  110.                 free(action);
  111.         if (charset != NULL)
  112.                 free(charset);
  113.         if (target != NULL)
  114.                 free(target);
  115.         return ret;
  116. }
  117.  
  118. /* documented in html_internal.h */
  119. struct form *html_forms_get_forms(const char *docenc, dom_html_document *doc)
  120. {
  121.         dom_html_collection *forms;
  122.         struct form *ret = NULL, *newf;
  123.         dom_node *node;
  124.         unsigned long n;
  125.         uint32_t nforms;
  126.  
  127.         if (doc == NULL)
  128.                 return NULL;
  129.  
  130.         /* Attempt to build a set of all the forms */
  131.         if (dom_html_document_get_forms(doc, &forms) != DOM_NO_ERR)
  132.                 return NULL;
  133.  
  134.         /* Count the number of forms so we can iterate */
  135.         if (dom_html_collection_get_length(forms, &nforms) != DOM_NO_ERR)
  136.                 goto out;
  137.  
  138.         /* Iterate the forms collection, making form structs for returning */
  139.         for (n = 0; n < nforms; ++n) {
  140.                 if (dom_html_collection_item(forms, n, &node) != DOM_NO_ERR) {
  141.                         goto out;
  142.                 }
  143.                 newf = parse_form_element(docenc, node);
  144.                 dom_node_unref(node);
  145.                 if (newf == NULL) {
  146.                         goto err;
  147.                 }
  148.                 newf->prev = ret;
  149.                 ret = newf;
  150.         }
  151.  
  152.         /* All went well */
  153.         goto out;
  154. err:
  155.         while (ret != NULL) {
  156.                 struct form *prev = ret->prev;
  157.                 /* Destroy ret */
  158.                 free(ret);
  159.                 ret = prev;
  160.         }
  161. out:
  162.         /* Finished with the collection, return it */
  163.         dom_html_collection_unref(forms);
  164.  
  165.         return ret;
  166. }
  167.  
  168. static struct form *
  169. find_form(struct form *forms, dom_html_form_element *form)
  170. {
  171.         while (forms != NULL) {
  172.                 if (forms->node == form)
  173.                         break;
  174.                 forms = forms->prev;
  175.         }
  176.  
  177.         return forms;
  178. }
  179.  
  180. static struct form_control *
  181. parse_button_element(struct form *forms, dom_html_button_element *button)
  182. {
  183.         struct form_control *control = NULL;
  184.         dom_exception err;
  185.         dom_html_form_element *form = NULL;
  186.         dom_string *ds_type = NULL;
  187.         dom_string *ds_value = NULL;
  188.         dom_string *ds_name = NULL;
  189.  
  190.         err = dom_html_button_element_get_form(button, &form);
  191.         if (err != DOM_NO_ERR)
  192.                 goto out;
  193.  
  194.         err = dom_html_button_element_get_type(button, &ds_type);
  195.         if (err != DOM_NO_ERR)
  196.                 goto out;
  197.  
  198.         if (ds_type == NULL) {
  199.                 control = form_new_control(button, GADGET_SUBMIT);
  200.         } else {
  201.                 if (dom_string_caseless_lwc_isequal(ds_type,
  202.                                 corestring_lwc_submit)) {
  203.                         control = form_new_control(button, GADGET_SUBMIT);
  204.                 } else if (dom_string_caseless_lwc_isequal(ds_type,
  205.                                 corestring_lwc_reset)) {
  206.                         control = form_new_control(button, GADGET_RESET);
  207.                 } else {
  208.                         control = form_new_control(button, GADGET_BUTTON);
  209.                 }
  210.         }
  211.  
  212.         if (control == NULL)
  213.                 goto out;
  214.  
  215.         err = dom_html_button_element_get_value(button, &ds_value);
  216.         if (err != DOM_NO_ERR)
  217.                 goto out;
  218.         err = dom_html_button_element_get_name(button, &ds_name);
  219.         if (err != DOM_NO_ERR)
  220.                 goto out;
  221.  
  222.         if (ds_value != NULL) {
  223.                 control->value = strndup(
  224.                         dom_string_data(ds_value),
  225.                         dom_string_byte_length(ds_value));
  226.  
  227.                 if (control->value == NULL) {
  228.                         form_free_control(control);
  229.                         control = NULL;
  230.                         goto out;
  231.                 }
  232.         }
  233.  
  234.         if (ds_name != NULL) {
  235.                 control->name = strndup(
  236.                         dom_string_data(ds_name),
  237.                         dom_string_byte_length(ds_name));
  238.  
  239.                 if (control->name == NULL) {
  240.                         form_free_control(control);
  241.                         control = NULL;
  242.                         goto out;
  243.                 }
  244.         }
  245.  
  246.         if (form != NULL && control != NULL)
  247.                 form_add_control(find_form(forms, form), control);
  248.  
  249. out:
  250.         if (form != NULL)
  251.                 dom_node_unref(form);
  252.         if (ds_type != NULL)
  253.                 dom_string_unref(ds_type);
  254.         if (ds_value != NULL)
  255.                 dom_string_unref(ds_value);
  256.         if (ds_name != NULL)
  257.                 dom_string_unref(ds_name);
  258.  
  259.         return control;
  260. }
  261.  
  262. static struct form_control *
  263. parse_input_element(struct form *forms, dom_html_input_element *input)
  264. {
  265.         struct form_control *control = NULL;
  266.         dom_html_form_element *form = NULL;
  267.         dom_string *ds_type = NULL;
  268.         dom_string *ds_name = NULL;
  269.         dom_string *ds_value = NULL;
  270.  
  271.         char *name = NULL;
  272.  
  273.         if (dom_html_input_element_get_form(input, &form) != DOM_NO_ERR)
  274.                 goto out;
  275.  
  276.         if (dom_html_input_element_get_type(input, &ds_type) != DOM_NO_ERR)
  277.                 goto out;
  278.  
  279.         if (dom_html_input_element_get_name(input, &ds_name) != DOM_NO_ERR)
  280.                 goto out;
  281.  
  282.         if (ds_name != NULL)
  283.                 name = strndup(dom_string_data(ds_name),
  284.                                dom_string_byte_length(ds_name));
  285.  
  286.         if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
  287.                         corestring_lwc_password)) {
  288.                 control = form_new_control(input, GADGET_PASSWORD);
  289.         } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
  290.                         corestring_lwc_file)) {
  291.                 control = form_new_control(input, GADGET_FILE);
  292.         } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
  293.                         corestring_lwc_hidden)) {
  294.                 control = form_new_control(input, GADGET_HIDDEN);
  295.         } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
  296.                         corestring_lwc_checkbox)) {
  297.                 control = form_new_control(input, GADGET_CHECKBOX);
  298.         } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
  299.                         corestring_lwc_radio)) {
  300.                 control = form_new_control(input, GADGET_RADIO);
  301.         } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
  302.                         corestring_lwc_submit)) {
  303.                 control = form_new_control(input, GADGET_SUBMIT);
  304.         } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
  305.                         corestring_lwc_reset)) {
  306.                 control = form_new_control(input, GADGET_RESET);
  307.         } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
  308.                         corestring_lwc_button)) {
  309.                 control = form_new_control(input, GADGET_BUTTON);
  310.         } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
  311.                         corestring_lwc_image)) {
  312.                 control = form_new_control(input, GADGET_IMAGE);
  313.         } else {
  314.                 control = form_new_control(input, GADGET_TEXTBOX);
  315.         }
  316.  
  317.         if (control == NULL)
  318.                 goto out;
  319.  
  320.         if (name != NULL) {
  321.                 /* Hand the name string over */
  322.                 control->name = name;
  323.                 name = NULL;
  324.         }
  325.  
  326.         if (control->type == GADGET_CHECKBOX || control->type == GADGET_RADIO) {
  327.                 bool selected;
  328.                 if (dom_html_input_element_get_checked(
  329.                             input, &selected) == DOM_NO_ERR) {
  330.                         control->selected = selected;
  331.                 }
  332.         }
  333.  
  334.         if (control->type == GADGET_PASSWORD ||
  335.             control->type == GADGET_TEXTBOX) {
  336.                 int32_t maxlength;
  337.                 if (dom_html_input_element_get_max_length(
  338.                             input, &maxlength) != DOM_NO_ERR) {
  339.                         maxlength = -1;
  340.                 }
  341.  
  342.                 if (maxlength >= 0) {
  343.                         /* Got valid maxlength */
  344.                         control->maxlength = maxlength;
  345.                 } else {
  346.                         /* Input has no maxlength attr, or
  347.                          * dom_html_input_element_get_max_length failed.
  348.                          *
  349.                          * Set it to something insane. */
  350.                         control->maxlength = UINT_MAX;
  351.                 }
  352.         }
  353.  
  354.         if (control->type != GADGET_FILE && control->type != GADGET_IMAGE) {
  355.                 if (dom_html_input_element_get_value(
  356.                             input, &ds_value) == DOM_NO_ERR) {
  357.                         if (ds_value != NULL) {
  358.                                 control->value = strndup(
  359.                                         dom_string_data(ds_value),
  360.                                         dom_string_byte_length(ds_value));
  361.                                 if (control->value == NULL) {
  362.                                         form_free_control(control);
  363.                                         control = NULL;
  364.                                         goto out;
  365.                                 }
  366.                                 control->length = strlen(control->value);
  367.                         }
  368.                 }
  369.  
  370.                 if (control->type == GADGET_TEXTBOX ||
  371.                                 control->type == GADGET_PASSWORD) {
  372.                         if (control->value == NULL) {
  373.                                 control->value = strdup("");
  374.                                 if (control->value == NULL) {
  375.                                         form_free_control(control);
  376.                                         control = NULL;
  377.                                         goto out;
  378.                                 }
  379.  
  380.                                 control->length = 0;
  381.                         }
  382.  
  383.                         control->initial_value = strdup(control->value);
  384.                         if (control->initial_value == NULL) {
  385.                                 form_free_control(control);
  386.                                 control = NULL;
  387.                                 goto out;
  388.                         }
  389.                 }
  390.         }
  391.  
  392.         if (form != NULL && control != NULL)
  393.                 form_add_control(find_form(forms, form), control);
  394.  
  395. out:
  396.         if (form != NULL)
  397.                 dom_node_unref(form);
  398.         if (ds_type != NULL)
  399.                 dom_string_unref(ds_type);
  400.         if (ds_name != NULL)
  401.                 dom_string_unref(ds_name);
  402.         if (ds_value != NULL)
  403.                 dom_string_unref(ds_value);
  404.  
  405.         if (name != NULL)
  406.                 free(name);
  407.  
  408.         return control;
  409. }
  410.  
  411. static struct form_control *
  412. parse_textarea_element(struct form *forms, dom_html_text_area_element *ta)
  413. {
  414.         struct form_control *control = NULL;
  415.         dom_html_form_element *form = NULL;
  416.         dom_string *ds_name = NULL;
  417.  
  418.         char *name = NULL;
  419.  
  420.         if (dom_html_text_area_element_get_form(ta, &form) != DOM_NO_ERR)
  421.                 goto out;
  422.  
  423.         if (dom_html_text_area_element_get_name(ta, &ds_name) != DOM_NO_ERR)
  424.                 goto out;
  425.  
  426.         if (ds_name != NULL)
  427.                 name = strndup(dom_string_data(ds_name),
  428.                                dom_string_byte_length(ds_name));
  429.  
  430.         control = form_new_control(ta, GADGET_TEXTAREA);
  431.  
  432.         if (control == NULL)
  433.                 goto out;
  434.  
  435.         if (name != NULL) {
  436.                 /* Hand the name string over */
  437.                 control->name = name;
  438.                 name = NULL;
  439.         }
  440.  
  441.         if (form != NULL && control != NULL)
  442.                 form_add_control(find_form(forms, form), control);
  443.  
  444. out:
  445.         if (form != NULL)
  446.                 dom_node_unref(form);
  447.         if (ds_name != NULL)
  448.                 dom_string_unref(ds_name);
  449.  
  450.         if (name != NULL)
  451.                 free(name);
  452.  
  453.  
  454.         return control;
  455. }
  456.  
  457. static struct form_control *
  458. parse_select_element(struct form *forms, dom_html_select_element *select)
  459. {
  460.         struct form_control *control = NULL;
  461.         dom_html_form_element *form = NULL;
  462.         dom_string *ds_name = NULL;
  463.  
  464.         char *name = NULL;
  465.  
  466.         if (dom_html_select_element_get_form(select, &form) != DOM_NO_ERR)
  467.                 goto out;
  468.  
  469.         if (dom_html_select_element_get_name(select, &ds_name) != DOM_NO_ERR)
  470.                 goto out;
  471.  
  472.         if (ds_name != NULL)
  473.                 name = strndup(dom_string_data(ds_name),
  474.                                dom_string_byte_length(ds_name));
  475.  
  476.         control = form_new_control(select, GADGET_SELECT);
  477.  
  478.         if (control == NULL)
  479.                 goto out;
  480.  
  481.         if (name != NULL) {
  482.                 /* Hand the name string over */
  483.                 control->name = name;
  484.                 name = NULL;
  485.         }
  486.  
  487.         dom_html_select_element_get_multiple(select,
  488.                         &(control->data.select.multiple));
  489.  
  490.         if (form != NULL && control != NULL)
  491.                 form_add_control(find_form(forms, form), control);
  492.  
  493. out:
  494.         if (form != NULL)
  495.                 dom_node_unref(form);
  496.         if (ds_name != NULL)
  497.                 dom_string_unref(ds_name);
  498.  
  499.         if (name != NULL)
  500.                 free(name);
  501.  
  502.  
  503.         return control;
  504. }
  505.  
  506.  
  507. static struct form_control *
  508. invent_fake_gadget(dom_node *node)
  509. {
  510.         struct form_control *ctl = form_new_control(node, GADGET_HIDDEN);
  511.         if (ctl != NULL) {
  512.                 ctl->value = strdup("");
  513.                 ctl->initial_value = strdup("");
  514.                 ctl->name = strdup("foo");
  515.  
  516.                 if (ctl->value == NULL || ctl->initial_value == NULL ||
  517.                                 ctl->name == NULL) {
  518.                         form_free_control(ctl);
  519.                         ctl = NULL;
  520.                 }
  521.         }
  522.         return ctl;
  523. }
  524.  
  525. /* documented in html_internal.h */
  526. struct form_control *html_forms_get_control_for_node(struct form *forms, dom_node *node)
  527. {
  528.         struct form *f;
  529.         struct form_control *ctl = NULL;
  530.         dom_exception err;
  531.         dom_string *ds_name = NULL;
  532.  
  533.         /* Step one, see if we already have a control */
  534.         for (f = forms; f != NULL; f = f->prev) {
  535.                 for (ctl = f->controls; ctl != NULL; ctl = ctl->next) {
  536.                         if (ctl->node == node)
  537.                                 return ctl;
  538.                 }
  539.         }
  540.  
  541.         /* Step two, extract the node's name so we can construct a gadget. */
  542.         err = dom_element_get_tag_name(node, &ds_name);
  543.         if (err == DOM_NO_ERR && ds_name != NULL) {
  544.  
  545.                 /* Step three, attempt to work out what gadget to make */
  546.                 if (dom_string_caseless_lwc_isequal(ds_name,
  547.                                 corestring_lwc_button)) {
  548.                         ctl = parse_button_element(forms,
  549.                                         (dom_html_button_element *) node);
  550.                 } else if (dom_string_caseless_lwc_isequal(ds_name,
  551.                                 corestring_lwc_input)) {
  552.                         ctl = parse_input_element(forms,
  553.                                         (dom_html_input_element *) node);
  554.                 } else if (dom_string_caseless_lwc_isequal(ds_name,
  555.                                 corestring_lwc_textarea)) {
  556.                         ctl = parse_textarea_element(forms,
  557.                                         (dom_html_text_area_element *) node);
  558.                 } else if (dom_string_caseless_lwc_isequal(ds_name,
  559.                                 corestring_lwc_select)) {
  560.                         ctl = parse_select_element(forms,
  561.                                         (dom_html_select_element *) node);
  562.                 }
  563.         }
  564.  
  565.         /* If all else fails, fake gadget time */
  566.         if (ctl == NULL)
  567.                 ctl = invent_fake_gadget(node);
  568.  
  569.         if (ds_name != NULL)
  570.                 dom_string_unref(ds_name);
  571.  
  572.         return ctl;
  573. }
  574.  
  575.