Intial commit
[profile/ivi/w3m.git] / etc.c
1 /* $Id: etc.c,v 1.81 2007/05/23 15:06:05 inu Exp $ */
2 #include "fm.h"
3 #ifndef __MINGW32_VERSION
4 #include <pwd.h>
5 #endif
6 #include "myctype.h"
7 #include "html.h"
8 #include "local.h"
9 #include "hash.h"
10
11 #include <fcntl.h>
12 #include <sys/types.h>
13 #include <time.h>
14 #if defined(HAVE_WAITPID) || defined(HAVE_WAIT3)
15 #include <sys/wait.h>
16 #endif
17 #include <signal.h>
18
19 #ifdef  __WATT32__
20 #define read(a,b,c)     read_s(a,b,c)
21 #define close(x)        close_s(x)
22 #endif                          /* __WATT32__ */
23
24 struct auth_pass {
25     int bad;
26     int is_proxy;
27     Str host;
28     int port;
29 /*    Str file; */
30     Str realm;
31     Str uname;
32     Str pwd;
33     struct auth_pass *next;
34 };
35
36 struct auth_pass *passwords = NULL;
37
38 int
39 columnSkip(Buffer *buf, int offset)
40 {
41     int i, maxColumn;
42     int column = buf->currentColumn + offset;
43     int nlines = buf->LINES + 1;
44     Line *l;
45
46     maxColumn = 0;
47     for (i = 0, l = buf->topLine; i < nlines && l != NULL; i++, l = l->next) {
48         if (l->width < 0)
49             l->width = COLPOS(l, l->len);
50         if (l->width - 1 > maxColumn)
51             maxColumn = l->width - 1;
52     }
53     maxColumn -= buf->COLS - 1;
54     if (column < maxColumn)
55         maxColumn = column;
56     if (maxColumn < 0)
57         maxColumn = 0;
58
59     if (buf->currentColumn == maxColumn)
60         return 0;
61     buf->currentColumn = maxColumn;
62     return 1;
63 }
64
65 int
66 columnPos(Line *line, int column)
67 {
68     int i;
69
70     for (i = 1; i < line->len; i++) {
71         if (COLPOS(line, i) > column)
72             break;
73     }
74 #ifdef USE_M17N
75     for (i--; i > 0 && line->propBuf[i] & PC_WCHAR2; i--) ;
76     return i;
77 #else
78     return i - 1;
79 #endif
80 }
81
82 Line *
83 lineSkip(Buffer *buf, Line *line, int offset, int last)
84 {
85     int i;
86     Line *l;
87
88     l = currentLineSkip(buf, line, offset, last);
89     if (!nextpage_topline)
90         for (i = buf->LINES - 1 - (buf->lastLine->linenumber - l->linenumber);
91              i > 0 && l->prev != NULL; i--, l = l->prev) ;
92     return l;
93 }
94
95 Line *
96 currentLineSkip(Buffer *buf, Line *line, int offset, int last)
97 {
98     int i, n;
99     Line *l = line;
100
101     if (buf->pagerSource && !(buf->bufferprop & BP_CLOSE)) {
102         n = line->linenumber + offset + buf->LINES;
103         if (buf->lastLine->linenumber < n)
104             getNextPage(buf, n - buf->lastLine->linenumber);
105         while ((last || (buf->lastLine->linenumber < n)) &&
106                (getNextPage(buf, 1) != NULL)) ;
107         if (last)
108             l = buf->lastLine;
109     }
110
111     if (offset == 0)
112         return l;
113     if (offset > 0)
114         for (i = 0; i < offset && l->next != NULL; i++, l = l->next) ;
115     else
116         for (i = 0; i < -offset && l->prev != NULL; i++, l = l->prev) ;
117     return l;
118 }
119
120 #define MAX_CMD_LEN 128
121
122 int
123 gethtmlcmd(char **s)
124 {
125     extern Hash_si tagtable;
126     char cmdstr[MAX_CMD_LEN];
127     char *p = cmdstr;
128     char *save = *s;
129     int cmd;
130
131     (*s)++;
132     /* first character */
133     if (IS_ALNUM(**s) || **s == '_' || **s == '/') {
134         *(p++) = TOLOWER(**s);
135         (*s)++;
136     }
137     else
138         return HTML_UNKNOWN;
139     if (p[-1] == '/')
140         SKIP_BLANKS(*s);
141     while ((IS_ALNUM(**s) || **s == '_') && p - cmdstr < MAX_CMD_LEN) {
142         *(p++) = TOLOWER(**s);
143         (*s)++;
144     }
145     if (p - cmdstr == MAX_CMD_LEN) {
146         /* buffer overflow: perhaps caused by bad HTML source */
147         *s = save + 1;
148         return HTML_UNKNOWN;
149     }
150     *p = '\0';
151
152     /* hash search */
153     cmd = getHash_si(&tagtable, cmdstr, HTML_UNKNOWN);
154     while (**s && **s != '>')
155         (*s)++;
156     if (**s == '>')
157         (*s)++;
158     return cmd;
159 }
160
161 #ifdef USE_ANSI_COLOR
162 static int
163 parse_ansi_color(char **str, Lineprop *effect, Linecolor *color)
164 {
165     char *p = *str, *q;
166     Lineprop e = *effect;
167     Linecolor c = *color;
168     int i;
169
170     if (*p != ESC_CODE || *(p + 1) != '[')
171         return 0;
172     p += 2;
173     for (q = p; IS_DIGIT(*q) || *q == ';'; q++) ;
174     if (*q != 'm')
175         return 0;
176     *str = q + 1;
177     while (1) {
178         if (*p == 'm') {
179             e = PE_NORMAL;
180             c = 0;
181             break;
182         }
183         if (IS_DIGIT(*p)) {
184             q = p;
185             for (p++; IS_DIGIT(*p); p++) ;
186             i = atoi(allocStr(q, p - q));
187             switch (i) {
188             case 0:
189                 e = PE_NORMAL;
190                 c = 0;
191                 break;
192             case 1:
193             case 5:
194                 e = PE_BOLD;
195                 break;
196             case 4:
197                 e = PE_UNDER;
198                 break;
199             case 7:
200                 e = PE_STAND;
201                 break;
202             case 100:           /* for EWS4800 kterm */
203                 c = 0;
204                 break;
205             case 39:
206                 c &= 0xf0;
207                 break;
208             case 49:
209                 c &= 0x0f;
210                 break;
211             default:
212                 if (i >= 30 && i <= 37)
213                     c = (c & 0xf0) | (i - 30) | 0x08;
214                 else if (i >= 40 && i <= 47)
215                     c = (c & 0x0f) | ((i - 40) << 4) | 0x80;
216                 break;
217             }
218             if (*p == 'm')
219                 break;
220         }
221         else {
222             e = PE_NORMAL;
223             c = 0;
224             break;
225         }
226         p++;                    /* *p == ';' */
227     }
228     *effect = e;
229     *color = c;
230     return 1;
231 }
232 #endif
233 /* 
234  * Check character type
235  */
236
237 Str
238 checkType(Str s, Lineprop **oprop, Linecolor **ocolor)
239 {
240     Lineprop mode;
241     Lineprop effect = PE_NORMAL;
242     Lineprop *prop;
243     static Lineprop *prop_buffer = NULL;
244     static int prop_size = 0;
245     char *str = s->ptr, *endp = &s->ptr[s->length], *bs = NULL;
246 #ifdef USE_ANSI_COLOR
247     Lineprop ceffect = PE_NORMAL;
248     Linecolor cmode = 0;
249     int check_color = FALSE;
250     Linecolor *color = NULL;
251     static Linecolor *color_buffer = NULL;
252     static int color_size = 0;
253     char *es = NULL;
254 #endif
255     int do_copy = FALSE;
256     int i;
257     int plen = 0, clen;
258
259     if (prop_size < s->length) {
260         prop_size = (s->length > LINELEN) ? s->length : LINELEN;
261         prop_buffer = New_Reuse(Lineprop, prop_buffer, prop_size);
262     }
263     prop = prop_buffer;
264
265     if (ShowEffect) {
266         bs = memchr(str, '\b', s->length);
267 #ifdef USE_ANSI_COLOR
268         if (ocolor) {
269             es = memchr(str, ESC_CODE, s->length);
270             if (es) {
271                 if (color_size < s->length) {
272                     color_size = (s->length > LINELEN) ? s->length : LINELEN;
273                     color_buffer = New_Reuse(Linecolor, color_buffer,
274                                              color_size);
275                 }
276                 color = color_buffer;
277             }
278         }
279 #endif
280         if ((bs != NULL)
281 #ifdef USE_ANSI_COLOR
282             || (es != NULL)
283 #endif
284             ) {
285             char *sp = str, *ep;
286             s = Strnew_size(s->length);
287             do_copy = TRUE;
288             ep = bs ? (bs - 2) : endp;
289 #ifdef USE_ANSI_COLOR
290             if (es && ep > es - 2)
291                 ep = es - 2;
292 #endif
293             for (; str < ep && IS_ASCII(*str); str++) {
294                 *(prop++) = PE_NORMAL | (IS_CNTRL(*str) ? PC_CTRL : PC_ASCII);
295 #ifdef USE_ANSI_COLOR
296                 if (color)
297                     *(color++) = 0;
298 #endif
299             }
300             Strcat_charp_n(s, sp, (int)(str - sp));
301         }
302     }
303     if (!do_copy) {
304         for (; str < endp && IS_ASCII(*str); str++)
305             *(prop++) = PE_NORMAL | (IS_CNTRL(*str) ? PC_CTRL : PC_ASCII);
306     }
307
308     while (str < endp) {
309         if (prop - prop_buffer >= prop_size)
310             break;
311         if (bs != NULL) {
312 #ifdef USE_M17N
313             if (str == bs - 2 && !strncmp(str, "__\b\b", 4)) {
314                 str += 4;
315                 effect = PE_UNDER;
316                 if (str < endp)
317                     bs = memchr(str, '\b', endp - str);
318                 continue;
319             }
320             else
321 #endif
322             if (str == bs - 1 && *str == '_') {
323                 str += 2;
324                 effect = PE_UNDER;
325                 if (str < endp)
326                     bs = memchr(str, '\b', endp - str);
327                 continue;
328             }
329             else if (str == bs) {
330                 if (*(str + 1) == '_') {
331                     if (s->length) {
332                         str += 2;
333 #ifdef USE_M17N
334                         for (i = 1; i <= plen; i++)
335                             *(prop - i) |= PE_UNDER;
336 #else
337                         *(prop - 1) |= PE_UNDER;
338 #endif
339                     }
340                     else {
341                         str++;
342                     }
343                 }
344 #ifdef USE_M17N
345                 else if (!strncmp(str + 1, "\b__", 3)) {
346                     if (s->length) {
347                         str += (plen == 1) ? 3 : 4;
348                         for (i = 1; i <= plen; i++)
349                             *(prop - i) |= PE_UNDER;
350                     }
351                     else {
352                         str += 2;
353                     }
354                 }
355                 else if (*(str + 1) == '\b') {
356                     if (s->length) {
357                         clen = get_mclen(str + 2);
358                         if (plen == clen &&
359                             !strncmp(str - plen, str + 2, plen)) {
360                             for (i = 1; i <= plen; i++)
361                                 *(prop - i) |= PE_BOLD;
362                             str += 2 + clen;
363                         }
364                         else {
365                             Strshrink(s, plen);
366                             prop -= plen;
367                             str += 2;
368                         }
369                     }
370                     else {
371                         str += 2;
372                     }
373                 }
374 #endif
375                 else {
376                     if (s->length) {
377 #ifdef USE_M17N
378                         clen = get_mclen(str + 1);
379                         if (plen == clen &&
380                             !strncmp(str - plen, str + 1, plen)) {
381                             for (i = 1; i <= plen; i++)
382                                 *(prop - i) |= PE_BOLD;
383                             str += 1 + clen;
384                         }
385                         else {
386                             Strshrink(s, plen);
387                             prop -= plen;
388                             str++;
389                         }
390 #else
391                         if (*(str - 1) == *(str + 1)) {
392                             *(prop - 1) |= PE_BOLD;
393                             str += 2;
394                         }
395                         else {
396                             Strshrink(s, 1);
397                             prop--;
398                             str++;
399                         }
400 #endif
401                     }
402                     else {
403                         str++;
404                     }
405                 }
406                 if (str < endp)
407                     bs = memchr(str, '\b', endp - str);
408                 continue;
409             }
410 #ifdef USE_ANSI_COLOR
411             else if (str > bs)
412                 bs = memchr(str, '\b', endp - str);
413 #endif
414         }
415 #ifdef USE_ANSI_COLOR
416         if (es != NULL) {
417             if (str == es) {
418                 int ok = parse_ansi_color(&str, &ceffect, &cmode);
419                 if (str < endp)
420                     es = memchr(str, ESC_CODE, endp - str);
421                 if (ok) {
422                     if (cmode)
423                         check_color = TRUE;
424                     continue;
425                 }
426             }
427             else if (str > es)
428                 es = memchr(str, ESC_CODE, endp - str);
429         }
430 #endif
431
432         plen = get_mclen(str);
433         mode = get_mctype(str) | effect;
434 #ifdef USE_ANSI_COLOR
435         if (color) {
436             *(color++) = cmode;
437             mode |= ceffect;
438         }
439 #endif
440         *(prop++) = mode;
441 #ifdef USE_M17N
442         if (plen > 1) {
443             mode = (mode & ~PC_WCHAR1) | PC_WCHAR2;
444             for (i = 1; i < plen; i++) {
445                 *(prop++) = mode;
446 #ifdef USE_ANSI_COLOR
447                 if (color)
448                     *(color++) = cmode;
449 #endif
450             }
451             if (do_copy)
452                 Strcat_charp_n(s, (char *)str, plen);
453             str += plen;
454         }
455         else
456 #endif
457         {
458             if (do_copy)
459                 Strcat_char(s, (char)*str);
460             str++;
461         }
462         effect = PE_NORMAL;
463     }
464     *oprop = prop_buffer;
465 #ifdef USE_ANSI_COLOR
466     if (ocolor)
467         *ocolor = check_color ? color_buffer : NULL;
468 #endif
469     return s;
470 }
471
472 static int
473 nextColumn(int n, char *p, Lineprop *pr)
474 {
475     if (*pr & PC_CTRL) {
476         if (*p == '\t')
477             return (n + Tabstop) / Tabstop * Tabstop;
478         else if (*p == '\n')
479             return n + 1;
480         else if (*p != '\r')
481             return n + 2;
482         return n;
483     }
484 #ifdef USE_M17N
485     if (*pr & PC_UNKNOWN)
486         return n + 4;
487     return n + wtf_width((wc_uchar *) p);
488 #else
489     return n + 1;
490 #endif
491 }
492
493 int
494 calcPosition(char *l, Lineprop *pr, int len, int pos, int bpos, int mode)
495 {
496     static int *realColumn = NULL;
497     static int size = 0;
498     static char *prevl = NULL;
499     int i, j;
500
501     if (l == NULL || len == 0)
502         return bpos;
503     if (l == prevl && mode == CP_AUTO) {
504         if (pos <= len)
505             return realColumn[pos];
506     }
507     if (size < len + 1) {
508         size = (len + 1 > LINELEN) ? (len + 1) : LINELEN;
509         realColumn = New_N(int, size);
510     }
511     prevl = l;
512     i = 0;
513     j = bpos;
514 #ifdef USE_M17N
515     if (pr[i] & PC_WCHAR2) {
516         for (; i < len && pr[i] & PC_WCHAR2; i++)
517             realColumn[i] = j;
518         if (i > 0 && pr[i - 1] & PC_KANJI && WcOption.use_wide)
519             j++;
520     }
521 #endif
522     while (1) {
523         realColumn[i] = j;
524         if (i == len)
525             break;
526         j = nextColumn(j, &l[i], &pr[i]);
527         i++;
528 #ifdef USE_M17N
529         for (; i < len && pr[i] & PC_WCHAR2; i++)
530             realColumn[i] = realColumn[i - 1];
531 #endif
532     }
533     if (pos >= i)
534         return j;
535     return realColumn[pos];
536 }
537
538 int
539 columnLen(Line *line, int column)
540 {
541     int i, j;
542
543     for (i = 0, j = 0; i < line->len;) {
544         j = nextColumn(j, &line->lineBuf[i], &line->propBuf[i]);
545         if (j > column)
546             return i;
547         i++;
548 #ifdef USE_M17N
549         while (i < line->len && line->propBuf[i] & PC_WCHAR2)
550             i++;
551 #endif
552     }
553     return line->len;
554 }
555
556 char *
557 lastFileName(char *path)
558 {
559     char *p, *q;
560
561     p = q = path;
562     while (*p != '\0') {
563         if (*p == '/')
564             q = p + 1;
565         p++;
566     }
567
568     return allocStr(q, -1);
569 }
570
571 #ifdef USE_INCLUDED_SRAND48
572 static unsigned long R1 = 0x1234abcd;
573 static unsigned long R2 = 0x330e;
574 #define A1 0x5deec
575 #define A2 0xe66d
576 #define C 0xb
577
578 void
579 srand48(long seed)
580 {
581     R1 = (unsigned long)seed;
582     R2 = 0x330e;
583 }
584
585 long
586 lrand48(void)
587 {
588     R1 = (A1 * R1 << 16) + A1 * R2 + A2 * R1 + ((A2 * R2 + C) >> 16);
589     R2 = (A2 * R2 + C) & 0xffff;
590     return (long)(R1 >> 1);
591 }
592 #endif
593
594 char *
595 mybasename(char *s)
596 {
597     char *p = s;
598     while (*p)
599         p++;
600     while (s <= p && *p != '/')
601         p--;
602     if (*p == '/')
603         p++;
604     else
605         p = s;
606     return allocStr(p, -1);
607 }
608
609 char *
610 mydirname(char *s)
611 {
612     char *p = s;
613     while (*p)
614         p++;
615     if (s != p)
616         p--;
617     while (s != p && *p == '/')
618         p--;
619     while (s != p && *p != '/')
620         p--;
621     if (*p != '/')
622         return ".";
623     while (s != p && *p == '/')
624         p--;
625     return allocStr(s, strlen(s) - strlen(p) + 1);
626 }
627
628 #ifndef HAVE_STRERROR
629 char *
630 strerror(int errno)
631 {
632     extern char *sys_errlist[];
633     return sys_errlist[errno];
634 }
635 #endif                          /* not HAVE_STRERROR */
636
637 #ifndef HAVE_SYS_ERRLIST
638 char **sys_errlist;
639
640 prepare_sys_errlist()
641 {
642     int i, n;
643
644     i = 1;
645     while (strerror(i) != NULL)
646         i++;
647     n = i;
648     sys_errlist = New_N(char *, n);
649     sys_errlist[0] = "";
650     for (i = 1; i < n; i++)
651         sys_errlist[i] = strerror(i);
652 }
653 #endif                          /* not HAVE_SYS_ERRLIST */
654
655 int
656 next_status(char c, int *status)
657 {
658     switch (*status) {
659     case R_ST_NORMAL:
660         if (c == '<') {
661             *status = R_ST_TAG0;
662             return 0;
663         }
664         else if (c == '&') {
665             *status = R_ST_AMP;
666             return 1;
667         }
668         else
669             return 1;
670         break;
671     case R_ST_TAG0:
672         if (c == '!') {
673             *status = R_ST_CMNT1;
674             return 0;
675         }
676         *status = R_ST_TAG;
677         /* continues to next case */
678     case R_ST_TAG:
679         if (c == '>')
680             *status = R_ST_NORMAL;
681         else if (c == '=')
682             *status = R_ST_EQL;
683         return 0;
684     case R_ST_EQL:
685         if (c == '"')
686             *status = R_ST_DQUOTE;
687         else if (c == '\'')
688             *status = R_ST_QUOTE;
689         else if (IS_SPACE(c))
690             *status = R_ST_EQL;
691         else if (c == '>')
692             *status = R_ST_NORMAL;
693         else
694             *status = R_ST_VALUE;
695         return 0;
696     case R_ST_QUOTE:
697         if (c == '\'')
698             *status = R_ST_TAG;
699         return 0;
700     case R_ST_DQUOTE:
701         if (c == '"')
702             *status = R_ST_TAG;
703         return 0;
704     case R_ST_VALUE:
705         if (c == '>')
706             *status = R_ST_NORMAL;
707         else if (IS_SPACE(c))
708             *status = R_ST_TAG;
709         return 0;
710     case R_ST_AMP:
711         if (c == ';') {
712             *status = R_ST_NORMAL;
713             return 0;
714         }
715         else if (c != '#' && !IS_ALNUM(c) && c != '_') {
716             /* something's wrong! */
717             *status = R_ST_NORMAL;
718             return 0;
719         }
720         else
721             return 0;
722     case R_ST_CMNT1:
723         switch (c) {
724         case '-':
725             *status = R_ST_CMNT2;
726             break;
727         case '>':
728             *status = R_ST_NORMAL;
729             break;
730         default:
731             *status = R_ST_IRRTAG;
732         }
733         return 0;
734     case R_ST_CMNT2:
735         switch (c) {
736         case '-':
737             *status = R_ST_CMNT;
738             break;
739         case '>':
740             *status = R_ST_NORMAL;
741             break;
742         default:
743             *status = R_ST_IRRTAG;
744         }
745         return 0;
746     case R_ST_CMNT:
747         if (c == '-')
748             *status = R_ST_NCMNT1;
749         return 0;
750     case R_ST_NCMNT1:
751         if (c == '-')
752             *status = R_ST_NCMNT2;
753         else
754             *status = R_ST_CMNT;
755         return 0;
756     case R_ST_NCMNT2:
757         switch (c) {
758         case '>':
759             *status = R_ST_NORMAL;
760             break;
761         case '-':
762             *status = R_ST_NCMNT2;
763             break;
764         default:
765             if (IS_SPACE(c))
766                 *status = R_ST_NCMNT3;
767             else
768                 *status = R_ST_CMNT;
769             break;
770         }
771         break;
772     case R_ST_NCMNT3:
773         switch (c) {
774         case '>':
775             *status = R_ST_NORMAL;
776             break;
777         case '-':
778             *status = R_ST_NCMNT1;
779             break;
780         default:
781             if (IS_SPACE(c))
782                 *status = R_ST_NCMNT3;
783             else
784                 *status = R_ST_CMNT;
785             break;
786         }
787         return 0;
788     case R_ST_IRRTAG:
789         if (c == '>')
790             *status = R_ST_NORMAL;
791         return 0;
792     }
793     /* notreached */
794     return 0;
795 }
796
797 int
798 read_token(Str buf, char **instr, int *status, int pre, int append)
799 {
800     char *p;
801     int prev_status;
802
803     if (!append)
804         Strclear(buf);
805     if (**instr == '\0')
806         return 0;
807     for (p = *instr; *p; p++) {
808         prev_status = *status;
809         next_status(*p, status);
810         switch (*status) {
811         case R_ST_NORMAL:
812             if (prev_status == R_ST_AMP && *p != ';') {
813                 p--;
814                 break;
815             }
816             if (prev_status == R_ST_NCMNT2 || prev_status == R_ST_NCMNT3 ||
817                 prev_status == R_ST_IRRTAG || prev_status == R_ST_CMNT1) {
818                 if (prev_status == R_ST_CMNT1 && !append && !pre)
819                     Strclear(buf);
820                 if (pre)
821                     Strcat_char(buf, *p);
822                 p++;
823                 goto proc_end;
824             }
825             Strcat_char(buf, (!pre && IS_SPACE(*p)) ? ' ' : *p);
826             if (ST_IS_REAL_TAG(prev_status)) {
827                 *instr = p + 1;
828                 if (buf->length < 2 ||
829                     buf->ptr[buf->length - 2] != '<' ||
830                     buf->ptr[buf->length - 1] != '>')
831                     return 1;
832                 Strshrink(buf, 2);
833             }
834             break;
835         case R_ST_TAG0:
836         case R_ST_TAG:
837             if (prev_status == R_ST_NORMAL && p != *instr) {
838                 *instr = p;
839                 *status = prev_status;
840                 return 1;
841             }
842             if (*status == R_ST_TAG0 && !REALLY_THE_BEGINNING_OF_A_TAG(p)) {
843                 /* it seems that this '<' is not a beginning of a tag */
844                 /*
845                  * Strcat_charp(buf, "&lt;");
846                  */
847                 Strcat_char(buf, '<');
848                 *status = R_ST_NORMAL;
849             }
850             else
851                 Strcat_char(buf, *p);
852             break;
853         case R_ST_EQL:
854         case R_ST_QUOTE:
855         case R_ST_DQUOTE:
856         case R_ST_VALUE:
857         case R_ST_AMP:
858             Strcat_char(buf, *p);
859             break;
860         case R_ST_CMNT:
861         case R_ST_IRRTAG:
862             if (pre)
863                 Strcat_char(buf, *p);
864             else if (!append)
865                 Strclear(buf);
866             break;
867         case R_ST_CMNT1:
868         case R_ST_CMNT2:
869         case R_ST_NCMNT1:
870         case R_ST_NCMNT2:
871         case R_ST_NCMNT3:
872             /* do nothing */
873             if (pre)
874                 Strcat_char(buf, *p);
875             break;
876         }
877     }
878   proc_end:
879     *instr = p;
880     return 1;
881 }
882
883 Str
884 correct_irrtag(int status)
885 {
886     char c;
887     Str tmp = Strnew();
888
889     while (status != R_ST_NORMAL) {
890         switch (status) {
891         case R_ST_CMNT: /* required "-->" */
892         case R_ST_NCMNT1:       /* required "->" */
893             c = '-';
894             break;
895         case R_ST_NCMNT2:
896         case R_ST_NCMNT3:
897         case R_ST_IRRTAG:
898         case R_ST_CMNT1:
899         case R_ST_CMNT2:
900         case R_ST_TAG:
901         case R_ST_TAG0:
902         case R_ST_EQL:          /* required ">" */
903         case R_ST_VALUE:
904             c = '>';
905             break;
906         case R_ST_QUOTE:
907             c = '\'';
908             break;
909         case R_ST_DQUOTE:
910             c = '"';
911             break;
912         case R_ST_AMP:
913             c = ';';
914             break;
915         default:
916             return tmp;
917         }
918         next_status(c, &status);
919         Strcat_char(tmp, c);
920     }
921     return tmp;
922 }
923
924 /*
925  * RFC2617: 1.2 Access Authentication Framework
926  *
927  * The realm value (case-sensitive), in combination with the canonical root
928  * URL (the absoluteURI for the server whose abs_path is empty; see section
929  * 5.1.2 of RFC2616 ) of the server being accessed, defines the protection
930  * space. These realms allow the protected resources on a server to be
931  * partitioned into a set of protection spaces, each with its own
932  * authentication scheme and/or authorization database.
933  *
934  */
935 static void
936 add_auth_pass_entry(const struct auth_pass *ent, int netrc, int override)
937 {
938     if ((ent->host || netrc)    /* netrc accept default (host == NULL) */
939         &&(ent->is_proxy || ent->realm || netrc)
940         && ent->uname && ent->pwd) {
941         struct auth_pass *newent = New(struct auth_pass);
942         memcpy(newent, ent, sizeof(struct auth_pass));
943         if (override) {
944             newent->next = passwords;
945             passwords = newent;
946         } 
947         else {
948             if (passwords == NULL)
949                 passwords = newent;
950             else if (passwords->next == NULL)
951                 passwords->next = newent;
952             else {
953                 struct auth_pass *ep = passwords;
954                 for (; ep->next; ep = ep->next) ;
955                 ep->next = newent;
956             }
957         }
958     }
959     /* ignore invalid entries */
960 }
961
962 static struct auth_pass *
963 find_auth_pass_entry(char *host, int port, char *realm, char *uname, 
964                      int is_proxy)
965 {
966     struct auth_pass *ent;
967     for (ent = passwords; ent != NULL; ent = ent->next) {
968         if (ent->is_proxy == is_proxy
969             && (ent->bad != TRUE)
970             && (!ent->host || !Strcasecmp_charp(ent->host, host))
971             && (!ent->port || ent->port == port)
972             && (!ent->uname || !uname || !Strcmp_charp(ent->uname, uname))
973             && (!ent->realm || !realm || !Strcmp_charp(ent->realm, realm))
974             )
975             return ent;
976     }
977     return NULL;
978 }
979
980 int
981 find_auth_user_passwd(ParsedURL *pu, char *realm,
982                       Str *uname, Str *pwd, int is_proxy)
983 {
984     struct auth_pass *ent;
985
986     if (pu->user && pu->pass) {
987         *uname = Strnew_charp(pu->user);
988         *pwd = Strnew_charp(pu->pass);
989         return 1;
990     }
991     ent = find_auth_pass_entry(pu->host, pu->port, realm, pu->user, is_proxy);
992     if (ent) {
993         *uname = ent->uname;
994         *pwd = ent->pwd;
995         return 1;
996     }
997     return 0;
998 }
999
1000 void
1001 add_auth_user_passwd(ParsedURL *pu, char *realm, Str uname, Str pwd, 
1002                      int is_proxy)
1003 {
1004     struct auth_pass ent;
1005     memset(&ent, 0, sizeof(ent));
1006
1007     ent.is_proxy = is_proxy;
1008     ent.host = Strnew_charp(pu->host);
1009     ent.port = pu->port;
1010     ent.realm = Strnew_charp(realm);
1011     ent.uname = uname;
1012     ent.pwd = pwd;
1013     add_auth_pass_entry(&ent, 0, 1);
1014 }
1015
1016 void
1017 invalidate_auth_user_passwd(ParsedURL *pu, char *realm, Str uname, Str pwd, 
1018                             int is_proxy)
1019 {
1020     struct auth_pass *ent;
1021     ent = find_auth_pass_entry(pu->host, pu->port, realm, NULL, is_proxy);
1022     if (ent) {
1023         ent->bad = TRUE;
1024     }
1025     return;
1026 }
1027
1028 /* passwd */
1029 /*
1030  * machine <host>
1031  * host <host>
1032  * port <port>
1033  * proxy
1034  * path <file>  ; not used
1035  * realm <realm>
1036  * login <login>
1037  * passwd <passwd>
1038  * password <passwd>
1039  */
1040
1041 static Str
1042 next_token(Str arg)
1043 {
1044     Str narg = NULL;
1045     char *p, *q;
1046     if (arg == NULL || arg->length == 0)
1047         return NULL;
1048     p = arg->ptr;
1049     q = p;
1050     SKIP_NON_BLANKS(q);
1051     if (*q != '\0') {
1052         *q++ = '\0';
1053         SKIP_BLANKS(q);
1054         if (*q != '\0')
1055             narg = Strnew_charp(q);
1056     }
1057     return narg;
1058 }
1059
1060 static void
1061 parsePasswd(FILE * fp, int netrc)
1062 {
1063     struct auth_pass ent;
1064     Str line = NULL;
1065
1066     bzero(&ent, sizeof(struct auth_pass));
1067     while (1) {
1068         Str arg = NULL;
1069         char *p;
1070
1071         if (line == NULL || line->length == 0)
1072             line = Strfgets(fp);
1073         if (line->length == 0)
1074             break;
1075         Strchop(line);
1076         Strremovefirstspaces(line);
1077         p = line->ptr;
1078         if (*p == '#' || *p == '\0') {
1079             line = NULL;
1080             continue;           /* comment or empty line */
1081         }
1082         arg = next_token(line);
1083
1084         if (!strcmp(p, "machine") || !strcmp(p, "host")
1085             || (netrc && !strcmp(p, "default"))) {
1086             add_auth_pass_entry(&ent, netrc, 0);
1087             bzero(&ent, sizeof(struct auth_pass));
1088             if (netrc)
1089                 ent.port = 21;  /* XXX: getservbyname("ftp"); ? */
1090             if (strcmp(p, "default") != 0) {
1091                 line = next_token(arg);
1092                 ent.host = arg;
1093             }
1094             else {
1095                 line = arg;
1096             }
1097         }
1098         else if (!netrc && !strcmp(p, "port") && arg) {
1099             line = next_token(arg);
1100             ent.port = atoi(arg->ptr);
1101         }
1102         else if (!netrc && !strcmp(p, "proxy")) {
1103             ent.is_proxy = 1;
1104             line = arg;
1105         }
1106         else if (!netrc && !strcmp(p, "path")) {
1107             line = next_token(arg);
1108             /* ent.file = arg; */
1109         }
1110         else if (!netrc && !strcmp(p, "realm")) {
1111             /* XXX: rest of line becomes arg for realm */
1112             line = NULL;
1113             ent.realm = arg;
1114         }
1115         else if (!strcmp(p, "login")) {
1116             line = next_token(arg);
1117             ent.uname = arg;
1118         }
1119         else if (!strcmp(p, "password") || !strcmp(p, "passwd")) {
1120             line = next_token(arg);
1121             ent.pwd = arg;
1122         }
1123         else if (netrc && !strcmp(p, "machdef")) {
1124             while ((line = Strfgets(fp))->length != 0) {
1125                 if (*line->ptr == '\n')
1126                     break;
1127             }
1128             line = NULL;
1129         }
1130         else if (netrc && !strcmp(p, "account")) {
1131             /* ignore */
1132             line = next_token(arg);
1133         }
1134         else {
1135             /* ignore rest of line */
1136             line = NULL;
1137         }
1138     }
1139     add_auth_pass_entry(&ent, netrc, 0);
1140 }
1141
1142 /* FIXME: gettextize? */
1143 #define FILE_IS_READABLE_MSG "SECURITY NOTE: file %s must not be accessible by others"
1144
1145 FILE *
1146 openSecretFile(char *fname)
1147 {
1148     char *efname;
1149     struct stat st;
1150
1151     if (fname == NULL)
1152         return NULL;
1153     efname = expandPath(fname);
1154     if (stat(efname, &st) < 0)
1155         return NULL;
1156
1157     /* check permissions, if group or others readable or writable,
1158      * refuse it, because it's insecure.
1159      *
1160      * XXX: disable_secret_security_check will introduce some
1161      *    security issues, but on some platform such as Windows
1162      *    it's not possible (or feasible) to disable group|other
1163      *    readable and writable.
1164      *   [w3m-dev 03368][w3m-dev 03369][w3m-dev 03370]
1165      */
1166     if (disable_secret_security_check)
1167         /* do nothing */ ;
1168     else if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
1169         if (fmInitialized) {
1170             message(Sprintf(FILE_IS_READABLE_MSG, fname)->ptr, 0, 0);
1171             refresh();
1172         }
1173         else {
1174             fputs(Sprintf(FILE_IS_READABLE_MSG, fname)->ptr, stderr);
1175             fputc('\n', stderr);
1176         }
1177         sleep(2);
1178         return NULL;
1179     }
1180
1181     return fopen(efname, "r");
1182 }
1183
1184 void
1185 loadPasswd(void)
1186 {
1187     FILE *fp;
1188
1189     passwords = NULL;
1190     fp = openSecretFile(passwd_file);
1191     if (fp != NULL) {
1192         parsePasswd(fp, 0);
1193         fclose(fp);
1194     }
1195
1196     /* for FTP */
1197     fp = openSecretFile("~/.netrc");
1198     if (fp != NULL) {
1199         parsePasswd(fp, 1);
1200         fclose(fp);
1201     }
1202     return;
1203 }
1204
1205 /* get last modified time */
1206 char *
1207 last_modified(Buffer *buf)
1208 {
1209     TextListItem *ti;
1210     struct stat st;
1211
1212     if (buf->document_header) {
1213         for (ti = buf->document_header->first; ti; ti = ti->next) {
1214             if (strncasecmp(ti->ptr, "Last-modified: ", 15) == 0) {
1215                 return ti->ptr + 15;
1216             }
1217         }
1218         return "unknown";
1219     }
1220     else if (buf->currentURL.scheme == SCM_LOCAL) {
1221         if (stat(buf->currentURL.file, &st) < 0)
1222             return "unknown";
1223         return ctime(&st.st_mtime);
1224     }
1225     return "unknown";
1226 }
1227
1228 static char roman_num1[] = {
1229     'i', 'x', 'c', 'm', '*',
1230 };
1231 static char roman_num5[] = {
1232     'v', 'l', 'd', '*',
1233 };
1234
1235 static Str
1236 romanNum2(int l, int n)
1237 {
1238     Str s = Strnew();
1239
1240     switch (n) {
1241     case 1:
1242     case 2:
1243     case 3:
1244         for (; n > 0; n--)
1245             Strcat_char(s, roman_num1[l]);
1246         break;
1247     case 4:
1248         Strcat_char(s, roman_num1[l]);
1249         Strcat_char(s, roman_num5[l]);
1250         break;
1251     case 5:
1252     case 6:
1253     case 7:
1254     case 8:
1255         Strcat_char(s, roman_num5[l]);
1256         for (n -= 5; n > 0; n--)
1257             Strcat_char(s, roman_num1[l]);
1258         break;
1259     case 9:
1260         Strcat_char(s, roman_num1[l]);
1261         Strcat_char(s, roman_num1[l + 1]);
1262         break;
1263     }
1264     return s;
1265 }
1266
1267 Str
1268 romanNumeral(int n)
1269 {
1270     Str r = Strnew();
1271
1272     if (n <= 0)
1273         return r;
1274     if (n >= 4000) {
1275         Strcat_charp(r, "**");
1276         return r;
1277     }
1278     Strcat(r, romanNum2(3, n / 1000));
1279     Strcat(r, romanNum2(2, (n % 1000) / 100));
1280     Strcat(r, romanNum2(1, (n % 100) / 10));
1281     Strcat(r, romanNum2(0, n % 10));
1282
1283     return r;
1284 }
1285
1286 Str
1287 romanAlphabet(int n)
1288 {
1289     Str r = Strnew();
1290     int l;
1291     char buf[14];
1292
1293     if (n <= 0)
1294         return r;
1295
1296     l = 0;
1297     while (n) {
1298         buf[l++] = 'a' + (n - 1) % 26;
1299         n = (n - 1) / 26;
1300     }
1301     l--;
1302     for (; l >= 0; l--)
1303         Strcat_char(r, buf[l]);
1304
1305     return r;
1306 }
1307
1308 #ifndef SIGIOT
1309 #define SIGIOT SIGABRT
1310 #endif                          /* not SIGIOT */
1311
1312 static void
1313 reset_signals(void)
1314 {
1315 #ifdef SIGHUP
1316     mySignal(SIGHUP, SIG_DFL);  /* terminate process */
1317 #endif
1318     mySignal(SIGINT, SIG_DFL);  /* terminate process */
1319 #ifdef SIGQUIT
1320     mySignal(SIGQUIT, SIG_DFL); /* terminate process */
1321 #endif
1322     mySignal(SIGTERM, SIG_DFL); /* terminate process */
1323     mySignal(SIGILL, SIG_DFL);  /* create core image */
1324     mySignal(SIGIOT, SIG_DFL);  /* create core image */
1325     mySignal(SIGFPE, SIG_DFL);  /* create core image */
1326 #ifdef SIGBUS
1327     mySignal(SIGBUS, SIG_DFL);  /* create core image */
1328 #endif                          /* SIGBUS */
1329 #ifdef SIGCHLD
1330     mySignal(SIGCHLD, SIG_IGN);
1331 #endif
1332 #ifdef SIGPIPE
1333     mySignal(SIGPIPE, SIG_IGN);
1334 #endif
1335 }
1336
1337 #ifndef FOPEN_MAX
1338 #define FOPEN_MAX 1024          /* XXX */
1339 #endif
1340
1341 static void
1342 close_all_fds_except(int i, int f)
1343 {
1344     switch (i) {                /* fall through */
1345     case 0:
1346         dup2(open(DEV_NULL_PATH, O_RDONLY), 0);
1347     case 1:
1348         dup2(open(DEV_NULL_PATH, O_WRONLY), 1);
1349     case 2:
1350         dup2(open(DEV_NULL_PATH, O_WRONLY), 2);
1351     }
1352     /* close all other file descriptors (socket, ...) */
1353     for (i = 3; i < FOPEN_MAX; i++) {
1354         if (i != f)
1355             close(i);
1356     }
1357 }
1358
1359 void
1360 setup_child(int child, int i, int f)
1361 {
1362     reset_signals();
1363     mySignal(SIGINT, SIG_IGN);
1364 #ifndef __MINGW32_VERSION
1365     if (!child)
1366         SETPGRP();
1367 #endif /* __MINGW32_VERSION */
1368     close_tty();
1369     close_all_fds_except(i, f);
1370     QuietMessage = TRUE;
1371     fmInitialized = FALSE;
1372     TrapSignal = FALSE;
1373 }
1374
1375 #ifndef __MINGW32_VERSION
1376 pid_t
1377 open_pipe_rw(FILE ** fr, FILE ** fw)
1378 {
1379     int fdr[2];
1380     int fdw[2];
1381     pid_t pid;
1382
1383     if (fr && pipe(fdr) < 0)
1384         goto err0;
1385     if (fw && pipe(fdw) < 0)
1386         goto err1;
1387
1388     flush_tty();
1389     pid = fork();
1390     if (pid < 0)
1391         goto err2;
1392     if (pid == 0) {
1393         /* child */
1394         if (fr) {
1395             close(fdr[0]);
1396             dup2(fdr[1], 1);
1397         }
1398         if (fw) {
1399             close(fdw[1]);
1400             dup2(fdw[0], 0);
1401         }
1402     }
1403     else {
1404         if (fr) {
1405             close(fdr[1]);
1406             if (*fr == stdin)
1407                 dup2(fdr[0], 0);
1408             else
1409                 *fr = fdopen(fdr[0], "r");
1410         }
1411         if (fw) {
1412             close(fdw[0]);
1413             if (*fw == stdout)
1414                 dup2(fdw[1], 1);
1415             else
1416                 *fw = fdopen(fdw[1], "w");
1417         }
1418     }
1419     return pid;
1420   err2:
1421     if (fw) {
1422         close(fdw[0]);
1423         close(fdw[1]);
1424     }
1425   err1:
1426     if (fr) {
1427         close(fdr[0]);
1428         close(fdr[1]);
1429     }
1430   err0:
1431     return (pid_t) - 1;
1432 }
1433 #endif /* __MINGW32_VERSION */
1434
1435 void
1436 myExec(char *command)
1437 {
1438     mySignal(SIGINT, SIG_DFL);
1439     execl("/bin/sh", "sh", "-c", command, NULL);
1440     exit(127);
1441 }
1442
1443 void
1444 mySystem(char *command, int background)
1445 {
1446 #ifndef __MINGW32_VERSION
1447     if (background) {
1448 #ifndef __EMX__
1449         flush_tty();
1450         if (!fork()) {
1451             setup_child(FALSE, 0, -1);
1452             myExec(command);
1453         }
1454 #else
1455         Str cmd = Strnew_charp("start /f ");
1456         Strcat_charp(cmd, command);
1457         system(cmd->ptr);
1458 #endif
1459     }
1460     else
1461 #endif /* __MINGW32_VERSION */
1462         system(command);
1463 }
1464
1465 Str
1466 myExtCommand(char *cmd, char *arg, int redirect)
1467 {
1468     Str tmp = NULL;
1469     char *p;
1470     int set_arg = FALSE;
1471
1472     for (p = cmd; *p; p++) {
1473         if (*p == '%' && *(p + 1) == 's' && !set_arg) {
1474             if (tmp == NULL)
1475                 tmp = Strnew_charp_n(cmd, (int)(p - cmd));
1476             Strcat_charp(tmp, arg);
1477             set_arg = TRUE;
1478             p++;
1479         }
1480         else {
1481             if (tmp)
1482                 Strcat_char(tmp, *p);
1483         }
1484     }
1485     if (!set_arg) {
1486         if (redirect)
1487             tmp = Strnew_m_charp("(", cmd, ") < ", arg, NULL);
1488         else
1489             tmp = Strnew_m_charp(cmd, " ", arg, NULL);
1490     }
1491     return tmp;
1492 }
1493
1494 Str
1495 myEditor(char *cmd, char *file, int line)
1496 {
1497     Str tmp = NULL;
1498     char *p;
1499     int set_file = FALSE, set_line = FALSE;
1500
1501     for (p = cmd; *p; p++) {
1502         if (*p == '%' && *(p + 1) == 's' && !set_file) {
1503             if (tmp == NULL)
1504                 tmp = Strnew_charp_n(cmd, (int)(p - cmd));
1505             Strcat_charp(tmp, file);
1506             set_file = TRUE;
1507             p++;
1508         }
1509         else if (*p == '%' && *(p + 1) == 'd' && !set_line && line > 0) {
1510             if (tmp == NULL)
1511                 tmp = Strnew_charp_n(cmd, (int)(p - cmd));
1512             Strcat(tmp, Sprintf("%d", line));
1513             set_line = TRUE;
1514             p++;
1515         }
1516         else {
1517             if (tmp)
1518                 Strcat_char(tmp, *p);
1519         }
1520     }
1521     if (!set_file) {
1522         if (tmp == NULL)
1523             tmp = Strnew_charp(cmd);
1524         if (!set_line && line > 1 && strcasestr(cmd, "vi"))
1525             Strcat(tmp, Sprintf(" +%d", line));
1526         Strcat_m_charp(tmp, " ", file, NULL);
1527     }
1528     return tmp;
1529 }
1530
1531 #ifdef __MINGW32_VERSION
1532 char *
1533 expandName(char *name)
1534 {
1535     return getenv("HOME");
1536 }
1537 #else
1538 char *
1539 expandName(char *name)
1540 {
1541     char *p;
1542     struct passwd *passent, *getpwnam(const char *);
1543     Str extpath = NULL;
1544
1545     if (name == NULL)
1546         return NULL;
1547     p = name;
1548     if (*p == '/') {
1549         if ((*(p + 1) == '~' && IS_ALPHA(*(p + 2)))
1550             && personal_document_root) {
1551             char *q;
1552             p += 2;
1553             q = strchr(p, '/');
1554             if (q) {            /* /~user/dir... */
1555                 passent = getpwnam(allocStr(p, q - p));
1556                 p = q;
1557             }
1558             else {              /* /~user */
1559                 passent = getpwnam(p);
1560                 p = "";
1561             }
1562             if (!passent)
1563                 goto rest;
1564             extpath = Strnew_m_charp(passent->pw_dir, "/",
1565                                      personal_document_root, NULL);
1566             if (*personal_document_root == '\0' && *p == '/')
1567                 p++;
1568         }
1569         else
1570             goto rest;
1571         if (Strcmp_charp(extpath, "/") == 0 && *p == '/')
1572             p++;
1573         Strcat_charp(extpath, p);
1574         return extpath->ptr;
1575     }
1576     else
1577         return expandPath(p);
1578   rest:
1579     return name;
1580 }
1581 #endif
1582
1583 char *
1584 file_to_url(char *file)
1585 {
1586     Str tmp;
1587 #ifdef SUPPORT_DOS_DRIVE_PREFIX
1588     char *drive = NULL;
1589 #endif
1590 #ifdef SUPPORT_NETBIOS_SHARE
1591     char *host = NULL;
1592 #endif
1593
1594     file = expandPath(file);
1595 #ifdef SUPPORT_NETBIOS_SHARE
1596     if (file[0] == '/' && file[1] == '/') {
1597         char *p;
1598         file += 2;
1599         if (*file) {
1600             p = strchr(file, '/');
1601             if (p != NULL && p != file) {
1602                 host = allocStr(file, (p - file));
1603                 file = p;
1604             }
1605         }
1606     }
1607 #endif
1608 #ifdef SUPPORT_DOS_DRIVE_PREFIX
1609     if (IS_ALPHA(file[0]) && file[1] == ':') {
1610         drive = allocStr(file, 2);
1611         file += 2;
1612     }
1613     else
1614 #endif
1615     if (file[0] != '/') {
1616         tmp = Strnew_charp(CurrentDir);
1617         if (Strlastchar(tmp) != '/')
1618             Strcat_char(tmp, '/');
1619         Strcat_charp(tmp, file);
1620         file = tmp->ptr;
1621     }
1622     tmp = Strnew_charp("file://");
1623 #ifdef SUPPORT_NETBIOS_SHARE
1624     if (host)
1625         Strcat_charp(tmp, host);
1626 #endif
1627 #ifdef SUPPORT_DOS_DRIVE_PREFIX
1628     if (drive)
1629         Strcat_charp(tmp, drive);
1630 #endif
1631     Strcat_charp(tmp, file_quote(cleanupName(file)));
1632     return tmp->ptr;
1633 }
1634
1635 #ifdef USE_M17N
1636 char *
1637 url_unquote_conv(char *url, wc_ces charset)
1638 #else
1639 char *
1640 url_unquote_conv0(char *url)
1641 #endif
1642 {
1643 #ifdef USE_M17N
1644     wc_uint8 old_auto_detect = WcOption.auto_detect;
1645 #endif
1646     Str tmp;
1647     tmp = Str_url_unquote(Strnew_charp(url), FALSE, TRUE);
1648 #ifdef USE_M17N
1649     if (!charset || charset == WC_CES_US_ASCII)
1650         charset = SystemCharset;
1651     WcOption.auto_detect = WC_OPT_DETECT_ON;
1652     tmp = convertLine(NULL, tmp, RAW_MODE, &charset, charset);
1653     WcOption.auto_detect = old_auto_detect;
1654 #endif
1655     return tmp->ptr;
1656 }
1657
1658 static char *tmpf_base[MAX_TMPF_TYPE] = {
1659     "tmp", "src", "frame", "cache", "cookie",
1660 };
1661 static unsigned int tmpf_seq[MAX_TMPF_TYPE];
1662
1663 Str
1664 tmpfname(int type, char *ext)
1665 {
1666     Str tmpf;
1667     tmpf = Sprintf("%s/w3m%s%d-%d%s",
1668                    tmp_dir,
1669                    tmpf_base[type],
1670                    CurrentPid, tmpf_seq[type]++, (ext) ? ext : "");
1671     pushText(fileToDelete, tmpf->ptr);
1672     return tmpf;
1673 }
1674
1675 static char *monthtbl[] = {
1676     "Jan", "Feb", "Mar", "Apr", "May", "Jun",
1677     "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
1678 };
1679
1680 static int
1681 get_day(char **s)
1682 {
1683     Str tmp = Strnew();
1684     int day;
1685     char *ss = *s;
1686
1687     if (!**s)
1688         return -1;
1689
1690     while (**s && IS_DIGIT(**s))
1691         Strcat_char(tmp, *((*s)++));
1692
1693     day = atoi(tmp->ptr);
1694
1695     if (day < 1 || day > 31) {
1696         *s = ss;
1697         return -1;
1698     }
1699     return day;
1700 }
1701
1702 static int
1703 get_month(char **s)
1704 {
1705     Str tmp = Strnew();
1706     int mon;
1707     char *ss = *s;
1708
1709     if (!**s)
1710         return -1;
1711
1712     while (**s && IS_DIGIT(**s))
1713         Strcat_char(tmp, *((*s)++));
1714     if (tmp->length > 0) {
1715         mon = atoi(tmp->ptr);
1716     }
1717     else {
1718         while (**s && IS_ALPHA(**s))
1719             Strcat_char(tmp, *((*s)++));
1720         for (mon = 1; mon <= 12; mon++) {
1721             if (strncmp(tmp->ptr, monthtbl[mon - 1], 3) == 0)
1722                 break;
1723         }
1724     }
1725     if (mon < 1 || mon > 12) {
1726         *s = ss;
1727         return -1;
1728     }
1729     return mon;
1730 }
1731
1732 static int
1733 get_year(char **s)
1734 {
1735     Str tmp = Strnew();
1736     int year;
1737     char *ss = *s;
1738
1739     if (!**s)
1740         return -1;
1741
1742     while (**s && IS_DIGIT(**s))
1743         Strcat_char(tmp, *((*s)++));
1744     if (tmp->length != 2 && tmp->length != 4) {
1745         *s = ss;
1746         return -1;
1747     }
1748
1749     year = atoi(tmp->ptr);
1750     if (tmp->length == 2) {
1751         if (year >= 70)
1752             year += 1900;
1753         else
1754             year += 2000;
1755     }
1756     return year;
1757 }
1758
1759 static int
1760 get_time(char **s, int *hour, int *min, int *sec)
1761 {
1762     Str tmp = Strnew();
1763     char *ss = *s;
1764
1765     if (!**s)
1766         return -1;
1767
1768     while (**s && IS_DIGIT(**s))
1769         Strcat_char(tmp, *((*s)++));
1770     if (**s != ':') {
1771         *s = ss;
1772         return -1;
1773     }
1774     *hour = atoi(tmp->ptr);
1775
1776     (*s)++;
1777     Strclear(tmp);
1778     while (**s && IS_DIGIT(**s))
1779         Strcat_char(tmp, *((*s)++));
1780     if (**s != ':') {
1781         *s = ss;
1782         return -1;
1783     }
1784     *min = atoi(tmp->ptr);
1785
1786     (*s)++;
1787     Strclear(tmp);
1788     while (**s && IS_DIGIT(**s))
1789         Strcat_char(tmp, *((*s)++));
1790     *sec = atoi(tmp->ptr);
1791
1792     if (*hour < 0 || *hour >= 24 ||
1793         *min < 0 || *min >= 60 || *sec < 0 || *sec >= 60) {
1794         *s = ss;
1795         return -1;
1796     }
1797     return 0;
1798 }
1799
1800 static int
1801 get_zone(char **s, int *z_hour, int *z_min)
1802 {
1803     Str tmp = Strnew();
1804     int zone;
1805     char *ss = *s;
1806
1807     if (!**s)
1808         return -1;
1809
1810     if (**s == '+' || **s == '-')
1811         Strcat_char(tmp, *((*s)++));
1812     while (**s && IS_DIGIT(**s))
1813         Strcat_char(tmp, *((*s)++));
1814     if (!(tmp->length == 4 && IS_DIGIT(*ss)) &&
1815         !(tmp->length == 5 && (*ss == '+' || *ss == '-'))) {
1816         *s = ss;
1817         return -1;
1818     }
1819
1820     zone = atoi(tmp->ptr);
1821     *z_hour = zone / 100;
1822     *z_min = zone - (zone / 100) * 100;
1823     return 0;
1824 }
1825
1826 /* RFC 1123 or RFC 850 or ANSI C asctime() format string -> time_t */
1827 time_t
1828 mymktime(char *timestr)
1829 {
1830     char *s;
1831     int day, mon, year, hour, min, sec, z_hour = 0, z_min = 0;
1832
1833     if (!(timestr && *timestr))
1834         return -1;
1835     s = timestr;
1836
1837 #ifdef DEBUG
1838     fprintf(stderr, "mktime: %s\n", timestr);
1839 #endif                          /* DEBUG */
1840
1841     while (*s && IS_ALPHA(*s))
1842         s++;
1843     while (*s && !IS_ALNUM(*s))
1844         s++;
1845
1846     if (IS_DIGIT(*s)) {
1847         /* RFC 1123 or RFC 850 format */
1848         if ((day = get_day(&s)) == -1)
1849             return -1;
1850
1851         while (*s && !IS_ALNUM(*s))
1852             s++;
1853         if ((mon = get_month(&s)) == -1)
1854             return -1;
1855
1856         while (*s && !IS_DIGIT(*s))
1857             s++;
1858         if ((year = get_year(&s)) == -1)
1859             return -1;
1860
1861         while (*s && !IS_DIGIT(*s))
1862             s++;
1863         if (!*s) {
1864             hour = 0;
1865             min = 0;
1866             sec = 0;
1867         }
1868         else {
1869             if (get_time(&s, &hour, &min, &sec) == -1)
1870                 return -1;
1871             while (*s && !IS_DIGIT(*s) && *s != '+' && *s != '-')
1872                 s++;
1873             get_zone(&s, &z_hour, &z_min);
1874         }
1875     }
1876     else {
1877         /* ANSI C asctime() format. */
1878         while (*s && !IS_ALNUM(*s))
1879             s++;
1880         if ((mon = get_month(&s)) == -1)
1881             return -1;
1882
1883         while (*s && !IS_DIGIT(*s))
1884             s++;
1885         if ((day = get_day(&s)) == -1)
1886             return -1;
1887
1888         while (*s && !IS_DIGIT(*s))
1889             s++;
1890         if (get_time(&s, &hour, &min, &sec) == -1)
1891             return -1;
1892
1893         while (*s && !IS_DIGIT(*s))
1894             s++;
1895         if ((year = get_year(&s)) == -1)
1896             return -1;
1897     }
1898 #ifdef DEBUG
1899     fprintf(stderr,
1900             "year=%d month=%d day=%d hour:min:sec=%d:%d:%d zone=%d:%d\n", year,
1901             mon, day, hour, min, sec, z_hour, z_min);
1902 #endif                          /* DEBUG */
1903
1904     mon -= 3;
1905     if (mon < 0) {
1906         mon += 12;
1907         year--;
1908     }
1909     day += (year - 1968) * 1461 / 4;
1910     day += ((((mon * 153) + 2) / 5) - 672);
1911     hour -= z_hour;
1912     min -= z_min;
1913     return (time_t) ((day * 60 * 60 * 24) +
1914                      (hour * 60 * 60) + (min * 60) + sec);
1915 }
1916
1917 #ifdef USE_COOKIE
1918 #ifdef INET6
1919 #include <sys/socket.h>
1920 #endif                          /* INET6 */
1921 #ifndef __MINGW32_VERSION
1922 #include <netdb.h>
1923 #else
1924 #include <winsock.h>
1925 #endif
1926 char *
1927 FQDN(char *host)
1928 {
1929     char *p;
1930 #ifndef INET6
1931     struct hostent *entry;
1932 #else                           /* INET6 */
1933     int *af;
1934 #endif                          /* INET6 */
1935
1936     if (host == NULL)
1937         return NULL;
1938
1939     if (strcasecmp(host, "localhost") == 0)
1940         return host;
1941
1942     for (p = host; *p && *p != '.'; p++) ;
1943
1944     if (*p == '.')
1945         return host;
1946
1947 #ifndef INET6
1948     if (!(entry = gethostbyname(host)))
1949         return NULL;
1950
1951     return allocStr(entry->h_name, -1);
1952 #else                           /* INET6 */
1953     for (af = ai_family_order_table[DNS_order];; af++) {
1954         int error;
1955         struct addrinfo hints;
1956         struct addrinfo *res, *res0;
1957         char *namebuf;
1958
1959         memset(&hints, 0, sizeof(hints));
1960         hints.ai_flags = AI_CANONNAME;
1961         hints.ai_family = *af;
1962         hints.ai_socktype = SOCK_STREAM;
1963         error = getaddrinfo(host, NULL, &hints, &res0);
1964         if (error) {
1965             if (*af == PF_UNSPEC) {
1966                 /* all done */
1967                 break;
1968             }
1969             /* try next address family */
1970             continue;
1971         }
1972         for (res = res0; res != NULL; res = res->ai_next) {
1973             if (res->ai_canonname) {
1974                 /* found */
1975                 namebuf = strdup(res->ai_canonname);
1976                 freeaddrinfo(res0);
1977                 return namebuf;
1978             }
1979         }
1980         freeaddrinfo(res0);
1981         if (*af == PF_UNSPEC) {
1982             break;
1983         }
1984     }
1985     /* all failed */
1986     return NULL;
1987 #endif                          /* INET6 */
1988 }
1989
1990 #endif                          /* USE_COOKIE */
1991
1992 void (*mySignal(int signal_number, void (*action) (int))) (int) {
1993 #ifdef  SA_RESTART
1994     struct sigaction new_action, old_action;
1995
1996     sigemptyset(&new_action.sa_mask);
1997     new_action.sa_handler = action;
1998     if (signal_number == SIGALRM) {
1999 #ifdef  SA_INTERRUPT
2000         new_action.sa_flags = SA_INTERRUPT;
2001 #else
2002         new_action.sa_flags = 0;
2003 #endif
2004     }
2005     else {
2006         new_action.sa_flags = SA_RESTART;
2007     }
2008     sigaction(signal_number, &new_action, &old_action);
2009     return (old_action.sa_handler);
2010 #else
2011     return (signal(signal_number, action));
2012 #endif
2013 }