diff options
Diffstat (limited to 'src/form.cc')
-rw-r--r-- | src/form.cc | 792 |
1 files changed, 400 insertions, 392 deletions
diff --git a/src/form.cc b/src/form.cc index 6a7f167f..a98a3fea 100644 --- a/src/form.cc +++ b/src/form.cc @@ -41,20 +41,6 @@ class DilloHtmlInput; typedef struct _DilloHtmlSelect DilloHtmlSelect; typedef struct _DilloHtmlOption DilloHtmlOption; -static Dstr *Html_encode_text(iconv_t encoder, Dstr **input); -static void Html_urlencode_append(Dstr *str, const char *val); -static void Html_append_input_urlencode(Dstr *data, const char *name, - const char *value); -static void Html_append_input_multipart_files(Dstr* data, const char *boundary, - const char *name, Dstr *file, - const char *filename); -static void Html_append_input_multipart(Dstr *data, const char *boundary, - const char *name, const char *value); -static void Html_append_clickpos_urlencode(Dstr *data, - Dstr *name, int x,int y); -static void Html_append_clickpos_multipart(Dstr *data, const char *boundary, - Dstr *name, int x, int y); - static dw::core::ui::Embed *Html_input_image(DilloHtml *html, const char *tag, int tagsize); @@ -94,6 +80,25 @@ class DilloHtmlForm { DilloHtml *html; void eventHandler(dw::core::ui::Resource *resource, int click_x, int click_y); + DilloUrl *buildQueryUrl(DilloHtmlInput *input, int click_x, int click_y); + Dstr *buildQueryData(DilloHtmlInput *active_submit, int x, int y); + char *makeMultipartBoundary(iconv_t encoder, DilloHtmlInput *active_submit); + Dstr *encodeText(iconv_t encoder, Dstr **input); + void urlencodeAppend(Dstr *str, const char *val); + void appendInputUrlencode(Dstr *data, + const char *name, const char *value); + void appendInputMultipartFiles(Dstr* data, + const char *boundary, + const char *name, Dstr *file, + const char *filename); + void appendInputMultipart(Dstr *data, + const char *boundary, + const char *name, + const char *value); + void appendClickposUrlencode(Dstr *data, Dstr *name, int x,int y); + void appendClickposMultipart(Dstr *data, + const char *boundary, + Dstr *name, int x, int y); public: //BUG: for now everything is public DilloHtmlMethod method; @@ -123,9 +128,6 @@ public: const char *init_str, DilloHtmlSelect *select, bool_t init_val); - DilloUrl *buildQueryUrl(DilloHtmlInput *input, int click_x, int click_y); - Dstr *buildQueryData(DilloHtmlInput *active_submit, int x, int y); - char *makeMultipartBoundary(iconv_t encoder, DilloHtmlInput *active_submit); }; class DilloHtmlReceiver: @@ -944,55 +946,6 @@ DilloHtmlForm::~DilloHtmlForm () delete(form_receiver); } -/* - * Get the current input. - */ -DilloHtmlInput *DilloHtmlForm::getCurrentInput () -{ - return inputs->get (inputs->size() - 1); -} - -/* - * Reset all inputs containing reset to their initial values. In - * general, reset is the reset button for the form. - */ -void DilloHtmlForm::reset () -{ - int size = inputs->size(); - for (int i = 0; i < size; i++) - inputs->get(i)->reset(); -} - -/* - * Add a new input, setting the initial values. - */ -void DilloHtmlForm::addInput(DilloHtmlInputType type, - dw::core::ui::Embed *embed, - const char *name, - const char *init_str, - DilloHtmlSelect *select, - bool_t init_val) -{ - _MSG("name=[%s] init_str=[%s] init_val=[%d]\n", - name, init_str, init_val); - DilloHtmlInput *input = - new DilloHtmlInput (type,embed,name,init_str,select,init_val); - input->connectTo (form_receiver); - int ni = inputs->size (); - inputs->increase (); - inputs->set (ni,input); - - /* some stats */ - if (type == DILLO_HTML_INPUT_PASSWORD || - type == DILLO_HTML_INPUT_TEXT) { - num_entry_fields++; - } else if (type == DILLO_HTML_INPUT_SUBMIT || - type == DILLO_HTML_INPUT_BUTTON_SUBMIT || - type == DILLO_HTML_INPUT_IMAGE) { - num_submit_buttons++; - } -} - void DilloHtmlForm::eventHandler(dw::core::ui::Resource *resource, int click_x, int click_y) { @@ -1039,94 +992,63 @@ void DilloHtmlForm::eventHandler(dw::core::ui::Resource *resource, } /* - * Return the input with a given resource. - */ -DilloHtmlInput *DilloHtmlForm::getInput (dw::core::ui::Resource *resource) -{ - for (int idx = 0; idx < inputs->size(); idx++) { - DilloHtmlInput *input = inputs->get(idx); - if (input->embed && - resource == input->embed->getResource()) - return input; - } - return NULL; -} - -/* - * Return a Radio input for the given name. + * Build a new query URL. + * (Called by eventHandler()) + * click_x and click_y are used only by input images. */ -DilloHtmlInput *DilloHtmlForm::getRadioInput (const char *name) +DilloUrl *DilloHtmlForm::buildQueryUrl(DilloHtmlInput *input, + int click_x, int click_y) { - for (int idx = 0; idx < inputs->size(); idx++) { - DilloHtmlInput *input = inputs->get(idx); - if (input->type == DILLO_HTML_INPUT_RADIO && - input->name && !dStrcasecmp(input->name, name)) - return input; - } - return NULL; -} + DilloUrl *new_url = NULL; -/* - * Generate a boundary string for use in separating the parts of a - * multipart/form-data submission. - */ -char *DilloHtmlForm::makeMultipartBoundary(iconv_t encoder, - DilloHtmlInput *active_submit) -{ - const int max_tries = 10; - Dlist *values = dList_new(5); - Dstr *DataStr = dStr_new(""); - Dstr *boundary = dStr_new(""); - char *ret = NULL; + if ((method == DILLO_HTML_METHOD_GET) || + (method == DILLO_HTML_METHOD_POST)) { + Dstr *DataStr; + DilloHtmlInput *active_submit = NULL; - /* fill DataStr with names, filenames, and values */ - for (int input_idx = 0; input_idx < inputs->size(); input_idx++) { - Dstr *dstr; - DilloHtmlInput *input = inputs->get (input_idx); - bool is_active_submit = (input == active_submit); - input->getInputValues(is_active_submit, values); + _MSG("DilloHtmlForm::buildQueryUrl: action=%s\n",URL_STR_(action)); - if (input->name) { - dstr = dStr_new(input->name); - dstr = Html_encode_text(encoder, &dstr); - dStr_append_l(DataStr, dstr->str, dstr->len); - dStr_free(dstr, 1); - } - if (input->type == DILLO_HTML_INPUT_FILE) { - dw::core::ui::LabelButtonResource *lbr = - (dw::core::ui::LabelButtonResource*)input->embed->getResource(); - const char *filename = lbr->getLabel(); - if (filename[0] && strcmp(filename, input->init_str)) { - dstr = dStr_new(filename); - dstr = Html_encode_text(encoder, &dstr); - dStr_append_l(DataStr, dstr->str, dstr->len); - dStr_free(dstr, 1); + if (num_submit_buttons > 0) { + if ((input->type == DILLO_HTML_INPUT_SUBMIT) || + (input->type == DILLO_HTML_INPUT_IMAGE) || + (input->type == DILLO_HTML_INPUT_BUTTON_SUBMIT)) { + active_submit = input; } } - int length = dList_length(values); - for (int i = 0; i < length; i++) { - dstr = (Dstr *) dList_nth_data(values, 0); - dList_remove(values, dstr); - if (input->type != DILLO_HTML_INPUT_FILE) - dstr = Html_encode_text(encoder, &dstr); - dStr_append_l(DataStr, dstr->str, dstr->len); - dStr_free(dstr, 1); + + DataStr = buildQueryData(active_submit, click_x, click_y); + if (DataStr) { + /* action was previously resolved against base URL */ + char *action_str = dStrdup(URL_STR(action)); + + if (method == DILLO_HTML_METHOD_POST) { + new_url = a_Url_new(action_str, NULL, 0, 0, 0); + /* new_url keeps the dStr and sets DataStr to NULL */ + a_Url_set_data(new_url, &DataStr); + a_Url_set_flags(new_url, URL_FLAGS(new_url) | URL_Post); + if (enc == DILLO_HTML_ENC_MULTIPART) + a_Url_set_flags(new_url, URL_FLAGS(new_url) | URL_MultipartEnc); + } else { + /* remove <fragment> and <query> sections if present */ + char *url_str, *p; + if ((p = strchr(action_str, '#'))) + *p = 0; + if ((p = strchr(action_str, '?'))) + *p = 0; + + url_str = dStrconcat(action_str, "?", DataStr->str, NULL); + new_url = a_Url_new(url_str, NULL, 0, 0, 0); + a_Url_set_flags(new_url, URL_FLAGS(new_url) | URL_Get); + dFree(url_str); + } + dStr_free(DataStr, 1); + dFree(action_str); } + } else { + MSG("DilloHtmlForm::buildQueryUrl: Method unknown\n"); } - /* generate a boundary that is not contained within the data */ - for (int i = 0; i < max_tries && !ret; i++) { - // Firefox-style boundary - dStr_sprintf(boundary, "---------------------------%d%d%d", - rand(), rand(), rand()); - dStr_truncate(boundary, 70); - if (dStr_memmem(DataStr, boundary) == NULL) - ret = boundary->str; - } - dList_free(values); - dStr_free(DataStr, 1); - dStr_free(boundary, (ret == NULL)); - return ret; + return new_url; } /* @@ -1163,14 +1085,14 @@ Dstr *DilloHtmlForm::buildQueryData(DilloHtmlInput *active_submit, Dstr *name = dStr_new(input->name); bool is_active_submit = (input == active_submit); - name = Html_encode_text(encoder, &name); + name = encodeText(encoder, &name); if (input->type == DILLO_HTML_INPUT_IMAGE) { if (is_active_submit){ if (enc == DILLO_HTML_ENC_URLENCODING) - Html_append_clickpos_urlencode(DataStr, name, x, y); + appendClickposUrlencode(DataStr, name, x, y); else if (enc == DILLO_HTML_ENC_MULTIPART) - Html_append_clickpos_multipart(DataStr, boundary, name, x,y); + appendClickposMultipart(DataStr, boundary, name, x,y); } } else { input->getInputValues(is_active_submit, values); @@ -1192,29 +1114,29 @@ Dstr *DilloHtmlForm::buildQueryData(DilloHtmlInput *active_submit, if (p) filename = p + 1; /* don't reveal path */ Dstr *dfilename = dStr_new(filename); - dfilename = Html_encode_text(encoder, &dfilename); - Html_append_input_multipart_files(DataStr, boundary, - name->str, file, dfilename->str); + dfilename = encodeText(encoder, &dfilename); + appendInputMultipartFiles(DataStr, boundary, name->str, + file, dfilename->str); dStr_free(dfilename, 1); } dStr_free(file, 1); } else if (input->type == DILLO_HTML_INPUT_INDEX) { Dstr *val = (Dstr *) dList_nth_data(values, 0); dList_remove(values, val); - val = Html_encode_text(encoder, &val); - Html_urlencode_append(DataStr, val->str); + val = encodeText(encoder, &val); + urlencodeAppend(DataStr, val->str); dStr_free(val, 1); } else { int length = dList_length(values), i; for (i = 0; i < length; i++) { Dstr *val = (Dstr *) dList_nth_data(values, 0); dList_remove(values, val); - val = Html_encode_text(encoder, &val); + val = encodeText(encoder, &val); if (enc == DILLO_HTML_ENC_URLENCODING) - Html_append_input_urlencode(DataStr, name->str, val->str); + appendInputUrlencode(DataStr, name->str, val->str); else if (enc == DILLO_HTML_ENC_MULTIPART) - Html_append_input_multipart(DataStr, boundary, name->str, - val->str); + appendInputMultipart(DataStr, boundary, + name->str, val->str); dStr_free(val, 1); } } @@ -1238,63 +1160,340 @@ Dstr *DilloHtmlForm::buildQueryData(DilloHtmlInput *active_submit, } /* - * Build a new query URL. - * (Called by eventHandler()) - * click_x and click_y are used only by input images. + * Generate a boundary string for use in separating the parts of a + * multipart/form-data submission. */ -DilloUrl *DilloHtmlForm::buildQueryUrl(DilloHtmlInput *input, - int click_x, int click_y) +char *DilloHtmlForm::makeMultipartBoundary(iconv_t encoder, + DilloHtmlInput *active_submit) { - DilloUrl *new_url = NULL; - - if ((method == DILLO_HTML_METHOD_GET) || - (method == DILLO_HTML_METHOD_POST)) { - Dstr *DataStr; - DilloHtmlInput *active_submit = NULL; + const int max_tries = 10; + Dlist *values = dList_new(5); + Dstr *DataStr = dStr_new(""); + Dstr *boundary = dStr_new(""); + char *ret = NULL; - _MSG("DilloHtmlForm::buildQueryUrl: action=%s\n",URL_STR_(action)); + /* fill DataStr with names, filenames, and values */ + for (int input_idx = 0; input_idx < inputs->size(); input_idx++) { + Dstr *dstr; + DilloHtmlInput *input = inputs->get (input_idx); + bool is_active_submit = (input == active_submit); + input->getInputValues(is_active_submit, values); - if (num_submit_buttons > 0) { - if ((input->type == DILLO_HTML_INPUT_SUBMIT) || - (input->type == DILLO_HTML_INPUT_IMAGE) || - (input->type == DILLO_HTML_INPUT_BUTTON_SUBMIT)) { - active_submit = input; + if (input->name) { + dstr = dStr_new(input->name); + dstr = encodeText(encoder, &dstr); + dStr_append_l(DataStr, dstr->str, dstr->len); + dStr_free(dstr, 1); + } + if (input->type == DILLO_HTML_INPUT_FILE) { + dw::core::ui::LabelButtonResource *lbr = + (dw::core::ui::LabelButtonResource*)input->embed->getResource(); + const char *filename = lbr->getLabel(); + if (filename[0] && strcmp(filename, input->init_str)) { + dstr = dStr_new(filename); + dstr = encodeText(encoder, &dstr); + dStr_append_l(DataStr, dstr->str, dstr->len); + dStr_free(dstr, 1); } } + int length = dList_length(values); + for (int i = 0; i < length; i++) { + dstr = (Dstr *) dList_nth_data(values, 0); + dList_remove(values, dstr); + if (input->type != DILLO_HTML_INPUT_FILE) + dstr = encodeText(encoder, &dstr); + dStr_append_l(DataStr, dstr->str, dstr->len); + dStr_free(dstr, 1); + } + } - DataStr = buildQueryData(active_submit, click_x, click_y); - if (DataStr) { - /* action was previously resolved against base URL */ - char *action_str = dStrdup(URL_STR(action)); + /* generate a boundary that is not contained within the data */ + for (int i = 0; i < max_tries && !ret; i++) { + // Firefox-style boundary + dStr_sprintf(boundary, "---------------------------%d%d%d", + rand(), rand(), rand()); + dStr_truncate(boundary, 70); + if (dStr_memmem(DataStr, boundary) == NULL) + ret = boundary->str; + } + dList_free(values); + dStr_free(DataStr, 1); + dStr_free(boundary, (ret == NULL)); + return ret; +} - if (method == DILLO_HTML_METHOD_POST) { - new_url = a_Url_new(action_str, NULL, 0, 0, 0); - /* new_url keeps the dStr and sets DataStr to NULL */ - a_Url_set_data(new_url, &DataStr); - a_Url_set_flags(new_url, URL_FLAGS(new_url) | URL_Post); - if (enc == DILLO_HTML_ENC_MULTIPART) - a_Url_set_flags(new_url, URL_FLAGS(new_url) | URL_MultipartEnc); - } else { - /* remove <fragment> and <query> sections if present */ - char *url_str, *p; - if ((p = strchr(action_str, '#'))) - *p = 0; - if ((p = strchr(action_str, '?'))) - *p = 0; +/* + * Pass input text through character set encoder. + * Return value: same input Dstr if no encoding is needed. + new Dstr when encoding (input Dstr is freed). + */ +Dstr *DilloHtmlForm::encodeText(iconv_t encoder, Dstr **input) +{ + int rc = 0; + Dstr *output; + const int bufsize = 128; + inbuf_t *inPtr; + char *buffer, *outPtr; + size_t inLeft, outRoom; + bool bad_chars = false; - url_str = dStrconcat(action_str, "?", DataStr->str, NULL); - new_url = a_Url_new(url_str, NULL, 0, 0, 0); - a_Url_set_flags(new_url, URL_FLAGS(new_url) | URL_Get); - dFree(url_str); - } - dStr_free(DataStr, 1); - dFree(action_str); + if ((encoder == (iconv_t) -1) || *input == NULL || (*input)->len == 0) + return *input; + + output = dStr_new(""); + inPtr = (*input)->str; + inLeft = (*input)->len; + buffer = dNew(char, bufsize); + + while ((rc != EINVAL) && (inLeft > 0)) { + + outPtr = buffer; + outRoom = bufsize; + + rc = iconv(encoder, &inPtr, &inLeft, &outPtr, &outRoom); + + // iconv() on success, number of bytes converted + // -1, errno == EILSEQ illegal byte sequence found + // EINVAL partial character ends source buffer + // E2BIG destination buffer is full + // + // GNU iconv has the undocumented(!) behavior that EILSEQ is also + // returned when a character cannot be converted. + + dStr_append_l(output, buffer, bufsize - outRoom); + + if (rc == -1) { + rc = errno; + } + if (rc == EILSEQ){ + /* count chars? (would be utf-8-specific) */ + bad_chars = true; + inPtr++; + inLeft--; + dStr_append_c(output, '?'); + } else if (rc == EINVAL) { + MSG_ERR("Html_decode_text: bad source string\n"); } - } else { - MSG("DilloHtmlForm::buildQueryUrl: Method unknown\n"); } - return new_url; + if (bad_chars) { + /* + * It might be friendly to inform the caller, who would know whether + * it is safe to display the beginning of the string in a message + * (isn't, e.g., a password). + */ + MSG_WARN("String cannot be converted cleanly.\n"); + } + + dFree(buffer); + dStr_free(*input, 1); + + return output; +} + +/* + * Urlencode 'val' and append it to 'str' + */ +void DilloHtmlForm::urlencodeAppend(Dstr *str, const char *val) +{ + char *enc_val = a_Url_encode_hex_str(val); + dStr_append(str, enc_val); + dFree(enc_val); +} + +/* + * Append a name-value pair to url data using url encoding. + */ +void DilloHtmlForm::appendInputUrlencode(Dstr *data, + const char *name, + const char *value) +{ + if (name && name[0]) { + urlencodeAppend(data, name); + dStr_append_c(data, '='); + urlencodeAppend(data, value); + dStr_append_c(data, '&'); + } +} + +/* + * Append files to URL data using multipart encoding. + * Currently only accepts one file. + */ +void DilloHtmlForm::appendInputMultipartFiles(Dstr* data, + const char *boundary, + const char *name, + Dstr *file, + const char *filename) +{ + const char *ctype, *ext; + + if (name && name[0]) { + (void)a_Misc_get_content_type_from_data(file->str, file->len, &ctype); + /* Heuristic: text/plain with ".htm[l]" extension -> text/html */ + if ((ext = strrchr(filename, '.')) && + !dStrcasecmp(ctype, "text/plain") && + (!dStrcasecmp(ext, ".html") || !dStrcasecmp(ext, ".htm"))) { + ctype = "text/html"; + } + + if (data->len == 0) { + dStr_append(data, "--"); + dStr_append(data, boundary); + } + // todo: encode name, filename + dStr_sprintfa(data, + "\r\n" + "Content-Disposition: form-data; name=\"%s\"; " + "filename=\"%s\"\r\n" + "Content-Type: %s\r\n" + "\r\n", name, filename, ctype); + + dStr_append_l(data, file->str, file->len); + + dStr_sprintfa(data, + "\r\n" + "--%s", boundary); + } +} + +/* + * Append a name-value pair to url data using multipart encoding. + */ +void DilloHtmlForm::appendInputMultipart(Dstr *data, + const char *boundary, + const char *name, + const char *value) +{ + if (name && name[0]) { + if (data->len == 0) { + dStr_append(data, "--"); + dStr_append(data, boundary); + } + // todo: encode name (RFC 2231) [coming soon] + dStr_sprintfa(data, + "\r\n" + "Content-Disposition: form-data; name=\"%s\"\r\n" + "\r\n" + "%s\r\n" + "--%s", + name, value, boundary); + } +} + +/* + * Append an image button click position to url data using url encoding. + */ +void DilloHtmlForm::appendClickposUrlencode(Dstr *data, + Dstr *name, int x,int y) +{ + if (name->len) { + urlencodeAppend(data, name->str); + dStr_sprintfa(data, ".x=%d&", x); + urlencodeAppend(data, name->str); + dStr_sprintfa(data, ".y=%d&", y); + } else + dStr_sprintfa(data, "x=%d&y=%d&", x, y); +} + +/* + * Append an image button click position to url data using multipart encoding. + */ +void DilloHtmlForm::appendClickposMultipart(Dstr *data, + const char *boundary, + Dstr *name, int x, int y) +{ + char posstr[16]; + int orig_len = name->len; + + if (orig_len) + dStr_append_c(name, '.'); + dStr_append_c(name, 'x'); + + snprintf(posstr, 16, "%d", x); + appendInputMultipart(data, boundary, name->str, posstr); + dStr_truncate(name, name->len - 1); + dStr_append_c(name, 'y'); + snprintf(posstr, 16, "%d", y); + appendInputMultipart(data, boundary, name->str, posstr); + dStr_truncate(name, orig_len); +} + +/* + * Get the current input. + */ +DilloHtmlInput *DilloHtmlForm::getCurrentInput () +{ + return inputs->get (inputs->size() - 1); +} + +/* + * Reset all inputs containing reset to their initial values. In + * general, reset is the reset button for the form. + */ +void DilloHtmlForm::reset () +{ + int size = inputs->size(); + for (int i = 0; i < size; i++) + inputs->get(i)->reset(); +} + +/* + * Add a new input, setting the initial values. + */ +void DilloHtmlForm::addInput(DilloHtmlInputType type, + dw::core::ui::Embed *embed, + const char *name, + const char *init_str, + DilloHtmlSelect *select, + bool_t init_val) +{ + _MSG("name=[%s] init_str=[%s] init_val=[%d]\n", + name, init_str, init_val); + DilloHtmlInput *input = + new DilloHtmlInput (type,embed,name,init_str,select,init_val); + input->connectTo (form_receiver); + int ni = inputs->size (); + inputs->increase (); + inputs->set (ni,input); + + /* some stats */ + if (type == DILLO_HTML_INPUT_PASSWORD || + type == DILLO_HTML_INPUT_TEXT) { + num_entry_fields++; + } else if (type == DILLO_HTML_INPUT_SUBMIT || + type == DILLO_HTML_INPUT_BUTTON_SUBMIT || + type == DILLO_HTML_INPUT_IMAGE) { + num_submit_buttons++; + } +} + +/* + * Return the input with a given resource. + */ +DilloHtmlInput *DilloHtmlForm::getInput (dw::core::ui::Resource *resource) +{ + for (int idx = 0; idx < inputs->size(); idx++) { + DilloHtmlInput *input = inputs->get(idx); + if (input->embed && + resource == input->embed->getResource()) + return input; + } + return NULL; +} + +/* + * Return a Radio input for the given name. + */ +DilloHtmlInput *DilloHtmlForm::getRadioInput (const char *name) +{ + for (int idx = 0; idx < inputs->size(); idx++) { + DilloHtmlInput *input = inputs->get(idx); + if (input->type == DILLO_HTML_INPUT_RADIO && + input->name && !dStrcasecmp(input->name, name)) + return input; + } + return NULL; } /* @@ -1554,197 +1753,6 @@ void DilloHtmlInput::reset () */ /* - * Pass input text through character set encoder. - * Return value: same input Dstr if no encoding is needed. - new Dstr when encoding (input Dstr is freed). - */ -static Dstr *Html_encode_text(iconv_t encoder, Dstr **input) -{ - int rc = 0; - Dstr *output; - const int bufsize = 128; - inbuf_t *inPtr; - char *buffer, *outPtr; - size_t inLeft, outRoom; - bool bad_chars = false; - - if ((encoder == (iconv_t) -1) || *input == NULL || (*input)->len == 0) - return *input; - - output = dStr_new(""); - inPtr = (*input)->str; - inLeft = (*input)->len; - buffer = dNew(char, bufsize); - - while ((rc != EINVAL) && (inLeft > 0)) { - - outPtr = buffer; - outRoom = bufsize; - - rc = iconv(encoder, &inPtr, &inLeft, &outPtr, &outRoom); - - // iconv() on success, number of bytes converted - // -1, errno == EILSEQ illegal byte sequence found - // EINVAL partial character ends source buffer - // E2BIG destination buffer is full - // - // GNU iconv has the undocumented(!) behavior that EILSEQ is also - // returned when a character cannot be converted. - - dStr_append_l(output, buffer, bufsize - outRoom); - - if (rc == -1) { - rc = errno; - } - if (rc == EILSEQ){ - /* count chars? (would be utf-8-specific) */ - bad_chars = true; - inPtr++; - inLeft--; - dStr_append_c(output, '?'); - } else if (rc == EINVAL) { - MSG_ERR("Html_decode_text: bad source string\n"); - } - } - - if (bad_chars) { - /* - * It might be friendly to inform the caller, who would know whether - * it is safe to display the beginning of the string in a message - * (isn't, e.g., a password). - */ - MSG_WARN("String cannot be converted cleanly.\n"); - } - - dFree(buffer); - dStr_free(*input, 1); - - return output; -} - -/* - * Urlencode 'val' and append it to 'str' - */ -static void Html_urlencode_append(Dstr *str, const char *val) -{ - char *enc_val = a_Url_encode_hex_str(val); - dStr_append(str, enc_val); - dFree(enc_val); -} - -/* - * Append a name-value pair to url data using url encoding. - */ -static void Html_append_input_urlencode(Dstr *data, const char *name, - const char *value) -{ - if (name && name[0]) { - Html_urlencode_append(data, name); - dStr_append_c(data, '='); - Html_urlencode_append(data, value); - dStr_append_c(data, '&'); - } -} - -/* - * Append files to URL data using multipart encoding. - * Currently only accepts one file. - */ -static void Html_append_input_multipart_files(Dstr* data, const char *boundary, - const char *name, Dstr *file, - const char *filename) -{ - const char *ctype, *ext; - - if (name && name[0]) { - (void)a_Misc_get_content_type_from_data(file->str, file->len, &ctype); - /* Heuristic: text/plain with ".htm[l]" extension -> text/html */ - if ((ext = strrchr(filename, '.')) && - !dStrcasecmp(ctype, "text/plain") && - (!dStrcasecmp(ext, ".html") || !dStrcasecmp(ext, ".htm"))) { - ctype = "text/html"; - } - - if (data->len == 0) { - dStr_append(data, "--"); - dStr_append(data, boundary); - } - // todo: encode name, filename - dStr_sprintfa(data, - "\r\n" - "Content-Disposition: form-data; name=\"%s\"; " - "filename=\"%s\"\r\n" - "Content-Type: %s\r\n" - "\r\n", name, filename, ctype); - - dStr_append_l(data, file->str, file->len); - - dStr_sprintfa(data, - "\r\n" - "--%s", boundary); - } -} - -/* - * Append a name-value pair to url data using multipart encoding. - */ -static void Html_append_input_multipart(Dstr *data, const char *boundary, - const char *name, const char *value) -{ - if (name && name[0]) { - if (data->len == 0) { - dStr_append(data, "--"); - dStr_append(data, boundary); - } - // todo: encode name (RFC 2231) [coming soon] - dStr_sprintfa(data, - "\r\n" - "Content-Disposition: form-data; name=\"%s\"\r\n" - "\r\n" - "%s\r\n" - "--%s", - name, value, boundary); - } -} - -/* - * Append an image button click position to url data using url encoding. - */ -static void Html_append_clickpos_urlencode(Dstr *data, - Dstr *name, int x,int y) -{ - if (name->len) { - Html_urlencode_append(data, name->str); - dStr_sprintfa(data, ".x=%d&", x); - Html_urlencode_append(data, name->str); - dStr_sprintfa(data, ".y=%d&", y); - } else - dStr_sprintfa(data, "x=%d&y=%d&", x, y); -} - -/* - * Append an image button click position to url data using multipart encoding. - */ -static void Html_append_clickpos_multipart(Dstr *data, const char *boundary, - Dstr *name, int x, int y) -{ - char posstr[16]; - int orig_len = name->len; - - if (orig_len) - dStr_append_c(name, '.'); - dStr_append_c(name, 'x'); - - snprintf(posstr, 16, "%d", x); - Html_append_input_multipart(data, boundary, name->str, posstr); - dStr_truncate(name, name->len - 1); - dStr_append_c(name, 'y'); - snprintf(posstr, 16, "%d", y); - Html_append_input_multipart(data, boundary, name->str, posstr); - dStr_truncate(name, orig_len); -} - -/* * Create input image for the form */ static dw::core::ui::Embed *Html_input_image(DilloHtml *html, |