Dillo v3.2.0-170-gacf511bb
Loading...
Searching...
No Matches
form.cc
Go to the documentation of this file.
1/*
2 * File: form.cc
3 *
4 * Copyright 2008 Jorge Arellano Cid <jcid@dillo.org>
5 * Copyright 2024-2026 Rodrigo Arias Mallo <rodarima@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
13#include "form.hh"
14#include "html_common.hh"
15
16#include <errno.h>
17#include <iconv.h>
18
19#include "lout/misc.hh"
20#include "dw/core.hh"
21#include "dw/textblock.hh"
22
23#include "dlib/dlib.h"
24#include "misc.h"
25#include "msg.h"
26#include "prefs.h"
27#include "uicmd.hh"
28#include "dialog.hh"
29
30using namespace lout;
31using namespace dw;
32using namespace dw::core;
33using namespace dw::core::style;
34using namespace dw::core::ui;
35
36/*
37 * Forward declarations
38 */
39
40class DilloHtmlReceiver;
41class DilloHtmlSelect;
42
43static Embed *Html_input_image(DilloHtml *html, const char *tag, int tagsize);
44
45static void Html_option_finish(DilloHtml *html);
46
47/*
48 * Typedefs
49 */
50
70
71/*
72 * Class declarations
73 */
74
75class DilloHtmlForm {
76 friend class DilloHtmlReceiver;
77 friend class DilloHtmlInput;
78
79 DilloHtml *html;
80 bool showing_hiddens;
81 bool enabled;
82 void eventHandler(Resource *resource, EventButton *event);
83 DilloUrl *buildQueryUrl(DilloHtmlInput *active_input);
84 Dstr *buildQueryData(DilloHtmlInput *active_submit);
85 char *makeMultipartBoundary(iconv_t char_encoder,
86 DilloHtmlInput *active_submit);
87 Dstr *encodeText(iconv_t char_encoder, Dstr **input);
88 void strUrlencodeAppend(Dstr *dstr, const char *str);
89 void inputUrlencodeAppend(Dstr *data, const char *name, const char *value);
90 void inputMultipartAppend(Dstr *data, const char *boundary,
91 const char *name, const char *value);
92 void filesInputMultipartAppend(Dstr* data, const char *boundary,
93 const char *name, Dstr *file,
94 const char *filename);
95 void imageInputUrlencodeAppend(Dstr *data, Dstr *name, Dstr *x, Dstr *y);
96 void imageInputMultipartAppend(Dstr *data, const char *boundary, Dstr *name,
97 Dstr *x, Dstr *y);
98
99public: //BUG: for now everything is public
100 DilloHtmlMethod method;
101 DilloUrl *action;
102 DilloHtmlEnc content_type;
103 char *submit_charset;
104
106
107 int num_entry_fields;
108
109 DilloHtmlReceiver *form_receiver;
110
111public:
112 DilloHtmlForm (DilloHtml *html,
113 DilloHtmlMethod method, const DilloUrl *action,
114 DilloHtmlEnc content_type, const char *charset,
115 bool enabled);
116 ~DilloHtmlForm ();
117 DilloHtmlInput *getInput (Resource *resource);
118 DilloHtmlInput *getRadioInput (const char *name);
119 void submit(DilloHtmlInput *active_input, EventButton *event);
120 void reset ();
121 void display_hiddens(bool display);
122 void addInput(DilloHtmlInput *input, DilloHtmlInputType type);
123 void setEnabled(bool enabled);
124};
125
126class DilloHtmlReceiver:
129{
130 friend class DilloHtmlForm;
131 DilloHtmlForm* form;
132 DilloHtmlReceiver (DilloHtmlForm* form2) { form = form2; }
133 ~DilloHtmlReceiver () { }
134 void activate (Resource *resource);
135 void enter (Resource *resource);
136 void leave (Resource *resource);
137 void clicked (Resource *resource, EventButton *event);
138};
139
140class DilloHtmlInput {
141
142 // DilloHtmlForm::addInput() calls connectTo()
143 friend class DilloHtmlForm;
144
145private:
146 Embed *embed; /* May be NULL (think: hidden input) */
147 bool owns_embed; /* Should destroy embed? */
148
149public: //BUG: for now everything is public
151 char *name;
152 char *init_str; /* note: some overloading - for buttons, init_str
153 is simply the value of the button; for text
154 entries, it is the initial value */
155 DilloHtmlSelect *select;
156 bool init_val; /* only meaningful for buttons */
157 Dstr *file_data; /* only meaningful for file inputs.
158 TODO: may become a list... */
159
160private:
161 void connectTo(DilloHtmlReceiver *form_receiver);
162 void activate(DilloHtmlForm *form, int num_entry_fields,EventButton *event);
163 void readFile(BrowserWindow *bw);
164
165public:
166 DilloHtmlInput (DilloHtmlInputType type, Embed *embed,
167 const char *name, const char *init_str, bool init_val, bool owns_embed);
168 ~DilloHtmlInput ();
169 void appendValuesTo(Dlist *values, bool is_active_submit);
170 void reset();
171 void setEnabled(bool enabled) {if (embed) embed->setEnabled(enabled); };
172 Resource *getResource() {if (embed) { return embed->getResource(); } else { return NULL; } };
173};
174
175class DilloHtmlOptbase
176{
177public:
178 virtual ~DilloHtmlOptbase () {};
179 virtual bool isSelected() {return false;}
180 virtual bool select() {return false;}
181 virtual const char *getValue() {return NULL;}
182 virtual void setContent(const char *str, int len)
183 {MSG_ERR("Form: Optbase setContent()\n");}
184 virtual void addSelf(SelectionResource *res) = 0;
185};
186
187class DilloHtmlOptgroup : public DilloHtmlOptbase {
188private:
189 char *label;
190 bool enabled;
191public:
192 DilloHtmlOptgroup (char *label, bool enabled);
193 virtual ~DilloHtmlOptgroup ();
194 void addSelf (SelectionResource *res)
195 {res->pushGroup(label, enabled);}
196};
197
198class DilloHtmlOptgroupClose : public DilloHtmlOptbase {
199public:
200 virtual ~DilloHtmlOptgroupClose () {};
201 void addSelf (SelectionResource *res)
202 {res->popGroup();}
203};
204
205class DilloHtmlOption : public DilloHtmlOptbase {
206 friend class DilloHtmlSelect;
207public:
208 char *value, *label, *content;
209 bool selected, enabled;
210 DilloHtmlOption (char *value, char *label, bool selected, bool enabled);
211 virtual ~DilloHtmlOption ();
212 bool isSelected() {return selected;}
213 bool select() {return (selected = true);}
214 const char *getValue() {return value ? value : content;}
215 void setContent(const char *str, int len) {content = dStrndup(str, len);}
216 void addSelf (SelectionResource *res)
217 {res->addItem(label ? label : content, enabled, selected);}
218};
219
220class DilloHtmlSelect {
221 friend class DilloHtmlInput;
222private:
224 DilloHtmlSelect ();
225 ~DilloHtmlSelect ();
226public:
227 DilloHtmlOptbase *getCurrentOpt ();
228 void addOpt (DilloHtmlOptbase *opt);
229 void ensureSelection ();
230 void addOptsTo (SelectionResource *res);
231 void reset (SelectionResource *res);
232 void appendValuesTo (Dlist *values, SelectionResource *res);
233};
234
235/*
236 * Form API
237 */
238
239DilloHtmlForm *a_Html_form_new (DilloHtml *html, DilloHtmlMethod method,
240 const DilloUrl *action,
241 DilloHtmlEnc content_type, const char *charset,
242 bool enabled)
243{
244 return new DilloHtmlForm (html, method, action, content_type, charset,
245 enabled);
246}
247
248void a_Html_form_delete (DilloHtmlForm *form)
249{
250 delete form;
251}
252
253void a_Html_input_delete (DilloHtmlInput *input)
254{
255 delete input;
256}
257
258void a_Html_form_submit2(void *vform)
259{
260 ((DilloHtmlForm *)vform)->submit(NULL, NULL);
261}
262
263void a_Html_form_reset2(void *vform)
264{
265 ((DilloHtmlForm *)vform)->reset();
266}
267
268void a_Html_form_display_hiddens2(void *vform, bool display)
269{
270 ((DilloHtmlForm *)vform)->display_hiddens(display);
271}
272
273/*
274 * Form parsing functions
275 */
276
281 Embed *embed, const char *name, const char *init_str,
282 bool init_val, bool owns_embed)
283{
284 _MSG("name=[%s] init_str=[%s] init_val=[%d]\n", name, init_str, init_val);
285 DilloHtmlInput *input =
286 new DilloHtmlInput(type, embed, name, init_str, init_val, owns_embed);
287 if (html->InFlags & IN_FORM) {
288 html->getCurrentForm()->addInput(input, type);
289 } else {
290 int ni = html->inputs_outside_form->size();
292 html->inputs_outside_form->set(ni, input);
293
294 if (html->bw->NumPendingStyleSheets > 0) {
295 input->setEnabled(false);
296 }
297 }
298}
299
303static DilloHtmlInput *Html_get_radio_input(DilloHtml *html, const char *name)
304{
305 if (name) {
307
308 if (html->InFlags & IN_FORM)
309 inputs = html->getCurrentForm()->inputs;
310 else
311 inputs = html->inputs_outside_form;
312
313 for (int idx = 0; idx < inputs->size(); idx++) {
314 DilloHtmlInput *input = inputs->get(idx);
315 if (input->type == DILLO_HTML_INPUT_RADIO &&
316 input->name && !dStrAsciiCasecmp(input->name, name))
317 return input;
318 }
319 }
320 return NULL;
321}
322
326static DilloHtmlInput *Html_get_current_input(DilloHtml *html)
327{
329
330 if (html->InFlags & IN_FORM)
331 inputs = html->getCurrentForm()->inputs;
332 else
333 inputs = html->inputs_outside_form;
334
335 return (inputs && inputs->size() > 0) ?
336 inputs->get (inputs->size() - 1) : NULL;
337}
338
342void Html_tag_open_form(DilloHtml *html, const char *tag, int tagsize)
343{
344 DilloUrl *action;
345 DilloHtmlMethod method;
346 DilloHtmlEnc content_type;
347 char *charset, *first;
348 const char *attrbuf;
349
350 /* Don't break paragraph if the form is under display:none */
351 if (a_Html_should_display(html))
352 HT2TB(html)->addParbreak (9, html->wordStyle ());
353
354 if (html->InFlags & IN_FORM) {
355 BUG_MSG("Nested <form>.");
356 return;
357 }
358 html->InFlags |= IN_FORM;
359 html->InFlags &= ~IN_SELECT;
360 html->InFlags &= ~IN_OPTION;
361 html->InFlags &= ~IN_TEXTAREA;
362
363 method = DILLO_HTML_METHOD_GET;
364 if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "method"))) {
365 if (!dStrAsciiCasecmp(attrbuf, "post")) {
366 method = DILLO_HTML_METHOD_POST;
367 } else if (dStrAsciiCasecmp(attrbuf, "get")) {
368 BUG_MSG("<form> submission method unknown: '%s'.", attrbuf);
369 }
370 }
371 if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "action")))
372 action = a_Html_url_new(html, attrbuf, NULL, 0);
373 else {
374 if (html->DocType != DT_HTML || html->DocTypeVersion <= 4.01f)
375 BUG_MSG("<form> requires action attribute.");
376 action = a_Url_dup(html->base_url);
377 }
378 content_type = DILLO_HTML_ENC_URLENCODED;
379 if ((method == DILLO_HTML_METHOD_POST) &&
380 ((attrbuf = a_Html_get_attr(html, tag, tagsize, "enctype")))) {
381 if (!dStrAsciiCasecmp(attrbuf, "multipart/form-data"))
382 content_type = DILLO_HTML_ENC_MULTIPART;
383 }
384 charset = NULL;
385 first = NULL;
386 if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "accept-charset"))) {
387 /* a list of acceptable charsets, separated by commas or spaces */
388 char *ptr = first = dStrdup(attrbuf);
389 while (ptr && !charset) {
390 char *curr = dStrsep(&ptr, " ,");
391 if (!dStrAsciiCasecmp(curr, "utf-8")) {
392 charset = curr;
393 } else if (!dStrAsciiCasecmp(curr, "UNKNOWN")) {
394 /* defined to be whatever encoding the document is in */
395 charset = html->charset;
396 }
397 }
398 if (!charset)
399 charset = first;
400 }
401 if (!charset)
402 charset = html->charset;
403 html->formNew(method, action, content_type, charset);
404 dFree(first);
405 a_Url_free(action);
406}
407
409{
410 html->InFlags &= ~IN_FORM;
411 html->InFlags &= ~IN_SELECT;
412 html->InFlags &= ~IN_OPTION;
413 html->InFlags &= ~IN_TEXTAREA;
414}
415
419static int Html_input_get_size(DilloHtml *html, const char *attrbuf)
420{
421 const int MAX_SIZE = 1024;
422 int size = 20;
423
424 if (attrbuf) {
425 size = strtol(attrbuf, NULL, 10);
426 if (size < 1 || size > MAX_SIZE) {
427 int badSize = size;
428 size = (size < 1 ? 20 : MAX_SIZE);
429 BUG_MSG("<input> size=%d, using size=%d instead.", badSize, size);
430 }
431 }
432 return size;
433}
434
438void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize)
439{
440 bool owns_embed = true;
441 DilloHtmlInputType inp_type;
442 Resource *resource = NULL;
443 Embed *embed = NULL;
444 char *value, *name, *type, *init_str, *placeholder = NULL;
445 const char *attrbuf, *label;
446 bool init_val = false;
447 ResourceFactory *factory;
448
449 if (html->InFlags & IN_SELECT) {
450 BUG_MSG("<input> inside <select>.");
451 return;
452 }
453 if (html->InFlags & IN_BUTTON) {
454 BUG_MSG("<input> inside <button>.");
455 return;
456 }
457
458 factory = HT2LT(html)->getResourceFactory();
459
460 /* Get 'value', 'name' and 'type' */
461 value = a_Html_get_attr_wdef(html, tag, tagsize, "value", NULL);
462 name = a_Html_get_attr_wdef(html, tag, tagsize, "name", NULL);
463 type = a_Html_get_attr_wdef(html, tag, tagsize, "type", "");
464
465 init_str = NULL;
466 inp_type = DILLO_HTML_INPUT_UNKNOWN;
467 if (!dStrAsciiCasecmp(type, "password")) {
468 inp_type = DILLO_HTML_INPUT_PASSWORD;
469 placeholder = a_Html_get_attr_wdef(html, tag,tagsize,"placeholder",NULL);
470 attrbuf = a_Html_get_attr(html, tag, tagsize, "size");
471 int size = Html_input_get_size(html, attrbuf);
472 resource = factory->createEntryResource (size, true, NULL, placeholder);
473 init_str = value;
474 } else if (!dStrAsciiCasecmp(type, "checkbox")) {
475 inp_type = DILLO_HTML_INPUT_CHECKBOX;
476 resource = factory->createCheckButtonResource(false);
477 init_val = (a_Html_get_attr(html, tag, tagsize, "checked") != NULL);
478 init_str = (value) ? value : dStrdup("on");
479 } else if (!dStrAsciiCasecmp(type, "radio")) {
480 inp_type = DILLO_HTML_INPUT_RADIO;
481 RadioButtonResource *rb_r = NULL;
482 DilloHtmlInput *input = Html_get_radio_input(html, name);
483 if (input && input->getResource())
484 rb_r = (RadioButtonResource*) input->getResource();
485 resource = factory->createRadioButtonResource(rb_r, false);
486 init_val = (a_Html_get_attr(html, tag, tagsize, "checked") != NULL);
487 init_str = value;
488 } else if (!dStrAsciiCasecmp(type, "hidden")) {
489 inp_type = DILLO_HTML_INPUT_HIDDEN;
490 init_str = value;
491 int size = Html_input_get_size(html, NULL);
492 resource = factory->createEntryResource(size, false, name, NULL);
493 } else if (!dStrAsciiCasecmp(type, "submit")) {
494 inp_type = DILLO_HTML_INPUT_SUBMIT;
495 init_str = (value) ? value : dStrdup("Submit");
496 resource = factory->createLabelButtonResource(init_str);
497 } else if (!dStrAsciiCasecmp(type, "reset")) {
498 inp_type = DILLO_HTML_INPUT_RESET;
499 init_str = (value) ? value : dStrdup("Reset");
500 resource = factory->createLabelButtonResource(init_str);
501 } else if (!dStrAsciiCasecmp(type, "image")) {
502 if (URL_FLAGS(html->base_url) & URL_SpamSafe ||
503 !a_Html_should_display(html)) {
504 /* Don't request the image; make a text submit button instead */
505 inp_type = DILLO_HTML_INPUT_SUBMIT;
506 attrbuf = a_Html_get_attr(html, tag, tagsize, "alt");
507 label = attrbuf ? attrbuf : value ? value : name ? name : "Submit";
508 init_str = dStrdup(label);
509 resource = factory->createLabelButtonResource(init_str);
510 } else {
511 inp_type = DILLO_HTML_INPUT_IMAGE;
512 /* use a dw_image widget */
513 embed = Html_input_image(html, tag, tagsize);
514 owns_embed = false; /* adds it to the tree */
515 init_str = value;
516 }
517 } else if (!dStrAsciiCasecmp(type, "file")) {
518 bool valid = true;
519 if (html->InFlags & IN_FORM) {
520 DilloHtmlForm *form = html->getCurrentForm();
521 if (form->method != DILLO_HTML_METHOD_POST) {
522 valid = false;
523 BUG_MSG("<form> with file input MUST use HTTP POST method.");
524 MSG("File input ignored in form not using HTTP POST method\n");
525 } else if (form->content_type != DILLO_HTML_ENC_MULTIPART) {
526 valid = false;
527 BUG_MSG("<form> with file input MUST use multipart/form-data"
528 " encoding.");
529 MSG("File input ignored in form not using multipart/form-data"
530 " encoding\n");
531 }
532 }
533 if (valid) {
534 inp_type = DILLO_HTML_INPUT_FILE;
535 init_str = dStrdup("File selector");
536 resource = factory->createLabelButtonResource(init_str);
537 }
538 } else if (!dStrAsciiCasecmp(type, "button")) {
539 inp_type = DILLO_HTML_INPUT_BUTTON;
540 if (value) {
541 init_str = value;
542 resource = factory->createLabelButtonResource(init_str);
543 }
544 } else {
545 /* Text input, which also is the default */
546 inp_type = DILLO_HTML_INPUT_TEXT;
547 placeholder = a_Html_get_attr_wdef(html, tag,tagsize,"placeholder",NULL);
548 attrbuf = a_Html_get_attr(html, tag, tagsize, "size");
549 int size = Html_input_get_size(html, attrbuf);
550 resource = factory->createEntryResource(size, false, NULL, placeholder);
551 init_str = value;
552 }
553
554 if (inp_type != DILLO_HTML_INPUT_UNKNOWN) {
555
556 if (!embed)
557 embed = new Embed(resource);
558
559 assert(embed);
560
561 if (inp_type == DILLO_HTML_INPUT_HIDDEN) {
562 /* TODO Perhaps do this with access to current form setting */
563 embed->setDisplayed(false);
564 }
565 if (inp_type == DILLO_HTML_INPUT_TEXT ||
566 inp_type == DILLO_HTML_INPUT_PASSWORD) {
567 if (a_Html_get_attr(html, tag, tagsize, "readonly"))
568 ((EntryResource *) resource)->setEditable(false);
569
570 /* Maximum length of the text in the entry */
571 if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "maxlength"))) {
572 int maxlen = strtol(attrbuf, NULL, 10);
573 ((EntryResource *) resource)->setMaxLength(maxlen);
574 }
575 }
576 if (prefs.show_tooltip &&
577 (attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) {
578
580 attrbuf);
581 }
582
583 /* Only add to the tree if needs to be shown. Ignore images as
584 * they are already added in Html_input_image(). */
585 if (a_Html_should_display(html) && inp_type != DILLO_HTML_INPUT_IMAGE) {
586 HT2TB(html)->addWidget (embed, html->backgroundStyle());
587 owns_embed = false;
588 }
589
590 Html_add_input(html, inp_type, embed, name,
591 (init_str) ? init_str : "", init_val, owns_embed);
592 }
593
594 dFree(type);
595 dFree(name);
596 if (init_str != value)
597 dFree(init_str);
598 dFree(placeholder);
599 dFree(value);
600}
601
606void Html_tag_open_isindex(DilloHtml *html, const char *tag, int tagsize)
607{
608 DilloUrl *action;
609 const char *attrbuf;
610
611 if (html->InFlags & IN_FORM) {
612 MSG("<isindex> inside <form> not handled.\n");
613 return;
614 }
615
616 if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "action")))
617 action = a_Html_url_new(html, attrbuf, NULL, 0);
618 else
619 action = a_Url_dup(html->base_url);
620
622 html->charset);
623 html->InFlags |= IN_FORM;
624
625 ResourceFactory *factory = HT2LT(html)->getResourceFactory();
626 EntryResource *resource = factory->createEntryResource(20, false, NULL, NULL);
627 Embed *embed = new Embed (resource);
628
629 if (a_Html_should_display(html)) {
630 HT2TB(html)->addParbreak (9, html->wordStyle ());
631
632 if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "prompt")))
633 HT2TB(html)->addText(attrbuf, html->wordStyle ());
634
635 HT2TB(html)->addWidget (embed, html->backgroundStyle ());
636 Html_add_input(html, DILLO_HTML_INPUT_INDEX, embed, NULL, NULL, false, false);
637 } else {
638 Html_add_input(html, DILLO_HTML_INPUT_INDEX, embed, NULL, NULL, false, true);
639 }
640
641 a_Url_free(action);
642 html->InFlags &= ~IN_FORM;
643}
644
645void Html_tag_open_textarea(DilloHtml *html, const char *tag, int tagsize)
646{
647 assert((html->InFlags & (IN_BUTTON | IN_SELECT | IN_TEXTAREA)) == 0);
648
649 html->InFlags |= IN_TEXTAREA;
650}
651
655void Html_tag_content_textarea(DilloHtml *html, const char *tag, int tagsize)
656{
657 const int MAX_COLS=1024, MAX_ROWS=10000;
658
659 char *name;
660 const char *attrbuf;
661 int cols, rows;
662
663 a_Html_stash_init(html);
664 S_TOP(html)->parse_mode = DILLO_HTML_PARSE_MODE_VERBATIM;
665
666 if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "cols"))) {
667 cols = strtol(attrbuf, NULL, 10);
668 } else {
669 if (html->DocType != DT_HTML || html->DocTypeVersion <= 4.01f)
670 BUG_MSG("<textarea> requires cols attribute.");
671 cols = 20;
672 }
673 if (cols < 1 || cols > MAX_COLS) {
674 int badCols = cols;
675 cols = (cols < 1 ? 20 : MAX_COLS);
676 BUG_MSG("<textarea> cols=%d, using cols=%d instead.", badCols, cols);
677 }
678 if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "rows"))) {
679 rows = strtol(attrbuf, NULL, 10);
680 } else {
681 if (html->DocType != DT_HTML || html->DocTypeVersion <= 4.01f)
682 BUG_MSG("<textarea> requires rows attribute.");
683 rows = 3;
684 }
685 if (rows < 1 || rows > MAX_ROWS) {
686 int badRows = rows;
687 rows = (rows < 1 ? 2 : MAX_ROWS);
688 BUG_MSG("<textarea> rows=%d, using rows=%d instead.", badRows, rows);
689 }
690 name = NULL;
691 if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "name")))
692 name = dStrdup(attrbuf);
693
694 attrbuf = a_Html_get_attr(html, tag, tagsize, "placeholder");
695
696 /* The textarea should never call the _content hook on display:none,
697 * but we still treat it as if it is posible for robustness. */
698
699 ResourceFactory *factory = HT2LT(html)->getResourceFactory();
700 MultiLineTextResource *textres =
701 factory->createMultiLineTextResource (cols, rows, attrbuf);
702
703 Embed *embed = new Embed(textres);
704
705 /* Readonly or not? */
706 if (a_Html_get_attr(html, tag, tagsize, "readonly"))
707 textres->setEditable(false);
708
709 if (a_Html_should_display(html)) {
710 HT2TB(html)->addWidget (embed, html->backgroundStyle ());
711 Html_add_input(html, DILLO_HTML_INPUT_TEXTAREA, embed, name, NULL, false, false);
712 } else {
713 Html_add_input(html, DILLO_HTML_INPUT_TEXTAREA, embed, name, NULL, false, true);
714 }
715
716
717 dFree(name);
718}
719
725{
726 char *str;
727 DilloHtmlInput *input;
728 int i;
729
730 if (html->InFlags & IN_TEXTAREA && a_Html_should_display(html)) {
731 /* Remove the line ending that follows the opening tag */
732 if (html->Stash->str[0] == '\r')
733 dStr_erase(html->Stash, 0, 1);
734 if (html->Stash->str[0] == '\n')
735 dStr_erase(html->Stash, 0, 1);
736
737 /* As the spec recommends to canonicalize line endings, it is safe
738 * to replace '\r' with '\n'. It will be canonicalized anyway! */
739 for (i = 0; i < html->Stash->len; ++i) {
740 if (html->Stash->str[i] == '\r') {
741 if (html->Stash->str[i + 1] == '\n')
742 dStr_erase(html->Stash, i, 1);
743 else
744 html->Stash->str[i] = '\n';
745 }
746 }
747
748 /* The HTML3.2 spec says it can have "text and character entities". */
749 str = a_Html_parse_entities(html, html->Stash->str, html->Stash->len);
750 input = Html_get_current_input(html);
751 if (input) {
752 input->init_str = str;
753 Resource *res = input->getResource();
754 if (res)
755 ((MultiLineTextResource *)res)->setText(str);
756 }
757 }
758 html->InFlags &= ~IN_TEXTAREA;
759}
760
761/*
762 * <SELECT>
763 */
764/* The select tag is quite tricky, because of gorpy html syntax. */
765void Html_tag_open_select(DilloHtml *html, const char *tag, int tagsize)
766{
767 const char *attrbuf;
768 int rows = 0;
769
770 assert((html->InFlags & (IN_BUTTON | IN_SELECT | IN_TEXTAREA)) == 0);
771
772 html->InFlags |= IN_SELECT;
773 html->InFlags &= ~IN_OPTION;
774
775 char *name = a_Html_get_attr_wdef(html, tag, tagsize, "name", NULL);
776 bool multi = a_Html_get_attr(html, tag, tagsize, "multiple") != NULL;
777
778 if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "size"))) {
779 rows = strtol(attrbuf, NULL, 10);
780 if (rows > 100)
781 rows = 100;
782 }
783 if (rows < 1)
784 rows = multi ? 10 : 1;
785
787
788 if (rows == 1 && multi == false)
790 else
792
793
794 ResourceFactory *factory = HT2LT(html)->getResourceFactory ();
796
797 if (type == DILLO_HTML_INPUT_SELECT) {
798 res = factory->createOptionMenuResource ();
799 } else {
804 res = factory->createListResource (mode, rows);
805 }
806
807 Embed *embed = new Embed(res);
808
809 if (a_Html_should_display(html)) {
810 if (prefs.show_tooltip &&
811 (attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) {
813 CSS_TYPE_STRING, attrbuf);
814 }
815 HT2TB(html)->addWidget (embed, html->backgroundStyle ());
816 Html_add_input(html, type, embed, name, NULL, false, false);
817 } else {
818 Html_add_input(html, type, embed, name, NULL, false, true);
819 }
820
821 a_Html_stash_init(html);
822 dFree(name);
823}
824
825/*
826 * ?
827 */
829{
830 if (html->InFlags & IN_SELECT) {
831 if (html->InFlags & IN_OPTION)
832 Html_option_finish(html);
833 html->InFlags &= ~IN_SELECT;
834 html->InFlags &= ~IN_OPTION;
835
836 DilloHtmlInput *input = Html_get_current_input(html);
837 if (input) {
838 DilloHtmlSelect *select = input->select;
839 if (input->type == DILLO_HTML_INPUT_SELECT) {
840 // option menu interface requires that something be selected */
841 select->ensureSelection ();
842 }
843 /* May not have an embed or resource */
844 if (input->getResource())
845 select->addOptsTo ((SelectionResource*)input->getResource());
846 }
847 }
848}
849
850void Html_tag_open_optgroup(DilloHtml *html, const char *tag, int tagsize)
851{
852 if (!(html->InFlags & IN_SELECT)) {
853 BUG_MSG("<optgroup> outside <select>.");
854 return;
855 }
856 if (html->InFlags & IN_OPTGROUP) {
857 BUG_MSG("Nested <optgroup>.");
858 return;
859 }
860 if (html->InFlags & IN_OPTION) {
861 Html_option_finish(html);
862 html->InFlags &= ~IN_OPTION;
863 }
864
865 html->InFlags |= IN_OPTGROUP;
866
867 DilloHtmlInput *input = Html_get_current_input(html);
868 if (input &&
869 (input->type == DILLO_HTML_INPUT_SELECT ||
870 input->type == DILLO_HTML_INPUT_SEL_LIST)) {
871 char *label = a_Html_get_attr_wdef(html, tag, tagsize, "label", NULL);
872 bool enabled = (a_Html_get_attr(html, tag, tagsize, "disabled") == NULL);
873
874 if (!label) {
875 BUG_MSG("<optgroup> requires label attribute.");
876 label = dStrdup("");
877 }
878
879 DilloHtmlOptgroup *opt =
880 new DilloHtmlOptgroup (label, enabled);
881
882 input->select->addOpt(opt);
883 }
884}
885
887{
888 if (html->InFlags & IN_OPTGROUP) {
889 html->InFlags &= ~IN_OPTGROUP;
890
891 if (html->InFlags & IN_OPTION) {
892 Html_option_finish(html);
893 html->InFlags &= ~IN_OPTION;
894 }
895
896 DilloHtmlInput *input = Html_get_current_input(html);
897 if (input &&
898 (input->type == DILLO_HTML_INPUT_SELECT ||
899 input->type == DILLO_HTML_INPUT_SEL_LIST)) {
900 DilloHtmlOptgroupClose *opt = new DilloHtmlOptgroupClose ();
901
902 input->select->addOpt(opt);
903 }
904 }
905}
906
907/*
908 * <OPTION>
909 */
910void Html_tag_open_option(DilloHtml *html, const char *tag, int tagsize)
911{
912 if (!(html->InFlags & IN_SELECT)) {
913 BUG_MSG("<option> outside <select>.");
914 return;
915 }
916 if (html->InFlags & IN_OPTION)
917 Html_option_finish(html);
918 html->InFlags |= IN_OPTION;
919
920 DilloHtmlInput *input = Html_get_current_input(html);
921 if (input &&
922 (input->type == DILLO_HTML_INPUT_SELECT ||
923 input->type == DILLO_HTML_INPUT_SEL_LIST)) {
924 char *value = a_Html_get_attr_wdef(html, tag, tagsize, "value", NULL);
925 char *label = a_Html_get_attr_wdef(html, tag, tagsize, "label", NULL);
926 bool selected = (a_Html_get_attr(html, tag, tagsize,"selected") != NULL);
927 bool enabled = (a_Html_get_attr(html, tag, tagsize, "disabled") == NULL);
928
929 DilloHtmlOption *option =
930 new DilloHtmlOption (value, label, selected, enabled);
931
932 input->select->addOpt(option);
933 }
934
935 a_Html_stash_init(html);
936}
937
939{
940 if (html->InFlags & IN_OPTION) {
941 Html_option_finish(html);
942 html->InFlags &= ~IN_OPTION;
943 }
944}
945
946/*
947 * <BUTTON>
948 */
949void Html_tag_open_button(DilloHtml *html, const char *tag, int tagsize)
950{
951 /*
952 * Buttons are rendered on one line, this is (at several levels) a
953 * bit simpler. May be changed in the future.
954 */
955 DilloHtmlInputType inp_type;
956 char *type;
957
958 assert((html->InFlags & (IN_BUTTON | IN_SELECT | IN_TEXTAREA)) == 0);
959
960 html->InFlags |= IN_BUTTON;
961 type = a_Html_get_attr_wdef(html, tag, tagsize, "type", "");
962
963 if (!dStrAsciiCasecmp(type, "button")) {
964 inp_type = DILLO_HTML_INPUT_BUTTON;
965 } else if (!dStrAsciiCasecmp(type, "reset")) {
967 } else if (!dStrAsciiCasecmp(type, "submit") || !*type) {
968 /* submit button is the default */
970 } else {
971 inp_type = DILLO_HTML_INPUT_UNKNOWN;
972 BUG_MSG("<button> type unknown: '%s'.", type);
973 }
974
975 if (inp_type != DILLO_HTML_INPUT_UNKNOWN) {
976 /* Render the button */
977 Embed *embed;
978 const char *attrbuf;
979
980 if (prefs.show_tooltip &&
981 (attrbuf = a_Html_get_attr(html, tag, tagsize, "title"))) {
982
984 attrbuf);
985 }
986
987 /* Always add the input element, so is present in the form */
988 char *value = a_Html_get_attr_wdef(html, tag, tagsize, "value", NULL);
989 char *name = a_Html_get_attr_wdef(html, tag, tagsize, "name", NULL);
990
991 ResourceFactory *factory = HT2LT(html)->getResourceFactory();
992
993 bool owns_embed = true;
994 if (a_Html_should_display(html)) {
995 /* We used to have Textblock (prefs.limit_text_width, ...) here,
996 * but it caused 100% CPU usage.
997 */
998 Widget *page = new Textblock (false, true);
999 page->setStyle (html->backgroundStyle ());
1000
1001 ComplexButtonResource *resource = factory->createComplexButtonResource(page, true);
1002 embed = new Embed(resource);
1003
1004 HT2TB(html)->addWidget (embed, html->backgroundStyle ());
1005 S_TOP(html)->textblock = html->dw = page;
1006 owns_embed = false;
1007 } else {
1008 /* Use simple button if not visible */
1009 Resource *resource = factory->createLabelButtonResource(value);
1010 embed = new Embed(resource);
1011 }
1012
1013 Html_add_input(html, inp_type, embed, name, value, FALSE, owns_embed);
1014 dFree(name);
1015 dFree(value);
1016 }
1017 dFree(type);
1018}
1019
1024{
1025 html->InFlags &= ~IN_BUTTON;
1026}
1027
1028/*
1029 * Class implementations
1030 */
1031
1032/*
1033 * DilloHtmlForm
1034 */
1035
1036/*
1037 * Constructor
1038 */
1039DilloHtmlForm::DilloHtmlForm (DilloHtml *html2,
1040 DilloHtmlMethod method2,
1041 const DilloUrl *action2,
1042 DilloHtmlEnc content_type2,
1043 const char *charset, bool enabled)
1044{
1045 html = html2;
1046 method = method2;
1047 action = a_Url_dup(action2);
1048 content_type = content_type2;
1049 submit_charset = dStrdup(charset);
1050 inputs = new misc::SimpleVector <DilloHtmlInput*> (4);
1051 num_entry_fields = 0;
1052 showing_hiddens = false;
1053 this->enabled = enabled;
1054 form_receiver = new DilloHtmlReceiver (this);
1055}
1056
1057/*
1058 * Destructor
1059 */
1060DilloHtmlForm::~DilloHtmlForm ()
1061{
1062 a_Url_free(action);
1063 dFree(submit_charset);
1064 for (int j = 0; j < inputs->size(); j++)
1065 delete inputs->get(j);
1066 delete(inputs);
1067 if (form_receiver)
1068 delete(form_receiver);
1069}
1070
1071void DilloHtmlForm::eventHandler(Resource *resource, EventButton *event)
1072{
1073 _MSG("DilloHtmlForm::eventHandler\n");
1074 if (event && (event->button == 3)) {
1075 a_UIcmd_form_popup(html->bw, html->page_url, this, showing_hiddens);
1076 } else {
1077 DilloHtmlInput *input = getInput(resource);
1078 if (input) {
1079 input->activate (this, num_entry_fields, event);
1080 } else {
1081 MSG("DilloHtmlForm::eventHandler: ERROR, input not found!\n");
1082 }
1083 }
1084}
1085
1086/*
1087 * Submit.
1088 * (Called by eventHandler())
1089 */
1090void DilloHtmlForm::submit(DilloHtmlInput *active_input, EventButton *event)
1091{
1092 if (!dStrAsciiCasecmp(URL_SCHEME(html->page_url), "https") &&
1093 dStrAsciiCasecmp(URL_SCHEME(action), "https")) {
1094 int choice = a_Dialog_choice("Dillo: Insecure form submission",
1095 "A form on a SECURE page wants to use an "
1096 "INSECURE protocol to submit data.",
1097 "Continue", "Cancel", NULL);
1098 if (choice != 1)
1099 return;
1100 }
1101
1102 DilloUrl *url = buildQueryUrl(active_input);
1103 if (url) {
1104 if (event && event->button == 2) {
1106 int focus = prefs.focus_new_tab ? 1 : 0;
1107 if (event->state == SHIFT_MASK) focus = !focus;
1108 a_UIcmd_open_url_nt(html->bw, url, focus);
1109 } else {
1110 a_UIcmd_open_url_nw(html->bw, url);
1111 }
1112 } else {
1113 a_UIcmd_open_url(html->bw, url);
1114 }
1115 a_Url_free(url);
1116 }
1117}
1118
1123DilloUrl *DilloHtmlForm::buildQueryUrl(DilloHtmlInput *active_input)
1124{
1125 DilloUrl *new_url = NULL;
1126
1127 if ((method == DILLO_HTML_METHOD_GET) ||
1128 (method == DILLO_HTML_METHOD_POST)) {
1129 Dstr *DataStr;
1130 DilloHtmlInput *active_submit = NULL;
1131
1132 _MSG("DilloHtmlForm::buildQueryUrl: action=%s\n",URL_STR_(action));
1133
1134 if (active_input) {
1135 if ((active_input->type == DILLO_HTML_INPUT_SUBMIT) ||
1136 (active_input->type == DILLO_HTML_INPUT_IMAGE) ||
1137 (active_input->type == DILLO_HTML_INPUT_BUTTON_SUBMIT)) {
1138 active_submit = active_input;
1139 }
1140 }
1141
1142 DataStr = buildQueryData(active_submit);
1143 if (DataStr) {
1144 /* action was previously resolved against base URL */
1145 char *action_str = dStrdup(URL_STR(action));
1146
1147 if (method == DILLO_HTML_METHOD_POST) {
1148 new_url = a_Url_new(action_str, NULL);
1149 /* new_url keeps the dStr and sets DataStr to NULL */
1150 a_Url_set_data(new_url, &DataStr);
1151 a_Url_set_flags(new_url, URL_FLAGS(new_url) | URL_Post);
1152 if (content_type == DILLO_HTML_ENC_MULTIPART)
1153 a_Url_set_flags(new_url, URL_FLAGS(new_url) | URL_MultipartEnc);
1154 } else {
1155 /* remove <fragment> and <query> sections if present */
1156 char *url_str, *p;
1157 if ((p = strchr(action_str, '#')))
1158 *p = 0;
1159 if ((p = strchr(action_str, '?')))
1160 *p = 0;
1161
1162 url_str = dStrconcat(action_str, "?", DataStr->str, NULL);
1163 new_url = a_Url_new(url_str, NULL);
1164 a_Url_set_flags(new_url, URL_FLAGS(new_url) | URL_Get);
1165 dFree(url_str);
1166 }
1167 dStr_free(DataStr, 1);
1168 dFree(action_str);
1169 }
1170 } else {
1171 MSG("DilloHtmlForm::buildQueryUrl: Method unknown\n");
1172 }
1173
1174 return new_url;
1175}
1176
1180Dstr *DilloHtmlForm::buildQueryData(DilloHtmlInput *active_submit)
1181{
1182 Dstr *DataStr = NULL;
1183 char *boundary = NULL;
1184 iconv_t char_encoder = (iconv_t) -1;
1185
1186 if (submit_charset && dStrAsciiCasecmp(submit_charset, "UTF-8")) {
1187 /* Some iconv implementations, given "//TRANSLIT", will do their best to
1188 * transliterate the string. Under the circumstances, doing so is likely
1189 * for the best.
1190 */
1191 char *translit = dStrconcat(submit_charset, "//TRANSLIT", NULL);
1192
1193 char_encoder = iconv_open(translit, "UTF-8");
1194 dFree(translit);
1195
1196 if (char_encoder == (iconv_t) -1)
1197 char_encoder = iconv_open(submit_charset, "UTF-8");
1198
1199 if (char_encoder == (iconv_t) -1) {
1200 MSG_WARN("Cannot convert to character encoding '%s'\n",
1201 submit_charset);
1202 } else {
1203 MSG("Form character encoding: '%s'\n", submit_charset);
1204 }
1205 }
1206
1207 if (content_type == DILLO_HTML_ENC_MULTIPART) {
1208 if (!(boundary = makeMultipartBoundary(char_encoder, active_submit)))
1209 MSG_ERR("Cannot generate multipart/form-data boundary.\n");
1210 }
1211
1212 if ((content_type == DILLO_HTML_ENC_URLENCODED) || (boundary != NULL)) {
1213 Dlist *values = dList_new(5);
1214
1215 DataStr = dStr_sized_new(4096);
1216 for (int i = 0; i < inputs->size(); i++) {
1217 DilloHtmlInput *input = inputs->get (i);
1218 Dstr *name = dStr_new(input->name);
1219 bool is_active_submit = (input == active_submit);
1220 int valcount;
1221
1222 name = encodeText(char_encoder, &name);
1223
1224 input->appendValuesTo(values, is_active_submit);
1225
1226 if ((valcount = dList_length(values)) > 0) {
1227 if (input->type == DILLO_HTML_INPUT_FILE) {
1228 if (valcount > 1)
1229 MSG_WARN("multiple files per form control not supported\n");
1230 Dstr *file = (Dstr *) dList_nth_data(values, 0);
1231 dList_remove(values, file);
1232
1233 /* Get filename and encode it. Do not encode file contents. */
1234 if (input->getResource()) {
1235 LabelButtonResource *lbr =
1236 (LabelButtonResource*) input->getResource();
1237 const char *filename = lbr->getLabel();
1238 if (filename[0] && strcmp(filename, input->init_str)) {
1239 const char *p = strrchr(filename, '/');
1240 if (p)
1241 filename = p + 1; /* don't reveal path */
1242 Dstr *dfilename = dStr_new(filename);
1243 dfilename = encodeText(char_encoder, &dfilename);
1244 filesInputMultipartAppend(DataStr, boundary, name->str,
1245 file, dfilename->str);
1246 dStr_free(dfilename, 1);
1247 }
1248 }
1249 dStr_free(file, 1);
1250 } else if (input->type == DILLO_HTML_INPUT_INDEX) {
1251 /* no name */
1252 Dstr *val = (Dstr *) dList_nth_data(values, 0);
1253 dList_remove(values, val);
1254 val = encodeText(char_encoder, &val);
1255 strUrlencodeAppend(DataStr, val->str);
1256 dStr_free(val, 1);
1257 } else if (input->type == DILLO_HTML_INPUT_IMAGE) {
1258 Dstr *x, *y;
1259 x = (Dstr *) dList_nth_data(values, 0);
1260 dList_remove(values, x);
1261 y = (Dstr *) dList_nth_data(values, 0);
1262 dList_remove(values, y);
1263 if (content_type == DILLO_HTML_ENC_URLENCODED)
1264 imageInputUrlencodeAppend(DataStr, name, x, y);
1265 else if (content_type == DILLO_HTML_ENC_MULTIPART)
1266 imageInputMultipartAppend(DataStr, boundary, name, x, y);
1267 dStr_free(x, 1);
1268 dStr_free(y, 1);
1269 } else {
1270 for (int j = 0; j < valcount; j++) {
1271 Dstr *val = (Dstr *) dList_nth_data(values, 0);
1272 dList_remove(values, val);
1273 val = encodeText(char_encoder, &val);
1274 if (content_type == DILLO_HTML_ENC_URLENCODED)
1275 inputUrlencodeAppend(DataStr, name->str, val->str);
1276 else if (content_type == DILLO_HTML_ENC_MULTIPART)
1277 inputMultipartAppend(DataStr, boundary, name->str,
1278 val->str);
1279 dStr_free(val, 1);
1280 }
1281 }
1282 }
1283 dStr_free(name, 1);
1284 }
1285 if (DataStr->len > 0) {
1286 if (content_type == DILLO_HTML_ENC_URLENCODED) {
1287 if (DataStr->str[DataStr->len - 1] == '&')
1288 dStr_truncate(DataStr, DataStr->len - 1);
1289 } else if (content_type == DILLO_HTML_ENC_MULTIPART) {
1290 dStr_append(DataStr, "--");
1291 }
1292 }
1293 dList_free(values);
1294 }
1295 dFree(boundary);
1296 if (char_encoder != (iconv_t) -1)
1297 (void)iconv_close(char_encoder);
1298 return DataStr;
1299}
1300
1307static void generate_boundary(Dstr *boundary)
1308{
1309 /* Extracted from RFC 2046, section 5.1.1. */
1310 static const char set[] = "abcdefghijklmnopqrstuvwxyz"
1311 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1312 "0123456789";
1313 static const size_t n = strlen(set);
1314
1315 for (int i = 0; i < 70; i++) {
1316 int c = (unsigned char) set[rand() % n];
1317 dStr_append_c(boundary, c);
1318 }
1319}
1320
1325char *DilloHtmlForm::makeMultipartBoundary(iconv_t char_encoder,
1326 DilloHtmlInput *active_submit)
1327{
1328 Dlist *values = dList_new(5);
1329 Dstr *DataStr = dStr_new("");
1330 Dstr *boundary = dStr_new("");
1331 char *ret = NULL;
1332
1333 /* fill DataStr with names, filenames, and values */
1334 for (int i = 0; i < inputs->size(); i++) {
1335 Dstr *dstr;
1336 DilloHtmlInput *input = inputs->get (i);
1337 bool is_active_submit = (input == active_submit);
1338 input->appendValuesTo(values, is_active_submit);
1339
1340 if (input->name) {
1341 dstr = dStr_new(input->name);
1342 dstr = encodeText(char_encoder, &dstr);
1343 dStr_append_l(DataStr, dstr->str, dstr->len);
1344 dStr_free(dstr, 1);
1345 }
1346 if (input->type == DILLO_HTML_INPUT_FILE) {
1347 LabelButtonResource *lbr =
1348 (LabelButtonResource*)input->embed->getResource();
1349 const char *filename = lbr->getLabel();
1350 if (filename[0] && strcmp(filename, input->init_str)) {
1351 dstr = dStr_new(filename);
1352 dstr = encodeText(char_encoder, &dstr);
1353 dStr_append_l(DataStr, dstr->str, dstr->len);
1354 dStr_free(dstr, 1);
1355 }
1356 }
1357 int length = dList_length(values);
1358 for (int i = 0; i < length; i++) {
1359 dstr = (Dstr *) dList_nth_data(values, 0);
1360 dList_remove(values, dstr);
1361 if (input->type != DILLO_HTML_INPUT_FILE)
1362 dstr = encodeText(char_encoder, &dstr);
1363 dStr_append_l(DataStr, dstr->str, dstr->len);
1364 dStr_free(dstr, 1);
1365 }
1366 }
1367
1368 generate_boundary(boundary);
1369 ret = boundary->str;
1370 dList_free(values);
1371 dStr_free(DataStr, 1);
1372 dStr_free(boundary, (ret == NULL));
1373 return ret;
1374}
1375
1381Dstr *DilloHtmlForm::encodeText(iconv_t char_encoder, Dstr **input)
1382{
1383 int rc = 0;
1384 Dstr *output;
1385 const int bufsize = 128;
1386 inbuf_t *inPtr;
1387 char *buffer, *outPtr;
1388 size_t inLeft, outRoom;
1389 bool bad_chars = false;
1390
1391 if ((char_encoder == (iconv_t) -1) || *input == NULL || (*input)->len == 0)
1392 return *input;
1393
1394 output = dStr_new("");
1395 inPtr = (*input)->str;
1396 inLeft = (*input)->len;
1397 buffer = dNew(char, bufsize);
1398
1399 while ((rc != EINVAL) && (inLeft > 0)) {
1400
1401 outPtr = buffer;
1402 outRoom = bufsize;
1403
1404 rc = iconv(char_encoder, &inPtr, &inLeft, &outPtr, &outRoom);
1405
1406 // iconv() on success, number of bytes converted
1407 // -1, errno == EILSEQ illegal byte sequence found
1408 // EINVAL partial character ends source buffer
1409 // E2BIG destination buffer is full
1410 //
1411 // GNU iconv has the undocumented(!) behavior that EILSEQ is also
1412 // returned when a character cannot be converted.
1413
1414 dStr_append_l(output, buffer, bufsize - outRoom);
1415
1416 if (rc == -1) {
1417 rc = errno;
1418 }
1419 if (rc == EILSEQ){
1420 /* count chars? (would be utf-8-specific) */
1421 bad_chars = true;
1422 inPtr++;
1423 inLeft--;
1424 dStr_append_c(output, '?');
1425 } else if (rc == EINVAL) {
1426 MSG_ERR("Form encode text: bad source string.\n");
1427 }
1428 }
1429
1430 if (bad_chars) {
1431 /*
1432 * It might be friendly to inform the caller, who would know whether
1433 * it is safe to display the beginning of the string in a message
1434 * (isn't, e.g., a password).
1435 */
1436 MSG_WARN("Form encode text: string cannot be converted cleanly.\n");
1437 }
1438
1439 dFree(buffer);
1440 dStr_free(*input, 1);
1441
1442 return output;
1443}
1444
1448void DilloHtmlForm::strUrlencodeAppend(Dstr *dstr, const char *str)
1449{
1450 char *encoded = a_Url_encode_hex_str(str);
1451 dStr_append(dstr, encoded);
1452 dFree(encoded);
1453}
1454
1458void DilloHtmlForm::inputUrlencodeAppend(Dstr *data, const char *name,
1459 const char *value)
1460{
1461 if (name && name[0]) {
1462 strUrlencodeAppend(data, name);
1463 dStr_append_c(data, '=');
1464 strUrlencodeAppend(data, value);
1465 dStr_append_c(data, '&');
1466 }
1467}
1468
1473void DilloHtmlForm::filesInputMultipartAppend(Dstr* data,
1474 const char *boundary,
1475 const char *name,
1476 Dstr *file,
1477 const char *filename)
1478{
1479 const char *ctype, *ext;
1480
1481 if (name && name[0]) {
1482 (void)a_Misc_get_content_type_from_data(file->str, file->len, &ctype);
1483 /* Heuristic: text/plain with ".htm[l]" extension -> text/html */
1484 if ((ext = strrchr(filename, '.')) &&
1485 !dStrAsciiCasecmp(ctype, "text/plain") &&
1486 (!dStrAsciiCasecmp(ext, ".html") || !dStrAsciiCasecmp(ext, ".htm"))){
1487 ctype = "text/html";
1488 }
1489
1490 if (data->len == 0) {
1491 dStr_append(data, "--");
1492 dStr_append(data, boundary);
1493 }
1494 dStr_sprintfa(data,
1495 "\r\n"
1496 "Content-Disposition: form-data; name=\"%s\"; "
1497 "filename=\"", name);
1498 /*
1499 * Replace the characters that are the most likely to damage things.
1500 * For a while, there was some momentum to standardize on an encoding,
1501 * but HTML5/Ian Hickson/his Google masters are, as of late 2012,
1502 * evidently standing in opposition to all of that for some reason.
1503 */
1504 for (int i = 0; char c = filename[i]; i++) {
1505 if (c == '\"' || c == '\r' || c == '\n')
1506 c = '_';
1507 dStr_append_c(data, c);
1508 }
1509 dStr_sprintfa(data,
1510 "\"\r\n"
1511 "Content-Type: %s\r\n"
1512 "\r\n", ctype);
1513
1514 dStr_append_l(data, file->str, file->len);
1515
1516 dStr_sprintfa(data,
1517 "\r\n"
1518 "--%s", boundary);
1519 }
1520}
1521
1525void DilloHtmlForm::inputMultipartAppend(Dstr *data,
1526 const char *boundary,
1527 const char *name,
1528 const char *value)
1529{
1530 if (name && name[0]) {
1531 if (data->len == 0) {
1532 dStr_append(data, "--");
1533 dStr_append(data, boundary);
1534 }
1535 dStr_sprintfa(data,
1536 "\r\n"
1537 "Content-Disposition: form-data; name=\"%s\"\r\n"
1538 "\r\n"
1539 "%s\r\n"
1540 "--%s",
1541 name, value, boundary);
1542 }
1543}
1544
1548void DilloHtmlForm::imageInputUrlencodeAppend(Dstr *data, Dstr *name, Dstr *x,
1549 Dstr *y)
1550{
1551 if (name->len) {
1552 strUrlencodeAppend(data, name->str);
1553 dStr_sprintfa(data, ".x=%s&", x->str);
1554 strUrlencodeAppend(data, name->str);
1555 dStr_sprintfa(data, ".y=%s&", y->str);
1556 } else
1557 dStr_sprintfa(data, "x=%s&y=%s&", x->str, y->str);
1558}
1559
1563void DilloHtmlForm::imageInputMultipartAppend(Dstr *data, const char *boundary,
1564 Dstr *name, Dstr *x, Dstr *y)
1565{
1566 int orig_len = name->len;
1567
1568 if (orig_len)
1569 dStr_append_c(name, '.');
1570 dStr_append_c(name, 'x');
1571
1572 inputMultipartAppend(data, boundary, name->str, x->str);
1573 dStr_truncate(name, name->len - 1);
1574 dStr_append_c(name, 'y');
1575 inputMultipartAppend(data, boundary, name->str, y->str);
1576 dStr_truncate(name, orig_len);
1577}
1578
1583void DilloHtmlForm::reset ()
1584{
1585 int size = inputs->size();
1586 for (int i = 0; i < size; i++)
1587 inputs->get(i)->reset();
1588}
1589
1593void DilloHtmlForm::display_hiddens(bool display)
1594{
1595 int size = inputs->size();
1596 for (int i = 0; i < size; i++) {
1597 DilloHtmlInput *input = inputs->get(i);
1598 if (input->type == DILLO_HTML_INPUT_HIDDEN) {
1599 input->embed->setDisplayed(display);
1600 }
1601 }
1602 showing_hiddens = display;
1603}
1604
1605void DilloHtmlForm::setEnabled(bool enabled)
1606{
1607 for (int i = 0; i < inputs->size(); i++)
1608 inputs->get(i)->setEnabled(enabled);
1609}
1610
1614void DilloHtmlForm::addInput(DilloHtmlInput *input, DilloHtmlInputType type)
1615{
1616 input->connectTo (form_receiver);
1617 input->setEnabled (enabled);
1618 int ni = inputs->size ();
1619 inputs->increase ();
1620 inputs->set (ni,input);
1621
1622 /* some stats */
1623 if (type == DILLO_HTML_INPUT_PASSWORD ||
1624 type == DILLO_HTML_INPUT_TEXT) {
1625 num_entry_fields++;
1626 }
1627}
1628
1632DilloHtmlInput *DilloHtmlForm::getInput (Resource *resource)
1633{
1634 if (resource == NULL)
1635 return NULL;
1636
1637 for (int idx = 0; idx < inputs->size(); idx++) {
1638 DilloHtmlInput *input = inputs->get(idx);
1639 Resource *r = input->getResource();
1640 if (r && resource == r)
1641 return input;
1642 }
1643 return NULL;
1644}
1645
1649DilloHtmlInput *DilloHtmlForm::getRadioInput (const char *name)
1650{
1651 for (int idx = 0; idx < inputs->size(); idx++) {
1652 DilloHtmlInput *input = inputs->get(idx);
1653 if (input->type == DILLO_HTML_INPUT_RADIO &&
1654 input->name && !dStrAsciiCasecmp(input->name, name))
1655 return input;
1656 }
1657 return NULL;
1658}
1659
1660/*
1661 * DilloHtmlReceiver
1662 *
1663 * TODO: Currently there's "clicked" for buttons, we surely need "enter" for
1664 * textentries, and maybe the "mouseover, ...." set for Javascript.
1665 */
1666
1667void DilloHtmlReceiver::activate (Resource *resource)
1668{
1669 form->eventHandler(resource, NULL);
1670}
1671
1676void DilloHtmlReceiver::enter (Resource *resource)
1677{
1678 DilloHtml *html = form->html;
1679 DilloHtmlInput *input = form->getInput(resource);
1680 const char *msg = "";
1681
1682 if ((input->type == DILLO_HTML_INPUT_SUBMIT) ||
1683 (input->type == DILLO_HTML_INPUT_IMAGE) ||
1684 (input->type == DILLO_HTML_INPUT_BUTTON_SUBMIT) ||
1685 (input->type == DILLO_HTML_INPUT_INDEX) ||
1686 ((prefs.enterpress_forces_submit || form->num_entry_fields == 1) &&
1687 ((input->type == DILLO_HTML_INPUT_PASSWORD) ||
1688 (input->type == DILLO_HTML_INPUT_TEXT)))) {
1689 /* The control can submit form. Show action URL. */
1690 msg = URL_STR(form->action);
1691 }
1692 a_UIcmd_set_msg(html->bw, "%s", msg);
1693}
1694
1698void DilloHtmlReceiver::leave (Resource *resource)
1699{
1700 DilloHtml *html = form->html;
1701 a_UIcmd_set_msg(html->bw, "");
1702}
1703
1704void DilloHtmlReceiver::clicked (Resource *resource,
1705 EventButton *event)
1706{
1707 form->eventHandler(resource, event);
1708}
1709
1710/*
1711 * DilloHtmlInput
1712 */
1713
1714/*
1715 * Constructor
1716 */
1717DilloHtmlInput::DilloHtmlInput (DilloHtmlInputType type2, Embed *embed2,
1718 const char *name2, const char *init_str2,
1719 bool init_val2, bool owns_embed)
1720{
1721 type = type2;
1722 assert(embed2);
1723 embed = embed2; /* Cannot be NULL! */
1724 this->owns_embed = owns_embed;
1725 name = (name2) ? dStrdup(name2) : NULL;
1726 init_str = (init_str2) ? dStrdup(init_str2) : NULL;
1727 init_val = init_val2;
1728 select = NULL;
1729 switch (type) {
1732 select = new DilloHtmlSelect;
1733 break;
1734 default:
1735 break;
1736 }
1737 file_data = NULL;
1738 reset ();
1739}
1740
1741/*
1742 * Destructor
1743 */
1744DilloHtmlInput::~DilloHtmlInput ()
1745{
1746 /* Embed is not released here */
1747 dFree(name);
1748 dFree(init_str);
1749 dStr_free(file_data, 1);
1750 if (select)
1751 delete select;
1752 if (owns_embed && embed)
1753 delete embed;
1754}
1755
1759void DilloHtmlInput::connectTo(DilloHtmlReceiver *form_receiver)
1760{
1761 Resource *resource = getResource();
1762 if (resource) {
1763 resource->connectClicked (form_receiver);
1764 if (type == DILLO_HTML_INPUT_SUBMIT ||
1765 type == DILLO_HTML_INPUT_RESET ||
1768 type == DILLO_HTML_INPUT_IMAGE ||
1769 type == DILLO_HTML_INPUT_FILE ||
1770 type == DILLO_HTML_INPUT_TEXT ||
1771 type == DILLO_HTML_INPUT_PASSWORD ||
1772 type == DILLO_HTML_INPUT_INDEX) {
1773 resource->connectActivate (form_receiver);
1774 }
1775 }
1776}
1777
1781void DilloHtmlInput::activate(DilloHtmlForm *form, int num_entry_fields,
1782 EventButton *event)
1783{
1784 switch (type) {
1786 readFile (form->html->bw);
1787 break;
1790 form->reset();
1791 break;
1794 if (!(prefs.enterpress_forces_submit || num_entry_fields == 1)) {
1795 break;
1796 }
1797 /* fallthrough */
1802 form->submit(this, event);
1803 break;
1804 default:
1805 break;
1806 }
1807}
1808
1812void DilloHtmlInput::readFile (BrowserWindow *bw)
1813{
1814 const char *filename = a_UIcmd_select_file();
1815 if (filename) {
1816 a_UIcmd_set_msg(bw, "Loading file...");
1817 dStr_free(file_data, 1);
1818 file_data = a_Misc_file2dstr(filename);
1819 if (file_data) {
1820 a_UIcmd_set_msg(bw, "File loaded.");
1822 lbr->setLabel(filename);
1823 } else {
1824 a_UIcmd_set_msg(bw, "ERROR: can't load: %s", filename);
1825 }
1826 }
1827}
1828
1832void DilloHtmlInput::appendValuesTo(Dlist *values, bool is_active_submit)
1833{
1834 switch (type) {
1839 {
1840 EntryResource *entryres = (EntryResource*)embed->getResource();
1841 dList_append(values, dStr_new(entryres->getText()));
1842 }
1843 break;
1845 {
1846 MultiLineTextResource *textres =
1848 dList_append(values, dStr_new(textres->getText()));
1849 }
1850 break;
1853 {
1854 ToggleButtonResource *cb_r =
1856 if (name && init_str && cb_r->isActivated()) {
1857 dList_append(values, dStr_new(init_str));
1858 }
1859 }
1860 break;
1863 if (is_active_submit)
1864 dList_append(values, dStr_new(init_str));
1865 break;
1868 {
1869 SelectionResource *sel_res = (SelectionResource*)embed->getResource();
1870 select->appendValuesTo (values, sel_res);
1871 }
1872 break;
1874 {
1876 const char *filename = lbr->getLabel();
1877 if (filename[0] && strcmp(filename, init_str)) {
1878 if (file_data) {
1879 Dstr *file = dStr_sized_new(file_data->len);
1880 dStr_append_l(file, file_data->str, file_data->len);
1881 dList_append(values, file);
1882 } else {
1883 MSG("FORM file input \"%s\" not loaded.\n", filename);
1884 }
1885 }
1886 }
1887 break;
1889 if (is_active_submit) {
1892 Dstr *strX = dStr_new("");
1893 Dstr *strY = dStr_new("");
1894 dStr_sprintf(strX, "%d", cbr->getClickX());
1895 dStr_sprintf(strY, "%d", cbr->getClickY());
1896 dList_append(values, strX);
1897 dList_append(values, strY);
1898 }
1899 break;
1900 default:
1901 break;
1902 }
1903}
1904
1908void DilloHtmlInput::reset ()
1909{
1910 if (embed == NULL || embed->getResource() == NULL)
1911 return;
1912
1913 switch (type) {
1918 {
1919 EntryResource *entryres = (EntryResource*)embed->getResource();
1920 entryres->setText(init_str ? init_str : "");
1921 }
1922 break;
1925 {
1926 ToggleButtonResource *tb_r =
1928 tb_r->setActivated(init_val);
1929 }
1930 break;
1933 if (select != NULL) {
1935 select->reset(sr);
1936 }
1937 break;
1939 if (init_str != NULL) {
1940 MultiLineTextResource *textres =
1942 textres->setText(init_str ? init_str : "");
1943 }
1944 break;
1946 {
1948 lbr->setLabel(init_str);
1949 }
1950 break;
1951 default:
1952 break;
1953 }
1954}
1955
1956/*
1957 * DilloHtmlSelect
1958 */
1959
1960/*
1961 * Constructor
1962 */
1963DilloHtmlSelect::DilloHtmlSelect ()
1964{
1966}
1967
1968/*
1969 * Destructor
1970 */
1971DilloHtmlSelect::~DilloHtmlSelect ()
1972{
1973 int size = opts->size ();
1974 for (int k = 0; k < size; k++)
1975 delete opts->get (k);
1976 delete opts;
1977}
1978
1979DilloHtmlOptbase *DilloHtmlSelect::getCurrentOpt ()
1980{
1981 return opts->get (opts->size() - 1);
1982}
1983
1984void DilloHtmlSelect::addOpt (DilloHtmlOptbase *opt)
1985{
1986 int size = opts->size ();
1987 opts->increase ();
1988 opts->set (size, opt);
1989}
1990
1994void DilloHtmlSelect::ensureSelection()
1995{
1996 int size = opts->size ();
1997 if (size > 0) {
1998 for (int i = 0; i < size; i++) {
1999 DilloHtmlOptbase *opt = opts->get (i);
2000 if (opt->isSelected())
2001 return;
2002 }
2003 for (int i = 0; i < size; i++) {
2004 DilloHtmlOptbase *opt = opts->get (i);
2005 if (opt->select())
2006 break;
2007 }
2008 }
2009}
2010
2011void DilloHtmlSelect::addOptsTo (SelectionResource *res)
2012{
2013 int size = opts->size ();
2014 for (int i = 0; i < size; i++) {
2015 DilloHtmlOptbase *opt = opts->get (i);
2016 opt->addSelf(res);
2017 }
2018}
2019
2020void DilloHtmlSelect::reset (SelectionResource *res)
2021{
2022 int size = opts->size ();
2023 for (int i = 0; i < size; i++) {
2024 DilloHtmlOptbase *opt = opts->get (i);
2025 res->setItem(i, opt->isSelected());
2026 }
2027}
2028
2029void DilloHtmlSelect::appendValuesTo (Dlist *values, SelectionResource *res)
2030{
2031 int size = opts->size ();
2032 for (int i = 0; i < size; i++) {
2033 if (res->isSelected (i)) {
2034 DilloHtmlOptbase *opt = opts->get (i);
2035 const char *val = opt->getValue();
2036
2037 if (val)
2038 dList_append(values, dStr_new(val));
2039 }
2040 }
2041}
2042
2043DilloHtmlOptgroup::DilloHtmlOptgroup (char *label, bool enabled)
2044{
2045 this->label = label;
2046 this->enabled = enabled;
2047}
2048
2049DilloHtmlOptgroup::~DilloHtmlOptgroup ()
2050{
2051 dFree(label);
2052}
2053
2054/*
2055 * DilloHtmlOption
2056 */
2057
2058/*
2059 * Constructor
2060 */
2061DilloHtmlOption::DilloHtmlOption (char *value2, char *label2, bool selected2,
2062 bool enabled2)
2063{
2064 value = value2;
2065 label = label2;
2066 content = NULL;
2067 selected = selected2;
2068 enabled = enabled2;
2069}
2070
2071/*
2072 * Destructor
2073 */
2074DilloHtmlOption::~DilloHtmlOption ()
2075{
2076 dFree(value);
2077 dFree(label);
2078 dFree(content);
2079}
2080
2081/*
2082 * Utilities
2083 */
2084
2088static Embed *Html_input_image(DilloHtml *html, const char *tag, int tagsize)
2089{
2091 Embed *button = NULL;
2092
2093 html->styleEngine->setPseudoLink ();
2094
2095 /* create new image and add it to the button */
2096 a_Html_common_image_attrs(html, tag, tagsize);
2097 if ((Image = a_Html_image_new(html, tag, tagsize))) {
2098 // At this point, we know that Image->ir represents an image
2099 // widget. Notice that the order of the casts matters, because
2100 // of multiple inheritance.
2101 dw::Image *dwi = (dw::Image*)(dw::core::ImgRenderer*)Image->img_rndr;
2102 dwi->setStyle (html->backgroundStyle ());
2103 ResourceFactory *factory = HT2LT(html)->getResourceFactory();
2104 ComplexButtonResource *complex_b_r =
2105 factory->createComplexButtonResource(dwi, false);
2106 button = new Embed(complex_b_r);
2107 HT2TB(html)->addWidget (button, html->style ());
2108 }
2109 if (!button)
2110 MSG("Html_input_image: unable to create image submit.\n");
2111 return button;
2112}
2113
2114/*
2115 * ?
2116 */
2118{
2119 DilloHtmlInput *input = Html_get_current_input(html);
2120 if (input &&
2121 (input->type == DILLO_HTML_INPUT_SELECT ||
2122 input->type == DILLO_HTML_INPUT_SEL_LIST)) {
2123 DilloHtmlOptbase *opt = input->select->getCurrentOpt ();
2124 opt->setContent (html->Stash->str, html->Stash->len);
2125 }
2126}
#define _MSG(...)
Definition bookmarks.c:44
#define MSG(...)
Definition bookmarks.c:45
int InFlags
tracks which elements we are in
DilloHtmlDocumentType DocType
DilloUrl * base_url
dw::core::style::Style * backgroundStyle()
int formNew(DilloHtmlMethod method, const DilloUrl *action, DilloHtmlEnc enc, const char *charset)
Allocate and insert form information.
Definition html.cc:667
float DocTypeVersion
Dstr * Stash
lout::misc::SimpleVector< DilloHtmlInput * > * inputs_outside_form
dw::core::style::Style * wordStyle()
BrowserWindow * bw
dw::core::style::Style * style()
dw::core::Widget * dw
char * charset
StyleEngine * styleEngine
DilloHtmlForm * getCurrentForm()
Get the current form.
Definition html.cc:684
void setNonCssHint(CssPropertyName name, CssValueType type, CssPropertyValue value)
void setPseudoLink()
set the CSS pseudo class :link.
Displays an instance of dw::core::Imgbuf.
Definition image.hh:140
A Widget for rendering text blocks, i.e.
Definition textblock.hh:206
Represents a button press or release event.
Definition events.hh:58
ButtonState state
Definition events.hh:42
The base class of all dillo widgets.
Definition widget.hh:44
virtual void setStyle(style::Style *style)
Change the style of a widget.
Definition widget.cc:1316
A widget for embedding UI widgets.
Definition ui.hh:224
void setEnabled(bool enabled)
Definition ui.cc:136
void setDisplayed(bool displayed)
Definition ui.cc:131
Resource * getResource()
Definition ui.hh:263
Interface for labelled buttons resources.
Definition ui.hh:400
virtual const char * getLabel()=0
virtual void setLabel(const char *label)=0
@ SELECTION_AT_MOST_ONE
At most one item is selected.
Definition ui.hh:503
@ SELECTION_MULTIPLE
An arbitrary number of items may be selected.
Definition ui.hh:508
A factory for the common resource.
Definition ui.hh:581
virtual OptionMenuResource * createOptionMenuResource()=0
virtual EntryResource * createEntryResource(int size, bool password, const char *label, const char *placeholder)=0
virtual MultiLineTextResource * createMultiLineTextResource(int cols, int rows, const char *placeholder)=0
virtual RadioButtonResource * createRadioButtonResource(RadioButtonResource *groupedWith, bool activated)=0
virtual CheckButtonResource * createCheckButtonResource(bool activated)=0
virtual ListResource * createListResource(ListResource::SelectionMode selectionMode, int rows)=0
virtual ComplexButtonResource * createComplexButtonResource(Widget *widget, bool relief)=0
virtual LabelButtonResource * createLabelButtonResource(const char *label)=0
Receiver interface for the "activate" signal.
Definition ui.hh:297
virtual void activate(Resource *resource)=0
virtual void leave(Resource *resource)=0
virtual void enter(Resource *resource)=0
Receiver interface for the "clicked" signal.
Definition ui.hh:307
virtual void clicked(Resource *resource, EventButton *event)=0
Basic interface for all resources.
Definition ui.hh:289
void connectClicked(ClickedReceiver *receiver)
Definition ui.hh:388
void connectActivate(ActivateReceiver *receiver)
Definition ui.hh:386
Base interface for dw::core::ui::ListResource and dw::core::ui::OptionMenuResource.
Definition ui.hh:467
virtual void pushGroup(const char *name, bool enabled)=0
virtual bool isSelected(int index)=0
virtual void setItem(int index, bool selected)=0
virtual void addItem(const char *str, bool enabled, bool selected)=0
virtual void setText(const char *text)=0
virtual const char * getText()=0
virtual void setEditable(bool editable)=0
virtual void setActivated(bool activated)=0
Simple (simpler than container::untyped::Vector and container::typed::Vector) template based vector.
Definition misc.hh:115
void increase()
Increase the vector size by one.
Definition misc.hh:181
void set(int i, T t)
Store an object in the vector.
Definition misc.hh:267
T get(int i) const
Return the one element, explicitly.
Definition misc.hh:222
int size() const
Return the number of elements put into this vector.
Definition misc.hh:162
@ PROPERTY_X_TOOLTIP
Definition css.hh:251
@ CSS_TYPE_STRING
<string>
Definition css.hh:58
static const int bufsize
Definition decode.c:28
int a_Dialog_choice(const char *title, const char *msg,...)
Make a question-dialog with a question and alternatives.
Definition dialog.cc:370
char * dStrconcat(const char *s1,...)
Concatenate a NULL-terminated list of strings.
Definition dlib.c:101
char * dStrsep(char **orig, const char *delim)
strsep() implementation
Definition dlib.c:158
void dFree(void *mem)
Definition dlib.c:67
int dStrAsciiCasecmp(const char *s1, const char *s2)
Definition dlib.c:202
void dStr_sprintfa(Dstr *ds, const char *format,...)
Printf-like function that appends.
Definition dlib.c:463
void dStr_append(Dstr *ds, const char *s)
Append a C string to a Dstr.
Definition dlib.c:315
char * dStrdup(const char *s)
Definition dlib.c:76
Dlist * dList_new(int size)
Create a new empty list.
Definition dlib.c:575
Dstr * dStr_sized_new(int sz)
Create a new string with a given size.
Definition dlib.c:253
void dStr_erase(Dstr *ds, int pos_0, int len)
Erase a substring.
Definition dlib.c:387
int dList_length(Dlist *lp)
For completing the ADT.
Definition dlib.c:640
void * dList_nth_data(Dlist *lp, int n0)
Return the nth data item, NULL when not found or 'n0' is out of range.
Definition dlib.c:689
void dStr_free(Dstr *ds, int all)
Free a dillo string.
Definition dlib.c:336
void dStr_append_l(Dstr *ds, const char *s, int l)
Append a C string to a Dstr (providing length).
Definition dlib.c:307
void dStr_append_c(Dstr *ds, int c)
Append one character.
Definition dlib.c:348
char * dStrndup(const char *s, size_t sz)
Definition dlib.c:87
void dStr_sprintf(Dstr *ds, const char *format,...)
Printf-like function.
Definition dlib.c:449
Dstr * dStr_new(const char *s)
Create a new string.
Definition dlib.c:324
void dList_append(Dlist *lp, void *data)
Append a data item to the list.
Definition dlib.c:624
void dList_free(Dlist *lp)
Free a list (not its elements)
Definition dlib.c:591
void dStr_truncate(Dstr *ds, int len)
Truncate a Dstr to be 'len' bytes long.
Definition dlib.c:367
void dList_remove(Dlist *lp, const void *data)
Definition dlib.c:668
#define FALSE
Definition dlib.h:32
#define dNew(type, count)
Definition dlib.h:78
#define MSG_ERR(...)
Definition dpid_common.h:23
const char * a_Html_get_attr(DilloHtml *html, const char *tag, int tagsize, const char *attrname)
Call Html_get_attr2 telling it to parse entities and strip the result.
Definition html.cc:4292
void a_Html_stash_init(DilloHtml *html)
Initialize the stash buffer.
Definition html.cc:853
bool a_Html_should_display(DilloHtml *html)
Definition html.cc:4033
DilloUrl * a_Html_url_new(DilloHtml *html, const char *url_str, const char *base_url, int use_base_url)
Wrapper for a_Url_new that adds an error detection message.
Definition html.cc:172
DilloImage * a_Html_image_new(DilloHtml *html, const char *tag, int tagsize)
Definition html.cc:2143
void a_Html_common_image_attrs(DilloHtml *html, const char *tag, int tagsize)
Read image-associated tag attributes and create new image.
Definition html.cc:2073
char * a_Html_get_attr_wdef(DilloHtml *html, const char *tag, int tagsize, const char *attrname, const char *def)
"a_Html_get_attr with default" Call a_Html_get_attr() and dStrdup() the returned string.
Definition html.cc:4306
char * a_Html_parse_entities(DilloHtml *html, const char *token, int toksize)
Parse all the entities in a token.
Definition html.cc:1080
#define HT2TB(html)
"html struct" to Textblock
@ DILLO_HTML_PARSE_MODE_VERBATIM
#define BUG_MSG(...)
Add a bug-meter message.
#define S_TOP(html)
Top of the parsing stack.
@ IN_OPTGROUP
@ IN_BUTTON
@ IN_OPTION
@ IN_TEXTAREA
@ IN_SELECT
@ IN_FORM
#define HT2LT(html)
"html struct" to "Layout"
@ DT_HTML
#define MSG_WARN(...)
Definition msg.h:26
Dstr * a_Misc_file2dstr(const char *filename)
Load a local file into a dStr.
Definition misc.c:465
int a_Misc_get_content_type_from_data(void *Data, size_t Size, const char **PT)
Detects 'Content-Type' from a data stream sample.
Definition misc.c:137
Anything related to Dillo Widget styles is defined here.
Definition style.cc:33
Anything related to embedded UI widgets is defined here.
Definition core.hh:36
The core of Dw is defined in this namespace.
Definition core.hh:23
@ SHIFT_MASK
Definition events.hh:17
Dw is in this namespace, or sub namespaces of this one.
Definition form.cc:25
DilloPrefs prefs
Global Data.
Definition prefs.c:33
void Html_tag_close_form(DilloHtml *html)
Definition form.cc:408
void a_Html_form_display_hiddens2(void *vform, bool display)
Definition form.cc:268
void Html_tag_open_textarea(DilloHtml *html, const char *tag, int tagsize)
Definition form.cc:645
void Html_tag_content_textarea(DilloHtml *html, const char *tag, int tagsize)
The textarea tag.
Definition form.cc:655
void Html_tag_close_button(DilloHtml *html)
Handle close <BUTTON>
Definition form.cc:1023
void Html_tag_open_option(DilloHtml *html, const char *tag, int tagsize)
Definition form.cc:910
static void Html_option_finish(DilloHtml *html)
Definition form.cc:2117
DilloHtmlForm * a_Html_form_new(DilloHtml *html, DilloHtmlMethod method, const DilloUrl *action, DilloHtmlEnc content_type, const char *charset, bool enabled)
Definition form.cc:239
static int Html_input_get_size(DilloHtml *html, const char *attrbuf)
get size, restrict it to reasonable value
Definition form.cc:419
void Html_tag_open_optgroup(DilloHtml *html, const char *tag, int tagsize)
Definition form.cc:850
void a_Html_form_reset2(void *vform)
Definition form.cc:263
void a_Html_form_delete(DilloHtmlForm *form)
Definition form.cc:248
void a_Html_input_delete(DilloHtmlInput *input)
Definition form.cc:253
static DilloHtmlInput * Html_get_current_input(DilloHtml *html)
Get the current input if available.
Definition form.cc:326
void Html_tag_close_select(DilloHtml *html)
Definition form.cc:828
void Html_tag_open_isindex(DilloHtml *html, const char *tag, int tagsize)
The ISINDEX tag is just a deprecated form of <INPUT type=text>> with implied FORM,...
Definition form.cc:606
void Html_tag_close_optgroup(DilloHtml *html)
Definition form.cc:886
void Html_tag_close_textarea(DilloHtml *html)
Close textarea.
Definition form.cc:724
void Html_tag_open_select(DilloHtml *html, const char *tag, int tagsize)
Definition form.cc:765
static void generate_boundary(Dstr *boundary)
Generate a random boundary.
Definition form.cc:1307
static Embed * Html_input_image(DilloHtml *html, const char *tag, int tagsize)
Create input image for the form.
Definition form.cc:2088
void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize)
Add a new input to current form.
Definition form.cc:438
void Html_tag_open_button(DilloHtml *html, const char *tag, int tagsize)
Definition form.cc:949
void Html_tag_open_form(DilloHtml *html, const char *tag, int tagsize)
Handle <FORM> tag.
Definition form.cc:342
DilloHtmlInputType
Definition form.cc:51
@ DILLO_HTML_INPUT_SEL_LIST
Definition form.cc:66
@ DILLO_HTML_INPUT_RADIO
Definition form.cc:56
@ DILLO_HTML_INPUT_HIDDEN
Definition form.cc:60
@ DILLO_HTML_INPUT_TEXTAREA
Definition form.cc:67
@ DILLO_HTML_INPUT_UNKNOWN
Definition form.cc:52
@ DILLO_HTML_INPUT_BUTTON_RESET
Definition form.cc:64
@ DILLO_HTML_INPUT_CHECKBOX
Definition form.cc:55
@ DILLO_HTML_INPUT_RESET
Definition form.cc:62
@ DILLO_HTML_INPUT_INDEX
Definition form.cc:68
@ DILLO_HTML_INPUT_TEXT
Definition form.cc:53
@ DILLO_HTML_INPUT_SUBMIT
Definition form.cc:61
@ DILLO_HTML_INPUT_SELECT
Definition form.cc:65
@ DILLO_HTML_INPUT_BUTTON
Definition form.cc:59
@ DILLO_HTML_INPUT_PASSWORD
Definition form.cc:54
@ DILLO_HTML_INPUT_BUTTON_SUBMIT
Definition form.cc:63
@ DILLO_HTML_INPUT_FILE
Definition form.cc:58
@ DILLO_HTML_INPUT_IMAGE
Definition form.cc:57
static DilloHtmlInput * Html_get_radio_input(DilloHtml *html, const char *name)
Find radio input by name.
Definition form.cc:303
void a_Html_form_submit2(void *vform)
Definition form.cc:258
void Html_tag_close_option(DilloHtml *html)
Definition form.cc:938
static void Html_add_input(DilloHtml *html, DilloHtmlInputType type, Embed *embed, const char *name, const char *init_str, bool init_val, bool owns_embed)
Add an HTML control.
Definition form.cc:280
DilloHtmlMethod
Definition form.hh:10
@ DILLO_HTML_METHOD_GET
Definition form.hh:12
@ DILLO_HTML_METHOD_POST
Definition form.hh:13
DilloHtmlEnc
Definition form.hh:16
@ DILLO_HTML_ENC_URLENCODED
Definition form.hh:17
@ DILLO_HTML_ENC_MULTIPART
Definition form.hh:18
Contains the specific data for a single window.
Definition bw.h:27
int NumPendingStyleSheets
Number of not yet arrived style sheets.
Definition bw.h:48
bool_t enterpress_forces_submit
Definition prefs.h:114
bool_t show_tooltip
Definition prefs.h:66
bool_t focus_new_tab
Definition prefs.h:74
bool_t middle_click_opens_new_tab
Definition prefs.h:115
Definition url.h:88
Definition dlib.h:161
Definition dlib.h:131
Dstr_char_t * str
Definition dlib.h:134
int len
Definition dlib.h:133
void a_UIcmd_set_msg(BrowserWindow *bw, const char *format,...)
Definition uicmd.cc:1636
void a_UIcmd_form_popup(void *vbw, const DilloUrl *url, void *vform, bool_t showing_hiddens)
Definition uicmd.cc:1349
void a_UIcmd_open_url_nw(BrowserWindow *bw, const DilloUrl *url)
Definition uicmd.cc:850
const char * a_UIcmd_select_file()
Definition uicmd.cc:1178
void a_UIcmd_open_url(BrowserWindow *bw, const DilloUrl *url)
Definition uicmd.cc:815
void a_UIcmd_open_url_nt(void *vbw, const DilloUrl *url, int focus)
Definition uicmd.cc:866
void a_Url_set_flags(DilloUrl *u, int flags)
Set DilloUrl flags.
Definition url.c:526
char * a_Url_encode_hex_str(const char *str)
Urlencode 'str'.
Definition url.c:619
void a_Url_free(DilloUrl *url)
Free a DilloUrl.
Definition url.c:207
void a_Url_set_data(DilloUrl *u, Dstr **data)
Set DilloUrl data (like POST info, etc.)
Definition url.c:535
DilloUrl * a_Url_new(const char *url_str, const char *base_url)
Transform (and resolve) an URL string into the respective DilloURL.
Definition url.c:370
DilloUrl * a_Url_dup(const DilloUrl *ori)
Duplicate a Url structure.
Definition url.c:476
#define URL_SpamSafe
Definition url.h:40
#define URL_FLAGS(u)
Definition url.h:79
#define URL_MultipartEnc
Definition url.h:42
#define URL_STR(u)
Definition url.h:76
#define URL_STR_(u)
Definition url.h:55
#define URL_SCHEME(u)
Definition url.h:70
#define URL_Post
Definition url.h:33
#define URL_Get
Definition url.h:32