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

unix.superglobalmegacorp.com

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