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