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