[BACK]Return to send.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / mail

Annotation of src/usr.bin/mail/send.c, Revision 1.19

1.19    ! martynas    1: /*     $OpenBSD: send.c,v 1.18 2007/03/20 21:01:08 millert Exp $       */
1.2       deraadt     2: /*     $NetBSD: send.c,v 1.6 1996/06/08 19:48:39 christos Exp $        */
                      3:
1.1       deraadt     4: /*
                      5:  * Copyright (c) 1980, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
1.17      millert    16:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: #ifndef lint
1.2       deraadt    34: #if 0
1.14      millert    35: static const char sccsid[] = "@(#)send.c       8.1 (Berkeley) 6/6/93";
1.2       deraadt    36: #else
1.19    ! martynas   37: static const char rcsid[] = "$OpenBSD: send.c,v 1.18 2007/03/20 21:01:08 millert Exp $";
1.2       deraadt    38: #endif
1.1       deraadt    39: #endif /* not lint */
                     40:
                     41: #include "rcv.h"
                     42: #include "extern.h"
                     43:
1.15      millert    44: static volatile sig_atomic_t sendsignal;       /* Interrupted by a signal? */
                     45:
1.1       deraadt    46: /*
                     47:  * Mail -- a mail program
                     48:  *
                     49:  * Mail to others.
                     50:  */
                     51:
                     52: /*
                     53:  * Send message described by the passed pointer to the
                     54:  * passed output buffer.  Return -1 on error.
                     55:  * Adjust the status: field if need be.
                     56:  * If doign is given, suppress ignored header fields.
                     57:  * prefix is a string to prepend to each output line.
                     58:  */
                     59: int
1.14      millert    60: sendmessage(struct message *mp, FILE *obuf, struct ignoretab *doign,
                     61:            char *prefix)
1.1       deraadt    62: {
1.7       millert    63:        int count;
1.9       millert    64:        FILE *ibuf;
1.1       deraadt    65:        char line[LINESIZE];
1.16      pjanzen    66:        char visline[4 * LINESIZE - 3];
1.2       deraadt    67:        int ishead, infld, ignoring = 0, dostat, firstline;
1.9       millert    68:        char *cp, *cp2;
                     69:        int c = 0;
1.1       deraadt    70:        int length;
1.2       deraadt    71:        int prefixlen = 0;
1.15      millert    72:        int rval;
1.16      pjanzen    73:        int dovis;
1.15      millert    74:        struct sigaction act, saveint;
                     75:        sigset_t oset;
                     76:
                     77:        sendsignal = 0;
                     78:        rval = -1;
1.16      pjanzen    79:        dovis = isatty(fileno(obuf));
1.15      millert    80:        sigemptyset(&act.sa_mask);
                     81:        act.sa_flags = SA_RESTART;
                     82:        act.sa_handler = sendint;
                     83:        (void)sigaction(SIGINT, &act, &saveint);
                     84:        (void)sigprocmask(SIG_UNBLOCK, &intset, &oset);
1.1       deraadt    85:
                     86:        /*
                     87:         * Compute the prefix string, without trailing whitespace
                     88:         */
1.5       millert    89:        if (prefix != NULL) {
1.1       deraadt    90:                cp2 = 0;
                     91:                for (cp = prefix; *cp; cp++)
                     92:                        if (*cp != ' ' && *cp != '\t')
                     93:                                cp2 = cp;
                     94:                prefixlen = cp2 == 0 ? 0 : cp2 - prefix + 1;
                     95:        }
                     96:        ibuf = setinput(mp);
                     97:        count = mp->m_size;
                     98:        ishead = 1;
                     99:        dostat = doign == 0 || !isign("status", doign);
                    100:        infld = 0;
                    101:        firstline = 1;
                    102:        /*
                    103:         * Process headers first
                    104:         */
                    105:        while (count > 0 && ishead) {
1.3       millert   106:                if (fgets(line, sizeof(line), ibuf) == NULL)
1.1       deraadt   107:                        break;
                    108:                count -= length = strlen(line);
                    109:                if (firstline) {
1.3       millert   110:                        /*
1.1       deraadt   111:                         * First line is the From line, so no headers
                    112:                         * there to worry about
                    113:                         */
                    114:                        firstline = 0;
                    115:                        ignoring = doign == ignoreall;
                    116:                } else if (line[0] == '\n') {
                    117:                        /*
                    118:                         * If line is blank, we've reached end of
                    119:                         * headers, so force out status: field
                    120:                         * and note that we are no longer in header
                    121:                         * fields
                    122:                         */
                    123:                        if (dostat) {
1.15      millert   124:                                if (statusput(mp, obuf, prefix) == -1)
                    125:                                        goto out;
1.1       deraadt   126:                                dostat = 0;
                    127:                        }
                    128:                        ishead = 0;
                    129:                        ignoring = doign == ignoreall;
                    130:                } else if (infld && (line[0] == ' ' || line[0] == '\t')) {
                    131:                        /*
                    132:                         * If this line is a continuation (via space or tab)
                    133:                         * of a previous header field, just echo it
                    134:                         * (unless the field should be ignored).
                    135:                         * In other words, nothing to do.
                    136:                         */
                    137:                } else {
                    138:                        /*
                    139:                         * Pick up the header field if we have one.
                    140:                         */
                    141:                        for (cp = line; (c = *cp++) && c != ':' && !isspace(c);)
                    142:                                ;
                    143:                        cp2 = --cp;
                    144:                        while (isspace(*cp++))
                    145:                                ;
                    146:                        if (cp[-1] != ':') {
                    147:                                /*
                    148:                                 * Not a header line, force out status:
                    149:                                 * This happens in uucp style mail where
                    150:                                 * there are no headers at all.
                    151:                                 */
                    152:                                if (dostat) {
1.15      millert   153:                                        if (statusput(mp, obuf, prefix) == -1)
                    154:                                                goto out;
1.1       deraadt   155:                                        dostat = 0;
                    156:                                }
                    157:                                if (doign != ignoreall)
                    158:                                        /* add blank line */
1.4       millert   159:                                        (void)putc('\n', obuf);
1.1       deraadt   160:                                ishead = 0;
                    161:                                ignoring = 0;
                    162:                        } else {
                    163:                                /*
                    164:                                 * If it is an ignored field and
                    165:                                 * we care about such things, skip it.
                    166:                                 */
                    167:                                *cp2 = 0;       /* temporarily null terminate */
                    168:                                if (doign && isign(line, doign))
                    169:                                        ignoring = 1;
1.19    ! martynas  170:                                else if (strcasecmp(line, "status") == 0) {
1.1       deraadt   171:                                        /*
                    172:                                         * If the field is "status," go compute
                    173:                                         * and print the real Status: field
                    174:                                         */
                    175:                                        if (dostat) {
1.15      millert   176:                                                if (statusput(mp, obuf, prefix) == -1)
                    177:                                                        goto out;
1.1       deraadt   178:                                                dostat = 0;
                    179:                                        }
                    180:                                        ignoring = 1;
                    181:                                } else {
                    182:                                        ignoring = 0;
                    183:                                        *cp2 = c;       /* restore */
                    184:                                }
                    185:                                infld = 1;
                    186:                        }
                    187:                }
                    188:                if (!ignoring) {
                    189:                        /*
                    190:                         * Strip trailing whitespace from prefix
                    191:                         * if line is blank.
                    192:                         */
1.13      millert   193:                        if (prefix != NULL) {
1.1       deraadt   194:                                if (length > 1)
                    195:                                        fputs(prefix, obuf);
                    196:                                else
1.4       millert   197:                                        (void)fwrite(prefix, sizeof(*prefix),
1.1       deraadt   198:                                                        prefixlen, obuf);
1.13      millert   199:                        }
1.16      pjanzen   200:                        if (dovis) {
                    201:                                length = strvis(visline, line, VIS_SAFE|VIS_NOSLASH);
                    202:                                (void)fwrite(visline, sizeof(*visline), length, obuf);
                    203:                        } else
                    204:                                (void)fwrite(line, sizeof(*line), length, obuf);
1.1       deraadt   205:                        if (ferror(obuf))
1.15      millert   206:                                goto out;
1.1       deraadt   207:                }
1.15      millert   208:                if (sendsignal == SIGINT)
                    209:                        goto out;
1.1       deraadt   210:        }
                    211:        /*
                    212:         * Copy out message body
                    213:         */
                    214:        if (doign == ignoreall)
                    215:                count--;                /* skip final blank line */
1.13      millert   216:        while (count > 0) {
                    217:                if (fgets(line, sizeof(line), ibuf) == NULL) {
                    218:                        c = 0;
                    219:                        break;
                    220:                }
                    221:                count -= c = strlen(line);
                    222:                if (prefix != NULL) {
1.1       deraadt   223:                        /*
                    224:                         * Strip trailing whitespace from prefix
                    225:                         * if line is blank.
                    226:                         */
                    227:                        if (c > 1)
                    228:                                fputs(prefix, obuf);
                    229:                        else
1.4       millert   230:                                (void)fwrite(prefix, sizeof(*prefix),
1.1       deraadt   231:                                                prefixlen, obuf);
                    232:                }
1.13      millert   233:                /*
                    234:                 * We can't read the record file (or inbox for recipient)
                    235:                 * properly with 'From ' lines in the message body (from
                    236:                 * forwarded messages or sentences starting with "From "),
                    237:                 * so we will prepend those lines with a '>'.
                    238:                 */
                    239:                if (strncmp(line, "From ", 5) == 0)
                    240:                        (void)fwrite(">", 1, 1, obuf); /* '>' before 'From ' */
1.16      pjanzen   241:                if (dovis) {
                    242:                        length = strvis(visline, line, VIS_SAFE|VIS_NOSLASH);
                    243:                        (void)fwrite(visline, sizeof(*visline), length, obuf);
                    244:                } else
                    245:                        (void)fwrite(line, sizeof(*line), c, obuf);
1.15      millert   246:                if (ferror(obuf) || sendsignal == SIGINT)
                    247:                        goto out;
1.13      millert   248:        }
1.1       deraadt   249:        if (doign == ignoreall && c > 0 && line[c - 1] != '\n')
                    250:                /* no final blank line */
                    251:                if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF)
1.15      millert   252:                        goto out;
                    253:        rval = 0;
                    254: out:
                    255:        sendsignal = 0;
                    256:        (void)sigprocmask(SIG_SETMASK, &oset, NULL);
                    257:        (void)sigaction(SIGINT, &saveint, NULL);
                    258:        return(rval);
1.1       deraadt   259: }
                    260:
                    261: /*
                    262:  * Output a reasonable looking status field.
                    263:  */
1.15      millert   264: int
1.14      millert   265: statusput(struct message *mp, FILE *obuf, char *prefix)
1.1       deraadt   266: {
                    267:        char statout[3];
1.9       millert   268:        char *cp = statout;
1.1       deraadt   269:
                    270:        if (mp->m_flag & MREAD)
                    271:                *cp++ = 'R';
                    272:        if ((mp->m_flag & MNEW) == 0)
                    273:                *cp++ = 'O';
                    274:        *cp = 0;
1.15      millert   275:        if (statout[0]) {
1.1       deraadt   276:                fprintf(obuf, "%sStatus: %s\n",
1.5       millert   277:                        prefix == NULL ? "" : prefix, statout);
1.15      millert   278:                return(ferror(obuf) ? -1 : 0);
                    279:        }
                    280:        return(0);
1.1       deraadt   281: }
                    282:
                    283: /*
                    284:  * Interface between the argument list and the mail1 routine
                    285:  * which does all the dirty work.
                    286:  */
                    287: int
1.14      millert   288: mail(struct name *to, struct name *cc, struct name *bcc, struct name *smopts,
                    289:      char *subject)
1.1       deraadt   290: {
                    291:        struct header head;
                    292:
                    293:        head.h_to = to;
                    294:        head.h_subject = subject;
                    295:        head.h_cc = cc;
                    296:        head.h_bcc = bcc;
                    297:        head.h_smopts = smopts;
                    298:        mail1(&head, 0);
                    299:        return(0);
                    300: }
                    301:
                    302:
                    303: /*
                    304:  * Send mail to a bunch of user names.  The interface is through
                    305:  * the mail routine below.
                    306:  */
                    307: int
1.14      millert   308: sendmail(void *v)
1.1       deraadt   309: {
1.2       deraadt   310:        char *str = v;
1.1       deraadt   311:        struct header head;
                    312:
                    313:        head.h_to = extract(str, GTO);
1.5       millert   314:        head.h_subject = NULL;
1.14      millert   315:        head.h_cc = NULL;
                    316:        head.h_bcc = NULL;
                    317:        head.h_smopts = NULL;
1.1       deraadt   318:        mail1(&head, 0);
                    319:        return(0);
                    320: }
                    321:
                    322: /*
                    323:  * Mail a message on standard input to the people indicated
                    324:  * in the passed header.  (Internal interface).
                    325:  */
                    326: void
1.14      millert   327: mail1(struct header *hp, int printheaders)
1.1       deraadt   328: {
                    329:        char *cp;
1.14      millert   330:        pid_t pid;
1.1       deraadt   331:        char **namelist;
                    332:        struct name *to;
                    333:        FILE *mtf;
                    334:
                    335:        /*
                    336:         * Collect user's mail from standard input.
                    337:         * Get the result as mtf.
                    338:         */
                    339:        if ((mtf = collect(hp, printheaders)) == NULL)
                    340:                return;
1.13      millert   341:        if (fsize(mtf) == 0) {
1.5       millert   342:                if (hp->h_subject == NULL)
1.3       millert   343:                        puts("No message, no subject; hope that's ok");
1.1       deraadt   344:                else
1.3       millert   345:                        puts("Null message body; hope that's ok");
1.13      millert   346:        }
1.1       deraadt   347:        /*
                    348:         * Now, take the user names from the combined
                    349:         * to and cc lists and do all the alias
                    350:         * processing.
                    351:         */
                    352:        senderr = 0;
                    353:        to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)));
1.14      millert   354:        if (to == NULL) {
1.3       millert   355:                puts("No recipients specified");
1.1       deraadt   356:                senderr++;
                    357:        }
                    358:        /*
                    359:         * Look through the recipient list for names with /'s
                    360:         * in them which we write to as files directly.
                    361:         */
                    362:        to = outof(to, mtf, hp);
                    363:        if (senderr)
                    364:                savedeadletter(mtf);
                    365:        to = elide(to);
                    366:        if (count(to) == 0)
                    367:                goto out;
                    368:        fixhead(hp, to);
                    369:        if ((mtf = infix(hp, mtf)) == NULL) {
1.3       millert   370:                fputs(". . . message lost, sorry.\n", stderr);
1.1       deraadt   371:                return;
                    372:        }
1.12      mickey    373:        namelist = unpack(hp->h_smopts, to);
1.1       deraadt   374:        if (debug) {
                    375:                char **t;
                    376:
1.3       millert   377:                fputs("Sendmail arguments:", stdout);
1.5       millert   378:                for (t = namelist; *t != NULL; t++)
1.1       deraadt   379:                        printf(" \"%s\"", *t);
1.3       millert   380:                putchar('\n');
1.1       deraadt   381:                goto out;
                    382:        }
1.5       millert   383:        if ((cp = value("record")) != NULL)
1.4       millert   384:                (void)savemail(expand(cp), mtf);
1.1       deraadt   385:        /*
                    386:         * Fork, set up the temporary mail file as standard
                    387:         * input for "mail", and exec with the user list we generated
                    388:         * far above.
                    389:         */
                    390:        pid = fork();
                    391:        if (pid == -1) {
1.3       millert   392:                warn("fork");
1.1       deraadt   393:                savedeadletter(mtf);
                    394:                goto out;
                    395:        }
                    396:        if (pid == 0) {
1.2       deraadt   397:                sigset_t nset;
1.6       millert   398:
1.2       deraadt   399:                sigemptyset(&nset);
                    400:                sigaddset(&nset, SIGHUP);
                    401:                sigaddset(&nset, SIGINT);
                    402:                sigaddset(&nset, SIGQUIT);
                    403:                sigaddset(&nset, SIGTSTP);
                    404:                sigaddset(&nset, SIGTTIN);
                    405:                sigaddset(&nset, SIGTTOU);
                    406:                prepare_child(&nset, fileno(mtf), -1);
1.5       millert   407:                if ((cp = value("sendmail")) != NULL)
1.1       deraadt   408:                        cp = expand(cp);
                    409:                else
                    410:                        cp = _PATH_SENDMAIL;
                    411:                execv(cp, namelist);
1.11      millert   412:                warn("%s", cp);
1.1       deraadt   413:                _exit(1);
                    414:        }
1.5       millert   415:        if (value("verbose") != NULL)
1.4       millert   416:                (void)wait_child(pid);
1.1       deraadt   417:        else
                    418:                free_child(pid);
                    419: out:
1.3       millert   420:        (void)Fclose(mtf);
1.1       deraadt   421: }
                    422:
                    423: /*
                    424:  * Fix the header by glopping all of the expanded names from
                    425:  * the distribution list into the appropriate fields.
                    426:  */
                    427: void
1.14      millert   428: fixhead(struct header *hp, struct name *tolist)
1.1       deraadt   429: {
1.9       millert   430:        struct name *np;
1.1       deraadt   431:
1.14      millert   432:        hp->h_to = NULL;
                    433:        hp->h_cc = NULL;
                    434:        hp->h_bcc = NULL;
                    435:        for (np = tolist; np != NULL; np = np->n_flink)
1.1       deraadt   436:                if ((np->n_type & GMASK) == GTO)
                    437:                        hp->h_to =
                    438:                                cat(hp->h_to, nalloc(np->n_name, np->n_type));
                    439:                else if ((np->n_type & GMASK) == GCC)
                    440:                        hp->h_cc =
                    441:                                cat(hp->h_cc, nalloc(np->n_name, np->n_type));
                    442:                else if ((np->n_type & GMASK) == GBCC)
                    443:                        hp->h_bcc =
                    444:                                cat(hp->h_bcc, nalloc(np->n_name, np->n_type));
                    445: }
                    446:
                    447: /*
                    448:  * Prepend a header in front of the collected stuff
                    449:  * and return the new file.
                    450:  */
                    451: FILE *
1.14      millert   452: infix(struct header *hp, FILE *fi)
1.1       deraadt   453: {
1.9       millert   454:        FILE *nfo, *nfi;
1.8       millert   455:        int c, fd;
                    456:        char tempname[PATHSIZE];
1.1       deraadt   457:
1.8       millert   458:        (void)snprintf(tempname, sizeof(tempname),
                    459:            "%s/mail.RsXXXXXXXXXX", tmpdir);
                    460:        if ((fd = mkstemp(tempname)) == -1 ||
                    461:            (nfo = Fdopen(fd, "w")) == NULL) {
1.11      millert   462:                warn("%s", tempname);
1.1       deraadt   463:                return(fi);
                    464:        }
1.8       millert   465:        if ((nfi = Fopen(tempname, "r")) == NULL) {
1.11      millert   466:                warn("%s", tempname);
1.3       millert   467:                (void)Fclose(nfo);
1.8       millert   468:                (void)rm(tempname);
1.1       deraadt   469:                return(fi);
                    470:        }
1.8       millert   471:        (void)rm(tempname);
1.4       millert   472:        (void)puthead(hp, nfo, GTO|GSUBJECT|GCC|GBCC|GNL|GCOMMA);
1.1       deraadt   473:        c = getc(fi);
                    474:        while (c != EOF) {
1.4       millert   475:                (void)putc(c, nfo);
1.1       deraadt   476:                c = getc(fi);
                    477:        }
                    478:        if (ferror(fi)) {
1.3       millert   479:                warn("read");
1.1       deraadt   480:                rewind(fi);
                    481:                return(fi);
                    482:        }
1.4       millert   483:        (void)fflush(nfo);
1.1       deraadt   484:        if (ferror(nfo)) {
1.11      millert   485:                warn("%s", tempname);
1.3       millert   486:                (void)Fclose(nfo);
                    487:                (void)Fclose(nfi);
1.1       deraadt   488:                rewind(fi);
                    489:                return(fi);
                    490:        }
1.3       millert   491:        (void)Fclose(nfo);
                    492:        (void)Fclose(fi);
1.1       deraadt   493:        rewind(nfi);
                    494:        return(nfi);
                    495: }
                    496:
                    497: /*
                    498:  * Dump the to, subject, cc header on the
                    499:  * passed file buffer.
                    500:  */
                    501: int
1.14      millert   502: puthead(struct header *hp, FILE *fo, int w)
1.1       deraadt   503: {
1.9       millert   504:        int gotcha;
1.1       deraadt   505:
                    506:        gotcha = 0;
1.14      millert   507:        if (hp->h_to != NULL && w & GTO)
1.1       deraadt   508:                fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++;
1.5       millert   509:        if (hp->h_subject != NULL && w & GSUBJECT)
1.1       deraadt   510:                fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
1.14      millert   511:        if (hp->h_cc != NULL && w & GCC)
1.1       deraadt   512:                fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++;
1.14      millert   513:        if (hp->h_bcc != NULL && w & GBCC)
1.1       deraadt   514:                fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++;
                    515:        if (gotcha && w & GNL)
1.4       millert   516:                (void)putc('\n', fo);
1.1       deraadt   517:        return(0);
                    518: }
                    519:
                    520: /*
                    521:  * Format the given header line to not exceed 72 characters.
                    522:  */
                    523: void
1.14      millert   524: fmt(char *str, struct name *np, FILE *fo, int comma)
1.1       deraadt   525: {
1.9       millert   526:        int col, len;
1.1       deraadt   527:
                    528:        comma = comma ? 1 : 0;
                    529:        col = strlen(str);
                    530:        if (col)
                    531:                fputs(str, fo);
1.14      millert   532:        for (; np != NULL; np = np->n_flink) {
                    533:                if (np->n_flink == NULL)
1.1       deraadt   534:                        comma = 0;
                    535:                len = strlen(np->n_name);
                    536:                col++;          /* for the space */
                    537:                if (col + len + comma > 72 && col > 4) {
                    538:                        fputs("\n    ", fo);
                    539:                        col = 4;
                    540:                } else
                    541:                        putc(' ', fo);
                    542:                fputs(np->n_name, fo);
                    543:                if (comma)
                    544:                        putc(',', fo);
                    545:                col += len + comma;
                    546:        }
                    547:        putc('\n', fo);
                    548: }
                    549:
                    550: /*
                    551:  * Save the outgoing mail on the passed file.
                    552:  */
                    553: /*ARGSUSED*/
                    554: int
1.14      millert   555: savemail(char *name, FILE *fi)
1.1       deraadt   556: {
1.9       millert   557:        FILE *fo;
1.1       deraadt   558:        char buf[BUFSIZ];
1.2       deraadt   559:        time_t now;
1.18      millert   560:        mode_t m;
1.1       deraadt   561:
1.18      millert   562:        m = umask(077);
                    563:        fo = Fopen(name, "a");
                    564:        (void)umask(m);
                    565:        if (fo == NULL) {
1.11      millert   566:                warn("%s", name);
1.3       millert   567:                return(-1);
1.1       deraadt   568:        }
1.4       millert   569:        (void)time(&now);
1.1       deraadt   570:        fprintf(fo, "From %s %s", myname, ctime(&now));
1.13      millert   571:        while (fgets(buf, sizeof(buf), fi) == buf) {
                    572:                /*
                    573:                 * We can't read the record file (or inbox for recipient)
                    574:                 * in the message body (from forwarded messages or sentences
                    575:                 * starting with "From "), so we will prepend those lines with
                    576:                 * a '>'.
                    577:                 */
                    578:                if (strncmp(buf, "From ", 5) == 0)
                    579:                        (void)fwrite(">", 1, 1, fo);   /* '>' before 'From ' */
                    580:                (void)fwrite(buf, 1, strlen(buf), fo);
                    581:        }
1.4       millert   582:        (void)putc('\n', fo);
                    583:        (void)fflush(fo);
1.1       deraadt   584:        if (ferror(fo))
1.11      millert   585:                warn("%s", name);
1.3       millert   586:        (void)Fclose(fo);
1.1       deraadt   587:        rewind(fi);
1.3       millert   588:        return(0);
1.15      millert   589: }
                    590:
                    591: /*ARGSUSED*/
                    592: void
                    593: sendint(int s)
                    594: {
                    595:
                    596:        sendsignal = s;
1.1       deraadt   597: }