form.c (24701B)
1 /* $Id$ */ 2 /* 3 * HTML forms 4 */ 5 #include "fm.h" 6 #include "parsetag.h" 7 #include "parsetagx.h" 8 #include "myctype.h" 9 #include "local.h" 10 #include "regex.h" 11 12 extern Str *textarea_str; 13 #ifdef MENU_SELECT 14 extern FormSelectOption *select_option; 15 #include "menu.h" 16 #endif /* MENU_SELECT */ 17 18 /* *INDENT-OFF* */ 19 struct { 20 char *action; 21 void (*rout)(struct parsed_tagarg *); 22 } internal_action[] = { 23 {"map", follow_map}, 24 {"option", panel_set_option}, 25 #ifdef USE_COOKIE 26 {"cookie", set_cookie_flag}, 27 #endif /* USE_COOKIE */ 28 {"download", download_action}, 29 #ifdef USE_M17N 30 { "charset", change_charset }, 31 #endif 32 {"none", NULL}, 33 {NULL, NULL}, 34 }; 35 /* *INDENT-ON* */ 36 37 struct form_list * 38 newFormList(char *action, char *method, char *charset, char *enctype, 39 char *target, char *name, struct form_list *_next) 40 { 41 struct form_list *l; 42 Str a = Strnew_charp(action); 43 int m = FORM_METHOD_GET; 44 int e = FORM_ENCTYPE_URLENCODED; 45 #ifdef USE_M17N 46 wc_ces c = 0; 47 #endif 48 49 if (method == NULL || !strcasecmp(method, "get")) 50 m = FORM_METHOD_GET; 51 else if (!strcasecmp(method, "post")) 52 m = FORM_METHOD_POST; 53 else if (!strcasecmp(method, "internal")) 54 m = FORM_METHOD_INTERNAL; 55 /* unknown method is regarded as 'get' */ 56 57 if (enctype != NULL && !strcasecmp(enctype, "multipart/form-data")) { 58 e = FORM_ENCTYPE_MULTIPART; 59 if (m == FORM_METHOD_GET) 60 m = FORM_METHOD_POST; 61 } 62 63 #ifdef USE_M17N 64 if (charset != NULL) 65 c = wc_guess_charset(charset, 0); 66 #endif 67 68 l = New(struct form_list); 69 l->item = l->lastitem = NULL; 70 l->action = a; 71 l->method = m; 72 #ifdef USE_M17N 73 l->charset = c; 74 #endif 75 l->enctype = e; 76 l->target = target; 77 l->name = name; 78 l->next = _next; 79 l->nitems = 0; 80 l->body = NULL; 81 l->length = 0; 82 return l; 83 } 84 85 /* 86 * add <input> element to form_list 87 */ 88 struct form_item_list * 89 formList_addInput(struct form_list *fl, struct parsed_tag *tag) 90 { 91 struct form_item_list *item; 92 char *p; 93 int i; 94 95 /* if not in <form>..</form> environment, just ignore <input> tag */ 96 if (fl == NULL) 97 return NULL; 98 99 item = New(struct form_item_list); 100 item->type = FORM_UNKNOWN; 101 item->size = -1; 102 item->rows = 0; 103 item->checked = item->init_checked = 0; 104 item->accept = 0; 105 item->name = NULL; 106 item->value = item->init_value = NULL; 107 item->readonly = 0; 108 if (parsedtag_get_value(tag, ATTR_TYPE, &p)) { 109 item->type = formtype(p); 110 if (item->size < 0 && 111 (item->type == FORM_INPUT_TEXT || 112 item->type == FORM_INPUT_FILE || 113 item->type == FORM_INPUT_PASSWORD)) 114 item->size = FORM_I_TEXT_DEFAULT_SIZE; 115 } 116 if (parsedtag_get_value(tag, ATTR_NAME, &p)) 117 item->name = Strnew_charp(p); 118 if (parsedtag_get_value(tag, ATTR_VALUE, &p)) 119 item->value = item->init_value = Strnew_charp(p); 120 item->checked = item->init_checked = parsedtag_exists(tag, ATTR_CHECKED); 121 item->accept = parsedtag_exists(tag, ATTR_ACCEPT); 122 parsedtag_get_value(tag, ATTR_SIZE, &item->size); 123 parsedtag_get_value(tag, ATTR_MAXLENGTH, &item->maxlength); 124 item->readonly = parsedtag_exists(tag, ATTR_READONLY); 125 if (parsedtag_get_value(tag, ATTR_TEXTAREANUMBER, &i)) 126 item->value = item->init_value = textarea_str[i]; 127 #ifdef MENU_SELECT 128 if (parsedtag_get_value(tag, ATTR_SELECTNUMBER, &i)) 129 item->select_option = select_option[i].first; 130 #endif /* MENU_SELECT */ 131 if (parsedtag_get_value(tag, ATTR_ROWS, &p)) 132 item->rows = atoi(p); 133 if (item->type == FORM_UNKNOWN) { 134 /* type attribute is missing. Ignore the tag. */ 135 return NULL; 136 } 137 #ifdef MENU_SELECT 138 if (item->type == FORM_SELECT) { 139 chooseSelectOption(item, item->select_option); 140 item->init_selected = item->selected; 141 item->init_value = item->value; 142 item->init_label = item->label; 143 } 144 #endif /* MENU_SELECT */ 145 if (item->type == FORM_INPUT_FILE && item->value && item->value->length) { 146 /* security hole ! */ 147 return NULL; 148 } 149 item->parent = fl; 150 item->next = NULL; 151 if (fl->item == NULL) { 152 fl->item = fl->lastitem = item; 153 } 154 else { 155 fl->lastitem->next = item; 156 fl->lastitem = item; 157 } 158 if (item->type == FORM_INPUT_HIDDEN) 159 return NULL; 160 fl->nitems++; 161 return item; 162 } 163 164 static char *_formtypetbl[] = { 165 "text", "password", "checkbox", "radio", "submit", "reset", "hidden", 166 "image", "select", "textarea", "button", "file", NULL 167 }; 168 169 static char *_formmethodtbl[] = { 170 "GET", "POST", "INTERNAL", "HEAD" 171 }; 172 173 char * 174 form2str(FormItemList *fi) 175 { 176 Str tmp = Strnew(); 177 178 if (fi->type != FORM_SELECT && fi->type != FORM_TEXTAREA) 179 Strcat_charp(tmp, "input type="); 180 Strcat_charp(tmp, _formtypetbl[fi->type]); 181 if (fi->name && fi->name->length) 182 Strcat_m_charp(tmp, " name=\"", fi->name->ptr, "\"", NULL); 183 if ((fi->type == FORM_INPUT_RADIO || fi->type == FORM_INPUT_CHECKBOX || 184 fi->type == FORM_SELECT) && fi->value) 185 Strcat_m_charp(tmp, " value=\"", fi->value->ptr, "\"", NULL); 186 Strcat_m_charp(tmp, " (", _formmethodtbl[fi->parent->method], " ", 187 fi->parent->action->ptr, ")", NULL); 188 return tmp->ptr; 189 } 190 191 int 192 formtype(char *typestr) 193 { 194 int i; 195 for (i = 0; _formtypetbl[i]; i++) { 196 if (!strcasecmp(typestr, _formtypetbl[i])) 197 return i; 198 } 199 return FORM_UNKNOWN; 200 } 201 202 void 203 formRecheckRadio(Anchor *a, Buffer *buf, FormItemList *fi) 204 { 205 int i; 206 Anchor *a2; 207 FormItemList *f2; 208 209 for (i = 0; i < buf->formitem->nanchor; i++) { 210 a2 = &buf->formitem->anchors[i]; 211 f2 = (FormItemList *)a2->url; 212 if (f2->parent == fi->parent && f2 != fi && 213 f2->type == FORM_INPUT_RADIO && Strcmp(f2->name, fi->name) == 0) { 214 f2->checked = 0; 215 formUpdateBuffer(a2, buf, f2); 216 } 217 } 218 fi->checked = 1; 219 formUpdateBuffer(a, buf, fi); 220 } 221 222 void 223 formResetBuffer(Buffer *buf, AnchorList *formitem) 224 { 225 int i; 226 Anchor *a; 227 FormItemList *f1, *f2; 228 229 if (buf == NULL || buf->formitem == NULL || formitem == NULL) 230 return; 231 for (i = 0; i < buf->formitem->nanchor && i < formitem->nanchor; i++) { 232 a = &buf->formitem->anchors[i]; 233 if (a->y != a->start.line) 234 continue; 235 f1 = (FormItemList *)a->url; 236 f2 = (FormItemList *)formitem->anchors[i].url; 237 if (f1->type != f2->type || 238 strcmp(((f1->name == NULL) ? "" : f1->name->ptr), 239 ((f2->name == NULL) ? "" : f2->name->ptr))) 240 break; /* What's happening */ 241 switch (f1->type) { 242 case FORM_INPUT_TEXT: 243 case FORM_INPUT_PASSWORD: 244 case FORM_INPUT_FILE: 245 case FORM_TEXTAREA: 246 f1->value = f2->value; 247 f1->init_value = f2->init_value; 248 break; 249 case FORM_INPUT_CHECKBOX: 250 case FORM_INPUT_RADIO: 251 f1->checked = f2->checked; 252 f1->init_checked = f2->init_checked; 253 break; 254 case FORM_SELECT: 255 #ifdef MENU_SELECT 256 f1->select_option = f2->select_option; 257 f1->value = f2->value; 258 f1->label = f2->label; 259 f1->selected = f2->selected; 260 f1->init_value = f2->init_value; 261 f1->init_label = f2->init_label; 262 f1->init_selected = f2->init_selected; 263 #endif /* MENU_SELECT */ 264 break; 265 default: 266 continue; 267 } 268 formUpdateBuffer(a, buf, f1); 269 } 270 } 271 272 static int 273 form_update_line(Line *line, char **str, int spos, int epos, int width, 274 int newline, int password) 275 { 276 int c_len = 1, c_width = 1, w, i, len, pos; 277 char *p, *buf; 278 Lineprop c_type, effect, *prop; 279 280 for (p = *str, w = 0, pos = 0; *p && w < width;) { 281 c_type = get_mctype((unsigned char *)p); 282 #ifdef USE_M17N 283 c_len = get_mclen(p); 284 c_width = get_mcwidth(p); 285 #endif 286 if (c_type == PC_CTRL) { 287 if (newline && *p == '\n') 288 break; 289 if (*p != '\r') { 290 w++; 291 pos++; 292 } 293 } 294 else if (password) { 295 #ifdef USE_M17N 296 if (w + c_width > width) 297 break; 298 #endif 299 w += c_width; 300 pos += c_width; 301 #ifdef USE_M17N 302 } 303 else if (c_type & PC_UNKNOWN) { 304 w++; 305 pos++; 306 } 307 else { 308 if (w + c_width > width) 309 break; 310 #endif 311 w += c_width; 312 pos += c_len; 313 } 314 p += c_len; 315 } 316 pos += width - w; 317 318 len = line->len + pos + spos - epos; 319 buf = New_N(char, len); 320 prop = New_N(Lineprop, len); 321 bcopy((void *)line->lineBuf, (void *)buf, spos * sizeof(char)); 322 bcopy((void *)line->propBuf, (void *)prop, spos * sizeof(Lineprop)); 323 324 effect = CharEffect(line->propBuf[spos]); 325 for (p = *str, w = 0, pos = spos; *p && w < width;) { 326 c_type = get_mctype((unsigned char *)p); 327 #ifdef USE_M17N 328 c_len = get_mclen(p); 329 c_width = get_mcwidth(p); 330 #endif 331 if (c_type == PC_CTRL) { 332 if (newline && *p == '\n') 333 break; 334 if (*p != '\r') { 335 buf[pos] = password ? '*' : ' '; 336 prop[pos] = effect | PC_ASCII; 337 pos++; 338 w++; 339 } 340 } 341 else if (password) { 342 #ifdef USE_M17N 343 if (w + c_width > width) 344 break; 345 #endif 346 for (i = 0; i < c_width; i++) { 347 buf[pos] = '*'; 348 prop[pos] = effect | PC_ASCII; 349 pos++; 350 w++; 351 } 352 #ifdef USE_M17N 353 } 354 else if (c_type & PC_UNKNOWN) { 355 buf[pos] = ' '; 356 prop[pos] = effect | PC_ASCII; 357 pos++; 358 w++; 359 } 360 else { 361 if (w + c_width > width) 362 break; 363 #else 364 } 365 else { 366 #endif 367 buf[pos] = *p; 368 prop[pos] = effect | c_type; 369 pos++; 370 #ifdef USE_M17N 371 c_type = (c_type & ~PC_WCHAR1) | PC_WCHAR2; 372 for (i = 1; i < c_len; i++) { 373 buf[pos] = p[i]; 374 prop[pos] = effect | c_type; 375 pos++; 376 } 377 #endif 378 w += c_width; 379 } 380 p += c_len; 381 } 382 for (; w < width; w++) { 383 buf[pos] = ' '; 384 prop[pos] = effect | PC_ASCII; 385 pos++; 386 } 387 if (newline) { 388 if (!FoldTextarea) { 389 while (*p && *p != '\r' && *p != '\n') 390 p++; 391 } 392 if (*p == '\r') 393 p++; 394 if (*p == '\n') 395 p++; 396 } 397 *str = p; 398 399 bcopy((void *)&line->lineBuf[epos], (void *)&buf[pos], 400 (line->len - epos) * sizeof(char)); 401 bcopy((void *)&line->propBuf[epos], (void *)&prop[pos], 402 (line->len - epos) * sizeof(Lineprop)); 403 line->lineBuf = buf; 404 line->propBuf = prop; 405 line->len = len; 406 line->size = len; 407 408 return pos; 409 } 410 411 void 412 formUpdateBuffer(Anchor *a, Buffer *buf, FormItemList *form) 413 { 414 Buffer save; 415 char *p; 416 int spos, epos, rows, c_rows, pos, col = 0; 417 Line *l; 418 419 copyBuffer(&save, buf); 420 gotoLine(buf, a->start.line); 421 switch (form->type) { 422 case FORM_TEXTAREA: 423 case FORM_INPUT_TEXT: 424 case FORM_INPUT_FILE: 425 case FORM_INPUT_PASSWORD: 426 case FORM_INPUT_CHECKBOX: 427 case FORM_INPUT_RADIO: 428 #ifdef MENU_SELECT 429 case FORM_SELECT: 430 #endif /* MENU_SELECT */ 431 spos = a->start.pos; 432 epos = a->end.pos; 433 break; 434 default: 435 spos = a->start.pos + 1; 436 epos = a->end.pos - 1; 437 } 438 switch (form->type) { 439 case FORM_INPUT_CHECKBOX: 440 case FORM_INPUT_RADIO: 441 if (form->checked) 442 buf->currentLine->lineBuf[spos] = '*'; 443 else 444 buf->currentLine->lineBuf[spos] = ' '; 445 break; 446 case FORM_INPUT_TEXT: 447 case FORM_INPUT_FILE: 448 case FORM_INPUT_PASSWORD: 449 case FORM_TEXTAREA: 450 #ifdef MENU_SELECT 451 case FORM_SELECT: 452 if (form->type == FORM_SELECT) { 453 p = form->label->ptr; 454 updateSelectOption(form, form->select_option); 455 } 456 else 457 #endif /* MENU_SELECT */ 458 p = form->value->ptr; 459 l = buf->currentLine; 460 if (form->type == FORM_TEXTAREA) { 461 int n = a->y - buf->currentLine->linenumber; 462 if (n > 0) 463 for (; l && n; l = l->prev, n--) ; 464 else if (n < 0) 465 for (; l && n; l = l->prev, n++) ; 466 if (!l) 467 break; 468 } 469 rows = form->rows ? form->rows : 1; 470 col = COLPOS(l, a->start.pos); 471 for (c_rows = 0; c_rows < rows; c_rows++, l = l->next) { 472 if (rows > 1) { 473 pos = columnPos(l, col); 474 a = retrieveAnchor(buf->formitem, l->linenumber, pos); 475 if (a == NULL) 476 break; 477 spos = a->start.pos; 478 epos = a->end.pos; 479 } 480 pos = form_update_line(l, &p, spos, epos, COLPOS(l, epos) - col, 481 rows > 1, 482 form->type == FORM_INPUT_PASSWORD); 483 if (pos != epos) { 484 shiftAnchorPosition(buf->href, buf->hmarklist, 485 a->start.line, spos, pos - epos); 486 shiftAnchorPosition(buf->name, buf->hmarklist, 487 a->start.line, spos, pos - epos); 488 shiftAnchorPosition(buf->img, buf->hmarklist, 489 a->start.line, spos, pos - epos); 490 shiftAnchorPosition(buf->formitem, buf->hmarklist, 491 a->start.line, spos, pos - epos); 492 } 493 } 494 break; 495 } 496 copyBuffer(buf, &save); 497 arrangeLine(buf); 498 } 499 500 501 Str 502 textfieldrep(Str s, int width) 503 { 504 Lineprop c_type; 505 Str n = Strnew_size(width + 2); 506 int i, j, k, c_len; 507 508 j = 0; 509 for (i = 0; i < s->length; i += c_len) { 510 c_type = get_mctype((unsigned char *)&s->ptr[i]); 511 c_len = get_mclen(&s->ptr[i]); 512 if (s->ptr[i] == '\r') 513 continue; 514 k = j + get_mcwidth(&s->ptr[i]); 515 if (k > width) 516 break; 517 if (c_type == PC_CTRL) 518 Strcat_char(n, ' '); 519 #ifdef USE_M17N 520 else if (c_type & PC_UNKNOWN) 521 Strcat_char(n, ' '); 522 #endif 523 else if (s->ptr[i] == '&') 524 Strcat_charp(n, "&"); 525 else if (s->ptr[i] == '<') 526 Strcat_charp(n, "<"); 527 else if (s->ptr[i] == '>') 528 Strcat_charp(n, ">"); 529 else 530 Strcat_charp_n(n, &s->ptr[i], c_len); 531 j = k; 532 } 533 for (; j < width; j++) 534 Strcat_char(n, ' '); 535 return n; 536 } 537 538 static void 539 form_fputs_decode(Str s, FILE * f) 540 { 541 char *p; 542 Str z = Strnew(); 543 544 for (p = s->ptr; *p;) { 545 switch (*p) { 546 #if !defined( __CYGWIN__ ) && !defined( __EMX__ ) 547 case '\r': 548 if (*(p + 1) == '\n') 549 p++; 550 /* continue to the next label */ 551 #endif /* !defined( __CYGWIN__ ) && !defined( __EMX__ 552 * ) */ 553 default: 554 Strcat_char(z, *p); 555 p++; 556 break; 557 } 558 } 559 #ifdef USE_M17N 560 z = wc_Str_conv_strict(z, InnerCharset, DisplayCharset); 561 #endif 562 Strfputs(z, f); 563 } 564 565 566 void 567 input_textarea(FormItemList *fi) 568 { 569 char *tmpf = tmpfname(TMPF_DFL, NULL)->ptr; 570 Str tmp; 571 FILE *f; 572 #ifdef USE_M17N 573 wc_ces charset = DisplayCharset; 574 wc_uint8 auto_detect; 575 #endif 576 577 f = fopen(tmpf, "w"); 578 if (f == NULL) { 579 /* FIXME: gettextize? */ 580 disp_err_message("Can't open temporary file", FALSE); 581 return; 582 } 583 if (fi->value) 584 form_fputs_decode(fi->value, f); 585 fclose(f); 586 587 fmTerm(); 588 system(myEditor(Editor, tmpf, 1)->ptr); 589 fmInit(); 590 591 if (fi->readonly) 592 goto input_end; 593 f = fopen(tmpf, "r"); 594 if (f == NULL) { 595 /* FIXME: gettextize? */ 596 disp_err_message("Can't open temporary file", FALSE); 597 goto input_end; 598 } 599 fi->value = Strnew(); 600 #ifdef USE_M17N 601 auto_detect = WcOption.auto_detect; 602 WcOption.auto_detect = WC_OPT_DETECT_ON; 603 #endif 604 while (tmp = Strfgets(f), tmp->length > 0) { 605 if (tmp->length == 1 && tmp->ptr[tmp->length - 1] == '\n') { 606 /* null line with bare LF */ 607 tmp = Strnew_charp("\r\n"); 608 } 609 else if (tmp->length > 1 && tmp->ptr[tmp->length - 1] == '\n' && 610 tmp->ptr[tmp->length - 2] != '\r') { 611 Strshrink(tmp, 1); 612 Strcat_charp(tmp, "\r\n"); 613 } 614 tmp = convertLine(NULL, tmp, RAW_MODE, &charset, DisplayCharset); 615 Strcat(fi->value, tmp); 616 } 617 #ifdef USE_M17N 618 WcOption.auto_detect = auto_detect; 619 #endif 620 fclose(f); 621 input_end: 622 unlink(tmpf); 623 } 624 625 void 626 do_internal(char *action, char *data) 627 { 628 int i; 629 630 for (i = 0; internal_action[i].action; i++) { 631 if (strcasecmp(internal_action[i].action, action) == 0) { 632 if (internal_action[i].rout) 633 internal_action[i].rout(cgistr2tagarg(data)); 634 return; 635 } 636 } 637 } 638 639 #ifdef MENU_SELECT 640 void 641 addSelectOption(FormSelectOption *fso, Str value, Str label, int chk) 642 { 643 FormSelectOptionItem *o; 644 o = New(FormSelectOptionItem); 645 if (value == NULL) 646 value = label; 647 o->value = value; 648 Strremovefirstspaces(label); 649 Strremovetrailingspaces(label); 650 o->label = label; 651 o->checked = chk; 652 o->next = NULL; 653 if (fso->first == NULL) 654 fso->first = fso->last = o; 655 else { 656 fso->last->next = o; 657 fso->last = o; 658 } 659 } 660 661 void 662 chooseSelectOption(FormItemList *fi, FormSelectOptionItem *item) 663 { 664 FormSelectOptionItem *opt; 665 int i; 666 667 fi->selected = 0; 668 if (item == NULL) { 669 fi->value = Strnew_size(0); 670 fi->label = Strnew_size(0); 671 return; 672 } 673 fi->value = item->value; 674 fi->label = item->label; 675 for (i = 0, opt = item; opt != NULL; i++, opt = opt->next) { 676 if (opt->checked) { 677 fi->value = opt->value; 678 fi->label = opt->label; 679 fi->selected = i; 680 break; 681 } 682 } 683 updateSelectOption(fi, item); 684 } 685 686 void 687 updateSelectOption(FormItemList *fi, FormSelectOptionItem *item) 688 { 689 int i; 690 691 if (fi == NULL || item == NULL) 692 return; 693 for (i = 0; item != NULL; i++, item = item->next) { 694 if (i == fi->selected) 695 item->checked = TRUE; 696 else 697 item->checked = FALSE; 698 } 699 } 700 701 int 702 formChooseOptionByMenu(struct form_item_list *fi, int x, int y) 703 { 704 int i, n, selected = -1, init_select = fi->selected; 705 FormSelectOptionItem *opt; 706 char **label; 707 708 for (n = 0, opt = fi->select_option; opt != NULL; n++, opt = opt->next) ; 709 label = New_N(char *, n + 1); 710 for (i = 0, opt = fi->select_option; opt != NULL; i++, opt = opt->next) 711 label[i] = opt->label->ptr; 712 label[n] = NULL; 713 714 optionMenu(x, y, label, &selected, init_select, NULL); 715 716 if (selected < 0) 717 return 0; 718 for (i = 0, opt = fi->select_option; opt != NULL; i++, opt = opt->next) { 719 if (i == selected) { 720 fi->selected = selected; 721 fi->value = opt->value; 722 fi->label = opt->label; 723 break; 724 } 725 } 726 updateSelectOption(fi, fi->select_option); 727 return 1; 728 } 729 #endif /* MENU_SELECT */ 730 731 void 732 form_write_data(FILE * f, char *boundary, char *name, char *value) 733 { 734 fprintf(f, "--%s\r\n", boundary); 735 fprintf(f, "Content-Disposition: form-data; name=\"%s\"\r\n\r\n", name); 736 fprintf(f, "%s\r\n", value); 737 } 738 739 void 740 form_write_from_file(FILE * f, char *boundary, char *name, char *filename, 741 char *file) 742 { 743 FILE *fd; 744 struct stat st; 745 int c; 746 char *type; 747 748 fprintf(f, "--%s\r\n", boundary); 749 fprintf(f, 750 "Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n", 751 name, mybasename(filename)); 752 type = guessContentType(file); 753 fprintf(f, "Content-Type: %s\r\n\r\n", 754 type ? type : "application/octet-stream"); 755 756 if (lstat(file, &st) < 0) 757 goto write_end; 758 if (S_ISDIR(st.st_mode)) 759 goto write_end; 760 fd = fopen(file, "r"); 761 if (fd != NULL) { 762 while ((c = fgetc(fd)) != EOF) 763 fputc(c, f); 764 fclose(fd); 765 } 766 write_end: 767 fprintf(f, "\r\n"); 768 } 769 770 struct pre_form_item { 771 int type; 772 char *name; 773 char *value; 774 int checked; 775 struct pre_form_item *next; 776 }; 777 778 struct pre_form { 779 char *url; 780 Regex *re_url; 781 char *name; 782 char *action; 783 struct pre_form_item *item; 784 struct pre_form *next; 785 }; 786 787 static struct pre_form *PreForm = NULL; 788 789 static struct pre_form * 790 add_pre_form(struct pre_form *prev, char *url, char *name, char *action) 791 { 792 ParsedURL pu; 793 struct pre_form *new; 794 795 if (prev) 796 new = prev->next = New(struct pre_form); 797 else 798 new = PreForm = New(struct pre_form); 799 if (url && *url == '/') { 800 int l = strlen(url); 801 if (l > 1 && url[l - 1] == '/') 802 new->url = allocStr(url + 1, l - 2); 803 else 804 new->url = url + 1; 805 new->re_url = newRegex(new->url, FALSE, NULL, NULL); 806 if (!new->re_url) 807 new->url = NULL; 808 } 809 else if (url) { 810 parseURL2(url, &pu, NULL); 811 new->url = parsedURL2Str(&pu)->ptr; 812 new->re_url = NULL; 813 } 814 new->name = (name && *name) ? name : NULL; 815 new->action = (action && *action) ? action : NULL; 816 new->item = NULL; 817 new->next = NULL; 818 return new; 819 } 820 821 static struct pre_form_item * 822 add_pre_form_item(struct pre_form *pf, struct pre_form_item *prev, int type, 823 char *name, char *value, char *checked) 824 { 825 struct pre_form_item *new; 826 827 if (!pf) 828 return NULL; 829 if (prev) 830 new = prev->next = New(struct pre_form_item); 831 else 832 new = pf->item = New(struct pre_form_item); 833 new->type = type; 834 new->name = name; 835 new->value = value; 836 if (checked && *checked && (!strcmp(checked, "0") || 837 strcasecmp(checked, "off") 838 || !strcasecmp(checked, "no"))) 839 new->checked = 0; 840 else 841 new->checked = 1; 842 new->next = NULL; 843 return new; 844 } 845 846 /* 847 * url <url>|/<re-url>/ 848 * form [<name>] <action> 849 * text <name> <value> 850 * file <name> <value> 851 * passwd <name> <value> 852 * checkbox <name> <value> [<checked>] 853 * radio <name> <value> 854 * select <name> <value> 855 * submit [<name> [<value>]] 856 * image [<name> [<value>]] 857 * textarea <name> 858 * <value> 859 * /textarea 860 */ 861 862 void 863 loadPreForm(void) 864 { 865 FILE *fp; 866 Str line = NULL, textarea = NULL; 867 struct pre_form *pf = NULL; 868 struct pre_form_item *pi = NULL; 869 int type = -1; 870 char *name = NULL; 871 872 PreForm = NULL; 873 fp = openSecretFile(pre_form_file); 874 if (fp == NULL) 875 return; 876 while (1) { 877 char *p, *s, *arg; 878 879 line = Strfgets(fp); 880 if (line->length == 0) 881 break; 882 if (textarea && !(!strncmp(line->ptr, "/textarea", 9) && 883 IS_SPACE(line->ptr[9]))) { 884 Strcat(textarea, line); 885 continue; 886 } 887 Strchop(line); 888 Strremovefirstspaces(line); 889 p = line->ptr; 890 if (*p == '#' || *p == '\0') 891 continue; /* comment or empty line */ 892 s = getWord(&p); 893 arg = getWord(&p); 894 895 if (!strcmp(s, "url")) { 896 if (!arg || !*arg) 897 continue; 898 p = getQWord(&p); 899 pf = add_pre_form(pf, arg, NULL, p); 900 pi = pf->item; 901 continue; 902 } 903 if (!pf) 904 continue; 905 if (!strcmp(s, "form")) { 906 if (!arg || !*arg) 907 continue; 908 s = getQWord(&p); 909 p = getQWord(&p); 910 if (!p || !*p) { 911 p = s; 912 s = NULL; 913 } 914 if (pf->item) { 915 struct pre_form *prev = pf; 916 pf = add_pre_form(prev, "", s, p); 917 /* copy previous URL */ 918 pf->url = prev->url; 919 pf->re_url = prev->re_url; 920 } 921 else { 922 pf->name = s; 923 pf->action = (p && *p) ? p : NULL; 924 } 925 pi = pf->item; 926 continue; 927 } 928 if (!strcmp(s, "text")) 929 type = FORM_INPUT_TEXT; 930 else if (!strcmp(s, "file")) 931 type = FORM_INPUT_FILE; 932 else if (!strcmp(s, "passwd") || !strcmp(s, "password")) 933 type = FORM_INPUT_PASSWORD; 934 else if (!strcmp(s, "checkbox")) 935 type = FORM_INPUT_CHECKBOX; 936 else if (!strcmp(s, "radio")) 937 type = FORM_INPUT_RADIO; 938 else if (!strcmp(s, "submit")) 939 type = FORM_INPUT_SUBMIT; 940 else if (!strcmp(s, "image")) 941 type = FORM_INPUT_IMAGE; 942 else if (!strcmp(s, "select")) 943 type = FORM_SELECT; 944 else if (!strcmp(s, "textarea")) { 945 type = FORM_TEXTAREA; 946 name = Strnew_charp(arg)->ptr; 947 textarea = Strnew(); 948 continue; 949 } 950 else if (textarea && name && !strcmp(s, "/textarea")) { 951 pi = add_pre_form_item(pf, pi, type, name, textarea->ptr, NULL); 952 textarea = NULL; 953 name = NULL; 954 continue; 955 } 956 else 957 continue; 958 s = getQWord(&p); 959 pi = add_pre_form_item(pf, pi, type, arg, s, getQWord(&p)); 960 } 961 fclose(fp); 962 } 963 964 void 965 preFormUpdateBuffer(Buffer *buf) 966 { 967 struct pre_form *pf; 968 struct pre_form_item *pi; 969 int i; 970 Anchor *a; 971 FormList *fl; 972 FormItemList *fi; 973 #ifdef MENU_SELECT 974 FormSelectOptionItem *opt; 975 int j; 976 #endif 977 978 if (!buf || !buf->formitem || !PreForm) 979 return; 980 981 for (pf = PreForm; pf; pf = pf->next) { 982 if (pf->re_url) { 983 Str url = parsedURL2Str(&buf->currentURL); 984 if (!RegexMatch(pf->re_url, url->ptr, url->length, 1)) 985 continue; 986 } 987 else if (pf->url) { 988 if (Strcmp_charp(parsedURL2Str(&buf->currentURL), pf->url)) 989 continue; 990 } 991 else 992 continue; 993 for (i = 0; i < buf->formitem->nanchor; i++) { 994 a = &buf->formitem->anchors[i]; 995 fi = (FormItemList *)a->url; 996 fl = fi->parent; 997 if (pf->name && (!fl->name || strcmp(fl->name, pf->name))) 998 continue; 999 if (pf->action 1000 && (!fl->action || Strcmp_charp(fl->action, pf->action))) 1001 continue; 1002 for (pi = pf->item; pi; pi = pi->next) { 1003 if (pi->type != fi->type) 1004 continue; 1005 if (pi->type == FORM_INPUT_SUBMIT || 1006 pi->type == FORM_INPUT_IMAGE) { 1007 if ((!pi->name || !*pi->name || 1008 (fi->name && !Strcmp_charp(fi->name, pi->name))) && 1009 (!pi->value || !*pi->value || 1010 (fi->value && !Strcmp_charp(fi->value, pi->value)))) 1011 buf->submit = a; 1012 continue; 1013 } 1014 if (!pi->name || !fi->name || Strcmp_charp(fi->name, pi->name)) 1015 continue; 1016 switch (pi->type) { 1017 case FORM_INPUT_TEXT: 1018 case FORM_INPUT_FILE: 1019 case FORM_INPUT_PASSWORD: 1020 case FORM_TEXTAREA: 1021 fi->value = Strnew_charp(pi->value); 1022 formUpdateBuffer(a, buf, fi); 1023 break; 1024 case FORM_INPUT_CHECKBOX: 1025 if (pi->value && fi->value && 1026 !Strcmp_charp(fi->value, pi->value)) { 1027 fi->checked = pi->checked; 1028 formUpdateBuffer(a, buf, fi); 1029 } 1030 break; 1031 case FORM_INPUT_RADIO: 1032 if (pi->value && fi->value && 1033 !Strcmp_charp(fi->value, pi->value)) 1034 formRecheckRadio(a, buf, fi); 1035 break; 1036 #ifdef MENU_SELECT 1037 case FORM_SELECT: 1038 for (j = 0, opt = fi->select_option; opt != NULL; 1039 j++, opt = opt->next) { 1040 if (pi->value && opt->value && 1041 !Strcmp_charp(opt->value, pi->value)) { 1042 fi->selected = j; 1043 fi->value = opt->value; 1044 fi->label = opt->label; 1045 updateSelectOption(fi, fi->select_option); 1046 formUpdateBuffer(a, buf, fi); 1047 break; 1048 } 1049 } 1050 break; 1051 #endif 1052 } 1053 } 1054 } 1055 } 1056 }