2 * type=image is treated like submit
11 typedef struct Field Field;
12 typedef struct Option Option;
16 Field *fields, *efields;
25 int size; /* should be a point, but that feature is deprecated */
31 int state; /* is the button marked? */
59 void h_checkinput(Panel *, int, int);
60 void h_radioinput(Panel *, int, int);
61 void h_submitinput(Panel *, int);
62 void h_buttoninput(Panel *, int);
63 void h_submittype(Panel *, char *);
64 void h_submitindex(Panel *, char *);
65 void h_resetinput(Panel *, int);
66 void h_select(Panel *, int, int);
67 char *selgen(Panel *, int);
68 char *nullgen(Panel *, int);
69 Field *newfield(Form *form){
71 f=emallocz(sizeof(Field), 1);
75 form->efields->next=f;
82 * Called by rdhtml on seeing a forms-related tag
84 void rdform(Hglob *g){
91 fprint(2, "Bad tag <%s> in rdform (Can't happen!)\n", g->token);
95 htmlerror(g->name, g->lineno, "nested forms illegal\n");
98 g->form=emallocz(sizeof(Form), 1);
99 s=pl_getattr(g->attr, "action");
100 g->form->action=strdup((s && s[0]) ? s : g->dst->url->fullname);
101 s=pl_getattr(g->attr, "method");
104 else if(cistrcmp(s, "post")==0)
105 g->form->method=POST;
107 if(cistrcmp(s, "get")!=0)
108 htmlerror(g->name, g->lineno,
109 "unknown form method %s\n", s);
114 g->form->next = g->dst->form;
115 g->dst->form = g->form;
122 htmlerror(g->name, g->lineno, "<%s> not in form, ignored\n",
127 s=pl_getattr(g->attr, "name");
132 s=pl_getattr(g->attr, "value");
137 f->checked=pl_hasattr(g->attr, "checked");
138 s=pl_getattr(g->attr, "size");
143 s=pl_getattr(g->attr, "maxlength");
145 f->maxlength=0x3fffffff;
147 f->maxlength=atoi(s);
148 s=pl_getattr(g->attr, "type");
149 if((g->tag == Tag_button) &&
150 (s==0 || cistrcmp(s, "reset") || cistrcmp(s, "button")))
154 if(cistrcmp(s, "checkbox")==0)
156 else if(cistrcmp(s, "radio")==0)
158 else if(cistrcmp(s, "submit")==0)
160 else if(cistrcmp(s, "button")==0)
162 else if(cistrcmp(s, "image")==0){
163 /* presotto's egregious hack to make image submits do something */
169 } else if(cistrcmp(s, "reset")==0)
171 else if(cistrcmp(s, "hidden")==0)
175 if(cistrcmp(s, "password")==0)
179 if(s && cistrcmp(s, "isindex")==0)
183 * If there's exactly one attribute, use its value as the name,
184 * regardless of the attribute name. This makes
185 * http://linus.att.com/ias/puborder.html work.
188 if(g->attr[0].name && g->attr[1].name==0)
189 f->name=strdup(g->attr[0].value);
191 f->name=strdup("no-name");
194 if((f->type==CHECK || f->type==RADIO) && !pl_hasattr(g->attr, "value")){
196 f->value=strdup("on");
199 pl_htmloutput(g, g->nsp, f->value[0]?f->value:"blank field", f);
202 if(g->form==0) goto BadTag;
204 s=pl_getattr(g->attr, "name");
206 f->name=strdup("select");
207 htmlerror(g->name, g->lineno, "select has no name=\n");
211 s=pl_getattr(g->attr, "size");
215 if(f->size<=0) f->size=1;
217 f->multiple=pl_hasattr(g->attr, "multiple");
225 if(g->form==0) goto BadTag;
226 if((f=g->form->efields)==0) goto BadTag;
227 o=emallocz(sizeof(Option), 1);
228 for(op=&f->options;*op;op=&(*op)->next);
233 g->etext=o->label+NLABEL;
234 memset(o->label, 0, NLABEL+1);
236 o->def=pl_hasattr(g->attr, "selected");
238 s=pl_getattr(g->attr, "value");
245 if(g->form==0) goto BadTag;
247 s=pl_getattr(g->attr, "name");
249 f->name=strdup("enter text");
250 htmlerror(g->name, g->lineno, "select has no name=\n");
254 s=pl_getattr(g->attr, "rows");
256 s=pl_getattr(g->attr, "cols");
257 f->cols=s?atoi(s):30;
259 /* suck up initial text */
260 pl_htmloutput(g, g->nsp, f->name, f);
264 * Make up a form with one tag, of type INDEX
265 * I have seen a page with <ISINDEX PROMPT="Enter a title here ">,
266 * which is nonstandard and not handled here.
268 form=emalloc(sizeof(Form));
271 s=pl_getattr(g->attr, "action");
272 form->action=strdup((s && s[0]) ? s : g->dst->url->fullname);
279 f->maxlength=0x3fffffff;
281 pl_htmloutput(g, g->nsp, f->value[0]?f->value:"blank field", f);
286 * Called by rdhtml on seeing a forms-related end tag
288 void endform(Hglob *g){
297 htmlerror(g->name, g->lineno, "</select> not in form, ignored\n");
298 else if((f=g->form->efields)==0)
299 htmlerror(g->name, g->lineno, "spurious </select>\n");
301 pl_htmloutput(g, g->nsp, f->name, f);
307 char *nullgen(Panel *, int ){
310 char *selgen(Panel *p, int index){
315 for(a=f->options;index!=0 && a!=0;--index,a=a->next);
317 a->label[0]=a->selected?'*':' ';
320 char *seloption(Field *f){
322 for(a=f->options;a!=0;a=a->next)
327 void mkfieldpanel(Rtext *t){
329 Panel *win, *scrl, *menu, *pop, *button;
332 if((a = t->user) == nil)
334 if((f = a->field) == nil)
340 f->p=plentry(0, 0, f->size*chrwidth, f->value, h_submittype);
343 f->p=plentry(0, USERFL, f->size*chrwidth, f->value, h_submittype);
346 f->p=plcheckbutton(0, 0, "", h_checkinput);
348 plsetbutton(f->p, f->checked);
351 f->p=plradiobutton(0, 0, "", h_radioinput);
353 plsetbutton(f->p, f->checked);
356 f->p=plbutton(0, 0, f->value[0]?f->value:"submit", h_submitinput);
359 f->p=plbutton(0, 0, f->value[0]?f->value:"reset", h_resetinput);
362 f->p=plbutton(0, 0, f->value[0]?f->value:"button", h_buttoninput);
365 f->pulldown=plgroup(0,0);
366 scrl=plscrollbar(f->pulldown, PACKW|FILLY);
367 win=pllist(f->pulldown, PACKN, nullgen, f->size, h_select);
369 plinitlist(win, PACKN, selgen, f->size, h_select);
370 plscroll(win, 0, scrl);
371 plpack(f->pulldown, Rect(0,0,1024,1024));
372 f->p=plpulldown(0, FIXEDX, seloption(f), f->pulldown, PACKS);
373 f->p->fixedsize.x=f->pulldown->r.max.x-f->pulldown->r.min.x;
377 pllabel(f->p, PACKN|FILLX, f->name);
378 scrl=plscrollbar(f->p, PACKW|FILLY);
379 f->textwin=pledit(f->p, EXPAND, Pt(f->cols*chrwidth, f->rows*font->height),
382 plscroll(f->textwin, 0, scrl);
385 f->p=plentry(0, 0, f->size*chrwidth, f->value, h_submitindex);
396 void h_checkinput(Panel *p, int, int v){
397 ((Field *)p->userp)->state=v;
399 void h_radioinput(Panel *p, int, int v){
404 for(f=me->form->fields;f;f=f->next)
405 if(f->type==RADIO && f!=me && strcmp(f->name, me->name)==0){
406 plsetbutton(f->p, 0);
408 pldraw(f->p, screen);
412 void h_select(Panel *p, int, int index){
417 if(!f->multiple) for(a=f->options;a;a=a->next) a->selected=0;
418 for(a=f->options;index!=0 && a!=0;--index,a=a->next);
420 a->selected=!a->selected;
421 plinitpulldown(f->p, FIXEDX, seloption(f), f->pulldown, PACKS);
422 pldraw(f->p, screen);
424 void h_resetinput(Panel *p, int){
427 for(f=((Field *)p->userp)->form->fields;f;f=f->next) switch(f->type){
429 plinitentry(f->p, 0, f->size*chrwidth, f->value, 0);
432 plinitentry(f->p, USERFL, f->size*chrwidth, f->value, 0);
437 plsetbutton(f->p, f->checked);
440 for(o=f->options;o;o=o->next)
444 pldraw(text, screen);
446 void h_buttoninput(Panel *p, int){
450 * If there's exactly one button with type=text, then
451 * a CR in the button is supposed to submit the form.
453 void h_submittype(Panel *p, char *){
457 for(f=((Field *)p->userp)->form->fields;f;f=f->next)
458 if(f->type==TYPEIN || f->type==PASSWD)
460 if(ntype==1) h_submitinput(p, 0);
462 void h_submitindex(Panel *p, char *){
467 uencodeform(Form *form, int fd){
475 for(f=form->fields;f;f=f->next) switch(f->type){
478 fprint(fd, "%s%U=%U", sep, f->name, plentryval(f->p));
482 fprint(fd, "%s%U", sep, plentryval(f->p));
489 if(f->name==0 || f->value==0)
491 fprint(fd, "%s%U=%U", sep, f->name, f->value);
497 for(o=f->options;o;o=o->next)
498 if(o->selected && o->value){
499 fprint(fd, "%s%U=%U", sep, f->name, o->value);
506 n=plelen(f->textwin);
507 rp=pleget(f->textwin);
508 p=b=malloc(UTFmax*n+1);
512 p += runetochar(p, rp);
517 fprint(fd, "%s%U=%U", sep, f->name, b);
524 void h_submitinput(Panel *p, int){
529 form=((Field *)p->userp)->form;
530 if(form->method==GET){
531 strcpy(buf, "/tmp/mfXXXXXXXXXXX");
532 fd = create(mktemp(buf), ORDWR|ORCLOSE, 0600);
534 fprint(fd, "%s?", form->action);
536 fd = urlpost(selurl(form->action), nil);
538 message("submit form: %r");
542 uencodeform(form, fd);
544 if(form->method==GET){
546 n = readn(fd, buf, sizeof(buf));
548 if(n < 0 || n >= sizeof(buf)){
549 message("submit form: post data too large");
553 if(debug)fprint(2, "GET %s\n", buf);
554 geturl(buf, -1, 0, 0);
557 if(debug)fprint(2, "POST %s\n", form->action);
558 geturl(form->action, fd, 0, 0);
562 void freeform(void *p)
571 while(f = form->fields){
572 form->fields = f->next;
580 while(o = f->options){
581 f->options = o->next;
582 if(o->value != o->label+1)
595 char *s = va_arg(f->args, char*);
597 if(strchr("/$-_@.!*'(),", *s)
598 || 'a'<=*s && *s<='z'
599 || 'A'<=*s && *s<='Z'
600 || '0'<=*s && *s<='9')
601 fmtprint(f, "%c", *s);
605 fmtprint(f, "%%%.2X", (unsigned int)*s);