From 72f72d64a422d6628c4796f5c0bf2e508f134214 Mon Sep 17 00:00:00 2001 From: Tatsuya Kinoshita Date: Wed, 4 May 2011 16:05:14 +0900 Subject: Adding upstream version 0.5.1 --- form.c | 1055 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1055 insertions(+) create mode 100644 form.c (limited to 'form.c') diff --git a/form.c b/form.c new file mode 100644 index 0000000..a9e52c0 --- /dev/null +++ b/form.c @@ -0,0 +1,1055 @@ +/* $Id: form.c,v 1.34 2004/02/05 17:23:07 ukai Exp $ */ +/* + * HTML forms + */ +#include "fm.h" +#include "parsetag.h" +#include "parsetagx.h" +#include "myctype.h" +#include "local.h" +#include "regex.h" + +extern Str *textarea_str; +#ifdef MENU_SELECT +extern FormSelectOption *select_option; +#include "menu.h" +#endif /* MENU_SELECT */ + +/* *INDENT-OFF* */ +struct { + char *action; + void (*rout)(struct parsed_tagarg *); +} internal_action[] = { + {"map", follow_map}, + {"option", panel_set_option}, +#ifdef USE_COOKIE + {"cookie", set_cookie_flag}, +#endif /* USE_COOKIE */ + {"download", download_action}, +#ifdef USE_M17N + { "charset", change_charset }, +#endif + {"none", NULL}, + {NULL, NULL}, +}; +/* *INDENT-ON* */ + +struct form_list * +newFormList(char *action, char *method, char *charset, char *enctype, + char *target, char *name, struct form_list *_next) +{ + struct form_list *l; + Str a = Strnew_charp(action); + int m = FORM_METHOD_GET; + int e = FORM_ENCTYPE_URLENCODED; +#ifdef USE_M17N + wc_ces c = 0; +#endif + + if (method == NULL || !strcasecmp(method, "get")) + m = FORM_METHOD_GET; + else if (!strcasecmp(method, "post")) + m = FORM_METHOD_POST; + else if (!strcasecmp(method, "internal")) + m = FORM_METHOD_INTERNAL; + /* unknown method is regarded as 'get' */ + + if (enctype != NULL && !strcasecmp(enctype, "multipart/form-data")) { + e = FORM_ENCTYPE_MULTIPART; + if (m == FORM_METHOD_GET) + m = FORM_METHOD_POST; + } + +#ifdef USE_M17N + if (charset != NULL) + c = wc_guess_charset(charset, 0); +#endif + + l = New(struct form_list); + l->item = l->lastitem = NULL; + l->action = a; + l->method = m; +#ifdef USE_M17N + l->charset = c; +#endif + l->enctype = e; + l->target = target; + l->name = name; + l->next = _next; + l->nitems = 0; + l->body = NULL; + l->length = 0; + return l; +} + +/* + * add element to form_list + */ +struct form_item_list * +formList_addInput(struct form_list *fl, struct parsed_tag *tag) +{ + struct form_item_list *item; + char *p; + int i; + + /* if not in
..
environment, just ignore tag */ + if (fl == NULL) + return NULL; + + item = New(struct form_item_list); + item->type = FORM_UNKNOWN; + item->size = -1; + item->rows = 0; + item->checked = item->init_checked = 0; + item->accept = 0; + item->name = NULL; + item->value = item->init_value = NULL; + item->readonly = 0; + if (parsedtag_get_value(tag, ATTR_TYPE, &p)) { + item->type = formtype(p); + if (item->size < 0 && + (item->type == FORM_INPUT_TEXT || + item->type == FORM_INPUT_FILE || + item->type == FORM_INPUT_PASSWORD)) + item->size = FORM_I_TEXT_DEFAULT_SIZE; + } + if (parsedtag_get_value(tag, ATTR_NAME, &p)) + item->name = Strnew_charp(p); + if (parsedtag_get_value(tag, ATTR_VALUE, &p)) + item->value = item->init_value = Strnew_charp(p); + item->checked = item->init_checked = parsedtag_exists(tag, ATTR_CHECKED); + item->accept = parsedtag_exists(tag, ATTR_ACCEPT); + parsedtag_get_value(tag, ATTR_SIZE, &item->size); + parsedtag_get_value(tag, ATTR_MAXLENGTH, &item->maxlength); + item->readonly = parsedtag_exists(tag, ATTR_READONLY); + if (parsedtag_get_value(tag, ATTR_TEXTAREANUMBER, &i)) + item->value = item->init_value = textarea_str[i]; +#ifdef MENU_SELECT + if (parsedtag_get_value(tag, ATTR_SELECTNUMBER, &i)) + item->select_option = select_option[i].first; +#endif /* MENU_SELECT */ + if (parsedtag_get_value(tag, ATTR_ROWS, &p)) + item->rows = atoi(p); + if (item->type == FORM_UNKNOWN) { + /* type attribute is missing. Ignore the tag. */ + return NULL; + } +#ifdef MENU_SELECT + if (item->type == FORM_SELECT) { + chooseSelectOption(item, item->select_option); + item->init_selected = item->selected; + item->init_value = item->value; + item->init_label = item->label; + } +#endif /* MENU_SELECT */ + if (item->type == FORM_INPUT_FILE && item->value && item->value->length) { + /* security hole ! */ + return NULL; + } + item->parent = fl; + item->next = NULL; + if (fl->item == NULL) { + fl->item = fl->lastitem = item; + } + else { + fl->lastitem->next = item; + fl->lastitem = item; + } + if (item->type == FORM_INPUT_HIDDEN) + return NULL; + fl->nitems++; + return item; +} + +static char *_formtypetbl[] = { + "text", "password", "checkbox", "radio", "submit", "reset", "hidden", + "image", "select", "textarea", "button", "file", NULL +}; + +static char *_formmethodtbl[] = { + "GET", "POST", "INTERNAL", "HEAD" +}; + +char * +form2str(FormItemList *fi) +{ + Str tmp = Strnew(); + + if (fi->type != FORM_SELECT && fi->type != FORM_TEXTAREA) + Strcat_charp(tmp, "input type="); + Strcat_charp(tmp, _formtypetbl[fi->type]); + if (fi->name && fi->name->length) + Strcat_m_charp(tmp, " name=\"", fi->name->ptr, "\"", NULL); + if ((fi->type == FORM_INPUT_RADIO || fi->type == FORM_INPUT_CHECKBOX || + fi->type == FORM_SELECT) && fi->value) + Strcat_m_charp(tmp, " value=\"", fi->value->ptr, "\"", NULL); + Strcat_m_charp(tmp, " (", _formmethodtbl[fi->parent->method], " ", + fi->parent->action->ptr, ")", NULL); + return tmp->ptr; +} + +int +formtype(char *typestr) +{ + int i; + for (i = 0; _formtypetbl[i]; i++) { + if (!strcasecmp(typestr, _formtypetbl[i])) + return i; + } + return FORM_UNKNOWN; +} + +void +formRecheckRadio(Anchor *a, Buffer *buf, FormItemList *fi) +{ + int i; + Anchor *a2; + FormItemList *f2; + + for (i = 0; i < buf->formitem->nanchor; i++) { + a2 = &buf->formitem->anchors[i]; + f2 = (FormItemList *)a2->url; + if (f2->parent == fi->parent && f2 != fi && + f2->type == FORM_INPUT_RADIO && Strcmp(f2->name, fi->name) == 0) { + f2->checked = 0; + formUpdateBuffer(a2, buf, f2); + } + } + fi->checked = 1; + formUpdateBuffer(a, buf, fi); +} + +void +formResetBuffer(Buffer *buf, AnchorList *formitem) +{ + int i; + Anchor *a; + FormItemList *f1, *f2; + + if (buf == NULL || buf->formitem == NULL || formitem == NULL) + return; + for (i = 0; i < buf->formitem->nanchor && i < formitem->nanchor; i++) { + a = &buf->formitem->anchors[i]; + if (a->y != a->start.line) + continue; + f1 = (FormItemList *)a->url; + f2 = (FormItemList *)formitem->anchors[i].url; + if (f1->type != f2->type || + strcmp(((f1->name == NULL) ? "" : f1->name->ptr), + ((f2->name == NULL) ? "" : f2->name->ptr))) + break; /* What's happening */ + switch (f1->type) { + case FORM_INPUT_TEXT: + case FORM_INPUT_PASSWORD: + case FORM_INPUT_FILE: + case FORM_TEXTAREA: + f1->value = f2->value; + f1->init_value = f2->init_value; + break; + case FORM_INPUT_CHECKBOX: + case FORM_INPUT_RADIO: + f1->checked = f2->checked; + f1->init_checked = f2->init_checked; + break; + case FORM_SELECT: +#ifdef MENU_SELECT + f1->select_option = f2->select_option; + f1->value = f2->value; + f1->label = f2->label; + f1->selected = f2->selected; + f1->init_value = f2->init_value; + f1->init_label = f2->init_label; + f1->init_selected = f2->init_selected; +#endif /* MENU_SELECT */ + break; + default: + continue; + } + formUpdateBuffer(a, buf, f1); + } +} + +static int +form_update_line(Line *line, char **str, int spos, int epos, int width, + int newline, int password) +{ + int c_len = 1, c_width = 1, w, i, len, pos; + char *p, *buf; + Lineprop c_type, effect, *prop; + + for (p = *str, w = 0, pos = 0; *p && w < width;) { + c_type = get_mctype((unsigned char *)p); +#ifdef USE_M17N + c_len = get_mclen(p); + c_width = get_mcwidth(p); +#endif + if (c_type == PC_CTRL) { + if (newline && *p == '\n') + break; + if (*p != '\r') { + w++; + pos++; + } + } + else if (password) { +#ifdef USE_M17N + if (w + c_width > width) + break; +#endif + w += c_width; + pos += c_width; +#ifdef USE_M17N + } + else if (c_type & PC_UNKNOWN) { + w++; + pos++; + } + else { + if (w + c_width > width) + break; +#endif + w += c_width; + pos += c_len; + } + p += c_len; + } + pos += width - w; + + len = line->len + pos + spos - epos; + buf = New_N(char, len); + prop = New_N(Lineprop, len); + bcopy((void *)line->lineBuf, (void *)buf, spos * sizeof(char)); + bcopy((void *)line->propBuf, (void *)prop, spos * sizeof(Lineprop)); + + effect = CharEffect(line->propBuf[spos]); + for (p = *str, w = 0, pos = spos; *p && w < width;) { + c_type = get_mctype((unsigned char *)p); +#ifdef USE_M17N + c_len = get_mclen(p); + c_width = get_mcwidth(p); +#endif + if (c_type == PC_CTRL) { + if (newline && *p == '\n') + break; + if (*p != '\r') { + buf[pos] = password ? '*' : ' '; + prop[pos] = effect | PC_ASCII; + pos++; + w++; + } + } + else if (password) { +#ifdef USE_M17N + if (w + c_width > width) + break; +#endif + for (i = 0; i < c_width; i++) { + buf[pos] = '*'; + prop[pos] = effect | PC_ASCII; + pos++; + w++; + } +#ifdef USE_M17N + } + else if (c_type & PC_UNKNOWN) { + buf[pos] = ' '; + prop[pos] = effect | PC_ASCII; + pos++; + w++; + } + else { + if (w + c_width > width) + break; +#else + } + else { +#endif + buf[pos] = *p; + prop[pos] = effect | c_type; + pos++; +#ifdef USE_M17N + c_type = (c_type & ~PC_WCHAR1) | PC_WCHAR2; + for (i = 1; i < c_len; i++) { + buf[pos] = p[i]; + prop[pos] = effect | c_type; + pos++; + } +#endif + w += c_width; + } + p += c_len; + } + for (; w < width; w++) { + buf[pos] = ' '; + prop[pos] = effect | PC_ASCII; + pos++; + } + if (newline) { + if (!FoldTextarea) { + while (*p && *p != '\r' && *p != '\n') + p++; + } + if (*p == '\r') + p++; + if (*p == '\n') + p++; + } + *str = p; + + bcopy((void *)&line->lineBuf[epos], (void *)&buf[pos], + (line->len - epos) * sizeof(char)); + bcopy((void *)&line->propBuf[epos], (void *)&prop[pos], + (line->len - epos) * sizeof(Lineprop)); + line->lineBuf = buf; + line->propBuf = prop; + line->len = len; + + return pos; +} + +void +formUpdateBuffer(Anchor *a, Buffer *buf, FormItemList *form) +{ + Buffer save; + char *p; + int spos, epos, rows, c_rows, pos, col = 0; + Line *l; + + copyBuffer(&save, buf); + gotoLine(buf, a->start.line); + switch (form->type) { + case FORM_TEXTAREA: + case FORM_INPUT_TEXT: + case FORM_INPUT_FILE: + case FORM_INPUT_PASSWORD: + case FORM_INPUT_CHECKBOX: + case FORM_INPUT_RADIO: +#ifdef MENU_SELECT + case FORM_SELECT: +#endif /* MENU_SELECT */ + spos = a->start.pos; + epos = a->end.pos; + break; + default: + spos = a->start.pos + 1; + epos = a->end.pos - 1; + } + switch (form->type) { + case FORM_INPUT_CHECKBOX: + case FORM_INPUT_RADIO: + if (form->checked) + buf->currentLine->lineBuf[spos] = '*'; + else + buf->currentLine->lineBuf[spos] = ' '; + break; + case FORM_INPUT_TEXT: + case FORM_INPUT_FILE: + case FORM_INPUT_PASSWORD: + case FORM_TEXTAREA: +#ifdef MENU_SELECT + case FORM_SELECT: + if (form->type == FORM_SELECT) { + p = form->label->ptr; + updateSelectOption(form, form->select_option); + } + else +#endif /* MENU_SELECT */ + p = form->value->ptr; + l = buf->currentLine; + if (form->type == FORM_TEXTAREA) { + int n = a->y - buf->currentLine->linenumber; + if (n > 0) + for (; l && n; l = l->prev, n--) ; + else if (n < 0) + for (; l && n; l = l->prev, n++) ; + if (!l) + break; + } + rows = form->rows ? form->rows : 1; + col = COLPOS(l, a->start.pos); + for (c_rows = 0; c_rows < rows; c_rows++, l = l->next) { + if (rows > 1) { + pos = columnPos(l, col); + a = retrieveAnchor(buf->formitem, l->linenumber, pos); + if (a == NULL) + break; + spos = a->start.pos; + epos = a->end.pos; + } + pos = form_update_line(l, &p, spos, epos, COLPOS(l, epos) - col, + rows > 1, + form->type == FORM_INPUT_PASSWORD); + if (pos != epos) { + shiftAnchorPosition(buf->href, buf->hmarklist, + a->start.line, spos, pos - epos); + shiftAnchorPosition(buf->name, buf->hmarklist, + a->start.line, spos, pos - epos); + shiftAnchorPosition(buf->img, buf->hmarklist, + a->start.line, spos, pos - epos); + shiftAnchorPosition(buf->formitem, buf->hmarklist, + a->start.line, spos, pos - epos); + } + } + break; + } + copyBuffer(buf, &save); + arrangeLine(buf); +} + + +Str +textfieldrep(Str s, int width) +{ + Lineprop c_type; + Str n = Strnew_size(width + 2); + int i, j, k, c_len; + + j = 0; + for (i = 0; i < s->length; i += c_len) { + c_type = get_mctype((unsigned char *)&s->ptr[i]); + c_len = get_mclen(&s->ptr[i]); + if (s->ptr[i] == '\r') + continue; + k = j + get_mcwidth(&s->ptr[i]); + if (k > width) + break; + if (c_type == PC_CTRL) + Strcat_char(n, ' '); +#ifdef USE_M17N + else if (c_type & PC_UNKNOWN) + Strcat_char(n, ' '); +#endif + else if (s->ptr[i] == '&') + Strcat_charp(n, "&"); + else if (s->ptr[i] == '<') + Strcat_charp(n, "<"); + else if (s->ptr[i] == '>') + Strcat_charp(n, ">"); + else + Strcat_charp_n(n, &s->ptr[i], c_len); + j = k; + } + for (; j < width; j++) + Strcat_char(n, ' '); + return n; +} + +static void +form_fputs_decode(Str s, FILE * f) +{ + char *p; + Str z = Strnew(); + + for (p = s->ptr; *p;) { + switch (*p) { +#if !defined( __CYGWIN__ ) && !defined( __EMX__ ) + case '\r': + if (*(p + 1) == '\n') + p++; + /* continue to the next label */ +#endif /* !defined( __CYGWIN__ ) && !defined( __EMX__ + * ) */ + default: + Strcat_char(z, *p); + p++; + break; + } + } +#ifdef USE_M17N + z = wc_Str_conv_strict(z, InnerCharset, DisplayCharset); +#endif + Strfputs(z, f); +} + + +void +input_textarea(FormItemList *fi) +{ + char *tmpf = tmpfname(TMPF_DFL, NULL)->ptr; + Str tmp; + FILE *f; +#ifdef USE_M17N + wc_ces charset = DisplayCharset; + wc_uint8 auto_detect; +#endif + + f = fopen(tmpf, "w"); + if (f == NULL) { + /* FIXME: gettextize? */ + disp_err_message("Can't open temporary file", FALSE); + return; + } + if (fi->value) + form_fputs_decode(fi->value, f); + fclose(f); + + fmTerm(); + system(myEditor(Editor, tmpf, 1)->ptr); + fmInit(); + + if (fi->readonly) + goto input_end; + f = fopen(tmpf, "r"); + if (f == NULL) { + /* FIXME: gettextize? */ + disp_err_message("Can't open temporary file", FALSE); + goto input_end; + } + fi->value = Strnew(); +#ifdef USE_M17N + auto_detect = WcOption.auto_detect; + WcOption.auto_detect = WC_OPT_DETECT_ON; +#endif + while (tmp = Strfgets(f), tmp->length > 0) { + if (tmp->length == 1 && tmp->ptr[tmp->length - 1] == '\n') { + /* null line with bare LF */ + tmp = Strnew_charp("\r\n"); + } + else if (tmp->length > 1 && tmp->ptr[tmp->length - 1] == '\n' && + tmp->ptr[tmp->length - 2] != '\r') { + Strshrink(tmp, 1); + Strcat_charp(tmp, "\r\n"); + } + tmp = convertLine(NULL, tmp, RAW_MODE, &charset, DisplayCharset); + Strcat(fi->value, tmp); + } +#ifdef USE_M17N + WcOption.auto_detect = auto_detect; +#endif + fclose(f); + input_end: + unlink(tmpf); +} + +void +do_internal(char *action, char *data) +{ + int i; + + for (i = 0; internal_action[i].action; i++) { + if (strcasecmp(internal_action[i].action, action) == 0) { + if (internal_action[i].rout) + internal_action[i].rout(cgistr2tagarg(data)); + return; + } + } +} + +#ifdef MENU_SELECT +void +addSelectOption(FormSelectOption *fso, Str value, Str label, int chk) +{ + FormSelectOptionItem *o; + o = New(FormSelectOptionItem); + if (value == NULL) + value = label; + o->value = value; + Strremovefirstspaces(label); + Strremovetrailingspaces(label); + o->label = label; + o->checked = chk; + o->next = NULL; + if (fso->first == NULL) + fso->first = fso->last = o; + else { + fso->last->next = o; + fso->last = o; + } +} + +void +chooseSelectOption(FormItemList *fi, FormSelectOptionItem *item) +{ + FormSelectOptionItem *opt; + int i; + + fi->selected = 0; + if (item == NULL) { + fi->value = Strnew_size(0); + fi->label = Strnew_size(0); + return; + } + fi->value = item->value; + fi->label = item->label; + for (i = 0, opt = item; opt != NULL; i++, opt = opt->next) { + if (opt->checked) { + fi->value = opt->value; + fi->label = opt->label; + fi->selected = i; + break; + } + } + updateSelectOption(fi, item); +} + +void +updateSelectOption(FormItemList *fi, FormSelectOptionItem *item) +{ + int i; + + if (fi == NULL || item == NULL) + return; + for (i = 0; item != NULL; i++, item = item->next) { + if (i == fi->selected) + item->checked = TRUE; + else + item->checked = FALSE; + } +} + +int +formChooseOptionByMenu(struct form_item_list *fi, int x, int y) +{ + int i, n, selected = -1, init_select = fi->selected; + FormSelectOptionItem *opt; + char **label; + + for (n = 0, opt = fi->select_option; opt != NULL; n++, opt = opt->next) ; + label = New_N(char *, n + 1); + for (i = 0, opt = fi->select_option; opt != NULL; i++, opt = opt->next) + label[i] = opt->label->ptr; + label[n] = NULL; + + optionMenu(x, y, label, &selected, init_select, NULL); + + if (selected < 0) + return 0; + for (i = 0, opt = fi->select_option; opt != NULL; i++, opt = opt->next) { + if (i == selected) { + fi->selected = selected; + fi->value = opt->value; + fi->label = opt->label; + break; + } + } + updateSelectOption(fi, fi->select_option); + return 1; +} +#endif /* MENU_SELECT */ + +void +form_write_data(FILE * f, char *boundary, char *name, char *value) +{ + fprintf(f, "--%s\r\n", boundary); + fprintf(f, "Content-Disposition: form-data; name=\"%s\"\r\n\r\n", name); + fprintf(f, "%s\r\n", value); +} + +void +form_write_from_file(FILE * f, char *boundary, char *name, char *filename, + char *file) +{ + FILE *fd; + struct stat st; + int c; + char *type; + + fprintf(f, "--%s\r\n", boundary); + fprintf(f, + "Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n", + name, mybasename(filename)); + type = guessContentType(file); + fprintf(f, "Content-Type: %s\r\n\r\n", + type ? type : "application/octet-stream"); + + if (lstat(file, &st) < 0) + goto write_end; + if (S_ISDIR(st.st_mode)) + goto write_end; + fd = fopen(file, "r"); + if (fd != NULL) { + while ((c = fgetc(fd)) != EOF) + fputc(c, f); + fclose(fd); + } + write_end: + fprintf(f, "\r\n"); +} + +struct pre_form_item { + int type; + char *name; + char *value; + int checked; + struct pre_form_item *next; +}; + +struct pre_form { + char *url; + Regex *re_url; + char *name; + char *action; + struct pre_form_item *item; + struct pre_form *next; +}; + +static struct pre_form *PreForm = NULL; + +static struct pre_form * +add_pre_form(struct pre_form *prev, char *url, char *name, char *action) +{ + ParsedURL pu; + struct pre_form *new; + + if (prev) + new = prev->next = New(struct pre_form); + else + new = PreForm = New(struct pre_form); + if (url && *url == '/') { + int l = strlen(url); + if (l > 1 && url[l - 1] == '/') + new->url = allocStr(url + 1, l - 2); + else + new->url = url + 1; + new->re_url = newRegex(new->url, FALSE, NULL, NULL); + if (!new->re_url) + new->url = NULL; + } + else if (url) { + parseURL2(url, &pu, NULL); + new->url = parsedURL2Str(&pu)->ptr; + new->re_url = NULL; + } + new->name = (name && *name) ? name : NULL; + new->action = (action && *action) ? action : NULL; + new->item = NULL; + new->next = NULL; + return new; +} + +static struct pre_form_item * +add_pre_form_item(struct pre_form *pf, struct pre_form_item *prev, int type, + char *name, char *value, char *checked) +{ + struct pre_form_item *new; + + if (!pf) + return NULL; + if (prev) + new = prev->next = New(struct pre_form_item); + else + new = pf->item = New(struct pre_form_item); + new->type = type; + new->name = name; + new->value = value; + if (checked && *checked && (!strcmp(checked, "0") || + strcasecmp(checked, "off") + || !strcasecmp(checked, "no"))) + new->checked = 0; + else + new->checked = 1; + new->next = NULL; + return new; +} + +/* + * url |// + * form [] + * text + * file + * passwd + * checkbox [] + * radio + * select + * submit [ []] + * image [ []] + * textarea + * + * /textarea + */ + +void +loadPreForm(void) +{ + FILE *fp; + Str line = NULL, textarea = NULL; + struct pre_form *pf = NULL; + struct pre_form_item *pi = NULL; + int type = -1; + char *name = NULL; + + PreForm = NULL; + fp = openSecretFile(pre_form_file); + if (fp == NULL) + return; + while (1) { + char *p, *s, *arg; + + line = Strfgets(fp); + if (line->length == 0) + break; + if (textarea && !(!strncmp(line->ptr, "/textarea", 9) && + IS_SPACE(line->ptr[9]))) { + Strcat(textarea, line); + continue; + } + Strchop(line); + Strremovefirstspaces(line); + p = line->ptr; + if (*p == '#' || *p == '\0') + continue; /* comment or empty line */ + s = getWord(&p); + arg = getWord(&p); + + if (!strcmp(s, "url")) { + if (!arg || !*arg) + continue; + p = getQWord(&p); + pf = add_pre_form(pf, arg, NULL, p); + pi = pf->item; + continue; + } + if (!pf) + continue; + if (!strcmp(s, "form")) { + if (!arg || !*arg) + continue; + s = getQWord(&p); + p = getQWord(&p); + if (!p || !*p) { + p = s; + s = NULL; + } + if (pf->item) { + struct pre_form *prev = pf; + pf = add_pre_form(prev, "", s, p); + /* copy previous URL */ + pf->url = prev->url; + pf->re_url = prev->re_url; + } + else { + pf->name = s; + pf->action = (p && *p) ? p : NULL; + } + pi = pf->item; + continue; + } + if (!strcmp(s, "text")) + type = FORM_INPUT_TEXT; + else if (!strcmp(s, "file")) + type = FORM_INPUT_FILE; + else if (!strcmp(s, "passwd") || !strcmp(s, "password")) + type = FORM_INPUT_PASSWORD; + else if (!strcmp(s, "checkbox")) + type = FORM_INPUT_CHECKBOX; + else if (!strcmp(s, "radio")) + type = FORM_INPUT_RADIO; + else if (!strcmp(s, "submit")) + type = FORM_INPUT_SUBMIT; + else if (!strcmp(s, "image")) + type = FORM_INPUT_IMAGE; + else if (!strcmp(s, "select")) + type = FORM_SELECT; + else if (!strcmp(s, "textarea")) { + type = FORM_TEXTAREA; + name = Strnew_charp(arg)->ptr; + textarea = Strnew(); + continue; + } + else if (textarea && name && !strcmp(s, "/textarea")) { + pi = add_pre_form_item(pf, pi, type, name, textarea->ptr, NULL); + textarea = NULL; + name = NULL; + continue; + } + else + continue; + s = getQWord(&p); + pi = add_pre_form_item(pf, pi, type, arg, s, getQWord(&p)); + } + fclose(fp); +} + +void +preFormUpdateBuffer(Buffer *buf) +{ + struct pre_form *pf; + struct pre_form_item *pi; + int i; + Anchor *a; + FormList *fl; + FormItemList *fi; +#ifdef MENU_SELECT + FormSelectOptionItem *opt; + int j; +#endif + + if (!buf || !buf->formitem || !PreForm) + return; + + for (pf = PreForm; pf; pf = pf->next) { + if (pf->re_url) { + Str url = parsedURL2Str(&buf->currentURL); + if (!RegexMatch(pf->re_url, url->ptr, url->length, 1)) + continue; + } + else if (pf->url) { + if (Strcmp_charp(parsedURL2Str(&buf->currentURL), pf->url)) + continue; + } + else + continue; + for (i = 0; i < buf->formitem->nanchor; i++) { + a = &buf->formitem->anchors[i]; + fi = (FormItemList *)a->url; + fl = fi->parent; + if (pf->name && (!fl->name || strcmp(fl->name, pf->name))) + continue; + if (pf->action + && (!fl->action || Strcmp_charp(fl->action, pf->action))) + continue; + for (pi = pf->item; pi; pi = pi->next) { + if (pi->type != fi->type) + continue; + if (pi->type == FORM_INPUT_SUBMIT || + pi->type == FORM_INPUT_IMAGE) { + if ((!pi->name || !*pi->name || + (fi->name && !Strcmp_charp(fi->name, pi->name))) && + (!pi->value || !*pi->value || + (fi->value && !Strcmp_charp(fi->value, pi->value)))) + buf->submit = a; + continue; + } + if (!pi->name || !fi->name || Strcmp_charp(fi->name, pi->name)) + continue; + switch (pi->type) { + case FORM_INPUT_TEXT: + case FORM_INPUT_FILE: + case FORM_INPUT_PASSWORD: + case FORM_TEXTAREA: + fi->value = Strnew_charp(pi->value); + formUpdateBuffer(a, buf, fi); + break; + case FORM_INPUT_CHECKBOX: + if (pi->value && fi->value && + !Strcmp_charp(fi->value, pi->value)) { + fi->checked = pi->checked; + formUpdateBuffer(a, buf, fi); + } + break; + case FORM_INPUT_RADIO: + if (pi->value && fi->value && + !Strcmp_charp(fi->value, pi->value)) + formRecheckRadio(a, buf, fi); + break; +#ifdef MENU_SELECT + case FORM_SELECT: + for (j = 0, opt = fi->select_option; opt != NULL; + j++, opt = opt->next) { + if (pi->value && opt->value && + !Strcmp_charp(opt->value, pi->value)) { + fi->selected = j; + fi->value = opt->value; + fi->label = opt->label; + updateSelectOption(fi, fi->select_option); + formUpdateBuffer(a, buf, fi); + break; + } + } + break; +#endif + } + } + } + } +} -- cgit v1.2.3 From 5397d09e585a1938fb64bc9c5cd5daed1959eb90 Mon Sep 17 00:00:00 2001 From: Tatsuya Kinoshita Date: Wed, 4 May 2011 16:41:45 +0900 Subject: Adding upstream version 0.5.3 --- form.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'form.c') diff --git a/form.c b/form.c index a9e52c0..b7556ca 100644 --- a/form.c +++ b/form.c @@ -1,4 +1,4 @@ -/* $Id: form.c,v 1.34 2004/02/05 17:23:07 ukai Exp $ */ +/* $Id: form.c,v 1.35 2010/07/18 13:48:48 htrb Exp $ */ /* * HTML forms */ @@ -403,6 +403,7 @@ form_update_line(Line *line, char **str, int spos, int epos, int width, line->lineBuf = buf; line->propBuf = prop; line->len = len; + line->size = len; return pos; } -- cgit v1.2.3 From 1d0ba25a660483da1272a31dd077ed94441e3d9f Mon Sep 17 00:00:00 2001 From: Tatsuya Kinoshita Date: Sat, 2 Jan 2021 09:20:37 +0900 Subject: New upstream version 0.5.3+git20210102 --- form.c | 61 +++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 24 deletions(-) (limited to 'form.c') diff --git a/form.c b/form.c index b7556ca..bc14d39 100644 --- a/form.c +++ b/form.c @@ -10,8 +10,10 @@ #include "regex.h" extern Str *textarea_str; +extern int max_textarea; #ifdef MENU_SELECT extern FormSelectOption *select_option; +extern int max_select; #include "menu.h" #endif /* MENU_SELECT */ @@ -54,10 +56,9 @@ newFormList(char *action, char *method, char *charset, char *enctype, m = FORM_METHOD_INTERNAL; /* unknown method is regarded as 'get' */ - if (enctype != NULL && !strcasecmp(enctype, "multipart/form-data")) { + if (m != FORM_METHOD_GET && enctype != NULL && + !strcasecmp(enctype, "multipart/form-data")) { e = FORM_ENCTYPE_MULTIPART; - if (m == FORM_METHOD_GET) - m = FORM_METHOD_POST; } #ifdef USE_M17N @@ -122,10 +123,12 @@ formList_addInput(struct form_list *fl, struct parsed_tag *tag) parsedtag_get_value(tag, ATTR_SIZE, &item->size); parsedtag_get_value(tag, ATTR_MAXLENGTH, &item->maxlength); item->readonly = parsedtag_exists(tag, ATTR_READONLY); - if (parsedtag_get_value(tag, ATTR_TEXTAREANUMBER, &i)) + if (parsedtag_get_value(tag, ATTR_TEXTAREANUMBER, &i) + && i >= 0 && i < max_textarea) item->value = item->init_value = textarea_str[i]; #ifdef MENU_SELECT - if (parsedtag_get_value(tag, ATTR_SELECTNUMBER, &i)) + if (parsedtag_get_value(tag, ATTR_SELECTNUMBER, &i) + && i >= 0 && i < max_select) item->select_option = select_option[i].first; #endif /* MENU_SELECT */ if (parsedtag_get_value(tag, ATTR_ROWS, &p)) @@ -196,7 +199,7 @@ formtype(char *typestr) if (!strcasecmp(typestr, _formtypetbl[i])) return i; } - return FORM_UNKNOWN; + return FORM_INPUT_TEXT; } void @@ -316,7 +319,8 @@ form_update_line(Line *line, char **str, int spos, int epos, int width, pos += width - w; len = line->len + pos + spos - epos; - buf = New_N(char, len); + buf = New_N(char, len + 1); + buf[len] = '\0'; prop = New_N(Lineprop, len); bcopy((void *)line->lineBuf, (void *)buf, spos * sizeof(char)); bcopy((void *)line->propBuf, (void *)prop, spos * sizeof(Lineprop)); @@ -438,6 +442,9 @@ formUpdateBuffer(Anchor *a, Buffer *buf, FormItemList *form) switch (form->type) { case FORM_INPUT_CHECKBOX: case FORM_INPUT_RADIO: + if (buf->currentLine == NULL || + spos >= buf->currentLine->len || spos < 0) + break; if (form->checked) buf->currentLine->lineBuf[spos] = '*'; else @@ -455,8 +462,14 @@ formUpdateBuffer(Anchor *a, Buffer *buf, FormItemList *form) } else #endif /* MENU_SELECT */ + { + if (!form->value) + break; p = form->value->ptr; + } l = buf->currentLine; + if (!l) + break; if (form->type == FORM_TEXTAREA) { int n = a->y - buf->currentLine->linenumber; if (n > 0) @@ -469,6 +482,8 @@ formUpdateBuffer(Anchor *a, Buffer *buf, FormItemList *form) rows = form->rows ? form->rows : 1; col = COLPOS(l, a->start.pos); for (c_rows = 0; c_rows < rows; c_rows++, l = l->next) { + if (l == NULL) + break; if (rows > 1) { pos = columnPos(l, col); a = retrieveAnchor(buf->formitem, l->linenumber, pos); @@ -477,6 +492,9 @@ formUpdateBuffer(Anchor *a, Buffer *buf, FormItemList *form) spos = a->start.pos; epos = a->end.pos; } + if (a->start.line != a->end.line || spos > epos || epos >= l->len || + spos < 0 || epos < 0 || COLPOS(l, epos) < col) + break; pos = form_update_line(l, &p, spos, epos, COLPOS(l, epos) - col, rows > 1, form->type == FORM_INPUT_PASSWORD); @@ -787,7 +805,7 @@ struct pre_form { static struct pre_form *PreForm = NULL; static struct pre_form * -add_pre_form(struct pre_form *prev, char *url, char *name, char *action) +add_pre_form(struct pre_form *prev, char *url, Regex *re_url, char *name, char *action) { ParsedURL pu; struct pre_form *new; @@ -796,21 +814,13 @@ add_pre_form(struct pre_form *prev, char *url, char *name, char *action) new = prev->next = New(struct pre_form); else new = PreForm = New(struct pre_form); - if (url && *url == '/') { - int l = strlen(url); - if (l > 1 && url[l - 1] == '/') - new->url = allocStr(url + 1, l - 2); - else - new->url = url + 1; - new->re_url = newRegex(new->url, FALSE, NULL, NULL); - if (!new->re_url) - new->url = NULL; - } - else if (url) { + if (url && !re_url) { parseURL2(url, &pu, NULL); new->url = parsedURL2Str(&pu)->ptr; - new->re_url = NULL; } + else + new->url = url; + new->re_url = re_url; new->name = (name && *name) ? name : NULL; new->action = (action && *action) ? action : NULL; new->item = NULL; @@ -834,7 +844,7 @@ add_pre_form_item(struct pre_form *pf, struct pre_form_item *prev, int type, new->name = name; new->value = value; if (checked && *checked && (!strcmp(checked, "0") || - strcasecmp(checked, "off") + !strcasecmp(checked, "off") || !strcasecmp(checked, "no"))) new->checked = 0; else @@ -875,6 +885,7 @@ loadPreForm(void) return; while (1) { char *p, *s, *arg; + Regex *re_arg; line = Strfgets(fp); if (line->length == 0) @@ -890,18 +901,20 @@ loadPreForm(void) if (*p == '#' || *p == '\0') continue; /* comment or empty line */ s = getWord(&p); - arg = getWord(&p); if (!strcmp(s, "url")) { + arg = getRegexWord((const char **)&p, &re_arg); if (!arg || !*arg) continue; p = getQWord(&p); - pf = add_pre_form(pf, arg, NULL, p); + pf = add_pre_form(pf, arg, re_arg, NULL, p); pi = pf->item; continue; } if (!pf) continue; + + arg = getWord(&p); if (!strcmp(s, "form")) { if (!arg || !*arg) continue; @@ -913,7 +926,7 @@ loadPreForm(void) } if (pf->item) { struct pre_form *prev = pf; - pf = add_pre_form(prev, "", s, p); + pf = add_pre_form(prev, "", NULL, s, p); /* copy previous URL */ pf->url = prev->url; pf->re_url = prev->re_url; -- cgit v1.2.3