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

Defined functions

alter defined in line 318; used 2 times
anyof defined in line 583; used 1 times
argcount defined in line 109; used 1 times
blankline defined in line 337; used 1 times
charcount defined in line 568; used 1 times
copy defined in line 608; used 4 times
gethfield defined in line 154; used 1 times
hfield defined in line 123; used 21 times
isdir defined in line 96; used 1 times
ishfield defined in line 212; used 2 times
isign defined in line 621; used 2 times
istrcpy defined in line 233; used 2 times
member defined in line 640; used 3 times
name1 defined in line 510; used 2 times
raise defined in line 596; used 4 times
savestr defined in line 51; used 7 times
skin defined in line 402; used 10 times
skip_comment defined in line 375; used 2 times
source defined in line 263; used 2 times
unstack defined in line 295; used 3 times

Defined variables

sccsid defined in line 35; never used
ssp defined in line 251; used 11 times
sstack defined in line 256; used 6 times

Defined struct's

sstack defined in line 252; never used
Last modified: 1992-10-22
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3663
Valid CSS Valid XHTML 1.0 Strict