summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--render/form.c514
-rw-r--r--render/form.h3
-rw-r--r--utils/corestrings.c36
-rw-r--r--utils/corestrings.h15
4 files changed, 563 insertions, 5 deletions
diff --git a/render/form.c b/render/form.c
index 9ac52392e..48648b103 100644
--- a/render/form.c
+++ b/render/form.c
@@ -88,7 +88,7 @@ static plot_font_style_t plot_fstyle_entry = {
};
static char *form_acceptable_charset(struct form *form);
-static char *form_encode_item(const char *item, const char *charset,
+static char *form_encode_item(const char *item, uint32_t len, const char *charset,
const char *fallback);
static void form_select_menu_clicked(struct form_control *control,
int x, int y);
@@ -321,6 +321,509 @@ bool form_add_option(struct form_control *control, char *value, char *text,
/**
+ * Identify 'successful' controls via the DOM.
+ *
+ * All text strings in the successful controls list will be in the charset most
+ * appropriate for submission. Therefore, no utf8_to_* processing should be
+ * performed upon them.
+ *
+ * \todo The chosen charset needs to be made available such that it can be
+ * included in the submission request (e.g. in the fetch's Content-Type header)
+ *
+ * \param form form to search for successful controls
+ * \param submit_button control used to submit the form, if any
+ * \param successful_controls updated to point to linked list of
+ * fetch_multipart_data, 0 if no controls
+ * \return true on success, false on memory exhaustion
+ *
+ * See HTML 4.01 section 17.13.2.
+ */
+bool form_successful_controls_dom(struct form *_form,
+ struct form_control *_submit_button,
+ struct fetch_multipart_data **successful_controls)
+{
+ dom_html_form_element *form = _form->node;
+ dom_html_element *submit_button = (_submit_button != NULL) ? _submit_button->node : NULL;
+ dom_html_collection *form_elements = NULL;
+ dom_html_options_collection *options = NULL;
+ dom_node *form_element = NULL, *option_element = NULL;
+ dom_exception err;
+ dom_string *nodename = NULL, *inputname = NULL, *inputvalue = NULL, *inputtype = NULL;
+ struct fetch_multipart_data sentinel, *last_success, *success_new;
+ bool had_submit = false, element_disabled;
+ char *charset, *rawfile_temp = NULL, *basename;
+ uint32_t index, element_count;
+
+ last_success = &sentinel;
+ sentinel.next = NULL;
+
+ LOG(("XYZZY: Yay, let's look for a form"));
+
+ /** \todo Replace this call with something DOMish */
+ charset = form_acceptable_charset(_form);
+ if (charset == NULL) {
+ LOG(("failed to find charset"));
+ return false;
+ }
+
+#define ENCODE_ITEM(i) (((i) == NULL) ? ( \
+ form_encode_item("", 0, charset, _form->document_charset) \
+ ):( \
+ form_encode_item(dom_string_data(i), dom_string_byte_length(i), \
+ charset, _form->document_charset) \
+ ))
+
+ err = dom_html_form_element_get_elements(form, &form_elements);
+
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get form elements"));
+ goto dom_no_memory;
+ }
+
+ LOG(("Reffed %p", form_elements));
+
+ err = dom_html_collection_get_length(form_elements, &element_count);
+
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get form element count"));
+ goto dom_no_memory;
+ }
+
+ for (index = 0; index < element_count; index++) {
+ if (form_element != NULL) {
+ LOG(("Unreffed %p", form_element));
+ dom_node_unref(form_element);
+ form_element = NULL;
+ }
+ if (nodename != NULL) {
+ dom_string_unref(nodename);
+ nodename = NULL;
+ }
+ if (inputname != NULL) {
+ dom_string_unref(inputname);
+ inputname = NULL;
+ }
+ if (inputvalue != NULL) {
+ dom_string_unref(inputvalue);
+ inputvalue = NULL;
+ }
+ if (inputtype != NULL) {
+ dom_string_unref(inputtype);
+ inputtype = NULL;
+ }
+ if (options != NULL) {
+ dom_html_options_collection_unref(options);
+ options = NULL;
+ }
+ err = dom_html_collection_item(form_elements,
+ index, &form_element);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not retrieve form element %d", index));
+ goto dom_no_memory;
+ }
+ LOG(("Reffed %p", form_element));
+ /* Form elements are one of:
+ * HTMLInputElement
+ * HTMLTextAreaElement
+ * HTMLSelectElement
+ */
+ err = dom_node_get_node_name(form_element, &nodename);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get node name"));
+ goto dom_no_memory;
+ }
+ LOG(("Found a node(%p): `%*s`", nodename,
+ dom_string_byte_length(nodename),
+ dom_string_data(nodename)));
+ if (dom_string_isequal(nodename, corestring_dom_TEXTAREA)) {
+ err = dom_html_text_area_element_get_disabled(
+ (dom_html_text_area_element *)form_element,
+ &element_disabled);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get text area disabled property"));
+ goto dom_no_memory;
+ }
+ err = dom_html_text_area_element_get_name(
+ (dom_html_text_area_element *)form_element,
+ &inputname);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get text area name property"));
+ goto dom_no_memory;
+ }
+ } else if (dom_string_isequal(nodename, corestring_dom_SELECT)) {
+ err = dom_html_select_element_get_disabled(
+ (dom_html_select_element *)form_element,
+ &element_disabled);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get select disabled property"));
+ goto dom_no_memory;
+ }
+ err = dom_html_select_element_get_name(
+ (dom_html_select_element *)form_element,
+ &inputname);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get select name property"));
+ goto dom_no_memory;
+ }
+ } else if (dom_string_isequal(nodename, corestring_dom_INPUT)) {
+ err = dom_html_input_element_get_disabled(
+ (dom_html_input_element *)form_element,
+ &element_disabled);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get input disabled property"));
+ goto dom_no_memory;
+ }
+ err = dom_html_input_element_get_name(
+ (dom_html_input_element *)form_element,
+ &inputname);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get input name property"));
+ goto dom_no_memory;
+ }
+ } else if (dom_string_isequal(nodename, corestring_dom_BUTTON)) {
+ /* It was a button, no fair */
+ continue;
+ } else {
+ /* Unknown element type came through! */
+ LOG(("Unknown element type: %*s",
+ dom_string_byte_length(nodename),
+ dom_string_data(nodename)));
+ goto dom_no_memory;
+ }
+ if (element_disabled)
+ continue;
+ if (inputname == NULL)
+ continue;
+
+ if (dom_string_isequal(nodename, corestring_dom_TEXTAREA)) {
+ err = dom_html_text_area_element_get_value(
+ (dom_html_text_area_element *)form_element,
+ &inputvalue);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get text area content"));
+ goto dom_no_memory;
+ }
+ } else if (dom_string_isequal(nodename, corestring_dom_SELECT)) {
+ uint32_t options_count, option_index;
+ err = dom_html_select_element_get_options(
+ (dom_html_select_element *)form_element,
+ &options);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get select options collection"));
+ goto dom_no_memory;
+ }
+ err = dom_html_options_collection_get_length(
+ options, &options_count);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get select options collection length"));
+ goto dom_no_memory;
+ }
+ for(option_index = 0; option_index < options_count;
+ ++option_index) {
+ bool selected;
+ if (option_element != NULL) {
+ dom_node_unref(option_element);
+ option_element = NULL;
+ }
+ if (inputvalue != NULL) {
+ dom_string_unref(inputvalue);
+ inputvalue = NULL;
+ }
+ err = dom_html_options_collection_item(
+ options, option_index, &option_element);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get options item %d", option_index));
+ goto dom_no_memory;
+ }
+ err = dom_html_option_element_get_selected(
+ (dom_html_option_element *)option_element,
+ &selected);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get option selected property"));
+ goto dom_no_memory;
+ }
+ if (!selected)
+ continue;
+ err = dom_html_option_element_get_value(
+ (dom_html_option_element *)option_element,
+ &inputvalue);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get option value"));
+ goto dom_no_memory;
+ }
+
+ success_new = calloc(1, sizeof(*success_new));
+ if (success_new == NULL) {
+ LOG(("Could not allocate data for option"));
+ goto dom_no_memory;
+ }
+
+ last_success->next = success_new;
+ last_success = success_new;
+
+ success_new->name = ENCODE_ITEM(inputname);
+ if (success_new->name == NULL) {
+ LOG(("Could not encode name for option"));
+ goto dom_no_memory;
+ }
+ success_new->value = ENCODE_ITEM(inputvalue);
+ if (success_new->value == NULL) {
+ LOG(("Could not encode value for option"));
+ goto dom_no_memory;
+ }
+ }
+ continue;
+ } else if (dom_string_isequal(nodename, corestring_dom_INPUT)) {
+ /* Things to consider here */
+ /* Buttons -- only if the successful control */
+ /* radio and checkbox -- only if selected */
+ /* file -- also get the rawfile */
+ /* everything else -- just value */
+ err = dom_html_input_element_get_type(
+ (dom_html_input_element *) form_element,
+ &inputtype);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get input element type"));
+ goto dom_no_memory;
+ }
+ if (dom_string_caseless_isequal(
+ inputtype, corestring_dom_submit)) {
+ LOG(("Examining submit button"));
+ if (submit_button == NULL && !had_submit)
+ /* no button used, and first submit
+ * node found, so use it
+ */
+ had_submit = true;
+ else if ((dom_node *)submit_button !=
+ (dom_node *)form_element)
+ continue;
+ err = dom_html_input_element_get_value(
+ (dom_html_input_element *)form_element,
+ &inputvalue);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get submit button value"));
+ goto dom_no_memory;
+ }
+ /* Drop through to report the successful button */
+ } else if (dom_string_caseless_isequal(
+ inputtype, corestring_dom_image)) {
+ /* We *ONLY* use an image input if it was the
+ * thing which activated us
+ */
+ LOG(("Examining image button"));
+ if ((dom_node *)submit_button !=
+ (dom_node *)form_element)
+ continue;
+
+ basename = ENCODE_ITEM(inputname);
+
+ success_new = calloc(1, sizeof(*success_new));
+ if (success_new == NULL) {
+ free(basename);
+ LOG(("Could not allocate data for image.x"));
+ goto dom_no_memory;
+ }
+
+ last_success->next = success_new;
+ last_success = success_new;
+
+ success_new->name = malloc(strlen(basename) + 3);
+ if (success_new->name == NULL) {
+ free(basename);
+ LOG(("Could not allocate name for image.x"));
+ goto dom_no_memory;
+ }
+ success_new->value = malloc(20);
+ if (success_new->value == NULL) {
+ free(basename);
+ LOG(("Could not allocate value for image.x"));
+ goto dom_no_memory;
+ }
+ sprintf(success_new->name, "%s.x", basename);
+ /** \todo Store this on the node and
+ * retrieve it here
+ */
+ sprintf(success_new->value, "%d", 0);
+
+ success_new = calloc(1, sizeof(*success_new));
+ if (success_new == NULL) {
+ free(basename);
+ LOG(("Could not allocate data for image.y"));
+ goto dom_no_memory;
+ }
+
+ last_success->next = success_new;
+ last_success = success_new;
+
+ success_new->name = malloc(strlen(basename) + 3);
+ if (success_new->name == NULL) {
+ free(basename);
+ LOG(("Could not allocate name for image.y"));
+ goto dom_no_memory;
+ }
+ success_new->value = malloc(20);
+ if (success_new->value == NULL) {
+ free(basename);
+ LOG(("Could not allocate value for image.y"));
+ goto dom_no_memory;
+ }
+ sprintf(success_new->name, "%s.y", basename);
+ /** \todo Store this on the node and
+ * retrieve it here
+ */
+ sprintf(success_new->value, "%d", 0);
+ free(basename);
+ continue;
+ } else if (dom_string_caseless_isequal(
+ inputtype, corestring_dom_radio) ||
+ dom_string_caseless_isequal(
+ inputtype, corestring_dom_checkbox)) {
+ LOG(("Examining radio or checkbox"));
+ err = dom_html_input_element_get_value(
+ (dom_html_input_element *)form_element,
+ &inputvalue);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get input element value"));
+ goto dom_no_memory;
+ }
+ if (inputvalue == NULL)
+ inputvalue = dom_string_ref(
+ corestring_dom_on);
+ /* Fall through to simple allocation */
+ } else if (dom_string_caseless_isequal(
+ inputtype, corestring_dom_file)) {
+ LOG(("Examining file input"));
+ err = dom_html_input_element_get_value(
+ (dom_html_input_element *)form_element,
+ &inputvalue);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get file value"));
+ goto dom_no_memory;
+ }
+ err = dom_node_get_user_data(
+ form_element,
+ corestring_dom___ns_key_file_name_node_data,
+ &rawfile_temp);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get file rawname"));
+ goto dom_no_memory;
+ }
+ rawfile_temp = strdup(rawfile_temp != NULL ?
+ rawfile_temp :
+ "");
+ if (rawfile_temp == NULL) {
+ LOG(("Could not copy file rawname"));
+ goto dom_no_memory;
+ }
+ /* Fall out to the allocation */
+ } else if (dom_string_caseless_isequal(
+ inputtype, corestring_dom_reset) ||
+ dom_string_caseless_isequal(
+ inputtype, corestring_dom_button)) {
+ /* Skip these */
+ LOG(("Skipping RESET and BUTTON"));
+ continue;
+ } else {
+ /* Everything else is treated as text values */
+ LOG(("Retrieving generic input text"));
+ err = dom_html_input_element_get_value(
+ (dom_html_input_element *)form_element,
+ &inputvalue);
+ if (err != DOM_NO_ERR) {
+ LOG(("Could not get input value"));
+ goto dom_no_memory;
+ }
+ /* Fall out to the allocation */
+ }
+ }
+
+ success_new = calloc(1, sizeof(*success_new));
+ if (success_new == NULL) {
+ LOG(("Could not allocate data for generic"));
+ goto dom_no_memory;
+ }
+
+ last_success->next = success_new;
+ last_success = success_new;
+
+ success_new->name = ENCODE_ITEM(inputname);
+ if (success_new->name == NULL) {
+ LOG(("Could not encode name for generic"));
+ goto dom_no_memory;
+ }
+ success_new->value = ENCODE_ITEM(inputvalue);
+ if (success_new->value == NULL) {
+ LOG(("Could not encode value for generic"));
+ goto dom_no_memory;
+ }
+ if (rawfile_temp != NULL) {
+ success_new->file = true;
+ success_new->rawfile = rawfile_temp;
+ rawfile_temp = NULL;
+ }
+ }
+
+ free(charset);
+ if (form_element != NULL) {
+ LOG(("Unreffed %p", form_element));
+ dom_node_unref(form_element);
+ }
+ if (form_elements != NULL) {
+ LOG(("Unreffed %p", form_elements));
+ dom_html_collection_unref(form_elements);
+ }
+ if (nodename != NULL)
+ dom_string_unref(nodename);
+ if (inputname != NULL)
+ dom_string_unref(inputname);
+ if (inputvalue != NULL)
+ dom_string_unref(inputvalue);
+ if (options != NULL)
+ dom_html_options_collection_unref(options);
+ if (option_element != NULL)
+ dom_node_unref(option_element);
+ if (inputtype != NULL)
+ dom_string_unref(inputtype);
+ if (rawfile_temp != NULL)
+ free(rawfile_temp);
+ *successful_controls = sentinel.next;
+
+ for (success_new = *successful_controls; success_new != NULL;
+ success_new = success_new->next) {
+ LOG(("%p -> %s=%s", success_new, success_new->name, success_new->value));
+ LOG(("%p -> file=%s rawfile=%s", success_new,
+ success_new->file ? "yes" : "no", success_new->rawfile));
+ }
+ return true;
+
+dom_no_memory:
+ free(charset);
+ fetch_multipart_data_destroy(sentinel.next);
+
+ if (form_elements != NULL)
+ dom_html_collection_unref(form_elements);
+ if (form_element != NULL)
+ dom_node_unref(form_element);
+ if (nodename != NULL)
+ dom_string_unref(nodename);
+ if (inputname != NULL)
+ dom_string_unref(inputname);
+ if (inputvalue != NULL)
+ dom_string_unref(inputvalue);
+ if (options != NULL)
+ dom_html_options_collection_unref(options);
+ if (option_element != NULL)
+ dom_node_unref(option_element);
+ if (inputtype != NULL)
+ dom_string_unref(inputtype);
+ if (rawfile_temp != NULL)
+ free(rawfile_temp);
+
+ return false;
+}
+#undef ENCODE_ITEM
+
+/**
* Identify 'successful' controls.
*
* All text strings in the successful controls list will be in the charset most
@@ -356,7 +859,7 @@ bool form_successful_controls(struct form *form,
if (charset == NULL)
return false;
-#define ENCODE_ITEM(i) form_encode_item((i), charset, form->document_charset)
+#define ENCODE_ITEM(i) form_encode_item((i), 0, charset, form->document_charset)
for (control = form->controls; control; control = control->next) {
/* ignore disabled controls */
@@ -812,12 +1315,13 @@ char *form_acceptable_charset(struct form *form)
* \todo Return charset used?
*
* \param item String to convert
+ * \param len Length of string to convert
* \param charset Destination charset
* \param fallback Fallback charset (may be NULL),
* used iff converting to charset fails
* \return Pointer to converted string (on heap, caller frees), or NULL
*/
-char *form_encode_item(const char *item, const char *charset,
+char *form_encode_item(const char *item, uint32_t len, const char *charset,
const char *fallback)
{
utf8_convert_ret err;
@@ -833,7 +1337,7 @@ char *form_encode_item(const char *item, const char *charset,
if (err == UTF8_CONVERT_BADENC) {
/* charset not understood, try without transliteration */
snprintf(cset, sizeof cset, "%s", charset);
- err = utf8_to_enc(item, cset, 0, &ret);
+ err = utf8_to_enc(item, cset, len, &ret);
if (err == UTF8_CONVERT_BADENC) {
/* nope, try fallback charset (if any) */
@@ -1490,7 +1994,7 @@ void form_submit(nsurl *page_url, struct browser_window *target,
assert(form != NULL);
- if (form_successful_controls(form, submit_button, &success) == false) {
+ if (form_successful_controls_dom(form, submit_button, &success) == false) {
warn_user("NoMemory", 0);
return;
}
diff --git a/render/form.h b/render/form.h
index b538c3b33..e65206d33 100644
--- a/render/form.h
+++ b/render/form.h
@@ -159,6 +159,9 @@ bool form_add_option(struct form_control *control, char *value, char *text,
bool form_successful_controls(struct form *form,
struct form_control *submit_button,
struct fetch_multipart_data **successful_controls);
+bool form_successful_controls_dom(struct form *form,
+ struct form_control *submit_button,
+ struct fetch_multipart_data **successful_controls);
bool form_open_select_menu(void *client_data,
struct form_control *control,
diff --git a/utils/corestrings.c b/utils/corestrings.c
index 8623d127b..9050ffe48 100644
--- a/utils/corestrings.c
+++ b/utils/corestrings.c
@@ -232,6 +232,16 @@ dom_string *corestring_dom_volumechange;
dom_string *corestring_dom_vspace;
dom_string *corestring_dom_waiting;
dom_string *corestring_dom_width;
+dom_string *corestring_dom_BUTTON;
+dom_string *corestring_dom_INPUT;
+dom_string *corestring_dom_SELECT;
+dom_string *corestring_dom_TEXTAREA;
+dom_string *corestring_dom_button;
+dom_string *corestring_dom_image;
+dom_string *corestring_dom_radio;
+dom_string *corestring_dom_checkbox;
+dom_string *corestring_dom_file;
+dom_string *corestring_dom_on;
dom_string *corestring_dom___ns_key_libcss_node_data;
dom_string *corestring_dom___ns_key_file_name_node_data;
@@ -463,6 +473,19 @@ void corestrings_fini(void)
CSS_DOM_STRING_UNREF(vspace);
CSS_DOM_STRING_UNREF(waiting);
CSS_DOM_STRING_UNREF(width);
+ /* DOM node names, not really CSS */
+ CSS_DOM_STRING_UNREF(BUTTON);
+ CSS_DOM_STRING_UNREF(INPUT);
+ CSS_DOM_STRING_UNREF(SELECT);
+ CSS_DOM_STRING_UNREF(TEXTAREA);
+ /* DOM input types, not really CSS */
+ CSS_DOM_STRING_UNREF(button);
+ CSS_DOM_STRING_UNREF(image);
+ CSS_DOM_STRING_UNREF(radio);
+ CSS_DOM_STRING_UNREF(checkbox);
+ CSS_DOM_STRING_UNREF(file);
+ CSS_DOM_STRING_UNREF(on);
+ /* DOM userdata keys, not really CSS */
CSS_DOM_STRING_UNREF(__ns_key_libcss_node_data);
CSS_DOM_STRING_UNREF(__ns_key_file_name_node_data);
#undef CSS_DOM_STRING_UNREF
@@ -725,6 +748,19 @@ nserror corestrings_init(void)
CSS_DOM_STRING_INTERN(vspace);
CSS_DOM_STRING_INTERN(waiting);
CSS_DOM_STRING_INTERN(width);
+ /* DOM node names, not really CSS */
+ CSS_DOM_STRING_INTERN(BUTTON);
+ CSS_DOM_STRING_INTERN(INPUT);
+ CSS_DOM_STRING_INTERN(SELECT);
+ CSS_DOM_STRING_INTERN(TEXTAREA);
+ /* DOM input types, not really CSS */
+ CSS_DOM_STRING_INTERN(button);
+ CSS_DOM_STRING_INTERN(image);
+ CSS_DOM_STRING_INTERN(radio);
+ CSS_DOM_STRING_INTERN(checkbox);
+ CSS_DOM_STRING_INTERN(file);
+ CSS_DOM_STRING_INTERN(on);
+ /* DOM userdata keys, not really CSS */
CSS_DOM_STRING_INTERN(__ns_key_libcss_node_data);
CSS_DOM_STRING_INTERN(__ns_key_file_name_node_data);
#undef CSS_DOM_STRING_INTERN
diff --git a/utils/corestrings.h b/utils/corestrings.h
index a8c345946..839d86522 100644
--- a/utils/corestrings.h
+++ b/utils/corestrings.h
@@ -238,6 +238,21 @@ extern struct dom_string *corestring_dom_volumechange;
extern struct dom_string *corestring_dom_vspace;
extern struct dom_string *corestring_dom_waiting;
extern struct dom_string *corestring_dom_width;
+/* DOM node types */
+extern struct dom_string *corestring_dom_BUTTON;
+extern struct dom_string *corestring_dom_INPUT;
+extern struct dom_string *corestring_dom_SELECT;
+extern struct dom_string *corestring_dom_TEXTAREA;
+/* DOM input node types */
+extern struct dom_string *corestring_dom_button;
+/* extern struct dom_string *corestring_dom_submit; */
+/* extern struct dom_string *corestring_dom_reset; */
+extern struct dom_string *corestring_dom_image;
+extern struct dom_string *corestring_dom_radio;
+extern struct dom_string *corestring_dom_checkbox;
+extern struct dom_string *corestring_dom_file;
+extern struct dom_string *corestring_dom_on;
+/* DOM userdata keys */
extern struct dom_string *corestring_dom___ns_key_libcss_node_data;
extern struct dom_string *corestring_dom___ns_key_file_name_node_data;