Annotation of 43BSD/usr.lib/sendmail/aux/arpa.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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