Annotation of 43BSDReno/usr.bin/mail/send.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1980 Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms are permitted provided
                      6:  * that: (1) source distributions retain this entire copyright notice and
                      7:  * comment, and (2) distributions including binaries display the following
                      8:  * acknowledgement:  ``This product includes software developed by the
                      9:  * University of California, Berkeley and its contributors'' in the
                     10:  * documentation or other materials provided with the distribution and in
                     11:  * all advertising materials mentioning features or use of this software.
                     12:  * Neither the name of the University nor the names of its contributors may
                     13:  * be used to endorse or promote products derived from this software without
                     14:  * specific prior written permission.
                     15:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
                     16:  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
                     17:  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
                     18:  */
                     19: 
                     20: #ifndef lint
                     21: static char sccsid[] = "@(#)send.c     5.21 (Berkeley) 6/25/90";
                     22: #endif /* not lint */
                     23: 
                     24: #include "rcv.h"
                     25: 
                     26: /*
                     27:  * Mail -- a mail program
                     28:  *
                     29:  * Mail to others.
                     30:  */
                     31: 
                     32: /*
                     33:  * Send message described by the passed pointer to the
                     34:  * passed output buffer.  Return -1 on error.
                     35:  * Adjust the status: field if need be.
                     36:  * If doign is given, suppress ignored header fields.
                     37:  * prefix is a string to prepend to each output line.
                     38:  */
                     39: send(mp, obuf, doign, prefix)
                     40:        register struct message *mp;
                     41:        FILE *obuf;
                     42:        struct ignoretab *doign;
                     43:        char *prefix;
                     44: {
                     45:        long count;
                     46:        register FILE *ibuf;
                     47:        char line[LINESIZE];
                     48:        int ishead, infld, ignoring, dostat, firstline;
                     49:        register char *cp, *cp2;
                     50:        register int c;
                     51:        int length;
                     52:        int prefixlen;
                     53: 
                     54:        /*
                     55:         * Compute the prefix string, without trailing whitespace
                     56:         */
                     57:        cp2 = 0;
                     58:        for (cp = prefix; *cp; cp++)
                     59:                if (*cp != ' ' && *cp != '\t')
                     60:                        cp2 = cp;
                     61:        prefixlen = cp2 == 0 ? 0 : cp2 - prefix + 1;
                     62:        ibuf = setinput(mp);
                     63:        count = mp->m_size;
                     64:        ishead = 1;
                     65:        dostat = doign == 0 || !isign("status", doign);
                     66:        infld = 0;
                     67:        firstline = 1;
                     68:        /*
                     69:         * Process headers first
                     70:         */
                     71:        while (count > 0 && ishead) {
                     72:                if (fgets(line, LINESIZE, ibuf) == NULL)
                     73:                        break;
                     74:                count -= length = strlen(line);
                     75:                if (firstline) {
                     76:                        /* 
                     77:                         * First line is the From line, so no headers
                     78:                         * there to worry about
                     79:                         */
                     80:                        firstline = 0;
                     81:                        ignoring = doign == ignoreall;
                     82:                } else if (line[0] == '\n') {
                     83:                        /*
                     84:                         * If line is blank, we've reached end of
                     85:                         * headers, so force out status: field
                     86:                         * and note that we are no longer in header
                     87:                         * fields
                     88:                         */
                     89:                        if (dostat) {
                     90:                                statusput(mp, obuf, prefix);
                     91:                                dostat = 0;
                     92:                        }
                     93:                        ishead = 0;
                     94:                        ignoring = doign == ignoreall;
                     95:                } else if (infld && (line[0] == ' ' || line[0] == '\t')) {
                     96:                        /*
                     97:                         * If this line is a continuation (via space or tab)
                     98:                         * of a previous header field, just echo it
                     99:                         * (unless the field should be ignored).
                    100:                         * In other words, nothing to do.
                    101:                         */
                    102:                } else {
                    103:                        /*
                    104:                         * Pick up the header field if we have one.
                    105:                         */
                    106:                        for (cp = line; (c = *cp++) && c != ':' && !isspace(c);)
                    107:                                ;
                    108:                        cp2 = --cp;
                    109:                        while (isspace(*cp++))
                    110:                                ;
                    111:                        if (cp[-1] != ':') {
                    112:                                /*
                    113:                                 * Not a header line, force out status:
                    114:                                 * This happens in uucp style mail where
                    115:                                 * there are no headers at all.
                    116:                                 */
                    117:                                if (dostat) {
                    118:                                        statusput(mp, obuf, prefix);
                    119:                                        dostat = 0;
                    120:                                }
                    121:                                if (doign != ignoreall)
                    122:                                        /* add blank line */
                    123:                                        (void) putc('\n', obuf);
                    124:                                ishead = 0;
                    125:                                ignoring = 0;
                    126:                        } else {
                    127:                                /*
                    128:                                 * If it is an ignored field and
                    129:                                 * we care about such things, skip it.
                    130:                                 */
                    131:                                *cp2 = 0;       /* temporarily null terminate */
                    132:                                if (doign && isign(line, doign))
                    133:                                        ignoring = 1;
                    134:                                else if ((line[0] == 's' || line[0] == 'S') &&
                    135:                                         strcasecmp(line, "status") == 0) {
                    136:                                        /*
                    137:                                         * If the field is "status," go compute
                    138:                                         * and print the real Status: field
                    139:                                         */
                    140:                                        if (dostat) {
                    141:                                                statusput(mp, obuf, prefix);
                    142:                                                dostat = 0;
                    143:                                        }
                    144:                                        ignoring = 1;
                    145:                                } else {
                    146:                                        ignoring = 0;
                    147:                                        *cp2 = c;       /* restore */
                    148:                                }
                    149:                                infld = 1;
                    150:                        }
                    151:                }
                    152:                if (!ignoring) {
                    153:                        /*
                    154:                         * Strip trailing whitespace from prefix
                    155:                         * if line is blank.
                    156:                         */
                    157:                        if (prefix != NOSTR)
                    158:                                if (length > 1)
                    159:                                        fputs(prefix, obuf);
                    160:                                else
                    161:                                        (void) fwrite(prefix, sizeof *prefix,
                    162:                                                        prefixlen, obuf);
                    163:                        (void) fwrite(line, sizeof *line, length, obuf);
                    164:                        if (ferror(obuf))
                    165:                                return -1;
                    166:                }
                    167:        }
                    168:        /*
                    169:         * Copy out message body
                    170:         */
                    171:        if (doign == ignoreall)
                    172:                count--;                /* skip final blank line */
                    173:        if (prefix != NOSTR)
                    174:                while (count > 0) {
                    175:                        if (fgets(line, LINESIZE, ibuf) == NULL) {
                    176:                                c = 0;
                    177:                                break;
                    178:                        }
                    179:                        count -= c = strlen(line);
                    180:                        /*
                    181:                         * Strip trailing whitespace from prefix
                    182:                         * if line is blank.
                    183:                         */
                    184:                        if (c > 1)
                    185:                                fputs(prefix, obuf);
                    186:                        else
                    187:                                (void) fwrite(prefix, sizeof *prefix,
                    188:                                                prefixlen, obuf);
                    189:                        (void) fwrite(line, sizeof *line, c, obuf);
                    190:                        if (ferror(obuf))
                    191:                                return -1;
                    192:                }
                    193:        else
                    194:                while (count > 0) {
                    195:                        c = count < LINESIZE ? count : LINESIZE;
                    196:                        if ((c = fread(line, sizeof *line, c, ibuf)) <= 0)
                    197:                                break;
                    198:                        count -= c;
                    199:                        if (fwrite(line, sizeof *line, c, obuf) != c)
                    200:                                return -1;
                    201:                }
                    202:        if (doign == ignoreall && c > 0 && line[c - 1] != '\n')
                    203:                /* no final blank line */
                    204:                if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF)
                    205:                        return -1;
                    206:        return 0;
                    207: }
                    208: 
                    209: /*
                    210:  * Output a reasonable looking status field.
                    211:  */
                    212: statusput(mp, obuf, prefix)
                    213:        register struct message *mp;
                    214:        FILE *obuf;
                    215:        char *prefix;
                    216: {
                    217:        char statout[3];
                    218:        register char *cp = statout;
                    219: 
                    220:        if (mp->m_flag & MREAD)
                    221:                *cp++ = 'R';
                    222:        if ((mp->m_flag & MNEW) == 0)
                    223:                *cp++ = 'O';
                    224:        *cp = 0;
                    225:        if (statout[0])
                    226:                fprintf(obuf, "%sStatus: %s\n",
                    227:                        prefix == NOSTR ? "" : prefix, statout);
                    228: }
                    229: 
                    230: /*
                    231:  * Interface between the argument list and the mail1 routine
                    232:  * which does all the dirty work.
                    233:  */
                    234: mail(to, cc, bcc, smopts, subject)
                    235:        struct name *to, *cc, *bcc, *smopts;
                    236:        char *subject;
                    237: {
                    238:        struct header head;
                    239: 
                    240:        head.h_to = to;
                    241:        head.h_subject = subject;
                    242:        head.h_cc = cc;
                    243:        head.h_bcc = bcc;
                    244:        head.h_smopts = smopts;
                    245:        mail1(&head, 0);
                    246:        return(0);
                    247: }
                    248: 
                    249: 
                    250: /*
                    251:  * Send mail to a bunch of user names.  The interface is through
                    252:  * the mail routine below.
                    253:  */
                    254: sendmail(str)
                    255:        char *str;
                    256: {
                    257:        struct header head;
                    258: 
                    259:        head.h_to = extract(str, GTO);
                    260:        head.h_subject = NOSTR;
                    261:        head.h_cc = NIL;
                    262:        head.h_bcc = NIL;
                    263:        head.h_smopts = NIL;
                    264:        mail1(&head, 0);
                    265:        return(0);
                    266: }
                    267: 
                    268: /*
                    269:  * Mail a message on standard input to the people indicated
                    270:  * in the passed header.  (Internal interface).
                    271:  */
                    272: mail1(hp, printheaders)
                    273:        struct header *hp;
                    274: {
                    275:        char *cp;
                    276:        int pid;
                    277:        char **namelist;
                    278:        struct name *to;
                    279:        FILE *mtf;
                    280: 
                    281:        /*
                    282:         * Collect user's mail from standard input.
                    283:         * Get the result as mtf.
                    284:         */
                    285:        if ((mtf = collect(hp, printheaders)) == NULL)
                    286:                return;
                    287:        if (value("interactive") != NOSTR)
                    288:                if (value("askcc") != NOSTR)
                    289:                        grabh(hp, GCC);
                    290:                else {
                    291:                        printf("EOT\n");
                    292:                        (void) fflush(stdout);
                    293:                }
                    294:        if (fsize(mtf) == 0)
                    295:                if (hp->h_subject == NOSTR)
                    296:                        printf("No message, no subject; hope that's ok\n");
                    297:                else
                    298:                        printf("Null message body; hope that's ok\n");
                    299:        /*
                    300:         * Now, take the user names from the combined
                    301:         * to and cc lists and do all the alias
                    302:         * processing.
                    303:         */
                    304:        senderr = 0;
                    305:        to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)));
                    306:        if (to == NIL) {
                    307:                printf("No recipients specified\n");
                    308:                senderr++;
                    309:        }
                    310:        /*
                    311:         * Look through the recipient list for names with /'s
                    312:         * in them which we write to as files directly.
                    313:         */
                    314:        to = outof(to, mtf, hp);
                    315:        if (senderr)
                    316:                savedeadletter(mtf);
                    317:        to = elide(to);
                    318:        if (count(to) == 0)
                    319:                goto out;
                    320:        fixhead(hp, to);
                    321:        if ((mtf = infix(hp, mtf)) == NULL) {
                    322:                fprintf(stderr, ". . . message lost, sorry.\n");
                    323:                return;
                    324:        }
                    325:        namelist = unpack(cat(hp->h_smopts, to));
                    326:        if (debug) {
                    327:                char **t;
                    328: 
                    329:                printf("Sendmail arguments:");
                    330:                for (t = namelist; *t != NOSTR; t++)
                    331:                        printf(" \"%s\"", *t);
                    332:                printf("\n");
                    333:                goto out;
                    334:        }
                    335:        if ((cp = value("record")) != NOSTR)
                    336:                (void) savemail(expand(cp), mtf);
                    337:        /*
                    338:         * Fork, set up the temporary mail file as standard
                    339:         * input for "mail", and exec with the user list we generated
                    340:         * far above.
                    341:         */
                    342:        pid = fork();
                    343:        if (pid == -1) {
                    344:                perror("fork");
                    345:                savedeadletter(mtf);
                    346:                goto out;
                    347:        }
                    348:        if (pid == 0) {
                    349:                if (access(_PATH_MAIL_LOG, 0) == 0) {
                    350:                        FILE *postage;
                    351: 
                    352:                        if ((postage = Fopen(_PATH_MAIL_LOG, "a")) != NULL) {
                    353:                                fprintf(postage, "%s %d %ld\n", myname,
                    354:                                    count(to), fsize(mtf));
                    355:                                (void) Fclose(postage);
                    356:                        }
                    357:                }
                    358:                prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)|
                    359:                        sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU),
                    360:                        fileno(mtf), -1);
                    361:                if ((cp = value("sendmail")) != NOSTR)
                    362:                        cp = expand(cp);
                    363:                else
                    364:                        cp = _PATH_SENDMAIL;
                    365:                execv(cp, namelist);
                    366:                perror(cp);
                    367:                _exit(1);
                    368:        }
                    369:        if (value("verbose") != NOSTR)
                    370:                (void) wait_child(pid);
                    371:        else
                    372:                free_child(pid);
                    373: out:
                    374:        (void) Fclose(mtf);
                    375: }
                    376: 
                    377: /*
                    378:  * Fix the header by glopping all of the expanded names from
                    379:  * the distribution list into the appropriate fields.
                    380:  */
                    381: fixhead(hp, tolist)
                    382:        struct header *hp;
                    383:        struct name *tolist;
                    384: {
                    385:        register struct name *np;
                    386: 
                    387:        hp->h_to = NIL;
                    388:        hp->h_cc = NIL;
                    389:        hp->h_bcc = NIL;
                    390:        for (np = tolist; np != NIL; np = np->n_flink)
                    391:                if ((np->n_type & GMASK) == GTO)
                    392:                        hp->h_to =
                    393:                                cat(hp->h_to, nalloc(np->n_name, np->n_type));
                    394:                else if ((np->n_type & GMASK) == GCC)
                    395:                        hp->h_cc =
                    396:                                cat(hp->h_cc, nalloc(np->n_name, np->n_type));
                    397:                else if ((np->n_type & GMASK) == GBCC)
                    398:                        hp->h_bcc =
                    399:                                cat(hp->h_bcc, nalloc(np->n_name, np->n_type));
                    400: }
                    401: 
                    402: /*
                    403:  * Prepend a header in front of the collected stuff
                    404:  * and return the new file.
                    405:  */
                    406: FILE *
                    407: infix(hp, fi)
                    408:        struct header *hp;
                    409:        FILE *fi;
                    410: {
                    411:        extern char tempMail[];
                    412:        register FILE *nfo, *nfi;
                    413:        register int c;
                    414: 
                    415:        if ((nfo = Fopen(tempMail, "w")) == NULL) {
                    416:                perror(tempMail);
                    417:                return(fi);
                    418:        }
                    419:        if ((nfi = Fopen(tempMail, "r")) == NULL) {
                    420:                perror(tempMail);
                    421:                (void) Fclose(nfo);
                    422:                return(fi);
                    423:        }
                    424:        (void) remove(tempMail);
                    425:        (void) puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA);
                    426:        c = getc(fi);
                    427:        while (c != EOF) {
                    428:                (void) putc(c, nfo);
                    429:                c = getc(fi);
                    430:        }
                    431:        if (ferror(fi)) {
                    432:                perror("read");
                    433:                rewind(fi);
                    434:                return(fi);
                    435:        }
                    436:        (void) fflush(nfo);
                    437:        if (ferror(nfo)) {
                    438:                perror(tempMail);
                    439:                (void) Fclose(nfo);
                    440:                (void) Fclose(nfi);
                    441:                rewind(fi);
                    442:                return(fi);
                    443:        }
                    444:        (void) Fclose(nfo);
                    445:        (void) Fclose(fi);
                    446:        rewind(nfi);
                    447:        return(nfi);
                    448: }
                    449: 
                    450: /*
                    451:  * Dump the to, subject, cc header on the
                    452:  * passed file buffer.
                    453:  */
                    454: puthead(hp, fo, w)
                    455:        struct header *hp;
                    456:        FILE *fo;
                    457: {
                    458:        register int gotcha;
                    459: 
                    460:        gotcha = 0;
                    461:        if (hp->h_to != NIL && w & GTO)
                    462:                fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++;
                    463:        if (hp->h_subject != NOSTR && w & GSUBJECT)
                    464:                fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
                    465:        if (hp->h_cc != NIL && w & GCC)
                    466:                fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++;
                    467:        if (hp->h_bcc != NIL && w & GBCC)
                    468:                fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++;
                    469:        if (gotcha && w & GNL)
                    470:                (void) putc('\n', fo);
                    471:        return(0);
                    472: }
                    473: 
                    474: /*
                    475:  * Format the given header line to not exceed 72 characters.
                    476:  */
                    477: fmt(str, np, fo, comma)
                    478:        char *str;
                    479:        register struct name *np;
                    480:        FILE *fo;
                    481:        int comma;
                    482: {
                    483:        register col, len;
                    484: 
                    485:        comma = comma ? 1 : 0;
                    486:        col = strlen(str);
                    487:        if (col)
                    488:                fputs(str, fo);
                    489:        for (; np != NIL; np = np->n_flink) {
                    490:                if (np->n_flink == NIL)
                    491:                        comma = 0;
                    492:                len = strlen(np->n_name);
                    493:                col++;          /* for the space */
                    494:                if (col + len + comma > 72 && col > 4) {
                    495:                        fputs("\n    ", fo);
                    496:                        col = 4;
                    497:                } else
                    498:                        putc(' ', fo);
                    499:                fputs(np->n_name, fo);
                    500:                if (comma)
                    501:                        putc(',', fo);
                    502:                col += len + comma;
                    503:        }
                    504:        putc('\n', fo);
                    505: }
                    506: 
                    507: /*
                    508:  * Save the outgoing mail on the passed file.
                    509:  */
                    510: 
                    511: /*ARGSUSED*/
                    512: savemail(name, fi)
                    513:        char name[];
                    514:        register FILE *fi;
                    515: {
                    516:        register FILE *fo;
                    517:        char buf[BUFSIZ];
                    518:        register i;
                    519:        time_t now, time();
                    520:        char *ctime();
                    521: 
                    522:        if ((fo = Fopen(name, "a")) == NULL) {
                    523:                perror(name);
                    524:                return (-1);
                    525:        }
                    526:        (void) time(&now);
                    527:        fprintf(fo, "From %s %s", myname, ctime(&now));
                    528:        while ((i = fread(buf, 1, sizeof buf, fi)) > 0)
                    529:                (void) fwrite(buf, 1, i, fo);
                    530:        (void) putc('\n', fo);
                    531:        (void) fflush(fo);
                    532:        if (ferror(fo))
                    533:                perror(name);
                    534:        (void) Fclose(fo);
                    535:        rewind(fi);
                    536:        return (0);
                    537: }

unix.superglobalmegacorp.com

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