file.c (203866B)
1 /* $Id$ */ 2 #include "fm.h" 3 #include <sys/types.h> 4 #include "myctype.h" 5 #include <signal.h> 6 #include <setjmp.h> 7 #if defined(HAVE_WAITPID) || defined(HAVE_WAIT3) 8 #include <sys/wait.h> 9 #endif 10 #include <stdio.h> 11 #include <time.h> 12 #include <sys/stat.h> 13 #include <fcntl.h> 14 #include <utime.h> 15 /* foo */ 16 17 #include "html.h" 18 #include "parsetagx.h" 19 #include "local.h" 20 #include "regex.h" 21 22 #ifndef max 23 #define max(a,b) ((a) > (b) ? (a) : (b)) 24 #endif /* not max */ 25 #ifndef min 26 #define min(a,b) ((a) > (b) ? (b) : (a)) 27 #endif /* not min */ 28 29 static int frame_source = 0; 30 31 static char *guess_filename(char *file); 32 static int _MoveFile(char *path1, char *path2); 33 static void uncompress_stream(URLFile *uf, char **src); 34 static FILE *lessopen_stream(char *path); 35 static Buffer *loadcmdout(char *cmd, 36 Buffer *(*loadproc) (URLFile *, Buffer *), 37 Buffer *defaultbuf); 38 #ifndef USE_ANSI_COLOR 39 #define addnewline(a,b,c,d,e,f,g) _addnewline(a,b,c,e,f,g) 40 #endif 41 static void addnewline(Buffer *buf, char *line, Lineprop *prop, 42 Linecolor *color, int pos, int width, int nlines); 43 static void addLink(Buffer *buf, struct parsed_tag *tag); 44 45 static JMP_BUF AbortLoading; 46 47 static struct table *tables[MAX_TABLE]; 48 static struct table_mode table_mode[MAX_TABLE]; 49 50 #ifdef USE_IMAGE 51 static ParsedURL *cur_baseURL = NULL; 52 #ifdef USE_M17N 53 static char cur_document_charset; 54 #endif 55 #endif 56 57 static Str cur_title; 58 static Str cur_select; 59 static Str select_str; 60 static int select_is_multiple; 61 static int n_selectitem; 62 static Str cur_option; 63 static Str cur_option_value; 64 static Str cur_option_label; 65 static int cur_option_selected; 66 static int cur_status; 67 #ifdef MENU_SELECT 68 /* menu based <select> */ 69 FormSelectOption *select_option; 70 static int max_select = MAX_SELECT; 71 static int n_select; 72 static int cur_option_maxwidth; 73 #endif /* MENU_SELECT */ 74 75 static Str cur_textarea; 76 Str *textarea_str; 77 static int cur_textarea_size; 78 static int cur_textarea_rows; 79 static int cur_textarea_readonly; 80 static int n_textarea; 81 static int ignore_nl_textarea; 82 static int max_textarea = MAX_TEXTAREA; 83 84 static int http_response_code; 85 86 #ifdef USE_M17N 87 static wc_ces content_charset = 0; 88 static wc_ces meta_charset = 0; 89 static char *check_charset(char *p); 90 static char *check_accept_charset(char *p); 91 #endif 92 93 #define set_prevchar(x,y,n) Strcopy_charp_n((x),(y),(n)) 94 #define set_space_to_prevchar(x) Strcopy_charp_n((x)," ",1) 95 96 struct link_stack { 97 int cmd; 98 short offset; 99 short pos; 100 struct link_stack *next; 101 }; 102 103 static struct link_stack *link_stack = NULL; 104 105 #define FORMSTACK_SIZE 10 106 #define FRAMESTACK_SIZE 10 107 108 #ifdef USE_NNTP 109 #define Str_news_endline(s) ((s)->ptr[0]=='.'&&((s)->ptr[1]=='\n'||(s)->ptr[1]=='\r'||(s)->ptr[1]=='\0')) 110 #endif /* USE_NNTP */ 111 112 #define INITIAL_FORM_SIZE 10 113 static FormList **forms; 114 static int *form_stack; 115 static int form_max = -1; 116 static int forms_size = 0; 117 #define cur_form_id ((form_sp >= 0)? form_stack[form_sp] : -1) 118 static int form_sp = 0; 119 120 static clen_t current_content_length; 121 122 static int cur_hseq; 123 #ifdef USE_IMAGE 124 static int cur_iseq; 125 #endif 126 127 #define MAX_UL_LEVEL 9 128 #define UL_SYMBOL(x) (N_GRAPH_SYMBOL + (x)) 129 #define UL_SYMBOL_DISC UL_SYMBOL(9) 130 #define UL_SYMBOL_CIRCLE UL_SYMBOL(10) 131 #define UL_SYMBOL_SQUARE UL_SYMBOL(11) 132 #define IMG_SYMBOL UL_SYMBOL(12) 133 #define HR_SYMBOL 26 134 135 #ifdef USE_COOKIE 136 /* This array should be somewhere else */ 137 /* FIXME: gettextize? */ 138 char *violations[COO_EMAX] = { 139 "internal error", 140 "tail match failed", 141 "wrong number of dots", 142 "RFC 2109 4.3.2 rule 1", 143 "RFC 2109 4.3.2 rule 2.1", 144 "RFC 2109 4.3.2 rule 2.2", 145 "RFC 2109 4.3.2 rule 3", 146 "RFC 2109 4.3.2 rule 4", 147 "RFC XXXX 4.3.2 rule 5" 148 }; 149 #endif 150 151 /* *INDENT-OFF* */ 152 static struct compression_decoder { 153 int type; 154 char *ext; 155 char *mime_type; 156 int auxbin_p; 157 char *cmd; 158 char *name; 159 char *encoding; 160 char *encodings[4]; 161 } compression_decoders[] = { 162 { CMP_COMPRESS, ".gz", "application/x-gzip", 163 0, GUNZIP_CMDNAME, GUNZIP_NAME, "gzip", 164 {"gzip", "x-gzip", NULL} }, 165 { CMP_COMPRESS, ".Z", "application/x-compress", 166 0, GUNZIP_CMDNAME, GUNZIP_NAME, "compress", 167 {"compress", "x-compress", NULL} }, 168 { CMP_BZIP2, ".bz2", "application/x-bzip", 169 0, BUNZIP2_CMDNAME, BUNZIP2_NAME, "bzip, bzip2", 170 {"x-bzip", "bzip", "bzip2", NULL} }, 171 { CMP_DEFLATE, ".deflate", "application/x-deflate", 172 1, INFLATE_CMDNAME, INFLATE_NAME, "deflate", 173 {"deflate", "x-deflate", NULL} }, 174 { CMP_NOCOMPRESS, NULL, NULL, 0, NULL, NULL, NULL, {NULL}}, 175 }; 176 /* *INDENT-ON* */ 177 178 #define SAVE_BUF_SIZE 1536 179 180 static MySignalHandler 181 KeyAbort(SIGNAL_ARG) 182 { 183 LONGJMP(AbortLoading, 1); 184 SIGNAL_RETURN; 185 } 186 187 static void 188 UFhalfclose(URLFile *f) 189 { 190 switch (f->scheme) { 191 case SCM_FTP: 192 closeFTP(); 193 break; 194 #ifdef USE_NNTP 195 case SCM_NEWS: 196 case SCM_NNTP: 197 closeNews(); 198 break; 199 #endif 200 default: 201 UFclose(f); 202 break; 203 } 204 } 205 206 int 207 currentLn(Buffer *buf) 208 { 209 if (buf->currentLine) 210 /* return buf->currentLine->real_linenumber + 1; */ 211 return buf->currentLine->linenumber + 1; 212 else 213 return 1; 214 } 215 216 static Buffer * 217 loadSomething(URLFile *f, 218 char *path, 219 Buffer *(*loadproc) (URLFile *, Buffer *), Buffer *defaultbuf) 220 { 221 Buffer *buf; 222 223 if ((buf = loadproc(f, defaultbuf)) == NULL) 224 return NULL; 225 226 buf->filename = path; 227 if (buf->buffername == NULL || buf->buffername[0] == '\0') { 228 buf->buffername = checkHeader(buf, "Subject:"); 229 if (buf->buffername == NULL) 230 buf->buffername = conv_from_system(lastFileName(path)); 231 } 232 if (buf->currentURL.scheme == SCM_UNKNOWN) 233 buf->currentURL.scheme = f->scheme; 234 buf->real_scheme = f->scheme; 235 if (f->scheme == SCM_LOCAL && buf->sourcefile == NULL) 236 buf->sourcefile = path; 237 return buf; 238 } 239 240 int 241 dir_exist(char *path) 242 { 243 struct stat stbuf; 244 245 if (path == NULL || *path == '\0') 246 return 0; 247 if (stat(path, &stbuf) == -1) 248 return 0; 249 return IS_DIRECTORY(stbuf.st_mode); 250 } 251 252 static int 253 is_dump_text_type(char *type) 254 { 255 struct mailcap *mcap; 256 return (type && (mcap = searchExtViewer(type)) && 257 (mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT))); 258 } 259 260 static int 261 is_text_type(char *type) 262 { 263 return (type == NULL || type[0] == '\0' || 264 strncasecmp(type, "text/", 5) == 0 || 265 (strncasecmp(type, "application/", 12) == 0 && 266 strstr(type, "xhtml") != NULL) || 267 strncasecmp(type, "message/", sizeof("message/") - 1) == 0); 268 } 269 270 static int 271 is_plain_text_type(char *type) 272 { 273 return ((type && strcasecmp(type, "text/plain") == 0) || 274 (is_text_type(type) && !is_dump_text_type(type))); 275 } 276 277 int 278 is_html_type(char *type) 279 { 280 return (type && (strcasecmp(type, "text/html") == 0 || 281 strcasecmp(type, "application/xhtml+xml") == 0)); 282 } 283 284 static void 285 check_compression(char *path, URLFile *uf) 286 { 287 int len; 288 struct compression_decoder *d; 289 290 if (path == NULL) 291 return; 292 293 len = strlen(path); 294 uf->compression = CMP_NOCOMPRESS; 295 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) { 296 int elen; 297 if (d->ext == NULL) 298 continue; 299 elen = strlen(d->ext); 300 if (len > elen && strcasecmp(&path[len - elen], d->ext) == 0) { 301 uf->compression = d->type; 302 uf->guess_type = d->mime_type; 303 break; 304 } 305 } 306 } 307 308 static char * 309 compress_application_type(int compression) 310 { 311 struct compression_decoder *d; 312 313 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) { 314 if (d->type == compression) 315 return d->mime_type; 316 } 317 return NULL; 318 } 319 320 static char * 321 uncompressed_file_type(char *path, char **ext) 322 { 323 int len, slen; 324 Str fn; 325 char *t0; 326 struct compression_decoder *d; 327 328 if (path == NULL) 329 return NULL; 330 331 slen = 0; 332 len = strlen(path); 333 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) { 334 if (d->ext == NULL) 335 continue; 336 slen = strlen(d->ext); 337 if (len > slen && strcasecmp(&path[len - slen], d->ext) == 0) 338 break; 339 } 340 if (d->type == CMP_NOCOMPRESS) 341 return NULL; 342 343 fn = Strnew_charp(path); 344 Strshrink(fn, slen); 345 if (ext) 346 *ext = filename_extension(fn->ptr, 0); 347 t0 = guessContentType(fn->ptr); 348 if (t0 == NULL) 349 t0 = "text/plain"; 350 return t0; 351 } 352 353 static int 354 setModtime(char *path, time_t modtime) 355 { 356 struct utimbuf t; 357 struct stat st; 358 359 if (stat(path, &st) == 0) 360 t.actime = st.st_atime; 361 else 362 t.actime = time(NULL); 363 t.modtime = modtime; 364 return utime(path, &t); 365 } 366 367 void 368 examineFile(char *path, URLFile *uf) 369 { 370 struct stat stbuf; 371 372 uf->guess_type = NULL; 373 if (path == NULL || *path == '\0' || 374 stat(path, &stbuf) == -1 || NOT_REGULAR(stbuf.st_mode)) { 375 uf->stream = NULL; 376 return; 377 } 378 uf->stream = openIS(path); 379 if (!do_download) { 380 if (use_lessopen && getenv("LESSOPEN") != NULL) { 381 FILE *fp; 382 uf->guess_type = guessContentType(path); 383 if (uf->guess_type == NULL) 384 uf->guess_type = "text/plain"; 385 if (is_html_type(uf->guess_type)) 386 return; 387 if ((fp = lessopen_stream(path))) { 388 UFclose(uf); 389 uf->stream = newFileStream(fp, (void (*)())pclose); 390 uf->guess_type = "text/plain"; 391 return; 392 } 393 } 394 check_compression(path, uf); 395 if (uf->compression != CMP_NOCOMPRESS) { 396 char *ext = uf->ext; 397 char *t0 = uncompressed_file_type(path, &ext); 398 uf->guess_type = t0; 399 uf->ext = ext; 400 uncompress_stream(uf, NULL); 401 return; 402 } 403 } 404 } 405 406 #define S_IXANY (S_IXUSR|S_IXGRP|S_IXOTH) 407 408 int 409 check_command(char *cmd, int auxbin_p) 410 { 411 static char *path = NULL; 412 Str dirs; 413 char *p, *np; 414 Str pathname; 415 struct stat st; 416 417 if (path == NULL) 418 path = getenv("PATH"); 419 if (auxbin_p) 420 dirs = Strnew_charp(w3m_auxbin_dir()); 421 else 422 dirs = Strnew_charp(path); 423 for (p = dirs->ptr; p != NULL; p = np) { 424 np = strchr(p, PATH_SEPARATOR); 425 if (np) 426 *np++ = '\0'; 427 pathname = Strnew(); 428 Strcat_charp(pathname, p); 429 Strcat_char(pathname, '/'); 430 Strcat_charp(pathname, cmd); 431 if (stat(pathname->ptr, &st) == 0 && S_ISREG(st.st_mode) 432 && (st.st_mode & S_IXANY) != 0) 433 return 1; 434 } 435 return 0; 436 } 437 438 char * 439 acceptableEncoding() 440 { 441 static Str encodings = NULL; 442 struct compression_decoder *d; 443 TextList *l; 444 char *p; 445 446 if (encodings != NULL) 447 return encodings->ptr; 448 l = newTextList(); 449 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) { 450 if (check_command(d->cmd, d->auxbin_p)) { 451 pushText(l, d->encoding); 452 } 453 } 454 encodings = Strnew(); 455 while ((p = popText(l)) != NULL) { 456 if (encodings->length) 457 Strcat_charp(encodings, ", "); 458 Strcat_charp(encodings, p); 459 } 460 return encodings->ptr; 461 } 462 463 /* 464 * convert line 465 */ 466 #ifdef USE_M17N 467 Str 468 convertLine(URLFile *uf, Str line, int mode, wc_ces * charset, 469 wc_ces doc_charset) 470 #else 471 Str 472 convertLine0(URLFile *uf, Str line, int mode) 473 #endif 474 { 475 #ifdef USE_M17N 476 line = wc_Str_conv_with_detect(line, charset, doc_charset, InnerCharset); 477 #endif 478 if (mode != RAW_MODE) 479 cleanup_line(line, mode); 480 #ifdef USE_NNTP 481 if (uf && uf->scheme == SCM_NEWS) 482 Strchop(line); 483 #endif /* USE_NNTP */ 484 return line; 485 } 486 487 /* 488 * loadFile: load file to buffer 489 */ 490 Buffer * 491 loadFile(char *path) 492 { 493 Buffer *buf; 494 URLFile uf; 495 init_stream(&uf, SCM_LOCAL, NULL); 496 examineFile(path, &uf); 497 if (uf.stream == NULL) 498 return NULL; 499 buf = newBuffer(INIT_BUFFER_WIDTH); 500 current_content_length = 0; 501 #ifdef USE_M17N 502 content_charset = 0; 503 #endif 504 buf = loadSomething(&uf, path, loadBuffer, buf); 505 UFclose(&uf); 506 return buf; 507 } 508 509 int 510 matchattr(char *p, char *attr, int len, Str *value) 511 { 512 int quoted; 513 char *q = NULL; 514 515 if (strncasecmp(p, attr, len) == 0) { 516 p += len; 517 SKIP_BLANKS(p); 518 if (value) { 519 *value = Strnew(); 520 if (*p == '=') { 521 p++; 522 SKIP_BLANKS(p); 523 quoted = 0; 524 while (!IS_ENDL(*p) && (quoted || *p != ';')) { 525 if (!IS_SPACE(*p)) 526 q = p; 527 if (*p == '"') 528 quoted = (quoted) ? 0 : 1; 529 else 530 Strcat_char(*value, *p); 531 p++; 532 } 533 if (q) 534 Strshrink(*value, p - q - 1); 535 } 536 return 1; 537 } 538 else { 539 if (IS_ENDT(*p)) { 540 return 1; 541 } 542 } 543 } 544 return 0; 545 } 546 547 #ifdef USE_IMAGE 548 #ifdef USE_XFACE 549 static char * 550 xface2xpm(char *xface) 551 { 552 Image image; 553 ImageCache *cache; 554 FILE *f; 555 struct stat st; 556 557 SKIP_BLANKS(xface); 558 image.url = xface; 559 image.ext = ".xpm"; 560 image.width = 48; 561 image.height = 48; 562 image.cache = NULL; 563 cache = getImage(&image, NULL, IMG_FLAG_AUTO); 564 if (cache->loaded & IMG_FLAG_LOADED && !stat(cache->file, &st)) 565 return cache->file; 566 cache->loaded = IMG_FLAG_ERROR; 567 568 f = popen(Sprintf("%s > %s", shell_quote(auxbinFile(XFACE2XPM)), 569 shell_quote(cache->file))->ptr, "w"); 570 if (!f) 571 return NULL; 572 fputs(xface, f); 573 pclose(f); 574 if (stat(cache->file, &st) || !st.st_size) 575 return NULL; 576 cache->loaded = IMG_FLAG_LOADED | IMG_FLAG_DONT_REMOVE; 577 cache->index = 0; 578 return cache->file; 579 } 580 #endif 581 #endif 582 583 void 584 readHeader(URLFile *uf, Buffer *newBuf, int thru, ParsedURL *pu) 585 { 586 char *p, *q; 587 #ifdef USE_COOKIE 588 char *emsg; 589 #endif 590 char c; 591 Str lineBuf2 = NULL; 592 Str tmp; 593 TextList *headerlist; 594 #ifdef USE_M17N 595 wc_ces charset = WC_CES_US_ASCII, mime_charset; 596 #endif 597 char *tmpf; 598 FILE *src = NULL; 599 Lineprop *propBuffer; 600 601 headerlist = newBuf->document_header = newTextList(); 602 if (uf->scheme == SCM_HTTP 603 #ifdef USE_SSL 604 || uf->scheme == SCM_HTTPS 605 #endif /* USE_SSL */ 606 ) 607 http_response_code = -1; 608 else 609 http_response_code = 0; 610 611 if (thru && !newBuf->header_source 612 #ifdef USE_IMAGE 613 && !image_source 614 #endif 615 ) { 616 tmpf = tmpfname(TMPF_DFL, NULL)->ptr; 617 src = fopen(tmpf, "w"); 618 if (src) 619 newBuf->header_source = tmpf; 620 } 621 while ((tmp = StrmyUFgets(uf))->length) { 622 #ifdef USE_NNTP 623 if (uf->scheme == SCM_NEWS && tmp->ptr[0] == '.') 624 Strshrinkfirst(tmp, 1); 625 #endif 626 if(w3m_reqlog){ 627 FILE *ff; 628 ff = fopen(w3m_reqlog, "a"); 629 Strfputs(tmp, ff); 630 fclose(ff); 631 } 632 if (src) 633 Strfputs(tmp, src); 634 cleanup_line(tmp, HEADER_MODE); 635 if (tmp->ptr[0] == '\n' || tmp->ptr[0] == '\r' || tmp->ptr[0] == '\0') { 636 if (!lineBuf2) 637 /* there is no header */ 638 break; 639 /* last header */ 640 } 641 else if (!(w3m_dump & DUMP_HEAD)) { 642 if (lineBuf2) { 643 Strcat(lineBuf2, tmp); 644 } 645 else { 646 lineBuf2 = tmp; 647 } 648 c = UFgetc(uf); 649 UFundogetc(uf); 650 if (c == ' ' || c == '\t') 651 /* header line is continued */ 652 continue; 653 lineBuf2 = decodeMIME(lineBuf2, &mime_charset); 654 lineBuf2 = convertLine(NULL, lineBuf2, RAW_MODE, 655 mime_charset ? &mime_charset : &charset, 656 mime_charset ? mime_charset 657 : DocumentCharset); 658 /* separated with line and stored */ 659 tmp = Strnew_size(lineBuf2->length); 660 for (p = lineBuf2->ptr; *p; p = q) { 661 for (q = p; *q && *q != '\r' && *q != '\n'; q++) ; 662 lineBuf2 = checkType(Strnew_charp_n(p, q - p), &propBuffer, 663 NULL); 664 Strcat(tmp, lineBuf2); 665 if (thru) 666 addnewline(newBuf, lineBuf2->ptr, propBuffer, NULL, 667 lineBuf2->length, FOLD_BUFFER_WIDTH, -1); 668 for (; *q && (*q == '\r' || *q == '\n'); q++) ; 669 } 670 #ifdef USE_IMAGE 671 if (thru && activeImage && displayImage) { 672 Str src = NULL; 673 if (!strncasecmp(tmp->ptr, "X-Image-URL:", 12)) { 674 tmpf = &tmp->ptr[12]; 675 SKIP_BLANKS(tmpf); 676 src = Strnew_m_charp("<img src=\"", html_quote(tmpf), 677 "\" alt=\"X-Image-URL\">", NULL); 678 } 679 #ifdef USE_XFACE 680 else if (!strncasecmp(tmp->ptr, "X-Face:", 7)) { 681 tmpf = xface2xpm(&tmp->ptr[7]); 682 if (tmpf) 683 src = Strnew_m_charp("<img src=\"file:", 684 html_quote(tmpf), 685 "\" alt=\"X-Face\"", 686 " width=48 height=48>", NULL); 687 } 688 #endif 689 if (src) { 690 URLFile f; 691 Line *l; 692 #ifdef USE_M17N 693 wc_ces old_charset = newBuf->document_charset; 694 #endif 695 init_stream(&f, SCM_LOCAL, newStrStream(src)); 696 loadHTMLstream(&f, newBuf, NULL, TRUE); 697 for (l = newBuf->lastLine; l && l->real_linenumber; 698 l = l->prev) 699 l->real_linenumber = 0; 700 #ifdef USE_M17N 701 newBuf->document_charset = old_charset; 702 #endif 703 } 704 } 705 #endif 706 lineBuf2 = tmp; 707 } 708 else { 709 lineBuf2 = tmp; 710 } 711 if ((uf->scheme == SCM_HTTP 712 #ifdef USE_SSL 713 || uf->scheme == SCM_HTTPS 714 #endif /* USE_SSL */ 715 ) && http_response_code == -1) { 716 p = lineBuf2->ptr; 717 while (*p && !IS_SPACE(*p)) 718 p++; 719 while (*p && IS_SPACE(*p)) 720 p++; 721 http_response_code = atoi(p); 722 if (fmInitialized) { 723 message(lineBuf2->ptr, 0, 0); 724 refresh(); 725 } 726 } 727 if (!strncasecmp(lineBuf2->ptr, "content-transfer-encoding:", 26)) { 728 p = lineBuf2->ptr + 26; 729 while (IS_SPACE(*p)) 730 p++; 731 if (!strncasecmp(p, "base64", 6)) 732 uf->encoding = ENC_BASE64; 733 else if (!strncasecmp(p, "quoted-printable", 16)) 734 uf->encoding = ENC_QUOTE; 735 else if (!strncasecmp(p, "uuencode", 8) || 736 !strncasecmp(p, "x-uuencode", 10)) 737 uf->encoding = ENC_UUENCODE; 738 else 739 uf->encoding = ENC_7BIT; 740 } 741 else if (!strncasecmp(lineBuf2->ptr, "content-encoding:", 17)) { 742 struct compression_decoder *d; 743 p = lineBuf2->ptr + 17; 744 while (IS_SPACE(*p)) 745 p++; 746 uf->compression = CMP_NOCOMPRESS; 747 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) { 748 char **e; 749 for (e = d->encodings; *e != NULL; e++) { 750 if (strncasecmp(p, *e, strlen(*e)) == 0) { 751 uf->compression = d->type; 752 break; 753 } 754 } 755 if (uf->compression != CMP_NOCOMPRESS) 756 break; 757 } 758 uf->content_encoding = uf->compression; 759 } 760 #ifdef USE_COOKIE 761 else if (use_cookie && accept_cookie && 762 pu && check_cookie_accept_domain(pu->host) && 763 (!strncasecmp(lineBuf2->ptr, "Set-Cookie:", 11) || 764 !strncasecmp(lineBuf2->ptr, "Set-Cookie2:", 12))) { 765 Str name = Strnew(), value = Strnew(), domain = NULL, path = NULL, 766 comment = NULL, commentURL = NULL, port = NULL, tmp2; 767 int version, quoted, flag = 0; 768 time_t expires = (time_t) - 1; 769 770 q = NULL; 771 if (lineBuf2->ptr[10] == '2') { 772 p = lineBuf2->ptr + 12; 773 version = 1; 774 } 775 else { 776 p = lineBuf2->ptr + 11; 777 version = 0; 778 } 779 #ifdef DEBUG 780 fprintf(stderr, "Set-Cookie: [%s]\n", p); 781 #endif /* DEBUG */ 782 SKIP_BLANKS(p); 783 while (*p != '=' && !IS_ENDT(*p)) 784 Strcat_char(name, *(p++)); 785 Strremovetrailingspaces(name); 786 if (*p == '=') { 787 p++; 788 SKIP_BLANKS(p); 789 quoted = 0; 790 while (!IS_ENDL(*p) && (quoted || *p != ';')) { 791 if (!IS_SPACE(*p)) 792 q = p; 793 if (*p == '"') 794 quoted = (quoted) ? 0 : 1; 795 Strcat_char(value, *(p++)); 796 } 797 if (q) 798 Strshrink(value, p - q - 1); 799 } 800 while (*p == ';') { 801 p++; 802 SKIP_BLANKS(p); 803 if (matchattr(p, "expires", 7, &tmp2)) { 804 /* version 0 */ 805 expires = mymktime(tmp2->ptr); 806 } 807 else if (matchattr(p, "max-age", 7, &tmp2)) { 808 /* XXX Is there any problem with max-age=0? (RFC 2109 ss. 4.2.1, 4.2.2 */ 809 expires = time(NULL) + atol(tmp2->ptr); 810 } 811 else if (matchattr(p, "domain", 6, &tmp2)) { 812 domain = tmp2; 813 } 814 else if (matchattr(p, "path", 4, &tmp2)) { 815 path = tmp2; 816 } 817 else if (matchattr(p, "secure", 6, NULL)) { 818 flag |= COO_SECURE; 819 } 820 else if (matchattr(p, "comment", 7, &tmp2)) { 821 comment = tmp2; 822 } 823 else if (matchattr(p, "version", 7, &tmp2)) { 824 version = atoi(tmp2->ptr); 825 } 826 else if (matchattr(p, "port", 4, &tmp2)) { 827 /* version 1, Set-Cookie2 */ 828 port = tmp2; 829 } 830 else if (matchattr(p, "commentURL", 10, &tmp2)) { 831 /* version 1, Set-Cookie2 */ 832 commentURL = tmp2; 833 } 834 else if (matchattr(p, "discard", 7, NULL)) { 835 /* version 1, Set-Cookie2 */ 836 flag |= COO_DISCARD; 837 } 838 quoted = 0; 839 while (!IS_ENDL(*p) && (quoted || *p != ';')) { 840 if (*p == '"') 841 quoted = (quoted) ? 0 : 1; 842 p++; 843 } 844 } 845 if (pu && name->length > 0) { 846 int err; 847 if (show_cookie) { 848 if (flag & COO_SECURE) 849 disp_message_nsec("Received a secured cookie", FALSE, 1, 850 TRUE, FALSE); 851 else 852 disp_message_nsec(Sprintf("Received cookie: %s=%s", 853 name->ptr, value->ptr)->ptr, 854 FALSE, 1, TRUE, FALSE); 855 } 856 err = 857 add_cookie(pu, name, value, expires, domain, path, flag, 858 comment, version, port, commentURL); 859 if (err) { 860 char *ans = (accept_bad_cookie == ACCEPT_BAD_COOKIE_ACCEPT) 861 ? "y" : NULL; 862 if (fmInitialized && (err & COO_OVERRIDE_OK) && 863 accept_bad_cookie == ACCEPT_BAD_COOKIE_ASK) { 864 Str msg = Sprintf("Accept bad cookie from %s for %s?", 865 pu->host, 866 ((domain && domain->ptr) 867 ? domain->ptr : "<localdomain>")); 868 if (msg->length > COLS - 10) 869 Strshrink(msg, msg->length - (COLS - 10)); 870 Strcat_charp(msg, " (y/n)"); 871 ans = inputAnswer(msg->ptr); 872 } 873 if (ans == NULL || TOLOWER(*ans) != 'y' || 874 (err = 875 add_cookie(pu, name, value, expires, domain, path, 876 flag | COO_OVERRIDE, comment, version, 877 port, commentURL))) { 878 err = (err & ~COO_OVERRIDE_OK) - 1; 879 if (err >= 0 && err < COO_EMAX) 880 emsg = Sprintf("This cookie was rejected " 881 "to prevent security violation. [%s]", 882 violations[err])->ptr; 883 else 884 emsg = 885 "This cookie was rejected to prevent security violation."; 886 record_err_message(emsg); 887 if (show_cookie) 888 disp_message_nsec(emsg, FALSE, 1, TRUE, FALSE); 889 } 890 else 891 if (show_cookie) 892 disp_message_nsec(Sprintf 893 ("Accepting invalid cookie: %s=%s", 894 name->ptr, value->ptr)->ptr, FALSE, 895 1, TRUE, FALSE); 896 } 897 } 898 } 899 #endif /* USE_COOKIE */ 900 else if (!strncasecmp(lineBuf2->ptr, "w3m-control:", 12) && 901 uf->scheme == SCM_LOCAL_CGI) { 902 Str funcname = Strnew(); 903 int f; 904 905 p = lineBuf2->ptr + 12; 906 SKIP_BLANKS(p); 907 while (*p && !IS_SPACE(*p)) 908 Strcat_char(funcname, *(p++)); 909 SKIP_BLANKS(p); 910 f = getFuncList(funcname->ptr); 911 if (f >= 0) { 912 tmp = Strnew_charp(p); 913 Strchop(tmp); 914 pushEvent(f, tmp->ptr); 915 } 916 } 917 if (headerlist) 918 pushText(headerlist, lineBuf2->ptr); 919 Strfree(lineBuf2); 920 lineBuf2 = NULL; 921 } 922 if (thru) 923 addnewline(newBuf, "", propBuffer, NULL, 0, -1, -1); 924 if (src) 925 fclose(src); 926 } 927 928 char * 929 checkHeader(Buffer *buf, char *field) 930 { 931 int len; 932 TextListItem *i; 933 char *p; 934 935 if (buf == NULL || field == NULL || buf->document_header == NULL) 936 return NULL; 937 len = strlen(field); 938 for (i = buf->document_header->first; i != NULL; i = i->next) { 939 if (!strncasecmp(i->ptr, field, len)) { 940 p = i->ptr + len; 941 return remove_space(p); 942 } 943 } 944 return NULL; 945 } 946 947 char * 948 checkContentType(Buffer *buf) 949 { 950 char *p; 951 Str r; 952 p = checkHeader(buf, "Content-Type:"); 953 if (p == NULL) 954 return NULL; 955 r = Strnew(); 956 while (*p && *p != ';' && !IS_SPACE(*p)) 957 Strcat_char(r, *p++); 958 #ifdef USE_M17N 959 if ((p = strcasestr(p, "charset")) != NULL) { 960 p += 7; 961 SKIP_BLANKS(p); 962 if (*p == '=') { 963 p++; 964 SKIP_BLANKS(p); 965 if (*p == '"') 966 p++; 967 content_charset = wc_guess_charset(p, 0); 968 } 969 } 970 #endif 971 return r->ptr; 972 } 973 974 struct auth_param { 975 char *name; 976 Str val; 977 }; 978 979 struct http_auth { 980 int pri; 981 char *scheme; 982 struct auth_param *param; 983 Str (*cred) (struct http_auth * ha, Str uname, Str pw, ParsedURL *pu, 984 HRequest *hr, FormList *request); 985 }; 986 987 enum { 988 AUTHCHR_NUL, 989 AUTHCHR_SEP, 990 AUTHCHR_TOKEN, 991 }; 992 993 static int 994 skip_auth_token(char **pp) 995 { 996 char *p; 997 int first = AUTHCHR_NUL, typ; 998 999 for (p = *pp ;; ++p) { 1000 switch (*p) { 1001 case '\0': 1002 goto endoftoken; 1003 default: 1004 if ((unsigned char)*p > 037) { 1005 typ = AUTHCHR_TOKEN; 1006 break; 1007 } 1008 /* thru */ 1009 case '\177': 1010 case '[': 1011 case ']': 1012 case '(': 1013 case ')': 1014 case '<': 1015 case '>': 1016 case '@': 1017 case ';': 1018 case ':': 1019 case '\\': 1020 case '"': 1021 case '/': 1022 case '?': 1023 case '=': 1024 case ' ': 1025 case '\t': 1026 case ',': 1027 typ = AUTHCHR_SEP; 1028 break; 1029 } 1030 1031 if (!first) 1032 first = typ; 1033 else if (first != typ) 1034 break; 1035 } 1036 endoftoken: 1037 *pp = p; 1038 return first; 1039 } 1040 1041 static Str 1042 extract_auth_val(char **q) 1043 { 1044 unsigned char *qq = *(unsigned char **)q; 1045 int quoted = 0; 1046 Str val = Strnew(); 1047 1048 SKIP_BLANKS(qq); 1049 if (*qq == '"') { 1050 quoted = TRUE; 1051 Strcat_char(val, *qq++); 1052 } 1053 while (*qq != '\0') { 1054 if (quoted && *qq == '"') { 1055 Strcat_char(val, *qq++); 1056 break; 1057 } 1058 if (!quoted) { 1059 switch (*qq) { 1060 case '[': 1061 case ']': 1062 case '(': 1063 case ')': 1064 case '<': 1065 case '>': 1066 case '@': 1067 case ';': 1068 case ':': 1069 case '\\': 1070 case '"': 1071 case '/': 1072 case '?': 1073 case '=': 1074 case ' ': 1075 case '\t': 1076 qq++; 1077 case ',': 1078 goto end_token; 1079 default: 1080 if (*qq <= 037 || *qq == 0177) { 1081 qq++; 1082 goto end_token; 1083 } 1084 } 1085 } 1086 else if (quoted && *qq == '\\') 1087 Strcat_char(val, *qq++); 1088 Strcat_char(val, *qq++); 1089 } 1090 end_token: 1091 *q = (char *)qq; 1092 return val; 1093 } 1094 1095 static Str 1096 qstr_unquote(Str s) 1097 { 1098 char *p; 1099 1100 if (s == NULL) 1101 return NULL; 1102 p = s->ptr; 1103 if (*p == '"') { 1104 Str tmp = Strnew(); 1105 for (p++; *p != '\0'; p++) { 1106 if (*p == '\\') 1107 p++; 1108 Strcat_char(tmp, *p); 1109 } 1110 if (Strlastchar(tmp) == '"') 1111 Strshrink(tmp, 1); 1112 return tmp; 1113 } 1114 else 1115 return s; 1116 } 1117 1118 static char * 1119 extract_auth_param(char *q, struct auth_param *auth) 1120 { 1121 struct auth_param *ap; 1122 char *p; 1123 1124 for (ap = auth; ap->name != NULL; ap++) { 1125 ap->val = NULL; 1126 } 1127 1128 while (*q != '\0') { 1129 SKIP_BLANKS(q); 1130 for (ap = auth; ap->name != NULL; ap++) { 1131 size_t len; 1132 1133 len = strlen(ap->name); 1134 if (strncasecmp(q, ap->name, len) == 0 && 1135 (IS_SPACE(q[len]) || q[len] == '=')) { 1136 p = q + len; 1137 SKIP_BLANKS(p); 1138 if (*p != '=') 1139 return q; 1140 q = p + 1; 1141 ap->val = extract_auth_val(&q); 1142 break; 1143 } 1144 } 1145 if (ap->name == NULL) { 1146 /* skip unknown param */ 1147 int token_type; 1148 p = q; 1149 if ((token_type = skip_auth_token(&q)) == AUTHCHR_TOKEN && 1150 (IS_SPACE(*q) || *q == '=')) { 1151 SKIP_BLANKS(q); 1152 if (*q != '=') 1153 return p; 1154 q++; 1155 extract_auth_val(&q); 1156 } 1157 else 1158 return p; 1159 } 1160 if (*q != '\0') { 1161 SKIP_BLANKS(q); 1162 if (*q == ',') 1163 q++; 1164 else 1165 break; 1166 } 1167 } 1168 return q; 1169 } 1170 1171 static Str 1172 get_auth_param(struct auth_param *auth, char *name) 1173 { 1174 struct auth_param *ap; 1175 for (ap = auth; ap->name != NULL; ap++) { 1176 if (strcasecmp(name, ap->name) == 0) 1177 return ap->val; 1178 } 1179 return NULL; 1180 } 1181 1182 static Str 1183 AuthBasicCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu, 1184 HRequest *hr, FormList *request) 1185 { 1186 Str s = Strdup(uname); 1187 Strcat_char(s, ':'); 1188 Strcat(s, pw); 1189 return Strnew_m_charp("Basic ", encodeB(s->ptr)->ptr, NULL); 1190 } 1191 1192 #ifdef USE_DIGEST_AUTH 1193 #include <openssl/md5.h> 1194 1195 /* RFC2617: 3.2.2 The Authorization Request Header 1196 * 1197 * credentials = "Digest" digest-response 1198 * digest-response = 1#( username | realm | nonce | digest-uri 1199 * | response | [ algorithm ] | [cnonce] | 1200 * [opaque] | [message-qop] | 1201 * [nonce-count] | [auth-param] ) 1202 * 1203 * username = "username" "=" username-value 1204 * username-value = quoted-string 1205 * digest-uri = "uri" "=" digest-uri-value 1206 * digest-uri-value = request-uri ; As specified by HTTP/1.1 1207 * message-qop = "qop" "=" qop-value 1208 * cnonce = "cnonce" "=" cnonce-value 1209 * cnonce-value = nonce-value 1210 * nonce-count = "nc" "=" nc-value 1211 * nc-value = 8LHEX 1212 * response = "response" "=" request-digest 1213 * request-digest = <"> 32LHEX <"> 1214 * LHEX = "0" | "1" | "2" | "3" | 1215 * "4" | "5" | "6" | "7" | 1216 * "8" | "9" | "a" | "b" | 1217 * "c" | "d" | "e" | "f" 1218 */ 1219 1220 static Str 1221 digest_hex(unsigned char *p) 1222 { 1223 char *h = "0123456789abcdef"; 1224 Str tmp = Strnew_size(MD5_DIGEST_LENGTH * 2 + 1); 1225 int i; 1226 for (i = 0; i < MD5_DIGEST_LENGTH; i++, p++) { 1227 Strcat_char(tmp, h[(*p >> 4) & 0x0f]); 1228 Strcat_char(tmp, h[*p & 0x0f]); 1229 } 1230 return tmp; 1231 } 1232 1233 enum { 1234 QOP_NONE, 1235 QOP_AUTH, 1236 QOP_AUTH_INT, 1237 }; 1238 1239 static Str 1240 AuthDigestCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu, 1241 HRequest *hr, FormList *request) 1242 { 1243 Str tmp, a1buf, a2buf, rd, s; 1244 unsigned char md5[MD5_DIGEST_LENGTH + 1]; 1245 Str uri = HTTPrequestURI(pu, hr); 1246 char nc[] = "00000001"; 1247 1248 Str algorithm = qstr_unquote(get_auth_param(ha->param, "algorithm")); 1249 Str nonce = qstr_unquote(get_auth_param(ha->param, "nonce")); 1250 Str cnonce /* = qstr_unquote(get_auth_param(ha->param, "cnonce")) */; 1251 /* cnonce is what client should generate. */ 1252 Str qop = qstr_unquote(get_auth_param(ha->param, "qop")); 1253 1254 static union { 1255 int r[4]; 1256 unsigned char s[sizeof(int) * 4]; 1257 } cnonce_seed; 1258 int qop_i = QOP_NONE; 1259 1260 cnonce_seed.r[0] = rand(); 1261 cnonce_seed.r[1] = rand(); 1262 cnonce_seed.r[2] = rand(); 1263 MD5(cnonce_seed.s, sizeof(cnonce_seed.s), md5); 1264 cnonce = digest_hex(md5); 1265 cnonce_seed.r[3]++; 1266 1267 if (qop) { 1268 char *p; 1269 size_t i; 1270 1271 p = qop->ptr; 1272 SKIP_BLANKS(p); 1273 1274 for (;;) { 1275 if ((i = strcspn(p, " \t,")) > 0) { 1276 if (i == sizeof("auth-int") - sizeof("") && !strncasecmp(p, "auth-int", i)) { 1277 if (qop_i < QOP_AUTH_INT) 1278 qop_i = QOP_AUTH_INT; 1279 } 1280 else if (i == sizeof("auth") - sizeof("") && !strncasecmp(p, "auth", i)) { 1281 if (qop_i < QOP_AUTH) 1282 qop_i = QOP_AUTH; 1283 } 1284 } 1285 1286 if (p[i]) { 1287 p += i + 1; 1288 SKIP_BLANKS(p); 1289 } 1290 else 1291 break; 1292 } 1293 } 1294 1295 /* A1 = unq(username-value) ":" unq(realm-value) ":" passwd */ 1296 tmp = Strnew_m_charp(uname->ptr, ":", 1297 qstr_unquote(get_auth_param(ha->param, "realm"))->ptr, 1298 ":", pw->ptr, NULL); 1299 MD5(tmp->ptr, strlen(tmp->ptr), md5); 1300 a1buf = digest_hex(md5); 1301 1302 if (algorithm) { 1303 if (strcasecmp(algorithm->ptr, "MD5-sess") == 0) { 1304 /* A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) 1305 * ":" unq(nonce-value) ":" unq(cnonce-value) 1306 */ 1307 if (nonce == NULL) 1308 return NULL; 1309 tmp = Strnew_m_charp(a1buf->ptr, ":", 1310 qstr_unquote(nonce)->ptr, 1311 ":", qstr_unquote(cnonce)->ptr, NULL); 1312 MD5(tmp->ptr, strlen(tmp->ptr), md5); 1313 a1buf = digest_hex(md5); 1314 } 1315 else if (strcasecmp(algorithm->ptr, "MD5") == 0) 1316 /* ok default */ 1317 ; 1318 else 1319 /* unknown algorithm */ 1320 return NULL; 1321 } 1322 1323 /* A2 = Method ":" digest-uri-value */ 1324 tmp = Strnew_m_charp(HTTPrequestMethod(hr)->ptr, ":", uri->ptr, NULL); 1325 if (qop_i == QOP_AUTH_INT) { 1326 /* A2 = Method ":" digest-uri-value ":" H(entity-body) */ 1327 if (request && request->body) { 1328 if (request->method == FORM_METHOD_POST && request->enctype == FORM_ENCTYPE_MULTIPART) { 1329 FILE *fp = fopen(request->body, "r"); 1330 if (fp != NULL) { 1331 Str ebody; 1332 ebody = Strfgetall(fp); 1333 MD5(ebody->ptr, strlen(ebody->ptr), md5); 1334 } 1335 else { 1336 MD5("", 0, md5); 1337 } 1338 } 1339 else { 1340 MD5(request->body, request->length, md5); 1341 } 1342 } 1343 else { 1344 MD5("", 0, md5); 1345 } 1346 Strcat_char(tmp, ':'); 1347 Strcat(tmp, digest_hex(md5)); 1348 } 1349 MD5(tmp->ptr, strlen(tmp->ptr), md5); 1350 a2buf = digest_hex(md5); 1351 1352 if (qop_i >= QOP_AUTH) { 1353 /* request-digest = <"> < KD ( H(A1), unq(nonce-value) 1354 * ":" nc-value 1355 * ":" unq(cnonce-value) 1356 * ":" unq(qop-value) 1357 * ":" H(A2) 1358 * ) <"> 1359 */ 1360 if (nonce == NULL) 1361 return NULL; 1362 tmp = Strnew_m_charp(a1buf->ptr, ":", qstr_unquote(nonce)->ptr, 1363 ":", nc, 1364 ":", qstr_unquote(cnonce)->ptr, 1365 ":", qop_i == QOP_AUTH ? "auth" : "auth-int", 1366 ":", a2buf->ptr, NULL); 1367 MD5(tmp->ptr, strlen(tmp->ptr), md5); 1368 rd = digest_hex(md5); 1369 } 1370 else { 1371 /* compatibility with RFC 2069 1372 * request_digest = KD(H(A1), unq(nonce), H(A2)) 1373 */ 1374 tmp = Strnew_m_charp(a1buf->ptr, ":", 1375 qstr_unquote(get_auth_param(ha->param, "nonce"))-> 1376 ptr, ":", a2buf->ptr, NULL); 1377 MD5(tmp->ptr, strlen(tmp->ptr), md5); 1378 rd = digest_hex(md5); 1379 } 1380 1381 /* 1382 * digest-response = 1#( username | realm | nonce | digest-uri 1383 * | response | [ algorithm ] | [cnonce] | 1384 * [opaque] | [message-qop] | 1385 * [nonce-count] | [auth-param] ) 1386 */ 1387 1388 tmp = Strnew_m_charp("Digest username=\"", uname->ptr, "\"", NULL); 1389 Strcat_m_charp(tmp, ", realm=", 1390 get_auth_param(ha->param, "realm")->ptr, NULL); 1391 Strcat_m_charp(tmp, ", nonce=", 1392 get_auth_param(ha->param, "nonce")->ptr, NULL); 1393 Strcat_m_charp(tmp, ", uri=\"", uri->ptr, "\"", NULL); 1394 Strcat_m_charp(tmp, ", response=\"", rd->ptr, "\"", NULL); 1395 1396 if (algorithm) 1397 Strcat_m_charp(tmp, ", algorithm=", 1398 get_auth_param(ha->param, "algorithm")->ptr, NULL); 1399 1400 if (cnonce) 1401 Strcat_m_charp(tmp, ", cnonce=\"", cnonce->ptr, "\"", NULL); 1402 1403 if ((s = get_auth_param(ha->param, "opaque")) != NULL) 1404 Strcat_m_charp(tmp, ", opaque=", s->ptr, NULL); 1405 1406 if (qop_i >= QOP_AUTH) { 1407 Strcat_m_charp(tmp, ", qop=", 1408 qop_i == QOP_AUTH ? "auth" : "auth-int", 1409 NULL); 1410 /* XXX how to count? */ 1411 /* Since nonce is unique up to each *-Authenticate and w3m does not re-use *-Authenticate: headers, 1412 nonce-count should be always "00000001". */ 1413 Strcat_m_charp(tmp, ", nc=", nc, NULL); 1414 } 1415 1416 return tmp; 1417 } 1418 #endif 1419 1420 /* *INDENT-OFF* */ 1421 struct auth_param none_auth_param[] = { 1422 {NULL, NULL} 1423 }; 1424 1425 struct auth_param basic_auth_param[] = { 1426 {"realm", NULL}, 1427 {NULL, NULL} 1428 }; 1429 1430 #ifdef USE_DIGEST_AUTH 1431 /* RFC2617: 3.2.1 The WWW-Authenticate Response Header 1432 * challenge = "Digest" digest-challenge 1433 * 1434 * digest-challenge = 1#( realm | [ domain ] | nonce | 1435 * [ opaque ] |[ stale ] | [ algorithm ] | 1436 * [ qop-options ] | [auth-param] ) 1437 * 1438 * domain = "domain" "=" <"> URI ( 1*SP URI ) <"> 1439 * URI = absoluteURI | abs_path 1440 * nonce = "nonce" "=" nonce-value 1441 * nonce-value = quoted-string 1442 * opaque = "opaque" "=" quoted-string 1443 * stale = "stale" "=" ( "true" | "false" ) 1444 * algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" | 1445 * token ) 1446 * qop-options = "qop" "=" <"> 1#qop-value <"> 1447 * qop-value = "auth" | "auth-int" | token 1448 */ 1449 struct auth_param digest_auth_param[] = { 1450 {"realm", NULL}, 1451 {"domain", NULL}, 1452 {"nonce", NULL}, 1453 {"opaque", NULL}, 1454 {"stale", NULL}, 1455 {"algorithm", NULL}, 1456 {"qop", NULL}, 1457 {NULL, NULL} 1458 }; 1459 #endif 1460 /* for RFC2617: HTTP Authentication */ 1461 struct http_auth www_auth[] = { 1462 { 1, "Basic ", basic_auth_param, AuthBasicCred }, 1463 #ifdef USE_DIGEST_AUTH 1464 { 10, "Digest ", digest_auth_param, AuthDigestCred }, 1465 #endif 1466 { 0, NULL, NULL, NULL,} 1467 }; 1468 /* *INDENT-ON* */ 1469 1470 static struct http_auth * 1471 findAuthentication(struct http_auth *hauth, Buffer *buf, char *auth_field) 1472 { 1473 struct http_auth *ha; 1474 int len = strlen(auth_field), slen; 1475 TextListItem *i; 1476 char *p0, *p; 1477 1478 bzero(hauth, sizeof(struct http_auth)); 1479 for (i = buf->document_header->first; i != NULL; i = i->next) { 1480 if (strncasecmp(i->ptr, auth_field, len) == 0) { 1481 for (p = i->ptr + len; p != NULL && *p != '\0';) { 1482 SKIP_BLANKS(p); 1483 p0 = p; 1484 for (ha = &www_auth[0]; ha->scheme != NULL; ha++) { 1485 slen = strlen(ha->scheme); 1486 if (strncasecmp(p, ha->scheme, slen) == 0) { 1487 p += slen; 1488 SKIP_BLANKS(p); 1489 if (hauth->pri < ha->pri) { 1490 *hauth = *ha; 1491 p = extract_auth_param(p, hauth->param); 1492 break; 1493 } 1494 else { 1495 /* weak auth */ 1496 p = extract_auth_param(p, none_auth_param); 1497 } 1498 } 1499 } 1500 if (p0 == p) { 1501 /* all unknown auth failed */ 1502 int token_type; 1503 if ((token_type = skip_auth_token(&p)) == AUTHCHR_TOKEN && IS_SPACE(*p)) { 1504 SKIP_BLANKS(p); 1505 p = extract_auth_param(p, none_auth_param); 1506 } 1507 else 1508 break; 1509 } 1510 } 1511 } 1512 } 1513 return hauth->scheme ? hauth : NULL; 1514 } 1515 1516 static void 1517 getAuthCookie(struct http_auth *hauth, char *auth_header, 1518 TextList *extra_header, ParsedURL *pu, HRequest *hr, 1519 FormList *request, 1520 volatile Str *uname, volatile Str *pwd) 1521 { 1522 Str ss = NULL; 1523 Str tmp; 1524 TextListItem *i; 1525 int a_found; 1526 int auth_header_len = strlen(auth_header); 1527 char *realm = NULL; 1528 int proxy; 1529 1530 if (hauth) 1531 realm = qstr_unquote(get_auth_param(hauth->param, "realm"))->ptr; 1532 1533 if (!realm) 1534 return; 1535 1536 a_found = FALSE; 1537 for (i = extra_header->first; i != NULL; i = i->next) { 1538 if (!strncasecmp(i->ptr, auth_header, auth_header_len)) { 1539 a_found = TRUE; 1540 break; 1541 } 1542 } 1543 proxy = !strncasecmp("Proxy-Authorization:", auth_header, 1544 auth_header_len); 1545 if (a_found) { 1546 /* This means that *-Authenticate: header is received after 1547 * Authorization: header is sent to the server. 1548 */ 1549 if (fmInitialized) { 1550 message("Wrong username or password", 0, 0); 1551 refresh(); 1552 } 1553 else 1554 fprintf(stderr, "Wrong username or password\n"); 1555 sleep(1); 1556 /* delete Authenticate: header from extra_header */ 1557 delText(extra_header, i); 1558 invalidate_auth_user_passwd(pu, realm, *uname, *pwd, proxy); 1559 } 1560 *uname = NULL; 1561 *pwd = NULL; 1562 1563 if (!a_found && find_auth_user_passwd(pu, realm, (Str*)uname, (Str*)pwd, 1564 proxy)) { 1565 /* found username & password in passwd file */ ; 1566 } 1567 else { 1568 if (QuietMessage) 1569 return; 1570 /* input username and password */ 1571 sleep(2); 1572 if (fmInitialized) { 1573 char *pp; 1574 term_raw(); 1575 /* FIXME: gettextize? */ 1576 if ((pp = inputStr(Sprintf("Username for %s: ", realm)->ptr, 1577 NULL)) == NULL) 1578 return; 1579 *uname = Str_conv_to_system(Strnew_charp(pp)); 1580 if ((pp = inputLine(Sprintf("Password for %s: ", realm)->ptr, NULL, 1581 IN_PASSWORD)) == NULL) { 1582 *uname = NULL; 1583 return; 1584 } 1585 *pwd = Str_conv_to_system(Strnew_charp(pp)); 1586 term_cbreak(); 1587 } 1588 else { 1589 /* 1590 * If post file is specified as '-', stdin is closed at this 1591 * point. 1592 * In this case, w3m cannot read username from stdin. 1593 * So exit with error message. 1594 * (This is same behavior as lwp-request.) 1595 */ 1596 if (feof(stdin) || ferror(stdin)) { 1597 /* FIXME: gettextize? */ 1598 fprintf(stderr, "w3m: Authorization required for %s\n", 1599 realm); 1600 exit(1); 1601 } 1602 1603 /* FIXME: gettextize? */ 1604 printf(proxy ? "Proxy Username for %s: " : "Username for %s: ", 1605 realm); 1606 fflush(stdout); 1607 *uname = Strfgets(stdin); 1608 Strchop(*uname); 1609 #ifdef HAVE_GETPASSPHRASE 1610 *pwd = Strnew_charp((char *) 1611 getpassphrase(proxy ? "Proxy Password: " : 1612 "Password: ")); 1613 #else 1614 #ifndef __MINGW32_VERSION 1615 *pwd = Strnew_charp((char *) 1616 getpass(proxy ? "Proxy Password: " : 1617 "Password: ")); 1618 #else 1619 term_raw(); 1620 *pwd = Strnew_charp((char *) 1621 inputLine(proxy ? "Proxy Password: " : 1622 "Password: ", NULL, IN_PASSWORD)); 1623 term_cbreak(); 1624 #endif /* __MINGW32_VERSION */ 1625 #endif 1626 } 1627 } 1628 ss = hauth->cred(hauth, *uname, *pwd, pu, hr, request); 1629 if (ss) { 1630 tmp = Strnew_charp(auth_header); 1631 Strcat_m_charp(tmp, " ", ss->ptr, "\r\n", NULL); 1632 pushText(extra_header, tmp->ptr); 1633 } 1634 else { 1635 *uname = NULL; 1636 *pwd = NULL; 1637 } 1638 return; 1639 } 1640 1641 static int 1642 same_url_p(ParsedURL *pu1, ParsedURL *pu2) 1643 { 1644 return (pu1->scheme == pu2->scheme && pu1->port == pu2->port && 1645 (pu1->host ? pu2->host ? !strcasecmp(pu1->host, pu2->host) : 0 : 1) 1646 && (pu1->file ? pu2-> 1647 file ? !strcmp(pu1->file, pu2->file) : 0 : 1)); 1648 } 1649 1650 static int 1651 checkRedirection(ParsedURL *pu) 1652 { 1653 static ParsedURL *puv = NULL; 1654 static int nredir = 0; 1655 static int nredir_size = 0; 1656 Str tmp; 1657 1658 if (pu == NULL) { 1659 nredir = 0; 1660 nredir_size = 0; 1661 puv = NULL; 1662 return TRUE; 1663 } 1664 if (nredir >= FollowRedirection) { 1665 /* FIXME: gettextize? */ 1666 tmp = Sprintf("Number of redirections exceeded %d at %s", 1667 FollowRedirection, parsedURL2Str(pu)->ptr); 1668 disp_err_message(tmp->ptr, FALSE); 1669 return FALSE; 1670 } 1671 else if (nredir_size > 0 && 1672 (same_url_p(pu, &puv[(nredir - 1) % nredir_size]) || 1673 (!(nredir % 2) 1674 && same_url_p(pu, &puv[(nredir / 2) % nredir_size])))) { 1675 /* FIXME: gettextize? */ 1676 tmp = Sprintf("Redirection loop detected (%s)", 1677 parsedURL2Str(pu)->ptr); 1678 disp_err_message(tmp->ptr, FALSE); 1679 return FALSE; 1680 } 1681 if (!puv) { 1682 nredir_size = FollowRedirection / 2 + 1; 1683 puv = New_N(ParsedURL, nredir_size); 1684 memset(puv, 0, sizeof(ParsedURL) * nredir_size); 1685 } 1686 copyParsedURL(&puv[nredir % nredir_size], pu); 1687 nredir++; 1688 return TRUE; 1689 } 1690 1691 Str 1692 getLinkNumberStr(int correction) 1693 { 1694 return Sprintf("[%d]", cur_hseq + correction); 1695 } 1696 1697 /* 1698 * loadGeneralFile: load file to buffer 1699 */ 1700 Buffer * 1701 loadGeneralFile(char *path, ParsedURL *volatile current, char *referer, 1702 int flag, FormList *volatile request) 1703 { 1704 URLFile f, *volatile of = NULL; 1705 ParsedURL pu; 1706 Buffer *b = NULL, *(*volatile proc)() = loadBuffer; 1707 char *volatile tpath; 1708 char *volatile t = "text/plain", *p, *volatile real_type = NULL; 1709 Buffer *volatile t_buf = NULL; 1710 int volatile searchHeader = SearchHeader; 1711 int volatile searchHeader_through = TRUE; 1712 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; 1713 TextList *extra_header = newTextList(); 1714 volatile Str uname = NULL; 1715 volatile Str pwd = NULL; 1716 volatile Str realm = NULL; 1717 int volatile add_auth_cookie_flag; 1718 unsigned char status = HTST_NORMAL; 1719 URLOption url_option; 1720 Str tmp; 1721 Str volatile page = NULL; 1722 #ifdef USE_M17N 1723 wc_ces charset = WC_CES_US_ASCII; 1724 #endif 1725 HRequest hr; 1726 ParsedURL *volatile auth_pu; 1727 1728 tpath = path; 1729 prevtrap = NULL; 1730 add_auth_cookie_flag = 0; 1731 1732 checkRedirection(NULL); 1733 load_doc: 1734 TRAP_OFF; 1735 url_option.referer = referer; 1736 url_option.flag = flag; 1737 f = openURL(tpath, &pu, current, &url_option, request, extra_header, of, 1738 &hr, &status); 1739 of = NULL; 1740 #ifdef USE_M17N 1741 content_charset = 0; 1742 #endif 1743 if (f.stream == NULL) { 1744 switch (f.scheme) { 1745 case SCM_LOCAL: 1746 { 1747 struct stat st; 1748 if (stat(pu.real_file, &st) < 0) 1749 return NULL; 1750 if (S_ISDIR(st.st_mode)) { 1751 if (UseExternalDirBuffer) { 1752 Str cmd = Sprintf("%s?dir=%s#current", 1753 DirBufferCommand, pu.file); 1754 b = loadGeneralFile(cmd->ptr, NULL, NO_REFERER, 0, 1755 NULL); 1756 if (b != NULL && b != NO_BUFFER) { 1757 copyParsedURL(&b->currentURL, &pu); 1758 b->filename = b->currentURL.real_file; 1759 } 1760 return b; 1761 } 1762 else { 1763 page = loadLocalDir(pu.real_file); 1764 t = "local:directory"; 1765 #ifdef USE_M17N 1766 charset = SystemCharset; 1767 #endif 1768 } 1769 } 1770 } 1771 break; 1772 case SCM_FTPDIR: 1773 page = loadFTPDir(&pu, &charset); 1774 t = "ftp:directory"; 1775 break; 1776 #ifdef USE_NNTP 1777 case SCM_NEWS_GROUP: 1778 page = loadNewsgroup(&pu, &charset); 1779 t = "news:group"; 1780 break; 1781 #endif 1782 case SCM_UNKNOWN: 1783 #ifdef USE_EXTERNAL_URI_LOADER 1784 tmp = searchURIMethods(&pu); 1785 if (tmp != NULL) { 1786 b = loadGeneralFile(tmp->ptr, current, referer, flag, request); 1787 if (b != NULL && b != NO_BUFFER) 1788 copyParsedURL(&b->currentURL, &pu); 1789 return b; 1790 } 1791 #endif 1792 /* FIXME: gettextize? */ 1793 disp_err_message(Sprintf("Unknown URI: %s", 1794 parsedURL2Str(&pu)->ptr)->ptr, FALSE); 1795 break; 1796 } 1797 if (page && page->length > 0) 1798 goto page_loaded; 1799 return NULL; 1800 } 1801 1802 if (status == HTST_MISSING) { 1803 TRAP_OFF; 1804 UFclose(&f); 1805 return NULL; 1806 } 1807 1808 /* openURL() succeeded */ 1809 if (SETJMP(AbortLoading) != 0) { 1810 /* transfer interrupted */ 1811 TRAP_OFF; 1812 if (b) 1813 discardBuffer(b); 1814 UFclose(&f); 1815 return NULL; 1816 } 1817 1818 b = NULL; 1819 if (f.is_cgi) { 1820 /* local CGI */ 1821 searchHeader = TRUE; 1822 searchHeader_through = FALSE; 1823 } 1824 if (header_string) 1825 header_string = NULL; 1826 TRAP_ON; 1827 if (pu.scheme == SCM_HTTP || 1828 #ifdef USE_SSL 1829 pu.scheme == SCM_HTTPS || 1830 #endif /* USE_SSL */ 1831 (( 1832 #ifdef USE_GOPHER 1833 (pu.scheme == SCM_GOPHER && non_null(GOPHER_proxy)) || 1834 #endif /* USE_GOPHER */ 1835 (pu.scheme == SCM_FTP && non_null(FTP_proxy)) 1836 ) && !Do_not_use_proxy && !check_no_proxy(pu.host))) { 1837 1838 if (fmInitialized) { 1839 term_cbreak(); 1840 /* FIXME: gettextize? */ 1841 message(Sprintf("%s contacted. Waiting for reply...", pu.host)-> 1842 ptr, 0, 0); 1843 refresh(); 1844 } 1845 if (t_buf == NULL) 1846 t_buf = newBuffer(INIT_BUFFER_WIDTH); 1847 #if 0 /* USE_SSL */ 1848 if (IStype(f.stream) == IST_SSL) { 1849 Str s = ssl_get_certificate(f.stream, pu.host); 1850 if (s == NULL) 1851 return NULL; 1852 else 1853 t_buf->ssl_certificate = s->ptr; 1854 } 1855 #endif 1856 readHeader(&f, t_buf, FALSE, &pu); 1857 if (((http_response_code >= 301 && http_response_code <= 303) 1858 || http_response_code == 307) 1859 && (p = checkHeader(t_buf, "Location:")) != NULL 1860 && checkRedirection(&pu)) { 1861 /* document moved */ 1862 /* 301: Moved Permanently */ 1863 /* 302: Found */ 1864 /* 303: See Other */ 1865 /* 307: Temporary Redirect (HTTP/1.1) */ 1866 tpath = url_quote_conv(p, DocumentCharset); 1867 request = NULL; 1868 UFclose(&f); 1869 current = New(ParsedURL); 1870 copyParsedURL(current, &pu); 1871 t_buf = newBuffer(INIT_BUFFER_WIDTH); 1872 t_buf->bufferprop |= BP_REDIRECTED; 1873 status = HTST_NORMAL; 1874 goto load_doc; 1875 } 1876 t = checkContentType(t_buf); 1877 if (t == NULL && pu.file != NULL) { 1878 if (!((http_response_code >= 400 && http_response_code <= 407) || 1879 (http_response_code >= 500 && http_response_code <= 505))) 1880 t = guessContentType(pu.file); 1881 } 1882 if (t == NULL) 1883 t = "text/plain"; 1884 if (add_auth_cookie_flag && realm && uname && pwd) { 1885 /* If authorization is required and passed */ 1886 add_auth_user_passwd(&pu, qstr_unquote(realm)->ptr, uname, pwd, 1887 0); 1888 add_auth_cookie_flag = 0; 1889 } 1890 if ((p = checkHeader(t_buf, "WWW-Authenticate:")) != NULL && 1891 http_response_code == 401) { 1892 /* Authentication needed */ 1893 struct http_auth hauth; 1894 if (findAuthentication(&hauth, t_buf, "WWW-Authenticate:") != NULL 1895 && (realm = get_auth_param(hauth.param, "realm")) != NULL) { 1896 auth_pu = &pu; 1897 getAuthCookie(&hauth, "Authorization:", extra_header, 1898 auth_pu, &hr, request, &uname, &pwd); 1899 if (uname == NULL) { 1900 /* abort */ 1901 TRAP_OFF; 1902 goto page_loaded; 1903 } 1904 UFclose(&f); 1905 add_auth_cookie_flag = 1; 1906 status = HTST_NORMAL; 1907 goto load_doc; 1908 } 1909 } 1910 if ((p = checkHeader(t_buf, "Proxy-Authenticate:")) != NULL && 1911 http_response_code == 407) { 1912 /* Authentication needed */ 1913 struct http_auth hauth; 1914 if (findAuthentication(&hauth, t_buf, "Proxy-Authenticate:") 1915 != NULL 1916 && (realm = get_auth_param(hauth.param, "realm")) != NULL) { 1917 auth_pu = schemeToProxy(pu.scheme); 1918 getAuthCookie(&hauth, "Proxy-Authorization:", 1919 extra_header, auth_pu, &hr, request, 1920 &uname, &pwd); 1921 if (uname == NULL) { 1922 /* abort */ 1923 TRAP_OFF; 1924 goto page_loaded; 1925 } 1926 UFclose(&f); 1927 add_auth_cookie_flag = 1; 1928 status = HTST_NORMAL; 1929 add_auth_user_passwd(auth_pu, qstr_unquote(realm)->ptr, uname, pwd, 1); 1930 goto load_doc; 1931 } 1932 } 1933 /* XXX: RFC2617 3.2.3 Authentication-Info: ? */ 1934 1935 if (status == HTST_CONNECT) { 1936 of = &f; 1937 goto load_doc; 1938 } 1939 1940 f.modtime = mymktime(checkHeader(t_buf, "Last-Modified:")); 1941 } 1942 #ifdef USE_NNTP 1943 else if (pu.scheme == SCM_NEWS || pu.scheme == SCM_NNTP) { 1944 if (t_buf == NULL) 1945 t_buf = newBuffer(INIT_BUFFER_WIDTH); 1946 readHeader(&f, t_buf, TRUE, &pu); 1947 t = checkContentType(t_buf); 1948 if (t == NULL) 1949 t = "text/plain"; 1950 } 1951 #endif /* USE_NNTP */ 1952 #ifdef USE_GOPHER 1953 else if (pu.scheme == SCM_GOPHER) { 1954 switch (*pu.file) { 1955 case '0': 1956 t = "text/plain"; 1957 break; 1958 case '1': 1959 case 'm': 1960 page = loadGopherDir(&f, &pu, &charset); 1961 t = "gopher:directory"; 1962 TRAP_OFF; 1963 goto page_loaded; 1964 case 's': 1965 t = "audio/basic"; 1966 break; 1967 case 'g': 1968 t = "image/gif"; 1969 break; 1970 case 'h': 1971 t = "text/html"; 1972 break; 1973 } 1974 } 1975 #endif /* USE_GOPHER */ 1976 else if (pu.scheme == SCM_FTP) { 1977 check_compression(path, &f); 1978 if (f.compression != CMP_NOCOMPRESS) { 1979 char *t1 = uncompressed_file_type(pu.file, NULL); 1980 real_type = f.guess_type; 1981 #if 0 1982 if (t1 && strncasecmp(t1, "application/", 12) == 0) { 1983 f.compression = CMP_NOCOMPRESS; 1984 t = real_type; 1985 } 1986 else 1987 #endif 1988 if (t1) 1989 t = t1; 1990 else 1991 t = real_type; 1992 } 1993 else { 1994 real_type = guessContentType(pu.file); 1995 if (real_type == NULL) 1996 real_type = "text/plain"; 1997 t = real_type; 1998 } 1999 #if 0 2000 if (!strncasecmp(t, "application/", 12)) { 2001 char *tmpf = tmpfname(TMPF_DFL, NULL)->ptr; 2002 current_content_length = 0; 2003 if (save2tmp(f, tmpf) < 0) 2004 UFclose(&f); 2005 else { 2006 UFclose(&f); 2007 TRAP_OFF; 2008 doFileMove(tmpf, guess_save_name(t_buf, pu.file)); 2009 } 2010 return NO_BUFFER; 2011 } 2012 #endif 2013 } 2014 else if (pu.scheme == SCM_DATA) { 2015 t = f.guess_type; 2016 } 2017 else if (searchHeader) { 2018 searchHeader = SearchHeader = FALSE; 2019 if (t_buf == NULL) 2020 t_buf = newBuffer(INIT_BUFFER_WIDTH); 2021 readHeader(&f, t_buf, searchHeader_through, &pu); 2022 if (f.is_cgi && (p = checkHeader(t_buf, "Location:")) != NULL && 2023 checkRedirection(&pu)) { 2024 /* document moved */ 2025 tpath = url_quote_conv(remove_space(p), DocumentCharset); 2026 request = NULL; 2027 UFclose(&f); 2028 add_auth_cookie_flag = 0; 2029 current = New(ParsedURL); 2030 copyParsedURL(current, &pu); 2031 t_buf = newBuffer(INIT_BUFFER_WIDTH); 2032 t_buf->bufferprop |= BP_REDIRECTED; 2033 status = HTST_NORMAL; 2034 goto load_doc; 2035 } 2036 #ifdef AUTH_DEBUG 2037 if ((p = checkHeader(t_buf, "WWW-Authenticate:")) != NULL) { 2038 /* Authentication needed */ 2039 struct http_auth hauth; 2040 if (findAuthentication(&hauth, t_buf, "WWW-Authenticate:") != NULL 2041 && (realm = get_auth_param(hauth.param, "realm")) != NULL) { 2042 auth_pu = &pu; 2043 getAuthCookie(&hauth, "Authorization:", extra_header, 2044 auth_pu, &hr, request, &uname, &pwd); 2045 if (uname == NULL) { 2046 /* abort */ 2047 TRAP_OFF; 2048 goto page_loaded; 2049 } 2050 UFclose(&f); 2051 add_auth_cookie_flag = 1; 2052 status = HTST_NORMAL; 2053 goto load_doc; 2054 } 2055 } 2056 #endif /* defined(AUTH_DEBUG) */ 2057 t = checkContentType(t_buf); 2058 if (t == NULL) 2059 t = "text/plain"; 2060 } 2061 else if (DefaultType) { 2062 t = DefaultType; 2063 DefaultType = NULL; 2064 } 2065 else { 2066 t = guessContentType(pu.file); 2067 if (t == NULL) 2068 t = "text/plain"; 2069 real_type = t; 2070 if (f.guess_type) 2071 t = f.guess_type; 2072 } 2073 2074 /* XXX: can we use guess_type to give the type to loadHTMLstream 2075 * to support default utf8 encoding for XHTML here? */ 2076 f.guess_type = t; 2077 2078 page_loaded: 2079 if (page) { 2080 FILE *src; 2081 #ifdef USE_IMAGE 2082 if (image_source) 2083 return NULL; 2084 #endif 2085 tmp = tmpfname(TMPF_SRC, ".html"); 2086 src = fopen(tmp->ptr, "w"); 2087 if (src) { 2088 Str s; 2089 s = wc_Str_conv_strict(page, InnerCharset, charset); 2090 Strfputs(s, src); 2091 fclose(src); 2092 } 2093 if (do_download) { 2094 char *file; 2095 if (!src) 2096 return NULL; 2097 file = guess_filename(pu.file); 2098 #ifdef USE_GOPHER 2099 if (f.scheme == SCM_GOPHER) 2100 file = Sprintf("%s.html", file)->ptr; 2101 #endif 2102 #ifdef USE_NNTP 2103 if (f.scheme == SCM_NEWS_GROUP) 2104 file = Sprintf("%s.html", file)->ptr; 2105 #endif 2106 doFileMove(tmp->ptr, file); 2107 return NO_BUFFER; 2108 } 2109 b = loadHTMLString(page); 2110 if (b) { 2111 copyParsedURL(&b->currentURL, &pu); 2112 b->real_scheme = pu.scheme; 2113 b->real_type = t; 2114 if (src) 2115 b->sourcefile = tmp->ptr; 2116 #ifdef USE_M17N 2117 b->document_charset = charset; 2118 #endif 2119 } 2120 return b; 2121 } 2122 2123 if (real_type == NULL) 2124 real_type = t; 2125 proc = loadBuffer; 2126 #ifdef USE_IMAGE 2127 cur_baseURL = New(ParsedURL); 2128 copyParsedURL(cur_baseURL, &pu); 2129 #endif 2130 2131 current_content_length = 0; 2132 if ((p = checkHeader(t_buf, "Content-Length:")) != NULL) 2133 current_content_length = strtoclen(p); 2134 if (do_download) { 2135 /* download only */ 2136 char *file; 2137 TRAP_OFF; 2138 if (DecodeCTE && IStype(f.stream) != IST_ENCODED) 2139 f.stream = newEncodedStream(f.stream, f.encoding); 2140 if (pu.scheme == SCM_LOCAL) { 2141 struct stat st; 2142 if (PreserveTimestamp && !stat(pu.real_file, &st)) 2143 f.modtime = st.st_mtime; 2144 file = conv_from_system(guess_save_name(NULL, pu.real_file)); 2145 } 2146 else 2147 file = guess_save_name(t_buf, pu.file); 2148 if (doFileSave(f, file) == 0) 2149 UFhalfclose(&f); 2150 else 2151 UFclose(&f); 2152 return NO_BUFFER; 2153 } 2154 2155 if ((f.content_encoding != CMP_NOCOMPRESS) && AutoUncompress 2156 && !(w3m_dump & DUMP_EXTRA)) { 2157 uncompress_stream(&f, &pu.real_file); 2158 } 2159 else if (f.compression != CMP_NOCOMPRESS) { 2160 if (!(w3m_dump & DUMP_SOURCE) && 2161 (w3m_dump & ~DUMP_FRAME || is_text_type(t) 2162 || searchExtViewer(t))) { 2163 if (t_buf == NULL) 2164 t_buf = newBuffer(INIT_BUFFER_WIDTH); 2165 uncompress_stream(&f, &t_buf->sourcefile); 2166 uncompressed_file_type(pu.file, &f.ext); 2167 } 2168 else { 2169 t = compress_application_type(f.compression); 2170 f.compression = CMP_NOCOMPRESS; 2171 } 2172 } 2173 #ifdef USE_IMAGE 2174 if (image_source) { 2175 Buffer *b = NULL; 2176 if (IStype(f.stream) != IST_ENCODED) 2177 f.stream = newEncodedStream(f.stream, f.encoding); 2178 if (save2tmp(f, image_source) == 0) { 2179 b = newBuffer(INIT_BUFFER_WIDTH); 2180 b->sourcefile = image_source; 2181 b->real_type = t; 2182 } 2183 UFclose(&f); 2184 TRAP_OFF; 2185 return b; 2186 } 2187 #endif 2188 2189 if (is_html_type(t)) 2190 proc = loadHTMLBuffer; 2191 else if (is_plain_text_type(t)) 2192 proc = loadBuffer; 2193 #ifdef USE_IMAGE 2194 else if (activeImage && displayImage && !useExtImageViewer && 2195 !(w3m_dump & ~DUMP_FRAME) && !strncasecmp(t, "image/", 6)) 2196 proc = loadImageBuffer; 2197 #endif 2198 else if (w3m_backend) ; 2199 else if (!(w3m_dump & ~DUMP_FRAME) || is_dump_text_type(t)) { 2200 if (!do_download && doExternal(f, 2201 pu.real_file ? pu.real_file : pu.file, 2202 t, &b, t_buf)) { 2203 if (b && b != NO_BUFFER) { 2204 b->real_scheme = f.scheme; 2205 b->real_type = real_type; 2206 if (b->currentURL.host == NULL && b->currentURL.file == NULL) 2207 copyParsedURL(&b->currentURL, &pu); 2208 } 2209 UFclose(&f); 2210 TRAP_OFF; 2211 return b; 2212 } 2213 else { 2214 TRAP_OFF; 2215 if (pu.scheme == SCM_LOCAL) { 2216 UFclose(&f); 2217 _doFileCopy(pu.real_file, 2218 conv_from_system(guess_save_name 2219 (NULL, pu.real_file)), TRUE); 2220 } 2221 else { 2222 if (DecodeCTE && IStype(f.stream) != IST_ENCODED) 2223 f.stream = newEncodedStream(f.stream, f.encoding); 2224 if (doFileSave(f, guess_save_name(t_buf, pu.file)) == 0) 2225 UFhalfclose(&f); 2226 else 2227 UFclose(&f); 2228 } 2229 return NO_BUFFER; 2230 } 2231 } 2232 else if (w3m_dump & DUMP_FRAME) 2233 return NULL; 2234 2235 if (flag & RG_FRAME) { 2236 if (t_buf == NULL) 2237 t_buf = newBuffer(INIT_BUFFER_WIDTH); 2238 t_buf->bufferprop |= BP_FRAME; 2239 } 2240 #ifdef USE_SSL 2241 if (t_buf) 2242 t_buf->ssl_certificate = f.ssl_certificate; 2243 #endif 2244 frame_source = flag & RG_FRAME_SRC; 2245 b = loadSomething(&f, pu.real_file ? pu.real_file : pu.file, proc, t_buf); 2246 UFclose(&f); 2247 frame_source = 0; 2248 if (b) { 2249 b->real_scheme = f.scheme; 2250 b->real_type = real_type; 2251 if (b->currentURL.host == NULL && b->currentURL.file == NULL) 2252 copyParsedURL(&b->currentURL, &pu); 2253 if (is_html_type(t)) 2254 b->type = "text/html"; 2255 else if (w3m_backend) { 2256 Str s = Strnew_charp(t); 2257 b->type = s->ptr; 2258 } 2259 #ifdef USE_IMAGE 2260 else if (proc == loadImageBuffer) 2261 b->type = "text/html"; 2262 #endif 2263 else 2264 b->type = "text/plain"; 2265 if (pu.label) { 2266 if (proc == loadHTMLBuffer) { 2267 Anchor *a; 2268 a = searchURLLabel(b, pu.label); 2269 if (a != NULL) { 2270 gotoLine(b, a->start.line); 2271 if (label_topline) 2272 b->topLine = lineSkip(b, b->topLine, 2273 b->currentLine->linenumber 2274 - b->topLine->linenumber, FALSE); 2275 b->pos = a->start.pos; 2276 arrangeCursor(b); 2277 } 2278 } 2279 else { /* plain text */ 2280 int l = atoi(pu.label); 2281 gotoRealLine(b, l); 2282 b->pos = 0; 2283 arrangeCursor(b); 2284 } 2285 } 2286 } 2287 if (header_string) 2288 header_string = NULL; 2289 #ifdef USE_NNTP 2290 if (f.scheme == SCM_NNTP || f.scheme == SCM_NEWS) 2291 reAnchorNewsheader(b); 2292 #endif 2293 preFormUpdateBuffer(b); 2294 TRAP_OFF; 2295 return b; 2296 } 2297 2298 #define TAG_IS(s,tag,len)\ 2299 (strncasecmp(s,tag,len)==0&&(s[len] == '>' || IS_SPACE((int)s[len]))) 2300 2301 static char * 2302 has_hidden_link(struct readbuffer *obuf, int cmd) 2303 { 2304 Str line = obuf->line; 2305 struct link_stack *p; 2306 2307 if (Strlastchar(line) != '>') 2308 return NULL; 2309 2310 for (p = link_stack; p; p = p->next) 2311 if (p->cmd == cmd) 2312 break; 2313 if (!p) 2314 return NULL; 2315 2316 if (obuf->pos == p->pos) 2317 return line->ptr + p->offset; 2318 2319 return NULL; 2320 } 2321 2322 static void 2323 push_link(int cmd, int offset, int pos) 2324 { 2325 struct link_stack *p; 2326 p = New(struct link_stack); 2327 p->cmd = cmd; 2328 p->offset = offset; 2329 p->pos = pos; 2330 p->next = link_stack; 2331 link_stack = p; 2332 } 2333 2334 static int 2335 is_period_char(unsigned char *ch) 2336 { 2337 switch (*ch) { 2338 case ',': 2339 case '.': 2340 case ':': 2341 case ';': 2342 case '?': 2343 case '!': 2344 case ')': 2345 case ']': 2346 case '}': 2347 case '>': 2348 return 1; 2349 default: 2350 return 0; 2351 } 2352 } 2353 2354 static int 2355 is_beginning_char(unsigned char *ch) 2356 { 2357 switch (*ch) { 2358 case '(': 2359 case '[': 2360 case '{': 2361 case '`': 2362 case '<': 2363 return 1; 2364 default: 2365 return 0; 2366 } 2367 } 2368 2369 static int 2370 is_word_char(unsigned char *ch) 2371 { 2372 Lineprop ctype = get_mctype(ch); 2373 2374 #ifdef USE_M17N 2375 if (ctype & (PC_CTRL | PC_KANJI | PC_UNKNOWN)) 2376 return 0; 2377 if (ctype & (PC_WCHAR1 | PC_WCHAR2)) 2378 return 1; 2379 #else 2380 if (ctype == PC_CTRL) 2381 return 0; 2382 #endif 2383 2384 if (IS_ALNUM(*ch)) 2385 return 1; 2386 2387 switch (*ch) { 2388 case ',': 2389 case '.': 2390 case ':': 2391 case '\"': /* " */ 2392 case '\'': 2393 case '$': 2394 case '%': 2395 case '*': 2396 case '+': 2397 case '-': 2398 case '@': 2399 case '~': 2400 case '_': 2401 return 1; 2402 } 2403 #ifdef USE_M17N 2404 if (*ch == NBSP_CODE) 2405 return 1; 2406 #else 2407 if (*ch == TIMES_CODE || *ch == DIVIDE_CODE || *ch == ANSP_CODE) 2408 return 0; 2409 if (*ch >= AGRAVE_CODE || *ch == NBSP_CODE) 2410 return 1; 2411 #endif 2412 return 0; 2413 } 2414 2415 #ifdef USE_M17N 2416 static int 2417 is_combining_char(unsigned char *ch) 2418 { 2419 Lineprop ctype = get_mctype(ch); 2420 2421 if (ctype & PC_WCHAR2) 2422 return 1; 2423 return 0; 2424 } 2425 #endif 2426 2427 int 2428 is_boundary(unsigned char *ch1, unsigned char *ch2) 2429 { 2430 if (!*ch1 || !*ch2) 2431 return 1; 2432 2433 if (*ch1 == ' ' && *ch2 == ' ') 2434 return 0; 2435 2436 if (*ch1 != ' ' && is_period_char(ch2)) 2437 return 0; 2438 2439 if (*ch2 != ' ' && is_beginning_char(ch1)) 2440 return 0; 2441 2442 #ifdef USE_M17N 2443 if (is_combining_char(ch2)) 2444 return 0; 2445 #endif 2446 if (is_word_char(ch1) && is_word_char(ch2)) 2447 return 0; 2448 2449 return 1; 2450 } 2451 2452 2453 static void 2454 set_breakpoint(struct readbuffer *obuf, int tag_length) 2455 { 2456 obuf->bp.len = obuf->line->length; 2457 obuf->bp.pos = obuf->pos; 2458 obuf->bp.tlen = tag_length; 2459 obuf->bp.flag = obuf->flag; 2460 #ifdef FORMAT_NICE 2461 obuf->bp.flag &= ~RB_FILL; 2462 #endif /* FORMAT_NICE */ 2463 obuf->bp.top_margin = obuf->top_margin; 2464 obuf->bp.bottom_margin = obuf->bottom_margin; 2465 2466 if (!obuf->bp.init_flag) 2467 return; 2468 2469 bcopy((void *)&obuf->anchor, (void *)&obuf->bp.anchor, 2470 sizeof(obuf->anchor)); 2471 obuf->bp.img_alt = obuf->img_alt; 2472 obuf->bp.in_bold = obuf->in_bold; 2473 obuf->bp.in_italic = obuf->in_italic; 2474 obuf->bp.in_under = obuf->in_under; 2475 obuf->bp.in_strike = obuf->in_strike; 2476 obuf->bp.in_ins = obuf->in_ins; 2477 obuf->bp.nobr_level = obuf->nobr_level; 2478 obuf->bp.prev_ctype = obuf->prev_ctype; 2479 obuf->bp.init_flag = 0; 2480 } 2481 2482 static void 2483 back_to_breakpoint(struct readbuffer *obuf) 2484 { 2485 obuf->flag = obuf->bp.flag; 2486 bcopy((void *)&obuf->bp.anchor, (void *)&obuf->anchor, 2487 sizeof(obuf->anchor)); 2488 obuf->img_alt = obuf->bp.img_alt; 2489 obuf->in_bold = obuf->bp.in_bold; 2490 obuf->in_italic = obuf->bp.in_italic; 2491 obuf->in_under = obuf->bp.in_under; 2492 obuf->in_strike = obuf->bp.in_strike; 2493 obuf->in_ins = obuf->bp.in_ins; 2494 obuf->prev_ctype = obuf->bp.prev_ctype; 2495 obuf->pos = obuf->bp.pos; 2496 obuf->top_margin = obuf->bp.top_margin; 2497 obuf->bottom_margin = obuf->bp.bottom_margin; 2498 if (obuf->flag & RB_NOBR) 2499 obuf->nobr_level = obuf->bp.nobr_level; 2500 } 2501 2502 static void 2503 append_tags(struct readbuffer *obuf) 2504 { 2505 int i; 2506 int len = obuf->line->length; 2507 int set_bp = 0; 2508 2509 for (i = 0; i < obuf->tag_sp; i++) { 2510 switch (obuf->tag_stack[i]->cmd) { 2511 case HTML_A: 2512 case HTML_IMG_ALT: 2513 case HTML_B: 2514 case HTML_U: 2515 case HTML_I: 2516 case HTML_S: 2517 push_link(obuf->tag_stack[i]->cmd, obuf->line->length, obuf->pos); 2518 break; 2519 } 2520 Strcat_charp(obuf->line, obuf->tag_stack[i]->cmdname); 2521 switch (obuf->tag_stack[i]->cmd) { 2522 case HTML_NOBR: 2523 if (obuf->nobr_level > 1) 2524 break; 2525 case HTML_WBR: 2526 set_bp = 1; 2527 break; 2528 } 2529 } 2530 obuf->tag_sp = 0; 2531 if (set_bp) 2532 set_breakpoint(obuf, obuf->line->length - len); 2533 } 2534 2535 static void 2536 push_tag(struct readbuffer *obuf, char *cmdname, int cmd) 2537 { 2538 obuf->tag_stack[obuf->tag_sp] = New(struct cmdtable); 2539 obuf->tag_stack[obuf->tag_sp]->cmdname = allocStr(cmdname, -1); 2540 obuf->tag_stack[obuf->tag_sp]->cmd = cmd; 2541 obuf->tag_sp++; 2542 if (obuf->tag_sp >= TAG_STACK_SIZE || obuf->flag & (RB_SPECIAL & ~RB_NOBR)) 2543 append_tags(obuf); 2544 } 2545 2546 static void 2547 push_nchars(struct readbuffer *obuf, int width, 2548 char *str, int len, Lineprop mode) 2549 { 2550 append_tags(obuf); 2551 Strcat_charp_n(obuf->line, str, len); 2552 obuf->pos += width; 2553 if (width > 0) { 2554 set_prevchar(obuf->prevchar, str, len); 2555 obuf->prev_ctype = mode; 2556 } 2557 obuf->flag |= RB_NFLUSHED; 2558 } 2559 2560 #define push_charp(obuf, width, str, mode)\ 2561 push_nchars(obuf, width, str, strlen(str), mode) 2562 2563 #define push_str(obuf, width, str, mode)\ 2564 push_nchars(obuf, width, str->ptr, str->length, mode) 2565 2566 static void 2567 check_breakpoint(struct readbuffer *obuf, int pre_mode, char *ch) 2568 { 2569 int tlen, len = obuf->line->length; 2570 2571 append_tags(obuf); 2572 if (pre_mode) 2573 return; 2574 tlen = obuf->line->length - len; 2575 if (tlen > 0 2576 || is_boundary((unsigned char *)obuf->prevchar->ptr, 2577 (unsigned char *)ch)) 2578 set_breakpoint(obuf, tlen); 2579 } 2580 2581 static void 2582 push_char(struct readbuffer *obuf, int pre_mode, char ch) 2583 { 2584 check_breakpoint(obuf, pre_mode, &ch); 2585 Strcat_char(obuf->line, ch); 2586 obuf->pos++; 2587 set_prevchar(obuf->prevchar, &ch, 1); 2588 if (ch != ' ') 2589 obuf->prev_ctype = PC_ASCII; 2590 obuf->flag |= RB_NFLUSHED; 2591 } 2592 2593 #define PUSH(c) push_char(obuf, obuf->flag & RB_SPECIAL, c) 2594 2595 static void 2596 push_spaces(struct readbuffer *obuf, int pre_mode, int width) 2597 { 2598 int i; 2599 2600 if (width <= 0) 2601 return; 2602 check_breakpoint(obuf, pre_mode, " "); 2603 for (i = 0; i < width; i++) 2604 Strcat_char(obuf->line, ' '); 2605 obuf->pos += width; 2606 set_space_to_prevchar(obuf->prevchar); 2607 obuf->flag |= RB_NFLUSHED; 2608 } 2609 2610 static void 2611 proc_mchar(struct readbuffer *obuf, int pre_mode, 2612 int width, char **str, Lineprop mode) 2613 { 2614 check_breakpoint(obuf, pre_mode, *str); 2615 obuf->pos += width; 2616 Strcat_charp_n(obuf->line, *str, get_mclen(*str)); 2617 if (width > 0) { 2618 set_prevchar(obuf->prevchar, *str, 1); 2619 if (**str != ' ') 2620 obuf->prev_ctype = mode; 2621 } 2622 (*str) += get_mclen(*str); 2623 obuf->flag |= RB_NFLUSHED; 2624 } 2625 2626 void 2627 push_render_image(Str str, int width, int limit, 2628 struct html_feed_environ *h_env) 2629 { 2630 struct readbuffer *obuf = h_env->obuf; 2631 int indent = h_env->envs[h_env->envc].indent; 2632 2633 push_spaces(obuf, 1, (limit - width) / 2); 2634 push_str(obuf, width, str, PC_ASCII); 2635 push_spaces(obuf, 1, (limit - width + 1) / 2); 2636 if (width > 0) 2637 flushline(h_env, obuf, indent, 0, h_env->limit); 2638 } 2639 2640 static int 2641 sloppy_parse_line(char **str) 2642 { 2643 if (**str == '<') { 2644 while (**str && **str != '>') 2645 (*str)++; 2646 if (**str == '>') 2647 (*str)++; 2648 return 1; 2649 } 2650 else { 2651 while (**str && **str != '<') 2652 (*str)++; 2653 return 0; 2654 } 2655 } 2656 2657 static void 2658 passthrough(struct readbuffer *obuf, char *str, int back) 2659 { 2660 int cmd; 2661 Str tok = Strnew(); 2662 char *str_bak; 2663 2664 if (back) { 2665 Str str_save = Strnew_charp(str); 2666 Strshrink(obuf->line, obuf->line->ptr + obuf->line->length - str); 2667 str = str_save->ptr; 2668 } 2669 while (*str) { 2670 str_bak = str; 2671 if (sloppy_parse_line(&str)) { 2672 char *q = str_bak; 2673 cmd = gethtmlcmd(&q); 2674 if (back) { 2675 struct link_stack *p; 2676 for (p = link_stack; p; p = p->next) { 2677 if (p->cmd == cmd) { 2678 link_stack = p->next; 2679 break; 2680 } 2681 } 2682 back = 0; 2683 } 2684 else { 2685 Strcat_charp_n(tok, str_bak, str - str_bak); 2686 push_tag(obuf, tok->ptr, cmd); 2687 Strclear(tok); 2688 } 2689 } 2690 else { 2691 push_nchars(obuf, 0, str_bak, str - str_bak, obuf->prev_ctype); 2692 } 2693 } 2694 } 2695 2696 #if 0 2697 int 2698 is_blank_line(char *line, int indent) 2699 { 2700 int i, is_blank = 0; 2701 2702 for (i = 0; i < indent; i++) { 2703 if (line[i] == '\0') { 2704 is_blank = 1; 2705 } 2706 else if (line[i] != ' ') { 2707 break; 2708 } 2709 } 2710 if (i == indent && line[i] == '\0') 2711 is_blank = 1; 2712 return is_blank; 2713 } 2714 #endif 2715 2716 void 2717 fillline(struct readbuffer *obuf, int indent) 2718 { 2719 push_spaces(obuf, 1, indent - obuf->pos); 2720 obuf->flag &= ~RB_NFLUSHED; 2721 } 2722 2723 void 2724 flushline(struct html_feed_environ *h_env, struct readbuffer *obuf, int indent, 2725 int force, int width) 2726 { 2727 TextLineList *buf = h_env->buf; 2728 FILE *f = h_env->f; 2729 Str line = obuf->line, pass = NULL; 2730 char *hidden_anchor = NULL, *hidden_img = NULL, *hidden_bold = NULL, 2731 *hidden_under = NULL, *hidden_italic = NULL, *hidden_strike = NULL, 2732 *hidden_ins = NULL, *hidden = NULL; 2733 2734 #ifdef DEBUG 2735 if (w3m_debug) { 2736 FILE *df = fopen("zzzproc1", "a"); 2737 fprintf(df, "flushline(%s,%d,%d,%d)\n", obuf->line->ptr, indent, force, 2738 width); 2739 if (buf) { 2740 TextLineListItem *p; 2741 for (p = buf->first; p; p = p->next) { 2742 fprintf(df, "buf=\"%s\"\n", p->ptr->line->ptr); 2743 } 2744 } 2745 fclose(df); 2746 } 2747 #endif 2748 2749 if (!(obuf->flag & (RB_SPECIAL & ~RB_NOBR)) && Strlastchar(line) == ' ') { 2750 Strshrink(line, 1); 2751 obuf->pos--; 2752 } 2753 2754 append_tags(obuf); 2755 2756 if (obuf->anchor.url) 2757 hidden = hidden_anchor = has_hidden_link(obuf, HTML_A); 2758 if (obuf->img_alt) { 2759 if ((hidden_img = has_hidden_link(obuf, HTML_IMG_ALT)) != NULL) { 2760 if (!hidden || hidden_img < hidden) 2761 hidden = hidden_img; 2762 } 2763 } 2764 if (obuf->in_bold) { 2765 if ((hidden_bold = has_hidden_link(obuf, HTML_B)) != NULL) { 2766 if (!hidden || hidden_bold < hidden) 2767 hidden = hidden_bold; 2768 } 2769 } 2770 if (obuf->in_italic) { 2771 if ((hidden_italic = has_hidden_link(obuf, HTML_I)) != NULL) { 2772 if (!hidden || hidden_italic < hidden) 2773 hidden = hidden_italic; 2774 } 2775 } 2776 if (obuf->in_under) { 2777 if ((hidden_under = has_hidden_link(obuf, HTML_U)) != NULL) { 2778 if (!hidden || hidden_under < hidden) 2779 hidden = hidden_under; 2780 } 2781 } 2782 if (obuf->in_strike) { 2783 if ((hidden_strike = has_hidden_link(obuf, HTML_S)) != NULL) { 2784 if (!hidden || hidden_strike < hidden) 2785 hidden = hidden_strike; 2786 } 2787 } 2788 if (obuf->in_ins) { 2789 if ((hidden_ins = has_hidden_link(obuf, HTML_INS)) != NULL) { 2790 if (!hidden || hidden_ins < hidden) 2791 hidden = hidden_ins; 2792 } 2793 } 2794 if (hidden) { 2795 pass = Strnew_charp(hidden); 2796 Strshrink(line, line->ptr + line->length - hidden); 2797 } 2798 2799 if (!(obuf->flag & (RB_SPECIAL & ~RB_NOBR)) && obuf->pos > width) { 2800 char *tp = &line->ptr[obuf->bp.len - obuf->bp.tlen]; 2801 char *ep = &line->ptr[line->length]; 2802 2803 if (obuf->bp.pos == obuf->pos && tp <= ep && 2804 tp > line->ptr && tp[-1] == ' ') { 2805 bcopy(tp, tp - 1, ep - tp + 1); 2806 line->length--; 2807 obuf->pos--; 2808 } 2809 } 2810 2811 if (obuf->anchor.url && !hidden_anchor) 2812 Strcat_charp(line, "</a>"); 2813 if (obuf->img_alt && !hidden_img) 2814 Strcat_charp(line, "</img_alt>"); 2815 if (obuf->in_bold && !hidden_bold) 2816 Strcat_charp(line, "</b>"); 2817 if (obuf->in_italic && !hidden_italic) 2818 Strcat_charp(line, "</i>"); 2819 if (obuf->in_under && !hidden_under) 2820 Strcat_charp(line, "</u>"); 2821 if (obuf->in_strike && !hidden_strike) 2822 Strcat_charp(line, "</s>"); 2823 if (obuf->in_ins && !hidden_ins) 2824 Strcat_charp(line, "</ins>"); 2825 2826 if (obuf->top_margin > 0) { 2827 int i; 2828 struct html_feed_environ h; 2829 struct readbuffer o; 2830 struct environment e[1]; 2831 2832 init_henv(&h, &o, e, 1, NULL, width, indent); 2833 o.line = Strnew_size(width + 20); 2834 o.pos = obuf->pos; 2835 o.flag = obuf->flag; 2836 o.top_margin = -1; 2837 o.bottom_margin = -1; 2838 Strcat_charp(o.line, "<pre_int>"); 2839 for (i = 0; i < o.pos; i++) 2840 Strcat_char(o.line, ' '); 2841 Strcat_charp(o.line, "</pre_int>"); 2842 for (i = 0; i < obuf->top_margin; i++) 2843 flushline(h_env, &o, indent, force, width); 2844 } 2845 2846 if (force == 1 || obuf->flag & RB_NFLUSHED) { 2847 TextLine *lbuf = newTextLine(line, obuf->pos); 2848 if (RB_GET_ALIGN(obuf) == RB_CENTER) { 2849 align(lbuf, width, ALIGN_CENTER); 2850 } 2851 else if (RB_GET_ALIGN(obuf) == RB_RIGHT) { 2852 align(lbuf, width, ALIGN_RIGHT); 2853 } 2854 else if (RB_GET_ALIGN(obuf) == RB_LEFT && obuf->flag & RB_INTABLE) { 2855 align(lbuf, width, ALIGN_LEFT); 2856 } 2857 #ifdef FORMAT_NICE 2858 else if (obuf->flag & RB_FILL) { 2859 char *p; 2860 int rest, rrest; 2861 int nspace, d, i; 2862 2863 rest = width - get_Str_strwidth(line); 2864 if (rest > 1) { 2865 nspace = 0; 2866 for (p = line->ptr + indent; *p; p++) { 2867 if (*p == ' ') 2868 nspace++; 2869 } 2870 if (nspace > 0) { 2871 int indent_here = 0; 2872 d = rest / nspace; 2873 p = line->ptr; 2874 while (IS_SPACE(*p)) { 2875 p++; 2876 indent_here++; 2877 } 2878 rrest = rest - d * nspace; 2879 line = Strnew_size(width + 1); 2880 for (i = 0; i < indent_here; i++) 2881 Strcat_char(line, ' '); 2882 for (; *p; p++) { 2883 Strcat_char(line, *p); 2884 if (*p == ' ') { 2885 for (i = 0; i < d; i++) 2886 Strcat_char(line, ' '); 2887 if (rrest > 0) { 2888 Strcat_char(line, ' '); 2889 rrest--; 2890 } 2891 } 2892 } 2893 lbuf = newTextLine(line, width); 2894 } 2895 } 2896 } 2897 #endif /* FORMAT_NICE */ 2898 #ifdef TABLE_DEBUG 2899 if (w3m_debug) { 2900 FILE *f = fopen("zzzproc1", "a"); 2901 fprintf(f, "pos=%d,%d, maxlimit=%d\n", 2902 visible_length(lbuf->line->ptr), lbuf->pos, 2903 h_env->maxlimit); 2904 fclose(f); 2905 } 2906 #endif 2907 if (lbuf->pos > h_env->maxlimit) 2908 h_env->maxlimit = lbuf->pos; 2909 if (buf) 2910 pushTextLine(buf, lbuf); 2911 else if (f) { 2912 Strfputs(Str_conv_to_halfdump(lbuf->line), f); 2913 fputc('\n', f); 2914 } 2915 if (obuf->flag & RB_SPECIAL || obuf->flag & RB_NFLUSHED) 2916 h_env->blank_lines = 0; 2917 else 2918 h_env->blank_lines++; 2919 } 2920 else { 2921 char *p = line->ptr, *q; 2922 Str tmp = Strnew(), tmp2 = Strnew(); 2923 2924 #define APPEND(str) \ 2925 if (buf) \ 2926 appendTextLine(buf,(str),0); \ 2927 else if (f) \ 2928 Strfputs((str),f) 2929 2930 while (*p) { 2931 q = p; 2932 if (sloppy_parse_line(&p)) { 2933 Strcat_charp_n(tmp, q, p - q); 2934 if (force == 2) { 2935 APPEND(tmp); 2936 } 2937 else 2938 Strcat(tmp2, tmp); 2939 Strclear(tmp); 2940 } 2941 } 2942 if (force == 2) { 2943 if (pass) { 2944 APPEND(pass); 2945 } 2946 pass = NULL; 2947 } 2948 else { 2949 if (pass) 2950 Strcat(tmp2, pass); 2951 pass = tmp2; 2952 } 2953 } 2954 2955 if (obuf->bottom_margin > 0) { 2956 int i; 2957 struct html_feed_environ h; 2958 struct readbuffer o; 2959 struct environment e[1]; 2960 2961 init_henv(&h, &o, e, 1, NULL, width, indent); 2962 o.line = Strnew_size(width + 20); 2963 o.pos = obuf->pos; 2964 o.flag = obuf->flag; 2965 o.top_margin = -1; 2966 o.bottom_margin = -1; 2967 Strcat_charp(o.line, "<pre_int>"); 2968 for (i = 0; i < o.pos; i++) 2969 Strcat_char(o.line, ' '); 2970 Strcat_charp(o.line, "</pre_int>"); 2971 for (i = 0; i < obuf->bottom_margin; i++) 2972 flushline(h_env, &o, indent, force, width); 2973 } 2974 if (obuf->top_margin < 0 || obuf->bottom_margin < 0) 2975 return; 2976 2977 obuf->line = Strnew_size(256); 2978 obuf->pos = 0; 2979 obuf->top_margin = 0; 2980 obuf->bottom_margin = 0; 2981 set_space_to_prevchar(obuf->prevchar); 2982 obuf->bp.init_flag = 1; 2983 obuf->flag &= ~RB_NFLUSHED; 2984 set_breakpoint(obuf, 0); 2985 obuf->prev_ctype = PC_ASCII; 2986 link_stack = NULL; 2987 fillline(obuf, indent); 2988 if (pass) 2989 passthrough(obuf, pass->ptr, 0); 2990 if (!hidden_anchor && obuf->anchor.url) { 2991 Str tmp; 2992 if (obuf->anchor.hseq > 0) 2993 obuf->anchor.hseq = -obuf->anchor.hseq; 2994 tmp = Sprintf("<A HSEQ=\"%d\" HREF=\"", obuf->anchor.hseq); 2995 Strcat_charp(tmp, html_quote(obuf->anchor.url)); 2996 if (obuf->anchor.target) { 2997 Strcat_charp(tmp, "\" TARGET=\""); 2998 Strcat_charp(tmp, html_quote(obuf->anchor.target)); 2999 } 3000 if (obuf->anchor.referer) { 3001 Strcat_charp(tmp, "\" REFERER=\""); 3002 Strcat_charp(tmp, html_quote(obuf->anchor.referer)); 3003 } 3004 if (obuf->anchor.title) { 3005 Strcat_charp(tmp, "\" TITLE=\""); 3006 Strcat_charp(tmp, html_quote(obuf->anchor.title)); 3007 } 3008 if (obuf->anchor.accesskey) { 3009 char *c = html_quote_char(obuf->anchor.accesskey); 3010 Strcat_charp(tmp, "\" ACCESSKEY=\""); 3011 if (c) 3012 Strcat_charp(tmp, c); 3013 else 3014 Strcat_char(tmp, obuf->anchor.accesskey); 3015 } 3016 Strcat_charp(tmp, "\">"); 3017 push_tag(obuf, tmp->ptr, HTML_A); 3018 } 3019 if (!hidden_img && obuf->img_alt) { 3020 Str tmp = Strnew_charp("<IMG_ALT SRC=\""); 3021 Strcat_charp(tmp, html_quote(obuf->img_alt->ptr)); 3022 Strcat_charp(tmp, "\">"); 3023 push_tag(obuf, tmp->ptr, HTML_IMG_ALT); 3024 } 3025 if (!hidden_bold && obuf->in_bold) 3026 push_tag(obuf, "<B>", HTML_B); 3027 if (!hidden_italic && obuf->in_italic) 3028 push_tag(obuf, "<I>", HTML_I); 3029 if (!hidden_under && obuf->in_under) 3030 push_tag(obuf, "<U>", HTML_U); 3031 if (!hidden_strike && obuf->in_strike) 3032 push_tag(obuf, "<S>", HTML_S); 3033 if (!hidden_ins && obuf->in_ins) 3034 push_tag(obuf, "<INS>", HTML_INS); 3035 } 3036 3037 void 3038 do_blankline(struct html_feed_environ *h_env, struct readbuffer *obuf, 3039 int indent, int indent_incr, int width) 3040 { 3041 if (h_env->blank_lines == 0) 3042 flushline(h_env, obuf, indent, 1, width); 3043 } 3044 3045 void 3046 purgeline(struct html_feed_environ *h_env) 3047 { 3048 char *p, *q; 3049 Str tmp; 3050 3051 if (h_env->buf == NULL || h_env->blank_lines == 0) 3052 return; 3053 3054 p = rpopTextLine(h_env->buf)->line->ptr; 3055 tmp = Strnew(); 3056 while (*p) { 3057 q = p; 3058 if (sloppy_parse_line(&p)) { 3059 Strcat_charp_n(tmp, q, p - q); 3060 } 3061 } 3062 appendTextLine(h_env->buf, tmp, 0); 3063 h_env->blank_lines--; 3064 } 3065 3066 static int 3067 close_effect0(struct readbuffer *obuf, int cmd) 3068 { 3069 int i; 3070 char *p; 3071 3072 for (i = obuf->tag_sp - 1; i >= 0; i--) { 3073 if (obuf->tag_stack[i]->cmd == cmd) 3074 break; 3075 } 3076 if (i >= 0) { 3077 obuf->tag_sp--; 3078 bcopy(&obuf->tag_stack[i + 1], &obuf->tag_stack[i], 3079 (obuf->tag_sp - i) * sizeof(struct cmdtable *)); 3080 return 1; 3081 } 3082 else if ((p = has_hidden_link(obuf, cmd)) != NULL) { 3083 passthrough(obuf, p, 1); 3084 return 1; 3085 } 3086 return 0; 3087 } 3088 3089 static void 3090 close_anchor(struct html_feed_environ *h_env, struct readbuffer *obuf) 3091 { 3092 if (obuf->anchor.url) { 3093 int i; 3094 char *p = NULL; 3095 int is_erased = 0; 3096 3097 for (i = obuf->tag_sp - 1; i >= 0; i--) { 3098 if (obuf->tag_stack[i]->cmd == HTML_A) 3099 break; 3100 } 3101 if (i < 0 && obuf->anchor.hseq > 0 && Strlastchar(obuf->line) == ' ') { 3102 Strshrink(obuf->line, 1); 3103 obuf->pos--; 3104 is_erased = 1; 3105 } 3106 3107 if (i >= 0 || (p = has_hidden_link(obuf, HTML_A))) { 3108 if (obuf->anchor.hseq > 0) { 3109 HTMLlineproc1(ANSP, h_env); 3110 set_space_to_prevchar(obuf->prevchar); 3111 } 3112 else { 3113 if (i >= 0) { 3114 obuf->tag_sp--; 3115 bcopy(&obuf->tag_stack[i + 1], &obuf->tag_stack[i], 3116 (obuf->tag_sp - i) * sizeof(struct cmdtable *)); 3117 } 3118 else { 3119 passthrough(obuf, p, 1); 3120 } 3121 bzero((void *)&obuf->anchor, sizeof(obuf->anchor)); 3122 return; 3123 } 3124 is_erased = 0; 3125 } 3126 if (is_erased) { 3127 Strcat_char(obuf->line, ' '); 3128 obuf->pos++; 3129 } 3130 3131 push_tag(obuf, "</a>", HTML_N_A); 3132 } 3133 bzero((void *)&obuf->anchor, sizeof(obuf->anchor)); 3134 } 3135 3136 void 3137 save_fonteffect(struct html_feed_environ *h_env, struct readbuffer *obuf) 3138 { 3139 if (obuf->fontstat_sp < FONT_STACK_SIZE) 3140 bcopy(obuf->fontstat, obuf->fontstat_stack[obuf->fontstat_sp], 3141 FONTSTAT_SIZE); 3142 obuf->fontstat_sp++; 3143 if (obuf->in_bold) 3144 push_tag(obuf, "</b>", HTML_N_B); 3145 if (obuf->in_italic) 3146 push_tag(obuf, "</i>", HTML_N_I); 3147 if (obuf->in_under) 3148 push_tag(obuf, "</u>", HTML_N_U); 3149 if (obuf->in_strike) 3150 push_tag(obuf, "</s>", HTML_N_S); 3151 if (obuf->in_ins) 3152 push_tag(obuf, "</ins>", HTML_N_INS); 3153 bzero(obuf->fontstat, FONTSTAT_SIZE); 3154 } 3155 3156 void 3157 restore_fonteffect(struct html_feed_environ *h_env, struct readbuffer *obuf) 3158 { 3159 if (obuf->fontstat_sp > 0) 3160 obuf->fontstat_sp--; 3161 if (obuf->fontstat_sp < FONT_STACK_SIZE) 3162 bcopy(obuf->fontstat_stack[obuf->fontstat_sp], obuf->fontstat, 3163 FONTSTAT_SIZE); 3164 if (obuf->in_bold) 3165 push_tag(obuf, "<b>", HTML_B); 3166 if (obuf->in_italic) 3167 push_tag(obuf, "<i>", HTML_I); 3168 if (obuf->in_under) 3169 push_tag(obuf, "<u>", HTML_U); 3170 if (obuf->in_strike) 3171 push_tag(obuf, "<s>", HTML_S); 3172 if (obuf->in_ins) 3173 push_tag(obuf, "<ins>", HTML_INS); 3174 } 3175 3176 static Str 3177 process_title(struct parsed_tag *tag) 3178 { 3179 cur_title = Strnew(); 3180 return NULL; 3181 } 3182 3183 static Str 3184 process_n_title(struct parsed_tag *tag) 3185 { 3186 Str tmp; 3187 3188 if (!cur_title) 3189 return NULL; 3190 Strremovefirstspaces(cur_title); 3191 Strremovetrailingspaces(cur_title); 3192 tmp = Strnew_m_charp("<title_alt title=\"", 3193 html_quote(cur_title->ptr), "\">", NULL); 3194 cur_title = NULL; 3195 return tmp; 3196 } 3197 3198 static void 3199 feed_title(char *str) 3200 { 3201 if (!cur_title) 3202 return; 3203 while (*str) { 3204 if (*str == '&') 3205 Strcat_charp(cur_title, getescapecmd(&str)); 3206 else if (*str == '\n' || *str == '\r') { 3207 Strcat_char(cur_title, ' '); 3208 str++; 3209 } 3210 else 3211 Strcat_char(cur_title, *(str++)); 3212 } 3213 } 3214 3215 Str 3216 process_img(struct parsed_tag *tag, int width) 3217 { 3218 char *p, *q, *r, *r2 = NULL, *s, *t; 3219 #ifdef USE_IMAGE 3220 int w, i, nw, ni = 1, n, w0 = -1, i0 = -1; 3221 int align, xoffset, yoffset, top, bottom, ismap = 0; 3222 int use_image = activeImage && displayImage; 3223 #else 3224 int w, i, nw, n; 3225 #endif 3226 int pre_int = FALSE, ext_pre_int = FALSE; 3227 Str tmp = Strnew(); 3228 3229 if (!parsedtag_get_value(tag, ATTR_SRC, &p)) 3230 return tmp; 3231 p = remove_space(p); 3232 q = NULL; 3233 parsedtag_get_value(tag, ATTR_ALT, &q); 3234 if (!pseudoInlines && (q == NULL || (*q == '\0' && ignore_null_img_alt))) 3235 return tmp; 3236 t = q; 3237 parsedtag_get_value(tag, ATTR_TITLE, &t); 3238 w = -1; 3239 if (parsedtag_get_value(tag, ATTR_WIDTH, &w)) { 3240 if (w < 0) { 3241 if (width > 0) 3242 w = (int)(-width * pixel_per_char * w / 100 + 0.5); 3243 else 3244 w = -1; 3245 } 3246 #ifdef USE_IMAGE 3247 if (use_image) { 3248 if (w > 0) { 3249 w = (int)(w * image_scale / 100 + 0.5); 3250 if (w == 0) 3251 w = 1; 3252 else if (w > MAX_IMAGE_SIZE) 3253 w = MAX_IMAGE_SIZE; 3254 } 3255 } 3256 #endif 3257 } 3258 #ifdef USE_IMAGE 3259 if (use_image) { 3260 i = -1; 3261 if (parsedtag_get_value(tag, ATTR_HEIGHT, &i)) { 3262 if (i > 0) { 3263 i = (int)(i * image_scale / 100 + 0.5); 3264 if (i == 0) 3265 i = 1; 3266 else if (i > MAX_IMAGE_SIZE) 3267 i = MAX_IMAGE_SIZE; 3268 } 3269 else { 3270 i = -1; 3271 } 3272 } 3273 align = -1; 3274 parsedtag_get_value(tag, ATTR_ALIGN, &align); 3275 ismap = 0; 3276 if (parsedtag_exists(tag, ATTR_ISMAP)) 3277 ismap = 1; 3278 } 3279 else 3280 #endif 3281 parsedtag_get_value(tag, ATTR_HEIGHT, &i); 3282 r = NULL; 3283 parsedtag_get_value(tag, ATTR_USEMAP, &r); 3284 if (parsedtag_exists(tag, ATTR_PRE_INT)) 3285 ext_pre_int = TRUE; 3286 3287 tmp = Strnew_size(128); 3288 #ifdef USE_IMAGE 3289 if (use_image) { 3290 switch (align) { 3291 case ALIGN_LEFT: 3292 Strcat_charp(tmp, "<div_int align=left>"); 3293 break; 3294 case ALIGN_CENTER: 3295 Strcat_charp(tmp, "<div_int align=center>"); 3296 break; 3297 case ALIGN_RIGHT: 3298 Strcat_charp(tmp, "<div_int align=right>"); 3299 break; 3300 } 3301 } 3302 #endif 3303 if (r) { 3304 Str tmp2; 3305 r2 = strchr(r, '#'); 3306 s = "<form_int method=internal action=map>"; 3307 tmp2 = process_form(parse_tag(&s, TRUE)); 3308 if (tmp2) 3309 Strcat(tmp, tmp2); 3310 Strcat(tmp, Sprintf("<input_alt fid=\"%d\" " 3311 "type=hidden name=link value=\"", cur_form_id)); 3312 Strcat_charp(tmp, html_quote((r2) ? r2 + 1 : r)); 3313 Strcat(tmp, Sprintf("\"><input_alt hseq=\"%d\" fid=\"%d\" " 3314 "type=submit no_effect=true>", 3315 cur_hseq++, cur_form_id)); 3316 } 3317 #ifdef USE_IMAGE 3318 if (use_image) { 3319 w0 = w; 3320 i0 = i; 3321 if (w < 0 || i < 0) { 3322 Image image; 3323 ParsedURL u; 3324 3325 #ifdef USE_M17N 3326 parseURL2(wc_conv(p, InnerCharset, cur_document_charset)->ptr, &u, 3327 cur_baseURL); 3328 #else 3329 parseURL2(p, &u, cur_baseURL); 3330 #endif 3331 image.url = parsedURL2Str(&u)->ptr; 3332 if (!uncompressed_file_type(u.file, &image.ext)) 3333 image.ext = filename_extension(u.file, TRUE); 3334 image.cache = NULL; 3335 image.width = w; 3336 image.height = i; 3337 3338 image.cache = getImage(&image, cur_baseURL, IMG_FLAG_SKIP); 3339 if (image.cache && image.cache->width > 0 && 3340 image.cache->height > 0) { 3341 w = w0 = image.cache->width; 3342 i = i0 = image.cache->height; 3343 } 3344 if (w < 0) 3345 w = 8 * pixel_per_char; 3346 if (i < 0) 3347 i = pixel_per_line; 3348 } 3349 nw = (w > 3) ? (int)((w - 3) / pixel_per_char + 1) : 1; 3350 ni = (i > 3) ? (int)((i - 3) / pixel_per_line + 1) : 1; 3351 Strcat(tmp, 3352 Sprintf("<pre_int><img_alt hseq=\"%d\" src=\"", cur_iseq++)); 3353 pre_int = TRUE; 3354 } 3355 else 3356 #endif 3357 { 3358 if (w < 0) 3359 w = 12 * pixel_per_char; 3360 nw = w ? (int)((w - 1) / pixel_per_char + 1) : 1; 3361 if (r) { 3362 Strcat_charp(tmp, "<pre_int>"); 3363 pre_int = TRUE; 3364 } 3365 Strcat_charp(tmp, "<img_alt src=\""); 3366 } 3367 Strcat_charp(tmp, html_quote(p)); 3368 Strcat_charp(tmp, "\""); 3369 if (t) { 3370 Strcat_charp(tmp, " title=\""); 3371 Strcat_charp(tmp, html_quote(t)); 3372 Strcat_charp(tmp, "\""); 3373 } 3374 #ifdef USE_IMAGE 3375 if (use_image) { 3376 if (w0 >= 0) 3377 Strcat(tmp, Sprintf(" width=%d", w0)); 3378 if (i0 >= 0) 3379 Strcat(tmp, Sprintf(" height=%d", i0)); 3380 switch (align) { 3381 case ALIGN_TOP: 3382 top = 0; 3383 bottom = ni - 1; 3384 yoffset = 0; 3385 break; 3386 case ALIGN_MIDDLE: 3387 top = ni / 2; 3388 bottom = top; 3389 if (top * 2 == ni) 3390 yoffset = (int)(((ni + 1) * pixel_per_line - i) / 2); 3391 else 3392 yoffset = (int)((ni * pixel_per_line - i) / 2); 3393 break; 3394 case ALIGN_BOTTOM: 3395 top = ni - 1; 3396 bottom = 0; 3397 yoffset = (int)(ni * pixel_per_line - i); 3398 break; 3399 default: 3400 top = ni - 1; 3401 bottom = 0; 3402 if (ni == 1 && ni * pixel_per_line > i) 3403 yoffset = 0; 3404 else { 3405 yoffset = (int)(ni * pixel_per_line - i); 3406 if (yoffset <= -2) 3407 yoffset++; 3408 } 3409 break; 3410 } 3411 xoffset = (int)((nw * pixel_per_char - w) / 2); 3412 if (xoffset) 3413 Strcat(tmp, Sprintf(" xoffset=%d", xoffset)); 3414 if (yoffset) 3415 Strcat(tmp, Sprintf(" yoffset=%d", yoffset)); 3416 if (top) 3417 Strcat(tmp, Sprintf(" top_margin=%d", top)); 3418 if (bottom) 3419 Strcat(tmp, Sprintf(" bottom_margin=%d", bottom)); 3420 if (r) { 3421 Strcat_charp(tmp, " usemap=\""); 3422 Strcat_charp(tmp, html_quote((r2) ? r2 + 1 : r)); 3423 Strcat_charp(tmp, "\""); 3424 } 3425 if (ismap) 3426 Strcat_charp(tmp, " ismap"); 3427 } 3428 #endif 3429 Strcat_charp(tmp, ">"); 3430 if (q != NULL && *q == '\0' && ignore_null_img_alt) 3431 q = NULL; 3432 if (q != NULL) { 3433 n = get_strwidth(q); 3434 #ifdef USE_IMAGE 3435 if (use_image) { 3436 if (n > nw) { 3437 char *r; 3438 for (r = q, n = 0; r; r += get_mclen(r), n += get_mcwidth(r)) { 3439 if (n + get_mcwidth(r) > nw) 3440 break; 3441 } 3442 Strcat_charp(tmp, html_quote(Strnew_charp_n(q, r - q)->ptr)); 3443 } 3444 else 3445 Strcat_charp(tmp, html_quote(q)); 3446 } 3447 else 3448 #endif 3449 Strcat_charp(tmp, html_quote(q)); 3450 goto img_end; 3451 } 3452 if (w > 0 && i > 0) { 3453 /* guess what the image is! */ 3454 if (w < 32 && i < 48) { 3455 /* must be an icon or space */ 3456 n = 1; 3457 if (strcasestr(p, "space") || strcasestr(p, "blank")) 3458 Strcat_charp(tmp, "_"); 3459 else { 3460 if (w * i < 8 * 16) 3461 Strcat_charp(tmp, "*"); 3462 else { 3463 if (!pre_int) { 3464 Strcat_charp(tmp, "<pre_int>"); 3465 pre_int = TRUE; 3466 } 3467 push_symbol(tmp, IMG_SYMBOL, symbol_width, 1); 3468 n = symbol_width; 3469 } 3470 } 3471 goto img_end; 3472 } 3473 if (w > 200 && i < 13) { 3474 /* must be a horizontal line */ 3475 if (!pre_int) { 3476 Strcat_charp(tmp, "<pre_int>"); 3477 pre_int = TRUE; 3478 } 3479 w = w / pixel_per_char / symbol_width; 3480 if (w <= 0) 3481 w = 1; 3482 push_symbol(tmp, HR_SYMBOL, symbol_width, w); 3483 n = w * symbol_width; 3484 goto img_end; 3485 } 3486 } 3487 for (q = p; *q; q++) ; 3488 while (q > p && *q != '/') 3489 q--; 3490 if (*q == '/') 3491 q++; 3492 Strcat_char(tmp, '['); 3493 n = 1; 3494 p = q; 3495 for (; *q; q++) { 3496 if (!IS_ALNUM(*q) && *q != '_' && *q != '-') { 3497 break; 3498 } 3499 Strcat_char(tmp, *q); 3500 n++; 3501 if (n + 1 >= nw) 3502 break; 3503 } 3504 Strcat_char(tmp, ']'); 3505 n++; 3506 img_end: 3507 #ifdef USE_IMAGE 3508 if (use_image) { 3509 for (; n < nw; n++) 3510 Strcat_char(tmp, ' '); 3511 } 3512 #endif 3513 Strcat_charp(tmp, "</img_alt>"); 3514 if (pre_int && !ext_pre_int) 3515 Strcat_charp(tmp, "</pre_int>"); 3516 if (r) { 3517 Strcat_charp(tmp, "</input_alt>"); 3518 process_n_form(); 3519 } 3520 #ifdef USE_IMAGE 3521 if (use_image) { 3522 switch (align) { 3523 case ALIGN_RIGHT: 3524 case ALIGN_CENTER: 3525 case ALIGN_LEFT: 3526 Strcat_charp(tmp, "</div_int>"); 3527 break; 3528 } 3529 } 3530 #endif 3531 return tmp; 3532 } 3533 3534 Str 3535 process_anchor(struct parsed_tag *tag, char *tagbuf) 3536 { 3537 if (parsedtag_need_reconstruct(tag)) { 3538 parsedtag_set_value(tag, ATTR_HSEQ, Sprintf("%d", cur_hseq++)->ptr); 3539 return parsedtag2str(tag); 3540 } 3541 else { 3542 Str tmp = Sprintf("<a hseq=\"%d\"", cur_hseq++); 3543 Strcat_charp(tmp, tagbuf + 2); 3544 return tmp; 3545 } 3546 } 3547 3548 Str 3549 process_input(struct parsed_tag *tag) 3550 { 3551 int i, w, v, x, y, z, iw, ih; 3552 char *q, *p, *r, *p2, *s; 3553 Str tmp = NULL; 3554 char *qq = ""; 3555 int qlen = 0; 3556 3557 if (cur_form_id < 0) { 3558 char *s = "<form_int method=internal action=none>"; 3559 tmp = process_form(parse_tag(&s, TRUE)); 3560 } 3561 if (tmp == NULL) 3562 tmp = Strnew(); 3563 3564 p = "text"; 3565 parsedtag_get_value(tag, ATTR_TYPE, &p); 3566 q = NULL; 3567 parsedtag_get_value(tag, ATTR_VALUE, &q); 3568 r = ""; 3569 parsedtag_get_value(tag, ATTR_NAME, &r); 3570 w = 20; 3571 parsedtag_get_value(tag, ATTR_SIZE, &w); 3572 i = 20; 3573 parsedtag_get_value(tag, ATTR_MAXLENGTH, &i); 3574 p2 = NULL; 3575 parsedtag_get_value(tag, ATTR_ALT, &p2); 3576 x = parsedtag_exists(tag, ATTR_CHECKED); 3577 y = parsedtag_exists(tag, ATTR_ACCEPT); 3578 z = parsedtag_exists(tag, ATTR_READONLY); 3579 3580 v = formtype(p); 3581 if (v == FORM_UNKNOWN) 3582 return NULL; 3583 3584 if (!q) { 3585 switch (v) { 3586 case FORM_INPUT_IMAGE: 3587 case FORM_INPUT_SUBMIT: 3588 case FORM_INPUT_BUTTON: 3589 q = "SUBMIT"; 3590 break; 3591 case FORM_INPUT_RESET: 3592 q = "RESET"; 3593 break; 3594 /* if no VALUE attribute is specified in 3595 * <INPUT TYPE=CHECKBOX> tag, then the value "on" is used 3596 * as a default value. It is not a part of HTML4.0 3597 * specification, but an imitation of Netscape behaviour. 3598 */ 3599 case FORM_INPUT_CHECKBOX: 3600 q = "on"; 3601 } 3602 } 3603 /* VALUE attribute is not allowed in <INPUT TYPE=FILE> tag. */ 3604 if (v == FORM_INPUT_FILE) 3605 q = NULL; 3606 if (q) { 3607 qq = html_quote(q); 3608 qlen = get_strwidth(q); 3609 } 3610 3611 Strcat_charp(tmp, "<pre_int>"); 3612 switch (v) { 3613 case FORM_INPUT_PASSWORD: 3614 case FORM_INPUT_TEXT: 3615 case FORM_INPUT_FILE: 3616 case FORM_INPUT_CHECKBOX: 3617 if (displayLinkNumber) 3618 Strcat(tmp, getLinkNumberStr(0)); 3619 Strcat_char(tmp, '['); 3620 break; 3621 case FORM_INPUT_RADIO: 3622 if (displayLinkNumber) 3623 Strcat(tmp, getLinkNumberStr(0)); 3624 Strcat_char(tmp, '('); 3625 } 3626 Strcat(tmp, Sprintf("<input_alt hseq=\"%d\" fid=\"%d\" type=%s " 3627 "name=\"%s\" width=%d maxlength=%d value=\"%s\"", 3628 cur_hseq++, cur_form_id, p, html_quote(r), w, i, qq)); 3629 if (x) 3630 Strcat_charp(tmp, " checked"); 3631 if (y) 3632 Strcat_charp(tmp, " accept"); 3633 if (z) 3634 Strcat_charp(tmp, " readonly"); 3635 Strcat_char(tmp, '>'); 3636 3637 if (v == FORM_INPUT_HIDDEN) 3638 Strcat_charp(tmp, "</input_alt></pre_int>"); 3639 else { 3640 switch (v) { 3641 case FORM_INPUT_PASSWORD: 3642 case FORM_INPUT_TEXT: 3643 case FORM_INPUT_FILE: 3644 Strcat_charp(tmp, "<u>"); 3645 break; 3646 case FORM_INPUT_IMAGE: 3647 s = NULL; 3648 parsedtag_get_value(tag, ATTR_SRC, &s); 3649 if (s) { 3650 Strcat(tmp, Sprintf("<img src=\"%s\"", html_quote(s))); 3651 if (p2) 3652 Strcat(tmp, Sprintf(" alt=\"%s\"", html_quote(p2))); 3653 if (parsedtag_get_value(tag, ATTR_WIDTH, &iw)) 3654 Strcat(tmp, Sprintf(" width=\"%d\"", iw)); 3655 if (parsedtag_get_value(tag, ATTR_HEIGHT, &ih)) 3656 Strcat(tmp, Sprintf(" height=\"%d\"", ih)); 3657 Strcat_charp(tmp, " pre_int>"); 3658 Strcat_charp(tmp, "</input_alt></pre_int>"); 3659 return tmp; 3660 } 3661 case FORM_INPUT_SUBMIT: 3662 case FORM_INPUT_BUTTON: 3663 case FORM_INPUT_RESET: 3664 if (displayLinkNumber) 3665 Strcat(tmp, getLinkNumberStr(-1)); 3666 Strcat_charp(tmp, "["); 3667 break; 3668 } 3669 switch (v) { 3670 case FORM_INPUT_PASSWORD: 3671 i = 0; 3672 if (q) { 3673 for (; i < qlen && i < w; i++) 3674 Strcat_char(tmp, '*'); 3675 } 3676 for (; i < w; i++) 3677 Strcat_char(tmp, ' '); 3678 break; 3679 case FORM_INPUT_TEXT: 3680 case FORM_INPUT_FILE: 3681 if (q) 3682 Strcat(tmp, textfieldrep(Strnew_charp(q), w)); 3683 else { 3684 for (i = 0; i < w; i++) 3685 Strcat_char(tmp, ' '); 3686 } 3687 break; 3688 case FORM_INPUT_SUBMIT: 3689 case FORM_INPUT_BUTTON: 3690 if (p2) 3691 Strcat_charp(tmp, html_quote(p2)); 3692 else 3693 Strcat_charp(tmp, qq); 3694 break; 3695 case FORM_INPUT_RESET: 3696 Strcat_charp(tmp, qq); 3697 break; 3698 case FORM_INPUT_RADIO: 3699 case FORM_INPUT_CHECKBOX: 3700 if (x) 3701 Strcat_char(tmp, '*'); 3702 else 3703 Strcat_char(tmp, ' '); 3704 break; 3705 } 3706 switch (v) { 3707 case FORM_INPUT_PASSWORD: 3708 case FORM_INPUT_TEXT: 3709 case FORM_INPUT_FILE: 3710 Strcat_charp(tmp, "</u>"); 3711 break; 3712 case FORM_INPUT_IMAGE: 3713 case FORM_INPUT_SUBMIT: 3714 case FORM_INPUT_BUTTON: 3715 case FORM_INPUT_RESET: 3716 Strcat_charp(tmp, "]"); 3717 } 3718 Strcat_charp(tmp, "</input_alt>"); 3719 switch (v) { 3720 case FORM_INPUT_PASSWORD: 3721 case FORM_INPUT_TEXT: 3722 case FORM_INPUT_FILE: 3723 case FORM_INPUT_CHECKBOX: 3724 Strcat_char(tmp, ']'); 3725 break; 3726 case FORM_INPUT_RADIO: 3727 Strcat_char(tmp, ')'); 3728 } 3729 Strcat_charp(tmp, "</pre_int>"); 3730 } 3731 return tmp; 3732 } 3733 3734 Str 3735 process_select(struct parsed_tag *tag) 3736 { 3737 Str tmp = NULL; 3738 char *p; 3739 3740 if (cur_form_id < 0) { 3741 char *s = "<form_int method=internal action=none>"; 3742 tmp = process_form(parse_tag(&s, TRUE)); 3743 } 3744 3745 p = ""; 3746 parsedtag_get_value(tag, ATTR_NAME, &p); 3747 cur_select = Strnew_charp(p); 3748 select_is_multiple = parsedtag_exists(tag, ATTR_MULTIPLE); 3749 3750 #ifdef MENU_SELECT 3751 if (!select_is_multiple) { 3752 select_str = Strnew_charp("<pre_int>"); 3753 if (displayLinkNumber) 3754 Strcat(select_str, getLinkNumberStr(0)); 3755 Strcat(select_str, Sprintf("[<input_alt hseq=\"%d\" " 3756 "fid=\"%d\" type=select name=\"%s\" selectnumber=%d", 3757 cur_hseq++, cur_form_id, html_quote(p), n_select)); 3758 Strcat_charp(select_str, ">"); 3759 if (n_select == max_select) { 3760 max_select *= 2; 3761 select_option = 3762 New_Reuse(FormSelectOption, select_option, max_select); 3763 } 3764 select_option[n_select].first = NULL; 3765 select_option[n_select].last = NULL; 3766 cur_option_maxwidth = 0; 3767 } 3768 else 3769 #endif /* MENU_SELECT */ 3770 select_str = Strnew(); 3771 cur_option = NULL; 3772 cur_status = R_ST_NORMAL; 3773 n_selectitem = 0; 3774 return tmp; 3775 } 3776 3777 Str 3778 process_n_select(void) 3779 { 3780 if (cur_select == NULL) 3781 return NULL; 3782 process_option(); 3783 #ifdef MENU_SELECT 3784 if (!select_is_multiple) { 3785 if (select_option[n_select].first) { 3786 FormItemList sitem; 3787 chooseSelectOption(&sitem, select_option[n_select].first); 3788 Strcat(select_str, textfieldrep(sitem.label, cur_option_maxwidth)); 3789 } 3790 Strcat_charp(select_str, "</input_alt>]</pre_int>"); 3791 n_select++; 3792 } 3793 else 3794 #endif /* MENU_SELECT */ 3795 Strcat_charp(select_str, "<br>"); 3796 cur_select = NULL; 3797 n_selectitem = 0; 3798 return select_str; 3799 } 3800 3801 void 3802 feed_select(char *str) 3803 { 3804 Str tmp = Strnew(); 3805 int prev_status = cur_status; 3806 static int prev_spaces = -1; 3807 char *p; 3808 3809 if (cur_select == NULL) 3810 return; 3811 while (read_token(tmp, &str, &cur_status, 0, 0)) { 3812 if (cur_status != R_ST_NORMAL || prev_status != R_ST_NORMAL) 3813 continue; 3814 p = tmp->ptr; 3815 if (tmp->ptr[0] == '<' && Strlastchar(tmp) == '>') { 3816 struct parsed_tag *tag; 3817 char *q; 3818 if (!(tag = parse_tag(&p, FALSE))) 3819 continue; 3820 switch (tag->tagid) { 3821 case HTML_OPTION: 3822 process_option(); 3823 cur_option = Strnew(); 3824 if (parsedtag_get_value(tag, ATTR_VALUE, &q)) 3825 cur_option_value = Strnew_charp(q); 3826 else 3827 cur_option_value = NULL; 3828 if (parsedtag_get_value(tag, ATTR_LABEL, &q)) 3829 cur_option_label = Strnew_charp(q); 3830 else 3831 cur_option_label = NULL; 3832 cur_option_selected = parsedtag_exists(tag, ATTR_SELECTED); 3833 prev_spaces = -1; 3834 break; 3835 case HTML_N_OPTION: 3836 /* do nothing */ 3837 break; 3838 default: 3839 /* never happen */ 3840 break; 3841 } 3842 } 3843 else if (cur_option) { 3844 while (*p) { 3845 if (IS_SPACE(*p) && prev_spaces != 0) { 3846 p++; 3847 if (prev_spaces > 0) 3848 prev_spaces++; 3849 } 3850 else { 3851 if (IS_SPACE(*p)) 3852 prev_spaces = 1; 3853 else 3854 prev_spaces = 0; 3855 if (*p == '&') 3856 Strcat_charp(cur_option, getescapecmd(&p)); 3857 else 3858 Strcat_char(cur_option, *(p++)); 3859 } 3860 } 3861 } 3862 } 3863 } 3864 3865 void 3866 process_option(void) 3867 { 3868 char begin_char = '[', end_char = ']'; 3869 int len; 3870 3871 if (cur_select == NULL || cur_option == NULL) 3872 return; 3873 while (cur_option->length > 0 && IS_SPACE(Strlastchar(cur_option))) 3874 Strshrink(cur_option, 1); 3875 if (cur_option_value == NULL) 3876 cur_option_value = cur_option; 3877 if (cur_option_label == NULL) 3878 cur_option_label = cur_option; 3879 #ifdef MENU_SELECT 3880 if (!select_is_multiple) { 3881 len = get_Str_strwidth(cur_option_label); 3882 if (len > cur_option_maxwidth) 3883 cur_option_maxwidth = len; 3884 addSelectOption(&select_option[n_select], 3885 cur_option_value, 3886 cur_option_label, cur_option_selected); 3887 return; 3888 } 3889 #endif /* MENU_SELECT */ 3890 if (!select_is_multiple) { 3891 begin_char = '('; 3892 end_char = ')'; 3893 } 3894 Strcat(select_str, Sprintf("<br><pre_int>%c<input_alt hseq=\"%d\" " 3895 "fid=\"%d\" type=%s name=\"%s\" value=\"%s\"", 3896 begin_char, cur_hseq++, cur_form_id, 3897 select_is_multiple ? "checkbox" : "radio", 3898 html_quote(cur_select->ptr), 3899 html_quote(cur_option_value->ptr))); 3900 if (cur_option_selected) 3901 Strcat_charp(select_str, " checked>*</input_alt>"); 3902 else 3903 Strcat_charp(select_str, "> </input_alt>"); 3904 Strcat_char(select_str, end_char); 3905 Strcat_charp(select_str, html_quote(cur_option_label->ptr)); 3906 Strcat_charp(select_str, "</pre_int>"); 3907 n_selectitem++; 3908 } 3909 3910 Str 3911 process_textarea(struct parsed_tag *tag, int width) 3912 { 3913 Str tmp = NULL; 3914 char *p; 3915 #define TEXTAREA_ATTR_COL_MAX 4096 3916 #define TEXTAREA_ATTR_ROWS_MAX 4096 3917 3918 if (cur_form_id < 0) { 3919 char *s = "<form_int method=internal action=none>"; 3920 tmp = process_form(parse_tag(&s, TRUE)); 3921 } 3922 3923 p = ""; 3924 parsedtag_get_value(tag, ATTR_NAME, &p); 3925 cur_textarea = Strnew_charp(p); 3926 cur_textarea_size = 20; 3927 if (parsedtag_get_value(tag, ATTR_COLS, &p)) { 3928 cur_textarea_size = atoi(p); 3929 if (p[strlen(p) - 1] == '%') 3930 cur_textarea_size = width * cur_textarea_size / 100 - 2; 3931 if (cur_textarea_size <= 0) { 3932 cur_textarea_size = 20; 3933 } else if (cur_textarea_size > TEXTAREA_ATTR_COL_MAX) { 3934 cur_textarea_size = TEXTAREA_ATTR_COL_MAX; 3935 } 3936 } 3937 cur_textarea_rows = 1; 3938 if (parsedtag_get_value(tag, ATTR_ROWS, &p)) { 3939 cur_textarea_rows = atoi(p); 3940 if (cur_textarea_rows <= 0) { 3941 cur_textarea_rows = 1; 3942 } else if (cur_textarea_rows > TEXTAREA_ATTR_ROWS_MAX) { 3943 cur_textarea_rows = TEXTAREA_ATTR_ROWS_MAX; 3944 } 3945 } 3946 cur_textarea_readonly = parsedtag_exists(tag, ATTR_READONLY); 3947 if (n_textarea >= max_textarea) { 3948 max_textarea *= 2; 3949 textarea_str = New_Reuse(Str, textarea_str, max_textarea); 3950 } 3951 textarea_str[n_textarea] = Strnew(); 3952 ignore_nl_textarea = TRUE; 3953 3954 return tmp; 3955 } 3956 3957 Str 3958 process_n_textarea(void) 3959 { 3960 Str tmp; 3961 int i; 3962 3963 if (cur_textarea == NULL) 3964 return NULL; 3965 3966 tmp = Strnew(); 3967 Strcat(tmp, Sprintf("<pre_int>[<input_alt hseq=\"%d\" fid=\"%d\" " 3968 "type=textarea name=\"%s\" size=%d rows=%d " 3969 "top_margin=%d textareanumber=%d", 3970 cur_hseq, cur_form_id, 3971 html_quote(cur_textarea->ptr), 3972 cur_textarea_size, cur_textarea_rows, 3973 cur_textarea_rows - 1, n_textarea)); 3974 if (cur_textarea_readonly) 3975 Strcat_charp(tmp, " readonly"); 3976 Strcat_charp(tmp, "><u>"); 3977 for (i = 0; i < cur_textarea_size; i++) 3978 Strcat_char(tmp, ' '); 3979 Strcat_charp(tmp, "</u></input_alt>]</pre_int>\n"); 3980 cur_hseq++; 3981 n_textarea++; 3982 cur_textarea = NULL; 3983 3984 return tmp; 3985 } 3986 3987 void 3988 feed_textarea(char *str) 3989 { 3990 if (cur_textarea == NULL) 3991 return; 3992 if (ignore_nl_textarea) { 3993 if (*str == '\r') 3994 str++; 3995 if (*str == '\n') 3996 str++; 3997 } 3998 ignore_nl_textarea = FALSE; 3999 while (*str) { 4000 if (*str == '&') 4001 Strcat_charp(textarea_str[n_textarea], getescapecmd(&str)); 4002 else if (*str == '\n') { 4003 Strcat_charp(textarea_str[n_textarea], "\r\n"); 4004 str++; 4005 } 4006 else if (*str != '\r') 4007 Strcat_char(textarea_str[n_textarea], *(str++)); 4008 } 4009 } 4010 4011 Str 4012 process_hr(struct parsed_tag *tag, int width, int indent_width) 4013 { 4014 Str tmp = Strnew_charp("<nobr>"); 4015 int w = 0; 4016 int x = ALIGN_CENTER; 4017 #define HR_ATTR_WIDTH_MAX 65535 4018 4019 if (width > indent_width) 4020 width -= indent_width; 4021 if (parsedtag_get_value(tag, ATTR_WIDTH, &w)) { 4022 if (w > HR_ATTR_WIDTH_MAX) { 4023 w = HR_ATTR_WIDTH_MAX; 4024 } 4025 w = REAL_WIDTH(w, width); 4026 } else { 4027 w = width; 4028 } 4029 4030 parsedtag_get_value(tag, ATTR_ALIGN, &x); 4031 switch (x) { 4032 case ALIGN_CENTER: 4033 Strcat_charp(tmp, "<div_int align=center>"); 4034 break; 4035 case ALIGN_RIGHT: 4036 Strcat_charp(tmp, "<div_int align=right>"); 4037 break; 4038 case ALIGN_LEFT: 4039 Strcat_charp(tmp, "<div_int align=left>"); 4040 break; 4041 } 4042 w /= symbol_width; 4043 if (w <= 0) 4044 w = 1; 4045 push_symbol(tmp, HR_SYMBOL, symbol_width, w); 4046 Strcat_charp(tmp, "</div_int></nobr>"); 4047 return tmp; 4048 } 4049 4050 #ifdef USE_M17N 4051 static char * 4052 check_charset(char *p) 4053 { 4054 return wc_guess_charset(p, 0) ? p : NULL; 4055 } 4056 4057 static char * 4058 check_accept_charset(char *ac) 4059 { 4060 char *s = ac, *e; 4061 4062 while (*s) { 4063 while (*s && (IS_SPACE(*s) || *s == ',')) 4064 s++; 4065 if (!*s) 4066 break; 4067 e = s; 4068 while (*e && !(IS_SPACE(*e) || *e == ',')) 4069 e++; 4070 if (wc_guess_charset(Strnew_charp_n(s, e - s)->ptr, 0)) 4071 return ac; 4072 s = e; 4073 } 4074 return NULL; 4075 } 4076 #endif 4077 4078 static Str 4079 process_form_int(struct parsed_tag *tag, int fid) 4080 { 4081 char *p, *q, *r, *s, *tg, *n; 4082 4083 p = "get"; 4084 parsedtag_get_value(tag, ATTR_METHOD, &p); 4085 q = "!CURRENT_URL!"; 4086 parsedtag_get_value(tag, ATTR_ACTION, &q); 4087 r = NULL; 4088 #ifdef USE_M17N 4089 if (parsedtag_get_value(tag, ATTR_ACCEPT_CHARSET, &r)) 4090 r = check_accept_charset(r); 4091 if (!r && parsedtag_get_value(tag, ATTR_CHARSET, &r)) 4092 r = check_charset(r); 4093 #endif 4094 s = NULL; 4095 parsedtag_get_value(tag, ATTR_ENCTYPE, &s); 4096 tg = NULL; 4097 parsedtag_get_value(tag, ATTR_TARGET, &tg); 4098 n = NULL; 4099 parsedtag_get_value(tag, ATTR_NAME, &n); 4100 4101 if (fid < 0) { 4102 form_max++; 4103 form_sp++; 4104 fid = form_max; 4105 } 4106 else { /* <form_int> */ 4107 if (form_max < fid) 4108 form_max = fid; 4109 form_sp = fid; 4110 } 4111 if (forms_size == 0) { 4112 forms_size = INITIAL_FORM_SIZE; 4113 forms = New_N(FormList *, forms_size); 4114 form_stack = NewAtom_N(int, forms_size); 4115 } 4116 else if (forms_size <= form_max) { 4117 forms_size += form_max; 4118 forms = New_Reuse(FormList *, forms, forms_size); 4119 form_stack = New_Reuse(int, form_stack, forms_size); 4120 } 4121 form_stack[form_sp] = fid; 4122 4123 if (w3m_halfdump) { 4124 Str tmp = Sprintf("<form_int fid=\"%d\" action=\"%s\" method=\"%s\"", 4125 fid, html_quote(q), html_quote(p)); 4126 if (s) 4127 Strcat(tmp, Sprintf(" enctype=\"%s\"", html_quote(s))); 4128 if (tg) 4129 Strcat(tmp, Sprintf(" target=\"%s\"", html_quote(tg))); 4130 if (n) 4131 Strcat(tmp, Sprintf(" name=\"%s\"", html_quote(n))); 4132 #ifdef USE_M17N 4133 if (r) 4134 Strcat(tmp, Sprintf(" accept-charset=\"%s\"", html_quote(r))); 4135 #endif 4136 Strcat_charp(tmp, ">"); 4137 return tmp; 4138 } 4139 4140 forms[fid] = newFormList(q, p, r, s, tg, n, NULL); 4141 return NULL; 4142 } 4143 4144 Str 4145 process_form(struct parsed_tag *tag) 4146 { 4147 return process_form_int(tag, -1); 4148 } 4149 4150 Str 4151 process_n_form(void) 4152 { 4153 if (form_sp >= 0) 4154 form_sp--; 4155 return NULL; 4156 } 4157 4158 static void 4159 clear_ignore_p_flag(int cmd, struct readbuffer *obuf) 4160 { 4161 static int clear_flag_cmd[] = { 4162 HTML_HR, HTML_UNKNOWN 4163 }; 4164 int i; 4165 4166 for (i = 0; clear_flag_cmd[i] != HTML_UNKNOWN; i++) { 4167 if (cmd == clear_flag_cmd[i]) { 4168 obuf->flag &= ~RB_IGNORE_P; 4169 return; 4170 } 4171 } 4172 } 4173 4174 static void 4175 set_alignment(struct readbuffer *obuf, struct parsed_tag *tag) 4176 { 4177 long flag = -1; 4178 int align; 4179 4180 if (parsedtag_get_value(tag, ATTR_ALIGN, &align)) { 4181 switch (align) { 4182 case ALIGN_CENTER: 4183 flag = RB_CENTER; 4184 break; 4185 case ALIGN_RIGHT: 4186 flag = RB_RIGHT; 4187 break; 4188 case ALIGN_LEFT: 4189 flag = RB_LEFT; 4190 } 4191 } 4192 RB_SAVE_FLAG(obuf); 4193 if (flag != -1) { 4194 RB_SET_ALIGN(obuf, flag); 4195 } 4196 } 4197 4198 #ifdef ID_EXT 4199 static void 4200 process_idattr(struct readbuffer *obuf, int cmd, struct parsed_tag *tag) 4201 { 4202 char *id = NULL, *framename = NULL; 4203 Str idtag = NULL; 4204 4205 /* 4206 * HTML_TABLE is handled by the other process. 4207 */ 4208 if (cmd == HTML_TABLE) 4209 return; 4210 4211 parsedtag_get_value(tag, ATTR_ID, &id); 4212 parsedtag_get_value(tag, ATTR_FRAMENAME, &framename); 4213 if (id == NULL) 4214 return; 4215 if (framename) 4216 idtag = Sprintf("<_id id=\"%s\" framename=\"%s\">", 4217 html_quote(id), html_quote(framename)); 4218 else 4219 idtag = Sprintf("<_id id=\"%s\">", html_quote(id)); 4220 push_tag(obuf, idtag->ptr, HTML_NOP); 4221 } 4222 #endif /* ID_EXT */ 4223 4224 #define CLOSE_P if (obuf->flag & RB_P) { \ 4225 flushline(h_env, obuf, envs[h_env->envc].indent,0,h_env->limit);\ 4226 RB_RESTORE_FLAG(obuf);\ 4227 obuf->flag &= ~RB_P;\ 4228 } 4229 4230 #define CLOSE_A \ 4231 CLOSE_P; \ 4232 close_anchor(h_env, obuf); 4233 4234 #define CLOSE_DT \ 4235 if (obuf->flag & RB_IN_DT) { \ 4236 obuf->flag &= ~RB_IN_DT; \ 4237 HTMLlineproc1("</b>", h_env); \ 4238 } 4239 4240 #define PUSH_ENV(cmd) \ 4241 if (++h_env->envc_real < h_env->nenv) { \ 4242 ++h_env->envc; \ 4243 envs[h_env->envc].env = cmd; \ 4244 envs[h_env->envc].count = 0; \ 4245 if (h_env->envc <= MAX_INDENT_LEVEL) \ 4246 envs[h_env->envc].indent = envs[h_env->envc - 1].indent + INDENT_INCR; \ 4247 else \ 4248 envs[h_env->envc].indent = envs[h_env->envc - 1].indent; \ 4249 } 4250 4251 #define POP_ENV \ 4252 if (h_env->envc_real-- < h_env->nenv) \ 4253 h_env->envc--; 4254 4255 static int 4256 ul_type(struct parsed_tag *tag, int default_type) 4257 { 4258 char *p; 4259 if (parsedtag_get_value(tag, ATTR_TYPE, &p)) { 4260 if (!strcasecmp(p, "disc")) 4261 return (int)'d'; 4262 else if (!strcasecmp(p, "circle")) 4263 return (int)'c'; 4264 else if (!strcasecmp(p, "square")) 4265 return (int)'s'; 4266 } 4267 return default_type; 4268 } 4269 4270 int 4271 getMetaRefreshParam(char *q, Str *refresh_uri) 4272 { 4273 int refresh_interval; 4274 char *r; 4275 Str s_tmp = NULL; 4276 4277 if (q == NULL || refresh_uri == NULL) 4278 return 0; 4279 4280 refresh_interval = atoi(q); 4281 if (refresh_interval < 0) 4282 return 0; 4283 4284 while (*q) { 4285 if (!strncasecmp(q, "url=", 4)) { 4286 q += 4; 4287 if (*q == '\"') /* " */ 4288 q++; 4289 r = q; 4290 while (*r && !IS_SPACE(*r) && *r != ';') 4291 r++; 4292 s_tmp = Strnew_charp_n(q, r - q); 4293 4294 if (s_tmp->ptr[s_tmp->length - 1] == '\"') { /* " 4295 */ 4296 s_tmp->length--; 4297 s_tmp->ptr[s_tmp->length] = '\0'; 4298 } 4299 q = r; 4300 } 4301 while (*q && *q != ';') 4302 q++; 4303 if (*q == ';') 4304 q++; 4305 while (*q && *q == ' ') 4306 q++; 4307 } 4308 *refresh_uri = s_tmp; 4309 return refresh_interval; 4310 } 4311 4312 int 4313 HTMLtagproc1(struct parsed_tag *tag, struct html_feed_environ *h_env) 4314 { 4315 char *p, *q, *r; 4316 int i, w, x, y, z, count, width; 4317 struct readbuffer *obuf = h_env->obuf; 4318 struct environment *envs = h_env->envs; 4319 Str tmp; 4320 int hseq; 4321 int cmd; 4322 #ifdef ID_EXT 4323 char *id = NULL; 4324 #endif /* ID_EXT */ 4325 4326 cmd = tag->tagid; 4327 4328 if (obuf->flag & RB_PRE) { 4329 switch (cmd) { 4330 case HTML_NOBR: 4331 case HTML_N_NOBR: 4332 case HTML_PRE_INT: 4333 case HTML_N_PRE_INT: 4334 return 1; 4335 } 4336 } 4337 4338 switch (cmd) { 4339 case HTML_B: 4340 obuf->in_bold++; 4341 if (obuf->in_bold > 1) 4342 return 1; 4343 return 0; 4344 case HTML_N_B: 4345 if (obuf->in_bold == 1 && close_effect0(obuf, HTML_B)) 4346 obuf->in_bold = 0; 4347 if (obuf->in_bold > 0) { 4348 obuf->in_bold--; 4349 if (obuf->in_bold == 0) 4350 return 0; 4351 } 4352 return 1; 4353 case HTML_I: 4354 obuf->in_italic++; 4355 if (obuf->in_italic > 1) 4356 return 1; 4357 return 0; 4358 case HTML_N_I: 4359 if (obuf->in_italic == 1 && close_effect0(obuf, HTML_I)) 4360 obuf->in_italic = 0; 4361 if (obuf->in_italic > 0) { 4362 obuf->in_italic--; 4363 if (obuf->in_italic == 0) 4364 return 0; 4365 } 4366 return 1; 4367 case HTML_U: 4368 obuf->in_under++; 4369 if (obuf->in_under > 1) 4370 return 1; 4371 return 0; 4372 case HTML_N_U: 4373 if (obuf->in_under == 1 && close_effect0(obuf, HTML_U)) 4374 obuf->in_under = 0; 4375 if (obuf->in_under > 0) { 4376 obuf->in_under--; 4377 if (obuf->in_under == 0) 4378 return 0; 4379 } 4380 return 1; 4381 case HTML_EM: 4382 HTMLlineproc1("<i>", h_env); 4383 return 1; 4384 case HTML_N_EM: 4385 HTMLlineproc1("</i>", h_env); 4386 return 1; 4387 case HTML_STRONG: 4388 HTMLlineproc1("<b>", h_env); 4389 return 1; 4390 case HTML_N_STRONG: 4391 HTMLlineproc1("</b>", h_env); 4392 return 1; 4393 case HTML_Q: 4394 HTMLlineproc1("`", h_env); 4395 return 1; 4396 case HTML_N_Q: 4397 HTMLlineproc1("'", h_env); 4398 return 1; 4399 case HTML_P: 4400 case HTML_N_P: 4401 CLOSE_A; 4402 if (!(obuf->flag & RB_IGNORE_P)) { 4403 flushline(h_env, obuf, envs[h_env->envc].indent, 1, h_env->limit); 4404 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 4405 h_env->limit); 4406 } 4407 obuf->flag |= RB_IGNORE_P; 4408 if (cmd == HTML_P) { 4409 set_alignment(obuf, tag); 4410 obuf->flag |= RB_P; 4411 } 4412 return 1; 4413 case HTML_BR: 4414 flushline(h_env, obuf, envs[h_env->envc].indent, 1, h_env->limit); 4415 h_env->blank_lines = 0; 4416 return 1; 4417 case HTML_H: 4418 if (!(obuf->flag & (RB_PREMODE | RB_IGNORE_P))) { 4419 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4420 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 4421 h_env->limit); 4422 } 4423 HTMLlineproc1("<b>", h_env); 4424 set_alignment(obuf, tag); 4425 return 1; 4426 case HTML_N_H: 4427 HTMLlineproc1("</b>", h_env); 4428 if (!(obuf->flag & RB_PREMODE)) { 4429 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4430 } 4431 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4432 RB_RESTORE_FLAG(obuf); 4433 close_anchor(h_env, obuf); 4434 obuf->flag |= RB_IGNORE_P; 4435 return 1; 4436 case HTML_UL: 4437 case HTML_OL: 4438 case HTML_BLQ: 4439 CLOSE_A; 4440 if (!(obuf->flag & RB_IGNORE_P)) { 4441 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4442 if (!(obuf->flag & RB_PREMODE) && 4443 (h_env->envc == 0 || cmd == HTML_BLQ)) 4444 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 4445 h_env->limit); 4446 } 4447 PUSH_ENV(cmd); 4448 if (cmd == HTML_UL || cmd == HTML_OL) { 4449 if (parsedtag_get_value(tag, ATTR_START, &count)) { 4450 envs[h_env->envc].count = count - 1; 4451 } 4452 } 4453 if (cmd == HTML_OL) { 4454 envs[h_env->envc].type = '1'; 4455 if (parsedtag_get_value(tag, ATTR_TYPE, &p)) { 4456 envs[h_env->envc].type = (int)*p; 4457 } 4458 } 4459 if (cmd == HTML_UL) 4460 envs[h_env->envc].type = ul_type(tag, 0); 4461 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4462 return 1; 4463 case HTML_N_UL: 4464 case HTML_N_OL: 4465 case HTML_N_DL: 4466 case HTML_N_BLQ: 4467 CLOSE_DT; 4468 CLOSE_A; 4469 if (h_env->envc > 0) { 4470 flushline(h_env, obuf, envs[h_env->envc - 1].indent, 0, 4471 h_env->limit); 4472 POP_ENV; 4473 if (!(obuf->flag & RB_PREMODE) && 4474 (h_env->envc == 0 || cmd == HTML_N_DL || cmd == HTML_N_BLQ)) { 4475 do_blankline(h_env, obuf, 4476 envs[h_env->envc].indent, 4477 INDENT_INCR, h_env->limit); 4478 obuf->flag |= RB_IGNORE_P; 4479 } 4480 } 4481 close_anchor(h_env, obuf); 4482 return 1; 4483 case HTML_DL: 4484 CLOSE_A; 4485 if (!(obuf->flag & RB_IGNORE_P)) { 4486 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4487 if (!(obuf->flag & RB_PREMODE)) 4488 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 4489 h_env->limit); 4490 } 4491 PUSH_ENV(cmd); 4492 if (parsedtag_exists(tag, ATTR_COMPACT)) 4493 envs[h_env->envc].env = HTML_DL_COMPACT; 4494 obuf->flag |= RB_IGNORE_P; 4495 return 1; 4496 case HTML_LI: 4497 CLOSE_A; 4498 CLOSE_DT; 4499 if (h_env->envc > 0) { 4500 Str num; 4501 flushline(h_env, obuf, 4502 envs[h_env->envc - 1].indent, 0, h_env->limit); 4503 envs[h_env->envc].count++; 4504 if (parsedtag_get_value(tag, ATTR_VALUE, &p)) { 4505 count = atoi(p); 4506 if (count > 0) 4507 envs[h_env->envc].count = count; 4508 else 4509 envs[h_env->envc].count = 0; 4510 } 4511 switch (envs[h_env->envc].env) { 4512 case HTML_UL: 4513 envs[h_env->envc].type = ul_type(tag, envs[h_env->envc].type); 4514 for (i = 0; i < INDENT_INCR - 3; i++) 4515 push_charp(obuf, 1, NBSP, PC_ASCII); 4516 tmp = Strnew(); 4517 switch (envs[h_env->envc].type) { 4518 case 'd': 4519 push_symbol(tmp, UL_SYMBOL_DISC, symbol_width, 1); 4520 break; 4521 case 'c': 4522 push_symbol(tmp, UL_SYMBOL_CIRCLE, symbol_width, 1); 4523 break; 4524 case 's': 4525 push_symbol(tmp, UL_SYMBOL_SQUARE, symbol_width, 1); 4526 break; 4527 default: 4528 push_symbol(tmp, 4529 UL_SYMBOL((h_env->envc_real - 4530 1) % MAX_UL_LEVEL), symbol_width, 4531 1); 4532 break; 4533 } 4534 if (symbol_width == 1) 4535 push_charp(obuf, 1, NBSP, PC_ASCII); 4536 push_str(obuf, symbol_width, tmp, PC_ASCII); 4537 push_charp(obuf, 1, NBSP, PC_ASCII); 4538 set_space_to_prevchar(obuf->prevchar); 4539 break; 4540 case HTML_OL: 4541 if (parsedtag_get_value(tag, ATTR_TYPE, &p)) 4542 envs[h_env->envc].type = (int)*p; 4543 switch ((envs[h_env->envc].count > 0)? envs[h_env->envc].type: '1') { 4544 case 'i': 4545 num = romanNumeral(envs[h_env->envc].count); 4546 break; 4547 case 'I': 4548 num = romanNumeral(envs[h_env->envc].count); 4549 Strupper(num); 4550 break; 4551 case 'a': 4552 num = romanAlphabet(envs[h_env->envc].count); 4553 break; 4554 case 'A': 4555 num = romanAlphabet(envs[h_env->envc].count); 4556 Strupper(num); 4557 break; 4558 default: 4559 num = Sprintf("%d", envs[h_env->envc].count); 4560 break; 4561 } 4562 if (INDENT_INCR >= 4) 4563 Strcat_charp(num, ". "); 4564 else 4565 Strcat_char(num, '.'); 4566 push_spaces(obuf, 1, INDENT_INCR - num->length); 4567 push_str(obuf, num->length, num, PC_ASCII); 4568 if (INDENT_INCR >= 4) 4569 set_space_to_prevchar(obuf->prevchar); 4570 break; 4571 default: 4572 push_spaces(obuf, 1, INDENT_INCR); 4573 break; 4574 } 4575 } 4576 else { 4577 flushline(h_env, obuf, 0, 0, h_env->limit); 4578 } 4579 obuf->flag |= RB_IGNORE_P; 4580 return 1; 4581 case HTML_DT: 4582 CLOSE_A; 4583 if (h_env->envc == 0 || 4584 (h_env->envc_real < h_env->nenv && 4585 envs[h_env->envc].env != HTML_DL && 4586 envs[h_env->envc].env != HTML_DL_COMPACT)) { 4587 PUSH_ENV(HTML_DL); 4588 } 4589 if (h_env->envc > 0) { 4590 flushline(h_env, obuf, 4591 envs[h_env->envc - 1].indent, 0, h_env->limit); 4592 } 4593 if (!(obuf->flag & RB_IN_DT)) { 4594 HTMLlineproc1("<b>", h_env); 4595 obuf->flag |= RB_IN_DT; 4596 } 4597 obuf->flag |= RB_IGNORE_P; 4598 return 1; 4599 case HTML_DD: 4600 CLOSE_A; 4601 CLOSE_DT; 4602 if (envs[h_env->envc].env == HTML_DL_COMPACT) { 4603 if (obuf->pos > envs[h_env->envc].indent) 4604 flushline(h_env, obuf, envs[h_env->envc].indent, 0, 4605 h_env->limit); 4606 else 4607 push_spaces(obuf, 1, envs[h_env->envc].indent - obuf->pos); 4608 } 4609 else 4610 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4611 /* obuf->flag |= RB_IGNORE_P; */ 4612 return 1; 4613 case HTML_TITLE: 4614 close_anchor(h_env, obuf); 4615 process_title(tag); 4616 obuf->flag |= RB_TITLE; 4617 obuf->end_tag = HTML_N_TITLE; 4618 return 1; 4619 case HTML_N_TITLE: 4620 if (!(obuf->flag & RB_TITLE)) 4621 return 1; 4622 obuf->flag &= ~RB_TITLE; 4623 obuf->end_tag = 0; 4624 tmp = process_n_title(tag); 4625 if (tmp) 4626 HTMLlineproc1(tmp->ptr, h_env); 4627 return 1; 4628 case HTML_TITLE_ALT: 4629 if (parsedtag_get_value(tag, ATTR_TITLE, &p)) 4630 h_env->title = html_unquote(p); 4631 return 0; 4632 case HTML_FRAMESET: 4633 PUSH_ENV(cmd); 4634 push_charp(obuf, 9, "--FRAME--", PC_ASCII); 4635 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4636 return 0; 4637 case HTML_N_FRAMESET: 4638 if (h_env->envc > 0) { 4639 POP_ENV; 4640 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4641 } 4642 return 0; 4643 case HTML_NOFRAMES: 4644 CLOSE_A; 4645 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4646 obuf->flag |= (RB_NOFRAMES | RB_IGNORE_P); 4647 /* istr = str; */ 4648 return 1; 4649 case HTML_N_NOFRAMES: 4650 CLOSE_A; 4651 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4652 obuf->flag &= ~RB_NOFRAMES; 4653 return 1; 4654 case HTML_FRAME: 4655 q = r = NULL; 4656 parsedtag_get_value(tag, ATTR_SRC, &q); 4657 parsedtag_get_value(tag, ATTR_NAME, &r); 4658 if (q) { 4659 q = html_quote(q); 4660 push_tag(obuf, Sprintf("<a hseq=\"%d\" href=\"%s\">", 4661 cur_hseq++, q)->ptr, HTML_A); 4662 if (r) 4663 q = html_quote(r); 4664 push_charp(obuf, get_strwidth(q), q, PC_ASCII); 4665 push_tag(obuf, "</a>", HTML_N_A); 4666 } 4667 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4668 return 0; 4669 case HTML_HR: 4670 close_anchor(h_env, obuf); 4671 tmp = process_hr(tag, h_env->limit, envs[h_env->envc].indent); 4672 HTMLlineproc1(tmp->ptr, h_env); 4673 set_space_to_prevchar(obuf->prevchar); 4674 return 1; 4675 case HTML_PRE: 4676 x = parsedtag_exists(tag, ATTR_FOR_TABLE); 4677 CLOSE_A; 4678 if (!(obuf->flag & RB_IGNORE_P)) { 4679 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4680 if (!x) 4681 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 4682 h_env->limit); 4683 } 4684 else 4685 fillline(obuf, envs[h_env->envc].indent); 4686 obuf->flag |= (RB_PRE | RB_IGNORE_P); 4687 /* istr = str; */ 4688 return 1; 4689 case HTML_N_PRE: 4690 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4691 if (!(obuf->flag & RB_IGNORE_P)) { 4692 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 4693 h_env->limit); 4694 obuf->flag |= RB_IGNORE_P; 4695 h_env->blank_lines++; 4696 } 4697 obuf->flag &= ~RB_PRE; 4698 close_anchor(h_env, obuf); 4699 return 1; 4700 case HTML_PRE_INT: 4701 i = obuf->line->length; 4702 append_tags(obuf); 4703 if (!(obuf->flag & RB_SPECIAL)) { 4704 set_breakpoint(obuf, obuf->line->length - i); 4705 } 4706 obuf->flag |= RB_PRE_INT; 4707 return 0; 4708 case HTML_N_PRE_INT: 4709 push_tag(obuf, "</pre_int>", HTML_N_PRE_INT); 4710 obuf->flag &= ~RB_PRE_INT; 4711 if (!(obuf->flag & RB_SPECIAL) && obuf->pos > obuf->bp.pos) { 4712 set_prevchar(obuf->prevchar, "", 0); 4713 obuf->prev_ctype = PC_CTRL; 4714 } 4715 return 1; 4716 case HTML_NOBR: 4717 obuf->flag |= RB_NOBR; 4718 obuf->nobr_level++; 4719 return 0; 4720 case HTML_N_NOBR: 4721 if (obuf->nobr_level > 0) 4722 obuf->nobr_level--; 4723 if (obuf->nobr_level == 0) 4724 obuf->flag &= ~RB_NOBR; 4725 return 0; 4726 case HTML_PRE_PLAIN: 4727 CLOSE_A; 4728 if (!(obuf->flag & RB_IGNORE_P)) { 4729 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4730 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 4731 h_env->limit); 4732 } 4733 obuf->flag |= (RB_PRE | RB_IGNORE_P); 4734 return 1; 4735 case HTML_N_PRE_PLAIN: 4736 CLOSE_A; 4737 if (!(obuf->flag & RB_IGNORE_P)) { 4738 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4739 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 4740 h_env->limit); 4741 obuf->flag |= RB_IGNORE_P; 4742 } 4743 obuf->flag &= ~RB_PRE; 4744 return 1; 4745 case HTML_LISTING: 4746 case HTML_XMP: 4747 case HTML_PLAINTEXT: 4748 CLOSE_A; 4749 if (!(obuf->flag & RB_IGNORE_P)) { 4750 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4751 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 4752 h_env->limit); 4753 } 4754 obuf->flag |= (RB_PLAIN | RB_IGNORE_P); 4755 switch (cmd) { 4756 case HTML_LISTING: 4757 obuf->end_tag = HTML_N_LISTING; 4758 break; 4759 case HTML_XMP: 4760 obuf->end_tag = HTML_N_XMP; 4761 break; 4762 case HTML_PLAINTEXT: 4763 obuf->end_tag = MAX_HTMLTAG; 4764 break; 4765 } 4766 return 1; 4767 case HTML_N_LISTING: 4768 case HTML_N_XMP: 4769 CLOSE_A; 4770 if (!(obuf->flag & RB_IGNORE_P)) { 4771 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4772 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 4773 h_env->limit); 4774 obuf->flag |= RB_IGNORE_P; 4775 } 4776 obuf->flag &= ~RB_PLAIN; 4777 obuf->end_tag = 0; 4778 return 1; 4779 case HTML_SCRIPT: 4780 obuf->flag |= RB_SCRIPT; 4781 obuf->end_tag = HTML_N_SCRIPT; 4782 return 1; 4783 case HTML_STYLE: 4784 obuf->flag |= RB_STYLE; 4785 obuf->end_tag = HTML_N_STYLE; 4786 return 1; 4787 case HTML_N_SCRIPT: 4788 obuf->flag &= ~RB_SCRIPT; 4789 obuf->end_tag = 0; 4790 return 1; 4791 case HTML_N_STYLE: 4792 obuf->flag &= ~RB_STYLE; 4793 obuf->end_tag = 0; 4794 return 1; 4795 case HTML_A: 4796 if (obuf->anchor.url) 4797 close_anchor(h_env, obuf); 4798 4799 hseq = 0; 4800 4801 if (parsedtag_get_value(tag, ATTR_HREF, &p)) 4802 obuf->anchor.url = Strnew_charp(p)->ptr; 4803 if (parsedtag_get_value(tag, ATTR_TARGET, &p)) 4804 obuf->anchor.target = Strnew_charp(p)->ptr; 4805 if (parsedtag_get_value(tag, ATTR_REFERER, &p)) 4806 obuf->anchor.referer = Strnew_charp(p)->ptr; 4807 if (parsedtag_get_value(tag, ATTR_TITLE, &p)) 4808 obuf->anchor.title = Strnew_charp(p)->ptr; 4809 if (parsedtag_get_value(tag, ATTR_ACCESSKEY, &p)) 4810 obuf->anchor.accesskey = (unsigned char)*p; 4811 if (parsedtag_get_value(tag, ATTR_HSEQ, &hseq)) 4812 obuf->anchor.hseq = hseq; 4813 4814 if (hseq == 0 && obuf->anchor.url) { 4815 obuf->anchor.hseq = cur_hseq; 4816 tmp = process_anchor(tag, h_env->tagbuf->ptr); 4817 push_tag(obuf, tmp->ptr, HTML_A); 4818 if (displayLinkNumber) 4819 HTMLlineproc1(getLinkNumberStr(-1)->ptr, h_env); 4820 return 1; 4821 } 4822 return 0; 4823 case HTML_N_A: 4824 close_anchor(h_env, obuf); 4825 return 1; 4826 case HTML_IMG: 4827 tmp = process_img(tag, h_env->limit); 4828 HTMLlineproc1(tmp->ptr, h_env); 4829 return 1; 4830 case HTML_IMG_ALT: 4831 if (parsedtag_get_value(tag, ATTR_SRC, &p)) 4832 obuf->img_alt = Strnew_charp(p); 4833 #ifdef USE_IMAGE 4834 i = 0; 4835 if (parsedtag_get_value(tag, ATTR_TOP_MARGIN, &i)) { 4836 if (i > obuf->top_margin) 4837 obuf->top_margin = i; 4838 } 4839 i = 0; 4840 if (parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &i)) { 4841 if (i > obuf->bottom_margin) 4842 obuf->bottom_margin = i; 4843 } 4844 #endif 4845 return 0; 4846 case HTML_N_IMG_ALT: 4847 if (obuf->img_alt) { 4848 if (!close_effect0(obuf, HTML_IMG_ALT)) 4849 push_tag(obuf, "</img_alt>", HTML_N_IMG_ALT); 4850 obuf->img_alt = NULL; 4851 } 4852 return 1; 4853 case HTML_INPUT_ALT: 4854 i = 0; 4855 if (parsedtag_get_value(tag, ATTR_TOP_MARGIN, &i)) { 4856 if (i > obuf->top_margin) 4857 obuf->top_margin = i; 4858 } 4859 i = 0; 4860 if (parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &i)) { 4861 if (i > obuf->bottom_margin) 4862 obuf->bottom_margin = i; 4863 } 4864 return 0; 4865 case HTML_TABLE: 4866 close_anchor(h_env, obuf); 4867 obuf->table_level++; 4868 if (obuf->table_level >= MAX_TABLE) 4869 break; 4870 w = BORDER_NONE; 4871 /* x: cellspacing, y: cellpadding */ 4872 x = 2; 4873 y = 1; 4874 z = 0; 4875 width = 0; 4876 if (parsedtag_exists(tag, ATTR_BORDER)) { 4877 if (parsedtag_get_value(tag, ATTR_BORDER, &w)) { 4878 if (w > 2) 4879 w = BORDER_THICK; 4880 else if (w < 0) { /* weird */ 4881 w = BORDER_THIN; 4882 } 4883 } 4884 else 4885 w = BORDER_THIN; 4886 } 4887 if (parsedtag_get_value(tag, ATTR_WIDTH, &i)) { 4888 if (obuf->table_level == 0) 4889 width = REAL_WIDTH(i, h_env->limit - envs[h_env->envc].indent); 4890 else 4891 width = RELATIVE_WIDTH(i); 4892 } 4893 if (parsedtag_exists(tag, ATTR_HBORDER)) 4894 w = BORDER_NOWIN; 4895 parsedtag_get_value(tag, ATTR_CELLSPACING, &x); 4896 parsedtag_get_value(tag, ATTR_CELLPADDING, &y); 4897 parsedtag_get_value(tag, ATTR_VSPACE, &z); 4898 #ifdef ID_EXT 4899 parsedtag_get_value(tag, ATTR_ID, &id); 4900 #endif /* ID_EXT */ 4901 tables[obuf->table_level] = begin_table(w, x, y, z); 4902 #ifdef ID_EXT 4903 if (id != NULL) 4904 tables[obuf->table_level]->id = Strnew_charp(id); 4905 #endif /* ID_EXT */ 4906 table_mode[obuf->table_level].pre_mode = 0; 4907 table_mode[obuf->table_level].indent_level = 0; 4908 table_mode[obuf->table_level].nobr_level = 0; 4909 table_mode[obuf->table_level].caption = 0; 4910 table_mode[obuf->table_level].end_tag = 0; /* HTML_UNKNOWN */ 4911 #ifndef TABLE_EXPAND 4912 tables[obuf->table_level]->total_width = width; 4913 #else 4914 tables[obuf->table_level]->real_width = width; 4915 tables[obuf->table_level]->total_width = 0; 4916 #endif 4917 return 1; 4918 case HTML_N_TABLE: 4919 /* should be processed in HTMLlineproc() */ 4920 return 1; 4921 case HTML_CENTER: 4922 CLOSE_A; 4923 if (!(obuf->flag & (RB_PREMODE | RB_IGNORE_P))) 4924 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4925 RB_SAVE_FLAG(obuf); 4926 RB_SET_ALIGN(obuf, RB_CENTER); 4927 return 1; 4928 case HTML_N_CENTER: 4929 CLOSE_A; 4930 if (!(obuf->flag & RB_PREMODE)) 4931 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4932 RB_RESTORE_FLAG(obuf); 4933 return 1; 4934 case HTML_DIV: 4935 CLOSE_A; 4936 if (!(obuf->flag & RB_IGNORE_P)) 4937 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4938 set_alignment(obuf, tag); 4939 return 1; 4940 case HTML_N_DIV: 4941 CLOSE_A; 4942 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4943 RB_RESTORE_FLAG(obuf); 4944 return 1; 4945 case HTML_DIV_INT: 4946 CLOSE_P; 4947 if (!(obuf->flag & RB_IGNORE_P)) 4948 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4949 set_alignment(obuf, tag); 4950 return 1; 4951 case HTML_N_DIV_INT: 4952 CLOSE_P; 4953 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4954 RB_RESTORE_FLAG(obuf); 4955 return 1; 4956 case HTML_FORM: 4957 CLOSE_A; 4958 if (!(obuf->flag & RB_IGNORE_P)) 4959 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4960 tmp = process_form(tag); 4961 if (tmp) 4962 HTMLlineproc1(tmp->ptr, h_env); 4963 return 1; 4964 case HTML_N_FORM: 4965 CLOSE_A; 4966 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit); 4967 obuf->flag |= RB_IGNORE_P; 4968 process_n_form(); 4969 return 1; 4970 case HTML_INPUT: 4971 close_anchor(h_env, obuf); 4972 tmp = process_input(tag); 4973 if (tmp) 4974 HTMLlineproc1(tmp->ptr, h_env); 4975 return 1; 4976 case HTML_SELECT: 4977 close_anchor(h_env, obuf); 4978 tmp = process_select(tag); 4979 if (tmp) 4980 HTMLlineproc1(tmp->ptr, h_env); 4981 obuf->flag |= RB_INSELECT; 4982 obuf->end_tag = HTML_N_SELECT; 4983 return 1; 4984 case HTML_N_SELECT: 4985 obuf->flag &= ~RB_INSELECT; 4986 obuf->end_tag = 0; 4987 tmp = process_n_select(); 4988 if (tmp) 4989 HTMLlineproc1(tmp->ptr, h_env); 4990 return 1; 4991 case HTML_OPTION: 4992 /* nothing */ 4993 return 1; 4994 case HTML_TEXTAREA: 4995 close_anchor(h_env, obuf); 4996 tmp = process_textarea(tag, h_env->limit); 4997 if (tmp) 4998 HTMLlineproc1(tmp->ptr, h_env); 4999 obuf->flag |= RB_INTXTA; 5000 obuf->end_tag = HTML_N_TEXTAREA; 5001 return 1; 5002 case HTML_N_TEXTAREA: 5003 obuf->flag &= ~RB_INTXTA; 5004 obuf->end_tag = 0; 5005 tmp = process_n_textarea(); 5006 if (tmp) 5007 HTMLlineproc1(tmp->ptr, h_env); 5008 return 1; 5009 case HTML_ISINDEX: 5010 p = ""; 5011 q = "!CURRENT_URL!"; 5012 parsedtag_get_value(tag, ATTR_PROMPT, &p); 5013 parsedtag_get_value(tag, ATTR_ACTION, &q); 5014 tmp = Strnew_m_charp("<form method=get action=\"", 5015 html_quote(q), 5016 "\">", 5017 html_quote(p), 5018 "<input type=text name=\"\" accept></form>", 5019 NULL); 5020 HTMLlineproc1(tmp->ptr, h_env); 5021 return 1; 5022 case HTML_META: 5023 p = q = NULL; 5024 parsedtag_get_value(tag, ATTR_HTTP_EQUIV, &p); 5025 parsedtag_get_value(tag, ATTR_CONTENT, &q); 5026 #ifdef USE_M17N 5027 if (p && q && !strcasecmp(p, "Content-Type") && 5028 (q = strcasestr(q, "charset")) != NULL) { 5029 q += 7; 5030 SKIP_BLANKS(q); 5031 if (*q == '=') { 5032 q++; 5033 SKIP_BLANKS(q); 5034 meta_charset = wc_guess_charset(q, 0); 5035 } 5036 } 5037 else 5038 #endif 5039 if (p && q && !strcasecmp(p, "refresh")) { 5040 int refresh_interval; 5041 tmp = NULL; 5042 refresh_interval = getMetaRefreshParam(q, &tmp); 5043 if (tmp) { 5044 q = html_quote(tmp->ptr); 5045 tmp = Sprintf("Refresh (%d sec) <a href=\"%s\">%s</a>", 5046 refresh_interval, q, q); 5047 } 5048 else if (refresh_interval > 0) 5049 tmp = Sprintf("Refresh (%d sec)", refresh_interval); 5050 if (tmp) { 5051 HTMLlineproc1(tmp->ptr, h_env); 5052 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, 5053 h_env->limit); 5054 if (!is_redisplay && 5055 !((obuf->flag & RB_NOFRAMES) && RenderFrame)) { 5056 tag->need_reconstruct = TRUE; 5057 return 0; 5058 } 5059 } 5060 } 5061 return 1; 5062 case HTML_BASE: 5063 #ifdef USE_IMAGE 5064 p = NULL; 5065 if (parsedtag_get_value(tag, ATTR_HREF, &p)) { 5066 if (!cur_baseURL) 5067 cur_baseURL = New(ParsedURL); 5068 parseURL(p, cur_baseURL, NULL); 5069 } 5070 #endif 5071 case HTML_MAP: 5072 case HTML_N_MAP: 5073 case HTML_AREA: 5074 return 0; 5075 case HTML_DEL: 5076 switch (displayInsDel) { 5077 case DISPLAY_INS_DEL_SIMPLE: 5078 obuf->flag |= RB_DEL; 5079 break; 5080 case DISPLAY_INS_DEL_NORMAL: 5081 HTMLlineproc1("<U>[DEL:</U>", h_env); 5082 break; 5083 case DISPLAY_INS_DEL_FONTIFY: 5084 obuf->in_strike++; 5085 if (obuf->in_strike == 1) { 5086 push_tag(obuf, "<s>", HTML_S); 5087 } 5088 break; 5089 } 5090 return 1; 5091 case HTML_N_DEL: 5092 switch (displayInsDel) { 5093 case DISPLAY_INS_DEL_SIMPLE: 5094 obuf->flag &= ~RB_DEL; 5095 break; 5096 case DISPLAY_INS_DEL_NORMAL: 5097 HTMLlineproc1("<U>:DEL]</U>", h_env); 5098 case DISPLAY_INS_DEL_FONTIFY: 5099 if (obuf->in_strike == 0) 5100 return 1; 5101 if (obuf->in_strike == 1 && close_effect0(obuf, HTML_S)) 5102 obuf->in_strike = 0; 5103 if (obuf->in_strike > 0) { 5104 obuf->in_strike--; 5105 if (obuf->in_strike == 0) { 5106 push_tag(obuf, "</s>", HTML_N_S); 5107 } 5108 } 5109 break; 5110 } 5111 return 1; 5112 case HTML_S: 5113 switch (displayInsDel) { 5114 case DISPLAY_INS_DEL_SIMPLE: 5115 obuf->flag |= RB_S; 5116 break; 5117 case DISPLAY_INS_DEL_NORMAL: 5118 HTMLlineproc1("<U>[S:</U>", h_env); 5119 break; 5120 case DISPLAY_INS_DEL_FONTIFY: 5121 obuf->in_strike++; 5122 if (obuf->in_strike == 1) { 5123 push_tag(obuf, "<s>", HTML_S); 5124 } 5125 break; 5126 } 5127 return 1; 5128 case HTML_N_S: 5129 switch (displayInsDel) { 5130 case DISPLAY_INS_DEL_SIMPLE: 5131 obuf->flag &= ~RB_S; 5132 break; 5133 case DISPLAY_INS_DEL_NORMAL: 5134 HTMLlineproc1("<U>:S]</U>", h_env); 5135 break; 5136 case DISPLAY_INS_DEL_FONTIFY: 5137 if (obuf->in_strike == 0) 5138 return 1; 5139 if (obuf->in_strike == 1 && close_effect0(obuf, HTML_S)) 5140 obuf->in_strike = 0; 5141 if (obuf->in_strike > 0) { 5142 obuf->in_strike--; 5143 if (obuf->in_strike == 0) { 5144 push_tag(obuf, "</s>", HTML_N_S); 5145 } 5146 } 5147 } 5148 return 1; 5149 case HTML_INS: 5150 switch (displayInsDel) { 5151 case DISPLAY_INS_DEL_SIMPLE: 5152 break; 5153 case DISPLAY_INS_DEL_NORMAL: 5154 HTMLlineproc1("<U>[INS:</U>", h_env); 5155 break; 5156 case DISPLAY_INS_DEL_FONTIFY: 5157 obuf->in_ins++; 5158 if (obuf->in_ins == 1) { 5159 push_tag(obuf, "<ins>", HTML_INS); 5160 } 5161 break; 5162 } 5163 return 1; 5164 case HTML_N_INS: 5165 switch (displayInsDel) { 5166 case DISPLAY_INS_DEL_SIMPLE: 5167 break; 5168 case DISPLAY_INS_DEL_NORMAL: 5169 HTMLlineproc1("<U>:INS]</U>", h_env); 5170 break; 5171 case DISPLAY_INS_DEL_FONTIFY: 5172 if (obuf->in_ins == 0) 5173 return 1; 5174 if (obuf->in_ins == 1 && close_effect0(obuf, HTML_INS)) 5175 obuf->in_ins = 0; 5176 if (obuf->in_ins > 0) { 5177 obuf->in_ins--; 5178 if (obuf->in_ins == 0) { 5179 push_tag(obuf, "</ins>", HTML_N_INS); 5180 } 5181 } 5182 break; 5183 } 5184 return 1; 5185 case HTML_SUP: 5186 if (!(obuf->flag & (RB_DEL | RB_S))) 5187 HTMLlineproc1("^", h_env); 5188 return 1; 5189 case HTML_N_SUP: 5190 return 1; 5191 case HTML_SUB: 5192 if (!(obuf->flag & (RB_DEL | RB_S))) 5193 HTMLlineproc1("[", h_env); 5194 return 1; 5195 case HTML_N_SUB: 5196 if (!(obuf->flag & (RB_DEL | RB_S))) 5197 HTMLlineproc1("]", h_env); 5198 return 1; 5199 case HTML_FONT: 5200 case HTML_N_FONT: 5201 case HTML_NOP: 5202 return 1; 5203 case HTML_BGSOUND: 5204 if (view_unseenobject) { 5205 if (parsedtag_get_value(tag, ATTR_SRC, &p)) { 5206 Str s; 5207 q = html_quote(p); 5208 s = Sprintf("<A HREF=\"%s\">bgsound(%s)</A>", q, q); 5209 HTMLlineproc1(s->ptr, h_env); 5210 } 5211 } 5212 return 1; 5213 case HTML_EMBED: 5214 if (view_unseenobject) { 5215 if (parsedtag_get_value(tag, ATTR_SRC, &p)) { 5216 Str s; 5217 q = html_quote(p); 5218 s = Sprintf("<A HREF=\"%s\">embed(%s)</A>", q, q); 5219 HTMLlineproc1(s->ptr, h_env); 5220 } 5221 } 5222 return 1; 5223 case HTML_APPLET: 5224 if (view_unseenobject) { 5225 if (parsedtag_get_value(tag, ATTR_ARCHIVE, &p)) { 5226 Str s; 5227 q = html_quote(p); 5228 s = Sprintf("<A HREF=\"%s\">applet archive(%s)</A>", q, q); 5229 HTMLlineproc1(s->ptr, h_env); 5230 } 5231 } 5232 return 1; 5233 case HTML_BODY: 5234 if (view_unseenobject) { 5235 if (parsedtag_get_value(tag, ATTR_BACKGROUND, &p)) { 5236 Str s; 5237 q = html_quote(p); 5238 s = Sprintf("<IMG SRC=\"%s\" ALT=\"bg image(%s)\"><BR>", q, q); 5239 HTMLlineproc1(s->ptr, h_env); 5240 } 5241 } 5242 case HTML_N_HEAD: 5243 if (obuf->flag & RB_TITLE) 5244 HTMLlineproc1("</title>", h_env); 5245 case HTML_HEAD: 5246 case HTML_N_BODY: 5247 return 1; 5248 default: 5249 /* obuf->prevchar = '\0'; */ 5250 return 0; 5251 } 5252 /* not reached */ 5253 return 0; 5254 } 5255 5256 #define PPUSH(p,c) {outp[pos]=(p);outc[pos]=(c);pos++;} 5257 #define PSIZE \ 5258 if (out_size <= pos + 1) { \ 5259 out_size = pos * 3 / 2; \ 5260 outc = New_Reuse(char, outc, out_size); \ 5261 outp = New_Reuse(Lineprop, outp, out_size); \ 5262 } 5263 5264 static TextLineListItem *_tl_lp2; 5265 5266 static Str 5267 textlist_feed() 5268 { 5269 TextLine *p; 5270 if (_tl_lp2 != NULL) { 5271 p = _tl_lp2->ptr; 5272 _tl_lp2 = _tl_lp2->next; 5273 return p->line; 5274 } 5275 return NULL; 5276 } 5277 5278 static int 5279 ex_efct(int ex) 5280 { 5281 int effect = 0; 5282 5283 if (! ex) 5284 return 0; 5285 5286 if (ex & PE_EX_ITALIC) 5287 effect |= PE_EX_ITALIC_E; 5288 5289 if (ex & PE_EX_INSERT) 5290 effect |= PE_EX_INSERT_E; 5291 5292 if (ex & PE_EX_STRIKE) 5293 effect |= PE_EX_STRIKE_E; 5294 5295 return effect; 5296 } 5297 5298 static void 5299 HTMLlineproc2body(Buffer *buf, Str (*feed) (), int llimit) 5300 { 5301 static char *outc = NULL; 5302 static Lineprop *outp = NULL; 5303 static int out_size = 0; 5304 Anchor *a_href = NULL, *a_img = NULL, *a_form = NULL; 5305 char *p, *q, *r, *s, *t, *str; 5306 Lineprop mode, effect, ex_effect; 5307 int pos; 5308 int nlines; 5309 #ifdef DEBUG 5310 FILE *debug = NULL; 5311 #endif 5312 struct frameset *frameset_s[FRAMESTACK_SIZE]; 5313 int frameset_sp = -1; 5314 union frameset_element *idFrame = NULL; 5315 char *id = NULL; 5316 int hseq, form_id; 5317 Str line; 5318 char *endp; 5319 char symbol = '\0'; 5320 int internal = 0; 5321 Anchor **a_textarea = NULL; 5322 #ifdef MENU_SELECT 5323 Anchor **a_select = NULL; 5324 #endif 5325 5326 if (out_size == 0) { 5327 out_size = LINELEN; 5328 outc = NewAtom_N(char, out_size); 5329 outp = NewAtom_N(Lineprop, out_size); 5330 } 5331 5332 n_textarea = -1; 5333 if (!max_textarea) { /* halfload */ 5334 max_textarea = MAX_TEXTAREA; 5335 textarea_str = New_N(Str, max_textarea); 5336 a_textarea = New_N(Anchor *, max_textarea); 5337 } 5338 #ifdef MENU_SELECT 5339 n_select = -1; 5340 if (!max_select) { /* halfload */ 5341 max_select = MAX_SELECT; 5342 select_option = New_N(FormSelectOption, max_select); 5343 a_select = New_N(Anchor *, max_select); 5344 } 5345 #endif 5346 5347 #ifdef DEBUG 5348 if (w3m_debug) 5349 debug = fopen("zzzerr", "a"); 5350 #endif 5351 5352 effect = 0; 5353 ex_effect = 0; 5354 nlines = 0; 5355 while ((line = feed()) != NULL) { 5356 #ifdef DEBUG 5357 if (w3m_debug) { 5358 Strfputs(line, debug); 5359 fputc('\n', debug); 5360 } 5361 #endif 5362 if (n_textarea >= 0 && *(line->ptr) != '<') { /* halfload */ 5363 Strcat(textarea_str[n_textarea], line); 5364 continue; 5365 } 5366 proc_again: 5367 if (++nlines == llimit) 5368 break; 5369 pos = 0; 5370 #ifdef ENABLE_REMOVE_TRAILINGSPACES 5371 Strremovetrailingspaces(line); 5372 #endif 5373 str = line->ptr; 5374 endp = str + line->length; 5375 while (str < endp) { 5376 PSIZE; 5377 mode = get_mctype(str); 5378 if ((effect | ex_efct(ex_effect)) & PC_SYMBOL && *str != '<') { 5379 #ifdef USE_M17N 5380 char **buf = set_symbol(symbol_width0); 5381 int len; 5382 5383 p = buf[(int)symbol]; 5384 len = get_mclen(p); 5385 mode = get_mctype(p); 5386 PPUSH(mode | effect | ex_efct(ex_effect), *(p++)); 5387 if (--len) { 5388 mode = (mode & ~PC_WCHAR1) | PC_WCHAR2; 5389 while (len--) { 5390 PSIZE; 5391 PPUSH(mode | effect | ex_efct(ex_effect), *(p++)); 5392 } 5393 } 5394 #else 5395 PPUSH(PC_ASCII | effect | ex_efct(ex_effect), SYMBOL_BASE + symbol); 5396 #endif 5397 str += symbol_width; 5398 } 5399 #ifdef USE_M17N 5400 else if (mode == PC_CTRL || mode == PC_UNDEF) { 5401 #else 5402 else if (mode == PC_CTRL || IS_INTSPACE(*str)) { 5403 #endif 5404 PPUSH(PC_ASCII | effect | ex_efct(ex_effect), ' '); 5405 str++; 5406 } 5407 #ifdef USE_M17N 5408 else if (mode & PC_UNKNOWN) { 5409 PPUSH(PC_ASCII | effect | ex_efct(ex_effect), ' '); 5410 str += get_mclen(str); 5411 } 5412 #endif 5413 else if (*str != '<' && *str != '&') { 5414 #ifdef USE_M17N 5415 int len = get_mclen(str); 5416 #endif 5417 PPUSH(mode | effect | ex_efct(ex_effect), *(str++)); 5418 #ifdef USE_M17N 5419 if (--len) { 5420 mode = (mode & ~PC_WCHAR1) | PC_WCHAR2; 5421 while (len--) { 5422 PSIZE; 5423 PPUSH(mode | effect | ex_efct(ex_effect), *(str++)); 5424 } 5425 } 5426 #endif 5427 } 5428 else if (*str == '&') { 5429 /* 5430 * & escape processing 5431 */ 5432 p = getescapecmd(&str); 5433 while (*p) { 5434 PSIZE; 5435 mode = get_mctype((unsigned char *)p); 5436 #ifdef USE_M17N 5437 if (mode == PC_CTRL || mode == PC_UNDEF) { 5438 #else 5439 if (mode == PC_CTRL || IS_INTSPACE(*str)) { 5440 #endif 5441 PPUSH(PC_ASCII | effect | ex_efct(ex_effect), ' '); 5442 p++; 5443 } 5444 #ifdef USE_M17N 5445 else if (mode & PC_UNKNOWN) { 5446 PPUSH(PC_ASCII | effect | ex_efct(ex_effect), ' '); 5447 p += get_mclen(p); 5448 } 5449 #endif 5450 else { 5451 #ifdef USE_M17N 5452 int len = get_mclen(p); 5453 #endif 5454 PPUSH(mode | effect | ex_efct(ex_effect), *(p++)); 5455 #ifdef USE_M17N 5456 if (--len) { 5457 mode = (mode & ~PC_WCHAR1) | PC_WCHAR2; 5458 while (len--) { 5459 PSIZE; 5460 PPUSH(mode | effect | ex_efct(ex_effect), *(p++)); 5461 } 5462 } 5463 #endif 5464 } 5465 } 5466 } 5467 else { 5468 /* tag processing */ 5469 struct parsed_tag *tag; 5470 if (!(tag = parse_tag(&str, TRUE))) 5471 continue; 5472 switch (tag->tagid) { 5473 case HTML_B: 5474 effect |= PE_BOLD; 5475 break; 5476 case HTML_N_B: 5477 effect &= ~PE_BOLD; 5478 break; 5479 case HTML_I: 5480 ex_effect |= PE_EX_ITALIC; 5481 break; 5482 case HTML_N_I: 5483 ex_effect &= ~PE_EX_ITALIC; 5484 break; 5485 case HTML_INS: 5486 ex_effect |= PE_EX_INSERT; 5487 break; 5488 case HTML_N_INS: 5489 ex_effect &= ~PE_EX_INSERT; 5490 break; 5491 case HTML_U: 5492 effect |= PE_UNDER; 5493 break; 5494 case HTML_N_U: 5495 effect &= ~PE_UNDER; 5496 break; 5497 case HTML_S: 5498 ex_effect |= PE_EX_STRIKE; 5499 break; 5500 case HTML_N_S: 5501 ex_effect &= ~PE_EX_STRIKE; 5502 break; 5503 case HTML_A: 5504 if (renderFrameSet && 5505 parsedtag_get_value(tag, ATTR_FRAMENAME, &p)) { 5506 p = url_quote_conv(p, buf->document_charset); 5507 if (!idFrame || strcmp(idFrame->body->name, p)) { 5508 idFrame = search_frame(renderFrameSet, p); 5509 if (idFrame && idFrame->body->attr != F_BODY) 5510 idFrame = NULL; 5511 } 5512 } 5513 p = r = s = NULL; 5514 q = buf->baseTarget; 5515 t = ""; 5516 hseq = 0; 5517 id = NULL; 5518 if (parsedtag_get_value(tag, ATTR_NAME, &id)) { 5519 id = url_quote_conv(id, buf->document_charset); 5520 registerName(buf, id, currentLn(buf), pos); 5521 } 5522 if (parsedtag_get_value(tag, ATTR_HREF, &p)) 5523 p = url_quote_conv(remove_space(p), 5524 buf->document_charset); 5525 if (parsedtag_get_value(tag, ATTR_TARGET, &q)) 5526 q = url_quote_conv(q, buf->document_charset); 5527 if (parsedtag_get_value(tag, ATTR_REFERER, &r)) 5528 r = url_quote_conv(r, buf->document_charset); 5529 parsedtag_get_value(tag, ATTR_TITLE, &s); 5530 parsedtag_get_value(tag, ATTR_ACCESSKEY, &t); 5531 parsedtag_get_value(tag, ATTR_HSEQ, &hseq); 5532 if (hseq > 0) 5533 buf->hmarklist = 5534 putHmarker(buf->hmarklist, currentLn(buf), 5535 pos, hseq - 1); 5536 else if (hseq < 0) { 5537 int h = -hseq - 1; 5538 if (buf->hmarklist && 5539 h < buf->hmarklist->nmark && 5540 buf->hmarklist->marks[h].invalid) { 5541 buf->hmarklist->marks[h].pos = pos; 5542 buf->hmarklist->marks[h].line = currentLn(buf); 5543 buf->hmarklist->marks[h].invalid = 0; 5544 hseq = -hseq; 5545 } 5546 } 5547 if (id && idFrame) 5548 idFrame->body->nameList = 5549 putAnchor(idFrame->body->nameList, id, NULL, 5550 (Anchor **)NULL, NULL, NULL, '\0', 5551 currentLn(buf), pos); 5552 if (p) { 5553 effect |= PE_ANCHOR; 5554 a_href = registerHref(buf, p, q, r, s, 5555 *t, currentLn(buf), pos); 5556 a_href->hseq = ((hseq > 0) ? hseq : -hseq) - 1; 5557 a_href->slave = (hseq > 0) ? FALSE : TRUE; 5558 } 5559 break; 5560 case HTML_N_A: 5561 effect &= ~PE_ANCHOR; 5562 if (a_href) { 5563 a_href->end.line = currentLn(buf); 5564 a_href->end.pos = pos; 5565 if (a_href->start.line == a_href->end.line && 5566 a_href->start.pos == a_href->end.pos) { 5567 if (buf->hmarklist && 5568 a_href->hseq < buf->hmarklist->nmark) 5569 buf->hmarklist->marks[a_href->hseq].invalid = 1; 5570 a_href->hseq = -1; 5571 } 5572 a_href = NULL; 5573 } 5574 break; 5575 5576 case HTML_LINK: 5577 addLink(buf, tag); 5578 break; 5579 5580 case HTML_IMG_ALT: 5581 if (parsedtag_get_value(tag, ATTR_SRC, &p)) { 5582 #ifdef USE_IMAGE 5583 int w = -1, h = -1, iseq = 0, ismap = 0; 5584 int xoffset = 0, yoffset = 0, top = 0, bottom = 0; 5585 parsedtag_get_value(tag, ATTR_HSEQ, &iseq); 5586 parsedtag_get_value(tag, ATTR_WIDTH, &w); 5587 parsedtag_get_value(tag, ATTR_HEIGHT, &h); 5588 parsedtag_get_value(tag, ATTR_XOFFSET, &xoffset); 5589 parsedtag_get_value(tag, ATTR_YOFFSET, &yoffset); 5590 parsedtag_get_value(tag, ATTR_TOP_MARGIN, &top); 5591 parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &bottom); 5592 if (parsedtag_exists(tag, ATTR_ISMAP)) 5593 ismap = 1; 5594 q = NULL; 5595 parsedtag_get_value(tag, ATTR_USEMAP, &q); 5596 if (iseq > 0) { 5597 buf->imarklist = putHmarker(buf->imarklist, 5598 currentLn(buf), pos, 5599 iseq - 1); 5600 } 5601 #endif 5602 s = NULL; 5603 parsedtag_get_value(tag, ATTR_TITLE, &s); 5604 p = url_quote_conv(remove_space(p), 5605 buf->document_charset); 5606 a_img = registerImg(buf, p, s, currentLn(buf), pos); 5607 #ifdef USE_IMAGE 5608 a_img->hseq = iseq; 5609 a_img->image = NULL; 5610 if (iseq > 0) { 5611 ParsedURL u; 5612 Image *image; 5613 5614 parseURL2(a_img->url, &u, cur_baseURL); 5615 a_img->image = image = New(Image); 5616 image->url = parsedURL2Str(&u)->ptr; 5617 if (!uncompressed_file_type(u.file, &image->ext)) 5618 image->ext = filename_extension(u.file, TRUE); 5619 image->cache = NULL; 5620 image->width = 5621 (w > MAX_IMAGE_SIZE) ? MAX_IMAGE_SIZE : w; 5622 image->height = 5623 (h > MAX_IMAGE_SIZE) ? MAX_IMAGE_SIZE : h; 5624 image->xoffset = xoffset; 5625 image->yoffset = yoffset; 5626 image->y = currentLn(buf) - top; 5627 if (image->xoffset < 0 && pos == 0) 5628 image->xoffset = 0; 5629 if (image->yoffset < 0 && image->y == 1) 5630 image->yoffset = 0; 5631 image->rows = 1 + top + bottom; 5632 image->map = q; 5633 image->ismap = ismap; 5634 image->touch = 0; 5635 image->cache = getImage(image, cur_baseURL, 5636 IMG_FLAG_SKIP); 5637 } 5638 else if (iseq < 0) { 5639 BufferPoint *po = buf->imarklist->marks - iseq - 1; 5640 Anchor *a = retrieveAnchor(buf->img, 5641 po->line, po->pos); 5642 if (a) { 5643 a_img->url = a->url; 5644 a_img->image = a->image; 5645 } 5646 } 5647 #endif 5648 } 5649 effect |= PE_IMAGE; 5650 break; 5651 case HTML_N_IMG_ALT: 5652 effect &= ~PE_IMAGE; 5653 if (a_img) { 5654 a_img->end.line = currentLn(buf); 5655 a_img->end.pos = pos; 5656 } 5657 a_img = NULL; 5658 break; 5659 case HTML_INPUT_ALT: 5660 { 5661 FormList *form; 5662 int top = 0, bottom = 0; 5663 int textareanumber = -1; 5664 #ifdef MENU_SELECT 5665 int selectnumber = -1; 5666 #endif 5667 hseq = 0; 5668 form_id = -1; 5669 5670 parsedtag_get_value(tag, ATTR_HSEQ, &hseq); 5671 parsedtag_get_value(tag, ATTR_FID, &form_id); 5672 parsedtag_get_value(tag, ATTR_TOP_MARGIN, &top); 5673 parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &bottom); 5674 if (form_id < 0 || form_id > form_max || forms == NULL) 5675 break; /* outside of <form>..</form> */ 5676 form = forms[form_id]; 5677 if (hseq > 0) { 5678 int hpos = pos; 5679 if (*str == '[') 5680 hpos++; 5681 buf->hmarklist = 5682 putHmarker(buf->hmarklist, currentLn(buf), 5683 hpos, hseq - 1); 5684 } 5685 if (!form->target) 5686 form->target = buf->baseTarget; 5687 if (a_textarea && 5688 parsedtag_get_value(tag, ATTR_TEXTAREANUMBER, 5689 &textareanumber)) { 5690 if (textareanumber >= max_textarea) { 5691 max_textarea = 2 * textareanumber; 5692 textarea_str = New_Reuse(Str, textarea_str, 5693 max_textarea); 5694 a_textarea = New_Reuse(Anchor *, a_textarea, 5695 max_textarea); 5696 } 5697 } 5698 #ifdef MENU_SELECT 5699 if (a_select && 5700 parsedtag_get_value(tag, ATTR_SELECTNUMBER, 5701 &selectnumber)) { 5702 if (selectnumber >= max_select) { 5703 max_select = 2 * selectnumber; 5704 select_option = New_Reuse(FormSelectOption, 5705 select_option, 5706 max_select); 5707 a_select = New_Reuse(Anchor *, a_select, 5708 max_select); 5709 } 5710 } 5711 #endif 5712 a_form = 5713 registerForm(buf, form, tag, currentLn(buf), pos); 5714 if (a_textarea && textareanumber >= 0) 5715 a_textarea[textareanumber] = a_form; 5716 #ifdef MENU_SELECT 5717 if (a_select && selectnumber >= 0) 5718 a_select[selectnumber] = a_form; 5719 #endif 5720 if (a_form) { 5721 a_form->hseq = hseq - 1; 5722 a_form->y = currentLn(buf) - top; 5723 a_form->rows = 1 + top + bottom; 5724 if (!parsedtag_exists(tag, ATTR_NO_EFFECT)) 5725 effect |= PE_FORM; 5726 break; 5727 } 5728 } 5729 case HTML_N_INPUT_ALT: 5730 effect &= ~PE_FORM; 5731 if (a_form) { 5732 a_form->end.line = currentLn(buf); 5733 a_form->end.pos = pos; 5734 if (a_form->start.line == a_form->end.line && 5735 a_form->start.pos == a_form->end.pos) 5736 a_form->hseq = -1; 5737 } 5738 a_form = NULL; 5739 break; 5740 case HTML_MAP: 5741 if (parsedtag_get_value(tag, ATTR_NAME, &p)) { 5742 MapList *m = New(MapList); 5743 m->name = Strnew_charp(p); 5744 m->area = newGeneralList(); 5745 m->next = buf->maplist; 5746 buf->maplist = m; 5747 } 5748 break; 5749 case HTML_N_MAP: 5750 /* nothing to do */ 5751 break; 5752 case HTML_AREA: 5753 if (buf->maplist == NULL) /* outside of <map>..</map> */ 5754 break; 5755 if (parsedtag_get_value(tag, ATTR_HREF, &p)) { 5756 MapArea *a; 5757 p = url_quote_conv(remove_space(p), 5758 buf->document_charset); 5759 t = NULL; 5760 parsedtag_get_value(tag, ATTR_TARGET, &t); 5761 q = ""; 5762 parsedtag_get_value(tag, ATTR_ALT, &q); 5763 r = NULL; 5764 s = NULL; 5765 #ifdef USE_IMAGE 5766 parsedtag_get_value(tag, ATTR_SHAPE, &r); 5767 parsedtag_get_value(tag, ATTR_COORDS, &s); 5768 #endif 5769 a = newMapArea(p, t, q, r, s); 5770 pushValue(buf->maplist->area, (void *)a); 5771 } 5772 break; 5773 case HTML_FRAMESET: 5774 frameset_sp++; 5775 if (frameset_sp >= FRAMESTACK_SIZE) 5776 break; 5777 frameset_s[frameset_sp] = newFrameSet(tag); 5778 if (frameset_s[frameset_sp] == NULL) 5779 break; 5780 if (frameset_sp == 0) { 5781 if (buf->frameset == NULL) { 5782 buf->frameset = frameset_s[frameset_sp]; 5783 } 5784 else 5785 pushFrameTree(&(buf->frameQ), 5786 frameset_s[frameset_sp], NULL); 5787 } 5788 else 5789 addFrameSetElement(frameset_s[frameset_sp - 1], 5790 *(union frameset_element *) 5791 &frameset_s[frameset_sp]); 5792 break; 5793 case HTML_N_FRAMESET: 5794 if (frameset_sp >= 0) 5795 frameset_sp--; 5796 break; 5797 case HTML_FRAME: 5798 if (frameset_sp >= 0 && frameset_sp < FRAMESTACK_SIZE) { 5799 union frameset_element element; 5800 5801 element.body = newFrame(tag, buf); 5802 addFrameSetElement(frameset_s[frameset_sp], element); 5803 } 5804 break; 5805 case HTML_BASE: 5806 if (parsedtag_get_value(tag, ATTR_HREF, &p)) { 5807 p = url_quote_conv(remove_space(p), 5808 buf->document_charset); 5809 if (!buf->baseURL) 5810 buf->baseURL = New(ParsedURL); 5811 parseURL(p, buf->baseURL, NULL); 5812 } 5813 if (parsedtag_get_value(tag, ATTR_TARGET, &p)) 5814 buf->baseTarget = 5815 url_quote_conv(p, buf->document_charset); 5816 break; 5817 case HTML_META: 5818 p = q = NULL; 5819 parsedtag_get_value(tag, ATTR_HTTP_EQUIV, &p); 5820 parsedtag_get_value(tag, ATTR_CONTENT, &q); 5821 if (p && q && !strcasecmp(p, "refresh") && MetaRefresh) { 5822 Str tmp = NULL; 5823 int refresh_interval = getMetaRefreshParam(q, &tmp); 5824 #ifdef USE_ALARM 5825 if (tmp) { 5826 p = url_quote_conv(remove_space(tmp->ptr), 5827 buf->document_charset); 5828 buf->event = setAlarmEvent(buf->event, 5829 refresh_interval, 5830 AL_IMPLICIT_ONCE, 5831 FUNCNAME_gorURL, p); 5832 } 5833 else if (refresh_interval > 0) 5834 buf->event = setAlarmEvent(buf->event, 5835 refresh_interval, 5836 AL_IMPLICIT, 5837 FUNCNAME_reload, NULL); 5838 #else 5839 if (tmp && refresh_interval == 0) { 5840 p = url_quote_conv(remove_space(tmp->ptr), 5841 buf->document_charset); 5842 pushEvent(FUNCNAME_gorURL, p); 5843 } 5844 #endif 5845 } 5846 break; 5847 case HTML_INTERNAL: 5848 internal = HTML_INTERNAL; 5849 break; 5850 case HTML_N_INTERNAL: 5851 internal = HTML_N_INTERNAL; 5852 break; 5853 case HTML_FORM_INT: 5854 if (parsedtag_get_value(tag, ATTR_FID, &form_id)) 5855 process_form_int(tag, form_id); 5856 break; 5857 case HTML_TEXTAREA_INT: 5858 if (parsedtag_get_value(tag, ATTR_TEXTAREANUMBER, 5859 &n_textarea) 5860 && n_textarea < max_textarea) { 5861 textarea_str[n_textarea] = Strnew(); 5862 } 5863 else 5864 n_textarea = -1; 5865 break; 5866 case HTML_N_TEXTAREA_INT: 5867 if (n_textarea >= 0) { 5868 FormItemList *item = 5869 (FormItemList *)a_textarea[n_textarea]->url; 5870 item->init_value = item->value = 5871 textarea_str[n_textarea]; 5872 } 5873 break; 5874 #ifdef MENU_SELECT 5875 case HTML_SELECT_INT: 5876 if (parsedtag_get_value(tag, ATTR_SELECTNUMBER, &n_select) 5877 && n_select < max_select) { 5878 select_option[n_select].first = NULL; 5879 select_option[n_select].last = NULL; 5880 } 5881 else 5882 n_select = -1; 5883 break; 5884 case HTML_N_SELECT_INT: 5885 if (n_select >= 0) { 5886 FormItemList *item = 5887 (FormItemList *)a_select[n_select]->url; 5888 item->select_option = select_option[n_select].first; 5889 chooseSelectOption(item, item->select_option); 5890 item->init_selected = item->selected; 5891 item->init_value = item->value; 5892 item->init_label = item->label; 5893 } 5894 break; 5895 case HTML_OPTION_INT: 5896 if (n_select >= 0) { 5897 int selected; 5898 q = ""; 5899 parsedtag_get_value(tag, ATTR_LABEL, &q); 5900 p = q; 5901 parsedtag_get_value(tag, ATTR_VALUE, &p); 5902 selected = parsedtag_exists(tag, ATTR_SELECTED); 5903 addSelectOption(&select_option[n_select], 5904 Strnew_charp(p), Strnew_charp(q), 5905 selected); 5906 } 5907 break; 5908 #endif 5909 case HTML_TITLE_ALT: 5910 if (parsedtag_get_value(tag, ATTR_TITLE, &p)) 5911 buf->buffername = html_unquote(p); 5912 break; 5913 case HTML_SYMBOL: 5914 effect |= PC_SYMBOL; 5915 if (parsedtag_get_value(tag, ATTR_TYPE, &p)) 5916 symbol = (char)atoi(p); 5917 break; 5918 case HTML_N_SYMBOL: 5919 effect &= ~PC_SYMBOL; 5920 break; 5921 } 5922 #ifdef ID_EXT 5923 id = NULL; 5924 if (parsedtag_get_value(tag, ATTR_ID, &id)) { 5925 id = url_quote_conv(id, buf->document_charset); 5926 registerName(buf, id, currentLn(buf), pos); 5927 } 5928 if (renderFrameSet && 5929 parsedtag_get_value(tag, ATTR_FRAMENAME, &p)) { 5930 p = url_quote_conv(p, buf->document_charset); 5931 if (!idFrame || strcmp(idFrame->body->name, p)) { 5932 idFrame = search_frame(renderFrameSet, p); 5933 if (idFrame && idFrame->body->attr != F_BODY) 5934 idFrame = NULL; 5935 } 5936 } 5937 if (id && idFrame) 5938 idFrame->body->nameList = 5939 putAnchor(idFrame->body->nameList, id, NULL, 5940 (Anchor **)NULL, NULL, NULL, '\0', 5941 currentLn(buf), pos); 5942 #endif /* ID_EXT */ 5943 } 5944 } 5945 /* end of processing for one line */ 5946 if (!internal) 5947 addnewline(buf, outc, outp, NULL, pos, -1, nlines); 5948 if (internal == HTML_N_INTERNAL) 5949 internal = 0; 5950 if (str != endp) { 5951 line = Strsubstr(line, str - line->ptr, endp - str); 5952 goto proc_again; 5953 } 5954 } 5955 #ifdef DEBUG 5956 if (w3m_debug) 5957 fclose(debug); 5958 #endif 5959 for (form_id = 1; form_id <= form_max; form_id++) 5960 forms[form_id]->next = forms[form_id - 1]; 5961 buf->formlist = (form_max >= 0) ? forms[form_max] : NULL; 5962 if (n_textarea) 5963 addMultirowsForm(buf, buf->formitem); 5964 #ifdef USE_IMAGE 5965 addMultirowsImg(buf, buf->img); 5966 #endif 5967 } 5968 5969 static void 5970 addLink(Buffer *buf, struct parsed_tag *tag) 5971 { 5972 char *href = NULL, *title = NULL, *ctype = NULL, *rel = NULL, *rev = NULL; 5973 char type = LINK_TYPE_NONE; 5974 LinkList *l; 5975 5976 parsedtag_get_value(tag, ATTR_HREF, &href); 5977 if (href) 5978 href = url_quote_conv(remove_space(href), buf->document_charset); 5979 parsedtag_get_value(tag, ATTR_TITLE, &title); 5980 parsedtag_get_value(tag, ATTR_TYPE, &ctype); 5981 parsedtag_get_value(tag, ATTR_REL, &rel); 5982 if (rel != NULL) { 5983 /* forward link type */ 5984 type = LINK_TYPE_REL; 5985 if (title == NULL) 5986 title = rel; 5987 } 5988 parsedtag_get_value(tag, ATTR_REV, &rev); 5989 if (rev != NULL) { 5990 /* reverse link type */ 5991 type = LINK_TYPE_REV; 5992 if (title == NULL) 5993 title = rev; 5994 } 5995 5996 l = New(LinkList); 5997 l->url = href; 5998 l->title = title; 5999 l->ctype = ctype; 6000 l->type = type; 6001 l->next = NULL; 6002 if (buf->linklist) { 6003 LinkList *i; 6004 for (i = buf->linklist; i->next; i = i->next) ; 6005 i->next = l; 6006 } 6007 else 6008 buf->linklist = l; 6009 } 6010 6011 void 6012 HTMLlineproc2(Buffer *buf, TextLineList *tl) 6013 { 6014 _tl_lp2 = tl->first; 6015 HTMLlineproc2body(buf, textlist_feed, -1); 6016 } 6017 6018 static InputStream _file_lp2; 6019 6020 static Str 6021 file_feed() 6022 { 6023 Str s; 6024 s = StrISgets(_file_lp2); 6025 if (s->length == 0) { 6026 ISclose(_file_lp2); 6027 return NULL; 6028 } 6029 return s; 6030 } 6031 6032 void 6033 HTMLlineproc3(Buffer *buf, InputStream stream) 6034 { 6035 _file_lp2 = stream; 6036 HTMLlineproc2body(buf, file_feed, -1); 6037 } 6038 6039 static void 6040 proc_escape(struct readbuffer *obuf, char **str_return) 6041 { 6042 char *str = *str_return, *estr; 6043 int ech = getescapechar(str_return); 6044 int width, n_add = *str_return - str; 6045 Lineprop mode = PC_ASCII; 6046 6047 if (ech < 0) { 6048 *str_return = str; 6049 proc_mchar(obuf, obuf->flag & RB_SPECIAL, 1, str_return, PC_ASCII); 6050 return; 6051 } 6052 mode = IS_CNTRL(ech) ? PC_CTRL : PC_ASCII; 6053 6054 estr = conv_entity(ech); 6055 check_breakpoint(obuf, obuf->flag & RB_SPECIAL, estr); 6056 width = get_strwidth(estr); 6057 if (width == 1 && ech == (unsigned char)*estr && 6058 ech != '&' && ech != '<' && ech != '>') { 6059 if (IS_CNTRL(ech)) 6060 mode = PC_CTRL; 6061 push_charp(obuf, width, estr, mode); 6062 } 6063 else 6064 push_nchars(obuf, width, str, n_add, mode); 6065 set_prevchar(obuf->prevchar, estr, strlen(estr)); 6066 obuf->prev_ctype = mode; 6067 } 6068 6069 6070 static int 6071 need_flushline(struct html_feed_environ *h_env, struct readbuffer *obuf, 6072 Lineprop mode) 6073 { 6074 char ch; 6075 6076 if (obuf->flag & RB_PRE_INT) { 6077 if (obuf->pos > h_env->limit) 6078 return 1; 6079 else 6080 return 0; 6081 } 6082 6083 ch = Strlastchar(obuf->line); 6084 /* if (ch == ' ' && obuf->tag_sp > 0) */ 6085 if (ch == ' ') 6086 return 0; 6087 6088 if (obuf->pos > h_env->limit) 6089 return 1; 6090 6091 return 0; 6092 } 6093 6094 static int 6095 table_width(struct html_feed_environ *h_env, int table_level) 6096 { 6097 int width; 6098 if (table_level < 0) 6099 return 0; 6100 width = tables[table_level]->total_width; 6101 if (table_level > 0 || width > 0) 6102 return width; 6103 return h_env->limit - h_env->envs[h_env->envc].indent; 6104 } 6105 6106 /* HTML processing first pass */ 6107 void 6108 HTMLlineproc0(char *line, struct html_feed_environ *h_env, int internal) 6109 { 6110 Lineprop mode; 6111 int cmd; 6112 struct readbuffer *obuf = h_env->obuf; 6113 int indent, delta; 6114 struct parsed_tag *tag; 6115 Str tokbuf; 6116 struct table *tbl = NULL; 6117 struct table_mode *tbl_mode = NULL; 6118 int tbl_width = 0; 6119 #ifdef USE_M17N 6120 int is_hangul, prev_is_hangul = 0; 6121 #endif 6122 6123 #ifdef DEBUG 6124 if (w3m_debug) { 6125 FILE *f = fopen("zzzproc1", "a"); 6126 fprintf(f, "%c%c%c%c", 6127 (obuf->flag & RB_PREMODE) ? 'P' : ' ', 6128 (obuf->table_level >= 0) ? 'T' : ' ', 6129 (obuf->flag & RB_INTXTA) ? 'X' : ' ', 6130 (obuf->flag & (RB_SCRIPT | RB_STYLE)) ? 'S' : ' '); 6131 fprintf(f, "HTMLlineproc1(\"%s\",%d,%lx)\n", line, h_env->limit, 6132 (unsigned long)h_env); 6133 fclose(f); 6134 } 6135 #endif 6136 6137 tokbuf = Strnew(); 6138 6139 table_start: 6140 if (obuf->table_level >= 0) { 6141 int level = min(obuf->table_level, MAX_TABLE - 1); 6142 tbl = tables[level]; 6143 tbl_mode = &table_mode[level]; 6144 tbl_width = table_width(h_env, level); 6145 } 6146 6147 while (*line != '\0') { 6148 char *str, *p; 6149 int is_tag = FALSE; 6150 int pre_mode = (obuf->table_level >= 0) ? tbl_mode->pre_mode : 6151 obuf->flag; 6152 int end_tag = (obuf->table_level >= 0) ? tbl_mode->end_tag : 6153 obuf->end_tag; 6154 6155 if (*line == '<' || obuf->status != R_ST_NORMAL) { 6156 /* 6157 * Tag processing 6158 */ 6159 if (obuf->status == R_ST_EOL) 6160 obuf->status = R_ST_NORMAL; 6161 else { 6162 read_token(h_env->tagbuf, &line, &obuf->status, 6163 pre_mode & RB_PREMODE, obuf->status != R_ST_NORMAL); 6164 if (obuf->status != R_ST_NORMAL) 6165 return; 6166 } 6167 if (h_env->tagbuf->length == 0) 6168 continue; 6169 str = h_env->tagbuf->ptr; 6170 if (*str == '<') { 6171 if (str[1] && REALLY_THE_BEGINNING_OF_A_TAG(str)) 6172 is_tag = TRUE; 6173 else if (!(pre_mode & (RB_PLAIN | RB_INTXTA | RB_INSELECT | 6174 RB_SCRIPT | RB_STYLE | RB_TITLE))) { 6175 line = Strnew_m_charp(str + 1, line, NULL)->ptr; 6176 str = "<"; 6177 } 6178 } 6179 } 6180 else { 6181 read_token(tokbuf, &line, &obuf->status, pre_mode & RB_PREMODE, 0); 6182 if (obuf->status != R_ST_NORMAL) /* R_ST_AMP ? */ 6183 obuf->status = R_ST_NORMAL; 6184 str = tokbuf->ptr; 6185 } 6186 6187 if (pre_mode & (RB_PLAIN | RB_INTXTA | RB_INSELECT | RB_SCRIPT | 6188 RB_STYLE | RB_TITLE)) { 6189 if (is_tag) { 6190 p = str; 6191 if ((tag = parse_tag(&p, internal))) { 6192 if (tag->tagid == end_tag || 6193 (pre_mode & RB_INSELECT && tag->tagid == HTML_N_FORM) 6194 || (pre_mode & RB_TITLE 6195 && (tag->tagid == HTML_N_HEAD 6196 || tag->tagid == HTML_BODY))) 6197 goto proc_normal; 6198 } 6199 } 6200 /* title */ 6201 if (pre_mode & RB_TITLE) { 6202 feed_title(str); 6203 continue; 6204 } 6205 /* select */ 6206 if (pre_mode & RB_INSELECT) { 6207 if (obuf->table_level >= 0) 6208 goto proc_normal; 6209 feed_select(str); 6210 continue; 6211 } 6212 if (is_tag) { 6213 if (strncmp(str, "<!--", 4) && (p = strchr(str + 1, '<'))) { 6214 str = Strnew_charp_n(str, p - str)->ptr; 6215 line = Strnew_m_charp(p, line, NULL)->ptr; 6216 } 6217 is_tag = FALSE; 6218 } 6219 if (obuf->table_level >= 0) 6220 goto proc_normal; 6221 /* textarea */ 6222 if (pre_mode & RB_INTXTA) { 6223 feed_textarea(str); 6224 continue; 6225 } 6226 /* script */ 6227 if (pre_mode & RB_SCRIPT) 6228 continue; 6229 /* style */ 6230 if (pre_mode & RB_STYLE) 6231 continue; 6232 } 6233 6234 proc_normal: 6235 if (obuf->table_level >= 0) { 6236 /* 6237 * within table: in <table>..</table>, all input tokens 6238 * are fed to the table renderer, and then the renderer 6239 * makes HTML output. 6240 */ 6241 switch (feed_table(tbl, str, tbl_mode, tbl_width, internal)) { 6242 case 0: 6243 /* </table> tag */ 6244 obuf->table_level--; 6245 if (obuf->table_level >= MAX_TABLE - 1) 6246 continue; 6247 end_table(tbl); 6248 if (obuf->table_level >= 0) { 6249 struct table *tbl0 = tables[obuf->table_level]; 6250 str = Sprintf("<table_alt tid=%d>", tbl0->ntable)->ptr; 6251 pushTable(tbl0, tbl); 6252 tbl = tbl0; 6253 tbl_mode = &table_mode[obuf->table_level]; 6254 tbl_width = table_width(h_env, obuf->table_level); 6255 feed_table(tbl, str, tbl_mode, tbl_width, TRUE); 6256 continue; 6257 /* continue to the next */ 6258 } 6259 if (obuf->flag & RB_DEL) 6260 continue; 6261 /* all tables have been read */ 6262 if (tbl->vspace > 0 && !(obuf->flag & RB_IGNORE_P)) { 6263 int indent = h_env->envs[h_env->envc].indent; 6264 flushline(h_env, obuf, indent, 0, h_env->limit); 6265 do_blankline(h_env, obuf, indent, 0, h_env->limit); 6266 } 6267 save_fonteffect(h_env, obuf); 6268 renderTable(tbl, tbl_width, h_env); 6269 restore_fonteffect(h_env, obuf); 6270 obuf->flag &= ~RB_IGNORE_P; 6271 if (tbl->vspace > 0) { 6272 int indent = h_env->envs[h_env->envc].indent; 6273 do_blankline(h_env, obuf, indent, 0, h_env->limit); 6274 obuf->flag |= RB_IGNORE_P; 6275 } 6276 set_space_to_prevchar(obuf->prevchar); 6277 continue; 6278 case 1: 6279 /* <table> tag */ 6280 break; 6281 default: 6282 continue; 6283 } 6284 } 6285 6286 if (is_tag) { 6287 /*** Beginning of a new tag ***/ 6288 if ((tag = parse_tag(&str, internal))) 6289 cmd = tag->tagid; 6290 else 6291 continue; 6292 /* process tags */ 6293 if (HTMLtagproc1(tag, h_env) == 0) { 6294 /* preserve the tag for second-stage processing */ 6295 if (parsedtag_need_reconstruct(tag)) 6296 h_env->tagbuf = parsedtag2str(tag); 6297 push_tag(obuf, h_env->tagbuf->ptr, cmd); 6298 } 6299 #ifdef ID_EXT 6300 else { 6301 process_idattr(obuf, cmd, tag); 6302 } 6303 #endif /* ID_EXT */ 6304 obuf->bp.init_flag = 1; 6305 clear_ignore_p_flag(cmd, obuf); 6306 if (cmd == HTML_TABLE) 6307 goto table_start; 6308 else 6309 continue; 6310 } 6311 6312 if (obuf->flag & (RB_DEL | RB_S)) 6313 continue; 6314 while (*str) { 6315 mode = get_mctype(str); 6316 delta = get_mcwidth(str); 6317 if (obuf->flag & (RB_SPECIAL & ~RB_NOBR)) { 6318 char ch = *str; 6319 if (!(obuf->flag & RB_PLAIN) && (*str == '&')) { 6320 char *p = str; 6321 int ech = getescapechar(&p); 6322 if (ech == '\n' || ech == '\r') { 6323 ch = '\n'; 6324 str = p - 1; 6325 } 6326 else if (ech == '\t') { 6327 ch = '\t'; 6328 str = p - 1; 6329 } 6330 } 6331 if (ch != '\n') 6332 obuf->flag &= ~RB_IGNORE_P; 6333 if (ch == '\n') { 6334 str++; 6335 if (obuf->flag & RB_IGNORE_P) { 6336 obuf->flag &= ~RB_IGNORE_P; 6337 continue; 6338 } 6339 if (obuf->flag & RB_PRE_INT) 6340 PUSH(' '); 6341 else 6342 flushline(h_env, obuf, h_env->envs[h_env->envc].indent, 6343 1, h_env->limit); 6344 } 6345 else if (ch == '\t') { 6346 do { 6347 PUSH(' '); 6348 } while ((h_env->envs[h_env->envc].indent + obuf->pos) 6349 % Tabstop != 0); 6350 str++; 6351 } 6352 else if (obuf->flag & RB_PLAIN) { 6353 char *p = html_quote_char(*str); 6354 if (p) { 6355 push_charp(obuf, 1, p, PC_ASCII); 6356 str++; 6357 } 6358 else { 6359 proc_mchar(obuf, 1, delta, &str, mode); 6360 } 6361 } 6362 else { 6363 if (*str == '&') 6364 proc_escape(obuf, &str); 6365 else 6366 proc_mchar(obuf, 1, delta, &str, mode); 6367 } 6368 if (obuf->flag & (RB_SPECIAL & ~RB_PRE_INT)) 6369 continue; 6370 } 6371 else { 6372 if (!IS_SPACE(*str)) 6373 obuf->flag &= ~RB_IGNORE_P; 6374 if ((mode == PC_ASCII || mode == PC_CTRL) && IS_SPACE(*str)) { 6375 if (*obuf->prevchar->ptr != ' ') { 6376 PUSH(' '); 6377 } 6378 str++; 6379 } 6380 else { 6381 #ifdef USE_M17N 6382 if (mode == PC_KANJI1) 6383 is_hangul = wtf_is_hangul((wc_uchar *) str); 6384 else 6385 is_hangul = 0; 6386 if (!SimplePreserveSpace && mode == PC_KANJI1 && 6387 !is_hangul && !prev_is_hangul && 6388 obuf->pos > h_env->envs[h_env->envc].indent && 6389 Strlastchar(obuf->line) == ' ') { 6390 while (obuf->line->length >= 2 && 6391 !strncmp(obuf->line->ptr + obuf->line->length - 6392 2, " ", 2) 6393 && obuf->pos >= h_env->envs[h_env->envc].indent) { 6394 Strshrink(obuf->line, 1); 6395 obuf->pos--; 6396 } 6397 if (obuf->line->length >= 3 && 6398 obuf->prev_ctype == PC_KANJI1 && 6399 Strlastchar(obuf->line) == ' ' && 6400 obuf->pos >= h_env->envs[h_env->envc].indent) { 6401 Strshrink(obuf->line, 1); 6402 obuf->pos--; 6403 } 6404 } 6405 prev_is_hangul = is_hangul; 6406 #endif 6407 if (*str == '&') 6408 proc_escape(obuf, &str); 6409 else 6410 proc_mchar(obuf, obuf->flag & RB_SPECIAL, delta, &str, 6411 mode); 6412 } 6413 } 6414 if (need_flushline(h_env, obuf, mode)) { 6415 char *bp = obuf->line->ptr + obuf->bp.len; 6416 char *tp = bp - obuf->bp.tlen; 6417 int i = 0; 6418 6419 if (tp > obuf->line->ptr && tp[-1] == ' ') 6420 i = 1; 6421 6422 indent = h_env->envs[h_env->envc].indent; 6423 if (obuf->bp.pos - i > indent) { 6424 Str line; 6425 append_tags(obuf); 6426 line = Strnew_charp(bp); 6427 Strshrink(obuf->line, obuf->line->length - obuf->bp.len); 6428 #ifdef FORMAT_NICE 6429 if (obuf->pos - i > h_env->limit) 6430 obuf->flag |= RB_FILL; 6431 #endif /* FORMAT_NICE */ 6432 back_to_breakpoint(obuf); 6433 flushline(h_env, obuf, indent, 0, h_env->limit); 6434 #ifdef FORMAT_NICE 6435 obuf->flag &= ~RB_FILL; 6436 #endif /* FORMAT_NICE */ 6437 HTMLlineproc1(line->ptr, h_env); 6438 } 6439 } 6440 } 6441 } 6442 if (!(obuf->flag & (RB_SPECIAL | RB_INTXTA | RB_INSELECT))) { 6443 char *tp; 6444 int i = 0; 6445 6446 if (obuf->bp.pos == obuf->pos) { 6447 tp = &obuf->line->ptr[obuf->bp.len - obuf->bp.tlen]; 6448 } 6449 else { 6450 tp = &obuf->line->ptr[obuf->line->length]; 6451 } 6452 6453 if (tp > obuf->line->ptr && tp[-1] == ' ') 6454 i = 1; 6455 indent = h_env->envs[h_env->envc].indent; 6456 if (obuf->pos - i > h_env->limit) { 6457 #ifdef FORMAT_NICE 6458 obuf->flag |= RB_FILL; 6459 #endif /* FORMAT_NICE */ 6460 flushline(h_env, obuf, indent, 0, h_env->limit); 6461 #ifdef FORMAT_NICE 6462 obuf->flag &= ~RB_FILL; 6463 #endif /* FORMAT_NICE */ 6464 } 6465 } 6466 } 6467 6468 extern char *NullLine; 6469 extern Lineprop NullProp[]; 6470 6471 #ifndef USE_ANSI_COLOR 6472 #define addnewline2(a,b,c,d,e,f) _addnewline2(a,b,c,e,f) 6473 #endif 6474 static void 6475 addnewline2(Buffer *buf, char *line, Lineprop *prop, Linecolor *color, int pos, 6476 int nlines) 6477 { 6478 Line *l; 6479 l = New(Line); 6480 l->next = NULL; 6481 l->lineBuf = line; 6482 l->propBuf = prop; 6483 #ifdef USE_ANSI_COLOR 6484 l->colorBuf = color; 6485 #endif 6486 l->len = pos; 6487 l->width = -1; 6488 l->size = pos; 6489 l->bpos = 0; 6490 l->bwidth = 0; 6491 l->prev = buf->currentLine; 6492 if (buf->currentLine) { 6493 l->next = buf->currentLine->next; 6494 buf->currentLine->next = l; 6495 } 6496 else 6497 l->next = NULL; 6498 if (buf->lastLine == NULL || buf->lastLine == buf->currentLine) 6499 buf->lastLine = l; 6500 buf->currentLine = l; 6501 if (buf->firstLine == NULL) 6502 buf->firstLine = l; 6503 l->linenumber = ++buf->allLine; 6504 if (nlines < 0) { 6505 /* l->real_linenumber = l->linenumber; */ 6506 l->real_linenumber = 0; 6507 } 6508 else { 6509 l->real_linenumber = nlines; 6510 } 6511 l = NULL; 6512 } 6513 6514 static void 6515 addnewline(Buffer *buf, char *line, Lineprop *prop, Linecolor *color, int pos, 6516 int width, int nlines) 6517 { 6518 char *s; 6519 Lineprop *p; 6520 #ifdef USE_ANSI_COLOR 6521 Linecolor *c; 6522 #endif 6523 Line *l; 6524 int i, bpos, bwidth; 6525 6526 if (pos > 0) { 6527 s = allocStr(line, pos); 6528 p = NewAtom_N(Lineprop, pos); 6529 bcopy((void *)prop, (void *)p, pos * sizeof(Lineprop)); 6530 } 6531 else { 6532 s = NullLine; 6533 p = NullProp; 6534 } 6535 #ifdef USE_ANSI_COLOR 6536 if (pos > 0 && color) { 6537 c = NewAtom_N(Linecolor, pos); 6538 bcopy((void *)color, (void *)c, pos * sizeof(Linecolor)); 6539 } 6540 else { 6541 c = NULL; 6542 } 6543 #endif 6544 addnewline2(buf, s, p, c, pos, nlines); 6545 if (pos <= 0 || width <= 0) 6546 return; 6547 bpos = 0; 6548 bwidth = 0; 6549 while (1) { 6550 l = buf->currentLine; 6551 l->bpos = bpos; 6552 l->bwidth = bwidth; 6553 i = columnLen(l, width); 6554 if (i == 0) { 6555 i++; 6556 #ifdef USE_M17N 6557 while (i < l->len && p[i] & PC_WCHAR2) 6558 i++; 6559 #endif 6560 } 6561 l->len = i; 6562 l->width = COLPOS(l, l->len); 6563 if (pos <= i) 6564 return; 6565 bpos += l->len; 6566 bwidth += l->width; 6567 s += i; 6568 p += i; 6569 #ifdef USE_ANSI_COLOR 6570 if (c) 6571 c += i; 6572 #endif 6573 pos -= i; 6574 addnewline2(buf, s, p, c, pos, nlines); 6575 } 6576 } 6577 6578 /* 6579 * loadHTMLBuffer: read file and make new buffer 6580 */ 6581 Buffer * 6582 loadHTMLBuffer(URLFile *f, Buffer *newBuf) 6583 { 6584 FILE *src = NULL; 6585 Str tmp; 6586 6587 if (newBuf == NULL) 6588 newBuf = newBuffer(INIT_BUFFER_WIDTH); 6589 if (newBuf->sourcefile == NULL && 6590 (f->scheme != SCM_LOCAL || newBuf->mailcap)) { 6591 tmp = tmpfname(TMPF_SRC, ".html"); 6592 src = fopen(tmp->ptr, "w"); 6593 if (src) 6594 newBuf->sourcefile = tmp->ptr; 6595 } 6596 6597 loadHTMLstream(f, newBuf, src, newBuf->bufferprop & BP_FRAME); 6598 6599 newBuf->topLine = newBuf->firstLine; 6600 newBuf->lastLine = newBuf->currentLine; 6601 newBuf->currentLine = newBuf->firstLine; 6602 if (n_textarea) 6603 formResetBuffer(newBuf, newBuf->formitem); 6604 if (src) 6605 fclose(src); 6606 6607 return newBuf; 6608 } 6609 6610 static char *_size_unit[] = { "b", "kb", "Mb", "Gb", "Tb", 6611 "Pb", "Eb", "Zb", "Bb", "Yb", NULL 6612 }; 6613 6614 char * 6615 convert_size(clen_t size, int usefloat) 6616 { 6617 float csize; 6618 int sizepos = 0; 6619 char **sizes = _size_unit; 6620 6621 csize = (float)size; 6622 while (csize >= 999.495 && sizes[sizepos + 1]) { 6623 csize = csize / 1024.0; 6624 sizepos++; 6625 } 6626 return Sprintf(usefloat ? "%.3g%s" : "%.0f%s", 6627 floor(csize * 100.0 + 0.5) / 100.0, sizes[sizepos])->ptr; 6628 } 6629 6630 char * 6631 convert_size2(clen_t size1, clen_t size2, int usefloat) 6632 { 6633 char **sizes = _size_unit; 6634 float csize, factor = 1; 6635 int sizepos = 0; 6636 6637 csize = (float)((size1 > size2) ? size1 : size2); 6638 while (csize / factor >= 999.495 && sizes[sizepos + 1]) { 6639 factor *= 1024.0; 6640 sizepos++; 6641 } 6642 return Sprintf(usefloat ? "%.3g/%.3g%s" : "%.0f/%.0f%s", 6643 floor(size1 / factor * 100.0 + 0.5) / 100.0, 6644 floor(size2 / factor * 100.0 + 0.5) / 100.0, 6645 sizes[sizepos])->ptr; 6646 } 6647 6648 void 6649 showProgress(clen_t * linelen, clen_t * trbyte) 6650 { 6651 int i, j, rate, duration, eta, pos; 6652 static time_t last_time, start_time; 6653 time_t cur_time; 6654 Str messages; 6655 char *fmtrbyte, *fmrate; 6656 6657 if (!fmInitialized) 6658 return; 6659 6660 if (*linelen < 1024) 6661 return; 6662 if (current_content_length > 0) { 6663 double ratio; 6664 cur_time = time(0); 6665 if (*trbyte == 0) { 6666 move(LASTLINE, 0); 6667 clrtoeolx(); 6668 start_time = cur_time; 6669 } 6670 *trbyte += *linelen; 6671 *linelen = 0; 6672 if (cur_time == last_time) 6673 return; 6674 last_time = cur_time; 6675 move(LASTLINE, 0); 6676 ratio = 100.0 * (*trbyte) / current_content_length; 6677 fmtrbyte = convert_size2(*trbyte, current_content_length, 1); 6678 duration = cur_time - start_time; 6679 if (duration) { 6680 rate = *trbyte / duration; 6681 fmrate = convert_size(rate, 1); 6682 eta = rate ? (current_content_length - *trbyte) / rate : -1; 6683 messages = Sprintf("%11s %3.0f%% " 6684 "%7s/s " 6685 "eta %02d:%02d:%02d ", 6686 fmtrbyte, ratio, 6687 fmrate, 6688 eta / (60 * 60), (eta / 60) % 60, eta % 60); 6689 } 6690 else { 6691 messages = Sprintf("%11s %3.0f%% ", 6692 fmtrbyte, ratio); 6693 } 6694 addstr(messages->ptr); 6695 pos = 42; 6696 i = pos + (COLS - pos - 1) * (*trbyte) / current_content_length; 6697 move(LASTLINE, pos); 6698 standout(); 6699 addch(' '); 6700 for (j = pos + 1; j <= i; j++) 6701 addch('|'); 6702 standend(); 6703 /* no_clrtoeol(); */ 6704 refresh(); 6705 } 6706 else { 6707 cur_time = time(0); 6708 if (*trbyte == 0) { 6709 move(LASTLINE, 0); 6710 clrtoeolx(); 6711 start_time = cur_time; 6712 } 6713 *trbyte += *linelen; 6714 *linelen = 0; 6715 if (cur_time == last_time) 6716 return; 6717 last_time = cur_time; 6718 move(LASTLINE, 0); 6719 fmtrbyte = convert_size(*trbyte, 1); 6720 duration = cur_time - start_time; 6721 if (duration) { 6722 fmrate = convert_size(*trbyte / duration, 1); 6723 messages = Sprintf("%7s loaded %7s/s", fmtrbyte, fmrate); 6724 } 6725 else { 6726 messages = Sprintf("%7s loaded", fmtrbyte); 6727 } 6728 message(messages->ptr, 0, 0); 6729 refresh(); 6730 } 6731 } 6732 6733 void 6734 init_henv(struct html_feed_environ *h_env, struct readbuffer *obuf, 6735 struct environment *envs, int nenv, TextLineList *buf, 6736 int limit, int indent) 6737 { 6738 envs[0].indent = indent; 6739 6740 obuf->line = Strnew(); 6741 obuf->cprop = 0; 6742 obuf->pos = 0; 6743 obuf->prevchar = Strnew_size(8); 6744 set_space_to_prevchar(obuf->prevchar); 6745 obuf->flag = RB_IGNORE_P; 6746 obuf->flag_sp = 0; 6747 obuf->status = R_ST_NORMAL; 6748 obuf->table_level = -1; 6749 obuf->nobr_level = 0; 6750 bzero((void *)&obuf->anchor, sizeof(obuf->anchor)); 6751 obuf->img_alt = 0; 6752 obuf->in_bold = 0; 6753 obuf->in_italic = 0; 6754 obuf->in_under = 0; 6755 obuf->in_strike = 0; 6756 obuf->in_ins = 0; 6757 obuf->prev_ctype = PC_ASCII; 6758 obuf->tag_sp = 0; 6759 obuf->fontstat_sp = 0; 6760 obuf->top_margin = 0; 6761 obuf->bottom_margin = 0; 6762 obuf->bp.init_flag = 1; 6763 set_breakpoint(obuf, 0); 6764 6765 h_env->buf = buf; 6766 h_env->f = NULL; 6767 h_env->obuf = obuf; 6768 h_env->tagbuf = Strnew(); 6769 h_env->limit = limit; 6770 h_env->maxlimit = 0; 6771 h_env->envs = envs; 6772 h_env->nenv = nenv; 6773 h_env->envc = 0; 6774 h_env->envc_real = 0; 6775 h_env->title = NULL; 6776 h_env->blank_lines = 0; 6777 } 6778 6779 void 6780 completeHTMLstream(struct html_feed_environ *h_env, struct readbuffer *obuf) 6781 { 6782 close_anchor(h_env, obuf); 6783 if (obuf->img_alt) { 6784 push_tag(obuf, "</img_alt>", HTML_N_IMG_ALT); 6785 obuf->img_alt = NULL; 6786 } 6787 if (obuf->in_bold) { 6788 push_tag(obuf, "</b>", HTML_N_B); 6789 obuf->in_bold = 0; 6790 } 6791 if (obuf->in_italic) { 6792 push_tag(obuf, "</i>", HTML_N_I); 6793 obuf->in_italic = 0; 6794 } 6795 if (obuf->in_under) { 6796 push_tag(obuf, "</u>", HTML_N_U); 6797 obuf->in_under = 0; 6798 } 6799 if (obuf->in_strike) { 6800 push_tag(obuf, "</s>", HTML_N_S); 6801 obuf->in_strike = 0; 6802 } 6803 if (obuf->in_ins) { 6804 push_tag(obuf, "</ins>", HTML_N_INS); 6805 obuf->in_ins = 0; 6806 } 6807 if (obuf->flag & RB_INTXTA) 6808 HTMLlineproc1("</textarea>", h_env); 6809 /* for unbalanced select tag */ 6810 if (obuf->flag & RB_INSELECT) 6811 HTMLlineproc1("</select>", h_env); 6812 if (obuf->flag & RB_TITLE) 6813 HTMLlineproc1("</title>", h_env); 6814 6815 /* for unbalanced table tag */ 6816 if (obuf->table_level >= MAX_TABLE) 6817 obuf->table_level = MAX_TABLE - 1; 6818 6819 while (obuf->table_level >= 0) { 6820 table_mode[obuf->table_level].pre_mode 6821 &= ~(TBLM_SCRIPT | TBLM_STYLE | TBLM_PLAIN); 6822 HTMLlineproc1("</table>", h_env); 6823 } 6824 } 6825 6826 static void 6827 print_internal_information(struct html_feed_environ *henv) 6828 { 6829 int i; 6830 Str s; 6831 TextLineList *tl = newTextLineList(); 6832 6833 s = Strnew_charp("<internal>"); 6834 pushTextLine(tl, newTextLine(s, 0)); 6835 if (henv->title) { 6836 s = Strnew_m_charp("<title_alt title=\"", 6837 html_quote(henv->title), "\">", NULL); 6838 pushTextLine(tl, newTextLine(s, 0)); 6839 } 6840 #if 0 6841 if (form_max >= 0) { 6842 FormList *fp; 6843 for (i = 0; i <= form_max; i++) { 6844 fp = forms[i]; 6845 s = Sprintf("<form_int fid=\"%d\" action=\"%s\" method=\"%s\"", 6846 i, html_quote(fp->action->ptr), 6847 (fp->method == FORM_METHOD_POST) ? "post" 6848 : ((fp->method == 6849 FORM_METHOD_INTERNAL) ? "internal" : "get")); 6850 if (fp->target) 6851 Strcat(s, Sprintf(" target=\"%s\"", html_quote(fp->target))); 6852 if (fp->enctype == FORM_ENCTYPE_MULTIPART) 6853 Strcat_charp(s, " enctype=\"multipart/form-data\""); 6854 #ifdef USE_M17N 6855 if (fp->charset) 6856 Strcat(s, Sprintf(" accept-charset=\"%s\"", 6857 html_quote(fp->charset))); 6858 #endif 6859 Strcat_charp(s, ">"); 6860 pushTextLine(tl, newTextLine(s, 0)); 6861 } 6862 } 6863 #endif 6864 #ifdef MENU_SELECT 6865 if (n_select > 0) { 6866 FormSelectOptionItem *ip; 6867 for (i = 0; i < n_select; i++) { 6868 s = Sprintf("<select_int selectnumber=%d>", i); 6869 pushTextLine(tl, newTextLine(s, 0)); 6870 for (ip = select_option[i].first; ip; ip = ip->next) { 6871 s = Sprintf("<option_int value=\"%s\" label=\"%s\"%s>", 6872 html_quote(ip->value ? ip->value->ptr : 6873 ip->label->ptr), 6874 html_quote(ip->label->ptr), 6875 ip->checked ? " selected" : ""); 6876 pushTextLine(tl, newTextLine(s, 0)); 6877 } 6878 s = Strnew_charp("</select_int>"); 6879 pushTextLine(tl, newTextLine(s, 0)); 6880 } 6881 } 6882 #endif /* MENU_SELECT */ 6883 if (n_textarea > 0) { 6884 for (i = 0; i < n_textarea; i++) { 6885 s = Sprintf("<textarea_int textareanumber=%d>", i); 6886 pushTextLine(tl, newTextLine(s, 0)); 6887 s = Strnew_charp(html_quote(textarea_str[i]->ptr)); 6888 Strcat_charp(s, "</textarea_int>"); 6889 pushTextLine(tl, newTextLine(s, 0)); 6890 } 6891 } 6892 s = Strnew_charp("</internal>"); 6893 pushTextLine(tl, newTextLine(s, 0)); 6894 6895 if (henv->buf) 6896 appendTextLineList(henv->buf, tl); 6897 else if (henv->f) { 6898 TextLineListItem *p; 6899 for (p = tl->first; p; p = p->next) 6900 fprintf(henv->f, "%s\n", Str_conv_to_halfdump(p->ptr->line)->ptr); 6901 } 6902 } 6903 6904 void 6905 loadHTMLstream(URLFile *f, Buffer *newBuf, FILE * src, int internal) 6906 { 6907 struct environment envs[MAX_ENV_LEVEL]; 6908 clen_t linelen = 0; 6909 clen_t trbyte = 0; 6910 Str lineBuf2 = Strnew(); 6911 #ifdef USE_M17N 6912 wc_ces charset = WC_CES_US_ASCII; 6913 wc_ces volatile doc_charset = DocumentCharset; 6914 #endif 6915 struct html_feed_environ htmlenv1; 6916 struct readbuffer obuf; 6917 #ifdef USE_IMAGE 6918 int volatile image_flag; 6919 #endif 6920 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; 6921 6922 #ifdef USE_M17N 6923 if (fmInitialized && graph_ok()) { 6924 symbol_width = symbol_width0 = 1; 6925 } 6926 else { 6927 symbol_width0 = 0; 6928 get_symbol(DisplayCharset, &symbol_width0); 6929 symbol_width = WcOption.use_wide ? symbol_width0 : 1; 6930 } 6931 #else 6932 symbol_width = symbol_width0 = 1; 6933 #endif 6934 6935 cur_title = NULL; 6936 n_textarea = 0; 6937 cur_textarea = NULL; 6938 max_textarea = MAX_TEXTAREA; 6939 textarea_str = New_N(Str, max_textarea); 6940 #ifdef MENU_SELECT 6941 n_select = 0; 6942 max_select = MAX_SELECT; 6943 select_option = New_N(FormSelectOption, max_select); 6944 #endif /* MENU_SELECT */ 6945 cur_select = NULL; 6946 form_sp = -1; 6947 form_max = -1; 6948 forms_size = 0; 6949 forms = NULL; 6950 cur_hseq = 1; 6951 #ifdef USE_IMAGE 6952 cur_iseq = 1; 6953 if (newBuf->image_flag) 6954 image_flag = newBuf->image_flag; 6955 else if (activeImage && displayImage && autoImage) 6956 image_flag = IMG_FLAG_AUTO; 6957 else 6958 image_flag = IMG_FLAG_SKIP; 6959 if (newBuf->currentURL.file) 6960 cur_baseURL = baseURL(newBuf); 6961 #endif 6962 6963 if (w3m_halfload) { 6964 newBuf->buffername = "---"; 6965 #ifdef USE_M17N 6966 newBuf->document_charset = InnerCharset; 6967 #endif 6968 max_textarea = 0; 6969 #ifdef MENU_SELECT 6970 max_select = 0; 6971 #endif 6972 HTMLlineproc3(newBuf, f->stream); 6973 w3m_halfload = FALSE; 6974 return; 6975 } 6976 6977 init_henv(&htmlenv1, &obuf, envs, MAX_ENV_LEVEL, NULL, newBuf->width, 0); 6978 6979 if (w3m_halfdump) 6980 htmlenv1.f = stdout; 6981 else 6982 htmlenv1.buf = newTextLineList(); 6983 6984 if (SETJMP(AbortLoading) != 0) { 6985 HTMLlineproc1("<br>Transfer Interrupted!<br>", &htmlenv1); 6986 goto phase2; 6987 } 6988 TRAP_ON; 6989 6990 #ifdef USE_M17N 6991 if (newBuf != NULL) { 6992 if (newBuf->bufferprop & BP_FRAME) 6993 charset = InnerCharset; 6994 else if (newBuf->document_charset) 6995 charset = doc_charset = newBuf->document_charset; 6996 } 6997 if (content_charset && UseContentCharset) 6998 doc_charset = content_charset; 6999 else if (f->guess_type && !strcasecmp(f->guess_type, "application/xhtml+xml")) 7000 doc_charset = WC_CES_UTF_8; 7001 meta_charset = 0; 7002 #endif 7003 #if 0 7004 do_blankline(&htmlenv1, &obuf, 0, 0, htmlenv1.limit); 7005 obuf.flag = RB_IGNORE_P; 7006 #endif 7007 if (IStype(f->stream) != IST_ENCODED) 7008 f->stream = newEncodedStream(f->stream, f->encoding); 7009 while ((lineBuf2 = StrmyUFgets(f))->length) { 7010 #ifdef USE_NNTP 7011 if (f->scheme == SCM_NEWS && lineBuf2->ptr[0] == '.') { 7012 Strshrinkfirst(lineBuf2, 1); 7013 if (lineBuf2->ptr[0] == '\n' || lineBuf2->ptr[0] == '\r' || 7014 lineBuf2->ptr[0] == '\0') { 7015 /* 7016 * iseos(f->stream) = TRUE; 7017 */ 7018 break; 7019 } 7020 } 7021 #endif /* USE_NNTP */ 7022 if (src) 7023 Strfputs(lineBuf2, src); 7024 linelen += lineBuf2->length; 7025 if (w3m_dump & DUMP_EXTRA) 7026 printf("W3m-in-progress: %s\n", convert_size2(linelen, current_content_length, TRUE)); 7027 if (w3m_dump & DUMP_SOURCE) 7028 continue; 7029 showProgress(&linelen, &trbyte); 7030 /* 7031 * if (frame_source) 7032 * continue; 7033 */ 7034 #ifdef USE_M17N 7035 if (meta_charset) { /* <META> */ 7036 if (content_charset == 0 && UseContentCharset) { 7037 doc_charset = meta_charset; 7038 charset = WC_CES_US_ASCII; 7039 } 7040 meta_charset = 0; 7041 } 7042 #endif 7043 lineBuf2 = convertLine(f, lineBuf2, HTML_MODE, &charset, doc_charset); 7044 #if defined(USE_M17N) && defined(USE_IMAGE) 7045 cur_document_charset = charset; 7046 #endif 7047 HTMLlineproc0(lineBuf2->ptr, &htmlenv1, internal); 7048 } 7049 if (obuf.status != R_ST_NORMAL) { 7050 obuf.status = R_ST_EOL; 7051 HTMLlineproc0("\n", &htmlenv1, internal); 7052 } 7053 obuf.status = R_ST_NORMAL; 7054 completeHTMLstream(&htmlenv1, &obuf); 7055 flushline(&htmlenv1, &obuf, 0, 2, htmlenv1.limit); 7056 if (htmlenv1.title) 7057 newBuf->buffername = htmlenv1.title; 7058 if (w3m_halfdump) { 7059 TRAP_OFF; 7060 print_internal_information(&htmlenv1); 7061 return; 7062 } 7063 if (w3m_backend) { 7064 TRAP_OFF; 7065 print_internal_information(&htmlenv1); 7066 backend_halfdump_buf = htmlenv1.buf; 7067 return; 7068 } 7069 phase2: 7070 newBuf->trbyte = trbyte + linelen; 7071 TRAP_OFF; 7072 #ifdef USE_M17N 7073 if (!(newBuf->bufferprop & BP_FRAME)) 7074 newBuf->document_charset = charset; 7075 #endif 7076 #ifdef USE_IMAGE 7077 newBuf->image_flag = image_flag; 7078 #endif 7079 HTMLlineproc2(newBuf, htmlenv1.buf); 7080 } 7081 7082 /* 7083 * loadHTMLString: read string and make new buffer 7084 */ 7085 Buffer * 7086 loadHTMLString(Str page) 7087 { 7088 URLFile f; 7089 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; 7090 Buffer *newBuf; 7091 7092 newBuf = newBuffer(INIT_BUFFER_WIDTH); 7093 if (SETJMP(AbortLoading) != 0) { 7094 TRAP_OFF; 7095 discardBuffer(newBuf); 7096 return NULL; 7097 } 7098 TRAP_ON; 7099 7100 init_stream(&f, SCM_LOCAL, newStrStream(page)); 7101 7102 #ifdef USE_M17N 7103 newBuf->document_charset = InnerCharset; 7104 #endif 7105 loadHTMLstream(&f, newBuf, NULL, TRUE); 7106 #ifdef USE_M17N 7107 newBuf->document_charset = WC_CES_US_ASCII; 7108 #endif 7109 7110 TRAP_OFF; 7111 newBuf->topLine = newBuf->firstLine; 7112 newBuf->lastLine = newBuf->currentLine; 7113 newBuf->currentLine = newBuf->firstLine; 7114 newBuf->type = "text/html"; 7115 newBuf->real_type = newBuf->type; 7116 if (n_textarea) 7117 formResetBuffer(newBuf, newBuf->formitem); 7118 return newBuf; 7119 } 7120 7121 #ifdef USE_GOPHER 7122 7123 /* 7124 * loadGopherDir: get gopher directory 7125 */ 7126 Str 7127 loadGopherDir(URLFile *uf, ParsedURL *pu, wc_ces * charset) 7128 { 7129 Str volatile tmp; 7130 Str lbuf, name, file, host, port; 7131 char *volatile p, *volatile q; 7132 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; 7133 #ifdef USE_M17N 7134 wc_ces doc_charset = DocumentCharset; 7135 #endif 7136 7137 tmp = parsedURL2Str(pu); 7138 p = html_quote(tmp->ptr); 7139 tmp = 7140 convertLine(NULL, Strnew_charp(file_unquote(tmp->ptr)), RAW_MODE, 7141 charset, doc_charset); 7142 q = html_quote(tmp->ptr); 7143 tmp = Strnew_m_charp("<html>\n<head>\n<base href=\"", p, "\">\n<title>", q, 7144 "</title>\n</head>\n<body>\n<h1>Index of ", q, 7145 "</h1>\n<table>\n", NULL); 7146 7147 if (SETJMP(AbortLoading) != 0) 7148 goto gopher_end; 7149 TRAP_ON; 7150 7151 while (1) { 7152 if (lbuf = StrUFgets(uf), lbuf->length == 0) 7153 break; 7154 if (lbuf->ptr[0] == '.' && 7155 (lbuf->ptr[1] == '\n' || lbuf->ptr[1] == '\r')) 7156 break; 7157 lbuf = convertLine(uf, lbuf, HTML_MODE, charset, doc_charset); 7158 p = lbuf->ptr; 7159 for (q = p; *q && *q != '\t'; q++) ; 7160 name = Strnew_charp_n(p, q - p); 7161 if (!*q) 7162 continue; 7163 p = q + 1; 7164 for (q = p; *q && *q != '\t'; q++) ; 7165 file = Strnew_charp_n(p, q - p); 7166 if (!*q) 7167 continue; 7168 p = q + 1; 7169 for (q = p; *q && *q != '\t'; q++) ; 7170 host = Strnew_charp_n(p, q - p); 7171 if (!*q) 7172 continue; 7173 p = q + 1; 7174 for (q = p; *q && *q != '\t' && *q != '\r' && *q != '\n'; q++) ; 7175 port = Strnew_charp_n(p, q - p); 7176 7177 switch (name->ptr[0]) { 7178 case '0': 7179 p = "[text file]"; 7180 break; 7181 case '1': 7182 p = "[directory]"; 7183 break; 7184 case 'm': 7185 p = "[message]"; 7186 break; 7187 case 's': 7188 p = "[sound]"; 7189 break; 7190 case 'g': 7191 p = "[gif]"; 7192 break; 7193 case 'h': 7194 p = "[HTML]"; 7195 break; 7196 default: 7197 p = "[unsupported]"; 7198 break; 7199 } 7200 q = Strnew_m_charp("gopher://", host->ptr, ":", port->ptr, 7201 "/", file->ptr, NULL)->ptr; 7202 Strcat_m_charp(tmp, "<a href=\"", 7203 html_quote(url_quote_conv(q, *charset)), 7204 "\">", p, html_quote(name->ptr + 1), "</a>\n", NULL); 7205 } 7206 7207 gopher_end: 7208 TRAP_OFF; 7209 7210 Strcat_charp(tmp, "</table>\n</body>\n</html>\n"); 7211 return tmp; 7212 } 7213 #endif /* USE_GOPHER */ 7214 7215 /* 7216 * loadBuffer: read file and make new buffer 7217 */ 7218 Buffer * 7219 loadBuffer(URLFile *uf, Buffer *volatile newBuf) 7220 { 7221 FILE *volatile src = NULL; 7222 #ifdef USE_M17N 7223 wc_ces charset = WC_CES_US_ASCII; 7224 wc_ces volatile doc_charset = DocumentCharset; 7225 #endif 7226 Str lineBuf2; 7227 volatile char pre_lbuf = '\0'; 7228 int nlines; 7229 Str tmpf; 7230 clen_t linelen = 0, trbyte = 0; 7231 Lineprop *propBuffer = NULL; 7232 #ifdef USE_ANSI_COLOR 7233 Linecolor *colorBuffer = NULL; 7234 #endif 7235 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; 7236 7237 if (newBuf == NULL) 7238 newBuf = newBuffer(INIT_BUFFER_WIDTH); 7239 lineBuf2 = Strnew(); 7240 7241 if (SETJMP(AbortLoading) != 0) { 7242 goto _end; 7243 } 7244 TRAP_ON; 7245 7246 if (newBuf->sourcefile == NULL && 7247 (uf->scheme != SCM_LOCAL || newBuf->mailcap)) { 7248 tmpf = tmpfname(TMPF_SRC, NULL); 7249 src = fopen(tmpf->ptr, "w"); 7250 if (src) 7251 newBuf->sourcefile = tmpf->ptr; 7252 } 7253 #ifdef USE_M17N 7254 if (newBuf->document_charset) 7255 charset = doc_charset = newBuf->document_charset; 7256 if (content_charset && UseContentCharset) 7257 doc_charset = content_charset; 7258 #endif 7259 7260 nlines = 0; 7261 if (IStype(uf->stream) != IST_ENCODED) 7262 uf->stream = newEncodedStream(uf->stream, uf->encoding); 7263 while ((lineBuf2 = StrmyISgets(uf->stream))->length) { 7264 #ifdef USE_NNTP 7265 if (uf->scheme == SCM_NEWS && lineBuf2->ptr[0] == '.') { 7266 Strshrinkfirst(lineBuf2, 1); 7267 if (lineBuf2->ptr[0] == '\n' || lineBuf2->ptr[0] == '\r' || 7268 lineBuf2->ptr[0] == '\0') { 7269 /* 7270 * iseos(uf->stream) = TRUE; 7271 */ 7272 break; 7273 } 7274 } 7275 #endif /* USE_NNTP */ 7276 if (src) 7277 Strfputs(lineBuf2, src); 7278 linelen += lineBuf2->length; 7279 if (w3m_dump & DUMP_EXTRA) 7280 printf("W3m-in-progress: %s\n", convert_size2(linelen, current_content_length, TRUE)); 7281 if (w3m_dump & DUMP_SOURCE) 7282 continue; 7283 showProgress(&linelen, &trbyte); 7284 if (frame_source) 7285 continue; 7286 lineBuf2 = 7287 convertLine(uf, lineBuf2, PAGER_MODE, &charset, doc_charset); 7288 if (squeezeBlankLine) { 7289 if (lineBuf2->ptr[0] == '\n' && pre_lbuf == '\n') { 7290 ++nlines; 7291 continue; 7292 } 7293 pre_lbuf = lineBuf2->ptr[0]; 7294 } 7295 ++nlines; 7296 Strchop(lineBuf2); 7297 lineBuf2 = checkType(lineBuf2, &propBuffer, NULL); 7298 addnewline(newBuf, lineBuf2->ptr, propBuffer, colorBuffer, 7299 lineBuf2->length, FOLD_BUFFER_WIDTH, nlines); 7300 } 7301 _end: 7302 TRAP_OFF; 7303 newBuf->topLine = newBuf->firstLine; 7304 newBuf->lastLine = newBuf->currentLine; 7305 newBuf->currentLine = newBuf->firstLine; 7306 newBuf->trbyte = trbyte + linelen; 7307 #ifdef USE_M17N 7308 newBuf->document_charset = charset; 7309 #endif 7310 if (src) 7311 fclose(src); 7312 7313 return newBuf; 7314 } 7315 7316 #ifdef USE_IMAGE 7317 Buffer * 7318 loadImageBuffer(URLFile *uf, Buffer *newBuf) 7319 { 7320 Image image; 7321 ImageCache *cache; 7322 Str tmp, tmpf; 7323 FILE *src = NULL; 7324 URLFile f; 7325 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; 7326 struct stat st; 7327 7328 loadImage(newBuf, IMG_FLAG_STOP); 7329 image.url = uf->url; 7330 image.ext = uf->ext; 7331 image.width = -1; 7332 image.height = -1; 7333 image.cache = NULL; 7334 cache = getImage(&image, cur_baseURL, IMG_FLAG_AUTO); 7335 if (!cur_baseURL->is_nocache && cache->loaded & IMG_FLAG_LOADED && 7336 !stat(cache->file, &st)) 7337 goto image_buffer; 7338 7339 TRAP_ON; 7340 if (IStype(uf->stream) != IST_ENCODED) 7341 uf->stream = newEncodedStream(uf->stream, uf->encoding); 7342 if (save2tmp(*uf, cache->file) < 0) { 7343 UFclose(uf); 7344 TRAP_OFF; 7345 return NULL; 7346 } 7347 UFclose(uf); 7348 TRAP_OFF; 7349 7350 cache->loaded = IMG_FLAG_LOADED; 7351 cache->index = 0; 7352 7353 image_buffer: 7354 if (newBuf == NULL) 7355 newBuf = newBuffer(INIT_BUFFER_WIDTH); 7356 cache->loaded |= IMG_FLAG_DONT_REMOVE; 7357 if (newBuf->sourcefile == NULL && uf->scheme != SCM_LOCAL) 7358 newBuf->sourcefile = cache->file; 7359 7360 tmp = Sprintf("<img src=\"%s\"><br><br>", html_quote(image.url)); 7361 tmpf = tmpfname(TMPF_SRC, ".html"); 7362 src = fopen(tmpf->ptr, "w"); 7363 newBuf->mailcap_source = tmpf->ptr; 7364 7365 init_stream(&f, SCM_LOCAL, newStrStream(tmp)); 7366 loadHTMLstream(&f, newBuf, src, TRUE); 7367 if (src) 7368 fclose(src); 7369 7370 newBuf->topLine = newBuf->firstLine; 7371 newBuf->lastLine = newBuf->currentLine; 7372 newBuf->currentLine = newBuf->firstLine; 7373 newBuf->image_flag = IMG_FLAG_AUTO; 7374 return newBuf; 7375 } 7376 #endif 7377 7378 static Str 7379 conv_symbol(Line *l) 7380 { 7381 Str tmp = NULL; 7382 char *p = l->lineBuf, *ep = p + l->len; 7383 Lineprop *pr = l->propBuf; 7384 #ifdef USE_M17N 7385 int w; 7386 char **symbol = NULL; 7387 #else 7388 char **symbol = get_symbol(); 7389 #endif 7390 7391 for (; p < ep; p++, pr++) { 7392 if (*pr & PC_SYMBOL) { 7393 #ifdef USE_M17N 7394 char c = ((char)wtf_get_code((wc_uchar *) p) & 0x7f) - SYMBOL_BASE; 7395 int len = get_mclen(p); 7396 #else 7397 char c = *p - SYMBOL_BASE; 7398 #endif 7399 if (tmp == NULL) { 7400 tmp = Strnew_size(l->len); 7401 Strcopy_charp_n(tmp, l->lineBuf, p - l->lineBuf); 7402 #ifdef USE_M17N 7403 w = (*pr & PC_KANJI) ? 2 : 1; 7404 symbol = get_symbol(DisplayCharset, &w); 7405 #endif 7406 } 7407 Strcat_charp(tmp, symbol[(int)c]); 7408 #ifdef USE_M17N 7409 p += len - 1; 7410 pr += len - 1; 7411 #endif 7412 } 7413 else if (tmp != NULL) 7414 Strcat_char(tmp, *p); 7415 } 7416 if (tmp) 7417 return tmp; 7418 else 7419 return Strnew_charp_n(l->lineBuf, l->len); 7420 } 7421 7422 /* 7423 * saveBuffer: write buffer to file 7424 */ 7425 static void 7426 _saveBuffer(Buffer *buf, Line *l, FILE * f, int cont) 7427 { 7428 Str tmp; 7429 int is_html = FALSE; 7430 #ifdef USE_M17N 7431 int set_charset = !DisplayCharset; 7432 wc_ces charset = DisplayCharset ? DisplayCharset : WC_CES_US_ASCII; 7433 #endif 7434 7435 is_html = is_html_type(buf->type); 7436 7437 pager_next: 7438 for (; l != NULL; l = l->next) { 7439 if (is_html) 7440 tmp = conv_symbol(l); 7441 else 7442 tmp = Strnew_charp_n(l->lineBuf, l->len); 7443 tmp = wc_Str_conv(tmp, InnerCharset, charset); 7444 Strfputs(tmp, f); 7445 if (Strlastchar(tmp) != '\n' && !(cont && l->next && l->next->bpos)) 7446 putc('\n', f); 7447 } 7448 if (buf->pagerSource && !(buf->bufferprop & BP_CLOSE)) { 7449 l = getNextPage(buf, PagerMax); 7450 #ifdef USE_M17N 7451 if (set_charset) 7452 charset = buf->document_charset; 7453 #endif 7454 goto pager_next; 7455 } 7456 } 7457 7458 void 7459 saveBuffer(Buffer *buf, FILE * f, int cont) 7460 { 7461 _saveBuffer(buf, buf->firstLine, f, cont); 7462 } 7463 7464 void 7465 saveBufferBody(Buffer *buf, FILE * f, int cont) 7466 { 7467 Line *l = buf->firstLine; 7468 7469 while (l != NULL && l->real_linenumber == 0) 7470 l = l->next; 7471 _saveBuffer(buf, l, f, cont); 7472 } 7473 7474 static Buffer * 7475 loadcmdout(char *cmd, 7476 Buffer *(*loadproc) (URLFile *, Buffer *), Buffer *defaultbuf) 7477 { 7478 FILE *f, *popen(const char *, const char *); 7479 Buffer *buf; 7480 URLFile uf; 7481 7482 if (cmd == NULL || *cmd == '\0') 7483 return NULL; 7484 f = popen(cmd, "r"); 7485 if (f == NULL) 7486 return NULL; 7487 init_stream(&uf, SCM_UNKNOWN, newFileStream(f, (void (*)())pclose)); 7488 buf = loadproc(&uf, defaultbuf); 7489 UFclose(&uf); 7490 return buf; 7491 } 7492 7493 /* 7494 * getshell: execute shell command and get the result into a buffer 7495 */ 7496 Buffer * 7497 getshell(char *cmd) 7498 { 7499 Buffer *buf; 7500 7501 buf = loadcmdout(cmd, loadBuffer, NULL); 7502 if (buf == NULL) 7503 return NULL; 7504 buf->filename = cmd; 7505 buf->buffername = Sprintf("%s %s", SHELLBUFFERNAME, 7506 conv_from_system(cmd))->ptr; 7507 return buf; 7508 } 7509 7510 /* 7511 * getpipe: execute shell command and connect pipe to the buffer 7512 */ 7513 Buffer * 7514 getpipe(char *cmd) 7515 { 7516 FILE *f, *popen(const char *, const char *); 7517 Buffer *buf; 7518 7519 if (cmd == NULL || *cmd == '\0') 7520 return NULL; 7521 f = popen(cmd, "r"); 7522 if (f == NULL) 7523 return NULL; 7524 buf = newBuffer(INIT_BUFFER_WIDTH); 7525 buf->pagerSource = newFileStream(f, (void (*)())pclose); 7526 buf->filename = cmd; 7527 buf->buffername = Sprintf("%s %s", PIPEBUFFERNAME, 7528 conv_from_system(cmd))->ptr; 7529 buf->bufferprop |= BP_PIPE; 7530 #ifdef USE_M17N 7531 buf->document_charset = WC_CES_US_ASCII; 7532 #endif 7533 return buf; 7534 } 7535 7536 /* 7537 * Open pager buffer 7538 */ 7539 Buffer * 7540 openPagerBuffer(InputStream stream, Buffer *buf) 7541 { 7542 7543 if (buf == NULL) 7544 buf = newBuffer(INIT_BUFFER_WIDTH); 7545 buf->pagerSource = stream; 7546 buf->buffername = getenv("MAN_PN"); 7547 if (buf->buffername == NULL) 7548 buf->buffername = PIPEBUFFERNAME; 7549 else 7550 buf->buffername = conv_from_system(buf->buffername); 7551 buf->bufferprop |= BP_PIPE; 7552 #ifdef USE_M17N 7553 if (content_charset && UseContentCharset) 7554 buf->document_charset = content_charset; 7555 else 7556 buf->document_charset = WC_CES_US_ASCII; 7557 #endif 7558 buf->currentLine = buf->firstLine; 7559 7560 return buf; 7561 } 7562 7563 Buffer * 7564 openGeneralPagerBuffer(InputStream stream) 7565 { 7566 Buffer *buf; 7567 char *t = "text/plain"; 7568 Buffer *t_buf = NULL; 7569 URLFile uf; 7570 7571 init_stream(&uf, SCM_UNKNOWN, stream); 7572 7573 #ifdef USE_M17N 7574 content_charset = 0; 7575 #endif 7576 if (SearchHeader) { 7577 t_buf = newBuffer(INIT_BUFFER_WIDTH); 7578 readHeader(&uf, t_buf, TRUE, NULL); 7579 t = checkContentType(t_buf); 7580 if (t == NULL) 7581 t = "text/plain"; 7582 if (t_buf) { 7583 t_buf->topLine = t_buf->firstLine; 7584 t_buf->currentLine = t_buf->lastLine; 7585 } 7586 SearchHeader = FALSE; 7587 } 7588 else if (DefaultType) { 7589 t = DefaultType; 7590 DefaultType = NULL; 7591 } 7592 if (is_html_type(t)) { 7593 buf = loadHTMLBuffer(&uf, t_buf); 7594 buf->type = "text/html"; 7595 } 7596 else if (is_plain_text_type(t)) { 7597 if (IStype(stream) != IST_ENCODED) 7598 stream = newEncodedStream(stream, uf.encoding); 7599 buf = openPagerBuffer(stream, t_buf); 7600 buf->type = "text/plain"; 7601 } 7602 #ifdef USE_IMAGE 7603 else if (activeImage && displayImage && !useExtImageViewer && 7604 !(w3m_dump & ~DUMP_FRAME) && !strncasecmp(t, "image/", 6)) { 7605 cur_baseURL = New(ParsedURL); 7606 parseURL("-", cur_baseURL, NULL); 7607 buf = loadImageBuffer(&uf, t_buf); 7608 buf->type = "text/html"; 7609 } 7610 #endif 7611 else { 7612 if (doExternal(uf, "-", t, &buf, t_buf)) { 7613 UFclose(&uf); 7614 if (buf == NULL || buf == NO_BUFFER) 7615 return buf; 7616 } 7617 else { /* unknown type is regarded as text/plain */ 7618 if (IStype(stream) != IST_ENCODED) 7619 stream = newEncodedStream(stream, uf.encoding); 7620 buf = openPagerBuffer(stream, t_buf); 7621 buf->type = "text/plain"; 7622 } 7623 } 7624 buf->real_type = t; 7625 buf->currentURL.scheme = SCM_LOCAL; 7626 buf->currentURL.file = "-"; 7627 return buf; 7628 } 7629 7630 Line * 7631 getNextPage(Buffer *buf, int plen) 7632 { 7633 Line *volatile top = buf->topLine, *volatile last = buf->lastLine, 7634 *volatile cur = buf->currentLine; 7635 int i; 7636 int volatile nlines = 0; 7637 clen_t linelen = 0, trbyte = buf->trbyte; 7638 Str lineBuf2; 7639 char volatile pre_lbuf = '\0'; 7640 URLFile uf; 7641 #ifdef USE_M17N 7642 wc_ces charset; 7643 wc_ces volatile doc_charset = DocumentCharset; 7644 wc_uint8 old_auto_detect = WcOption.auto_detect; 7645 #endif 7646 int volatile squeeze_flag = FALSE; 7647 Lineprop *propBuffer = NULL; 7648 7649 #ifdef USE_ANSI_COLOR 7650 Linecolor *colorBuffer = NULL; 7651 #endif 7652 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; 7653 7654 if (buf->pagerSource == NULL) 7655 return NULL; 7656 7657 if (last != NULL) { 7658 nlines = last->real_linenumber; 7659 pre_lbuf = *(last->lineBuf); 7660 if (pre_lbuf == '\0') 7661 pre_lbuf = '\n'; 7662 buf->currentLine = last; 7663 } 7664 7665 #ifdef USE_M17N 7666 charset = buf->document_charset; 7667 if (buf->document_charset != WC_CES_US_ASCII) 7668 doc_charset = buf->document_charset; 7669 else if (UseContentCharset) { 7670 content_charset = 0; 7671 checkContentType(buf); 7672 if (content_charset) 7673 doc_charset = content_charset; 7674 } 7675 WcOption.auto_detect = buf->auto_detect; 7676 #endif 7677 7678 if (SETJMP(AbortLoading) != 0) { 7679 goto pager_end; 7680 } 7681 TRAP_ON; 7682 7683 init_stream(&uf, SCM_UNKNOWN, NULL); 7684 for (i = 0; i < plen; i++) { 7685 lineBuf2 = StrmyISgets(buf->pagerSource); 7686 if (lineBuf2->length == 0) { 7687 /* Assume that `cmd == buf->filename' */ 7688 if (buf->filename) 7689 buf->buffername = Sprintf("%s %s", 7690 CPIPEBUFFERNAME, 7691 conv_from_system(buf->filename))-> 7692 ptr; 7693 else if (getenv("MAN_PN") == NULL) 7694 buf->buffername = CPIPEBUFFERNAME; 7695 buf->bufferprop |= BP_CLOSE; 7696 break; 7697 } 7698 linelen += lineBuf2->length; 7699 showProgress(&linelen, &trbyte); 7700 lineBuf2 = 7701 convertLine(&uf, lineBuf2, PAGER_MODE, &charset, doc_charset); 7702 if (squeezeBlankLine) { 7703 squeeze_flag = FALSE; 7704 if (lineBuf2->ptr[0] == '\n' && pre_lbuf == '\n') { 7705 ++nlines; 7706 --i; 7707 squeeze_flag = TRUE; 7708 continue; 7709 } 7710 pre_lbuf = lineBuf2->ptr[0]; 7711 } 7712 ++nlines; 7713 Strchop(lineBuf2); 7714 lineBuf2 = checkType(lineBuf2, &propBuffer, &colorBuffer); 7715 addnewline(buf, lineBuf2->ptr, propBuffer, colorBuffer, 7716 lineBuf2->length, FOLD_BUFFER_WIDTH, nlines); 7717 if (!top) { 7718 top = buf->firstLine; 7719 cur = top; 7720 } 7721 if (buf->lastLine->real_linenumber - buf->firstLine->real_linenumber 7722 >= PagerMax) { 7723 Line *l = buf->firstLine; 7724 do { 7725 if (top == l) 7726 top = l->next; 7727 if (cur == l) 7728 cur = l->next; 7729 if (last == l) 7730 last = NULL; 7731 l = l->next; 7732 } while (l && l->bpos); 7733 buf->firstLine = l; 7734 buf->firstLine->prev = NULL; 7735 } 7736 } 7737 pager_end: 7738 TRAP_OFF; 7739 7740 buf->trbyte = trbyte + linelen; 7741 #ifdef USE_M17N 7742 buf->document_charset = charset; 7743 WcOption.auto_detect = old_auto_detect; 7744 #endif 7745 buf->topLine = top; 7746 buf->currentLine = cur; 7747 if (!last) 7748 last = buf->firstLine; 7749 else if (last && (last->next || !squeeze_flag)) 7750 last = last->next; 7751 return last; 7752 } 7753 7754 int 7755 save2tmp(URLFile uf, char *tmpf) 7756 { 7757 FILE *ff; 7758 int check; 7759 clen_t linelen = 0, trbyte = 0; 7760 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL; 7761 static JMP_BUF env_bak; 7762 7763 ff = fopen(tmpf, "wb"); 7764 if (ff == NULL) { 7765 /* fclose(f); */ 7766 return -1; 7767 } 7768 bcopy(AbortLoading, env_bak, sizeof(JMP_BUF)); 7769 if (SETJMP(AbortLoading) != 0) { 7770 goto _end; 7771 } 7772 TRAP_ON; 7773 check = 0; 7774 #ifdef USE_NNTP 7775 if (uf.scheme == SCM_NEWS) { 7776 char c; 7777 while (c = UFgetc(&uf), !iseos(uf.stream)) { 7778 if (c == '\n') { 7779 if (check == 0) 7780 check++; 7781 else if (check == 3) 7782 break; 7783 } 7784 else if (c == '.' && check == 1) 7785 check++; 7786 else if (c == '\r' && check == 2) 7787 check++; 7788 else 7789 check = 0; 7790 putc(c, ff); 7791 linelen += sizeof(c); 7792 showProgress(&linelen, &trbyte); 7793 } 7794 } 7795 else 7796 #endif /* USE_NNTP */ 7797 { 7798 Str buf = Strnew_size(SAVE_BUF_SIZE); 7799 while (UFread(&uf, buf, SAVE_BUF_SIZE)) { 7800 if (Strfputs(buf, ff) != buf->length) { 7801 bcopy(env_bak, AbortLoading, sizeof(JMP_BUF)); 7802 TRAP_OFF; 7803 fclose(ff); 7804 current_content_length = 0; 7805 return -2; 7806 } 7807 linelen += buf->length; 7808 showProgress(&linelen, &trbyte); 7809 } 7810 } 7811 _end: 7812 bcopy(env_bak, AbortLoading, sizeof(JMP_BUF)); 7813 TRAP_OFF; 7814 fclose(ff); 7815 current_content_length = 0; 7816 return 0; 7817 } 7818 7819 int 7820 doExternal(URLFile uf, char *path, char *type, Buffer **bufp, 7821 Buffer *defaultbuf) 7822 { 7823 Str tmpf, command; 7824 struct mailcap *mcap; 7825 int mc_stat; 7826 Buffer *buf = NULL; 7827 char *header, *src = NULL, *ext = uf.ext; 7828 7829 if (!(mcap = searchExtViewer(type))) 7830 return 0; 7831 7832 if (mcap->nametemplate) { 7833 tmpf = unquote_mailcap(mcap->nametemplate, NULL, "", NULL, NULL); 7834 if (tmpf->ptr[0] == '.') 7835 ext = tmpf->ptr; 7836 } 7837 tmpf = tmpfname(TMPF_DFL, (ext && *ext) ? ext : NULL); 7838 7839 if (IStype(uf.stream) != IST_ENCODED) 7840 uf.stream = newEncodedStream(uf.stream, uf.encoding); 7841 header = checkHeader(defaultbuf, "Content-Type:"); 7842 if (header) 7843 header = conv_to_system(header); 7844 command = unquote_mailcap(mcap->viewer, type, tmpf->ptr, header, &mc_stat); 7845 #ifndef __EMX__ 7846 if (!(mc_stat & MCSTAT_REPNAME)) { 7847 Str tmp = Sprintf("(%s) < %s", command->ptr, shell_quote(tmpf->ptr)); 7848 command = tmp; 7849 } 7850 #endif 7851 7852 #ifdef HAVE_SETPGRP 7853 if (!(mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT)) && 7854 !(mcap->flags & MAILCAP_NEEDSTERMINAL) && BackgroundExtViewer) { 7855 flush_tty(); 7856 if (!fork()) { 7857 setup_child(FALSE, 0, UFfileno(&uf)); 7858 if (save2tmp(uf, tmpf->ptr) < 0) 7859 exit(1); 7860 UFclose(&uf); 7861 myExec(command->ptr); 7862 } 7863 *bufp = NO_BUFFER; 7864 return 1; 7865 } 7866 else 7867 #endif 7868 { 7869 if (save2tmp(uf, tmpf->ptr) < 0) { 7870 *bufp = NULL; 7871 return 1; 7872 } 7873 } 7874 if (mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT)) { 7875 if (defaultbuf == NULL) 7876 defaultbuf = newBuffer(INIT_BUFFER_WIDTH); 7877 if (defaultbuf->sourcefile) 7878 src = defaultbuf->sourcefile; 7879 else 7880 src = tmpf->ptr; 7881 defaultbuf->sourcefile = NULL; 7882 defaultbuf->mailcap = mcap; 7883 } 7884 if (mcap->flags & MAILCAP_HTMLOUTPUT) { 7885 buf = loadcmdout(command->ptr, loadHTMLBuffer, defaultbuf); 7886 if (buf && buf != NO_BUFFER) { 7887 buf->type = "text/html"; 7888 buf->mailcap_source = buf->sourcefile; 7889 buf->sourcefile = src; 7890 } 7891 } 7892 else if (mcap->flags & MAILCAP_COPIOUSOUTPUT) { 7893 buf = loadcmdout(command->ptr, loadBuffer, defaultbuf); 7894 if (buf && buf != NO_BUFFER) { 7895 buf->type = "text/plain"; 7896 buf->mailcap_source = buf->sourcefile; 7897 buf->sourcefile = src; 7898 } 7899 } 7900 else { 7901 if (mcap->flags & MAILCAP_NEEDSTERMINAL || !BackgroundExtViewer) { 7902 fmTerm(); 7903 mySystem(command->ptr, 0); 7904 fmInit(); 7905 if (CurrentTab && Currentbuf) 7906 displayBuffer(Currentbuf, B_FORCE_REDRAW); 7907 } 7908 else { 7909 mySystem(command->ptr, 1); 7910 } 7911 buf = NO_BUFFER; 7912 } 7913 if (buf && buf != NO_BUFFER) { 7914 buf->filename = path; 7915 if (buf->buffername == NULL || buf->buffername[0] == '\0') 7916 buf->buffername = conv_from_system(lastFileName(path)); 7917 buf->edit = mcap->edit; 7918 buf->mailcap = mcap; 7919 } 7920 *bufp = buf; 7921 return 1; 7922 } 7923 7924 static int 7925 _MoveFile(char *path1, char *path2) 7926 { 7927 InputStream f1; 7928 FILE *f2; 7929 int is_pipe; 7930 clen_t linelen = 0, trbyte = 0; 7931 Str buf; 7932 7933 f1 = openIS(path1); 7934 if (f1 == NULL) 7935 return -1; 7936 if (*path2 == '|' && PermitSaveToPipe) { 7937 is_pipe = TRUE; 7938 f2 = popen(path2 + 1, "w"); 7939 } 7940 else { 7941 is_pipe = FALSE; 7942 f2 = fopen(path2, "wb"); 7943 } 7944 if (f2 == NULL) { 7945 ISclose(f1); 7946 return -1; 7947 } 7948 current_content_length = 0; 7949 buf = Strnew_size(SAVE_BUF_SIZE); 7950 while (ISread(f1, buf, SAVE_BUF_SIZE)) { 7951 Strfputs(buf, f2); 7952 linelen += buf->length; 7953 showProgress(&linelen, &trbyte); 7954 } 7955 ISclose(f1); 7956 if (is_pipe) 7957 pclose(f2); 7958 else 7959 fclose(f2); 7960 return 0; 7961 } 7962 7963 int 7964 _doFileCopy(char *tmpf, char *defstr, int download) 7965 { 7966 #ifndef __MINGW32_VERSION 7967 Str msg; 7968 Str filen; 7969 char *p, *q = NULL; 7970 pid_t pid; 7971 char *lock; 7972 #if !(defined(HAVE_SYMLINK) && defined(HAVE_LSTAT)) 7973 FILE *f; 7974 #endif 7975 struct stat st; 7976 clen_t size = 0; 7977 int is_pipe = FALSE; 7978 7979 if (fmInitialized) { 7980 p = searchKeyData(); 7981 if (p == NULL || *p == '\0') { 7982 /* FIXME: gettextize? */ 7983 q = inputLineHist("(Download)Save file to: ", 7984 defstr, IN_COMMAND, SaveHist); 7985 if (q == NULL || *q == '\0') 7986 return FALSE; 7987 p = conv_to_system(q); 7988 } 7989 if (*p == '|' && PermitSaveToPipe) 7990 is_pipe = TRUE; 7991 else { 7992 if (q) { 7993 p = unescape_spaces(Strnew_charp(q))->ptr; 7994 p = conv_to_system(q); 7995 } 7996 p = expandPath(p); 7997 if (checkOverWrite(p) < 0) 7998 return -1; 7999 } 8000 if (checkCopyFile(tmpf, p) < 0) { 8001 /* FIXME: gettextize? */ 8002 msg = Sprintf("Can't copy. %s and %s are identical.", 8003 conv_from_system(tmpf), conv_from_system(p)); 8004 disp_err_message(msg->ptr, FALSE); 8005 return -1; 8006 } 8007 if (!download) { 8008 if (_MoveFile(tmpf, p) < 0) { 8009 /* FIXME: gettextize? */ 8010 msg = Sprintf("Can't save to %s", conv_from_system(p)); 8011 disp_err_message(msg->ptr, FALSE); 8012 } 8013 return -1; 8014 } 8015 lock = tmpfname(TMPF_DFL, ".lock")->ptr; 8016 #if defined(HAVE_SYMLINK) && defined(HAVE_LSTAT) 8017 symlink(p, lock); 8018 #else 8019 f = fopen(lock, "w"); 8020 if (f) 8021 fclose(f); 8022 #endif 8023 flush_tty(); 8024 pid = fork(); 8025 if (!pid) { 8026 setup_child(FALSE, 0, -1); 8027 if (!_MoveFile(tmpf, p) && PreserveTimestamp && !is_pipe && 8028 !stat(tmpf, &st)) 8029 setModtime(p, st.st_mtime); 8030 unlink(lock); 8031 exit(0); 8032 } 8033 if (!stat(tmpf, &st)) 8034 size = st.st_size; 8035 addDownloadList(pid, conv_from_system(tmpf), p, lock, size); 8036 } 8037 else { 8038 q = searchKeyData(); 8039 if (q == NULL || *q == '\0') { 8040 /* FIXME: gettextize? */ 8041 printf("(Download)Save file to: "); 8042 fflush(stdout); 8043 filen = Strfgets(stdin); 8044 if (filen->length == 0) 8045 return -1; 8046 q = filen->ptr; 8047 } 8048 for (p = q + strlen(q) - 1; IS_SPACE(*p); p--) ; 8049 *(p + 1) = '\0'; 8050 if (*q == '\0') 8051 return -1; 8052 p = q; 8053 if (*p == '|' && PermitSaveToPipe) 8054 is_pipe = TRUE; 8055 else { 8056 p = expandPath(p); 8057 if (checkOverWrite(p) < 0) 8058 return -1; 8059 } 8060 if (checkCopyFile(tmpf, p) < 0) { 8061 /* FIXME: gettextize? */ 8062 printf("Can't copy. %s and %s are identical.", tmpf, p); 8063 return -1; 8064 } 8065 if (_MoveFile(tmpf, p) < 0) { 8066 /* FIXME: gettextize? */ 8067 printf("Can't save to %s\n", p); 8068 return -1; 8069 } 8070 if (PreserveTimestamp && !is_pipe && !stat(tmpf, &st)) 8071 setModtime(p, st.st_mtime); 8072 } 8073 #endif /* __MINGW32_VERSION */ 8074 return 0; 8075 } 8076 8077 int 8078 doFileMove(char *tmpf, char *defstr) 8079 { 8080 int ret = doFileCopy(tmpf, defstr); 8081 unlink(tmpf); 8082 return ret; 8083 } 8084 8085 int 8086 doFileSave(URLFile uf, char *defstr) 8087 { 8088 #ifndef __MINGW32_VERSION 8089 Str msg; 8090 Str filen; 8091 char *p, *q; 8092 pid_t pid; 8093 char *lock; 8094 char *tmpf = NULL; 8095 #if !(defined(HAVE_SYMLINK) && defined(HAVE_LSTAT)) 8096 FILE *f; 8097 #endif 8098 8099 if (fmInitialized) { 8100 p = searchKeyData(); 8101 if (p == NULL || *p == '\0') { 8102 /* FIXME: gettextize? */ 8103 p = inputLineHist("(Download)Save file to: ", 8104 defstr, IN_FILENAME, SaveHist); 8105 if (p == NULL || *p == '\0') 8106 return -1; 8107 p = conv_to_system(p); 8108 } 8109 if (checkOverWrite(p) < 0) 8110 return -1; 8111 if (checkSaveFile(uf.stream, p) < 0) { 8112 /* FIXME: gettextize? */ 8113 msg = Sprintf("Can't save. Load file and %s are identical.", 8114 conv_from_system(p)); 8115 disp_err_message(msg->ptr, FALSE); 8116 return -1; 8117 } 8118 /* 8119 * if (save2tmp(uf, p) < 0) { 8120 * msg = Sprintf("Can't save to %s", conv_from_system(p)); 8121 * disp_err_message(msg->ptr, FALSE); 8122 * } 8123 */ 8124 lock = tmpfname(TMPF_DFL, ".lock")->ptr; 8125 #if defined(HAVE_SYMLINK) && defined(HAVE_LSTAT) 8126 symlink(p, lock); 8127 #else 8128 f = fopen(lock, "w"); 8129 if (f) 8130 fclose(f); 8131 #endif 8132 flush_tty(); 8133 pid = fork(); 8134 if (!pid) { 8135 int err; 8136 if ((uf.content_encoding != CMP_NOCOMPRESS) && AutoUncompress) { 8137 uncompress_stream(&uf, &tmpf); 8138 if (tmpf) 8139 unlink(tmpf); 8140 } 8141 setup_child(FALSE, 0, UFfileno(&uf)); 8142 err = save2tmp(uf, p); 8143 if (err == 0 && PreserveTimestamp && uf.modtime != -1) 8144 setModtime(p, uf.modtime); 8145 UFclose(&uf); 8146 unlink(lock); 8147 if (err != 0) 8148 exit(-err); 8149 exit(0); 8150 } 8151 addDownloadList(pid, uf.url, p, lock, current_content_length); 8152 } 8153 else { 8154 q = searchKeyData(); 8155 if (q == NULL || *q == '\0') { 8156 /* FIXME: gettextize? */ 8157 printf("(Download)Save file to: "); 8158 fflush(stdout); 8159 filen = Strfgets(stdin); 8160 if (filen->length == 0) 8161 return -1; 8162 q = filen->ptr; 8163 } 8164 for (p = q + strlen(q) - 1; IS_SPACE(*p); p--) ; 8165 *(p + 1) = '\0'; 8166 if (*q == '\0') 8167 return -1; 8168 p = expandPath(q); 8169 if (checkOverWrite(p) < 0) 8170 return -1; 8171 if (checkSaveFile(uf.stream, p) < 0) { 8172 /* FIXME: gettextize? */ 8173 printf("Can't save. Load file and %s are identical.", p); 8174 return -1; 8175 } 8176 if (uf.content_encoding != CMP_NOCOMPRESS && AutoUncompress) { 8177 uncompress_stream(&uf, &tmpf); 8178 if (tmpf) 8179 unlink(tmpf); 8180 } 8181 if (save2tmp(uf, p) < 0) { 8182 /* FIXME: gettextize? */ 8183 printf("Can't save to %s\n", p); 8184 return -1; 8185 } 8186 if (PreserveTimestamp && uf.modtime != -1) 8187 setModtime(p, uf.modtime); 8188 } 8189 #endif /* __MINGW32_VERSION */ 8190 return 0; 8191 } 8192 8193 int 8194 checkCopyFile(char *path1, char *path2) 8195 { 8196 struct stat st1, st2; 8197 8198 if (*path2 == '|' && PermitSaveToPipe) 8199 return 0; 8200 if ((stat(path1, &st1) == 0) && (stat(path2, &st2) == 0)) 8201 if (st1.st_ino == st2.st_ino) 8202 return -1; 8203 return 0; 8204 } 8205 8206 int 8207 checkSaveFile(InputStream stream, char *path2) 8208 { 8209 struct stat st1, st2; 8210 int des = ISfileno(stream); 8211 8212 if (des < 0) 8213 return 0; 8214 if (*path2 == '|' && PermitSaveToPipe) 8215 return 0; 8216 if ((fstat(des, &st1) == 0) && (stat(path2, &st2) == 0)) 8217 if (st1.st_ino == st2.st_ino) 8218 return -1; 8219 return 0; 8220 } 8221 8222 int 8223 checkOverWrite(char *path) 8224 { 8225 struct stat st; 8226 char *ans; 8227 8228 if (stat(path, &st) < 0) 8229 return 0; 8230 /* FIXME: gettextize? */ 8231 ans = inputAnswer("File exists. Overwrite? (y/n)"); 8232 if (ans && TOLOWER(*ans) == 'y') 8233 return 0; 8234 else 8235 return -1; 8236 } 8237 8238 char * 8239 inputAnswer(char *prompt) 8240 { 8241 char *ans; 8242 8243 if (QuietMessage) 8244 return "n"; 8245 if (fmInitialized) { 8246 term_raw(); 8247 ans = inputChar(prompt); 8248 } 8249 else { 8250 printf("%s", prompt); 8251 fflush(stdout); 8252 ans = Strfgets(stdin)->ptr; 8253 } 8254 return ans; 8255 } 8256 8257 static void 8258 uncompress_stream(URLFile *uf, char **src) 8259 { 8260 #ifndef __MINGW32_VERSION 8261 pid_t pid1; 8262 FILE *f1; 8263 char *expand_cmd = GUNZIP_CMDNAME; 8264 char *expand_name = GUNZIP_NAME; 8265 char *tmpf = NULL; 8266 char *ext = NULL; 8267 struct compression_decoder *d; 8268 8269 if (IStype(uf->stream) != IST_ENCODED) { 8270 uf->stream = newEncodedStream(uf->stream, uf->encoding); 8271 uf->encoding = ENC_7BIT; 8272 } 8273 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) { 8274 if (uf->compression == d->type) { 8275 if (d->auxbin_p) 8276 expand_cmd = auxbinFile(d->cmd); 8277 else 8278 expand_cmd = d->cmd; 8279 expand_name = d->name; 8280 ext = d->ext; 8281 break; 8282 } 8283 } 8284 uf->compression = CMP_NOCOMPRESS; 8285 8286 if (uf->scheme != SCM_LOCAL 8287 #ifdef USE_IMAGE 8288 && !image_source 8289 #endif 8290 ) { 8291 tmpf = tmpfname(TMPF_DFL, ext)->ptr; 8292 } 8293 8294 /* child1 -- stdout|f1=uf -> parent */ 8295 pid1 = open_pipe_rw(&f1, NULL); 8296 if (pid1 < 0) { 8297 UFclose(uf); 8298 return; 8299 } 8300 if (pid1 == 0) { 8301 /* child */ 8302 pid_t pid2; 8303 FILE *f2 = stdin; 8304 8305 /* uf -> child2 -- stdout|stdin -> child1 */ 8306 pid2 = open_pipe_rw(&f2, NULL); 8307 if (pid2 < 0) { 8308 UFclose(uf); 8309 exit(1); 8310 } 8311 if (pid2 == 0) { 8312 /* child2 */ 8313 Str buf = Strnew_size(SAVE_BUF_SIZE); 8314 FILE *f = NULL; 8315 8316 setup_child(TRUE, 2, UFfileno(uf)); 8317 if (tmpf) 8318 f = fopen(tmpf, "wb"); 8319 while (UFread(uf, buf, SAVE_BUF_SIZE)) { 8320 if (Strfputs(buf, stdout) < 0) 8321 break; 8322 if (f) 8323 Strfputs(buf, f); 8324 } 8325 UFclose(uf); 8326 if (f) 8327 fclose(f); 8328 exit(0); 8329 } 8330 /* child1 */ 8331 dup2(1, 2); /* stderr>&stdout */ 8332 setup_child(TRUE, -1, -1); 8333 execlp(expand_cmd, expand_name, NULL); 8334 exit(1); 8335 } 8336 if (tmpf) { 8337 if (src) 8338 *src = tmpf; 8339 else 8340 uf->scheme = SCM_LOCAL; 8341 } 8342 UFhalfclose(uf); 8343 uf->stream = newFileStream(f1, (void (*)())fclose); 8344 #endif /* __MINGW32_VERSION */ 8345 } 8346 8347 static FILE * 8348 lessopen_stream(char *path) 8349 { 8350 char *lessopen; 8351 FILE *fp; 8352 8353 lessopen = getenv("LESSOPEN"); 8354 if (lessopen == NULL) { 8355 return NULL; 8356 } 8357 if (lessopen[0] == '\0') { 8358 return NULL; 8359 } 8360 8361 if (lessopen[0] == '|') { 8362 /* pipe mode */ 8363 Str tmpf; 8364 int c; 8365 8366 ++lessopen; 8367 tmpf = Sprintf(lessopen, shell_quote(path)); 8368 fp = popen(tmpf->ptr, "r"); 8369 if (fp == NULL) { 8370 return NULL; 8371 } 8372 c = getc(fp); 8373 if (c == EOF) { 8374 fclose(fp); 8375 return NULL; 8376 } 8377 ungetc(c, fp); 8378 } 8379 else { 8380 /* filename mode */ 8381 /* not supported m(__)m */ 8382 fp = NULL; 8383 } 8384 return fp; 8385 } 8386 8387 #if 0 8388 void 8389 reloadBuffer(Buffer *buf) 8390 { 8391 URLFile uf; 8392 8393 if (buf->sourcefile == NULL || buf->pagerSource != NULL) 8394 return; 8395 init_stream(&uf, SCM_UNKNOWN, NULL); 8396 examineFile(buf->mailcap_source ? buf->mailcap_source : buf->sourcefile, 8397 &uf); 8398 if (uf.stream == NULL) 8399 return; 8400 is_redisplay = TRUE; 8401 buf->allLine = 0; 8402 buf->href = NULL; 8403 buf->name = NULL; 8404 buf->img = NULL; 8405 buf->formitem = NULL; 8406 buf->linklist = NULL; 8407 buf->maplist = NULL; 8408 if (buf->hmarklist) 8409 buf->hmarklist->nmark = 0; 8410 if (buf->imarklist) 8411 buf->imarklist->nmark = 0; 8412 if (is_html_type(buf->type)) 8413 loadHTMLBuffer(&uf, buf); 8414 else 8415 loadBuffer(&uf, buf); 8416 UFclose(&uf); 8417 is_redisplay = FALSE; 8418 } 8419 #endif 8420 8421 static char * 8422 guess_filename(char *file) 8423 { 8424 char *p = NULL, *s; 8425 8426 if (file != NULL) 8427 p = mybasename(file); 8428 if (p == NULL || *p == '\0') 8429 return DEF_SAVE_FILE; 8430 s = p; 8431 if (*p == '#') 8432 p++; 8433 while (*p != '\0') { 8434 if ((*p == '#' && *(p + 1) != '\0') || *p == '?') { 8435 *p = '\0'; 8436 break; 8437 } 8438 p++; 8439 } 8440 return s; 8441 } 8442 8443 char * 8444 guess_save_name(Buffer *buf, char *path) 8445 { 8446 if (buf && buf->document_header) { 8447 Str name = NULL; 8448 char *p, *q; 8449 if ((p = checkHeader(buf, "Content-Disposition:")) != NULL && 8450 (q = strcasestr(p, "filename")) != NULL && 8451 (q == p || IS_SPACE(*(q - 1)) || *(q - 1) == ';') && 8452 matchattr(q, "filename", 8, &name)) 8453 path = name->ptr; 8454 else if ((p = checkHeader(buf, "Content-Type:")) != NULL && 8455 (q = strcasestr(p, "name")) != NULL && 8456 (q == p || IS_SPACE(*(q - 1)) || *(q - 1) == ';') && 8457 matchattr(q, "name", 4, &name)) 8458 path = name->ptr; 8459 } 8460 return guess_filename(path); 8461 } 8462 8463 /* Local Variables: */ 8464 /* c-basic-offset: 4 */ 8465 /* tab-width: 8 */ 8466 /* End: */