Files
w3m/form.c
Kyle J. McKay 89e60cc474 form.c: do not gratuitously turn GET into POST
When encountering a <form ...> tag that contains these values:

    method="get" enctype="multipart/form-data"

Do not transform the method into POST to accomodate enctype.

Instead behave in the compatible way that all other browsers
behave in this instance and ignore the enctype parameter
(treating it as the default application/x-www-form-urlencoded)
and perform a "GET" just as the method parameter requests.

This behavior produces far more compatible results than
gratuitously changing the "get" into a "post" which can
result in unexpected "405 Method Not Allowed" errors.

Signed-off-by: Kyle J. McKay <mackyle@gmail.com>
2017-08-23 13:14:23 -07:00

1068 lines
24 KiB
C

/* $Id: form.c,v 1.35 2010/07/18 13:48:48 htrb 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;
extern int max_textarea;
#ifdef MENU_SELECT
extern FormSelectOption *select_option;
extern int max_select;
#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 (m != FORM_METHOD_GET && enctype != NULL &&
!strcasecmp(enctype, "multipart/form-data")) {
e = FORM_ENCTYPE_MULTIPART;
}
#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 <input> 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 <form>..</form> environment, just ignore <input> 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)
&& i >= 0 && i < max_textarea)
item->value = item->init_value = textarea_str[i];
#ifdef MENU_SELECT
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))
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_INPUT_TEXT;
}
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 + 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));
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;
line->size = 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 (buf->currentLine == NULL ||
spos >= buf->currentLine->len || spos < 0)
break;
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 */
{
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)
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;
}
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);
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, "&amp;");
else if (s->ptr[i] == '<')
Strcat_charp(n, "&lt;");
else if (s->ptr[i] == '>')
Strcat_charp(n, "&gt;");
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, Regex *re_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 && !re_url) {
parseURL2(url, &pu, NULL);
new->url = parsedURL2Str(&pu)->ptr;
}
else
new->url = url;
new->re_url = re_url;
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 <url>|/<re-url>/
* form [<name>] <action>
* text <name> <value>
* file <name> <value>
* passwd <name> <value>
* checkbox <name> <value> [<checked>]
* radio <name> <value>
* select <name> <value>
* submit [<name> [<value>]]
* image [<name> [<value>]]
* textarea <name>
* <value>
* /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;
Regex *re_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);
if (!strcmp(s, "url")) {
arg = getRegexWord((const char **)&p, &re_arg);
if (!arg || !*arg)
continue;
p = getQWord(&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;
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, "", NULL, 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
}
}
}
}
}