Annotation of 43BSDReno/usr.sbin/sendmail/aux/arpa.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1983 Eric P. Allman
                      3:  * Copyright (c) 1988 Regents of the University of California.
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms are permitted provided
                      7:  * that: (1) source distributions retain this entire copyright notice and
                      8:  * comment, and (2) distributions including binaries display the following
                      9:  * acknowledgement:  ``This product includes software developed by the
                     10:  * University of California, Berkeley and its contributors'' in the
                     11:  * documentation or other materials provided with the distribution and in
                     12:  * all advertising materials mentioning features or use of this software.
                     13:  * Neither the name of the University nor the names of its contributors may
                     14:  * be used to endorse or promote products derived from this software without
                     15:  * specific prior written permission.
                     16:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     17:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     18:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     19:  */
                     20: 
                     21: #ifndef lint
                     22: char copyright[] =
                     23: "@(#) Copyright (c) 1988 Regents of the University of California.\n\
                     24:  All rights reserved.\n";
                     25: #endif /* not lint */
                     26: 
                     27: #ifndef lint
                     28: static char sccsid[] = "@(#)arpa.c     5.4 (Berkeley) 6/1/90";
                     29: #endif /* not lint */
                     30: 
                     31: # include      <stdio.h>
                     32: # include      <ctype.h>
                     33: # include      <signal.h>
                     34: # include      <sysexits.h>
                     35: # include      <whoami.h>
                     36: # include      <useful.h>
                     37: 
                     38: char Version[] = "@(#)Arpa-mailer version 5.4 of 6/1/90";
                     39: 
                     40: # define void  int
                     41: 
                     42: /*
                     43: **  ARPA MAILER -- Queue ARPANET mail for eventual delivery
                     44: **
                     45: **     The standard input is stuck away in the outgoing arpanet
                     46: **     mail queue for delivery by the true arpanet mailer.
                     47: **
                     48: **             CUSTOMIZED FOR THE C/70
                     49: **
                     50: **     Usage:
                     51: **             /usr/lib/mailers/arpa from host user
                     52: **
                     53: **     Positional Parameters:
                     54: **             from -- the person sending the mail.
                     55: **             host -- the host to send the mail to.
                     56: **             user -- the user to send the mail to.
                     57: **
                     58: **     Flags:
                     59: **             -T -- debug flag.
                     60: **
                     61: **     Files:
                     62: **             /usr/spool/netmail/* -- the queue file.
                     63: **
                     64: **     Return Codes:
                     65: **             0 -- all messages successfully mailed.
                     66: **             2 -- user or host unknown.
                     67: **             3 -- service unavailable, probably temporary
                     68: **                     file system condition.
                     69: **             4 -- syntax error in address.
                     70: **
                     71: **     Compilation Flags:
                     72: **             SPOOLDIR -- the spool directory
                     73: **
                     74: **     Compilation Instructions:
                     75: **             cc -n -O -s arpa-mailer.c -o arpa-mailer -lX
                     76: **             chmod 755 arpa-mailer
                     77: **             mv arpa-mailer /usr/lib/mailers/arpa
                     78: **
                     79: **     Author:
                     80: **             Eric Allman, UCB/INGRES (eric@berkeley)
                     81: */
                     82: 
                     83: # ifdef C70
                     84: # define SPOOLDIR      "/usr/netmail"
                     85: # else
                     86: # define SPOOLDIR      "/usr/spool/netmail"
                     87: # endif
                     88: 
                     89: 
                     90: 
                     91: 
                     92: char   *From;                  /* person sending this mail */
                     93: char   *To;                    /* current "To:" person */
                     94: int    State;                  /* the current state (for exit codes) */
                     95: # ifdef DEBUG
                     96: bool   Tflag;                  /* -T given */
                     97: # endif DEBUG
                     98: char   FromHost[200];          /* string to prepend to addresses */
                     99: /*
                    100: **  MAIN -- Main program for arpa mailer
                    101: **
                    102: **     Processes arguments, and calls sendmail successively on
                    103: **     the To: list.
                    104: **
                    105: **     Algorithm:
                    106: **             Scan for debug flag.
                    107: **             Catch interrupt signals.
                    108: **             Collect input file name and from person.
                    109: **             If more than one person in the to list, and
                    110: **                     if the input file is not a real file,
                    111: **                     collect input into a temp file.
                    112: **             For each person in the to list
                    113: **                     Send to that person.
                    114: **
                    115: **     Parameters:
                    116: **             argc
                    117: **             argv -- as usual
                    118: **
                    119: **     Returns:
                    120: **             via exit
                    121: **
                    122: **     Side Effects:
                    123: **             Mail gets sent.
                    124: **
                    125: **     Author:
                    126: **             Eric Allman UCB/INGRES.
                    127: */
                    128: 
                    129: main(argc, argv)
                    130:        int argc;
                    131:        char **argv;
                    132: {
                    133:        register int i;
                    134:        register char *p;
                    135:        register int ifd;
                    136:        char buf[512];
                    137:        extern int done();
                    138:        extern char *locv();
                    139:        register char *q;
                    140:        char *lastmark;
                    141: 
                    142:        State = 3;
                    143:        if (signal(SIGINT, SIG_IGN) != SIG_IGN)
                    144:                (void) signal(SIGINT, done);
                    145:        
                    146:        /* process flags */
                    147:        argv[argc] = 0;
                    148: # ifdef DEBUG
                    149:        if (strcmp(argv[1], "-T") == 0)
                    150:        {
                    151:                Tflag++;
                    152:                argv++;
                    153:                argc--;
                    154:                printf("%s\n", Version);
                    155:        }
                    156: # endif DEBUG
                    157: 
                    158:        if (argc != 4)
                    159:        {
                    160:                rexit(EX_SOFTWARE);
                    161:        }
                    162:        
                    163:        /* decode parameters */
                    164:        From = argv[1];
                    165:        lastmark = &FromHost[-1];
                    166:        for (p = From, q = FromHost; (*q = *p) != '\0'; p++, q++)
                    167:        {
                    168:                if (*p == ':')
                    169:                        *q = *p = '.';
                    170:                if (*q == '.' || *q == '!' || *q == '@')
                    171:                        lastmark = q;
                    172:        }
                    173:        lastmark[1] = '\0';
                    174: 
                    175:        /* start sending mail */
                    176:        State = sendmail(argv[2], argv[3]);
                    177: 
                    178:        /* all done, clean up */
                    179:        done();
                    180: }
                    181: /*
                    182: **  DONE -- Finish up, remove temp files, etc.
                    183: **
                    184: **     This does basic cleanup on interrupt, error, or
                    185: **     normal termination.  It uses "State" to tell which
                    186: **     is happening.
                    187: **
                    188: **     Parameters:
                    189: **             none
                    190: **
                    191: **     Returns:
                    192: **             none
                    193: **
                    194: **     Side Effects:
                    195: **             Exit(State).
                    196: */
                    197: 
                    198: done()
                    199: {
                    200:        rexit(State);
                    201: }
                    202: 
                    203: /*
                    204: ** REXIT -- exit, reporting error code if -T given
                    205: **
                    206: **     Parameters:
                    207: **             e -- error code to exit with; see sysexits.h
                    208: **
                    209: **     Returns:
                    210: **             none
                    211: **
                    212: **     Side Effects:
                    213: **             Exit(e).
                    214: */
                    215: rexit(e)
                    216: {
                    217: 
                    218: # ifdef DEBUG
                    219:        if (Tflag)
                    220:                fprintf(stderr, "arpa-mail: return code %d\n", e);
                    221: # endif
                    222:        exit(e);
                    223: }
                    224: /*
                    225: **  SENDMAIL -- Queue up mail for the arpanet mailer.
                    226: **
                    227: **     The mail is inserted with proper headers into the
                    228: **     arpanet queue directory.
                    229: **
                    230: **     Algorithm:
                    231: **             decode "to" address
                    232: **                     if error, exit.
                    233: **             create a spool file name.
                    234: **             output the header information to spool file,
                    235: **               separate names in To:, CC: fields with commas.
                    236: **             copy the mail to the spool file.
                    237: **
                    238: **     Parameters:
                    239: **             host -- the host to send to.
                    240: **             user -- the user to send to.
                    241: **
                    242: **     Returns:
                    243: **             none
                    244: **
                    245: **     Side Effects:
                    246: **             the mail is copied into a file in the network
                    247: **                     queue directory (/usr/spool/netmail).
                    248: */
                    249: 
                    250: sendmail(host, user)
                    251:        char *host;
                    252:        char *user;
                    253: {
                    254:        char spoolfile[50];     /* gets the spool file name */
                    255:        register int i;
                    256:        register char *p;
                    257:        static int callnum;     /* for the final letter on spoolfile */
                    258:        char buf[512];
                    259:        register FILE *sfp;     /* spool file */
                    260:        register int c;
                    261:        extern char *matchhdr();
                    262: 
                    263:        /* verify that the host exists */
                    264:        (void) strcpy(buf, "/dev/net/");
                    265:        (void) strcat(buf, host);
                    266: # ifndef C70
                    267: #ifdef DEBUG
                    268:        if (!Tflag)
                    269: #endif DEBUG
                    270:        if (host[0] == '\0' || access(buf, 0) < 0)
                    271:                return (EX_NOHOST);
                    272: # endif C70
                    273: 
                    274:        /*
                    275:        **  Create spool file name.
                    276:        **      Format is "username000nnX", where username is
                    277:        **      padded on the right with zeros and nn (the process
                    278:        **      id) is padded on the left with zeros; X is a unique
                    279:        **      sequence character.
                    280:        */
                    281: 
                    282: # ifdef DEBUG
                    283:        if (Tflag)
                    284:                (void) strcpy(spoolfile, "arpa.out");
                    285:        else
                    286: # endif DEBUG
                    287:                (void) sprintf(spoolfile, "%s/arpamail%05d%c", SPOOLDIR, getpid(), 'a' + callnum++);
                    288: 
                    289:        /* create spool file */
                    290:        sfp = fopen(spoolfile, "w");
                    291:        if (sfp == NULL)
                    292:        {
                    293:        spoolerr:
                    294:                return (EX_OSERR);
                    295:        }
                    296: # ifdef DEBUG
                    297:        if (!Tflag)
                    298: # endif DEBUG
                    299:                (void) chmod(spoolfile, 0400);
                    300: 
                    301:        /*
                    302:        ** Output mailer control lines.
                    303:        **      These lines are as follows:
                    304:        **              /dev/net/<hostname> {target host}
                    305:        **              user-name {at target host}
                    306:        **              /mnt/eric {pathname of sender; not used}
                    307:        **              eric {name of user who is sending}
                    308:        **      These are different (but close) on the C/70.
                    309:        */
                    310: 
                    311: # ifdef C70
                    312:        fputs(host, sfp);
                    313:        fputs(":", sfp);
                    314:        fputs(user, sfp);
                    315:        fputs(":", sfp);
                    316:        fputs(From, sfp);
                    317:        fputs(":\n", sfp);
                    318: # else
                    319:        fputs(buf, sfp);
                    320:        fputs("\n", sfp);
                    321:        fputs(user, sfp);
                    322:        fputs("\n\n", sfp);
                    323:        fputs(From, sfp);
                    324:        fputs("\n", sfp);
                    325: # endif
                    326: 
                    327:        /*
                    328:        **  Output the mail
                    329:        **      Check the first line for the date.  If not found,
                    330:        **      assume the message is not in arpanet standard format
                    331:        **      and output a "Date:" and "From:" header.
                    332:        */
                    333: 
                    334:        if (fgets(buf, sizeof buf, stdin) == NULL)
                    335:        {
                    336:                /* no message */
                    337:                (void) unlink(spoolfile);
                    338:                return (EX_OK);
                    339:        }
                    340:        if (strncmp("From ", buf, 5) == 0)
                    341:        {
                    342:                /* strip Unix "From" line */
                    343:                /* should save the date here */
                    344:                (void) fgets(buf, sizeof buf, stdin);
                    345:        }
                    346:        while (matchhdr(buf, "mail-from") != NULL ||
                    347:               matchhdr(buf, "sender-path") != NULL ||
                    348:               matchhdr(buf, "received") != NULL ||
                    349:               matchhdr(buf, "via") != NULL)
                    350:        {
                    351:                fputs(buf, sfp);
                    352:                (void) fgets(buf, sizeof buf, stdin);
                    353:        }
                    354:        if (matchhdr(buf, "date") == NULL)
                    355:                putdate(sfp);
                    356:        else
                    357:        {
                    358:                fputs(buf, sfp);
                    359:                (void) fgets(buf, sizeof buf, stdin);
                    360:        }
                    361:        if (matchhdr(buf, "from") == NULL)
                    362:                putfrom(sfp);
                    363:        else
                    364:        {
                    365:                /* hack to support sendmail -- for a while */
                    366:                if (index(buf, '@') == NULL)
                    367:                        putfrom(sfp);
                    368:                else
                    369:                        fputs(buf, sfp);
                    370:                (void) fgets(buf, sizeof buf, stdin);
                    371:        }
                    372:        if (!ishdr(buf))
                    373:        {
                    374:                if (buf[0] != '\n')
                    375:                        putc('\n', sfp);
                    376:                goto hdrdone;
                    377:        }
                    378: 
                    379:        /*
                    380:        ** At this point, we have a message with REAL headers.
                    381:        ** We look at each head line and insert commas if it
                    382:        ** is a To: or Cc: field.
                    383:        */
                    384: 
                    385:        do
                    386:        {
                    387:                if (!ishdr(buf))
                    388:                        break;
                    389:                if (!matchhdr(buf, "to") && !matchhdr(buf, "cc"))
                    390:                {
                    391:                        fputs(buf, sfp);
                    392:                        continue;
                    393:                }
                    394:                /* gotcha! */
                    395:                fixaddr(buf, 1, sfp);
                    396:                while (isspace(c = peekc(stdin)) && c != '\n')
                    397:                {
                    398:                        (void) fgets(buf, BUFSIZ, stdin);
                    399:                        fixaddr(buf, 0, sfp);
                    400:                }
                    401:        } while (fgets(buf, BUFSIZ, stdin) != NULL);
                    402: 
                    403: hdrdone:
                    404:        /* output the rest of the header & the body of the letter */
                    405:        do
                    406:        {
                    407:                fputs(buf, sfp);
                    408:                if (ferror(sfp))
                    409:                        goto spoolerr;
                    410:        } while (fgets(buf, sizeof buf, stdin) != NULL);
                    411: 
                    412:        /* all done! */
                    413:        (void) fclose(sfp);
                    414:        return (EX_OK);
                    415: }
                    416: /*
                    417: **  FIXADDR -- Output header line with needed commas.
                    418: **
                    419: **     Parameters:
                    420: **             buf -- header line
                    421: **             first -- true if this is not a continuation
                    422: **
                    423: **     Returns:
                    424: **             none
                    425: **
                    426: **     Side effects:
                    427: **             The contents of buf is copied onto the spool file with
                    428: **             with the right commas interlaced
                    429: **
                    430: **     Called by:
                    431: **             sendmail
                    432: */
                    433: 
                    434: fixaddr(buf, first, spf)
                    435:        char buf[];
                    436:        register FILE *spf;
                    437: {
                    438:        register char *cp;
                    439:        register int c;
                    440:        char word[BUFSIZ], word2[BUFSIZ];
                    441:        char *gword();
                    442:        static char wsep[] = ", ";
                    443: 
                    444:        cp = buf;
                    445:        if (first)
                    446:        {
                    447:                while (*cp != ':' && *cp)
                    448:                        putc(*cp++, spf);
                    449:                if (*cp == ':')
                    450:                {
                    451:                        fputs(": ", spf);
                    452:                        cp++;
                    453:                }
                    454:        }
                    455:        else
                    456:                while (*cp && isspace(*cp))
                    457:                        putc(*cp++, spf);
                    458:        cp = gword(word, cp);
                    459:        if (strlen(word) == 0)
                    460:        {
                    461:                putc('\n', spf);
                    462:                goto test;
                    463:        }
                    464:        for (;;)
                    465:        {
                    466:                cp = gword(word2, cp);
                    467:                if (strlen(word2) == 0)
                    468:                {
                    469:                        putaddr(word, spf);
                    470:                        break;
                    471:                }
                    472:                if (strcmp(word2, "%") == 0)
                    473:                        word2[0] = '@';
                    474:                if (strcmp(word2, "@") && strcmp(word2, "at"))
                    475:                {
                    476:                        putaddr(word, spf);
                    477:                        fputs(wsep, spf);
                    478:                        (void) strcpy(word, word2);
                    479:                        continue;
                    480:                }
                    481:                fputs(word, spf);
                    482:                if (word2[0] == '@')
                    483:                        putc('@', spf);
                    484:                else
                    485:                        fputs(" at ", spf);
                    486:                cp = gword(word, cp);
                    487:                fputs(word, spf);
                    488:                cp = gword(word, cp);
                    489:                if (strlen(word))
                    490:                        fputs(wsep, spf);
                    491:        }
                    492: 
                    493: test:
                    494:        c = peekc(stdin);
                    495:        if (isspace(c) && c != '\n')
                    496:                fputs(",\n", spf);
                    497:        else
                    498:                putc('\n', spf);
                    499: }
                    500: /*
                    501: **  PUTADDR -- output address onto file
                    502: **
                    503: **     Putaddr prepends the network header onto the address
                    504: **     unless one already exists.
                    505: **
                    506: **     Parameters:
                    507: **             name -- the name to output.
                    508: **             fp -- the file to put it on.
                    509: **
                    510: **     Returns:
                    511: **             none.
                    512: **
                    513: **     Side Effects:
                    514: **             name is put onto fp.
                    515: */
                    516: 
                    517: putaddr(name, fp)
                    518:        char *name;
                    519:        FILE *fp;
                    520: {
                    521:        register char *p;
                    522: 
                    523:        if (strlen(name) == 0)
                    524:                return;
                    525:        for (p = name; *p != '\0' && *p != ':' && *p != '.' && *p != '@' &&
                    526:             *p != '!' && *p != '^'; p++)
                    527:                continue;
                    528:        if (*p == ':')
                    529:                *p = '.';
                    530:        else if (*p == '\0')
                    531:                fputs(FromHost, fp);
                    532:        fputs(name, fp);
                    533:        if (*p != '@')
                    534:                fputs("@Berkeley", fp);
                    535: }
                    536: /*
                    537: **  PEEKC -- peek at next character in input file
                    538: **
                    539: **     Parameters:
                    540: **             fp -- stdio file buffer
                    541: **
                    542: **     Returns:
                    543: **             the next character in the input or EOF
                    544: **
                    545: **     Side effects:
                    546: **             None.
                    547: */
                    548: peekc(fp)
                    549:        register FILE *fp;
                    550: {
                    551:        register int c;
                    552: 
                    553:        c = getc(fp);
                    554:        (void) ungetc(c, fp);
                    555:        return(c);
                    556: }
                    557: 
                    558: /*
                    559: **  GWORD -- get the next liberal word from a string
                    560: **
                    561: **     Parameters:
                    562: **             buf -- place to put scanned word
                    563: **             p -- place to start looking for word
                    564: **
                    565: **     Returns:
                    566: **             updated value of p or 0 if no more left after this
                    567: **
                    568: **     Side effects:
                    569: **             buf gets the liberal word scanned.
                    570: **             buf will be length 0 if there is no more input,
                    571: **             or if p was passed as 0
                    572: */
                    573: char *
                    574: gword(buf, p)
                    575:        char buf[];
                    576:        register char *p;
                    577: {
                    578:        register char *sp, *dp;
                    579:        int     atfound = 0;                    /* weither or not a '@' found in the scan */
                    580: 
                    581:        (void) strcpy(buf, "");
                    582:        if (p == 0)
                    583:                return(0);
                    584:        sp = p;
                    585:        while (*sp && (isspace(*sp) || *sp == ','))
                    586:                sp++;
                    587:        dp = buf;
                    588:        if (*sp != '%' && *sp != '@')
                    589:        {
                    590:                while (*sp && !isspace(*sp) && *sp != ',' )
                    591:                {
                    592:                        if ( *sp == '@' || *sp == '%' )
                    593:                                atfound++;
                    594:                        *dp++ = *sp++;
                    595:                }
                    596:                if ( atfound )
                    597:                {
                    598:                        dp--;
                    599:                        while ( *dp != '@' && *dp != '%' )
                    600:                                dp--,sp--;
                    601:                        sp--;
                    602:                }
                    603:                        
                    604:        }
                    605:        else
                    606:                *dp++ = *sp++;
                    607:        *dp = 0;
                    608:        if (*sp == 0)
                    609:                return(0);
                    610:        return(sp);
                    611: }
                    612: /*
                    613: **  ISHDR -- see if the passed line is a ARPA style header line
                    614: **
                    615: **     Parameters:
                    616: **             buf -- header line
                    617: **
                    618: **     Returns:
                    619: **             non-zero if the line is a header line, else zero
                    620: **
                    621: **     Side effects:
                    622: **             none
                    623: **
                    624: **     Called by:
                    625: **             sendmail
                    626: */
                    627: ishdr(buf)
                    628:        char buf[];
                    629: {
                    630:        register char *p;
                    631: 
                    632:        p = buf;
                    633: 
                    634:        /* check for continuation lines */
                    635:        if (isspace(*p))
                    636:                return (1);
                    637:        else
                    638:        {
                    639:                while (*p != ':' && !isspace(*p))
                    640:                        p++;
                    641:                while (isspace(*p))
                    642:                        p++;
                    643:                if (*p != ':')
                    644:                        p = 0;
                    645:        }
                    646:        return(p != 0);
                    647: }
                    648: /*
                    649: **  PUTDATE -- Put the date field into the message.
                    650: **
                    651: **     Parameters:
                    652: **             fp -- file to put it onto.
                    653: **
                    654: **     Returns:
                    655: **             none
                    656: **
                    657: **     Side Effects:
                    658: **             output onto fp.
                    659: */
                    660: 
                    661: putdate(fp)
                    662:        register FILE *fp;
                    663: {
                    664:        extern char *arpadate();
                    665: 
                    666:        fputs("Date: ", fp);
                    667:        fputs(arpadate(NULL), fp);
                    668:        fputs("\n", fp);
                    669: }
                    670: /*
                    671: **  PUTFROM -- Put the from field into the message.
                    672: **
                    673: **     Parameters:
                    674: **             fp -- file to put it onto.
                    675: **
                    676: **     Returns:
                    677: **             none
                    678: **
                    679: **     Side Effects:
                    680: **             output onto fp.
                    681: */
                    682: 
                    683: putfrom(fp)
                    684:        register FILE *fp;
                    685: {
                    686: 
                    687:        fputs("From: ", fp);
                    688:        fputs(From, fp);
                    689:        fputs("@Berkeley\n", fp);
                    690: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.