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