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

Defined functions

_error defined in line 69; never used
alter defined in line 468; used 2 times
anyof defined in line 717; used 1 times
argcount defined in line 129; used 6 times
blankline defined in line 500; used 2 times
blockof defined in line 144; used 3 times
charcount defined in line 669; used 1 times
copyname defined in line 41; never used
gethfield defined in line 218; used 1 times
hcontents defined in line 333; used 2 times
index defined in line 733; used 15 times
isatty defined in line 173; used 2 times
isdir defined in line 115; used 2 times
ishfield defined in line 305; used 1 times
isign defined in line 768; used 4 times
istrcpy defined in line 364; used 2 times
name1 defined in line 609; used 2 times
numeric defined in line 702; never used
offsetof defined in line 159; used 3 times
prs defined in line 82; used 6 times
rindex defined in line 685; used 9 times
savestr defined in line 19; used 7 times
skin defined in line 538; used 10 times
source defined in line 395; used 3 times
source1 defined in line 426; never used
strncmp defined in line 750; used 6 times
touch defined in line 98; used 9 times
unstack defined in line 442; used 9 times

Defined variables

SccsId defined in line 13; never used
ssp defined in line 382; used 9 times
sstack defined in line 387; used 6 times

Defined struct's

sstack defined in line 383; never used
Last modified: 1983-07-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1586
Valid CSS Valid XHTML 1.0 Strict