|
|
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: #ifdef defined(USGFROM) ! 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: */ ! 214: if (ishfield(linebuf, field) && strncmp(linebuf, "FROM:", 5)) ! 215: #else !defined(USGFROM) ! 216: if (ishfield(linebuf, field)) ! 217: #endif defined(USGFROM) ! 218: return(savestr(hcontents(linebuf))); ! 219: } while (lc > 0); ! 220: return(NOSTR); ! 221: } ! 222: ! 223: /* ! 224: * Return the next header field found in the given message. ! 225: * Return > 0 if something found, <= 0 elsewise. ! 226: * Must deal with \ continuations & other such fraud. ! 227: */ ! 228: ! 229: gethfield(f, linebuf, rem) ! 230: register FILE *f; ! 231: char linebuf[]; ! 232: register int rem; ! 233: { ! 234: char line2[LINESIZE]; ! 235: long loc; ! 236: register char *cp, *cp2; ! 237: register int c; ! 238: ! 239: ! 240: for (;;) { ! 241: if (rem <= 0) ! 242: return(-1); ! 243: if (readline(f, linebuf) < 0) ! 244: return(-1); ! 245: rem--; ! 246: if (strlen(linebuf) == 0) ! 247: return(-1); ! 248: if (isspace(linebuf[0])) ! 249: continue; ! 250: if (linebuf[0] == '>') ! 251: continue; ! 252: cp = index(linebuf, ':'); ! 253: if (cp == NOSTR) ! 254: continue; ! 255: for (cp2 = linebuf; cp2 < cp; cp2++) ! 256: if (isdigit(*cp2)) ! 257: continue; ! 258: ! 259: /* ! 260: * I guess we got a headline. ! 261: * Handle wraparounding ! 262: */ ! 263: ! 264: for (;;) { ! 265: if (rem <= 0) ! 266: break; ! 267: #ifdef CANTELL ! 268: loc = ftell(f); ! 269: if (readline(f, line2) < 0) ! 270: break; ! 271: rem--; ! 272: if (!isspace(line2[0])) { ! 273: fseek(f, loc, 0); ! 274: rem++; ! 275: break; ! 276: } ! 277: #else ! 278: c = getc(f); ! 279: ungetc(c, f); ! 280: if (!isspace(c) || c == '\n') ! 281: break; ! 282: if (readline(f, line2) < 0) ! 283: break; ! 284: rem--; ! 285: #endif ! 286: cp2 = line2; ! 287: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++) ! 288: ; ! 289: if (strlen(linebuf) + strlen(cp2) >= LINESIZE-2) ! 290: break; ! 291: cp = &linebuf[strlen(linebuf)]; ! 292: while (cp > linebuf && ! 293: (isspace(cp[-1]) || cp[-1] == '\\')) ! 294: cp--; ! 295: *cp++ = ' '; ! 296: for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++) ! 297: ; ! 298: strcpy(cp, cp2); ! 299: } ! 300: if ((c = strlen(linebuf)) > 0) { ! 301: cp = &linebuf[c-1]; ! 302: while (cp > linebuf && isspace(*cp)) ! 303: cp--; ! 304: *++cp = 0; ! 305: } ! 306: return(rem); ! 307: } ! 308: /* NOTREACHED */ ! 309: } ! 310: ! 311: /* ! 312: * Check whether the passed line is a header line of ! 313: * the desired breed. ! 314: */ ! 315: ! 316: ishfield(linebuf, field) ! 317: char linebuf[], field[]; ! 318: { ! 319: register char *cp; ! 320: register int c; ! 321: ! 322: if ((cp = index(linebuf, ':')) == NOSTR) ! 323: return(0); ! 324: if (cp == linebuf) ! 325: return(0); ! 326: cp--; ! 327: while (cp > linebuf && isspace(*cp)) ! 328: cp--; ! 329: c = *++cp; ! 330: *cp = 0; ! 331: if (icequal(linebuf ,field)) { ! 332: *cp = c; ! 333: return(1); ! 334: } ! 335: *cp = c; ! 336: return(0); ! 337: } ! 338: ! 339: /* ! 340: * Extract the non label information from the given header field ! 341: * and return it. ! 342: */ ! 343: ! 344: char * ! 345: hcontents(hfield) ! 346: char hfield[]; ! 347: { ! 348: register char *cp; ! 349: ! 350: if ((cp = index(hfield, ':')) == NOSTR) ! 351: return(NOSTR); ! 352: cp++; ! 353: while (*cp && isspace(*cp)) ! 354: cp++; ! 355: return(cp); ! 356: } ! 357: ! 358: /* ! 359: * Compare two strings, ignoring case. ! 360: */ ! 361: ! 362: icequal(s1, s2) ! 363: register char *s1, *s2; ! 364: { ! 365: ! 366: while (raise(*s1++) == raise(*s2)) ! 367: if (*s2++ == 0) ! 368: return(1); ! 369: return(0); ! 370: } ! 371: ! 372: /* ! 373: * Copy a string, lowercasing it as we go. ! 374: */ ! 375: istrcpy(dest, src) ! 376: char *dest, *src; ! 377: { ! 378: register char *cp, *cp2; ! 379: ! 380: cp2 = dest; ! 381: cp = src; ! 382: do { ! 383: *cp2++ = little(*cp); ! 384: } while (*cp++ != 0); ! 385: } ! 386: ! 387: /* ! 388: * The following code deals with input stacking to do source ! 389: * commands. All but the current file pointer are saved on ! 390: * the stack. ! 391: */ ! 392: ! 393: static int ssp = -1; /* Top of file stack */ ! 394: struct sstack { ! 395: FILE *s_file; /* File we were in. */ ! 396: int s_cond; /* Saved state of conditionals */ ! 397: int s_loading; /* Loading .mailrc, etc. */ ! 398: } sstack[_NFILE]; ! 399: ! 400: /* ! 401: * Pushdown current input file and switch to a new one. ! 402: * Set the global flag "sourcing" so that others will realize ! 403: * that they are no longer reading from a tty (in all probability). ! 404: */ ! 405: ! 406: source(name) ! 407: char name[]; ! 408: { ! 409: register FILE *fi; ! 410: register char *cp; ! 411: ! 412: if ((cp = expand(name)) == NOSTR) ! 413: return(1); ! 414: if ((fi = fopen(cp, "r")) == NULL) { ! 415: perror(cp); ! 416: return(1); ! 417: } ! 418: if (ssp >= _NFILE-2) { ! 419: printf("Too much \"sourcing\" going on.\n"); ! 420: fclose(fi); ! 421: return(1); ! 422: } ! 423: sstack[++ssp].s_file = input; ! 424: sstack[ssp].s_cond = cond; ! 425: sstack[ssp].s_loading = loading; ! 426: loading = 0; ! 427: cond = CANY; ! 428: input = fi; ! 429: sourcing++; ! 430: return(0); ! 431: } ! 432: ! 433: /* ! 434: * Source a file, but do nothing if the file cannot be opened. ! 435: */ ! 436: ! 437: source1(name) ! 438: char name[]; ! 439: { ! 440: register int f; ! 441: ! 442: if ((f = open(name, 0)) < 0) ! 443: return(0); ! 444: close(f); ! 445: source(name); ! 446: } ! 447: ! 448: /* ! 449: * Pop the current input back to the previous level. ! 450: * Update the "sourcing" flag as appropriate. ! 451: */ ! 452: ! 453: unstack() ! 454: { ! 455: if (ssp < 0) { ! 456: printf("\"Source\" stack over-pop.\n"); ! 457: sourcing = 0; ! 458: return(1); ! 459: } ! 460: fclose(input); ! 461: if (cond != CANY) ! 462: printf("Unmatched \"if\"\n"); ! 463: cond = sstack[ssp].s_cond; ! 464: loading = sstack[ssp].s_loading; ! 465: input = sstack[ssp--].s_file; ! 466: if (ssp < 0) ! 467: sourcing = loading; ! 468: return(0); ! 469: } ! 470: ! 471: /* ! 472: * Touch the indicated file. ! 473: * This is nifty for the shell. ! 474: * If we have the utime() system call, this is better served ! 475: * by using that, since it will work for empty files. ! 476: * On non-utime systems, we must sleep a second, then read. ! 477: */ ! 478: ! 479: alter(name) ! 480: char name[]; ! 481: { ! 482: #ifdef UTIME ! 483: struct stat statb; ! 484: long time(); ! 485: time_t time_p[2]; ! 486: #else ! 487: register int pid, f; ! 488: char w; ! 489: #endif UTIME ! 490: ! 491: #ifdef UTIME ! 492: if (stat(name, &statb) < 0) ! 493: return; ! 494: time_p[0] = time((long *) 0) + 1; ! 495: time_p[1] = statb.st_mtime; ! 496: utime(name, time_p); ! 497: #else ! 498: sleep(1); ! 499: if ((f = open(name, 0)) < 0) ! 500: return; ! 501: read(f, &w, 1); ! 502: exit(0); ! 503: #endif ! 504: } ! 505: ! 506: /* ! 507: * Examine the passed line buffer and ! 508: * return true if it is all blanks and tabs. ! 509: */ ! 510: ! 511: blankline(linebuf) ! 512: char linebuf[]; ! 513: { ! 514: register char *cp; ! 515: ! 516: for (cp = linebuf; *cp; cp++) ! 517: if (!any(*cp, " \t")) ! 518: return(0); ! 519: return(1); ! 520: } ! 521: ! 522: /* ! 523: * Get sender's name from this message. If the message has ! 524: * a bunch of arpanet stuff in it, we may have to skin the name ! 525: * before returning it. ! 526: */ ! 527: char * ! 528: nameof(mp, reptype) ! 529: register struct message *mp; ! 530: { ! 531: register char *cp, *cp2; ! 532: ! 533: cp = skin(name1(mp, reptype)); ! 534: if (reptype != 0 || charcount(cp, '!') < 2) ! 535: return(cp); ! 536: cp2 = rindex(cp, '!'); ! 537: cp2--; ! 538: while (cp2 > cp && *cp2 != '!') ! 539: cp2--; ! 540: if (*cp2 == '!') ! 541: return(cp2 + 1); ! 542: return(cp); ! 543: } ! 544: ! 545: /* ! 546: * Skin an arpa net address according to the RFC 733 interpretation ! 547: * of "host-phrase." ! 548: */ ! 549: char * ! 550: skin(name) ! 551: char *name; ! 552: { ! 553: register int c; ! 554: register char *cp, *cp2; ! 555: int gotlt, lastsp; ! 556: char nbuf[BUFSIZ]; ! 557: ! 558: if (name == NOSTR) ! 559: return(NOSTR); ! 560: if (index(name, '(') == NOSTR && index(name, '<') == NOSTR ! 561: && index(name, ' ') == NOSTR) ! 562: return(name); ! 563: gotlt = 0; ! 564: lastsp = 0; ! 565: for (cp = name, cp2 = nbuf; c = *cp++; ) { ! 566: switch (c) { ! 567: case '(': ! 568: while (*cp != ')' && *cp != 0) ! 569: cp++; ! 570: if (*cp) ! 571: cp++; ! 572: lastsp = 0; ! 573: break; ! 574: ! 575: case ' ': ! 576: if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ') ! 577: cp += 3, *cp2++ = '@'; ! 578: else ! 579: if (cp[0] == '@' && cp[1] == ' ') ! 580: cp += 2, *cp2++ = '@'; ! 581: else ! 582: lastsp = 1; ! 583: break; ! 584: ! 585: case '<': ! 586: cp2 = nbuf; ! 587: gotlt++; ! 588: lastsp = 0; ! 589: break; ! 590: ! 591: case '>': ! 592: if (gotlt) ! 593: goto done; ! 594: ! 595: /* Fall into . . . */ ! 596: ! 597: default: ! 598: if (lastsp) { ! 599: lastsp = 0; ! 600: *cp2++ = ' '; ! 601: } ! 602: *cp2++ = c; ! 603: break; ! 604: } ! 605: } ! 606: done: ! 607: *cp2 = 0; ! 608: ! 609: return(savestr(nbuf)); ! 610: } ! 611: ! 612: /* ! 613: * Fetch the sender's name from the passed message. ! 614: * Reptype can be ! 615: * 0 -- get sender's name for display purposes ! 616: * 1 -- get sender's name for reply ! 617: * 2 -- get sender's name for Reply ! 618: * 3 -- get sender's name for back-to-you-bud ! 619: */ ! 620: ! 621: char * ! 622: name1(mp, reptype) ! 623: register struct message *mp; ! 624: { ! 625: char namebuf[LINESIZE]; ! 626: char linebuf[LINESIZE]; ! 627: register char *cp, *cp2; ! 628: register FILE *ibuf; ! 629: int first = 1; ! 630: ! 631: if (reptype != 3) ! 632: { ! 633: if ((cp = hfield("from", mp)) != NOSTR) ! 634: return(cp); ! 635: } ! 636: if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR) ! 637: return(cp); ! 638: ibuf = setinput(mp); ! 639: copy("", namebuf); ! 640: if (readline(ibuf, linebuf) <= 0) ! 641: return(savestr(namebuf)); ! 642: newname: ! 643: for (cp = linebuf; *cp != ' '; cp++) ! 644: ; ! 645: while (any(*cp, " \t")) ! 646: cp++; ! 647: for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") && ! 648: cp2-namebuf < LINESIZE-1; *cp2++ = *cp++) ! 649: ; ! 650: *cp2 = '\0'; ! 651: if (readline(ibuf, linebuf) <= 0) ! 652: return(savestr(namebuf)); ! 653: if ((cp = index(linebuf, 'F')) == NULL) ! 654: return(savestr(namebuf)); ! 655: if (strncmp(cp, "From", 4) != 0) ! 656: return(savestr(namebuf)); ! 657: while ((cp = index(cp, 'r')) != NULL) { ! 658: if (strncmp(cp, "remote", 6) == 0) { ! 659: if ((cp = index(cp, 'f')) == NULL) ! 660: break; ! 661: if (strncmp(cp, "from", 4) != 0) ! 662: break; ! 663: if ((cp = index(cp, ' ')) == NULL) ! 664: break; ! 665: cp++; ! 666: if (first) { ! 667: copy(cp, namebuf); ! 668: first = 0; ! 669: } else ! 670: strcpy(rindex(namebuf, '!')+1, cp); ! 671: strcat(namebuf, "!"); ! 672: goto newname; ! 673: } ! 674: cp++; ! 675: } ! 676: return(savestr(namebuf)); ! 677: } ! 678: ! 679: /* ! 680: * Count the occurances of c in str ! 681: */ ! 682: charcount(str, c) ! 683: char *str; ! 684: { ! 685: register char *cp; ! 686: register int i; ! 687: ! 688: for (i = 0, cp = str; *cp; cp++) ! 689: if (*cp == c) ! 690: i++; ! 691: return(i); ! 692: } ! 693: ! 694: /* ! 695: * Find the rightmost pointer to an instance of the ! 696: * character in the string and return it. ! 697: */ ! 698: char * ! 699: rindex(str, c) ! 700: char str[]; ! 701: register int c; ! 702: { ! 703: register char *cp, *cp2; ! 704: ! 705: for (cp = str, cp2 = NOSTR; *cp; cp++) ! 706: if (c == *cp) ! 707: cp2 = cp; ! 708: return(cp2); ! 709: } ! 710: ! 711: /* ! 712: * See if the string is a number. ! 713: */ ! 714: ! 715: numeric(str) ! 716: char str[]; ! 717: { ! 718: register char *cp = str; ! 719: ! 720: while (*cp) ! 721: if (!isdigit(*cp++)) ! 722: return(0); ! 723: return(1); ! 724: } ! 725: ! 726: /* ! 727: * Are any of the characters in the two strings the same? ! 728: */ ! 729: ! 730: anyof(s1, s2) ! 731: register char *s1, *s2; ! 732: { ! 733: register int c; ! 734: ! 735: while (c = *s1++) ! 736: if (any(c, s2)) ! 737: return(1); ! 738: return(0); ! 739: } ! 740: ! 741: /* ! 742: * Determine the leftmost index of the character ! 743: * in the string. ! 744: */ ! 745: ! 746: char * ! 747: index(str, ch) ! 748: char *str; ! 749: { ! 750: register char *cp; ! 751: register int c; ! 752: ! 753: for (c = ch, cp = str; *cp; cp++) ! 754: if (*cp == c) ! 755: return(cp); ! 756: return(NOSTR); ! 757: } ! 758: ! 759: /* ! 760: * String compare two strings of bounded length. ! 761: */ ! 762: ! 763: strncmp(as1, as2, an) ! 764: char *as1, *as2; ! 765: { ! 766: register char *s1, *s2; ! 767: register int n; ! 768: ! 769: s1 = as1; ! 770: s2 = as2; ! 771: n = an; ! 772: while (--n >= 0 && *s1 == *s2++) ! 773: if (*s1++ == '\0') ! 774: return(0); ! 775: return(n<0 ? 0 : *s1 - *--s2); ! 776: } ! 777: ! 778: /* ! 779: * See if the given header field is supposed to be ignored. ! 780: */ ! 781: isign(field) ! 782: char *field; ! 783: { ! 784: char realfld[BUFSIZ]; ! 785: register int h; ! 786: register struct ignore *igp; ! 787: ! 788: istrcpy(realfld, field); ! 789: h = hash(realfld); ! 790: for (igp = ignore[h]; igp != 0; igp = igp->i_link) ! 791: if (strcmp(igp->i_field, realfld) == 0) ! 792: return(1); ! 793: return(0); ! 794: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.