Annotation of 40BSD/cmd/delivermail/arpa.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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