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