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