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