|
|
1.1 ! root 1: #ifndef lint ! 2: static char *sccsid = "@(#)aux.c 2.11 (Berkeley) 8/11/83"; ! 3: #endif ! 4: ! 5: #include "rcv.h" ! 6: #include <sys/stat.h> ! 7: #include <ctype.h> ! 8: ! 9: /* ! 10: * Mail -- a mail program ! 11: * ! 12: * Auxiliary functions. ! 13: */ ! 14: ! 15: /* ! 16: * Return a pointer to a dynamic copy of the argument. ! 17: */ ! 18: ! 19: char * ! 20: savestr(str) ! 21: char *str; ! 22: { ! 23: register char *cp, *cp2, *top; ! 24: ! 25: for (cp = str; *cp; cp++) ! 26: ; ! 27: top = salloc(cp-str + 1); ! 28: if (top == NOSTR) ! 29: return(NOSTR); ! 30: for (cp = str, cp2 = top; *cp; cp++) ! 31: *cp2++ = *cp; ! 32: *cp2 = 0; ! 33: return(top); ! 34: } ! 35: ! 36: /* ! 37: * Copy the name from the passed header line into the passed ! 38: * name buffer. Null pad the name buffer. ! 39: */ ! 40: ! 41: copyname(linebuf, nbuf) ! 42: char *linebuf, *nbuf; ! 43: { ! 44: register char *cp, *cp2; ! 45: ! 46: for (cp = linebuf + 5, cp2 = nbuf; *cp != ' ' && cp2-nbuf < 8; cp++) ! 47: *cp2++ = *cp; ! 48: while (cp2-nbuf < 8) ! 49: *cp2++ = 0; ! 50: } ! 51: ! 52: /* ! 53: * Announce a fatal error and die. ! 54: */ ! 55: ! 56: panic(str) ! 57: char *str; ! 58: { ! 59: prs("panic: "); ! 60: prs(str); ! 61: prs("\n"); ! 62: exit(1); ! 63: } ! 64: ! 65: /* ! 66: * Catch stdio errors and report them more nicely. ! 67: */ ! 68: ! 69: _error(str) ! 70: char *str; ! 71: { ! 72: prs("Stdio Error: "); ! 73: prs(str); ! 74: prs("\n"); ! 75: abort(); ! 76: } ! 77: ! 78: /* ! 79: * Print a string on diagnostic output. ! 80: */ ! 81: ! 82: prs(str) ! 83: char *str; ! 84: { ! 85: register char *s; ! 86: ! 87: for (s = str; *s; s++) ! 88: ; ! 89: write(2, str, s-str); ! 90: } ! 91: ! 92: /* ! 93: * Touch the named message by setting its MTOUCH flag. ! 94: * Touched messages have the effect of not being sent ! 95: * back to the system mailbox on exit. ! 96: */ ! 97: ! 98: touch(mesg) ! 99: { ! 100: register struct message *mp; ! 101: ! 102: if (mesg < 1 || mesg > msgCount) ! 103: return; ! 104: mp = &message[mesg-1]; ! 105: mp->m_flag |= MTOUCH; ! 106: if ((mp->m_flag & MREAD) == 0) ! 107: mp->m_flag |= MREAD|MSTATUS; ! 108: } ! 109: ! 110: /* ! 111: * Test to see if the passed file name is a directory. ! 112: * Return true if it is. ! 113: */ ! 114: ! 115: isdir(name) ! 116: char name[]; ! 117: { ! 118: struct stat sbuf; ! 119: ! 120: if (stat(name, &sbuf) < 0) ! 121: return(0); ! 122: return((sbuf.st_mode & S_IFMT) == S_IFDIR); ! 123: } ! 124: ! 125: /* ! 126: * Count the number of arguments in the given string raw list. ! 127: */ ! 128: ! 129: argcount(argv) ! 130: char **argv; ! 131: { ! 132: register char **ap; ! 133: ! 134: for (ap = argv; *ap != NOSTR; ap++) ! 135: ; ! 136: return(ap-argv); ! 137: } ! 138: ! 139: /* ! 140: * Given a file address, determine the ! 141: * block number it represents. ! 142: */ ! 143: ! 144: blockof(off) ! 145: off_t off; ! 146: { ! 147: off_t a; ! 148: ! 149: a = off >> 9; ! 150: a &= 077777; ! 151: return((int) a); ! 152: } ! 153: ! 154: /* ! 155: * Take a file address, and determine ! 156: * its offset in the current block. ! 157: */ ! 158: ! 159: offsetof(off) ! 160: off_t off; ! 161: { ! 162: off_t a; ! 163: ! 164: a = off & 0777; ! 165: return((int) a); ! 166: } ! 167: ! 168: /* ! 169: * Determine if the passed file is actually a tty, via a call to ! 170: * gtty. This is not totally reliable, but . . . ! 171: */ ! 172: ! 173: isatty(f) ! 174: { ! 175: struct sgttyb buf; ! 176: ! 177: if (gtty(f, &buf) < 0) ! 178: return(0); ! 179: return(1); ! 180: } ! 181: ! 182: /* ! 183: * Return the desired header line from the passed message ! 184: * pointer (or NOSTR if the desired header field is not available). ! 185: */ ! 186: ! 187: char * ! 188: hfield(field, mp) ! 189: char field[]; ! 190: struct message *mp; ! 191: { ! 192: register FILE *ibuf; ! 193: char linebuf[LINESIZE]; ! 194: register int lc; ! 195: ! 196: ibuf = setinput(mp); ! 197: if ((lc = mp->m_lines) <= 0) ! 198: return(NOSTR); ! 199: if (readline(ibuf, linebuf) < 0) ! 200: return(NOSTR); ! 201: lc--; ! 202: do { ! 203: lc = gethfield(ibuf, linebuf, lc); ! 204: if (lc == -1) ! 205: return(NOSTR); ! 206: #if defined(USGFROM) /* mjm: #ifdef --> #if */ ! 207: /* ! 208: * The check against 'FROM:' is an icky kludge to prevent ! 209: * Mail from accepting the USG 'FROM:' field, their answer ! 210: * to everyone else's 'Full-name:' field, as a valid From ! 211: * line. Otherwise, Mail would try to respond to some ! 212: * truly fascinating, but unfortunately invalid, addresses! ! 213: * mjm: "FROM:" --> "From:" ! 214: */ ! 215: if (ishfield(linebuf, field) && strncmp(linebuf, "From:", 5)) ! 216: #else /* !defined(USGFROM) */ ! 217: if (ishfield(linebuf, field)) ! 218: #endif /* defined(USGFROM) */ ! 219: return(savestr(hcontents(linebuf))); ! 220: } while (lc > 0); ! 221: return(NOSTR); ! 222: } ! 223: ! 224: /* ! 225: * Return the next header field found in the given message. ! 226: * Return > 0 if something found, <= 0 elsewise. ! 227: * Must deal with \ continuations & other such fraud. ! 228: */ ! 229: ! 230: gethfield(f, linebuf, rem) ! 231: register FILE *f; ! 232: char linebuf[]; ! 233: register int rem; ! 234: { ! 235: char line2[LINESIZE]; ! 236: long loc; ! 237: register char *cp, *cp2; ! 238: register int c; ! 239: ! 240: ! 241: for (;;) { ! 242: if (rem <= 0) ! 243: return(-1); ! 244: if (readline(f, linebuf) < 0) ! 245: return(-1); ! 246: rem--; ! 247: if (strlen(linebuf) == 0) ! 248: return(-1); ! 249: if (isspace(linebuf[0])) ! 250: continue; ! 251: if (linebuf[0] == '>') ! 252: continue; ! 253: cp = index(linebuf, ':'); ! 254: if (cp == NOSTR) ! 255: continue; ! 256: for (cp2 = linebuf; cp2 < cp; cp2++) ! 257: if (isdigit(*cp2)) ! 258: continue; ! 259: ! 260: /* ! 261: * I guess we got a headline. ! 262: * Handle wraparounding ! 263: */ ! 264: ! 265: for (;;) { ! 266: if (rem <= 0) ! 267: break; ! 268: #ifdef CANTELL ! 269: loc = ftell(f); ! 270: if (readline(f, line2) < 0) ! 271: break; ! 272: rem--; ! 273: if (!isspace(line2[0])) { ! 274: fseek(f, loc, 0); ! 275: rem++; ! 276: break; ! 277: } ! 278: #else ! 279: c = getc(f); ! 280: ungetc(c, f); ! 281: if (!isspace(c) || c == '\n') ! 282: break; ! 283: if (readline(f, line2) < 0) ! 284: break; ! 285: rem--; ! 286: #endif ! 287: cp2 = line2; ! 288: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++) ! 289: ; ! 290: if (strlen(linebuf) + strlen(cp2) >= LINESIZE-2) ! 291: break; ! 292: cp = &linebuf[strlen(linebuf)]; ! 293: while (cp > linebuf && ! 294: (isspace(cp[-1]) || cp[-1] == '\\')) ! 295: cp--; ! 296: *cp++ = ' '; ! 297: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++) ! 298: ; ! 299: strcpy(cp, cp2); ! 300: } ! 301: if ((c = strlen(linebuf)) > 0) { ! 302: cp = &linebuf[c-1]; ! 303: while (cp > linebuf && isspace(*cp)) ! 304: cp--; ! 305: *++cp = 0; ! 306: } ! 307: return(rem); ! 308: } ! 309: /* NOTREACHED */ ! 310: } ! 311: ! 312: /* ! 313: * Check whether the passed line is a header line of ! 314: * the desired breed. ! 315: */ ! 316: ! 317: ishfield(linebuf, field) ! 318: char linebuf[], field[]; ! 319: { ! 320: register char *cp; ! 321: register int c; ! 322: ! 323: if ((cp = index(linebuf, ':')) == NOSTR) ! 324: return(0); ! 325: if (cp == linebuf) ! 326: return(0); ! 327: cp--; ! 328: while (cp > linebuf && isspace(*cp)) ! 329: cp--; ! 330: c = *++cp; ! 331: *cp = 0; ! 332: if (icequal(linebuf ,field)) { ! 333: *cp = c; ! 334: return(1); ! 335: } ! 336: *cp = c; ! 337: return(0); ! 338: } ! 339: ! 340: /* ! 341: * Extract the non label information from the given header field ! 342: * and return it. ! 343: */ ! 344: ! 345: char * ! 346: hcontents(hfield) ! 347: char hfield[]; ! 348: { ! 349: register char *cp; ! 350: ! 351: if ((cp = index(hfield, ':')) == NOSTR) ! 352: return(NOSTR); ! 353: cp++; ! 354: while (*cp && isspace(*cp)) ! 355: cp++; ! 356: return(cp); ! 357: } ! 358: ! 359: /* ! 360: * Compare two strings, ignoring case. ! 361: */ ! 362: ! 363: icequal(s1, s2) ! 364: register char *s1, *s2; ! 365: { ! 366: ! 367: while (raise(*s1++) == raise(*s2)) ! 368: if (*s2++ == 0) ! 369: return(1); ! 370: return(0); ! 371: } ! 372: ! 373: /* ! 374: * Copy a string, lowercasing it as we go. ! 375: */ ! 376: istrcpy(dest, src) ! 377: char *dest, *src; ! 378: { ! 379: register char *cp, *cp2; ! 380: ! 381: cp2 = dest; ! 382: cp = src; ! 383: do { ! 384: *cp2++ = little(*cp); ! 385: } while (*cp++ != 0); ! 386: } ! 387: ! 388: /* ! 389: * The following code deals with input stacking to do source ! 390: * commands. All but the current file pointer are saved on ! 391: * the stack. ! 392: */ ! 393: ! 394: static int ssp = -1; /* Top of file stack */ ! 395: struct sstack { ! 396: FILE *s_file; /* File we were in. */ ! 397: int s_cond; /* Saved state of conditionals */ ! 398: int s_loading; /* Loading .mailrc, etc. */ ! 399: } sstack[_NFILE]; ! 400: ! 401: /* ! 402: * Pushdown current input file and switch to a new one. ! 403: * Set the global flag "sourcing" so that others will realize ! 404: * that they are no longer reading from a tty (in all probability). ! 405: */ ! 406: ! 407: source(name) ! 408: char name[]; ! 409: { ! 410: register FILE *fi; ! 411: register char *cp; ! 412: ! 413: if ((cp = expand(name)) == NOSTR) ! 414: return(1); ! 415: if ((fi = fopen(cp, "r")) == NULL) { ! 416: perror(cp); ! 417: return(1); ! 418: } ! 419: if (ssp >= _NFILE-2) { ! 420: printf("Too much \"sourcing\" going on.\n"); ! 421: fclose(fi); ! 422: return(1); ! 423: } ! 424: sstack[++ssp].s_file = input; ! 425: sstack[ssp].s_cond = cond; ! 426: sstack[ssp].s_loading = loading; ! 427: loading = 0; ! 428: cond = CANY; ! 429: input = fi; ! 430: sourcing++; ! 431: return(0); ! 432: } ! 433: ! 434: /* ! 435: * Source a file, but do nothing if the file cannot be opened. ! 436: */ ! 437: ! 438: source1(name) ! 439: char name[]; ! 440: { ! 441: register int f; ! 442: ! 443: if ((f = open(name, 0)) < 0) ! 444: return(0); ! 445: close(f); ! 446: source(name); ! 447: } ! 448: ! 449: /* ! 450: * Pop the current input back to the previous level. ! 451: * Update the "sourcing" flag as appropriate. ! 452: */ ! 453: ! 454: unstack() ! 455: { ! 456: if (ssp < 0) { ! 457: printf("\"Source\" stack over-pop.\n"); ! 458: sourcing = 0; ! 459: return(1); ! 460: } ! 461: fclose(input); ! 462: if (cond != CANY) ! 463: printf("Unmatched \"if\"\n"); ! 464: cond = sstack[ssp].s_cond; ! 465: loading = sstack[ssp].s_loading; ! 466: input = sstack[ssp--].s_file; ! 467: if (ssp < 0) ! 468: sourcing = loading; ! 469: return(0); ! 470: } ! 471: ! 472: /* ! 473: * Touch the indicated file. ! 474: * This is nifty for the shell. ! 475: * If we have the utime() system call, this is better served ! 476: * by using that, since it will work for empty files. ! 477: * On non-utime systems, we must sleep a second, then read. ! 478: */ ! 479: ! 480: alter(name) ! 481: char name[]; ! 482: { ! 483: #ifdef UTIME ! 484: struct stat statb; ! 485: long time(); ! 486: time_t time_p[2]; ! 487: #else ! 488: register int pid, f; ! 489: char w; ! 490: #endif UTIME ! 491: ! 492: #ifdef UTIME ! 493: if (stat(name, &statb) < 0) ! 494: return; ! 495: time_p[0] = time((long *) 0) + 1; ! 496: time_p[1] = statb.st_mtime; ! 497: utime(name, time_p); ! 498: #else ! 499: sleep(1); ! 500: if ((f = open(name, 0)) < 0) ! 501: return; ! 502: read(f, &w, 1); ! 503: exit(0); ! 504: #endif ! 505: } ! 506: ! 507: /* ! 508: * Examine the passed line buffer and ! 509: * return true if it is all blanks and tabs. ! 510: */ ! 511: ! 512: blankline(linebuf) ! 513: char linebuf[]; ! 514: { ! 515: register char *cp; ! 516: ! 517: for (cp = linebuf; *cp; cp++) ! 518: if (!any(*cp, " \t")) ! 519: return(0); ! 520: return(1); ! 521: } ! 522: ! 523: /* ! 524: * Get sender's name from this message. If the message has ! 525: * a bunch of arpanet stuff in it, we may have to skin the name ! 526: * before returning it. ! 527: */ ! 528: char * ! 529: nameof(mp, reptype) ! 530: register struct message *mp; ! 531: { ! 532: register char *cp, *cp2; ! 533: ! 534: cp = skin(name1(mp, reptype)); ! 535: if (reptype != 0 || charcount(cp, '!') < 2) ! 536: return(cp); ! 537: cp2 = rindex(cp, '!'); ! 538: cp2--; ! 539: while (cp2 > cp && *cp2 != '!') ! 540: cp2--; ! 541: if (*cp2 == '!') ! 542: return(cp2 + 1); ! 543: return(cp); ! 544: } ! 545: ! 546: /* ! 547: * Skin an arpa net address according to the RFC 733 interpretation ! 548: * of "host-phrase." ! 549: */ ! 550: char * ! 551: skin(name) ! 552: char *name; ! 553: { ! 554: register int c; ! 555: register char *cp, *cp2; ! 556: int gotlt, lastsp; ! 557: char nbuf[BUFSIZ]; ! 558: ! 559: if (name == NOSTR) ! 560: return(NOSTR); ! 561: if (index(name, '(') == NOSTR && index(name, '<') == NOSTR ! 562: && index(name, ' ') == NOSTR) ! 563: return(name); ! 564: gotlt = 0; ! 565: lastsp = 0; ! 566: for (cp = name, cp2 = nbuf; c = *cp++; ) { ! 567: switch (c) { ! 568: case '(': ! 569: while (*cp != ')' && *cp != 0) ! 570: cp++; ! 571: if (*cp) ! 572: cp++; ! 573: lastsp = 0; ! 574: break; ! 575: ! 576: case ' ': ! 577: if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') ! 578: cp += 3, *cp2++ = '@'; ! 579: else ! 580: if (cp[0] == '@' && cp[1] == ' ') ! 581: cp += 2, *cp2++ = '@'; ! 582: else ! 583: lastsp = 1; ! 584: break; ! 585: ! 586: case '<': ! 587: cp2 = nbuf; ! 588: gotlt++; ! 589: lastsp = 0; ! 590: break; ! 591: ! 592: case '>': ! 593: if (gotlt) ! 594: goto done; ! 595: ! 596: /* Fall into . . . */ ! 597: ! 598: default: ! 599: if (lastsp) { ! 600: lastsp = 0; ! 601: *cp2++ = ' '; ! 602: } ! 603: *cp2++ = c; ! 604: break; ! 605: } ! 606: } ! 607: done: ! 608: *cp2 = 0; ! 609: ! 610: return(savestr(nbuf)); ! 611: } ! 612: ! 613: /* ! 614: * Fetch the sender's name from the passed message. ! 615: * Reptype can be ! 616: * 0 -- get sender's name for display purposes ! 617: * 1 -- get sender's name for reply ! 618: * 2 -- get sender's name for Reply ! 619: * 3 -- get sender's name for back-to-you-bud ! 620: */ ! 621: ! 622: char * ! 623: name1(mp, reptype) ! 624: register struct message *mp; ! 625: { ! 626: char namebuf[LINESIZE]; ! 627: char linebuf[LINESIZE]; ! 628: register char *cp, *cp2; ! 629: register FILE *ibuf; ! 630: int first = 1; ! 631: ! 632: if (reptype != 3) ! 633: { ! 634: if ((cp = hfield("from", mp)) != NOSTR) ! 635: return(cp); ! 636: } ! 637: if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR) ! 638: return(cp); ! 639: ibuf = setinput(mp); ! 640: copy("", namebuf); ! 641: if (readline(ibuf, linebuf) <= 0) ! 642: return(savestr(namebuf)); ! 643: newname: ! 644: for (cp = linebuf; *cp != ' '; cp++) ! 645: ; ! 646: while (any(*cp, " \t")) ! 647: cp++; ! 648: for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") && ! 649: cp2-namebuf < LINESIZE-1; *cp2++ = *cp++) ! 650: ; ! 651: *cp2 = '\0'; ! 652: if (readline(ibuf, linebuf) <= 0) ! 653: return(savestr(namebuf)); ! 654: if ((cp = index(linebuf, 'F')) == NULL) ! 655: return(savestr(namebuf)); ! 656: if (strncmp(cp, "From", 4) != 0) ! 657: return(savestr(namebuf)); ! 658: while ((cp = index(cp, 'r')) != NULL) { ! 659: if (strncmp(cp, "remote", 6) == 0) { ! 660: if ((cp = index(cp, 'f')) == NULL) ! 661: break; ! 662: if (strncmp(cp, "from", 4) != 0) ! 663: break; ! 664: if ((cp = index(cp, ' ')) == NULL) ! 665: break; ! 666: cp++; ! 667: if (first) { ! 668: copy(cp, namebuf); ! 669: first = 0; ! 670: } else ! 671: strcpy(rindex(namebuf, '!')+1, cp); ! 672: strcat(namebuf, "!"); ! 673: goto newname; ! 674: } ! 675: cp++; ! 676: } ! 677: return(savestr(namebuf)); ! 678: } ! 679: ! 680: /* ! 681: * Count the occurances of c in str ! 682: */ ! 683: charcount(str, c) ! 684: char *str; ! 685: { ! 686: register char *cp; ! 687: register int i; ! 688: ! 689: for (i = 0, cp = str; *cp; cp++) ! 690: if (*cp == c) ! 691: i++; ! 692: return(i); ! 693: } ! 694: ! 695: /* ! 696: * Find the rightmost pointer to an instance of the ! 697: * character in the string and return it. ! 698: */ ! 699: char * ! 700: rindex(str, c) ! 701: char str[]; ! 702: register int c; ! 703: { ! 704: register char *cp, *cp2; ! 705: ! 706: for (cp = str, cp2 = NOSTR; *cp; cp++) ! 707: if (c == *cp) ! 708: cp2 = cp; ! 709: return(cp2); ! 710: } ! 711: ! 712: /* ! 713: * See if the string is a number. ! 714: */ ! 715: ! 716: numeric(str) ! 717: char str[]; ! 718: { ! 719: register char *cp = str; ! 720: ! 721: while (*cp) ! 722: if (!isdigit(*cp++)) ! 723: return(0); ! 724: return(1); ! 725: } ! 726: ! 727: /* ! 728: * Are any of the characters in the two strings the same? ! 729: */ ! 730: ! 731: anyof(s1, s2) ! 732: register char *s1, *s2; ! 733: { ! 734: register int c; ! 735: ! 736: while (c = *s1++) ! 737: if (any(c, s2)) ! 738: return(1); ! 739: return(0); ! 740: } ! 741: ! 742: /* ! 743: * Determine the leftmost index of the character ! 744: * in the string. ! 745: */ ! 746: ! 747: char * ! 748: index(str, ch) ! 749: char *str; ! 750: { ! 751: register char *cp; ! 752: register int c; ! 753: ! 754: for (c = ch, cp = str; *cp; cp++) ! 755: if (*cp == c) ! 756: return(cp); ! 757: return(NOSTR); ! 758: } ! 759: ! 760: /* ! 761: * String compare two strings of bounded length. ! 762: */ ! 763: ! 764: strncmp(as1, as2, an) ! 765: char *as1, *as2; ! 766: { ! 767: register char *s1, *s2; ! 768: register int n; ! 769: ! 770: s1 = as1; ! 771: s2 = as2; ! 772: n = an; ! 773: while (--n >= 0 && *s1 == *s2++) ! 774: if (*s1++ == '\0') ! 775: return(0); ! 776: return(n<0 ? 0 : *s1 - *--s2); ! 777: } ! 778: ! 779: /* ! 780: * See if the given header field is supposed to be ignored. ! 781: */ ! 782: isign(field) ! 783: char *field; ! 784: { ! 785: char realfld[BUFSIZ]; ! 786: register int h; ! 787: register struct ignore *igp; ! 788: ! 789: istrcpy(realfld, field); ! 790: h = hash(realfld); ! 791: for (igp = ignore[h]; igp != 0; igp = igp->i_link) ! 792: if (strcmp(igp->i_field, realfld) == 0) ! 793: return(1); ! 794: return(0); ! 795: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.