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