etc.c (38903B)
1 /* $Id$ */ 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, "<"); 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 }