1 /* $Id: file.c,v 1.254 2007/05/23 15:06:05 inu Exp $ */
7 #if defined(HAVE_WAITPID) || defined(HAVE_WAIT3)
18 #include "parsetagx.h"
23 #define max(a,b) ((a) > (b) ? (a) : (b))
26 #define min(a,b) ((a) > (b) ? (b) : (a))
29 static int frame_source = 0;
31 static char *guess_filename(char *file);
32 static int _MoveFile(char *path1, char *path2);
33 static void uncompress_stream(URLFile *uf, char **src);
34 static FILE *lessopen_stream(char *path);
35 static Buffer *loadcmdout(char *cmd,
36 Buffer *(*loadproc) (URLFile *, Buffer *),
38 #ifndef USE_ANSI_COLOR
39 #define addnewline(a,b,c,d,e,f,g) _addnewline(a,b,c,e,f,g)
41 static void addnewline(Buffer *buf, char *line, Lineprop *prop,
42 Linecolor *color, int pos, int width, int nlines);
43 static void addLink(Buffer *buf, struct parsed_tag *tag);
45 static JMP_BUF AbortLoading;
47 static struct table *tables[MAX_TABLE];
48 static struct table_mode table_mode[MAX_TABLE];
51 static ParsedURL *cur_baseURL = NULL;
53 static char cur_document_charset;
58 static Str cur_select;
59 static Str select_str;
60 static int select_is_multiple;
61 static int n_selectitem;
62 static Str cur_option;
63 static Str cur_option_value;
64 static Str cur_option_label;
65 static int cur_option_selected;
66 static int cur_status;
68 /* menu based <select> */
69 FormSelectOption *select_option;
70 static int max_select = MAX_SELECT;
72 static int cur_option_maxwidth;
73 #endif /* MENU_SELECT */
75 static Str cur_textarea;
77 static int cur_textarea_size;
78 static int cur_textarea_rows;
79 static int cur_textarea_readonly;
80 static int n_textarea;
81 static int ignore_nl_textarea;
82 static int max_textarea = MAX_TEXTAREA;
84 static int http_response_code;
87 static wc_ces content_charset = 0;
88 static wc_ces meta_charset = 0;
89 static char *check_charset(char *p);
90 static char *check_accept_charset(char *p);
93 #define set_prevchar(x,y,n) Strcopy_charp_n((x),(y),(n))
94 #define set_space_to_prevchar(x) Strcopy_charp_n((x)," ",1)
100 struct link_stack *next;
103 static struct link_stack *link_stack = NULL;
105 #define FORMSTACK_SIZE 10
106 #define FRAMESTACK_SIZE 10
109 #define Str_news_endline(s) ((s)->ptr[0]=='.'&&((s)->ptr[1]=='\n'||(s)->ptr[1]=='\r'||(s)->ptr[1]=='\0'))
110 #endif /* USE_NNTP */
112 #define INITIAL_FORM_SIZE 10
113 static FormList **forms;
114 static int *form_stack;
115 static int form_max = -1;
116 static int forms_size = 0;
117 #define cur_form_id ((form_sp >= 0)? form_stack[form_sp] : -1)
118 static int form_sp = 0;
120 static clen_t current_content_length;
127 #define MAX_UL_LEVEL 9
128 #define UL_SYMBOL(x) (N_GRAPH_SYMBOL + (x))
129 #define UL_SYMBOL_DISC UL_SYMBOL(9)
130 #define UL_SYMBOL_CIRCLE UL_SYMBOL(10)
131 #define UL_SYMBOL_SQUARE UL_SYMBOL(11)
132 #define IMG_SYMBOL UL_SYMBOL(12)
136 /* This array should be somewhere else */
137 /* FIXME: gettextize? */
138 char *violations[COO_EMAX] = {
141 "wrong number of dots",
142 "RFC 2109 4.3.2 rule 1",
143 "RFC 2109 4.3.2 rule 2.1",
144 "RFC 2109 4.3.2 rule 2.2",
145 "RFC 2109 4.3.2 rule 3",
146 "RFC 2109 4.3.2 rule 4",
147 "RFC XXXX 4.3.2 rule 5"
152 static struct compression_decoder {
161 } compression_decoders[] = {
162 { CMP_COMPRESS, ".gz", "application/x-gzip",
163 0, GUNZIP_CMDNAME, GUNZIP_NAME, "gzip",
164 {"gzip", "x-gzip", NULL} },
165 { CMP_COMPRESS, ".Z", "application/x-compress",
166 0, GUNZIP_CMDNAME, GUNZIP_NAME, "compress",
167 {"compress", "x-compress", NULL} },
168 { CMP_BZIP2, ".bz2", "application/x-bzip",
169 0, BUNZIP2_CMDNAME, BUNZIP2_NAME, "bzip, bzip2",
170 {"x-bzip", "bzip", "bzip2", NULL} },
171 { CMP_DEFLATE, ".deflate", "application/x-deflate",
172 1, INFLATE_CMDNAME, INFLATE_NAME, "deflate",
173 {"deflate", "x-deflate", NULL} },
174 { CMP_NOCOMPRESS, NULL, NULL, 0, NULL, NULL, NULL, {NULL}},
178 #define SAVE_BUF_SIZE 1536
180 static MySignalHandler
183 LONGJMP(AbortLoading, 1);
188 UFhalfclose(URLFile *f)
207 currentLn(Buffer *buf)
209 if (buf->currentLine)
210 /* return buf->currentLine->real_linenumber + 1; */
211 return buf->currentLine->linenumber + 1;
217 loadSomething(URLFile *f,
219 Buffer *(*loadproc) (URLFile *, Buffer *), Buffer *defaultbuf)
223 if ((buf = loadproc(f, defaultbuf)) == NULL)
226 buf->filename = path;
227 if (buf->buffername == NULL || buf->buffername[0] == '\0') {
228 buf->buffername = checkHeader(buf, "Subject:");
229 if (buf->buffername == NULL)
230 buf->buffername = conv_from_system(lastFileName(path));
232 if (buf->currentURL.scheme == SCM_UNKNOWN)
233 buf->currentURL.scheme = f->scheme;
234 buf->real_scheme = f->scheme;
235 if (f->scheme == SCM_LOCAL && buf->sourcefile == NULL)
236 buf->sourcefile = path;
241 dir_exist(char *path)
245 if (path == NULL || *path == '\0')
247 if (stat(path, &stbuf) == -1)
249 return IS_DIRECTORY(stbuf.st_mode);
253 is_dump_text_type(char *type)
255 struct mailcap *mcap;
256 return (type && (mcap = searchExtViewer(type)) &&
257 (mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT)));
261 is_text_type(char *type)
263 return (type == NULL || type[0] == '\0' ||
264 strncasecmp(type, "text/", 5) == 0 ||
265 strncasecmp(type, "message/", sizeof("message/") - 1) == 0);
269 is_plain_text_type(char *type)
271 return ((type && strcasecmp(type, "text/plain") == 0) ||
272 (is_text_type(type) && !is_dump_text_type(type)));
276 check_compression(char *path, URLFile *uf)
279 struct compression_decoder *d;
285 uf->compression = CMP_NOCOMPRESS;
286 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
290 elen = strlen(d->ext);
291 if (len > elen && strcasecmp(&path[len - elen], d->ext) == 0) {
292 uf->compression = d->type;
293 uf->guess_type = d->mime_type;
300 compress_application_type(int compression)
302 struct compression_decoder *d;
304 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
305 if (d->type == compression)
312 uncompressed_file_type(char *path, char **ext)
317 struct compression_decoder *d;
324 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
327 slen = strlen(d->ext);
328 if (len > slen && strcasecmp(&path[len - slen], d->ext) == 0)
331 if (d->type == CMP_NOCOMPRESS)
334 fn = Strnew_charp(path);
337 *ext = filename_extension(fn->ptr, 0);
338 t0 = guessContentType(fn->ptr);
345 setModtime(char *path, time_t modtime)
350 if (stat(path, &st) == 0)
351 t.actime = st.st_atime;
353 t.actime = time(NULL);
355 return utime(path, &t);
359 examineFile(char *path, URLFile *uf)
363 uf->guess_type = NULL;
364 if (path == NULL || *path == '\0' ||
365 stat(path, &stbuf) == -1 || NOT_REGULAR(stbuf.st_mode)) {
369 uf->stream = openIS(path);
371 if (use_lessopen && getenv("LESSOPEN") != NULL) {
373 uf->guess_type = guessContentType(path);
374 if (uf->guess_type == NULL)
375 uf->guess_type = "text/plain";
376 if (strcasecmp(uf->guess_type, "text/html") == 0)
378 if ((fp = lessopen_stream(path))) {
380 uf->stream = newFileStream(fp, (void (*)())pclose);
381 uf->guess_type = "text/plain";
385 check_compression(path, uf);
386 if (uf->compression != CMP_NOCOMPRESS) {
388 char *t0 = uncompressed_file_type(path, &ext);
391 uncompress_stream(uf, NULL);
397 #define S_IXANY (S_IXUSR|S_IXGRP|S_IXOTH)
400 check_command(char *cmd, int auxbin_p)
402 static char *path = NULL;
409 path = getenv("PATH");
411 dirs = Strnew_charp(w3m_auxbin_dir());
413 dirs = Strnew_charp(path);
414 for (p = dirs->ptr; p != NULL; p = np) {
415 np = strchr(p, PATH_SEPARATOR);
419 Strcat_charp(pathname, p);
420 Strcat_char(pathname, '/');
421 Strcat_charp(pathname, cmd);
422 if (stat(pathname->ptr, &st) == 0 && S_ISREG(st.st_mode)
423 && (st.st_mode & S_IXANY) != 0)
432 static Str encodings = NULL;
433 struct compression_decoder *d;
437 if (encodings != NULL)
438 return encodings->ptr;
440 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
441 if (check_command(d->cmd, d->auxbin_p)) {
442 pushText(l, d->encoding);
445 encodings = Strnew();
446 while ((p = popText(l)) != NULL) {
447 if (encodings->length)
448 Strcat_charp(encodings, ", ");
449 Strcat_charp(encodings, p);
451 return encodings->ptr;
459 convertLine(URLFile *uf, Str line, int mode, wc_ces * charset,
463 convertLine0(URLFile *uf, Str line, int mode)
467 line = wc_Str_conv_with_detect(line, charset, doc_charset, InnerCharset);
469 if (mode != RAW_MODE)
470 cleanup_line(line, mode);
472 if (uf && uf->scheme == SCM_NEWS)
474 #endif /* USE_NNTP */
479 * loadFile: load file to buffer
486 init_stream(&uf, SCM_LOCAL, NULL);
487 examineFile(path, &uf);
488 if (uf.stream == NULL)
490 buf = newBuffer(INIT_BUFFER_WIDTH);
491 current_content_length = 0;
495 buf = loadSomething(&uf, path, loadBuffer, buf);
501 matchattr(char *p, char *attr, int len, Str *value)
506 if (strncasecmp(p, attr, len) == 0) {
515 while (!IS_ENDL(*p) && (quoted || *p != ';')) {
519 quoted = (quoted) ? 0 : 1;
521 Strcat_char(*value, *p);
525 Strshrink(*value, p - q - 1);
541 xface2xpm(char *xface)
554 cache = getImage(&image, NULL, IMG_FLAG_AUTO);
555 if (cache->loaded & IMG_FLAG_LOADED && !stat(cache->file, &st))
557 cache->loaded = IMG_FLAG_ERROR;
559 f = popen(Sprintf("%s > %s", shell_quote(auxbinFile(XFACE2XPM)),
560 shell_quote(cache->file))->ptr, "w");
565 if (stat(cache->file, &st) || !st.st_size)
567 cache->loaded = IMG_FLAG_LOADED | IMG_FLAG_DONT_REMOVE;
575 readHeader(URLFile *uf, Buffer *newBuf, int thru, ParsedURL *pu)
584 TextList *headerlist;
586 wc_ces charset = WC_CES_US_ASCII, mime_charset;
590 Lineprop *propBuffer;
592 headerlist = newBuf->document_header = newTextList();
593 if (uf->scheme == SCM_HTTP
595 || uf->scheme == SCM_HTTPS
598 http_response_code = -1;
600 http_response_code = 0;
602 if (thru && !newBuf->header_source
607 tmpf = tmpfname(TMPF_DFL, NULL)->ptr;
608 src = fopen(tmpf, "w");
610 newBuf->header_source = tmpf;
612 while ((tmp = StrmyUFgets(uf))->length) {
614 if (uf->scheme == SCM_NEWS && tmp->ptr[0] == '.')
615 Strshrinkfirst(tmp, 1);
619 ff = fopen(w3m_reqlog, "a");
625 cleanup_line(tmp, HEADER_MODE);
626 if (tmp->ptr[0] == '\n' || tmp->ptr[0] == '\r' || tmp->ptr[0] == '\0') {
628 /* there is no header */
632 else if (!(w3m_dump & DUMP_HEAD)) {
634 Strcat(lineBuf2, tmp);
641 if (c == ' ' || c == '\t')
642 /* header line is continued */
644 lineBuf2 = decodeMIME(lineBuf2, &mime_charset);
645 lineBuf2 = convertLine(NULL, lineBuf2, RAW_MODE,
646 mime_charset ? &mime_charset : &charset,
647 mime_charset ? mime_charset
649 /* separated with line and stored */
650 tmp = Strnew_size(lineBuf2->length);
651 for (p = lineBuf2->ptr; *p; p = q) {
652 for (q = p; *q && *q != '\r' && *q != '\n'; q++) ;
653 lineBuf2 = checkType(Strnew_charp_n(p, q - p), &propBuffer,
655 Strcat(tmp, lineBuf2);
657 addnewline(newBuf, lineBuf2->ptr, propBuffer, NULL,
658 lineBuf2->length, FOLD_BUFFER_WIDTH, -1);
659 for (; *q && (*q == '\r' || *q == '\n'); q++) ;
662 if (thru && activeImage && displayImage) {
664 if (!strncasecmp(tmp->ptr, "X-Image-URL:", 12)) {
665 tmpf = &tmp->ptr[12];
667 src = Strnew_m_charp("<img src=\"", html_quote(tmpf),
668 "\" alt=\"X-Image-URL\">", NULL);
671 else if (!strncasecmp(tmp->ptr, "X-Face:", 7)) {
672 tmpf = xface2xpm(&tmp->ptr[7]);
674 src = Strnew_m_charp("<img src=\"file:",
677 " width=48 height=48>", NULL);
684 wc_ces old_charset = newBuf->document_charset;
686 init_stream(&f, SCM_LOCAL, newStrStream(src));
687 loadHTMLstream(&f, newBuf, NULL, TRUE);
688 for (l = newBuf->lastLine; l && l->real_linenumber;
690 l->real_linenumber = 0;
692 newBuf->document_charset = old_charset;
702 if ((uf->scheme == SCM_HTTP
704 || uf->scheme == SCM_HTTPS
706 ) && http_response_code == -1) {
708 while (*p && !IS_SPACE(*p))
710 while (*p && IS_SPACE(*p))
712 http_response_code = atoi(p);
714 message(lineBuf2->ptr, 0, 0);
718 if (!strncasecmp(lineBuf2->ptr, "content-transfer-encoding:", 26)) {
719 p = lineBuf2->ptr + 26;
722 if (!strncasecmp(p, "base64", 6))
723 uf->encoding = ENC_BASE64;
724 else if (!strncasecmp(p, "quoted-printable", 16))
725 uf->encoding = ENC_QUOTE;
726 else if (!strncasecmp(p, "uuencode", 8) ||
727 !strncasecmp(p, "x-uuencode", 10))
728 uf->encoding = ENC_UUENCODE;
730 uf->encoding = ENC_7BIT;
732 else if (!strncasecmp(lineBuf2->ptr, "content-encoding:", 17)) {
733 struct compression_decoder *d;
734 p = lineBuf2->ptr + 17;
737 uf->compression = CMP_NOCOMPRESS;
738 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
740 for (e = d->encodings; *e != NULL; e++) {
741 if (strncasecmp(p, *e, strlen(*e)) == 0) {
742 uf->compression = d->type;
746 if (uf->compression != CMP_NOCOMPRESS)
749 uf->content_encoding = uf->compression;
752 else if (use_cookie && accept_cookie &&
753 pu && check_cookie_accept_domain(pu->host) &&
754 (!strncasecmp(lineBuf2->ptr, "Set-Cookie:", 11) ||
755 !strncasecmp(lineBuf2->ptr, "Set-Cookie2:", 12))) {
756 Str name = Strnew(), value = Strnew(), domain = NULL, path = NULL,
757 comment = NULL, commentURL = NULL, port = NULL, tmp2;
758 int version, quoted, flag = 0;
759 time_t expires = (time_t) - 1;
762 if (lineBuf2->ptr[10] == '2') {
763 p = lineBuf2->ptr + 12;
767 p = lineBuf2->ptr + 11;
771 fprintf(stderr, "Set-Cookie: [%s]\n", p);
774 while (*p != '=' && !IS_ENDT(*p))
775 Strcat_char(name, *(p++));
776 Strremovetrailingspaces(name);
781 while (!IS_ENDL(*p) && (quoted || *p != ';')) {
785 quoted = (quoted) ? 0 : 1;
786 Strcat_char(value, *(p++));
789 Strshrink(value, p - q - 1);
794 if (matchattr(p, "expires", 7, &tmp2)) {
796 expires = mymktime(tmp2->ptr);
798 else if (matchattr(p, "max-age", 7, &tmp2)) {
799 /* XXX Is there any problem with max-age=0? (RFC 2109 ss. 4.2.1, 4.2.2 */
800 expires = time(NULL) + atol(tmp2->ptr);
802 else if (matchattr(p, "domain", 6, &tmp2)) {
805 else if (matchattr(p, "path", 4, &tmp2)) {
808 else if (matchattr(p, "secure", 6, NULL)) {
811 else if (matchattr(p, "comment", 7, &tmp2)) {
814 else if (matchattr(p, "version", 7, &tmp2)) {
815 version = atoi(tmp2->ptr);
817 else if (matchattr(p, "port", 4, &tmp2)) {
818 /* version 1, Set-Cookie2 */
821 else if (matchattr(p, "commentURL", 10, &tmp2)) {
822 /* version 1, Set-Cookie2 */
825 else if (matchattr(p, "discard", 7, NULL)) {
826 /* version 1, Set-Cookie2 */
830 while (!IS_ENDL(*p) && (quoted || *p != ';')) {
832 quoted = (quoted) ? 0 : 1;
836 if (pu && name->length > 0) {
839 if (flag & COO_SECURE)
840 disp_message_nsec("Received a secured cookie", FALSE, 1,
843 disp_message_nsec(Sprintf("Received cookie: %s=%s",
844 name->ptr, value->ptr)->ptr,
845 FALSE, 1, TRUE, FALSE);
848 add_cookie(pu, name, value, expires, domain, path, flag,
849 comment, version, port, commentURL);
851 char *ans = (accept_bad_cookie == ACCEPT_BAD_COOKIE_ACCEPT)
853 if (fmInitialized && (err & COO_OVERRIDE_OK) &&
854 accept_bad_cookie == ACCEPT_BAD_COOKIE_ASK) {
855 Str msg = Sprintf("Accept bad cookie from %s for %s?",
857 ((domain && domain->ptr)
858 ? domain->ptr : "<localdomain>"));
859 if (msg->length > COLS - 10)
860 Strshrink(msg, msg->length - (COLS - 10));
861 Strcat_charp(msg, " (y/n)");
862 ans = inputAnswer(msg->ptr);
864 if (ans == NULL || TOLOWER(*ans) != 'y' ||
866 add_cookie(pu, name, value, expires, domain, path,
867 flag | COO_OVERRIDE, comment, version,
868 port, commentURL))) {
869 err = (err & ~COO_OVERRIDE_OK) - 1;
870 if (err >= 0 && err < COO_EMAX)
871 emsg = Sprintf("This cookie was rejected "
872 "to prevent security violation. [%s]",
873 violations[err])->ptr;
876 "This cookie was rejected to prevent security violation.";
877 record_err_message(emsg);
879 disp_message_nsec(emsg, FALSE, 1, TRUE, FALSE);
883 disp_message_nsec(Sprintf
884 ("Accepting invalid cookie: %s=%s",
885 name->ptr, value->ptr)->ptr, FALSE,
890 #endif /* USE_COOKIE */
891 else if (!strncasecmp(lineBuf2->ptr, "w3m-control:", 12) &&
892 uf->scheme == SCM_LOCAL_CGI) {
893 Str funcname = Strnew();
896 p = lineBuf2->ptr + 12;
898 while (*p && !IS_SPACE(*p))
899 Strcat_char(funcname, *(p++));
901 f = getFuncList(funcname->ptr);
903 tmp = Strnew_charp(p);
905 pushEvent(f, tmp->ptr);
909 pushText(headerlist, lineBuf2->ptr);
914 addnewline(newBuf, "", propBuffer, NULL, 0, -1, -1);
920 checkHeader(Buffer *buf, char *field)
926 if (buf == NULL || field == NULL || buf->document_header == NULL)
929 for (i = buf->document_header->first; i != NULL; i = i->next) {
930 if (!strncasecmp(i->ptr, field, len)) {
932 return remove_space(p);
939 checkContentType(Buffer *buf)
943 p = checkHeader(buf, "Content-Type:");
947 while (*p && *p != ';' && !IS_SPACE(*p))
948 Strcat_char(r, *p++);
950 if ((p = strcasestr(p, "charset")) != NULL) {
958 content_charset = wc_guess_charset(p, 0);
973 struct auth_param *param;
974 Str (*cred) (struct http_auth * ha, Str uname, Str pw, ParsedURL *pu,
975 HRequest *hr, FormList *request);
985 skip_auth_token(char **pp)
988 int first = AUTHCHR_NUL, typ;
990 for (p = *pp ;; ++p) {
995 if ((unsigned char)*p > 037) {
1024 else if (first != typ)
1033 extract_auth_val(char **q)
1035 unsigned char *qq = *(unsigned char **)q;
1042 Strcat_char(val, *qq++);
1044 while (*qq != '\0') {
1045 if (quoted && *qq == '"') {
1046 Strcat_char(val, *qq++);
1071 if (*qq <= 037 || *qq == 0177) {
1077 else if (quoted && *qq == '\\')
1078 Strcat_char(val, *qq++);
1079 Strcat_char(val, *qq++);
1096 for (p++; *p != '\0'; p++) {
1099 Strcat_char(tmp, *p);
1101 if (Strlastchar(tmp) == '"')
1110 extract_auth_param(char *q, struct auth_param *auth)
1112 struct auth_param *ap;
1115 for (ap = auth; ap->name != NULL; ap++) {
1119 while (*q != '\0') {
1121 for (ap = auth; ap->name != NULL; ap++) {
1124 len = strlen(ap->name);
1125 if (strncasecmp(q, ap->name, len) == 0 &&
1126 (IS_SPACE(q[len]) || q[len] == '=')) {
1132 ap->val = extract_auth_val(&q);
1136 if (ap->name == NULL) {
1137 /* skip unknown param */
1140 if ((token_type = skip_auth_token(&q)) == AUTHCHR_TOKEN &&
1141 (IS_SPACE(*q) || *q == '=')) {
1146 extract_auth_val(&q);
1163 get_auth_param(struct auth_param *auth, char *name)
1165 struct auth_param *ap;
1166 for (ap = auth; ap->name != NULL; ap++) {
1167 if (strcasecmp(name, ap->name) == 0)
1174 AuthBasicCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu,
1175 HRequest *hr, FormList *request)
1177 Str s = Strdup(uname);
1178 Strcat_char(s, ':');
1180 return Strnew_m_charp("Basic ", encodeB(s->ptr)->ptr, NULL);
1183 #ifdef USE_DIGEST_AUTH
1184 #include <openssl/md5.h>
1186 /* RFC2617: 3.2.2 The Authorization Request Header
1188 * credentials = "Digest" digest-response
1189 * digest-response = 1#( username | realm | nonce | digest-uri
1190 * | response | [ algorithm ] | [cnonce] |
1191 * [opaque] | [message-qop] |
1192 * [nonce-count] | [auth-param] )
1194 * username = "username" "=" username-value
1195 * username-value = quoted-string
1196 * digest-uri = "uri" "=" digest-uri-value
1197 * digest-uri-value = request-uri ; As specified by HTTP/1.1
1198 * message-qop = "qop" "=" qop-value
1199 * cnonce = "cnonce" "=" cnonce-value
1200 * cnonce-value = nonce-value
1201 * nonce-count = "nc" "=" nc-value
1203 * response = "response" "=" request-digest
1204 * request-digest = <"> 32LHEX <">
1205 * LHEX = "0" | "1" | "2" | "3" |
1206 * "4" | "5" | "6" | "7" |
1207 * "8" | "9" | "a" | "b" |
1208 * "c" | "d" | "e" | "f"
1214 char *h = "0123456789abcdef";
1215 Str tmp = Strnew_size(MD5_DIGEST_LENGTH * 2 + 1);
1217 for (i = 0; i < MD5_DIGEST_LENGTH; i++, p++) {
1218 Strcat_char(tmp, h[(*p >> 4) & 0x0f]);
1219 Strcat_char(tmp, h[*p & 0x0f]);
1231 AuthDigestCred(struct http_auth *ha, Str uname, Str pw, ParsedURL *pu,
1232 HRequest *hr, FormList *request)
1234 Str tmp, a1buf, a2buf, rd, s;
1235 char md5[MD5_DIGEST_LENGTH + 1];
1236 Str uri = HTTPrequestURI(pu, hr);
1237 char nc[] = "00000001";
1239 Str algorithm = qstr_unquote(get_auth_param(ha->param, "algorithm"));
1240 Str nonce = qstr_unquote(get_auth_param(ha->param, "nonce"));
1241 Str cnonce /* = qstr_unquote(get_auth_param(ha->param, "cnonce")) */;
1242 /* cnonce is what client should generate. */
1243 Str qop = qstr_unquote(get_auth_param(ha->param, "qop"));
1247 char s[sizeof(int) * 4];
1249 int qop_i = QOP_NONE;
1251 cnonce_seed.r[0] = rand();
1252 cnonce_seed.r[1] = rand();
1253 cnonce_seed.r[2] = rand();
1254 MD5(cnonce_seed.s, sizeof(cnonce_seed.s), md5);
1255 cnonce = digest_hex(md5);
1266 if ((i = strcspn(p, " \t,")) > 0) {
1267 if (i == sizeof("auth-int") - sizeof("") && !strncasecmp(p, "auth-int", i)) {
1268 if (qop_i < QOP_AUTH_INT)
1269 qop_i = QOP_AUTH_INT;
1271 else if (i == sizeof("auth") - sizeof("") && !strncasecmp(p, "auth", i)) {
1272 if (qop_i < QOP_AUTH)
1286 /* A1 = unq(username-value) ":" unq(realm-value) ":" passwd */
1287 tmp = Strnew_m_charp(uname->ptr, ":",
1288 qstr_unquote(get_auth_param(ha->param, "realm"))->ptr,
1289 ":", pw->ptr, NULL);
1290 MD5(tmp->ptr, strlen(tmp->ptr), md5);
1291 a1buf = digest_hex(md5);
1294 if (strcasecmp(algorithm->ptr, "MD5-sess") == 0) {
1295 /* A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd)
1296 * ":" unq(nonce-value) ":" unq(cnonce-value)
1300 tmp = Strnew_m_charp(a1buf->ptr, ":",
1301 qstr_unquote(nonce)->ptr,
1302 ":", qstr_unquote(cnonce)->ptr, NULL);
1303 MD5(tmp->ptr, strlen(tmp->ptr), md5);
1304 a1buf = digest_hex(md5);
1306 else if (strcasecmp(algorithm->ptr, "MD5") == 0)
1310 /* unknown algorithm */
1314 /* A2 = Method ":" digest-uri-value */
1315 tmp = Strnew_m_charp(HTTPrequestMethod(hr)->ptr, ":", uri->ptr, NULL);
1316 if (qop_i == QOP_AUTH_INT) {
1317 /* A2 = Method ":" digest-uri-value ":" H(entity-body) */
1318 if (request && request->body) {
1319 if (request->method == FORM_METHOD_POST && request->enctype == FORM_ENCTYPE_MULTIPART) {
1320 FILE *fp = fopen(request->body, "r");
1323 ebody = Strfgetall(fp);
1324 MD5(ebody->ptr, strlen(ebody->ptr), md5);
1331 MD5(request->body, request->length, md5);
1337 Strcat_char(tmp, ':');
1338 Strcat(tmp, digest_hex(md5));
1340 MD5(tmp->ptr, strlen(tmp->ptr), md5);
1341 a2buf = digest_hex(md5);
1343 if (qop_i >= QOP_AUTH) {
1344 /* request-digest = <"> < KD ( H(A1), unq(nonce-value)
1346 * ":" unq(cnonce-value)
1347 * ":" unq(qop-value)
1353 tmp = Strnew_m_charp(a1buf->ptr, ":", qstr_unquote(nonce)->ptr,
1355 ":", qstr_unquote(cnonce)->ptr,
1356 ":", qop_i == QOP_AUTH ? "auth" : "auth-int",
1357 ":", a2buf->ptr, NULL);
1358 MD5(tmp->ptr, strlen(tmp->ptr), md5);
1359 rd = digest_hex(md5);
1362 /* compatibility with RFC 2069
1363 * request_digest = KD(H(A1), unq(nonce), H(A2))
1365 tmp = Strnew_m_charp(a1buf->ptr, ":",
1366 qstr_unquote(get_auth_param(ha->param, "nonce"))->
1367 ptr, ":", a2buf->ptr, NULL);
1368 MD5(tmp->ptr, strlen(tmp->ptr), md5);
1369 rd = digest_hex(md5);
1373 * digest-response = 1#( username | realm | nonce | digest-uri
1374 * | response | [ algorithm ] | [cnonce] |
1375 * [opaque] | [message-qop] |
1376 * [nonce-count] | [auth-param] )
1379 tmp = Strnew_m_charp("Digest username=\"", uname->ptr, "\"", NULL);
1380 Strcat_m_charp(tmp, ", realm=",
1381 get_auth_param(ha->param, "realm")->ptr, NULL);
1382 Strcat_m_charp(tmp, ", nonce=",
1383 get_auth_param(ha->param, "nonce")->ptr, NULL);
1384 Strcat_m_charp(tmp, ", uri=\"", uri->ptr, "\"", NULL);
1385 Strcat_m_charp(tmp, ", response=\"", rd->ptr, "\"", NULL);
1388 Strcat_m_charp(tmp, ", algorithm=",
1389 get_auth_param(ha->param, "algorithm")->ptr, NULL);
1392 Strcat_m_charp(tmp, ", cnonce=\"", cnonce->ptr, "\"", NULL);
1394 if ((s = get_auth_param(ha->param, "opaque")) != NULL)
1395 Strcat_m_charp(tmp, ", opaque=", s->ptr, NULL);
1397 if (qop_i >= QOP_AUTH) {
1398 Strcat_m_charp(tmp, ", qop=",
1399 qop_i == QOP_AUTH ? "auth" : "auth-int",
1401 /* XXX how to count? */
1402 /* Since nonce is unique up to each *-Authenticate and w3m does not re-use *-Authenticate: headers,
1403 nonce-count should be always "00000001". */
1404 Strcat_m_charp(tmp, ", nc=", nc, NULL);
1412 struct auth_param none_auth_param[] = {
1416 struct auth_param basic_auth_param[] = {
1421 #ifdef USE_DIGEST_AUTH
1422 /* RFC2617: 3.2.1 The WWW-Authenticate Response Header
1423 * challenge = "Digest" digest-challenge
1425 * digest-challenge = 1#( realm | [ domain ] | nonce |
1426 * [ opaque ] |[ stale ] | [ algorithm ] |
1427 * [ qop-options ] | [auth-param] )
1429 * domain = "domain" "=" <"> URI ( 1*SP URI ) <">
1430 * URI = absoluteURI | abs_path
1431 * nonce = "nonce" "=" nonce-value
1432 * nonce-value = quoted-string
1433 * opaque = "opaque" "=" quoted-string
1434 * stale = "stale" "=" ( "true" | "false" )
1435 * algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" |
1437 * qop-options = "qop" "=" <"> 1#qop-value <">
1438 * qop-value = "auth" | "auth-int" | token
1440 struct auth_param digest_auth_param[] = {
1446 {"algorithm", NULL},
1451 /* for RFC2617: HTTP Authentication */
1452 struct http_auth www_auth[] = {
1453 { 1, "Basic ", basic_auth_param, AuthBasicCred },
1454 #ifdef USE_DIGEST_AUTH
1455 { 10, "Digest ", digest_auth_param, AuthDigestCred },
1457 { 0, NULL, NULL, NULL,}
1461 static struct http_auth *
1462 findAuthentication(struct http_auth *hauth, Buffer *buf, char *auth_field)
1464 struct http_auth *ha;
1465 int len = strlen(auth_field), slen;
1469 bzero(hauth, sizeof(struct http_auth));
1470 for (i = buf->document_header->first; i != NULL; i = i->next) {
1471 if (strncasecmp(i->ptr, auth_field, len) == 0) {
1472 for (p = i->ptr + len; p != NULL && *p != '\0';) {
1475 for (ha = &www_auth[0]; ha->scheme != NULL; ha++) {
1476 slen = strlen(ha->scheme);
1477 if (strncasecmp(p, ha->scheme, slen) == 0) {
1480 if (hauth->pri < ha->pri) {
1482 p = extract_auth_param(p, hauth->param);
1487 p = extract_auth_param(p, none_auth_param);
1492 /* all unknown auth failed */
1494 if ((token_type = skip_auth_token(&p)) == AUTHCHR_TOKEN && IS_SPACE(*p)) {
1496 p = extract_auth_param(p, none_auth_param);
1504 return hauth->scheme ? hauth : NULL;
1508 getAuthCookie(struct http_auth *hauth, char *auth_header,
1509 TextList *extra_header, ParsedURL *pu, HRequest *hr,
1511 volatile Str *uname, volatile Str *pwd)
1517 int auth_header_len = strlen(auth_header);
1522 realm = qstr_unquote(get_auth_param(hauth->param, "realm"))->ptr;
1528 for (i = extra_header->first; i != NULL; i = i->next) {
1529 if (!strncasecmp(i->ptr, auth_header, auth_header_len)) {
1534 proxy = !strncasecmp("Proxy-Authorization:", auth_header,
1537 /* This means that *-Authenticate: header is received after
1538 * Authorization: header is sent to the server.
1540 if (fmInitialized) {
1541 message("Wrong username or password", 0, 0);
1545 fprintf(stderr, "Wrong username or password\n");
1547 /* delete Authenticate: header from extra_header */
1548 delText(extra_header, i);
1549 invalidate_auth_user_passwd(pu, realm, *uname, *pwd, proxy);
1554 if (!a_found && find_auth_user_passwd(pu, realm, (Str*)uname, (Str*)pwd,
1556 /* found username & password in passwd file */ ;
1561 /* input username and password */
1563 if (fmInitialized) {
1566 /* FIXME: gettextize? */
1567 if ((pp = inputStr(Sprintf("Username for %s: ", realm)->ptr,
1570 *uname = Str_conv_to_system(Strnew_charp(pp));
1571 if ((pp = inputLine(Sprintf("Password for %s: ", realm)->ptr, NULL,
1572 IN_PASSWORD)) == NULL) {
1576 *pwd = Str_conv_to_system(Strnew_charp(pp));
1581 * If post file is specified as '-', stdin is closed at this
1583 * In this case, w3m cannot read username from stdin.
1584 * So exit with error message.
1585 * (This is same behavior as lwp-request.)
1587 if (feof(stdin) || ferror(stdin)) {
1588 /* FIXME: gettextize? */
1589 fprintf(stderr, "w3m: Authorization required for %s\n",
1594 /* FIXME: gettextize? */
1595 printf(proxy ? "Proxy Username for %s: " : "Username for %s: ",
1598 *uname = Strfgets(stdin);
1600 #ifdef HAVE_GETPASSPHRASE
1601 *pwd = Strnew_charp((char *)
1602 getpassphrase(proxy ? "Proxy Password: " :
1605 #ifndef __MINGW32_VERSION
1606 *pwd = Strnew_charp((char *)
1607 getpass(proxy ? "Proxy Password: " :
1611 *pwd = Strnew_charp((char *)
1612 inputLine(proxy ? "Proxy Password: " :
1613 "Password: ", NULL, IN_PASSWORD));
1615 #endif /* __MINGW32_VERSION */
1619 ss = hauth->cred(hauth, *uname, *pwd, pu, hr, request);
1621 tmp = Strnew_charp(auth_header);
1622 Strcat_m_charp(tmp, " ", ss->ptr, "\r\n", NULL);
1623 pushText(extra_header, tmp->ptr);
1633 same_url_p(ParsedURL *pu1, ParsedURL *pu2)
1635 return (pu1->scheme == pu2->scheme && pu1->port == pu2->port &&
1636 (pu1->host ? pu2->host ? !strcasecmp(pu1->host, pu2->host) : 0 : 1)
1637 && (pu1->file ? pu2->
1638 file ? !strcmp(pu1->file, pu2->file) : 0 : 1));
1642 checkRedirection(ParsedURL *pu)
1644 static ParsedURL *puv = NULL;
1645 static int nredir = 0;
1646 static int nredir_size = 0;
1655 if (nredir >= FollowRedirection) {
1656 /* FIXME: gettextize? */
1657 tmp = Sprintf("Number of redirections exceeded %d at %s",
1658 FollowRedirection, parsedURL2Str(pu)->ptr);
1659 disp_err_message(tmp->ptr, FALSE);
1662 else if (nredir_size > 0 &&
1663 (same_url_p(pu, &puv[(nredir - 1) % nredir_size]) ||
1665 && same_url_p(pu, &puv[(nredir / 2) % nredir_size])))) {
1666 /* FIXME: gettextize? */
1667 tmp = Sprintf("Redirection loop detected (%s)",
1668 parsedURL2Str(pu)->ptr);
1669 disp_err_message(tmp->ptr, FALSE);
1673 nredir_size = FollowRedirection / 2 + 1;
1674 puv = New_N(ParsedURL, nredir_size);
1675 memset(puv, 0, sizeof(ParsedURL) * nredir_size);
1677 copyParsedURL(&puv[nredir % nredir_size], pu);
1683 * loadGeneralFile: load file to buffer
1686 loadGeneralFile(char *path, ParsedURL *volatile current, char *referer,
1687 int flag, FormList *volatile request)
1689 URLFile f, *volatile of = NULL;
1691 Buffer *b = NULL, *(*volatile proc)() = loadBuffer;
1692 char *volatile tpath;
1693 char *volatile t = "text/plain", *p, *volatile real_type = NULL;
1694 Buffer *volatile t_buf = NULL;
1695 int volatile searchHeader = SearchHeader;
1696 int volatile searchHeader_through = TRUE;
1697 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
1698 TextList *extra_header = newTextList();
1699 volatile Str uname = NULL;
1700 volatile Str pwd = NULL;
1701 volatile Str realm = NULL;
1702 int volatile add_auth_cookie_flag;
1703 unsigned char status = HTST_NORMAL;
1704 URLOption url_option;
1706 Str volatile page = NULL;
1708 wc_ces charset = WC_CES_US_ASCII;
1711 ParsedURL *volatile auth_pu;
1715 add_auth_cookie_flag = 0;
1717 checkRedirection(NULL);
1720 url_option.referer = referer;
1721 url_option.flag = flag;
1722 f = openURL(tpath, &pu, current, &url_option, request, extra_header, of,
1726 content_charset = 0;
1728 if (f.stream == NULL) {
1733 if (stat(pu.real_file, &st) < 0)
1735 if (S_ISDIR(st.st_mode)) {
1736 if (UseExternalDirBuffer) {
1737 Str cmd = Sprintf("%s?dir=%s#current",
1738 DirBufferCommand, pu.file);
1739 b = loadGeneralFile(cmd->ptr, NULL, NO_REFERER, 0,
1741 if (b != NULL && b != NO_BUFFER) {
1742 copyParsedURL(&b->currentURL, &pu);
1743 b->filename = b->currentURL.real_file;
1748 page = loadLocalDir(pu.real_file);
1749 t = "local:directory";
1751 charset = SystemCharset;
1758 page = loadFTPDir(&pu, &charset);
1759 t = "ftp:directory";
1762 case SCM_NEWS_GROUP:
1763 page = loadNewsgroup(&pu, &charset);
1768 #ifdef USE_EXTERNAL_URI_LOADER
1769 tmp = searchURIMethods(&pu);
1771 b = loadGeneralFile(tmp->ptr, current, referer, flag, request);
1772 if (b != NULL && b != NO_BUFFER)
1773 copyParsedURL(&b->currentURL, &pu);
1777 /* FIXME: gettextize? */
1778 disp_err_message(Sprintf("Unknown URI: %s",
1779 parsedURL2Str(&pu)->ptr)->ptr, FALSE);
1782 if (page && page->length > 0)
1787 if (status == HTST_MISSING) {
1793 /* openURL() succeeded */
1794 if (SETJMP(AbortLoading) != 0) {
1795 /* transfer interrupted */
1806 searchHeader = TRUE;
1807 searchHeader_through = FALSE;
1810 header_string = NULL;
1812 if (pu.scheme == SCM_HTTP ||
1814 pu.scheme == SCM_HTTPS ||
1815 #endif /* USE_SSL */
1818 (pu.scheme == SCM_GOPHER && non_null(GOPHER_proxy)) ||
1819 #endif /* USE_GOPHER */
1820 (pu.scheme == SCM_FTP && non_null(FTP_proxy))
1821 ) && !Do_not_use_proxy && !check_no_proxy(pu.host))) {
1823 if (fmInitialized) {
1825 /* FIXME: gettextize? */
1826 message(Sprintf("%s contacted. Waiting for reply...", pu.host)->
1831 t_buf = newBuffer(INIT_BUFFER_WIDTH);
1833 if (IStype(f.stream) == IST_SSL) {
1834 Str s = ssl_get_certificate(f.stream, pu.host);
1838 t_buf->ssl_certificate = s->ptr;
1841 readHeader(&f, t_buf, FALSE, &pu);
1842 if (((http_response_code >= 301 && http_response_code <= 303)
1843 || http_response_code == 307)
1844 && (p = checkHeader(t_buf, "Location:")) != NULL
1845 && checkRedirection(&pu)) {
1846 /* document moved */
1847 /* 301: Moved Permanently */
1849 /* 303: See Other */
1850 /* 307: Temporary Redirect (HTTP/1.1) */
1851 tpath = url_quote_conv(p, DocumentCharset);
1854 current = New(ParsedURL);
1855 copyParsedURL(current, &pu);
1856 t_buf = newBuffer(INIT_BUFFER_WIDTH);
1857 t_buf->bufferprop |= BP_REDIRECTED;
1858 status = HTST_NORMAL;
1861 t = checkContentType(t_buf);
1862 if (t == NULL && pu.file != NULL) {
1863 if (!((http_response_code >= 400 && http_response_code <= 407) ||
1864 (http_response_code >= 500 && http_response_code <= 505)))
1865 t = guessContentType(pu.file);
1869 if (add_auth_cookie_flag && realm && uname && pwd) {
1870 /* If authorization is required and passed */
1871 add_auth_user_passwd(&pu, qstr_unquote(realm)->ptr, uname, pwd,
1873 add_auth_cookie_flag = 0;
1875 if ((p = checkHeader(t_buf, "WWW-Authenticate:")) != NULL &&
1876 http_response_code == 401) {
1877 /* Authentication needed */
1878 struct http_auth hauth;
1879 if (findAuthentication(&hauth, t_buf, "WWW-Authenticate:") != NULL
1880 && (realm = get_auth_param(hauth.param, "realm")) != NULL) {
1882 getAuthCookie(&hauth, "Authorization:", extra_header,
1883 auth_pu, &hr, request, &uname, &pwd);
1884 if (uname == NULL) {
1890 add_auth_cookie_flag = 1;
1891 status = HTST_NORMAL;
1895 if ((p = checkHeader(t_buf, "Proxy-Authenticate:")) != NULL &&
1896 http_response_code == 407) {
1897 /* Authentication needed */
1898 struct http_auth hauth;
1899 if (findAuthentication(&hauth, t_buf, "Proxy-Authenticate:")
1901 && (realm = get_auth_param(hauth.param, "realm")) != NULL) {
1902 auth_pu = schemeToProxy(pu.scheme);
1903 getAuthCookie(&hauth, "Proxy-Authorization:",
1904 extra_header, auth_pu, &hr, request,
1906 if (uname == NULL) {
1912 add_auth_cookie_flag = 1;
1913 status = HTST_NORMAL;
1917 /* XXX: RFC2617 3.2.3 Authentication-Info: ? */
1919 if (status == HTST_CONNECT) {
1924 f.modtime = mymktime(checkHeader(t_buf, "Last-Modified:"));
1927 else if (pu.scheme == SCM_NEWS || pu.scheme == SCM_NNTP) {
1929 t_buf = newBuffer(INIT_BUFFER_WIDTH);
1930 readHeader(&f, t_buf, TRUE, &pu);
1931 t = checkContentType(t_buf);
1935 #endif /* USE_NNTP */
1937 else if (pu.scheme == SCM_GOPHER) {
1944 page = loadGopherDir(&f, &pu, &charset);
1945 t = "gopher:directory";
1959 #endif /* USE_GOPHER */
1960 else if (pu.scheme == SCM_FTP) {
1961 check_compression(path, &f);
1962 if (f.compression != CMP_NOCOMPRESS) {
1963 char *t1 = uncompressed_file_type(pu.file, NULL);
1964 real_type = f.guess_type;
1966 if (t1 && strncasecmp(t1, "application/", 12) == 0) {
1967 f.compression = CMP_NOCOMPRESS;
1978 real_type = guessContentType(pu.file);
1979 if (real_type == NULL)
1980 real_type = "text/plain";
1984 if (!strncasecmp(t, "application/", 12)) {
1985 char *tmpf = tmpfname(TMPF_DFL, NULL)->ptr;
1986 current_content_length = 0;
1987 if (save2tmp(f, tmpf) < 0)
1992 doFileMove(tmpf, guess_save_name(t_buf, pu.file));
1998 else if (pu.scheme == SCM_DATA) {
2001 else if (searchHeader) {
2002 searchHeader = SearchHeader = FALSE;
2004 t_buf = newBuffer(INIT_BUFFER_WIDTH);
2005 readHeader(&f, t_buf, searchHeader_through, &pu);
2006 if (f.is_cgi && (p = checkHeader(t_buf, "Location:")) != NULL &&
2007 checkRedirection(&pu)) {
2008 /* document moved */
2009 tpath = url_quote_conv(remove_space(p), DocumentCharset);
2012 add_auth_cookie_flag = 0;
2013 current = New(ParsedURL);
2014 copyParsedURL(current, &pu);
2015 t_buf = newBuffer(INIT_BUFFER_WIDTH);
2016 t_buf->bufferprop |= BP_REDIRECTED;
2017 status = HTST_NORMAL;
2021 if ((p = checkHeader(t_buf, "WWW-Authenticate:")) != NULL) {
2022 /* Authentication needed */
2023 struct http_auth hauth;
2024 if (findAuthentication(&hauth, t_buf, "WWW-Authenticate:") != NULL
2025 && (realm = get_auth_param(hauth.param, "realm")) != NULL) {
2027 getAuthCookie(&hauth, "Authorization:", extra_header,
2028 auth_pu, &hr, request, &uname, &pwd);
2029 if (uname == NULL) {
2035 add_auth_cookie_flag = 1;
2036 status = HTST_NORMAL;
2040 #endif /* defined(AUTH_DEBUG) */
2041 t = checkContentType(t_buf);
2045 else if (DefaultType) {
2050 t = guessContentType(pu.file);
2065 tmp = tmpfname(TMPF_SRC, ".html");
2066 src = fopen(tmp->ptr, "w");
2069 s = wc_Str_conv_strict(page, InnerCharset, charset);
2077 file = guess_filename(pu.file);
2079 if (f.scheme == SCM_GOPHER)
2080 file = Sprintf("%s.html", file)->ptr;
2083 if (f.scheme == SCM_NEWS_GROUP)
2084 file = Sprintf("%s.html", file)->ptr;
2086 doFileMove(tmp->ptr, file);
2089 b = loadHTMLString(page);
2091 copyParsedURL(&b->currentURL, &pu);
2092 b->real_scheme = pu.scheme;
2095 b->sourcefile = tmp->ptr;
2097 b->document_charset = charset;
2103 if (real_type == NULL)
2107 cur_baseURL = New(ParsedURL);
2108 copyParsedURL(cur_baseURL, &pu);
2111 current_content_length = 0;
2112 if ((p = checkHeader(t_buf, "Content-Length:")) != NULL)
2113 current_content_length = strtoclen(p);
2118 if (DecodeCTE && IStype(f.stream) != IST_ENCODED)
2119 f.stream = newEncodedStream(f.stream, f.encoding);
2120 if (pu.scheme == SCM_LOCAL) {
2122 if (PreserveTimestamp && !stat(pu.real_file, &st))
2123 f.modtime = st.st_mtime;
2124 file = conv_from_system(guess_save_name(NULL, pu.real_file));
2127 file = guess_save_name(t_buf, pu.file);
2128 if (doFileSave(f, file) == 0)
2135 if ((f.content_encoding != CMP_NOCOMPRESS) && AutoUncompress
2136 && !(w3m_dump & DUMP_EXTRA)) {
2137 uncompress_stream(&f, &pu.real_file);
2139 else if (f.compression != CMP_NOCOMPRESS) {
2140 if (!(w3m_dump & DUMP_SOURCE) &&
2141 (w3m_dump & ~DUMP_FRAME || is_text_type(t)
2142 || searchExtViewer(t))) {
2144 t_buf = newBuffer(INIT_BUFFER_WIDTH);
2145 uncompress_stream(&f, &t_buf->sourcefile);
2146 uncompressed_file_type(pu.file, &f.ext);
2149 t = compress_application_type(f.compression);
2150 f.compression = CMP_NOCOMPRESS;
2156 if (IStype(f.stream) != IST_ENCODED)
2157 f.stream = newEncodedStream(f.stream, f.encoding);
2158 if (save2tmp(f, image_source) == 0) {
2159 b = newBuffer(INIT_BUFFER_WIDTH);
2160 b->sourcefile = image_source;
2169 if (!strcasecmp(t, "text/html"))
2170 proc = loadHTMLBuffer;
2171 else if (is_plain_text_type(t))
2174 else if (activeImage && displayImage && !useExtImageViewer &&
2175 !(w3m_dump & ~DUMP_FRAME) && !strncasecmp(t, "image/", 6))
2176 proc = loadImageBuffer;
2178 else if (w3m_backend) ;
2179 else if (!(w3m_dump & ~DUMP_FRAME) || is_dump_text_type(t)) {
2180 if (!do_download && doExternal(f,
2181 pu.real_file ? pu.real_file : pu.file,
2183 if (b && b != NO_BUFFER) {
2184 b->real_scheme = f.scheme;
2185 b->real_type = real_type;
2186 if (b->currentURL.host == NULL && b->currentURL.file == NULL)
2187 copyParsedURL(&b->currentURL, &pu);
2195 if (pu.scheme == SCM_LOCAL) {
2197 _doFileCopy(pu.real_file,
2198 conv_from_system(guess_save_name
2199 (NULL, pu.real_file)), TRUE);
2202 if (DecodeCTE && IStype(f.stream) != IST_ENCODED)
2203 f.stream = newEncodedStream(f.stream, f.encoding);
2204 if (doFileSave(f, guess_save_name(t_buf, pu.file)) == 0)
2212 else if (w3m_dump & DUMP_FRAME)
2215 if (flag & RG_FRAME) {
2217 t_buf = newBuffer(INIT_BUFFER_WIDTH);
2218 t_buf->bufferprop |= BP_FRAME;
2222 t_buf->ssl_certificate = f.ssl_certificate;
2224 frame_source = flag & RG_FRAME_SRC;
2225 b = loadSomething(&f, pu.real_file ? pu.real_file : pu.file, proc, t_buf);
2229 b->real_scheme = f.scheme;
2230 b->real_type = real_type;
2231 if (b->currentURL.host == NULL && b->currentURL.file == NULL)
2232 copyParsedURL(&b->currentURL, &pu);
2233 if (!strcasecmp(t, "text/html"))
2234 b->type = "text/html";
2235 else if (w3m_backend) {
2236 Str s = Strnew_charp(t);
2240 else if (proc == loadImageBuffer)
2241 b->type = "text/html";
2244 b->type = "text/plain";
2246 if (proc == loadHTMLBuffer) {
2248 a = searchURLLabel(b, pu.label);
2250 gotoLine(b, a->start.line);
2252 b->topLine = lineSkip(b, b->topLine,
2253 b->currentLine->linenumber
2254 - b->topLine->linenumber, FALSE);
2255 b->pos = a->start.pos;
2259 else { /* plain text */
2260 int l = atoi(pu.label);
2268 header_string = NULL;
2270 if (f.scheme == SCM_NNTP || f.scheme == SCM_NEWS)
2271 reAnchorNewsheader(b);
2273 preFormUpdateBuffer(b);
2278 #define TAG_IS(s,tag,len)\
2279 (strncasecmp(s,tag,len)==0&&(s[len] == '>' || IS_SPACE((int)s[len])))
2282 has_hidden_link(struct readbuffer *obuf, int cmd)
2284 Str line = obuf->line;
2285 struct link_stack *p;
2287 if (Strlastchar(line) != '>')
2290 for (p = link_stack; p; p = p->next)
2296 if (obuf->pos == p->pos)
2297 return line->ptr + p->offset;
2303 push_link(int cmd, int offset, int pos)
2305 struct link_stack *p;
2306 p = New(struct link_stack);
2310 p->next = link_stack;
2315 is_period_char(unsigned char *ch)
2335 is_beginning_char(unsigned char *ch)
2350 is_word_char(unsigned char *ch)
2352 Lineprop ctype = get_mctype(ch);
2355 if (ctype & (PC_CTRL | PC_KANJI | PC_UNKNOWN))
2357 if (ctype & (PC_WCHAR1 | PC_WCHAR2))
2360 if (ctype == PC_CTRL)
2384 if (*ch == NBSP_CODE)
2387 if (*ch == TIMES_CODE || *ch == DIVIDE_CODE || *ch == ANSP_CODE)
2389 if (*ch >= AGRAVE_CODE || *ch == NBSP_CODE)
2397 is_combining_char(unsigned char *ch)
2399 Lineprop ctype = get_mctype(ch);
2401 if (ctype & PC_WCHAR2)
2408 is_boundary(unsigned char *ch1, unsigned char *ch2)
2413 if (*ch1 == ' ' && *ch2 == ' ')
2416 if (*ch1 != ' ' && is_period_char(ch2))
2419 if (*ch2 != ' ' && is_beginning_char(ch1))
2423 if (is_combining_char(ch2))
2426 if (is_word_char(ch1) && is_word_char(ch2))
2434 set_breakpoint(struct readbuffer *obuf, int tag_length)
2436 obuf->bp.len = obuf->line->length;
2437 obuf->bp.pos = obuf->pos;
2438 obuf->bp.tlen = tag_length;
2439 obuf->bp.flag = obuf->flag;
2441 obuf->bp.flag &= ~RB_FILL;
2442 #endif /* FORMAT_NICE */
2443 obuf->bp.top_margin = obuf->top_margin;
2444 obuf->bp.bottom_margin = obuf->bottom_margin;
2446 if (!obuf->bp.init_flag)
2449 bcopy((void *)&obuf->anchor, (void *)&obuf->bp.anchor,
2450 sizeof(obuf->anchor));
2451 obuf->bp.img_alt = obuf->img_alt;
2452 obuf->bp.in_bold = obuf->in_bold;
2453 obuf->bp.in_italic = obuf->in_italic;
2454 obuf->bp.in_under = obuf->in_under;
2455 obuf->bp.in_strike = obuf->in_strike;
2456 obuf->bp.in_ins = obuf->in_ins;
2457 obuf->bp.nobr_level = obuf->nobr_level;
2458 obuf->bp.prev_ctype = obuf->prev_ctype;
2459 obuf->bp.init_flag = 0;
2463 back_to_breakpoint(struct readbuffer *obuf)
2465 obuf->flag = obuf->bp.flag;
2466 bcopy((void *)&obuf->bp.anchor, (void *)&obuf->anchor,
2467 sizeof(obuf->anchor));
2468 obuf->img_alt = obuf->bp.img_alt;
2469 obuf->in_bold = obuf->bp.in_bold;
2470 obuf->in_italic = obuf->bp.in_italic;
2471 obuf->in_under = obuf->bp.in_under;
2472 obuf->in_strike = obuf->bp.in_strike;
2473 obuf->in_ins = obuf->bp.in_ins;
2474 obuf->prev_ctype = obuf->bp.prev_ctype;
2475 obuf->pos = obuf->bp.pos;
2476 obuf->top_margin = obuf->bp.top_margin;
2477 obuf->bottom_margin = obuf->bp.bottom_margin;
2478 if (obuf->flag & RB_NOBR)
2479 obuf->nobr_level = obuf->bp.nobr_level;
2483 append_tags(struct readbuffer *obuf)
2486 int len = obuf->line->length;
2489 for (i = 0; i < obuf->tag_sp; i++) {
2490 switch (obuf->tag_stack[i]->cmd) {
2497 push_link(obuf->tag_stack[i]->cmd, obuf->line->length, obuf->pos);
2500 Strcat_charp(obuf->line, obuf->tag_stack[i]->cmdname);
2501 switch (obuf->tag_stack[i]->cmd) {
2503 if (obuf->nobr_level > 1)
2512 set_breakpoint(obuf, obuf->line->length - len);
2516 push_tag(struct readbuffer *obuf, char *cmdname, int cmd)
2518 obuf->tag_stack[obuf->tag_sp] = New(struct cmdtable);
2519 obuf->tag_stack[obuf->tag_sp]->cmdname = allocStr(cmdname, -1);
2520 obuf->tag_stack[obuf->tag_sp]->cmd = cmd;
2522 if (obuf->tag_sp >= TAG_STACK_SIZE || obuf->flag & (RB_SPECIAL & ~RB_NOBR))
2527 push_nchars(struct readbuffer *obuf, int width,
2528 char *str, int len, Lineprop mode)
2531 Strcat_charp_n(obuf->line, str, len);
2534 set_prevchar(obuf->prevchar, str, len);
2535 obuf->prev_ctype = mode;
2537 obuf->flag |= RB_NFLUSHED;
2540 #define push_charp(obuf, width, str, mode)\
2541 push_nchars(obuf, width, str, strlen(str), mode)
2543 #define push_str(obuf, width, str, mode)\
2544 push_nchars(obuf, width, str->ptr, str->length, mode)
2547 check_breakpoint(struct readbuffer *obuf, int pre_mode, char *ch)
2549 int tlen, len = obuf->line->length;
2554 tlen = obuf->line->length - len;
2556 || is_boundary((unsigned char *)obuf->prevchar->ptr,
2557 (unsigned char *)ch))
2558 set_breakpoint(obuf, tlen);
2562 push_char(struct readbuffer *obuf, int pre_mode, char ch)
2564 check_breakpoint(obuf, pre_mode, &ch);
2565 Strcat_char(obuf->line, ch);
2567 set_prevchar(obuf->prevchar, &ch, 1);
2569 obuf->prev_ctype = PC_ASCII;
2570 obuf->flag |= RB_NFLUSHED;
2573 #define PUSH(c) push_char(obuf, obuf->flag & RB_SPECIAL, c)
2576 push_spaces(struct readbuffer *obuf, int pre_mode, int width)
2582 check_breakpoint(obuf, pre_mode, " ");
2583 for (i = 0; i < width; i++)
2584 Strcat_char(obuf->line, ' ');
2586 set_space_to_prevchar(obuf->prevchar);
2587 obuf->flag |= RB_NFLUSHED;
2591 proc_mchar(struct readbuffer *obuf, int pre_mode,
2592 int width, char **str, Lineprop mode)
2594 check_breakpoint(obuf, pre_mode, *str);
2596 Strcat_charp_n(obuf->line, *str, get_mclen(*str));
2598 set_prevchar(obuf->prevchar, *str, 1);
2600 obuf->prev_ctype = mode;
2602 (*str) += get_mclen(*str);
2603 obuf->flag |= RB_NFLUSHED;
2607 push_render_image(Str str, int width, int limit,
2608 struct html_feed_environ *h_env)
2610 struct readbuffer *obuf = h_env->obuf;
2611 int indent = h_env->envs[h_env->envc].indent;
2613 push_spaces(obuf, 1, (limit - width) / 2);
2614 push_str(obuf, width, str, PC_ASCII);
2615 push_spaces(obuf, 1, (limit - width + 1) / 2);
2617 flushline(h_env, obuf, indent, 0, h_env->limit);
2621 sloppy_parse_line(char **str)
2624 while (**str && **str != '>')
2631 while (**str && **str != '<')
2638 passthrough(struct readbuffer *obuf, char *str, int back)
2645 Str str_save = Strnew_charp(str);
2646 Strshrink(obuf->line, obuf->line->ptr + obuf->line->length - str);
2647 str = str_save->ptr;
2651 if (sloppy_parse_line(&str)) {
2653 cmd = gethtmlcmd(&q);
2655 struct link_stack *p;
2656 for (p = link_stack; p; p = p->next) {
2657 if (p->cmd == cmd) {
2658 link_stack = p->next;
2665 Strcat_charp_n(tok, str_bak, str - str_bak);
2666 push_tag(obuf, tok->ptr, cmd);
2671 push_nchars(obuf, 0, str_bak, str - str_bak, obuf->prev_ctype);
2678 is_blank_line(char *line, int indent)
2680 int i, is_blank = 0;
2682 for (i = 0; i < indent; i++) {
2683 if (line[i] == '\0') {
2686 else if (line[i] != ' ') {
2690 if (i == indent && line[i] == '\0')
2697 fillline(struct readbuffer *obuf, int indent)
2699 push_spaces(obuf, 1, indent - obuf->pos);
2700 obuf->flag &= ~RB_NFLUSHED;
2704 flushline(struct html_feed_environ *h_env, struct readbuffer *obuf, int indent,
2705 int force, int width)
2707 TextLineList *buf = h_env->buf;
2709 Str line = obuf->line, pass = NULL;
2710 char *hidden_anchor = NULL, *hidden_img = NULL, *hidden_bold = NULL,
2711 *hidden_under = NULL, *hidden_italic = NULL, *hidden_strike = NULL,
2712 *hidden_ins = NULL, *hidden = NULL;
2716 FILE *df = fopen("zzzproc1", "a");
2717 fprintf(df, "flushline(%s,%d,%d,%d)\n", obuf->line->ptr, indent, force,
2720 TextLineListItem *p;
2721 for (p = buf->first; p; p = p->next) {
2722 fprintf(df, "buf=\"%s\"\n", p->ptr->line->ptr);
2729 if (!(obuf->flag & (RB_SPECIAL & ~RB_NOBR)) && Strlastchar(line) == ' ') {
2736 if (obuf->anchor.url)
2737 hidden = hidden_anchor = has_hidden_link(obuf, HTML_A);
2738 if (obuf->img_alt) {
2739 if ((hidden_img = has_hidden_link(obuf, HTML_IMG_ALT)) != NULL) {
2740 if (!hidden || hidden_img < hidden)
2741 hidden = hidden_img;
2744 if (obuf->in_bold) {
2745 if ((hidden_bold = has_hidden_link(obuf, HTML_B)) != NULL) {
2746 if (!hidden || hidden_bold < hidden)
2747 hidden = hidden_bold;
2750 if (obuf->in_italic) {
2751 if ((hidden_italic = has_hidden_link(obuf, HTML_I)) != NULL) {
2752 if (!hidden || hidden_italic < hidden)
2753 hidden = hidden_italic;
2756 if (obuf->in_under) {
2757 if ((hidden_under = has_hidden_link(obuf, HTML_U)) != NULL) {
2758 if (!hidden || hidden_under < hidden)
2759 hidden = hidden_under;
2762 if (obuf->in_strike) {
2763 if ((hidden_strike = has_hidden_link(obuf, HTML_S)) != NULL) {
2764 if (!hidden || hidden_strike < hidden)
2765 hidden = hidden_strike;
2769 if ((hidden_ins = has_hidden_link(obuf, HTML_INS)) != NULL) {
2770 if (!hidden || hidden_ins < hidden)
2771 hidden = hidden_ins;
2775 pass = Strnew_charp(hidden);
2776 Strshrink(line, line->ptr + line->length - hidden);
2779 if (!(obuf->flag & (RB_SPECIAL & ~RB_NOBR)) && obuf->pos > width) {
2780 char *tp = &line->ptr[obuf->bp.len - obuf->bp.tlen];
2781 char *ep = &line->ptr[line->length];
2783 if (obuf->bp.pos == obuf->pos && tp <= ep &&
2784 tp > line->ptr && tp[-1] == ' ') {
2785 bcopy(tp, tp - 1, ep - tp + 1);
2791 if (obuf->anchor.url && !hidden_anchor)
2792 Strcat_charp(line, "</a>");
2793 if (obuf->img_alt && !hidden_img)
2794 Strcat_charp(line, "</img_alt>");
2795 if (obuf->in_bold && !hidden_bold)
2796 Strcat_charp(line, "</b>");
2797 if (obuf->in_italic && !hidden_italic)
2798 Strcat_charp(line, "</i>");
2799 if (obuf->in_under && !hidden_under)
2800 Strcat_charp(line, "</u>");
2801 if (obuf->in_strike && !hidden_strike)
2802 Strcat_charp(line, "</s>");
2803 if (obuf->in_ins && !hidden_ins)
2804 Strcat_charp(line, "</ins>");
2806 if (obuf->top_margin > 0) {
2808 struct html_feed_environ h;
2809 struct readbuffer o;
2810 struct environment e[1];
2812 init_henv(&h, &o, e, 1, NULL, width, indent);
2813 o.line = Strnew_size(width + 20);
2815 o.flag = obuf->flag;
2817 o.bottom_margin = -1;
2818 Strcat_charp(o.line, "<pre_int>");
2819 for (i = 0; i < o.pos; i++)
2820 Strcat_char(o.line, ' ');
2821 Strcat_charp(o.line, "</pre_int>");
2822 for (i = 0; i < obuf->top_margin; i++)
2823 flushline(h_env, &o, indent, force, width);
2826 if (force == 1 || obuf->flag & RB_NFLUSHED) {
2827 TextLine *lbuf = newTextLine(line, obuf->pos);
2828 if (RB_GET_ALIGN(obuf) == RB_CENTER) {
2829 align(lbuf, width, ALIGN_CENTER);
2831 else if (RB_GET_ALIGN(obuf) == RB_RIGHT) {
2832 align(lbuf, width, ALIGN_RIGHT);
2834 else if (RB_GET_ALIGN(obuf) == RB_LEFT && obuf->flag & RB_INTABLE) {
2835 align(lbuf, width, ALIGN_LEFT);
2838 else if (obuf->flag & RB_FILL) {
2843 rest = width - get_Str_strwidth(line);
2846 for (p = line->ptr + indent; *p; p++) {
2851 int indent_here = 0;
2854 while (IS_SPACE(*p)) {
2858 rrest = rest - d * nspace;
2859 line = Strnew_size(width + 1);
2860 for (i = 0; i < indent_here; i++)
2861 Strcat_char(line, ' ');
2863 Strcat_char(line, *p);
2865 for (i = 0; i < d; i++)
2866 Strcat_char(line, ' ');
2868 Strcat_char(line, ' ');
2873 lbuf = newTextLine(line, width);
2877 #endif /* FORMAT_NICE */
2880 FILE *f = fopen("zzzproc1", "a");
2881 fprintf(f, "pos=%d,%d, maxlimit=%d\n",
2882 visible_length(lbuf->line->ptr), lbuf->pos,
2887 if (lbuf->pos > h_env->maxlimit)
2888 h_env->maxlimit = lbuf->pos;
2890 pushTextLine(buf, lbuf);
2892 Strfputs(Str_conv_to_halfdump(lbuf->line), f);
2895 if (obuf->flag & RB_SPECIAL || obuf->flag & RB_NFLUSHED)
2896 h_env->blank_lines = 0;
2898 h_env->blank_lines++;
2901 char *p = line->ptr, *q;
2902 Str tmp = Strnew(), tmp2 = Strnew();
2904 #define APPEND(str) \
2906 appendTextLine(buf,(str),0); \
2912 if (sloppy_parse_line(&p)) {
2913 Strcat_charp_n(tmp, q, p - q);
2935 if (obuf->bottom_margin > 0) {
2937 struct html_feed_environ h;
2938 struct readbuffer o;
2939 struct environment e[1];
2941 init_henv(&h, &o, e, 1, NULL, width, indent);
2942 o.line = Strnew_size(width + 20);
2944 o.flag = obuf->flag;
2946 o.bottom_margin = -1;
2947 Strcat_charp(o.line, "<pre_int>");
2948 for (i = 0; i < o.pos; i++)
2949 Strcat_char(o.line, ' ');
2950 Strcat_charp(o.line, "</pre_int>");
2951 for (i = 0; i < obuf->bottom_margin; i++)
2952 flushline(h_env, &o, indent, force, width);
2954 if (obuf->top_margin < 0 || obuf->bottom_margin < 0)
2957 obuf->line = Strnew_size(256);
2959 obuf->top_margin = 0;
2960 obuf->bottom_margin = 0;
2961 set_space_to_prevchar(obuf->prevchar);
2962 obuf->bp.init_flag = 1;
2963 obuf->flag &= ~RB_NFLUSHED;
2964 set_breakpoint(obuf, 0);
2965 obuf->prev_ctype = PC_ASCII;
2967 fillline(obuf, indent);
2969 passthrough(obuf, pass->ptr, 0);
2970 if (!hidden_anchor && obuf->anchor.url) {
2972 if (obuf->anchor.hseq > 0)
2973 obuf->anchor.hseq = -obuf->anchor.hseq;
2974 tmp = Sprintf("<A HSEQ=\"%d\" HREF=\"", obuf->anchor.hseq);
2975 Strcat_charp(tmp, html_quote(obuf->anchor.url));
2976 if (obuf->anchor.target) {
2977 Strcat_charp(tmp, "\" TARGET=\"");
2978 Strcat_charp(tmp, html_quote(obuf->anchor.target));
2980 if (obuf->anchor.referer) {
2981 Strcat_charp(tmp, "\" REFERER=\"");
2982 Strcat_charp(tmp, html_quote(obuf->anchor.referer));
2984 if (obuf->anchor.title) {
2985 Strcat_charp(tmp, "\" TITLE=\"");
2986 Strcat_charp(tmp, html_quote(obuf->anchor.title));
2988 if (obuf->anchor.accesskey) {
2989 char *c = html_quote_char(obuf->anchor.accesskey);
2990 Strcat_charp(tmp, "\" ACCESSKEY=\"");
2992 Strcat_charp(tmp, c);
2994 Strcat_char(tmp, obuf->anchor.accesskey);
2996 Strcat_charp(tmp, "\">");
2997 push_tag(obuf, tmp->ptr, HTML_A);
2999 if (!hidden_img && obuf->img_alt) {
3000 Str tmp = Strnew_charp("<IMG_ALT SRC=\"");
3001 Strcat_charp(tmp, html_quote(obuf->img_alt->ptr));
3002 Strcat_charp(tmp, "\">");
3003 push_tag(obuf, tmp->ptr, HTML_IMG_ALT);
3005 if (!hidden_bold && obuf->in_bold)
3006 push_tag(obuf, "<B>", HTML_B);
3007 if (!hidden_italic && obuf->in_italic)
3008 push_tag(obuf, "<I>", HTML_I);
3009 if (!hidden_under && obuf->in_under)
3010 push_tag(obuf, "<U>", HTML_U);
3011 if (!hidden_strike && obuf->in_strike)
3012 push_tag(obuf, "<S>", HTML_S);
3013 if (!hidden_ins && obuf->in_ins)
3014 push_tag(obuf, "<INS>", HTML_INS);
3018 do_blankline(struct html_feed_environ *h_env, struct readbuffer *obuf,
3019 int indent, int indent_incr, int width)
3021 if (h_env->blank_lines == 0)
3022 flushline(h_env, obuf, indent, 1, width);
3026 purgeline(struct html_feed_environ *h_env)
3031 if (h_env->buf == NULL || h_env->blank_lines == 0)
3034 p = rpopTextLine(h_env->buf)->line->ptr;
3038 if (sloppy_parse_line(&p)) {
3039 Strcat_charp_n(tmp, q, p - q);
3042 appendTextLine(h_env->buf, tmp, 0);
3043 h_env->blank_lines--;
3047 close_effect0(struct readbuffer *obuf, int cmd)
3052 for (i = obuf->tag_sp - 1; i >= 0; i--) {
3053 if (obuf->tag_stack[i]->cmd == cmd)
3058 bcopy(&obuf->tag_stack[i + 1], &obuf->tag_stack[i],
3059 (obuf->tag_sp - i) * sizeof(struct cmdtable *));
3062 else if ((p = has_hidden_link(obuf, cmd)) != NULL) {
3063 passthrough(obuf, p, 1);
3070 close_anchor(struct html_feed_environ *h_env, struct readbuffer *obuf)
3072 if (obuf->anchor.url) {
3077 for (i = obuf->tag_sp - 1; i >= 0; i--) {
3078 if (obuf->tag_stack[i]->cmd == HTML_A)
3081 if (i < 0 && obuf->anchor.hseq > 0 && Strlastchar(obuf->line) == ' ') {
3082 Strshrink(obuf->line, 1);
3087 if (i >= 0 || (p = has_hidden_link(obuf, HTML_A))) {
3088 if (obuf->anchor.hseq > 0) {
3089 HTMLlineproc1(ANSP, h_env);
3090 set_space_to_prevchar(obuf->prevchar);
3095 bcopy(&obuf->tag_stack[i + 1], &obuf->tag_stack[i],
3096 (obuf->tag_sp - i) * sizeof(struct cmdtable *));
3099 passthrough(obuf, p, 1);
3101 bzero((void *)&obuf->anchor, sizeof(obuf->anchor));
3107 Strcat_char(obuf->line, ' ');
3111 push_tag(obuf, "</a>", HTML_N_A);
3113 bzero((void *)&obuf->anchor, sizeof(obuf->anchor));
3117 save_fonteffect(struct html_feed_environ *h_env, struct readbuffer *obuf)
3119 if (obuf->fontstat_sp < FONT_STACK_SIZE)
3120 bcopy(obuf->fontstat, obuf->fontstat_stack[obuf->fontstat_sp],
3122 obuf->fontstat_sp++;
3124 push_tag(obuf, "</b>", HTML_N_B);
3125 if (obuf->in_italic)
3126 push_tag(obuf, "</i>", HTML_N_I);
3128 push_tag(obuf, "</u>", HTML_N_U);
3129 if (obuf->in_strike)
3130 push_tag(obuf, "</s>", HTML_N_S);
3132 push_tag(obuf, "</ins>", HTML_N_INS);
3133 bzero(obuf->fontstat, FONTSTAT_SIZE);
3137 restore_fonteffect(struct html_feed_environ *h_env, struct readbuffer *obuf)
3139 if (obuf->fontstat_sp > 0)
3140 obuf->fontstat_sp--;
3141 if (obuf->fontstat_sp < FONT_STACK_SIZE)
3142 bcopy(obuf->fontstat_stack[obuf->fontstat_sp], obuf->fontstat,
3145 push_tag(obuf, "<b>", HTML_B);
3146 if (obuf->in_italic)
3147 push_tag(obuf, "<i>", HTML_I);
3149 push_tag(obuf, "<u>", HTML_U);
3150 if (obuf->in_strike)
3151 push_tag(obuf, "<s>", HTML_S);
3153 push_tag(obuf, "<ins>", HTML_INS);
3157 process_title(struct parsed_tag *tag)
3159 cur_title = Strnew();
3164 process_n_title(struct parsed_tag *tag)
3170 Strremovefirstspaces(cur_title);
3171 Strremovetrailingspaces(cur_title);
3172 tmp = Strnew_m_charp("<title_alt title=\"",
3173 html_quote(cur_title->ptr), "\">", NULL);
3179 feed_title(char *str)
3185 Strcat_charp(cur_title, getescapecmd(&str));
3186 else if (*str == '\n' || *str == '\r') {
3187 Strcat_char(cur_title, ' ');
3191 Strcat_char(cur_title, *(str++));
3196 process_img(struct parsed_tag *tag, int width)
3198 char *p, *q, *r, *r2 = NULL, *s, *t;
3200 int w, i, nw, ni = 1, n, w0 = -1, i0 = -1;
3201 int align, xoffset, yoffset, top, bottom, ismap = 0;
3202 int use_image = activeImage && displayImage;
3206 int pre_int = FALSE, ext_pre_int = FALSE;
3209 if (!parsedtag_get_value(tag, ATTR_SRC, &p))
3211 p = remove_space(p);
3213 parsedtag_get_value(tag, ATTR_ALT, &q);
3215 parsedtag_get_value(tag, ATTR_TITLE, &t);
3217 if (parsedtag_get_value(tag, ATTR_WIDTH, &w)) {
3220 w = (int)(-width * pixel_per_char * w / 100 + 0.5);
3227 w = (int)(w * image_scale / 100 + 0.5);
3230 else if (w > MAX_IMAGE_SIZE)
3239 if (parsedtag_get_value(tag, ATTR_HEIGHT, &i)) {
3241 i = (int)(i * image_scale / 100 + 0.5);
3244 else if (i > MAX_IMAGE_SIZE)
3252 parsedtag_get_value(tag, ATTR_ALIGN, &align);
3254 if (parsedtag_exists(tag, ATTR_ISMAP))
3259 parsedtag_get_value(tag, ATTR_HEIGHT, &i);
3261 parsedtag_get_value(tag, ATTR_USEMAP, &r);
3262 if (parsedtag_exists(tag, ATTR_PRE_INT))
3265 tmp = Strnew_size(128);
3270 Strcat_charp(tmp, "<div_int align=left>");
3273 Strcat_charp(tmp, "<div_int align=center>");
3276 Strcat_charp(tmp, "<div_int align=right>");
3283 r2 = strchr(r, '#');
3284 s = "<form_int method=internal action=map>";
3285 tmp2 = process_form(parse_tag(&s, TRUE));
3288 Strcat(tmp, Sprintf("<input_alt fid=\"%d\" "
3289 "type=hidden name=link value=\"", cur_form_id));
3290 Strcat_charp(tmp, html_quote((r2) ? r2 + 1 : r));
3291 Strcat(tmp, Sprintf("\"><input_alt hseq=\"%d\" fid=\"%d\" "
3292 "type=submit no_effect=true>",
3293 cur_hseq++, cur_form_id));
3299 if (w < 0 || i < 0) {
3304 parseURL2(wc_conv(p, InnerCharset, cur_document_charset)->ptr, &u,
3307 parseURL2(p, &u, cur_baseURL);
3309 image.url = parsedURL2Str(&u)->ptr;
3310 if (!uncompressed_file_type(u.file, &image.ext))
3311 image.ext = filename_extension(u.file, TRUE);
3316 image.cache = getImage(&image, cur_baseURL, IMG_FLAG_SKIP);
3317 if (image.cache && image.cache->width > 0 &&
3318 image.cache->height > 0) {
3319 w = w0 = image.cache->width;
3320 i = i0 = image.cache->height;
3323 w = 8 * pixel_per_char;
3327 nw = (w > 3) ? (int)((w - 3) / pixel_per_char + 1) : 1;
3328 ni = (i > 3) ? (int)((i - 3) / pixel_per_line + 1) : 1;
3330 Sprintf("<pre_int><img_alt hseq=\"%d\" src=\"", cur_iseq++));
3337 w = 12 * pixel_per_char;
3338 nw = w ? (int)((w - 1) / pixel_per_char + 1) : 1;
3340 Strcat_charp(tmp, "<pre_int>");
3343 Strcat_charp(tmp, "<img_alt src=\"");
3345 Strcat_charp(tmp, html_quote(p));
3346 Strcat_charp(tmp, "\"");
3348 Strcat_charp(tmp, " title=\"");
3349 Strcat_charp(tmp, html_quote(t));
3350 Strcat_charp(tmp, "\"");
3355 Strcat(tmp, Sprintf(" width=%d", w0));
3357 Strcat(tmp, Sprintf(" height=%d", i0));
3368 yoffset = (int)(((ni + 1) * pixel_per_line - i) / 2);
3370 yoffset = (int)((ni * pixel_per_line - i) / 2);
3375 yoffset = (int)(ni * pixel_per_line - i);
3380 if (ni == 1 && ni * pixel_per_line > i)
3383 yoffset = (int)(ni * pixel_per_line - i);
3389 xoffset = (int)((nw * pixel_per_char - w) / 2);
3391 Strcat(tmp, Sprintf(" xoffset=%d", xoffset));
3393 Strcat(tmp, Sprintf(" yoffset=%d", yoffset));
3395 Strcat(tmp, Sprintf(" top_margin=%d", top));
3397 Strcat(tmp, Sprintf(" bottom_margin=%d", bottom));
3399 Strcat_charp(tmp, " usemap=\"");
3400 Strcat_charp(tmp, html_quote((r2) ? r2 + 1 : r));
3401 Strcat_charp(tmp, "\"");
3404 Strcat_charp(tmp, " ismap");
3407 Strcat_charp(tmp, ">");
3408 if (q != NULL && *q == '\0' && ignore_null_img_alt)
3411 n = get_strwidth(q);
3416 for (r = q, n = 0; r; r += get_mclen(r), n += get_mcwidth(r)) {
3417 if (n + get_mcwidth(r) > nw)
3420 Strcat_charp(tmp, html_quote(Strnew_charp_n(q, r - q)->ptr));
3423 Strcat_charp(tmp, html_quote(q));
3427 Strcat_charp(tmp, html_quote(q));
3430 if (w > 0 && i > 0) {
3431 /* guess what the image is! */
3432 if (w < 32 && i < 48) {
3433 /* must be an icon or space */
3435 if (strcasestr(p, "space") || strcasestr(p, "blank"))
3436 Strcat_charp(tmp, "_");
3439 Strcat_charp(tmp, "*");
3442 Strcat_charp(tmp, "<pre_int>");
3445 push_symbol(tmp, IMG_SYMBOL, symbol_width, 1);
3451 if (w > 200 && i < 13) {
3452 /* must be a horizontal line */
3454 Strcat_charp(tmp, "<pre_int>");
3457 w = w / pixel_per_char / symbol_width;
3460 push_symbol(tmp, HR_SYMBOL, symbol_width, w);
3461 n = w * symbol_width;
3465 for (q = p; *q; q++) ;
3466 while (q > p && *q != '/')
3470 Strcat_char(tmp, '[');
3474 if (!IS_ALNUM(*q) && *q != '_' && *q != '-') {
3477 Strcat_char(tmp, *q);
3482 Strcat_char(tmp, ']');
3488 Strcat_char(tmp, ' ');
3491 Strcat_charp(tmp, "</img_alt>");
3492 if (pre_int && !ext_pre_int)
3493 Strcat_charp(tmp, "</pre_int>");
3495 Strcat_charp(tmp, "</input_alt>");
3504 Strcat_charp(tmp, "</div_int>");
3513 process_anchor(struct parsed_tag *tag, char *tagbuf)
3515 if (parsedtag_need_reconstruct(tag)) {
3516 parsedtag_set_value(tag, ATTR_HSEQ, Sprintf("%d", cur_hseq++)->ptr);
3517 return parsedtag2str(tag);
3520 Str tmp = Sprintf("<a hseq=\"%d\"", cur_hseq++);
3521 Strcat_charp(tmp, tagbuf + 2);
3527 process_input(struct parsed_tag *tag)
3529 int i, w, v, x, y, z, iw, ih;
3530 char *q, *p, *r, *p2, *s;
3535 if (cur_form_id < 0) {
3536 char *s = "<form_int method=internal action=none>";
3537 tmp = process_form(parse_tag(&s, TRUE));
3543 parsedtag_get_value(tag, ATTR_TYPE, &p);
3545 parsedtag_get_value(tag, ATTR_VALUE, &q);
3547 parsedtag_get_value(tag, ATTR_NAME, &r);
3549 parsedtag_get_value(tag, ATTR_SIZE, &w);
3551 parsedtag_get_value(tag, ATTR_MAXLENGTH, &i);
3553 parsedtag_get_value(tag, ATTR_ALT, &p2);
3554 x = parsedtag_exists(tag, ATTR_CHECKED);
3555 y = parsedtag_exists(tag, ATTR_ACCEPT);
3556 z = parsedtag_exists(tag, ATTR_READONLY);
3559 if (v == FORM_UNKNOWN)
3564 case FORM_INPUT_IMAGE:
3565 case FORM_INPUT_SUBMIT:
3566 case FORM_INPUT_BUTTON:
3569 case FORM_INPUT_RESET:
3572 /* if no VALUE attribute is specified in
3573 * <INPUT TYPE=CHECKBOX> tag, then the value "on" is used
3574 * as a default value. It is not a part of HTML4.0
3575 * specification, but an imitation of Netscape behaviour.
3577 case FORM_INPUT_CHECKBOX:
3581 /* VALUE attribute is not allowed in <INPUT TYPE=FILE> tag. */
3582 if (v == FORM_INPUT_FILE)
3586 qlen = get_strwidth(q);
3589 Strcat_charp(tmp, "<pre_int>");
3591 case FORM_INPUT_PASSWORD:
3592 case FORM_INPUT_TEXT:
3593 case FORM_INPUT_FILE:
3594 case FORM_INPUT_CHECKBOX:
3595 Strcat_char(tmp, '[');
3597 case FORM_INPUT_RADIO:
3598 Strcat_char(tmp, '(');
3600 Strcat(tmp, Sprintf("<input_alt hseq=\"%d\" fid=\"%d\" type=%s "
3601 "name=\"%s\" width=%d maxlength=%d value=\"%s\"",
3602 cur_hseq++, cur_form_id, p, html_quote(r), w, i, qq));
3604 Strcat_charp(tmp, " checked");
3606 Strcat_charp(tmp, " accept");
3608 Strcat_charp(tmp, " readonly");
3609 Strcat_char(tmp, '>');
3611 if (v == FORM_INPUT_HIDDEN)
3612 Strcat_charp(tmp, "</input_alt></pre_int>");
3615 case FORM_INPUT_PASSWORD:
3616 case FORM_INPUT_TEXT:
3617 case FORM_INPUT_FILE:
3618 Strcat_charp(tmp, "<u>");
3620 case FORM_INPUT_IMAGE:
3622 parsedtag_get_value(tag, ATTR_SRC, &s);
3624 Strcat(tmp, Sprintf("<img src=\"%s\"", html_quote(s)));
3626 Strcat(tmp, Sprintf(" alt=\"%s\"", html_quote(p2)));
3627 if (parsedtag_get_value(tag, ATTR_WIDTH, &iw))
3628 Strcat(tmp, Sprintf(" width=\"%d\"", iw));
3629 if (parsedtag_get_value(tag, ATTR_HEIGHT, &ih))
3630 Strcat(tmp, Sprintf(" height=\"%d\"", ih));
3631 Strcat_charp(tmp, " pre_int>");
3632 Strcat_charp(tmp, "</input_alt></pre_int>");
3635 case FORM_INPUT_SUBMIT:
3636 case FORM_INPUT_BUTTON:
3637 case FORM_INPUT_RESET:
3638 Strcat_charp(tmp, "[");
3642 case FORM_INPUT_PASSWORD:
3645 for (; i < qlen && i < w; i++)
3646 Strcat_char(tmp, '*');
3649 Strcat_char(tmp, ' ');
3651 case FORM_INPUT_TEXT:
3652 case FORM_INPUT_FILE:
3654 Strcat(tmp, textfieldrep(Strnew_charp(q), w));
3656 for (i = 0; i < w; i++)
3657 Strcat_char(tmp, ' ');
3660 case FORM_INPUT_SUBMIT:
3661 case FORM_INPUT_BUTTON:
3663 Strcat_charp(tmp, html_quote(p2));
3665 Strcat_charp(tmp, qq);
3667 case FORM_INPUT_RESET:
3668 Strcat_charp(tmp, qq);
3670 case FORM_INPUT_RADIO:
3671 case FORM_INPUT_CHECKBOX:
3673 Strcat_char(tmp, '*');
3675 Strcat_char(tmp, ' ');
3679 case FORM_INPUT_PASSWORD:
3680 case FORM_INPUT_TEXT:
3681 case FORM_INPUT_FILE:
3682 Strcat_charp(tmp, "</u>");
3684 case FORM_INPUT_IMAGE:
3685 case FORM_INPUT_SUBMIT:
3686 case FORM_INPUT_BUTTON:
3687 case FORM_INPUT_RESET:
3688 Strcat_charp(tmp, "]");
3690 Strcat_charp(tmp, "</input_alt>");
3692 case FORM_INPUT_PASSWORD:
3693 case FORM_INPUT_TEXT:
3694 case FORM_INPUT_FILE:
3695 case FORM_INPUT_CHECKBOX:
3696 Strcat_char(tmp, ']');
3698 case FORM_INPUT_RADIO:
3699 Strcat_char(tmp, ')');
3701 Strcat_charp(tmp, "</pre_int>");
3707 process_select(struct parsed_tag *tag)
3712 if (cur_form_id < 0) {
3713 char *s = "<form_int method=internal action=none>";
3714 tmp = process_form(parse_tag(&s, TRUE));
3718 parsedtag_get_value(tag, ATTR_NAME, &p);
3719 cur_select = Strnew_charp(p);
3720 select_is_multiple = parsedtag_exists(tag, ATTR_MULTIPLE);
3723 if (!select_is_multiple) {
3724 select_str = Sprintf("<pre_int>[<input_alt hseq=\"%d\" "
3725 "fid=\"%d\" type=select name=\"%s\" selectnumber=%d",
3726 cur_hseq++, cur_form_id, html_quote(p), n_select);
3727 Strcat_charp(select_str, ">");
3728 if (n_select == max_select) {
3731 New_Reuse(FormSelectOption, select_option, max_select);
3733 select_option[n_select].first = NULL;
3734 select_option[n_select].last = NULL;
3735 cur_option_maxwidth = 0;
3738 #endif /* MENU_SELECT */
3739 select_str = Strnew();
3741 cur_status = R_ST_NORMAL;
3747 process_n_select(void)
3749 if (cur_select == NULL)
3753 if (!select_is_multiple) {
3754 if (select_option[n_select].first) {
3756 chooseSelectOption(&sitem, select_option[n_select].first);
3757 Strcat(select_str, textfieldrep(sitem.label, cur_option_maxwidth));
3759 Strcat_charp(select_str, "</input_alt>]</pre_int>");
3763 #endif /* MENU_SELECT */
3764 Strcat_charp(select_str, "<br>");
3771 feed_select(char *str)
3774 int prev_status = cur_status;
3775 static int prev_spaces = -1;
3778 if (cur_select == NULL)
3780 while (read_token(tmp, &str, &cur_status, 0, 0)) {
3781 if (cur_status != R_ST_NORMAL || prev_status != R_ST_NORMAL)
3784 if (tmp->ptr[0] == '<' && Strlastchar(tmp) == '>') {
3785 struct parsed_tag *tag;
3787 if (!(tag = parse_tag(&p, FALSE)))
3789 switch (tag->tagid) {
3792 cur_option = Strnew();
3793 if (parsedtag_get_value(tag, ATTR_VALUE, &q))
3794 cur_option_value = Strnew_charp(q);
3796 cur_option_value = NULL;
3797 if (parsedtag_get_value(tag, ATTR_LABEL, &q))
3798 cur_option_label = Strnew_charp(q);
3800 cur_option_label = NULL;
3801 cur_option_selected = parsedtag_exists(tag, ATTR_SELECTED);
3812 else if (cur_option) {
3814 if (IS_SPACE(*p) && prev_spaces != 0) {
3816 if (prev_spaces > 0)
3825 Strcat_charp(cur_option, getescapecmd(&p));
3827 Strcat_char(cur_option, *(p++));
3835 process_option(void)
3837 char begin_char = '[', end_char = ']';
3840 if (cur_select == NULL || cur_option == NULL)
3842 while (cur_option->length > 0 && IS_SPACE(Strlastchar(cur_option)))
3843 Strshrink(cur_option, 1);
3844 if (cur_option_value == NULL)
3845 cur_option_value = cur_option;
3846 if (cur_option_label == NULL)
3847 cur_option_label = cur_option;
3849 if (!select_is_multiple) {
3850 len = get_Str_strwidth(cur_option_label);
3851 if (len > cur_option_maxwidth)
3852 cur_option_maxwidth = len;
3853 addSelectOption(&select_option[n_select],
3855 cur_option_label, cur_option_selected);
3858 #endif /* MENU_SELECT */
3859 if (!select_is_multiple) {
3863 Strcat(select_str, Sprintf("<br><pre_int>%c<input_alt hseq=\"%d\" "
3864 "fid=\"%d\" type=%s name=\"%s\" value=\"%s\"",
3865 begin_char, cur_hseq++, cur_form_id,
3866 select_is_multiple ? "checkbox" : "radio",
3867 html_quote(cur_select->ptr),
3868 html_quote(cur_option_value->ptr)));
3869 if (cur_option_selected)
3870 Strcat_charp(select_str, " checked>*</input_alt>");
3872 Strcat_charp(select_str, "> </input_alt>");
3873 Strcat_char(select_str, end_char);
3874 Strcat_charp(select_str, html_quote(cur_option_label->ptr));
3875 Strcat_charp(select_str, "</pre_int>");
3880 process_textarea(struct parsed_tag *tag, int width)
3885 if (cur_form_id < 0) {
3886 char *s = "<form_int method=internal action=none>";
3887 tmp = process_form(parse_tag(&s, TRUE));
3891 parsedtag_get_value(tag, ATTR_NAME, &p);
3892 cur_textarea = Strnew_charp(p);
3893 cur_textarea_size = 20;
3894 if (parsedtag_get_value(tag, ATTR_COLS, &p)) {
3895 cur_textarea_size = atoi(p);
3896 if (p[strlen(p) - 1] == '%')
3897 cur_textarea_size = width * cur_textarea_size / 100 - 2;
3898 if (cur_textarea_size <= 0)
3899 cur_textarea_size = 20;
3901 cur_textarea_rows = 1;
3902 if (parsedtag_get_value(tag, ATTR_ROWS, &p)) {
3903 cur_textarea_rows = atoi(p);
3904 if (cur_textarea_rows <= 0)
3905 cur_textarea_rows = 1;
3907 cur_textarea_readonly = parsedtag_exists(tag, ATTR_READONLY);
3908 if (n_textarea >= max_textarea) {
3910 textarea_str = New_Reuse(Str, textarea_str, max_textarea);
3912 textarea_str[n_textarea] = Strnew();
3913 ignore_nl_textarea = TRUE;
3919 process_n_textarea(void)
3924 if (cur_textarea == NULL)
3928 Strcat(tmp, Sprintf("<pre_int>[<input_alt hseq=\"%d\" fid=\"%d\" "
3929 "type=textarea name=\"%s\" size=%d rows=%d "
3930 "top_margin=%d textareanumber=%d",
3931 cur_hseq, cur_form_id,
3932 html_quote(cur_textarea->ptr),
3933 cur_textarea_size, cur_textarea_rows,
3934 cur_textarea_rows - 1, n_textarea));
3935 if (cur_textarea_readonly)
3936 Strcat_charp(tmp, " readonly");
3937 Strcat_charp(tmp, "><u>");
3938 for (i = 0; i < cur_textarea_size; i++)
3939 Strcat_char(tmp, ' ');
3940 Strcat_charp(tmp, "</u></input_alt>]</pre_int>\n");
3943 cur_textarea = NULL;
3949 feed_textarea(char *str)
3951 if (cur_textarea == NULL)
3953 if (ignore_nl_textarea) {
3959 ignore_nl_textarea = FALSE;
3962 Strcat_charp(textarea_str[n_textarea], getescapecmd(&str));
3963 else if (*str == '\n') {
3964 Strcat_charp(textarea_str[n_textarea], "\r\n");
3967 else if (*str != '\r')
3968 Strcat_char(textarea_str[n_textarea], *(str++));
3973 process_hr(struct parsed_tag *tag, int width, int indent_width)
3975 Str tmp = Strnew_charp("<nobr>");
3977 int x = ALIGN_CENTER;
3979 if (width > indent_width)
3980 width -= indent_width;
3981 if (parsedtag_get_value(tag, ATTR_WIDTH, &w))
3982 w = REAL_WIDTH(w, width);
3986 parsedtag_get_value(tag, ATTR_ALIGN, &x);
3989 Strcat_charp(tmp, "<div_int align=center>");
3992 Strcat_charp(tmp, "<div_int align=right>");
3995 Strcat_charp(tmp, "<div_int align=left>");
4001 push_symbol(tmp, HR_SYMBOL, symbol_width, w);
4002 Strcat_charp(tmp, "</div_int></nobr>");
4008 check_charset(char *p)
4010 return wc_guess_charset(p, 0) ? p : NULL;
4014 check_accept_charset(char *ac)
4019 while (*s && (IS_SPACE(*s) || *s == ','))
4024 while (*e && !(IS_SPACE(*e) || *e == ','))
4026 if (wc_guess_charset(Strnew_charp_n(s, e - s)->ptr, 0))
4035 process_form_int(struct parsed_tag *tag, int fid)
4037 char *p, *q, *r, *s, *tg, *n;
4040 parsedtag_get_value(tag, ATTR_METHOD, &p);
4041 q = "!CURRENT_URL!";
4042 parsedtag_get_value(tag, ATTR_ACTION, &q);
4045 if (parsedtag_get_value(tag, ATTR_ACCEPT_CHARSET, &r))
4046 r = check_accept_charset(r);
4047 if (!r && parsedtag_get_value(tag, ATTR_CHARSET, &r))
4048 r = check_charset(r);
4051 parsedtag_get_value(tag, ATTR_ENCTYPE, &s);
4053 parsedtag_get_value(tag, ATTR_TARGET, &tg);
4055 parsedtag_get_value(tag, ATTR_NAME, &n);
4062 else { /* <form_int> */
4067 if (forms_size == 0) {
4068 forms_size = INITIAL_FORM_SIZE;
4069 forms = New_N(FormList *, forms_size);
4070 form_stack = NewAtom_N(int, forms_size);
4072 else if (forms_size <= form_max) {
4073 forms_size += form_max;
4074 forms = New_Reuse(FormList *, forms, forms_size);
4075 form_stack = New_Reuse(int, form_stack, forms_size);
4077 form_stack[form_sp] = fid;
4080 Str tmp = Sprintf("<form_int fid=\"%d\" action=\"%s\" method=\"%s\"",
4081 fid, html_quote(q), html_quote(p));
4083 Strcat(tmp, Sprintf(" enctype=\"%s\"", html_quote(s)));
4085 Strcat(tmp, Sprintf(" target=\"%s\"", html_quote(tg)));
4087 Strcat(tmp, Sprintf(" name=\"%s\"", html_quote(n)));
4090 Strcat(tmp, Sprintf(" accept-charset=\"%s\"", html_quote(r)));
4092 Strcat_charp(tmp, ">");
4096 forms[fid] = newFormList(q, p, r, s, tg, n, NULL);
4101 process_form(struct parsed_tag *tag)
4103 return process_form_int(tag, -1);
4107 process_n_form(void)
4115 clear_ignore_p_flag(int cmd, struct readbuffer *obuf)
4117 static int clear_flag_cmd[] = {
4118 HTML_HR, HTML_UNKNOWN
4122 for (i = 0; clear_flag_cmd[i] != HTML_UNKNOWN; i++) {
4123 if (cmd == clear_flag_cmd[i]) {
4124 obuf->flag &= ~RB_IGNORE_P;
4131 set_alignment(struct readbuffer *obuf, struct parsed_tag *tag)
4136 if (parsedtag_get_value(tag, ATTR_ALIGN, &align)) {
4150 RB_SET_ALIGN(obuf, flag);
4156 process_idattr(struct readbuffer *obuf, int cmd, struct parsed_tag *tag)
4158 char *id = NULL, *framename = NULL;
4162 * HTML_TABLE is handled by the other process.
4164 if (cmd == HTML_TABLE)
4167 parsedtag_get_value(tag, ATTR_ID, &id);
4168 parsedtag_get_value(tag, ATTR_FRAMENAME, &framename);
4172 idtag = Sprintf("<_id id=\"%s\" framename=\"%s\">",
4173 html_quote(id), html_quote(framename));
4175 idtag = Sprintf("<_id id=\"%s\">", html_quote(id));
4176 push_tag(obuf, idtag->ptr, HTML_NOP);
4180 #define CLOSE_P if (obuf->flag & RB_P) { \
4181 flushline(h_env, obuf, envs[h_env->envc].indent,0,h_env->limit);\
4182 RB_RESTORE_FLAG(obuf);\
4183 obuf->flag &= ~RB_P;\
4188 close_anchor(h_env, obuf);
4191 if (obuf->flag & RB_IN_DT) { \
4192 obuf->flag &= ~RB_IN_DT; \
4193 HTMLlineproc1("</b>", h_env); \
4196 #define PUSH_ENV(cmd) \
4197 if (++h_env->envc_real < h_env->nenv) { \
4199 envs[h_env->envc].env = cmd; \
4200 envs[h_env->envc].count = 0; \
4201 if (h_env->envc <= MAX_INDENT_LEVEL) \
4202 envs[h_env->envc].indent = envs[h_env->envc - 1].indent + INDENT_INCR; \
4204 envs[h_env->envc].indent = envs[h_env->envc - 1].indent; \
4208 if (h_env->envc_real-- < h_env->nenv) \
4212 ul_type(struct parsed_tag *tag, int default_type)
4215 if (parsedtag_get_value(tag, ATTR_TYPE, &p)) {
4216 if (!strcasecmp(p, "disc"))
4218 else if (!strcasecmp(p, "circle"))
4220 else if (!strcasecmp(p, "square"))
4223 return default_type;
4227 getMetaRefreshParam(char *q, Str *refresh_uri)
4229 int refresh_interval;
4233 if (q == NULL || refresh_uri == NULL)
4236 refresh_interval = atoi(q);
4237 if (refresh_interval < 0)
4241 if (!strncasecmp(q, "url=", 4)) {
4243 if (*q == '\"') /* " */
4246 while (*r && !IS_SPACE(*r) && *r != ';')
4248 s_tmp = Strnew_charp_n(q, r - q);
4250 if (s_tmp->ptr[s_tmp->length - 1] == '\"') { /* "
4253 s_tmp->ptr[s_tmp->length] = '\0';
4257 while (*q && *q != ';')
4261 while (*q && *q == ' ')
4264 *refresh_uri = s_tmp;
4265 return refresh_interval;
4269 HTMLtagproc1(struct parsed_tag *tag, struct html_feed_environ *h_env)
4272 int i, w, x, y, z, count, width;
4273 struct readbuffer *obuf = h_env->obuf;
4274 struct environment *envs = h_env->envs;
4284 if (obuf->flag & RB_PRE) {
4289 case HTML_N_PRE_INT:
4297 if (obuf->in_bold > 1)
4301 if (obuf->in_bold == 1 && close_effect0(obuf, HTML_B))
4303 if (obuf->in_bold > 0) {
4305 if (obuf->in_bold == 0)
4311 if (obuf->in_italic > 1)
4315 if (obuf->in_italic == 1 && close_effect0(obuf, HTML_I))
4316 obuf->in_italic = 0;
4317 if (obuf->in_italic > 0) {
4319 if (obuf->in_italic == 0)
4325 if (obuf->in_under > 1)
4329 if (obuf->in_under == 1 && close_effect0(obuf, HTML_U))
4331 if (obuf->in_under > 0) {
4333 if (obuf->in_under == 0)
4338 HTMLlineproc1("<i>", h_env);
4341 HTMLlineproc1("</i>", h_env);
4344 HTMLlineproc1("<b>", h_env);
4347 HTMLlineproc1("</b>", h_env);
4350 HTMLlineproc1("`", h_env);
4353 HTMLlineproc1("'", h_env);
4358 if (!(obuf->flag & RB_IGNORE_P)) {
4359 flushline(h_env, obuf, envs[h_env->envc].indent, 1, h_env->limit);
4360 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
4363 obuf->flag |= RB_IGNORE_P;
4364 if (cmd == HTML_P) {
4365 set_alignment(obuf, tag);
4370 flushline(h_env, obuf, envs[h_env->envc].indent, 1, h_env->limit);
4371 h_env->blank_lines = 0;
4374 if (!(obuf->flag & (RB_PREMODE | RB_IGNORE_P))) {
4375 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4376 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
4379 HTMLlineproc1("<b>", h_env);
4380 set_alignment(obuf, tag);
4383 HTMLlineproc1("</b>", h_env);
4384 if (!(obuf->flag & RB_PREMODE)) {
4385 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4387 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4388 RB_RESTORE_FLAG(obuf);
4389 close_anchor(h_env, obuf);
4390 obuf->flag |= RB_IGNORE_P;
4396 if (!(obuf->flag & RB_IGNORE_P)) {
4397 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4398 if (!(obuf->flag & RB_PREMODE) &&
4399 (h_env->envc == 0 || cmd == HTML_BLQ))
4400 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
4404 if (cmd == HTML_UL || cmd == HTML_OL) {
4405 if (parsedtag_get_value(tag, ATTR_START, &count)) {
4406 envs[h_env->envc].count = count - 1;
4409 if (cmd == HTML_OL) {
4410 envs[h_env->envc].type = '1';
4411 if (parsedtag_get_value(tag, ATTR_TYPE, &p)) {
4412 envs[h_env->envc].type = (int)*p;
4416 envs[h_env->envc].type = ul_type(tag, 0);
4417 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4425 if (h_env->envc > 0) {
4426 flushline(h_env, obuf, envs[h_env->envc - 1].indent, 0,
4429 if (!(obuf->flag & RB_PREMODE) &&
4430 (h_env->envc == 0 || cmd == HTML_N_DL || cmd == HTML_N_BLQ)) {
4431 do_blankline(h_env, obuf,
4432 envs[h_env->envc].indent,
4433 INDENT_INCR, h_env->limit);
4434 obuf->flag |= RB_IGNORE_P;
4437 close_anchor(h_env, obuf);
4441 if (!(obuf->flag & RB_IGNORE_P)) {
4442 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4443 if (!(obuf->flag & RB_PREMODE))
4444 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
4448 if (parsedtag_exists(tag, ATTR_COMPACT))
4449 envs[h_env->envc].env = HTML_DL_COMPACT;
4450 obuf->flag |= RB_IGNORE_P;
4455 if (h_env->envc > 0) {
4457 flushline(h_env, obuf,
4458 envs[h_env->envc - 1].indent, 0, h_env->limit);
4459 envs[h_env->envc].count++;
4460 if (parsedtag_get_value(tag, ATTR_VALUE, &p)) {
4463 envs[h_env->envc].count = count;
4465 envs[h_env->envc].count = 0;
4467 switch (envs[h_env->envc].env) {
4469 envs[h_env->envc].type = ul_type(tag, envs[h_env->envc].type);
4470 for (i = 0; i < INDENT_INCR - 3; i++)
4471 push_charp(obuf, 1, NBSP, PC_ASCII);
4473 switch (envs[h_env->envc].type) {
4475 push_symbol(tmp, UL_SYMBOL_DISC, symbol_width, 1);
4478 push_symbol(tmp, UL_SYMBOL_CIRCLE, symbol_width, 1);
4481 push_symbol(tmp, UL_SYMBOL_SQUARE, symbol_width, 1);
4485 UL_SYMBOL((h_env->envc_real -
4486 1) % MAX_UL_LEVEL), symbol_width,
4490 if (symbol_width == 1)
4491 push_charp(obuf, 1, NBSP, PC_ASCII);
4492 push_str(obuf, symbol_width, tmp, PC_ASCII);
4493 push_charp(obuf, 1, NBSP, PC_ASCII);
4494 set_space_to_prevchar(obuf->prevchar);
4497 if (parsedtag_get_value(tag, ATTR_TYPE, &p))
4498 envs[h_env->envc].type = (int)*p;
4499 switch ((envs[h_env->envc].count > 0)? envs[h_env->envc].type: '1') {
4501 num = romanNumeral(envs[h_env->envc].count);
4504 num = romanNumeral(envs[h_env->envc].count);
4508 num = romanAlphabet(envs[h_env->envc].count);
4511 num = romanAlphabet(envs[h_env->envc].count);
4515 num = Sprintf("%d", envs[h_env->envc].count);
4518 if (INDENT_INCR >= 4)
4519 Strcat_charp(num, ". ");
4521 Strcat_char(num, '.');
4522 push_spaces(obuf, 1, INDENT_INCR - num->length);
4523 push_str(obuf, num->length, num, PC_ASCII);
4524 if (INDENT_INCR >= 4)
4525 set_space_to_prevchar(obuf->prevchar);
4528 push_spaces(obuf, 1, INDENT_INCR);
4533 flushline(h_env, obuf, 0, 0, h_env->limit);
4535 obuf->flag |= RB_IGNORE_P;
4539 if (h_env->envc == 0 ||
4540 (h_env->envc_real < h_env->nenv &&
4541 envs[h_env->envc].env != HTML_DL &&
4542 envs[h_env->envc].env != HTML_DL_COMPACT)) {
4545 if (h_env->envc > 0) {
4546 flushline(h_env, obuf,
4547 envs[h_env->envc - 1].indent, 0, h_env->limit);
4549 if (!(obuf->flag & RB_IN_DT)) {
4550 HTMLlineproc1("<b>", h_env);
4551 obuf->flag |= RB_IN_DT;
4553 obuf->flag |= RB_IGNORE_P;
4558 if (envs[h_env->envc].env == HTML_DL_COMPACT) {
4559 if (obuf->pos > envs[h_env->envc].indent)
4560 flushline(h_env, obuf, envs[h_env->envc].indent, 0,
4563 push_spaces(obuf, 1, envs[h_env->envc].indent - obuf->pos);
4566 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4567 /* obuf->flag |= RB_IGNORE_P; */
4570 close_anchor(h_env, obuf);
4572 obuf->flag |= RB_TITLE;
4573 obuf->end_tag = HTML_N_TITLE;
4576 if (!(obuf->flag & RB_TITLE))
4578 obuf->flag &= ~RB_TITLE;
4580 tmp = process_n_title(tag);
4582 HTMLlineproc1(tmp->ptr, h_env);
4584 case HTML_TITLE_ALT:
4585 if (parsedtag_get_value(tag, ATTR_TITLE, &p))
4586 h_env->title = html_unquote(p);
4590 push_charp(obuf, 9, "--FRAME--", PC_ASCII);
4591 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4593 case HTML_N_FRAMESET:
4594 if (h_env->envc > 0) {
4596 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4601 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4602 obuf->flag |= (RB_NOFRAMES | RB_IGNORE_P);
4605 case HTML_N_NOFRAMES:
4607 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4608 obuf->flag &= ~RB_NOFRAMES;
4612 parsedtag_get_value(tag, ATTR_SRC, &q);
4613 parsedtag_get_value(tag, ATTR_NAME, &r);
4616 push_tag(obuf, Sprintf("<a hseq=\"%d\" href=\"%s\">",
4617 cur_hseq++, q)->ptr, HTML_A);
4620 push_charp(obuf, get_strwidth(q), q, PC_ASCII);
4621 push_tag(obuf, "</a>", HTML_N_A);
4623 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4626 close_anchor(h_env, obuf);
4627 tmp = process_hr(tag, h_env->limit, envs[h_env->envc].indent);
4628 HTMLlineproc1(tmp->ptr, h_env);
4629 set_space_to_prevchar(obuf->prevchar);
4632 x = parsedtag_exists(tag, ATTR_FOR_TABLE);
4634 if (!(obuf->flag & RB_IGNORE_P)) {
4635 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4637 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
4641 fillline(obuf, envs[h_env->envc].indent);
4642 obuf->flag |= (RB_PRE | RB_IGNORE_P);
4646 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4647 if (!(obuf->flag & RB_IGNORE_P)) {
4648 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
4650 obuf->flag |= RB_IGNORE_P;
4651 h_env->blank_lines++;
4653 obuf->flag &= ~RB_PRE;
4654 close_anchor(h_env, obuf);
4657 i = obuf->line->length;
4659 if (!(obuf->flag & RB_SPECIAL)) {
4660 set_breakpoint(obuf, obuf->line->length - i);
4662 obuf->flag |= RB_PRE_INT;
4664 case HTML_N_PRE_INT:
4665 push_tag(obuf, "</pre_int>", HTML_N_PRE_INT);
4666 obuf->flag &= ~RB_PRE_INT;
4667 if (!(obuf->flag & RB_SPECIAL) && obuf->pos > obuf->bp.pos) {
4668 set_prevchar(obuf->prevchar, "", 0);
4669 obuf->prev_ctype = PC_CTRL;
4673 obuf->flag |= RB_NOBR;
4677 if (obuf->nobr_level > 0)
4679 if (obuf->nobr_level == 0)
4680 obuf->flag &= ~RB_NOBR;
4682 case HTML_PRE_PLAIN:
4684 if (!(obuf->flag & RB_IGNORE_P)) {
4685 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4686 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
4689 obuf->flag |= (RB_PRE | RB_IGNORE_P);
4691 case HTML_N_PRE_PLAIN:
4693 if (!(obuf->flag & RB_IGNORE_P)) {
4694 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4695 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
4697 obuf->flag |= RB_IGNORE_P;
4699 obuf->flag &= ~RB_PRE;
4703 case HTML_PLAINTEXT:
4705 if (!(obuf->flag & RB_IGNORE_P)) {
4706 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4707 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
4710 obuf->flag |= (RB_PLAIN | RB_IGNORE_P);
4713 obuf->end_tag = HTML_N_LISTING;
4716 obuf->end_tag = HTML_N_XMP;
4718 case HTML_PLAINTEXT:
4719 obuf->end_tag = MAX_HTMLTAG;
4723 case HTML_N_LISTING:
4726 if (!(obuf->flag & RB_IGNORE_P)) {
4727 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4728 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
4730 obuf->flag |= RB_IGNORE_P;
4732 obuf->flag &= ~RB_PLAIN;
4736 obuf->flag |= RB_SCRIPT;
4737 obuf->end_tag = HTML_N_SCRIPT;
4740 obuf->flag |= RB_STYLE;
4741 obuf->end_tag = HTML_N_STYLE;
4744 obuf->flag &= ~RB_SCRIPT;
4748 obuf->flag &= ~RB_STYLE;
4752 if (obuf->anchor.url)
4753 close_anchor(h_env, obuf);
4757 if (parsedtag_get_value(tag, ATTR_HREF, &p))
4758 obuf->anchor.url = Strnew_charp(p)->ptr;
4759 if (parsedtag_get_value(tag, ATTR_TARGET, &p))
4760 obuf->anchor.target = Strnew_charp(p)->ptr;
4761 if (parsedtag_get_value(tag, ATTR_REFERER, &p))
4762 obuf->anchor.referer = Strnew_charp(p)->ptr;
4763 if (parsedtag_get_value(tag, ATTR_TITLE, &p))
4764 obuf->anchor.title = Strnew_charp(p)->ptr;
4765 if (parsedtag_get_value(tag, ATTR_ACCESSKEY, &p))
4766 obuf->anchor.accesskey = (unsigned char)*p;
4767 if (parsedtag_get_value(tag, ATTR_HSEQ, &hseq))
4768 obuf->anchor.hseq = hseq;
4770 if (hseq == 0 && obuf->anchor.url) {
4771 obuf->anchor.hseq = cur_hseq;
4772 tmp = process_anchor(tag, h_env->tagbuf->ptr);
4773 push_tag(obuf, tmp->ptr, HTML_A);
4778 close_anchor(h_env, obuf);
4781 tmp = process_img(tag, h_env->limit);
4782 HTMLlineproc1(tmp->ptr, h_env);
4785 if (parsedtag_get_value(tag, ATTR_SRC, &p))
4786 obuf->img_alt = Strnew_charp(p);
4789 if (parsedtag_get_value(tag, ATTR_TOP_MARGIN, &i)) {
4790 if (i > obuf->top_margin)
4791 obuf->top_margin = i;
4794 if (parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &i)) {
4795 if (i > obuf->bottom_margin)
4796 obuf->bottom_margin = i;
4800 case HTML_N_IMG_ALT:
4801 if (obuf->img_alt) {
4802 if (!close_effect0(obuf, HTML_IMG_ALT))
4803 push_tag(obuf, "</img_alt>", HTML_N_IMG_ALT);
4804 obuf->img_alt = NULL;
4807 case HTML_INPUT_ALT:
4809 if (parsedtag_get_value(tag, ATTR_TOP_MARGIN, &i)) {
4810 if (i > obuf->top_margin)
4811 obuf->top_margin = i;
4814 if (parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &i)) {
4815 if (i > obuf->bottom_margin)
4816 obuf->bottom_margin = i;
4820 close_anchor(h_env, obuf);
4821 obuf->table_level++;
4822 if (obuf->table_level >= MAX_TABLE)
4825 /* x: cellspacing, y: cellpadding */
4830 if (parsedtag_exists(tag, ATTR_BORDER)) {
4831 if (parsedtag_get_value(tag, ATTR_BORDER, &w)) {
4834 else if (w < 0) { /* weird */
4841 if (parsedtag_get_value(tag, ATTR_WIDTH, &i)) {
4842 if (obuf->table_level == 0)
4843 width = REAL_WIDTH(i, h_env->limit - envs[h_env->envc].indent);
4845 width = RELATIVE_WIDTH(i);
4847 if (parsedtag_exists(tag, ATTR_HBORDER))
4849 parsedtag_get_value(tag, ATTR_CELLSPACING, &x);
4850 parsedtag_get_value(tag, ATTR_CELLPADDING, &y);
4851 parsedtag_get_value(tag, ATTR_VSPACE, &z);
4853 parsedtag_get_value(tag, ATTR_ID, &id);
4855 tables[obuf->table_level] = begin_table(w, x, y, z);
4858 tables[obuf->table_level]->id = Strnew_charp(id);
4860 table_mode[obuf->table_level].pre_mode = 0;
4861 table_mode[obuf->table_level].indent_level = 0;
4862 table_mode[obuf->table_level].nobr_level = 0;
4863 table_mode[obuf->table_level].caption = 0;
4864 table_mode[obuf->table_level].end_tag = 0; /* HTML_UNKNOWN */
4865 #ifndef TABLE_EXPAND
4866 tables[obuf->table_level]->total_width = width;
4868 tables[obuf->table_level]->real_width = width;
4869 tables[obuf->table_level]->total_width = 0;
4873 /* should be processed in HTMLlineproc() */
4877 if (!(obuf->flag & (RB_PREMODE | RB_IGNORE_P)))
4878 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4880 RB_SET_ALIGN(obuf, RB_CENTER);
4884 if (!(obuf->flag & RB_PREMODE))
4885 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4886 RB_RESTORE_FLAG(obuf);
4890 if (!(obuf->flag & RB_IGNORE_P))
4891 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4892 set_alignment(obuf, tag);
4896 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4897 RB_RESTORE_FLAG(obuf);
4901 if (!(obuf->flag & RB_IGNORE_P))
4902 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4903 set_alignment(obuf, tag);
4905 case HTML_N_DIV_INT:
4907 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4908 RB_RESTORE_FLAG(obuf);
4912 if (!(obuf->flag & RB_IGNORE_P))
4913 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4914 tmp = process_form(tag);
4916 HTMLlineproc1(tmp->ptr, h_env);
4920 flushline(h_env, obuf, envs[h_env->envc].indent, 0, h_env->limit);
4921 obuf->flag |= RB_IGNORE_P;
4925 close_anchor(h_env, obuf);
4926 tmp = process_input(tag);
4928 HTMLlineproc1(tmp->ptr, h_env);
4931 close_anchor(h_env, obuf);
4932 tmp = process_select(tag);
4934 HTMLlineproc1(tmp->ptr, h_env);
4935 obuf->flag |= RB_INSELECT;
4936 obuf->end_tag = HTML_N_SELECT;
4939 obuf->flag &= ~RB_INSELECT;
4941 tmp = process_n_select();
4943 HTMLlineproc1(tmp->ptr, h_env);
4949 close_anchor(h_env, obuf);
4950 tmp = process_textarea(tag, h_env->limit);
4952 HTMLlineproc1(tmp->ptr, h_env);
4953 obuf->flag |= RB_INTXTA;
4954 obuf->end_tag = HTML_N_TEXTAREA;
4956 case HTML_N_TEXTAREA:
4957 obuf->flag &= ~RB_INTXTA;
4959 tmp = process_n_textarea();
4961 HTMLlineproc1(tmp->ptr, h_env);
4965 q = "!CURRENT_URL!";
4966 parsedtag_get_value(tag, ATTR_PROMPT, &p);
4967 parsedtag_get_value(tag, ATTR_ACTION, &q);
4968 tmp = Strnew_m_charp("<form method=get action=\"",
4972 "<input type=text name=\"\" accept></form>",
4974 HTMLlineproc1(tmp->ptr, h_env);
4978 parsedtag_get_value(tag, ATTR_HTTP_EQUIV, &p);
4979 parsedtag_get_value(tag, ATTR_CONTENT, &q);
4981 if (p && q && !strcasecmp(p, "Content-Type") &&
4982 (q = strcasestr(q, "charset")) != NULL) {
4988 meta_charset = wc_guess_charset(q, 0);
4993 if (p && q && !strcasecmp(p, "refresh")) {
4994 int refresh_interval;
4996 refresh_interval = getMetaRefreshParam(q, &tmp);
4998 q = html_quote(tmp->ptr);
4999 tmp = Sprintf("Refresh (%d sec) <a href=\"%s\">%s</a>",
5000 refresh_interval, q, q);
5002 else if (refresh_interval > 0)
5003 tmp = Sprintf("Refresh (%d sec)", refresh_interval);
5005 HTMLlineproc1(tmp->ptr, h_env);
5006 do_blankline(h_env, obuf, envs[h_env->envc].indent, 0,
5008 if (!is_redisplay &&
5009 !((obuf->flag & RB_NOFRAMES) && RenderFrame)) {
5010 tag->need_reconstruct = TRUE;
5019 if (parsedtag_get_value(tag, ATTR_HREF, &p)) {
5021 cur_baseURL = New(ParsedURL);
5022 parseURL(p, cur_baseURL, NULL);
5030 switch (displayInsDel) {
5031 case DISPLAY_INS_DEL_SIMPLE:
5032 obuf->flag |= RB_DEL;
5034 case DISPLAY_INS_DEL_NORMAL:
5035 HTMLlineproc1("<U>[DEL:</U>", h_env);
5037 case DISPLAY_INS_DEL_FONTIFY:
5039 if (obuf->in_strike == 1) {
5040 push_tag(obuf, "<s>", HTML_S);
5046 switch (displayInsDel) {
5047 case DISPLAY_INS_DEL_SIMPLE:
5048 obuf->flag &= ~RB_DEL;
5050 case DISPLAY_INS_DEL_NORMAL:
5051 HTMLlineproc1("<U>:DEL]</U>", h_env);
5052 case DISPLAY_INS_DEL_FONTIFY:
5053 if (obuf->in_strike == 0)
5055 if (obuf->in_strike == 1 && close_effect0(obuf, HTML_S))
5056 obuf->in_strike = 0;
5057 if (obuf->in_strike > 0) {
5059 if (obuf->in_strike == 0) {
5060 push_tag(obuf, "</s>", HTML_N_S);
5067 switch (displayInsDel) {
5068 case DISPLAY_INS_DEL_SIMPLE:
5071 case DISPLAY_INS_DEL_NORMAL:
5072 HTMLlineproc1("<U>[S:</U>", h_env);
5074 case DISPLAY_INS_DEL_FONTIFY:
5076 if (obuf->in_strike == 1) {
5077 push_tag(obuf, "<s>", HTML_S);
5083 switch (displayInsDel) {
5084 case DISPLAY_INS_DEL_SIMPLE:
5085 obuf->flag &= ~RB_S;
5087 case DISPLAY_INS_DEL_NORMAL:
5088 HTMLlineproc1("<U>:S]</U>", h_env);
5090 case DISPLAY_INS_DEL_FONTIFY:
5091 if (obuf->in_strike == 0)
5093 if (obuf->in_strike == 1 && close_effect0(obuf, HTML_S))
5094 obuf->in_strike = 0;
5095 if (obuf->in_strike > 0) {
5097 if (obuf->in_strike == 0) {
5098 push_tag(obuf, "</s>", HTML_N_S);
5104 switch (displayInsDel) {
5105 case DISPLAY_INS_DEL_SIMPLE:
5107 case DISPLAY_INS_DEL_NORMAL:
5108 HTMLlineproc1("<U>[INS:</U>", h_env);
5110 case DISPLAY_INS_DEL_FONTIFY:
5112 if (obuf->in_ins == 1) {
5113 push_tag(obuf, "<ins>", HTML_INS);
5119 switch (displayInsDel) {
5120 case DISPLAY_INS_DEL_SIMPLE:
5122 case DISPLAY_INS_DEL_NORMAL:
5123 HTMLlineproc1("<U>:INS]</U>", h_env);
5125 case DISPLAY_INS_DEL_FONTIFY:
5126 if (obuf->in_ins == 0)
5128 if (obuf->in_ins == 1 && close_effect0(obuf, HTML_INS))
5130 if (obuf->in_ins > 0) {
5132 if (obuf->in_ins == 0) {
5133 push_tag(obuf, "</ins>", HTML_N_INS);
5140 if (!(obuf->flag & (RB_DEL | RB_S)))
5141 HTMLlineproc1("^", h_env);
5146 if (!(obuf->flag & (RB_DEL | RB_S)))
5147 HTMLlineproc1("[", h_env);
5150 if (!(obuf->flag & (RB_DEL | RB_S)))
5151 HTMLlineproc1("]", h_env);
5158 if (view_unseenobject) {
5159 if (parsedtag_get_value(tag, ATTR_SRC, &p)) {
5162 s = Sprintf("<A HREF=\"%s\">bgsound(%s)</A>", q, q);
5163 HTMLlineproc1(s->ptr, h_env);
5168 if (view_unseenobject) {
5169 if (parsedtag_get_value(tag, ATTR_SRC, &p)) {
5172 s = Sprintf("<A HREF=\"%s\">embed(%s)</A>", q, q);
5173 HTMLlineproc1(s->ptr, h_env);
5178 if (view_unseenobject) {
5179 if (parsedtag_get_value(tag, ATTR_ARCHIVE, &p)) {
5182 s = Sprintf("<A HREF=\"%s\">applet archive(%s)</A>", q, q);
5183 HTMLlineproc1(s->ptr, h_env);
5188 if (view_unseenobject) {
5189 if (parsedtag_get_value(tag, ATTR_BACKGROUND, &p)) {
5192 s = Sprintf("<IMG SRC=\"%s\" ALT=\"bg image(%s)\"><BR>", q, q);
5193 HTMLlineproc1(s->ptr, h_env);
5197 if (obuf->flag & RB_TITLE)
5198 HTMLlineproc1("</title>", h_env);
5203 /* obuf->prevchar = '\0'; */
5210 #define PPUSH(p,c) {outp[pos]=(p);outc[pos]=(c);pos++;}
5212 if (out_size <= pos + 1) { \
5213 out_size = pos * 3 / 2; \
5214 outc = New_Reuse(char, outc, out_size); \
5215 outp = New_Reuse(Lineprop, outp, out_size); \
5218 static TextLineListItem *_tl_lp2;
5224 if (_tl_lp2 != NULL) {
5226 _tl_lp2 = _tl_lp2->next;
5239 if (ex & PE_EX_ITALIC)
5240 effect |= PE_EX_ITALIC_E;
5242 if (ex & PE_EX_INSERT)
5243 effect |= PE_EX_INSERT_E;
5245 if (ex & PE_EX_STRIKE)
5246 effect |= PE_EX_STRIKE_E;
5252 HTMLlineproc2body(Buffer *buf, Str (*feed) (), int llimit)
5254 static char *outc = NULL;
5255 static Lineprop *outp = NULL;
5256 static int out_size = 0;
5257 Anchor *a_href = NULL, *a_img = NULL, *a_form = NULL;
5258 char *p, *q, *r, *s, *t, *str;
5259 Lineprop mode, effect, ex_effect;
5265 struct frameset *frameset_s[FRAMESTACK_SIZE];
5266 int frameset_sp = -1;
5267 union frameset_element *idFrame = NULL;
5274 Anchor **a_textarea = NULL;
5276 Anchor **a_select = NULL;
5279 if (out_size == 0) {
5281 outc = NewAtom_N(char, out_size);
5282 outp = NewAtom_N(Lineprop, out_size);
5286 if (!max_textarea) { /* halfload */
5287 max_textarea = MAX_TEXTAREA;
5288 textarea_str = New_N(Str, max_textarea);
5289 a_textarea = New_N(Anchor *, max_textarea);
5293 if (!max_select) { /* halfload */
5294 max_select = MAX_SELECT;
5295 select_option = New_N(FormSelectOption, max_select);
5296 a_select = New_N(Anchor *, max_select);
5302 debug = fopen("zzzerr", "a");
5308 while ((line = feed()) != NULL) {
5311 Strfputs(line, debug);
5315 if (n_textarea >= 0 && *(line->ptr) != '<') { /* halfload */
5316 Strcat(textarea_str[n_textarea], line);
5320 if (++nlines == llimit)
5323 #ifdef ENABLE_REMOVE_TRAILINGSPACES
5324 Strremovetrailingspaces(line);
5327 endp = str + line->length;
5328 while (str < endp) {
5330 mode = get_mctype(str);
5331 if ((effect | ex_efct(ex_effect)) & PC_SYMBOL && *str != '<') {
5333 char **buf = set_symbol(symbol_width0);
5336 p = buf[(int)symbol];
5338 mode = get_mctype(p);
5339 PPUSH(mode | effect | ex_efct(ex_effect), *(p++));
5341 mode = (mode & ~PC_WCHAR1) | PC_WCHAR2;
5344 PPUSH(mode | effect | ex_efct(ex_effect), *(p++));
5348 PPUSH(PC_ASCII | effect | ex_efct(ex_effect), SYMBOL_BASE + symbol);
5350 str += symbol_width;
5353 else if (mode == PC_CTRL || mode == PC_UNDEF) {
5355 else if (mode == PC_CTRL || IS_INTSPACE(*str)) {
5357 PPUSH(PC_ASCII | effect | ex_efct(ex_effect), ' ');
5361 else if (mode & PC_UNKNOWN) {
5362 PPUSH(PC_ASCII | effect | ex_efct(ex_effect), ' ');
5363 str += get_mclen(str);
5366 else if (*str != '<' && *str != '&') {
5368 int len = get_mclen(str);
5370 PPUSH(mode | effect | ex_efct(ex_effect), *(str++));
5373 mode = (mode & ~PC_WCHAR1) | PC_WCHAR2;
5376 PPUSH(mode | effect | ex_efct(ex_effect), *(str++));
5381 else if (*str == '&') {
5383 * & escape processing
5385 p = getescapecmd(&str);
5388 mode = get_mctype((unsigned char *)p);
5390 if (mode == PC_CTRL || mode == PC_UNDEF) {
5392 if (mode == PC_CTRL || IS_INTSPACE(*str)) {
5394 PPUSH(PC_ASCII | effect | ex_efct(ex_effect), ' ');
5398 else if (mode & PC_UNKNOWN) {
5399 PPUSH(PC_ASCII | effect | ex_efct(ex_effect), ' ');
5405 int len = get_mclen(p);
5407 PPUSH(mode | effect | ex_efct(ex_effect), *(p++));
5410 mode = (mode & ~PC_WCHAR1) | PC_WCHAR2;
5413 PPUSH(mode | effect | ex_efct(ex_effect), *(p++));
5421 /* tag processing */
5422 struct parsed_tag *tag;
5423 if (!(tag = parse_tag(&str, TRUE)))
5425 switch (tag->tagid) {
5433 ex_effect |= PE_EX_ITALIC;
5436 ex_effect &= ~PE_EX_ITALIC;
5439 ex_effect |= PE_EX_INSERT;
5442 ex_effect &= ~PE_EX_INSERT;
5448 effect &= ~PE_UNDER;
5451 ex_effect |= PE_EX_STRIKE;
5454 ex_effect &= ~PE_EX_STRIKE;
5457 if (renderFrameSet &&
5458 parsedtag_get_value(tag, ATTR_FRAMENAME, &p)) {
5459 p = url_quote_conv(p, buf->document_charset);
5460 if (!idFrame || strcmp(idFrame->body->name, p)) {
5461 idFrame = search_frame(renderFrameSet, p);
5462 if (idFrame && idFrame->body->attr != F_BODY)
5467 q = buf->baseTarget;
5471 if (parsedtag_get_value(tag, ATTR_NAME, &id)) {
5472 id = url_quote_conv(id, buf->document_charset);
5473 registerName(buf, id, currentLn(buf), pos);
5475 if (parsedtag_get_value(tag, ATTR_HREF, &p))
5476 p = url_quote_conv(remove_space(p),
5477 buf->document_charset);
5478 if (parsedtag_get_value(tag, ATTR_TARGET, &q))
5479 q = url_quote_conv(q, buf->document_charset);
5480 if (parsedtag_get_value(tag, ATTR_REFERER, &r))
5481 r = url_quote_conv(r, buf->document_charset);
5482 parsedtag_get_value(tag, ATTR_TITLE, &s);
5483 parsedtag_get_value(tag, ATTR_ACCESSKEY, &t);
5484 parsedtag_get_value(tag, ATTR_HSEQ, &hseq);
5487 putHmarker(buf->hmarklist, currentLn(buf),
5489 else if (hseq < 0) {
5491 if (buf->hmarklist &&
5492 h < buf->hmarklist->nmark &&
5493 buf->hmarklist->marks[h].invalid) {
5494 buf->hmarklist->marks[h].pos = pos;
5495 buf->hmarklist->marks[h].line = currentLn(buf);
5496 buf->hmarklist->marks[h].invalid = 0;
5501 idFrame->body->nameList =
5502 putAnchor(idFrame->body->nameList, id, NULL,
5503 (Anchor **)NULL, NULL, NULL, '\0',
5504 currentLn(buf), pos);
5506 effect |= PE_ANCHOR;
5507 a_href = registerHref(buf, p, q, r, s,
5508 *t, currentLn(buf), pos);
5509 a_href->hseq = ((hseq > 0) ? hseq : -hseq) - 1;
5510 a_href->slave = (hseq > 0) ? FALSE : TRUE;
5514 effect &= ~PE_ANCHOR;
5516 a_href->end.line = currentLn(buf);
5517 a_href->end.pos = pos;
5518 if (a_href->start.line == a_href->end.line &&
5519 a_href->start.pos == a_href->end.pos) {
5520 if (buf->hmarklist &&
5521 a_href->hseq < buf->hmarklist->nmark)
5522 buf->hmarklist->marks[a_href->hseq].invalid = 1;
5534 if (parsedtag_get_value(tag, ATTR_SRC, &p)) {
5536 int w = -1, h = -1, iseq = 0, ismap = 0;
5537 int xoffset = 0, yoffset = 0, top = 0, bottom = 0;
5538 parsedtag_get_value(tag, ATTR_HSEQ, &iseq);
5539 parsedtag_get_value(tag, ATTR_WIDTH, &w);
5540 parsedtag_get_value(tag, ATTR_HEIGHT, &h);
5541 parsedtag_get_value(tag, ATTR_XOFFSET, &xoffset);
5542 parsedtag_get_value(tag, ATTR_YOFFSET, &yoffset);
5543 parsedtag_get_value(tag, ATTR_TOP_MARGIN, &top);
5544 parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &bottom);
5545 if (parsedtag_exists(tag, ATTR_ISMAP))
5548 parsedtag_get_value(tag, ATTR_USEMAP, &q);
5550 buf->imarklist = putHmarker(buf->imarklist,
5551 currentLn(buf), pos,
5556 parsedtag_get_value(tag, ATTR_TITLE, &s);
5557 p = url_quote_conv(remove_space(p),
5558 buf->document_charset);
5559 a_img = registerImg(buf, p, s, currentLn(buf), pos);
5562 a_img->image = NULL;
5567 parseURL2(a_img->url, &u, cur_baseURL);
5568 a_img->image = image = New(Image);
5569 image->url = parsedURL2Str(&u)->ptr;
5570 if (!uncompressed_file_type(u.file, &image->ext))
5571 image->ext = filename_extension(u.file, TRUE);
5572 image->cache = NULL;
5574 (w > MAX_IMAGE_SIZE) ? MAX_IMAGE_SIZE : w;
5576 (h > MAX_IMAGE_SIZE) ? MAX_IMAGE_SIZE : h;
5577 image->xoffset = xoffset;
5578 image->yoffset = yoffset;
5579 image->y = currentLn(buf) - top;
5580 if (image->xoffset < 0 && pos == 0)
5582 if (image->yoffset < 0 && image->y == 1)
5584 image->rows = 1 + top + bottom;
5586 image->ismap = ismap;
5588 image->cache = getImage(image, cur_baseURL,
5591 else if (iseq < 0) {
5592 BufferPoint *po = buf->imarklist->marks - iseq - 1;
5593 Anchor *a = retrieveAnchor(buf->img,
5596 a_img->url = a->url;
5597 a_img->image = a->image;
5604 case HTML_N_IMG_ALT:
5605 effect &= ~PE_IMAGE;
5607 a_img->end.line = currentLn(buf);
5608 a_img->end.pos = pos;
5612 case HTML_INPUT_ALT:
5615 int top = 0, bottom = 0;
5616 int textareanumber = -1;
5618 int selectnumber = -1;
5623 parsedtag_get_value(tag, ATTR_HSEQ, &hseq);
5624 parsedtag_get_value(tag, ATTR_FID, &form_id);
5625 parsedtag_get_value(tag, ATTR_TOP_MARGIN, &top);
5626 parsedtag_get_value(tag, ATTR_BOTTOM_MARGIN, &bottom);
5627 if (form_id < 0 || form_id > form_max || forms == NULL)
5628 break; /* outside of <form>..</form> */
5629 form = forms[form_id];
5635 putHmarker(buf->hmarklist, currentLn(buf),
5639 form->target = buf->baseTarget;
5641 parsedtag_get_value(tag, ATTR_TEXTAREANUMBER,
5643 if (textareanumber >= max_textarea) {
5644 max_textarea = 2 * textareanumber;
5645 textarea_str = New_Reuse(Str, textarea_str,
5647 a_textarea = New_Reuse(Anchor *, a_textarea,
5653 parsedtag_get_value(tag, ATTR_SELECTNUMBER,
5655 if (selectnumber >= max_select) {
5656 max_select = 2 * selectnumber;
5657 select_option = New_Reuse(FormSelectOption,
5660 a_select = New_Reuse(Anchor *, a_select,
5666 registerForm(buf, form, tag, currentLn(buf), pos);
5667 if (a_textarea && textareanumber >= 0)
5668 a_textarea[textareanumber] = a_form;
5670 if (a_select && selectnumber >= 0)
5671 a_select[selectnumber] = a_form;
5674 a_form->hseq = hseq - 1;
5675 a_form->y = currentLn(buf) - top;
5676 a_form->rows = 1 + top + bottom;
5677 if (!parsedtag_exists(tag, ATTR_NO_EFFECT))
5682 case HTML_N_INPUT_ALT:
5685 a_form->end.line = currentLn(buf);
5686 a_form->end.pos = pos;
5687 if (a_form->start.line == a_form->end.line &&
5688 a_form->start.pos == a_form->end.pos)
5694 if (parsedtag_get_value(tag, ATTR_NAME, &p)) {
5695 MapList *m = New(MapList);
5696 m->name = Strnew_charp(p);
5697 m->area = newGeneralList();
5698 m->next = buf->maplist;
5706 if (buf->maplist == NULL) /* outside of <map>..</map> */
5708 if (parsedtag_get_value(tag, ATTR_HREF, &p)) {
5710 p = url_quote_conv(remove_space(p),
5711 buf->document_charset);
5713 parsedtag_get_value(tag, ATTR_TARGET, &t);
5715 parsedtag_get_value(tag, ATTR_ALT, &q);
5719 parsedtag_get_value(tag, ATTR_SHAPE, &r);
5720 parsedtag_get_value(tag, ATTR_COORDS, &s);
5722 a = newMapArea(p, t, q, r, s);
5723 pushValue(buf->maplist->area, (void *)a);
5728 if (frameset_sp >= FRAMESTACK_SIZE)
5730 frameset_s[frameset_sp] = newFrameSet(tag);
5731 if (frameset_s[frameset_sp] == NULL)
5733 if (frameset_sp == 0) {
5734 if (buf->frameset == NULL) {
5735 buf->frameset = frameset_s[frameset_sp];
5738 pushFrameTree(&(buf->frameQ),
5739 frameset_s[frameset_sp], NULL);
5742 addFrameSetElement(frameset_s[frameset_sp - 1],
5743 *(union frameset_element *)
5744 &frameset_s[frameset_sp]);
5746 case HTML_N_FRAMESET:
5747 if (frameset_sp >= 0)
5751 if (frameset_sp >= 0 && frameset_sp < FRAMESTACK_SIZE) {
5752 union frameset_element element;
5754 element.body = newFrame(tag, buf);
5755 addFrameSetElement(frameset_s[frameset_sp], element);
5759 if (parsedtag_get_value(tag, ATTR_HREF, &p)) {
5760 p = url_quote_conv(remove_space(p),
5761 buf->document_charset);
5763 buf->baseURL = New(ParsedURL);
5764 parseURL(p, buf->baseURL, NULL);
5766 if (parsedtag_get_value(tag, ATTR_TARGET, &p))
5768 url_quote_conv(p, buf->document_charset);
5772 parsedtag_get_value(tag, ATTR_HTTP_EQUIV, &p);
5773 parsedtag_get_value(tag, ATTR_CONTENT, &q);
5774 if (p && q && !strcasecmp(p, "refresh") && MetaRefresh) {
5776 int refresh_interval = getMetaRefreshParam(q, &tmp);
5779 p = url_quote_conv(remove_space(tmp->ptr),
5780 buf->document_charset);
5781 buf->event = setAlarmEvent(buf->event,
5784 FUNCNAME_gorURL, p);
5786 else if (refresh_interval > 0)
5787 buf->event = setAlarmEvent(buf->event,
5790 FUNCNAME_reload, NULL);
5792 if (tmp && refresh_interval == 0) {
5793 p = url_quote_conv(remove_space(tmp->ptr),
5794 buf->document_charset);
5795 pushEvent(FUNCNAME_gorURL, p);
5801 internal = HTML_INTERNAL;
5803 case HTML_N_INTERNAL:
5804 internal = HTML_N_INTERNAL;
5807 if (parsedtag_get_value(tag, ATTR_FID, &form_id))
5808 process_form_int(tag, form_id);
5810 case HTML_TEXTAREA_INT:
5811 if (parsedtag_get_value(tag, ATTR_TEXTAREANUMBER,
5813 && n_textarea < max_textarea) {
5814 textarea_str[n_textarea] = Strnew();
5819 case HTML_N_TEXTAREA_INT:
5820 if (n_textarea >= 0) {
5821 FormItemList *item =
5822 (FormItemList *)a_textarea[n_textarea]->url;
5823 item->init_value = item->value =
5824 textarea_str[n_textarea];
5828 case HTML_SELECT_INT:
5829 if (parsedtag_get_value(tag, ATTR_SELECTNUMBER, &n_select)
5830 && n_select < max_select) {
5831 select_option[n_select].first = NULL;
5832 select_option[n_select].last = NULL;
5837 case HTML_N_SELECT_INT:
5838 if (n_select >= 0) {
5839 FormItemList *item =
5840 (FormItemList *)a_select[n_select]->url;
5841 item->select_option = select_option[n_select].first;
5842 chooseSelectOption(item, item->select_option);
5843 item->init_selected = item->selected;
5844 item->init_value = item->value;
5845 item->init_label = item->label;
5848 case HTML_OPTION_INT:
5849 if (n_select >= 0) {
5852 parsedtag_get_value(tag, ATTR_LABEL, &q);
5854 parsedtag_get_value(tag, ATTR_VALUE, &p);
5855 selected = parsedtag_exists(tag, ATTR_SELECTED);
5856 addSelectOption(&select_option[n_select],
5857 Strnew_charp(p), Strnew_charp(q),
5862 case HTML_TITLE_ALT:
5863 if (parsedtag_get_value(tag, ATTR_TITLE, &p))
5864 buf->buffername = html_unquote(p);
5867 effect |= PC_SYMBOL;
5868 if (parsedtag_get_value(tag, ATTR_TYPE, &p))
5869 symbol = (char)atoi(p);
5872 effect &= ~PC_SYMBOL;
5877 if (parsedtag_get_value(tag, ATTR_ID, &id)) {
5878 id = url_quote_conv(id, buf->document_charset);
5879 registerName(buf, id, currentLn(buf), pos);
5881 if (renderFrameSet &&
5882 parsedtag_get_value(tag, ATTR_FRAMENAME, &p)) {
5883 p = url_quote_conv(p, buf->document_charset);
5884 if (!idFrame || strcmp(idFrame->body->name, p)) {
5885 idFrame = search_frame(renderFrameSet, p);
5886 if (idFrame && idFrame->body->attr != F_BODY)
5891 idFrame->body->nameList =
5892 putAnchor(idFrame->body->nameList, id, NULL,
5893 (Anchor **)NULL, NULL, NULL, '\0',
5894 currentLn(buf), pos);
5898 /* end of processing for one line */
5900 addnewline(buf, outc, outp, NULL, pos, -1, nlines);
5901 if (internal == HTML_N_INTERNAL)
5904 line = Strsubstr(line, str - line->ptr, endp - str);
5912 for (form_id = 1; form_id <= form_max; form_id++)
5913 forms[form_id]->next = forms[form_id - 1];
5914 buf->formlist = (form_max >= 0) ? forms[form_max] : NULL;
5916 addMultirowsForm(buf, buf->formitem);
5918 addMultirowsImg(buf, buf->img);
5923 addLink(Buffer *buf, struct parsed_tag *tag)
5925 char *href = NULL, *title = NULL, *ctype = NULL, *rel = NULL, *rev = NULL;
5926 char type = LINK_TYPE_NONE;
5929 parsedtag_get_value(tag, ATTR_HREF, &href);
5931 href = url_quote_conv(remove_space(href), buf->document_charset);
5932 parsedtag_get_value(tag, ATTR_TITLE, &title);
5933 parsedtag_get_value(tag, ATTR_TYPE, &ctype);
5934 parsedtag_get_value(tag, ATTR_REL, &rel);
5936 /* forward link type */
5937 type = LINK_TYPE_REL;
5941 parsedtag_get_value(tag, ATTR_REV, &rev);
5943 /* reverse link type */
5944 type = LINK_TYPE_REV;
5955 if (buf->linklist) {
5957 for (i = buf->linklist; i->next; i = i->next) ;
5965 HTMLlineproc2(Buffer *buf, TextLineList *tl)
5967 _tl_lp2 = tl->first;
5968 HTMLlineproc2body(buf, textlist_feed, -1);
5971 static InputStream _file_lp2;
5977 s = StrISgets(_file_lp2);
5978 if (s->length == 0) {
5986 HTMLlineproc3(Buffer *buf, InputStream stream)
5989 HTMLlineproc2body(buf, file_feed, -1);
5993 proc_escape(struct readbuffer *obuf, char **str_return)
5995 char *str = *str_return, *estr;
5996 int ech = getescapechar(str_return);
5997 int width, n_add = *str_return - str;
5998 Lineprop mode = PC_ASCII;
6002 proc_mchar(obuf, obuf->flag & RB_SPECIAL, 1, str_return, PC_ASCII);
6005 mode = IS_CNTRL(ech) ? PC_CTRL : PC_ASCII;
6007 estr = conv_entity(ech);
6008 check_breakpoint(obuf, obuf->flag & RB_SPECIAL, estr);
6009 width = get_strwidth(estr);
6010 if (width == 1 && ech == (unsigned char)*estr &&
6011 ech != '&' && ech != '<' && ech != '>') {
6014 push_charp(obuf, width, estr, mode);
6017 push_nchars(obuf, width, str, n_add, mode);
6018 set_prevchar(obuf->prevchar, estr, strlen(estr));
6019 obuf->prev_ctype = mode;
6024 need_flushline(struct html_feed_environ *h_env, struct readbuffer *obuf,
6029 if (obuf->flag & RB_PRE_INT) {
6030 if (obuf->pos > h_env->limit)
6036 ch = Strlastchar(obuf->line);
6037 /* if (ch == ' ' && obuf->tag_sp > 0) */
6041 if (obuf->pos > h_env->limit)
6048 table_width(struct html_feed_environ *h_env, int table_level)
6051 if (table_level < 0)
6053 width = tables[table_level]->total_width;
6054 if (table_level > 0 || width > 0)
6056 return h_env->limit - h_env->envs[h_env->envc].indent;
6059 /* HTML processing first pass */
6061 HTMLlineproc0(char *line, struct html_feed_environ *h_env, int internal)
6065 struct readbuffer *obuf = h_env->obuf;
6067 struct parsed_tag *tag;
6069 struct table *tbl = NULL;
6070 struct table_mode *tbl_mode = NULL;
6073 int is_hangul, prev_is_hangul = 0;
6078 FILE *f = fopen("zzzproc1", "a");
6079 fprintf(f, "%c%c%c%c",
6080 (obuf->flag & RB_PREMODE) ? 'P' : ' ',
6081 (obuf->table_level >= 0) ? 'T' : ' ',
6082 (obuf->flag & RB_INTXTA) ? 'X' : ' ',
6083 (obuf->flag & (RB_SCRIPT | RB_STYLE)) ? 'S' : ' ');
6084 fprintf(f, "HTMLlineproc1(\"%s\",%d,%lx)\n", line, h_env->limit,
6085 (unsigned long)h_env);
6093 if (obuf->table_level >= 0) {
6094 int level = min(obuf->table_level, MAX_TABLE - 1);
6095 tbl = tables[level];
6096 tbl_mode = &table_mode[level];
6097 tbl_width = table_width(h_env, level);
6100 while (*line != '\0') {
6103 int pre_mode = (obuf->table_level >= 0) ? tbl_mode->pre_mode :
6105 int end_tag = (obuf->table_level >= 0) ? tbl_mode->end_tag :
6108 if (*line == '<' || obuf->status != R_ST_NORMAL) {
6112 if (obuf->status == R_ST_EOL)
6113 obuf->status = R_ST_NORMAL;
6115 read_token(h_env->tagbuf, &line, &obuf->status,
6116 pre_mode & RB_PREMODE, obuf->status != R_ST_NORMAL);
6117 if (obuf->status != R_ST_NORMAL)
6120 if (h_env->tagbuf->length == 0)
6122 str = h_env->tagbuf->ptr;
6124 if (str[1] && REALLY_THE_BEGINNING_OF_A_TAG(str))
6126 else if (!(pre_mode & (RB_PLAIN | RB_INTXTA | RB_INSELECT |
6127 RB_SCRIPT | RB_STYLE | RB_TITLE))) {
6128 line = Strnew_m_charp(str + 1, line, NULL)->ptr;
6134 read_token(tokbuf, &line, &obuf->status, pre_mode & RB_PREMODE, 0);
6135 if (obuf->status != R_ST_NORMAL) /* R_ST_AMP ? */
6136 obuf->status = R_ST_NORMAL;
6140 if (pre_mode & (RB_PLAIN | RB_INTXTA | RB_INSELECT | RB_SCRIPT |
6141 RB_STYLE | RB_TITLE)) {
6144 if ((tag = parse_tag(&p, internal))) {
6145 if (tag->tagid == end_tag ||
6146 (pre_mode & RB_INSELECT && tag->tagid == HTML_N_FORM)
6147 || (pre_mode & RB_TITLE
6148 && (tag->tagid == HTML_N_HEAD
6149 || tag->tagid == HTML_BODY)))
6154 if (pre_mode & RB_TITLE) {
6159 if (pre_mode & RB_INSELECT) {
6160 if (obuf->table_level >= 0)
6166 if (strncmp(str, "<!--", 4) && (p = strchr(str + 1, '<'))) {
6167 str = Strnew_charp_n(str, p - str)->ptr;
6168 line = Strnew_m_charp(p, line, NULL)->ptr;
6172 if (obuf->table_level >= 0)
6175 if (pre_mode & RB_INTXTA) {
6180 if (pre_mode & RB_SCRIPT)
6183 if (pre_mode & RB_STYLE)
6188 if (obuf->table_level >= 0) {
6190 * within table: in <table>..</table>, all input tokens
6191 * are fed to the table renderer, and then the renderer
6192 * makes HTML output.
6194 switch (feed_table(tbl, str, tbl_mode, tbl_width, internal)) {
6197 obuf->table_level--;
6198 if (obuf->table_level >= MAX_TABLE - 1)
6201 if (obuf->table_level >= 0) {
6202 struct table *tbl0 = tables[obuf->table_level];
6203 str = Sprintf("<table_alt tid=%d>", tbl0->ntable)->ptr;
6204 pushTable(tbl0, tbl);
6206 tbl_mode = &table_mode[obuf->table_level];
6207 tbl_width = table_width(h_env, obuf->table_level);
6208 feed_table(tbl, str, tbl_mode, tbl_width, TRUE);
6210 /* continue to the next */
6212 if (obuf->flag & RB_DEL)
6214 /* all tables have been read */
6215 if (tbl->vspace > 0 && !(obuf->flag & RB_IGNORE_P)) {
6216 int indent = h_env->envs[h_env->envc].indent;
6217 flushline(h_env, obuf, indent, 0, h_env->limit);
6218 do_blankline(h_env, obuf, indent, 0, h_env->limit);
6220 save_fonteffect(h_env, obuf);
6221 renderTable(tbl, tbl_width, h_env);
6222 restore_fonteffect(h_env, obuf);
6223 obuf->flag &= ~RB_IGNORE_P;
6224 if (tbl->vspace > 0) {
6225 int indent = h_env->envs[h_env->envc].indent;
6226 do_blankline(h_env, obuf, indent, 0, h_env->limit);
6227 obuf->flag |= RB_IGNORE_P;
6229 set_space_to_prevchar(obuf->prevchar);
6240 /*** Beginning of a new tag ***/
6241 if ((tag = parse_tag(&str, internal)))
6246 if (HTMLtagproc1(tag, h_env) == 0) {
6247 /* preserve the tag for second-stage processing */
6248 if (parsedtag_need_reconstruct(tag))
6249 h_env->tagbuf = parsedtag2str(tag);
6250 push_tag(obuf, h_env->tagbuf->ptr, cmd);
6254 process_idattr(obuf, cmd, tag);
6257 obuf->bp.init_flag = 1;
6258 clear_ignore_p_flag(cmd, obuf);
6259 if (cmd == HTML_TABLE)
6265 if (obuf->flag & (RB_DEL | RB_S))
6268 mode = get_mctype(str);
6269 delta = get_mcwidth(str);
6270 if (obuf->flag & (RB_SPECIAL & ~RB_NOBR)) {
6272 if (!(obuf->flag & RB_PLAIN) && (*str == '&')) {
6274 int ech = getescapechar(&p);
6275 if (ech == '\n' || ech == '\r') {
6279 else if (ech == '\t') {
6285 obuf->flag &= ~RB_IGNORE_P;
6288 if (obuf->flag & RB_IGNORE_P) {
6289 obuf->flag &= ~RB_IGNORE_P;
6292 if (obuf->flag & RB_PRE_INT)
6295 flushline(h_env, obuf, h_env->envs[h_env->envc].indent,
6298 else if (ch == '\t') {
6301 } while ((h_env->envs[h_env->envc].indent + obuf->pos)
6305 else if (obuf->flag & RB_PLAIN) {
6306 char *p = html_quote_char(*str);
6308 push_charp(obuf, 1, p, PC_ASCII);
6312 proc_mchar(obuf, 1, delta, &str, mode);
6317 proc_escape(obuf, &str);
6319 proc_mchar(obuf, 1, delta, &str, mode);
6321 if (obuf->flag & (RB_SPECIAL & ~RB_PRE_INT))
6325 if (!IS_SPACE(*str))
6326 obuf->flag &= ~RB_IGNORE_P;
6327 if ((mode == PC_ASCII || mode == PC_CTRL) && IS_SPACE(*str)) {
6328 if (*obuf->prevchar->ptr != ' ') {
6335 if (mode == PC_KANJI1)
6336 is_hangul = wtf_is_hangul((wc_uchar *) str);
6339 if (mode == PC_KANJI1 &&
6340 !is_hangul && !prev_is_hangul &&
6341 obuf->pos > h_env->envs[h_env->envc].indent &&
6342 Strlastchar(obuf->line) == ' ') {
6343 while (obuf->line->length >= 2 &&
6344 !strncmp(obuf->line->ptr + obuf->line->length -
6346 && obuf->pos >= h_env->envs[h_env->envc].indent) {
6347 Strshrink(obuf->line, 1);
6350 if (obuf->line->length >= 3 &&
6351 obuf->prev_ctype == PC_KANJI1 &&
6352 Strlastchar(obuf->line) == ' ' &&
6353 obuf->pos >= h_env->envs[h_env->envc].indent) {
6354 Strshrink(obuf->line, 1);
6358 prev_is_hangul = is_hangul;
6361 proc_escape(obuf, &str);
6363 proc_mchar(obuf, obuf->flag & RB_SPECIAL, delta, &str,
6367 if (need_flushline(h_env, obuf, mode)) {
6368 char *bp = obuf->line->ptr + obuf->bp.len;
6369 char *tp = bp - obuf->bp.tlen;
6372 if (tp > obuf->line->ptr && tp[-1] == ' ')
6375 indent = h_env->envs[h_env->envc].indent;
6376 if (obuf->bp.pos - i > indent) {
6379 line = Strnew_charp(bp);
6380 Strshrink(obuf->line, obuf->line->length - obuf->bp.len);
6382 if (obuf->pos - i > h_env->limit)
6383 obuf->flag |= RB_FILL;
6384 #endif /* FORMAT_NICE */
6385 back_to_breakpoint(obuf);
6386 flushline(h_env, obuf, indent, 0, h_env->limit);
6388 obuf->flag &= ~RB_FILL;
6389 #endif /* FORMAT_NICE */
6390 HTMLlineproc1(line->ptr, h_env);
6395 if (!(obuf->flag & (RB_SPECIAL | RB_INTXTA | RB_INSELECT))) {
6399 if (obuf->bp.pos == obuf->pos) {
6400 tp = &obuf->line->ptr[obuf->bp.len - obuf->bp.tlen];
6403 tp = &obuf->line->ptr[obuf->line->length];
6406 if (tp > obuf->line->ptr && tp[-1] == ' ')
6408 indent = h_env->envs[h_env->envc].indent;
6409 if (obuf->pos - i > h_env->limit) {
6411 obuf->flag |= RB_FILL;
6412 #endif /* FORMAT_NICE */
6413 flushline(h_env, obuf, indent, 0, h_env->limit);
6415 obuf->flag &= ~RB_FILL;
6416 #endif /* FORMAT_NICE */
6421 extern char *NullLine;
6422 extern Lineprop NullProp[];
6424 #ifndef USE_ANSI_COLOR
6425 #define addnewline2(a,b,c,d,e,f) _addnewline2(a,b,c,e,f)
6428 addnewline2(Buffer *buf, char *line, Lineprop *prop, Linecolor *color, int pos,
6436 #ifdef USE_ANSI_COLOR
6437 l->colorBuf = color;
6444 l->prev = buf->currentLine;
6445 if (buf->currentLine) {
6446 l->next = buf->currentLine->next;
6447 buf->currentLine->next = l;
6451 if (buf->lastLine == NULL || buf->lastLine == buf->currentLine)
6453 buf->currentLine = l;
6454 if (buf->firstLine == NULL)
6456 l->linenumber = ++buf->allLine;
6458 /* l->real_linenumber = l->linenumber; */
6459 l->real_linenumber = 0;
6462 l->real_linenumber = nlines;
6468 addnewline(Buffer *buf, char *line, Lineprop *prop, Linecolor *color, int pos,
6469 int width, int nlines)
6473 #ifdef USE_ANSI_COLOR
6477 int i, bpos, bwidth;
6480 s = allocStr(line, pos);
6481 p = NewAtom_N(Lineprop, pos);
6482 bcopy((void *)prop, (void *)p, pos * sizeof(Lineprop));
6488 #ifdef USE_ANSI_COLOR
6489 if (pos > 0 && color) {
6490 c = NewAtom_N(Linecolor, pos);
6491 bcopy((void *)color, (void *)c, pos * sizeof(Linecolor));
6497 addnewline2(buf, s, p, c, pos, nlines);
6498 if (pos <= 0 || width <= 0)
6503 l = buf->currentLine;
6506 i = columnLen(l, width);
6510 while (i < l->len && p[i] & PC_WCHAR2)
6515 l->width = COLPOS(l, l->len);
6522 #ifdef USE_ANSI_COLOR
6527 addnewline2(buf, s, p, c, pos, nlines);
6532 * loadHTMLBuffer: read file and make new buffer
6535 loadHTMLBuffer(URLFile *f, Buffer *newBuf)
6541 newBuf = newBuffer(INIT_BUFFER_WIDTH);
6542 if (newBuf->sourcefile == NULL &&
6543 (f->scheme != SCM_LOCAL || newBuf->mailcap)) {
6544 tmp = tmpfname(TMPF_SRC, ".html");
6545 src = fopen(tmp->ptr, "w");
6547 newBuf->sourcefile = tmp->ptr;
6550 loadHTMLstream(f, newBuf, src, newBuf->bufferprop & BP_FRAME);
6552 newBuf->topLine = newBuf->firstLine;
6553 newBuf->lastLine = newBuf->currentLine;
6554 newBuf->currentLine = newBuf->firstLine;
6556 formResetBuffer(newBuf, newBuf->formitem);
6563 static char *_size_unit[] = { "b", "kb", "Mb", "Gb", "Tb",
6564 "Pb", "Eb", "Zb", "Bb", "Yb", NULL
6568 convert_size(clen_t size, int usefloat)
6572 char **sizes = _size_unit;
6574 csize = (float)size;
6575 while (csize >= 999.495 && sizes[sizepos + 1]) {
6576 csize = csize / 1024.0;
6579 return Sprintf(usefloat ? "%.3g%s" : "%.0f%s",
6580 floor(csize * 100.0 + 0.5) / 100.0, sizes[sizepos])->ptr;
6584 convert_size2(clen_t size1, clen_t size2, int usefloat)
6586 char **sizes = _size_unit;
6587 float csize, factor = 1;
6590 csize = (float)((size1 > size2) ? size1 : size2);
6591 while (csize / factor >= 999.495 && sizes[sizepos + 1]) {
6595 return Sprintf(usefloat ? "%.3g/%.3g%s" : "%.0f/%.0f%s",
6596 floor(size1 / factor * 100.0 + 0.5) / 100.0,
6597 floor(size2 / factor * 100.0 + 0.5) / 100.0,
6598 sizes[sizepos])->ptr;
6602 showProgress(clen_t * linelen, clen_t * trbyte)
6604 int i, j, rate, duration, eta, pos;
6605 static time_t last_time, start_time;
6608 char *fmtrbyte, *fmrate;
6613 if (*linelen < 1024)
6615 if (current_content_length > 0) {
6621 start_time = cur_time;
6623 *trbyte += *linelen;
6625 if (cur_time == last_time)
6627 last_time = cur_time;
6629 ratio = 100.0 * (*trbyte) / current_content_length;
6630 fmtrbyte = convert_size2(*trbyte, current_content_length, 1);
6631 duration = cur_time - start_time;
6633 rate = *trbyte / duration;
6634 fmrate = convert_size(rate, 1);
6635 eta = rate ? (current_content_length - *trbyte) / rate : -1;
6636 messages = Sprintf("%11s %3.0f%% "
6638 "eta %02d:%02d:%02d ",
6641 eta / (60 * 60), (eta / 60) % 60, eta % 60);
6644 messages = Sprintf("%11s %3.0f%% ",
6647 addstr(messages->ptr);
6649 i = pos + (COLS - pos - 1) * (*trbyte) / current_content_length;
6650 move(LASTLINE, pos);
6653 for (j = pos + 1; j <= i; j++)
6656 /* no_clrtoeol(); */
6664 start_time = cur_time;
6666 *trbyte += *linelen;
6668 if (cur_time == last_time)
6670 last_time = cur_time;
6672 fmtrbyte = convert_size(*trbyte, 1);
6673 duration = cur_time - start_time;
6675 fmrate = convert_size(*trbyte / duration, 1);
6676 messages = Sprintf("%7s loaded %7s/s", fmtrbyte, fmrate);
6679 messages = Sprintf("%7s loaded", fmtrbyte);
6681 message(messages->ptr, 0, 0);
6687 init_henv(struct html_feed_environ *h_env, struct readbuffer *obuf,
6688 struct environment *envs, int nenv, TextLineList *buf,
6689 int limit, int indent)
6691 envs[0].indent = indent;
6693 obuf->line = Strnew();
6696 obuf->prevchar = Strnew_size(8);
6697 set_space_to_prevchar(obuf->prevchar);
6698 obuf->flag = RB_IGNORE_P;
6700 obuf->status = R_ST_NORMAL;
6701 obuf->table_level = -1;
6702 obuf->nobr_level = 0;
6703 bzero((void *)&obuf->anchor, sizeof(obuf->anchor));
6706 obuf->in_italic = 0;
6708 obuf->in_strike = 0;
6710 obuf->prev_ctype = PC_ASCII;
6712 obuf->fontstat_sp = 0;
6713 obuf->top_margin = 0;
6714 obuf->bottom_margin = 0;
6715 obuf->bp.init_flag = 1;
6716 set_breakpoint(obuf, 0);
6721 h_env->tagbuf = Strnew();
6722 h_env->limit = limit;
6723 h_env->maxlimit = 0;
6727 h_env->envc_real = 0;
6728 h_env->title = NULL;
6729 h_env->blank_lines = 0;
6733 completeHTMLstream(struct html_feed_environ *h_env, struct readbuffer *obuf)
6735 close_anchor(h_env, obuf);
6736 if (obuf->img_alt) {
6737 push_tag(obuf, "</img_alt>", HTML_N_IMG_ALT);
6738 obuf->img_alt = NULL;
6740 if (obuf->in_bold) {
6741 push_tag(obuf, "</b>", HTML_N_B);
6744 if (obuf->in_italic) {
6745 push_tag(obuf, "</i>", HTML_N_I);
6746 obuf->in_italic = 0;
6748 if (obuf->in_under) {
6749 push_tag(obuf, "</u>", HTML_N_U);
6752 if (obuf->in_strike) {
6753 push_tag(obuf, "</s>", HTML_N_S);
6754 obuf->in_strike = 0;
6757 push_tag(obuf, "</ins>", HTML_N_INS);
6760 if (obuf->flag & RB_INTXTA)
6761 HTMLlineproc1("</textarea>", h_env);
6762 /* for unbalanced select tag */
6763 if (obuf->flag & RB_INSELECT)
6764 HTMLlineproc1("</select>", h_env);
6765 if (obuf->flag & RB_TITLE)
6766 HTMLlineproc1("</title>", h_env);
6768 /* for unbalanced table tag */
6769 if (obuf->table_level >= MAX_TABLE)
6770 obuf->table_level = MAX_TABLE - 1;
6772 while (obuf->table_level >= 0) {
6773 table_mode[obuf->table_level].pre_mode
6774 &= ~(TBLM_SCRIPT | TBLM_STYLE | TBLM_PLAIN);
6775 HTMLlineproc1("</table>", h_env);
6780 print_internal_information(struct html_feed_environ *henv)
6784 TextLineList *tl = newTextLineList();
6786 s = Strnew_charp("<internal>");
6787 pushTextLine(tl, newTextLine(s, 0));
6789 s = Strnew_m_charp("<title_alt title=\"",
6790 html_quote(henv->title), "\">", NULL);
6791 pushTextLine(tl, newTextLine(s, 0));
6794 if (form_max >= 0) {
6796 for (i = 0; i <= form_max; i++) {
6798 s = Sprintf("<form_int fid=\"%d\" action=\"%s\" method=\"%s\"",
6799 i, html_quote(fp->action->ptr),
6800 (fp->method == FORM_METHOD_POST) ? "post"
6802 FORM_METHOD_INTERNAL) ? "internal" : "get"));
6804 Strcat(s, Sprintf(" target=\"%s\"", html_quote(fp->target)));
6805 if (fp->enctype == FORM_ENCTYPE_MULTIPART)
6806 Strcat_charp(s, " enctype=\"multipart/form-data\"");
6809 Strcat(s, Sprintf(" accept-charset=\"%s\"",
6810 html_quote(fp->charset)));
6812 Strcat_charp(s, ">");
6813 pushTextLine(tl, newTextLine(s, 0));
6819 FormSelectOptionItem *ip;
6820 for (i = 0; i < n_select; i++) {
6821 s = Sprintf("<select_int selectnumber=%d>", i);
6822 pushTextLine(tl, newTextLine(s, 0));
6823 for (ip = select_option[i].first; ip; ip = ip->next) {
6824 s = Sprintf("<option_int value=\"%s\" label=\"%s\"%s>",
6825 html_quote(ip->value ? ip->value->ptr :
6827 html_quote(ip->label->ptr),
6828 ip->checked ? " selected" : "");
6829 pushTextLine(tl, newTextLine(s, 0));
6831 s = Strnew_charp("</select_int>");
6832 pushTextLine(tl, newTextLine(s, 0));
6835 #endif /* MENU_SELECT */
6836 if (n_textarea > 0) {
6837 for (i = 0; i < n_textarea; i++) {
6838 s = Sprintf("<textarea_int textareanumber=%d>", i);
6839 pushTextLine(tl, newTextLine(s, 0));
6840 s = Strnew_charp(html_quote(textarea_str[i]->ptr));
6841 Strcat_charp(s, "</textarea_int>");
6842 pushTextLine(tl, newTextLine(s, 0));
6845 s = Strnew_charp("</internal>");
6846 pushTextLine(tl, newTextLine(s, 0));
6849 appendTextLineList(henv->buf, tl);
6851 TextLineListItem *p;
6852 for (p = tl->first; p; p = p->next)
6853 fprintf(henv->f, "%s\n", Str_conv_to_halfdump(p->ptr->line)->ptr);
6858 loadHTMLstream(URLFile *f, Buffer *newBuf, FILE * src, int internal)
6860 struct environment envs[MAX_ENV_LEVEL];
6863 Str lineBuf2 = Strnew();
6865 wc_ces charset = WC_CES_US_ASCII;
6866 wc_ces volatile doc_charset = DocumentCharset;
6868 struct html_feed_environ htmlenv1;
6869 struct readbuffer obuf;
6871 int volatile image_flag;
6873 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
6876 if (fmInitialized && graph_ok()) {
6877 symbol_width = symbol_width0 = 1;
6881 get_symbol(DisplayCharset, &symbol_width0);
6882 symbol_width = WcOption.use_wide ? symbol_width0 : 1;
6885 symbol_width = symbol_width0 = 1;
6890 cur_textarea = NULL;
6891 max_textarea = MAX_TEXTAREA;
6892 textarea_str = New_N(Str, max_textarea);
6895 max_select = MAX_SELECT;
6896 select_option = New_N(FormSelectOption, max_select);
6897 #endif /* MENU_SELECT */
6906 if (newBuf->image_flag)
6907 image_flag = newBuf->image_flag;
6908 else if (activeImage && displayImage && autoImage)
6909 image_flag = IMG_FLAG_AUTO;
6911 image_flag = IMG_FLAG_SKIP;
6912 if (newBuf->currentURL.file)
6913 cur_baseURL = baseURL(newBuf);
6917 newBuf->buffername = "---";
6919 newBuf->document_charset = InnerCharset;
6925 HTMLlineproc3(newBuf, f->stream);
6926 w3m_halfload = FALSE;
6930 init_henv(&htmlenv1, &obuf, envs, MAX_ENV_LEVEL, NULL, newBuf->width, 0);
6933 htmlenv1.f = stdout;
6935 htmlenv1.buf = newTextLineList();
6937 if (SETJMP(AbortLoading) != 0) {
6938 HTMLlineproc1("<br>Transfer Interrupted!<br>", &htmlenv1);
6944 if (newBuf != NULL) {
6945 if (newBuf->bufferprop & BP_FRAME)
6946 charset = InnerCharset;
6947 else if (newBuf->document_charset)
6948 charset = doc_charset = newBuf->document_charset;
6950 if (content_charset && UseContentCharset)
6951 doc_charset = content_charset;
6955 do_blankline(&htmlenv1, &obuf, 0, 0, htmlenv1.limit);
6956 obuf.flag = RB_IGNORE_P;
6958 if (IStype(f->stream) != IST_ENCODED)
6959 f->stream = newEncodedStream(f->stream, f->encoding);
6960 while ((lineBuf2 = StrmyUFgets(f))->length) {
6962 if (f->scheme == SCM_NEWS && lineBuf2->ptr[0] == '.') {
6963 Strshrinkfirst(lineBuf2, 1);
6964 if (lineBuf2->ptr[0] == '\n' || lineBuf2->ptr[0] == '\r' ||
6965 lineBuf2->ptr[0] == '\0') {
6967 * iseos(f->stream) = TRUE;
6972 #endif /* USE_NNTP */
6974 Strfputs(lineBuf2, src);
6975 linelen += lineBuf2->length;
6976 if (w3m_dump & DUMP_EXTRA)
6977 printf("W3m-in-progress: %s\n", convert_size2(linelen, current_content_length, TRUE));
6978 if (w3m_dump & DUMP_SOURCE)
6980 showProgress(&linelen, &trbyte);
6986 if (meta_charset) { /* <META> */
6987 if (content_charset == 0 && UseContentCharset) {
6988 doc_charset = meta_charset;
6989 charset = WC_CES_US_ASCII;
6994 lineBuf2 = convertLine(f, lineBuf2, HTML_MODE, &charset, doc_charset);
6995 #if defined(USE_M17N) && defined(USE_IMAGE)
6996 cur_document_charset = charset;
6998 HTMLlineproc0(lineBuf2->ptr, &htmlenv1, internal);
7000 if (obuf.status != R_ST_NORMAL) {
7001 obuf.status = R_ST_EOL;
7002 HTMLlineproc0("\n", &htmlenv1, internal);
7004 obuf.status = R_ST_NORMAL;
7005 completeHTMLstream(&htmlenv1, &obuf);
7006 flushline(&htmlenv1, &obuf, 0, 2, htmlenv1.limit);
7008 newBuf->buffername = htmlenv1.title;
7011 print_internal_information(&htmlenv1);
7016 print_internal_information(&htmlenv1);
7017 backend_halfdump_buf = htmlenv1.buf;
7021 newBuf->trbyte = trbyte + linelen;
7024 if (!(newBuf->bufferprop & BP_FRAME))
7025 newBuf->document_charset = charset;
7028 newBuf->image_flag = image_flag;
7030 HTMLlineproc2(newBuf, htmlenv1.buf);
7034 * loadHTMLString: read string and make new buffer
7037 loadHTMLString(Str page)
7040 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
7043 newBuf = newBuffer(INIT_BUFFER_WIDTH);
7044 if (SETJMP(AbortLoading) != 0) {
7046 discardBuffer(newBuf);
7051 init_stream(&f, SCM_LOCAL, newStrStream(page));
7054 newBuf->document_charset = InnerCharset;
7056 loadHTMLstream(&f, newBuf, NULL, TRUE);
7058 newBuf->document_charset = WC_CES_US_ASCII;
7062 newBuf->topLine = newBuf->firstLine;
7063 newBuf->lastLine = newBuf->currentLine;
7064 newBuf->currentLine = newBuf->firstLine;
7065 newBuf->type = "text/html";
7066 newBuf->real_type = newBuf->type;
7068 formResetBuffer(newBuf, newBuf->formitem);
7075 * loadGopherDir: get gopher directory
7078 loadGopherDir(URLFile *uf, ParsedURL *pu, wc_ces * charset)
7081 Str lbuf, name, file, host, port;
7082 char *volatile p, *volatile q;
7083 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
7085 wc_ces doc_charset = DocumentCharset;
7088 tmp = parsedURL2Str(pu);
7089 p = html_quote(tmp->ptr);
7091 convertLine(NULL, Strnew_charp(file_unquote(tmp->ptr)), RAW_MODE,
7092 charset, doc_charset);
7093 q = html_quote(tmp->ptr);
7094 tmp = Strnew_m_charp("<html>\n<head>\n<base href=\"", p, "\">\n<title>", q,
7095 "</title>\n</head>\n<body>\n<h1>Index of ", q,
7096 "</h1>\n<table>\n", NULL);
7098 if (SETJMP(AbortLoading) != 0)
7103 if (lbuf = StrUFgets(uf), lbuf->length == 0)
7105 if (lbuf->ptr[0] == '.' &&
7106 (lbuf->ptr[1] == '\n' || lbuf->ptr[1] == '\r'))
7108 lbuf = convertLine(uf, lbuf, HTML_MODE, charset, doc_charset);
7110 for (q = p; *q && *q != '\t'; q++) ;
7111 name = Strnew_charp_n(p, q - p);
7115 for (q = p; *q && *q != '\t'; q++) ;
7116 file = Strnew_charp_n(p, q - p);
7120 for (q = p; *q && *q != '\t'; q++) ;
7121 host = Strnew_charp_n(p, q - p);
7125 for (q = p; *q && *q != '\t' && *q != '\r' && *q != '\n'; q++) ;
7126 port = Strnew_charp_n(p, q - p);
7128 switch (name->ptr[0]) {
7148 p = "[unsupported]";
7151 q = Strnew_m_charp("gopher://", host->ptr, ":", port->ptr,
7152 "/", file->ptr, NULL)->ptr;
7153 Strcat_m_charp(tmp, "<a href=\"",
7154 html_quote(url_quote_conv(q, *charset)),
7155 "\">", p, html_quote(name->ptr + 1), "</a>\n", NULL);
7161 Strcat_charp(tmp, "</table>\n</body>\n</html>\n");
7164 #endif /* USE_GOPHER */
7167 * loadBuffer: read file and make new buffer
7170 loadBuffer(URLFile *uf, Buffer *volatile newBuf)
7172 FILE *volatile src = NULL;
7174 wc_ces charset = WC_CES_US_ASCII;
7175 wc_ces volatile doc_charset = DocumentCharset;
7178 volatile char pre_lbuf = '\0';
7181 clen_t linelen = 0, trbyte = 0;
7182 Lineprop *propBuffer = NULL;
7183 #ifdef USE_ANSI_COLOR
7184 Linecolor *colorBuffer = NULL;
7186 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
7189 newBuf = newBuffer(INIT_BUFFER_WIDTH);
7190 lineBuf2 = Strnew();
7192 if (SETJMP(AbortLoading) != 0) {
7197 if (newBuf->sourcefile == NULL &&
7198 (uf->scheme != SCM_LOCAL || newBuf->mailcap)) {
7199 tmpf = tmpfname(TMPF_SRC, NULL);
7200 src = fopen(tmpf->ptr, "w");
7202 newBuf->sourcefile = tmpf->ptr;
7205 if (newBuf->document_charset)
7206 charset = doc_charset = newBuf->document_charset;
7207 if (content_charset && UseContentCharset)
7208 doc_charset = content_charset;
7212 if (IStype(uf->stream) != IST_ENCODED)
7213 uf->stream = newEncodedStream(uf->stream, uf->encoding);
7214 while ((lineBuf2 = StrmyISgets(uf->stream))->length) {
7216 if (uf->scheme == SCM_NEWS && lineBuf2->ptr[0] == '.') {
7217 Strshrinkfirst(lineBuf2, 1);
7218 if (lineBuf2->ptr[0] == '\n' || lineBuf2->ptr[0] == '\r' ||
7219 lineBuf2->ptr[0] == '\0') {
7221 * iseos(uf->stream) = TRUE;
7226 #endif /* USE_NNTP */
7228 Strfputs(lineBuf2, src);
7229 linelen += lineBuf2->length;
7230 if (w3m_dump & DUMP_EXTRA)
7231 printf("W3m-in-progress: %s\n", convert_size2(linelen, current_content_length, TRUE));
7232 if (w3m_dump & DUMP_SOURCE)
7234 showProgress(&linelen, &trbyte);
7238 convertLine(uf, lineBuf2, PAGER_MODE, &charset, doc_charset);
7239 if (squeezeBlankLine) {
7240 if (lineBuf2->ptr[0] == '\n' && pre_lbuf == '\n') {
7244 pre_lbuf = lineBuf2->ptr[0];
7248 lineBuf2 = checkType(lineBuf2, &propBuffer, NULL);
7249 addnewline(newBuf, lineBuf2->ptr, propBuffer, colorBuffer,
7250 lineBuf2->length, FOLD_BUFFER_WIDTH, nlines);
7254 newBuf->topLine = newBuf->firstLine;
7255 newBuf->lastLine = newBuf->currentLine;
7256 newBuf->currentLine = newBuf->firstLine;
7257 newBuf->trbyte = trbyte + linelen;
7259 newBuf->document_charset = charset;
7269 loadImageBuffer(URLFile *uf, Buffer *newBuf)
7276 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
7279 loadImage(newBuf, IMG_FLAG_STOP);
7280 image.url = uf->url;
7281 image.ext = uf->ext;
7285 cache = getImage(&image, cur_baseURL, IMG_FLAG_AUTO);
7286 if (!cur_baseURL->is_nocache && cache->loaded & IMG_FLAG_LOADED &&
7287 !stat(cache->file, &st))
7291 if (IStype(uf->stream) != IST_ENCODED)
7292 uf->stream = newEncodedStream(uf->stream, uf->encoding);
7293 if (save2tmp(*uf, cache->file) < 0) {
7301 cache->loaded = IMG_FLAG_LOADED;
7306 newBuf = newBuffer(INIT_BUFFER_WIDTH);
7307 cache->loaded |= IMG_FLAG_DONT_REMOVE;
7308 if (newBuf->sourcefile == NULL && uf->scheme != SCM_LOCAL)
7309 newBuf->sourcefile = cache->file;
7311 tmp = Sprintf("<img src=\"%s\"><br><br>", html_quote(image.url));
7312 tmpf = tmpfname(TMPF_SRC, ".html");
7313 src = fopen(tmpf->ptr, "w");
7314 newBuf->mailcap_source = tmpf->ptr;
7316 init_stream(&f, SCM_LOCAL, newStrStream(tmp));
7317 loadHTMLstream(&f, newBuf, src, TRUE);
7321 newBuf->topLine = newBuf->firstLine;
7322 newBuf->lastLine = newBuf->currentLine;
7323 newBuf->currentLine = newBuf->firstLine;
7324 newBuf->image_flag = IMG_FLAG_AUTO;
7330 conv_symbol(Line *l)
7333 char *p = l->lineBuf, *ep = p + l->len;
7334 Lineprop *pr = l->propBuf;
7337 char **symbol = NULL;
7339 char **symbol = get_symbol();
7342 for (; p < ep; p++, pr++) {
7343 if (*pr & PC_SYMBOL) {
7345 char c = ((char)wtf_get_code((wc_uchar *) p) & 0x7f) - SYMBOL_BASE;
7346 int len = get_mclen(p);
7348 char c = *p - SYMBOL_BASE;
7351 tmp = Strnew_size(l->len);
7352 Strcopy_charp_n(tmp, l->lineBuf, p - l->lineBuf);
7354 w = (*pr & PC_KANJI) ? 2 : 1;
7355 symbol = get_symbol(DisplayCharset, &w);
7358 Strcat_charp(tmp, symbol[(int)c]);
7364 else if (tmp != NULL)
7365 Strcat_char(tmp, *p);
7370 return Strnew_charp_n(l->lineBuf, l->len);
7374 * saveBuffer: write buffer to file
7377 _saveBuffer(Buffer *buf, Line *l, FILE * f, int cont)
7380 int is_html = FALSE;
7382 int set_charset = !DisplayCharset;
7383 wc_ces charset = DisplayCharset ? DisplayCharset : WC_CES_US_ASCII;
7386 if (buf->type && !strcasecmp(buf->type, "text/html"))
7390 for (; l != NULL; l = l->next) {
7392 tmp = conv_symbol(l);
7394 tmp = Strnew_charp_n(l->lineBuf, l->len);
7395 tmp = wc_Str_conv(tmp, InnerCharset, charset);
7397 if (Strlastchar(tmp) != '\n' && !(cont && l->next && l->next->bpos))
7400 if (buf->pagerSource && !(buf->bufferprop & BP_CLOSE)) {
7401 l = getNextPage(buf, PagerMax);
7404 charset = buf->document_charset;
7411 saveBuffer(Buffer *buf, FILE * f, int cont)
7413 _saveBuffer(buf, buf->firstLine, f, cont);
7417 saveBufferBody(Buffer *buf, FILE * f, int cont)
7419 Line *l = buf->firstLine;
7421 while (l != NULL && l->real_linenumber == 0)
7423 _saveBuffer(buf, l, f, cont);
7427 loadcmdout(char *cmd,
7428 Buffer *(*loadproc) (URLFile *, Buffer *), Buffer *defaultbuf)
7430 FILE *f, *popen(const char *, const char *);
7434 if (cmd == NULL || *cmd == '\0')
7436 f = popen(cmd, "r");
7439 init_stream(&uf, SCM_UNKNOWN, newFileStream(f, (void (*)())pclose));
7440 buf = loadproc(&uf, defaultbuf);
7446 * getshell: execute shell command and get the result into a buffer
7453 buf = loadcmdout(cmd, loadBuffer, NULL);
7456 buf->filename = cmd;
7457 buf->buffername = Sprintf("%s %s", SHELLBUFFERNAME,
7458 conv_from_system(cmd))->ptr;
7463 * getpipe: execute shell command and connect pipe to the buffer
7468 FILE *f, *popen(const char *, const char *);
7471 if (cmd == NULL || *cmd == '\0')
7473 f = popen(cmd, "r");
7476 buf = newBuffer(INIT_BUFFER_WIDTH);
7477 buf->pagerSource = newFileStream(f, (void (*)())pclose);
7478 buf->filename = cmd;
7479 buf->buffername = Sprintf("%s %s", PIPEBUFFERNAME,
7480 conv_from_system(cmd))->ptr;
7481 buf->bufferprop |= BP_PIPE;
7483 buf->document_charset = WC_CES_US_ASCII;
7492 openPagerBuffer(InputStream stream, Buffer *buf)
7496 buf = newBuffer(INIT_BUFFER_WIDTH);
7497 buf->pagerSource = stream;
7498 buf->buffername = getenv("MAN_PN");
7499 if (buf->buffername == NULL)
7500 buf->buffername = PIPEBUFFERNAME;
7502 buf->buffername = conv_from_system(buf->buffername);
7503 buf->bufferprop |= BP_PIPE;
7505 if (content_charset && UseContentCharset)
7506 buf->document_charset = content_charset;
7508 buf->document_charset = WC_CES_US_ASCII;
7510 buf->currentLine = buf->firstLine;
7516 openGeneralPagerBuffer(InputStream stream)
7519 char *t = "text/plain";
7520 Buffer *t_buf = NULL;
7523 init_stream(&uf, SCM_UNKNOWN, stream);
7526 content_charset = 0;
7529 t_buf = newBuffer(INIT_BUFFER_WIDTH);
7530 readHeader(&uf, t_buf, TRUE, NULL);
7531 t = checkContentType(t_buf);
7535 t_buf->topLine = t_buf->firstLine;
7536 t_buf->currentLine = t_buf->lastLine;
7538 SearchHeader = FALSE;
7540 else if (DefaultType) {
7544 if (!strcasecmp(t, "text/html")) {
7545 buf = loadHTMLBuffer(&uf, t_buf);
7546 buf->type = "text/html";
7548 else if (is_plain_text_type(t)) {
7549 if (IStype(stream) != IST_ENCODED)
7550 stream = newEncodedStream(stream, uf.encoding);
7551 buf = openPagerBuffer(stream, t_buf);
7552 buf->type = "text/plain";
7555 else if (activeImage && displayImage && !useExtImageViewer &&
7556 !(w3m_dump & ~DUMP_FRAME) && !strncasecmp(t, "image/", 6)) {
7557 cur_baseURL = New(ParsedURL);
7558 parseURL("-", cur_baseURL, NULL);
7559 buf = loadImageBuffer(&uf, t_buf);
7560 buf->type = "text/html";
7564 if (doExternal(uf, "-", t, &buf, t_buf)) {
7566 if (buf == NULL || buf == NO_BUFFER)
7569 else { /* unknown type is regarded as text/plain */
7570 if (IStype(stream) != IST_ENCODED)
7571 stream = newEncodedStream(stream, uf.encoding);
7572 buf = openPagerBuffer(stream, t_buf);
7573 buf->type = "text/plain";
7577 buf->currentURL.scheme = SCM_LOCAL;
7578 buf->currentURL.file = "-";
7583 getNextPage(Buffer *buf, int plen)
7585 Line *volatile top = buf->topLine, *volatile last = buf->lastLine,
7586 *volatile cur = buf->currentLine;
7588 int volatile nlines = 0;
7589 clen_t linelen = 0, trbyte = buf->trbyte;
7591 char volatile pre_lbuf = '\0';
7595 wc_ces volatile doc_charset = DocumentCharset;
7596 wc_uint8 old_auto_detect = WcOption.auto_detect;
7598 int volatile squeeze_flag = FALSE;
7599 Lineprop *propBuffer = NULL;
7601 #ifdef USE_ANSI_COLOR
7602 Linecolor *colorBuffer = NULL;
7604 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
7606 if (buf->pagerSource == NULL)
7610 nlines = last->real_linenumber;
7611 pre_lbuf = *(last->lineBuf);
7612 if (pre_lbuf == '\0')
7614 buf->currentLine = last;
7618 charset = buf->document_charset;
7619 if (buf->document_charset != WC_CES_US_ASCII)
7620 doc_charset = buf->document_charset;
7621 else if (UseContentCharset) {
7622 content_charset = 0;
7623 checkContentType(buf);
7624 if (content_charset)
7625 doc_charset = content_charset;
7627 WcOption.auto_detect = buf->auto_detect;
7630 if (SETJMP(AbortLoading) != 0) {
7635 init_stream(&uf, SCM_UNKNOWN, NULL);
7636 for (i = 0; i < plen; i++) {
7637 lineBuf2 = StrmyISgets(buf->pagerSource);
7638 if (lineBuf2->length == 0) {
7639 /* Assume that `cmd == buf->filename' */
7641 buf->buffername = Sprintf("%s %s",
7643 conv_from_system(buf->filename))->
7645 else if (getenv("MAN_PN") == NULL)
7646 buf->buffername = CPIPEBUFFERNAME;
7647 buf->bufferprop |= BP_CLOSE;
7650 linelen += lineBuf2->length;
7651 showProgress(&linelen, &trbyte);
7653 convertLine(&uf, lineBuf2, PAGER_MODE, &charset, doc_charset);
7654 if (squeezeBlankLine) {
7655 squeeze_flag = FALSE;
7656 if (lineBuf2->ptr[0] == '\n' && pre_lbuf == '\n') {
7659 squeeze_flag = TRUE;
7662 pre_lbuf = lineBuf2->ptr[0];
7666 lineBuf2 = checkType(lineBuf2, &propBuffer, &colorBuffer);
7667 addnewline(buf, lineBuf2->ptr, propBuffer, colorBuffer,
7668 lineBuf2->length, FOLD_BUFFER_WIDTH, nlines);
7670 top = buf->firstLine;
7673 if (buf->lastLine->real_linenumber - buf->firstLine->real_linenumber
7675 Line *l = buf->firstLine;
7684 } while (l && l->bpos);
7686 buf->firstLine->prev = NULL;
7692 buf->trbyte = trbyte + linelen;
7694 buf->document_charset = charset;
7695 WcOption.auto_detect = old_auto_detect;
7698 buf->currentLine = cur;
7700 last = buf->firstLine;
7701 else if (last && (last->next || !squeeze_flag))
7707 save2tmp(URLFile uf, char *tmpf)
7711 clen_t linelen = 0, trbyte = 0;
7712 MySignalHandler(*volatile prevtrap) (SIGNAL_ARG) = NULL;
7713 static JMP_BUF env_bak;
7715 ff = fopen(tmpf, "wb");
7720 bcopy(AbortLoading, env_bak, sizeof(JMP_BUF));
7721 if (SETJMP(AbortLoading) != 0) {
7727 if (uf.scheme == SCM_NEWS) {
7729 while (c = UFgetc(&uf), !iseos(uf.stream)) {
7733 else if (check == 3)
7736 else if (c == '.' && check == 1)
7738 else if (c == '\r' && check == 2)
7743 linelen += sizeof(c);
7744 showProgress(&linelen, &trbyte);
7748 #endif /* USE_NNTP */
7750 Str buf = Strnew_size(SAVE_BUF_SIZE);
7751 while (UFread(&uf, buf, SAVE_BUF_SIZE)) {
7753 linelen += buf->length;
7754 showProgress(&linelen, &trbyte);
7758 bcopy(env_bak, AbortLoading, sizeof(JMP_BUF));
7761 current_content_length = 0;
7766 doExternal(URLFile uf, char *path, char *type, Buffer **bufp,
7770 struct mailcap *mcap;
7773 char *header, *src = NULL, *ext = uf.ext;
7775 if (!(mcap = searchExtViewer(type)))
7778 if (mcap->nametemplate) {
7779 tmpf = unquote_mailcap(mcap->nametemplate, NULL, "", NULL, NULL);
7780 if (tmpf->ptr[0] == '.')
7783 tmpf = tmpfname(TMPF_DFL, (ext && *ext) ? ext : NULL);
7785 if (IStype(uf.stream) != IST_ENCODED)
7786 uf.stream = newEncodedStream(uf.stream, uf.encoding);
7787 header = checkHeader(defaultbuf, "Content-Type:");
7789 header = conv_to_system(header);
7790 command = unquote_mailcap(mcap->viewer, type, tmpf->ptr, header, &mc_stat);
7792 if (!(mc_stat & MCSTAT_REPNAME)) {
7793 Str tmp = Sprintf("(%s) < %s", command->ptr, shell_quote(tmpf->ptr));
7799 if (!(mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT)) &&
7800 !(mcap->flags & MAILCAP_NEEDSTERMINAL) && BackgroundExtViewer) {
7803 setup_child(FALSE, 0, UFfileno(&uf));
7804 if (save2tmp(uf, tmpf->ptr) < 0)
7807 myExec(command->ptr);
7815 if (save2tmp(uf, tmpf->ptr) < 0) {
7820 if (mcap->flags & (MAILCAP_HTMLOUTPUT | MAILCAP_COPIOUSOUTPUT)) {
7821 if (defaultbuf == NULL)
7822 defaultbuf = newBuffer(INIT_BUFFER_WIDTH);
7823 if (defaultbuf->sourcefile)
7824 src = defaultbuf->sourcefile;
7827 defaultbuf->sourcefile = NULL;
7828 defaultbuf->mailcap = mcap;
7830 if (mcap->flags & MAILCAP_HTMLOUTPUT) {
7831 buf = loadcmdout(command->ptr, loadHTMLBuffer, defaultbuf);
7832 if (buf && buf != NO_BUFFER) {
7833 buf->type = "text/html";
7834 buf->mailcap_source = buf->sourcefile;
7835 buf->sourcefile = src;
7838 else if (mcap->flags & MAILCAP_COPIOUSOUTPUT) {
7839 buf = loadcmdout(command->ptr, loadBuffer, defaultbuf);
7840 if (buf && buf != NO_BUFFER) {
7841 buf->type = "text/plain";
7842 buf->mailcap_source = buf->sourcefile;
7843 buf->sourcefile = src;
7847 if (mcap->flags & MAILCAP_NEEDSTERMINAL || !BackgroundExtViewer) {
7849 mySystem(command->ptr, 0);
7851 if (CurrentTab && Currentbuf)
7852 displayBuffer(Currentbuf, B_FORCE_REDRAW);
7855 mySystem(command->ptr, 1);
7859 if (buf && buf != NO_BUFFER) {
7860 buf->filename = path;
7861 if (buf->buffername == NULL || buf->buffername[0] == '\0')
7862 buf->buffername = conv_from_system(lastFileName(path));
7863 buf->edit = mcap->edit;
7864 buf->mailcap = mcap;
7871 _MoveFile(char *path1, char *path2)
7876 clen_t linelen = 0, trbyte = 0;
7882 if (*path2 == '|' && PermitSaveToPipe) {
7884 f2 = popen(path2 + 1, "w");
7888 f2 = fopen(path2, "wb");
7894 current_content_length = 0;
7895 buf = Strnew_size(SAVE_BUF_SIZE);
7896 while (ISread(f1, buf, SAVE_BUF_SIZE)) {
7898 linelen += buf->length;
7899 showProgress(&linelen, &trbyte);
7910 _doFileCopy(char *tmpf, char *defstr, int download)
7912 #ifndef __MINGW32_VERSION
7918 #if !(defined(HAVE_SYMLINK) && defined(HAVE_LSTAT))
7923 int is_pipe = FALSE;
7925 if (fmInitialized) {
7926 p = searchKeyData();
7927 if (p == NULL || *p == '\0') {
7928 /* FIXME: gettextize? */
7929 q = inputLineHist("(Download)Save file to: ",
7930 defstr, IN_COMMAND, SaveHist);
7931 if (q == NULL || *q == '\0')
7933 p = conv_to_system(q);
7935 if (*p == '|' && PermitSaveToPipe)
7939 p = unescape_spaces(Strnew_charp(q))->ptr;
7940 p = conv_to_system(q);
7943 if (checkOverWrite(p) < 0)
7946 if (checkCopyFile(tmpf, p) < 0) {
7947 /* FIXME: gettextize? */
7948 msg = Sprintf("Can't copy. %s and %s are identical.",
7949 conv_from_system(tmpf), conv_from_system(p));
7950 disp_err_message(msg->ptr, FALSE);
7954 if (_MoveFile(tmpf, p) < 0) {
7955 /* FIXME: gettextize? */
7956 msg = Sprintf("Can't save to %s", conv_from_system(p));
7957 disp_err_message(msg->ptr, FALSE);
7961 lock = tmpfname(TMPF_DFL, ".lock")->ptr;
7962 #if defined(HAVE_SYMLINK) && defined(HAVE_LSTAT)
7965 f = fopen(lock, "w");
7972 setup_child(FALSE, 0, -1);
7973 if (!_MoveFile(tmpf, p) && PreserveTimestamp && !is_pipe &&
7975 setModtime(p, st.st_mtime);
7979 if (!stat(tmpf, &st))
7981 addDownloadList(pid, conv_from_system(tmpf), p, lock, size);
7984 q = searchKeyData();
7985 if (q == NULL || *q == '\0') {
7986 /* FIXME: gettextize? */
7987 printf("(Download)Save file to: ");
7989 filen = Strfgets(stdin);
7990 if (filen->length == 0)
7994 for (p = q + strlen(q) - 1; IS_SPACE(*p); p--) ;
7999 if (*p == '|' && PermitSaveToPipe)
8003 if (checkOverWrite(p) < 0)
8006 if (checkCopyFile(tmpf, p) < 0) {
8007 /* FIXME: gettextize? */
8008 printf("Can't copy. %s and %s are identical.", tmpf, p);
8011 if (_MoveFile(tmpf, p) < 0) {
8012 /* FIXME: gettextize? */
8013 printf("Can't save to %s\n", p);
8016 if (PreserveTimestamp && !is_pipe && !stat(tmpf, &st))
8017 setModtime(p, st.st_mtime);
8019 #endif /* __MINGW32_VERSION */
8024 doFileMove(char *tmpf, char *defstr)
8026 int ret = doFileCopy(tmpf, defstr);
8032 doFileSave(URLFile uf, char *defstr)
8034 #ifndef __MINGW32_VERSION
8041 #if !(defined(HAVE_SYMLINK) && defined(HAVE_LSTAT))
8045 if (fmInitialized) {
8046 p = searchKeyData();
8047 if (p == NULL || *p == '\0') {
8048 /* FIXME: gettextize? */
8049 p = inputLineHist("(Download)Save file to: ",
8050 defstr, IN_FILENAME, SaveHist);
8051 if (p == NULL || *p == '\0')
8053 p = conv_to_system(p);
8055 if (checkOverWrite(p) < 0)
8057 if (checkSaveFile(uf.stream, p) < 0) {
8058 /* FIXME: gettextize? */
8059 msg = Sprintf("Can't save. Load file and %s are identical.",
8060 conv_from_system(p));
8061 disp_err_message(msg->ptr, FALSE);
8065 * if (save2tmp(uf, p) < 0) {
8066 * msg = Sprintf("Can't save to %s", conv_from_system(p));
8067 * disp_err_message(msg->ptr, FALSE);
8070 lock = tmpfname(TMPF_DFL, ".lock")->ptr;
8071 #if defined(HAVE_SYMLINK) && defined(HAVE_LSTAT)
8074 f = fopen(lock, "w");
8081 if ((uf.content_encoding != CMP_NOCOMPRESS) && AutoUncompress) {
8082 uncompress_stream(&uf, &tmpf);
8086 setup_child(FALSE, 0, UFfileno(&uf));
8087 if (!save2tmp(uf, p) && PreserveTimestamp && uf.modtime != -1)
8088 setModtime(p, uf.modtime);
8093 addDownloadList(pid, uf.url, p, lock, current_content_length);
8096 q = searchKeyData();
8097 if (q == NULL || *q == '\0') {
8098 /* FIXME: gettextize? */
8099 printf("(Download)Save file to: ");
8101 filen = Strfgets(stdin);
8102 if (filen->length == 0)
8106 for (p = q + strlen(q) - 1; IS_SPACE(*p); p--) ;
8111 if (checkOverWrite(p) < 0)
8113 if (checkSaveFile(uf.stream, p) < 0) {
8114 /* FIXME: gettextize? */
8115 printf("Can't save. Load file and %s are identical.", p);
8118 if (uf.content_encoding != CMP_NOCOMPRESS && AutoUncompress) {
8119 uncompress_stream(&uf, &tmpf);
8123 if (save2tmp(uf, p) < 0) {
8124 /* FIXME: gettextize? */
8125 printf("Can't save to %s\n", p);
8128 if (PreserveTimestamp && uf.modtime != -1)
8129 setModtime(p, uf.modtime);
8131 #endif /* __MINGW32_VERSION */
8136 checkCopyFile(char *path1, char *path2)
8138 struct stat st1, st2;
8140 if (*path2 == '|' && PermitSaveToPipe)
8142 if ((stat(path1, &st1) == 0) && (stat(path2, &st2) == 0))
8143 if (st1.st_ino == st2.st_ino)
8149 checkSaveFile(InputStream stream, char *path2)
8151 struct stat st1, st2;
8152 int des = ISfileno(stream);
8156 if (*path2 == '|' && PermitSaveToPipe)
8158 if ((fstat(des, &st1) == 0) && (stat(path2, &st2) == 0))
8159 if (st1.st_ino == st2.st_ino)
8165 checkOverWrite(char *path)
8170 if (stat(path, &st) < 0)
8172 /* FIXME: gettextize? */
8173 ans = inputAnswer("File exists. Overwrite? (y/n)");
8174 if (ans && TOLOWER(*ans) == 'y')
8181 inputAnswer(char *prompt)
8187 if (fmInitialized) {
8189 ans = inputChar(prompt);
8192 printf("%s", prompt);
8194 ans = Strfgets(stdin)->ptr;
8200 uncompress_stream(URLFile *uf, char **src)
8202 #ifndef __MINGW32_VERSION
8205 char *expand_cmd = GUNZIP_CMDNAME;
8206 char *expand_name = GUNZIP_NAME;
8209 struct compression_decoder *d;
8211 if (IStype(uf->stream) != IST_ENCODED) {
8212 uf->stream = newEncodedStream(uf->stream, uf->encoding);
8213 uf->encoding = ENC_7BIT;
8215 for (d = compression_decoders; d->type != CMP_NOCOMPRESS; d++) {
8216 if (uf->compression == d->type) {
8218 expand_cmd = auxbinFile(d->cmd);
8220 expand_cmd = d->cmd;
8221 expand_name = d->name;
8226 uf->compression = CMP_NOCOMPRESS;
8228 if (uf->scheme != SCM_LOCAL
8233 tmpf = tmpfname(TMPF_DFL, ext)->ptr;
8236 /* child1 -- stdout|f1=uf -> parent */
8237 pid1 = open_pipe_rw(&f1, NULL);
8247 /* uf -> child2 -- stdout|stdin -> child1 */
8248 pid2 = open_pipe_rw(&f2, NULL);
8255 Str buf = Strnew_size(SAVE_BUF_SIZE);
8258 setup_child(TRUE, 2, UFfileno(uf));
8260 f = fopen(tmpf, "wb");
8261 while (UFread(uf, buf, SAVE_BUF_SIZE)) {
8262 if (Strfputs(buf, stdout) < 0)
8273 dup2(1, 2); /* stderr>&stdout */
8274 setup_child(TRUE, -1, -1);
8275 execlp(expand_cmd, expand_name, NULL);
8282 uf->scheme = SCM_LOCAL;
8285 uf->stream = newFileStream(f1, (void (*)())fclose);
8286 #endif /* __MINGW32_VERSION */
8290 lessopen_stream(char *path)
8295 lessopen = getenv("LESSOPEN");
8296 if (lessopen == NULL) {
8299 if (lessopen[0] == '\0') {
8303 if (lessopen[0] == '|') {
8309 tmpf = Sprintf(lessopen, shell_quote(path));
8310 fp = popen(tmpf->ptr, "r");
8323 /* not supported m(__)m */
8331 reloadBuffer(Buffer *buf)
8335 if (buf->sourcefile == NULL || buf->pagerSource != NULL)
8337 init_stream(&uf, SCM_UNKNOWN, NULL);
8338 examineFile(buf->mailcap_source ? buf->mailcap_source : buf->sourcefile,
8340 if (uf.stream == NULL)
8342 is_redisplay = TRUE;
8347 buf->formitem = NULL;
8348 buf->linklist = NULL;
8349 buf->maplist = NULL;
8351 buf->hmarklist->nmark = 0;
8353 buf->imarklist->nmark = 0;
8354 if (!strcasecmp(buf->type, "text/html"))
8355 loadHTMLBuffer(&uf, buf);
8357 loadBuffer(&uf, buf);
8359 is_redisplay = FALSE;
8364 guess_filename(char *file)
8369 p = mybasename(file);
8370 if (p == NULL || *p == '\0')
8371 return DEF_SAVE_FILE;
8375 while (*p != '\0') {
8376 if ((*p == '#' && *(p + 1) != '\0') || *p == '?') {
8386 guess_save_name(Buffer *buf, char *path)
8388 if (buf && buf->document_header) {
8391 if ((p = checkHeader(buf, "Content-Disposition:")) != NULL &&
8392 (q = strcasestr(p, "filename")) != NULL &&
8393 (q == p || IS_SPACE(*(q - 1)) || *(q - 1) == ';') &&
8394 matchattr(q, "filename", 8, &name))
8396 else if ((p = checkHeader(buf, "Content-Type:")) != NULL &&
8397 (q = strcasestr(p, "name")) != NULL &&
8398 (q == p || IS_SPACE(*(q - 1)) || *(q - 1) == ';') &&
8399 matchattr(q, "name", 4, &name))
8402 return guess_filename(path);
8405 /* Local Variables: */
8406 /* c-basic-offset: 4 */