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

Annotation of src/usr.bin/mail/collect.c, Revision 1.24

1.24    ! millert     1: /*     $OpenBSD: collect.c,v 1.23 2001/11/21 15:26:39 millert Exp $    */
1.6       millert     2: /*     $NetBSD: collect.c,v 1.9 1997/07/09 05:25:45 mikel Exp $        */
1.2       deraadt     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.
                     16:  * 3. All advertising materials mentioning features or use of this software
                     17:  *    must display the following acknowledgement:
                     18:  *     This product includes software developed by the University of
                     19:  *     California, Berkeley and its contributors.
                     20:  * 4. Neither the name of the University nor the names of its contributors
                     21:  *    may be used to endorse or promote products derived from this software
                     22:  *    without specific prior written permission.
                     23:  *
                     24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     34:  * SUCH DAMAGE.
                     35:  */
                     36:
                     37: #ifndef lint
1.2       deraadt    38: #if 0
1.23      millert    39: static const char sccsid[] = "@(#)collect.c    8.2 (Berkeley) 4/19/94";
1.2       deraadt    40: #else
1.24    ! millert    41: static const char rcsid[] = "$OpenBSD: collect.c,v 1.23 2001/11/21 15:26:39 millert Exp $";
1.2       deraadt    42: #endif
1.1       deraadt    43: #endif /* not lint */
                     44:
                     45: /*
                     46:  * Mail -- a mail program
                     47:  *
                     48:  * Collect input from standard input, handling
                     49:  * ~ escapes.
                     50:  */
                     51:
                     52: #include "rcv.h"
                     53: #include "extern.h"
                     54:
                     55: /*
                     56:  * Read a message from standard output and return a read file to it
                     57:  * or NULL on error.
                     58:  */
                     59:
                     60: /*
                     61:  * The following hokiness with global variables is so that on
                     62:  * receipt of an interrupt signal, the partial message can be salted
                     63:  * away on dead.letter.
                     64:  */
                     65: static FILE    *collf;                 /* File for saving away */
                     66: static int     hadintr;                /* Have seen one SIGINT so far */
                     67:
                     68: FILE *
1.23      millert    69: collect(struct header *hp, int printheaders)
1.1       deraadt    70: {
                     71:        FILE *fbuf;
1.22      millert    72:        int lc, cc, fd, c, t, lastlong, rc, sig;
                     73:        int escape, eofcount, longline;
                     74:        char getsub;
1.21      millert    75:        char linebuf[LINESIZE], tempname[PATHSIZE], *cp;
1.1       deraadt    76:
                     77:        collf = NULL;
1.22      millert    78:        eofcount = 0;
                     79:        hadintr = 0;
                     80:        lastlong = 0;
                     81:        longline = 0;
                     82:        if ((cp = value("escape")) != NULL)
                     83:                escape = *cp;
                     84:        else
                     85:                escape = ESCAPE;
                     86:        noreset++;
1.1       deraadt    87:
1.12      millert    88:        (void)snprintf(tempname, sizeof(tempname),
                     89:            "%s/mail.RsXXXXXXXXXX", tmpdir);
                     90:        if ((fd = mkstemp(tempname)) == -1 ||
                     91:            (collf = Fdopen(fd, "w+")) == NULL) {
1.19      millert    92:                warn("%s", tempname);
1.1       deraadt    93:                goto err;
                     94:        }
1.12      millert    95:        (void)rm(tempname);
1.1       deraadt    96:
                     97:        /*
                     98:         * If we are going to prompt for a subject,
                     99:         * refrain from printing a newline after
                    100:         * the headers (since some people mind).
                    101:         */
                    102:        t = GTO|GSUBJECT|GCC|GNL;
                    103:        getsub = 0;
1.8       millert   104:        if (hp->h_subject == NULL && value("interactive") != NULL &&
                    105:            (value("ask") != NULL || value("asksub") != NULL))
1.1       deraadt   106:                t &= ~GNL, getsub++;
                    107:        if (printheaders) {
                    108:                puthead(hp, stdout, t);
                    109:                fflush(stdout);
                    110:        }
1.22      millert   111:        if (getsub && gethfromtty(hp, GSUBJECT) == -1)
                    112:                goto err;
1.1       deraadt   113:
1.22      millert   114:        if (0) {
1.1       deraadt   115: cont:
1.22      millert   116:                /* Come here for printing the after-suspend message. */
                    117:                if (isatty(0)) {
                    118:                        puts("(continue)");
1.1       deraadt   119:                        fflush(stdout);
                    120:                }
                    121:        }
                    122:        for (;;) {
1.22      millert   123:                c = readline(stdin, linebuf, LINESIZE, &sig);
                    124:
                    125:                /* Act on any signal caught during readline() ignoring 'c' */
                    126:                switch (sig) {
                    127:                case 0:
                    128:                        break;
                    129:                case SIGINT:
                    130:                        if (collabort())
                    131:                                goto err;
                    132:                        continue;
                    133:                case SIGHUP:
                    134:                        rewind(collf);
                    135:                        savedeadletter(collf);
                    136:                        /*
                    137:                         * Let's pretend nobody else wants to clean up,
                    138:                         * a true statement at this time.
                    139:                         */
                    140:                        exit(1);
                    141:                default:
                    142:                        /* Stopped due to job control */
                    143:                        (void)kill(0, sig);
                    144:                        goto cont;
                    145:                }
                    146:
                    147:                /* No signal, check for error */
1.1       deraadt   148:                if (c < 0) {
1.8       millert   149:                        if (value("interactive") != NULL &&
                    150:                            value("ignoreeof") != NULL && ++eofcount < 25) {
1.6       millert   151:                                puts("Use \".\" to terminate letter");
1.1       deraadt   152:                                continue;
                    153:                        }
                    154:                        break;
                    155:                }
1.6       millert   156:                lastlong = longline;
                    157:                longline = (c == LINESIZE - 1);
1.1       deraadt   158:                eofcount = 0;
                    159:                hadintr = 0;
                    160:                if (linebuf[0] == '.' && linebuf[1] == '\0' &&
1.8       millert   161:                    value("interactive") != NULL && !lastlong &&
                    162:                    (value("dot") != NULL || value("ignoreeof") != NULL))
1.1       deraadt   163:                        break;
1.24    ! millert   164:                if (linebuf[0] != escape || value("interactive") == NULL ||
        !           165:                    lastlong) {
1.6       millert   166:                        if (putline(collf, linebuf, !longline) < 0)
1.1       deraadt   167:                                goto err;
                    168:                        continue;
                    169:                }
                    170:                c = linebuf[1];
                    171:                switch (c) {
                    172:                default:
                    173:                        /*
                    174:                         * On double escape, just send the single one.
                    175:                         * Otherwise, it's an error.
                    176:                         */
                    177:                        if (c == escape) {
1.6       millert   178:                                if (putline(collf, &linebuf[1], !longline) < 0)
1.1       deraadt   179:                                        goto err;
                    180:                                else
                    181:                                        break;
                    182:                        }
1.6       millert   183:                        puts("Unknown tilde escape.");
1.1       deraadt   184:                        break;
                    185:                case 'C':
                    186:                        /*
                    187:                         * Dump core.
                    188:                         */
1.2       deraadt   189:                        core(NULL);
1.1       deraadt   190:                        break;
                    191:                case '!':
                    192:                        /*
                    193:                         * Shell escape, send the balance of the
                    194:                         * line to sh -c.
                    195:                         */
                    196:                        shell(&linebuf[2]);
                    197:                        break;
                    198:                case ':':
                    199:                case '_':
                    200:                        /*
                    201:                         * Escape to command mode, but be nice!
                    202:                         */
                    203:                        execute(&linebuf[2], 1);
                    204:                        goto cont;
                    205:                case '.':
                    206:                        /*
                    207:                         * Simulate end of file on input.
                    208:                         */
                    209:                        goto out;
                    210:                case 'q':
                    211:                        /*
                    212:                         * Force a quit of sending mail.
                    213:                         * Act like an interrupt happened.
                    214:                         */
                    215:                        hadintr++;
1.22      millert   216:                        collabort();
                    217:                        fputs("Interrupt\n", stderr);
                    218:                        goto err;
1.1       deraadt   219:                case 'h':
                    220:                        /*
                    221:                         * Grab a bunch of headers.
                    222:                         */
                    223:                        grabh(hp, GTO|GSUBJECT|GCC|GBCC);
                    224:                        goto cont;
                    225:                case 't':
                    226:                        /*
                    227:                         * Add to the To list.
                    228:                         */
                    229:                        hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO));
                    230:                        break;
                    231:                case 's':
                    232:                        /*
                    233:                         * Set the Subject list.
                    234:                         */
                    235:                        cp = &linebuf[2];
                    236:                        while (isspace(*cp))
                    237:                                cp++;
                    238:                        hp->h_subject = savestr(cp);
                    239:                        break;
                    240:                case 'c':
                    241:                        /*
                    242:                         * Add to the CC list.
                    243:                         */
                    244:                        hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC));
                    245:                        break;
                    246:                case 'b':
                    247:                        /*
                    248:                         * Add stuff to blind carbon copies list.
                    249:                         */
                    250:                        hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC));
                    251:                        break;
                    252:                case 'd':
1.23      millert   253:                        linebuf[2] = '\0';
                    254:                        strlcat(linebuf, getdeadletter(), sizeof(linebuf));
1.1       deraadt   255:                        /* fall into . . . */
                    256:                case 'r':
                    257:                case '<':
                    258:                        /*
                    259:                         * Invoke a file:
                    260:                         * Search for the file name,
                    261:                         * then open it and copy the contents to collf.
                    262:                         */
                    263:                        cp = &linebuf[2];
                    264:                        while (isspace(*cp))
                    265:                                cp++;
                    266:                        if (*cp == '\0') {
1.6       millert   267:                                puts("Interpolate what file?");
1.1       deraadt   268:                                break;
                    269:                        }
                    270:                        cp = expand(cp);
1.8       millert   271:                        if (cp == NULL)
1.1       deraadt   272:                                break;
                    273:                        if (isdir(cp)) {
                    274:                                printf("%s: Directory\n", cp);
                    275:                                break;
                    276:                        }
                    277:                        if ((fbuf = Fopen(cp, "r")) == NULL) {
1.19      millert   278:                                warn("%s", cp);
1.1       deraadt   279:                                break;
                    280:                        }
                    281:                        printf("\"%s\" ", cp);
                    282:                        fflush(stdout);
                    283:                        lc = 0;
                    284:                        cc = 0;
1.22      millert   285:                        while ((rc = readline(fbuf, linebuf, LINESIZE, NULL)) >= 0) {
1.6       millert   286:                                if (rc != LINESIZE - 1)
                    287:                                        lc++;
                    288:                                if ((t = putline(collf, linebuf,
                    289:                                                 rc != LINESIZE-1)) < 0) {
                    290:                                        (void)Fclose(fbuf);
1.1       deraadt   291:                                        goto err;
                    292:                                }
                    293:                                cc += t;
                    294:                        }
1.6       millert   295:                        (void)Fclose(fbuf);
1.1       deraadt   296:                        printf("%d/%d\n", lc, cc);
                    297:                        break;
                    298:                case 'w':
                    299:                        /*
                    300:                         * Write the message on a file.
                    301:                         */
                    302:                        cp = &linebuf[2];
                    303:                        while (*cp == ' ' || *cp == '\t')
                    304:                                cp++;
                    305:                        if (*cp == '\0') {
1.6       millert   306:                                fputs("Write what file!?\n", stderr);
1.1       deraadt   307:                                break;
                    308:                        }
1.8       millert   309:                        if ((cp = expand(cp)) == NULL)
1.1       deraadt   310:                                break;
                    311:                        rewind(collf);
                    312:                        exwrite(cp, collf, 1);
                    313:                        break;
                    314:                case 'm':
                    315:                case 'M':
                    316:                case 'f':
                    317:                case 'F':
                    318:                        /*
                    319:                         * Interpolate the named messages, if we
                    320:                         * are in receiving mail mode.  Does the
                    321:                         * standard list processing garbage.
                    322:                         * If ~f is given, we don't shift over.
                    323:                         */
1.12      millert   324:                        if (forward(linebuf + 2, collf, tempname, c) < 0)
1.1       deraadt   325:                                goto err;
                    326:                        goto cont;
                    327:                case '?':
                    328:                        if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) {
1.6       millert   329:                                warn(_PATH_TILDE);
1.1       deraadt   330:                                break;
                    331:                        }
                    332:                        while ((t = getc(fbuf)) != EOF)
1.7       millert   333:                                (void)putchar(t);
1.6       millert   334:                        (void)Fclose(fbuf);
1.1       deraadt   335:                        break;
                    336:                case 'p':
                    337:                        /*
                    338:                         * Print out the current state of the
                    339:                         * message without altering anything.
                    340:                         */
                    341:                        rewind(collf);
1.6       millert   342:                        puts("-------\nMessage contains:");
1.1       deraadt   343:                        puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL);
                    344:                        while ((t = getc(collf)) != EOF)
1.7       millert   345:                                (void)putchar(t);
1.1       deraadt   346:                        goto cont;
                    347:                case '|':
                    348:                        /*
                    349:                         * Pipe message through command.
                    350:                         * Collect output as new message.
                    351:                         */
                    352:                        rewind(collf);
                    353:                        mespipe(collf, &linebuf[2]);
                    354:                        goto cont;
                    355:                case 'v':
                    356:                case 'e':
                    357:                        /*
                    358:                         * Edit the current message.
                    359:                         * 'e' means to use EDITOR
                    360:                         * 'v' means to use VISUAL
                    361:                         */
                    362:                        rewind(collf);
                    363:                        mesedit(collf, c);
                    364:                        goto cont;
                    365:                }
                    366:        }
1.11      millert   367:
                    368:        if (value("interactive") != NULL) {
                    369:                if (value("askcc") != NULL || value("askbcc") != NULL) {
1.22      millert   370:                        if (value("askcc") != NULL) {
                    371:                                if (gethfromtty(hp, GCC) == -1)
                    372:                                        goto err;
                    373:                        }
                    374:                        if (value("askbcc") != NULL) {
                    375:                                if (gethfromtty(hp, GBCC) == -1)
                    376:                                        goto err;
                    377:                        }
1.11      millert   378:                } else {
                    379:                        puts("EOT");
                    380:                        (void)fflush(stdout);
                    381:                }
                    382:        }
1.1       deraadt   383:        goto out;
                    384: err:
                    385:        if (collf != NULL) {
1.6       millert   386:                (void)Fclose(collf);
1.1       deraadt   387:                collf = NULL;
                    388:        }
                    389: out:
                    390:        if (collf != NULL)
                    391:                rewind(collf);
                    392:        noreset--;
1.6       millert   393:        return(collf);
1.1       deraadt   394: }
                    395:
                    396: /*
                    397:  * Write a file, ex-like if f set.
                    398:  */
                    399: int
1.23      millert   400: exwrite(char *name, FILE *fp, int f)
1.1       deraadt   401: {
1.15      millert   402:        FILE *of;
                    403:        int c;
1.11      millert   404:        ssize_t cc, lc;
1.1       deraadt   405:        struct stat junk;
                    406:
                    407:        if (f) {
                    408:                printf("\"%s\" ", name);
                    409:                fflush(stdout);
                    410:        }
1.15      millert   411:        if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) {
1.1       deraadt   412:                if (!f)
                    413:                        fprintf(stderr, "%s: ", name);
1.6       millert   414:                fputs("File exists\n", stderr);
1.1       deraadt   415:                return(-1);
                    416:        }
                    417:        if ((of = Fopen(name, "w")) == NULL) {
1.8       millert   418:                warn(NULL);
1.1       deraadt   419:                return(-1);
                    420:        }
                    421:        lc = 0;
                    422:        cc = 0;
                    423:        while ((c = getc(fp)) != EOF) {
                    424:                cc++;
                    425:                if (c == '\n')
                    426:                        lc++;
1.7       millert   427:                (void)putc(c, of);
1.1       deraadt   428:                if (ferror(of)) {
1.19      millert   429:                        warn("%s", name);
1.6       millert   430:                        (void)Fclose(of);
1.1       deraadt   431:                        return(-1);
                    432:                }
                    433:        }
1.6       millert   434:        (void)Fclose(of);
1.11      millert   435:        printf("%d/%d\n", lc, cc);
1.1       deraadt   436:        fflush(stdout);
                    437:        return(0);
                    438: }
                    439:
                    440: /*
                    441:  * Edit the message being collected on fp.
                    442:  * On return, make the edit file the new temp file.
                    443:  */
                    444: void
1.23      millert   445: mesedit(FILE *fp, int c)
1.1       deraadt   446: {
1.22      millert   447:        FILE *nf;
                    448:        struct sigaction oact;
                    449:        sigset_t oset;
1.1       deraadt   450:
1.22      millert   451:        (void)ignoresig(SIGINT, &oact, &oset);
                    452:        nf = run_editor(fp, (off_t)-1, c, 0);
1.1       deraadt   453:        if (nf != NULL) {
                    454:                fseek(nf, 0L, 2);
                    455:                collf = nf;
1.6       millert   456:                (void)Fclose(fp);
1.1       deraadt   457:        }
1.22      millert   458:        (void)sigprocmask(SIG_SETMASK, &oset, NULL);
                    459:        (void)sigaction(SIGINT, &oact, NULL);
1.1       deraadt   460: }
                    461:
                    462: /*
                    463:  * Pipe the message through the command.
                    464:  * Old message is on stdin of command;
                    465:  * New message collected from stdout.
                    466:  * Sh -c must return 0 to accept the new message.
                    467:  */
                    468: void
1.23      millert   469: mespipe(FILE *fp, char *cmd)
1.1       deraadt   470: {
                    471:        FILE *nf;
1.12      millert   472:        int fd;
                    473:        char *shell, tempname[PATHSIZE];
1.22      millert   474:        struct sigaction oact;
                    475:        sigset_t oset;
1.1       deraadt   476:
1.22      millert   477:        (void)ignoresig(SIGINT, &oact, &oset);
1.12      millert   478:        (void)snprintf(tempname, sizeof(tempname),
                    479:            "%s/mail.ReXXXXXXXXXX", tmpdir);
                    480:        if ((fd = mkstemp(tempname)) == -1 ||
                    481:            (nf = Fdopen(fd, "w+")) == NULL) {
1.19      millert   482:                warn("%s", tempname);
1.1       deraadt   483:                goto out;
                    484:        }
1.12      millert   485:        (void)rm(tempname);
1.1       deraadt   486:        /*
                    487:         * stdin = current message.
                    488:         * stdout = new message.
                    489:         */
1.20      millert   490:        shell = value("SHELL");
1.1       deraadt   491:        if (run_command(shell,
1.8       millert   492:            0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) {
1.6       millert   493:                (void)Fclose(nf);
1.1       deraadt   494:                goto out;
                    495:        }
                    496:        if (fsize(nf) == 0) {
                    497:                fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
1.6       millert   498:                (void)Fclose(nf);
1.1       deraadt   499:                goto out;
                    500:        }
                    501:        /*
                    502:         * Take new files.
                    503:         */
1.7       millert   504:        (void)fseek(nf, 0L, 2);
1.1       deraadt   505:        collf = nf;
1.6       millert   506:        (void)Fclose(fp);
1.1       deraadt   507: out:
1.22      millert   508:        (void)sigprocmask(SIG_SETMASK, &oset, NULL);
                    509:        (void)sigaction(SIGINT, &oact, NULL);
1.1       deraadt   510: }
                    511:
                    512: /*
                    513:  * Interpolate the named messages into the current
                    514:  * message, preceding each line with a tab.
                    515:  * Return a count of the number of characters now in
                    516:  * the message, or -1 if an error is encountered writing
                    517:  * the message temporary.  The flag argument is 'm' if we
                    518:  * should shift over and 'f' if not.
                    519:  */
                    520: int
1.23      millert   521: forward(char *ms, FILE *fp, char *fn, int f)
1.1       deraadt   522: {
1.15      millert   523:        int *msgvec;
1.1       deraadt   524:        struct ignoretab *ig;
                    525:        char *tabst;
                    526:
1.7       millert   527:        msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec));
1.8       millert   528:        if (msgvec == NULL)
1.1       deraadt   529:                return(0);
                    530:        if (getmsglist(ms, msgvec, 0) < 0)
                    531:                return(0);
                    532:        if (*msgvec == 0) {
                    533:                *msgvec = first(0, MMNORM);
                    534:                if (*msgvec == NULL) {
1.6       millert   535:                        puts("No appropriate messages");
1.1       deraadt   536:                        return(0);
                    537:                }
                    538:                msgvec[1] = NULL;
                    539:        }
                    540:        if (f == 'f' || f == 'F')
1.8       millert   541:                tabst = NULL;
                    542:        else if ((tabst = value("indentprefix")) == NULL)
1.1       deraadt   543:                tabst = "\t";
                    544:        ig = isupper(f) ? NULL : ignore;
1.6       millert   545:        fputs("Interpolating:", stdout);
1.1       deraadt   546:        for (; *msgvec != 0; msgvec++) {
                    547:                struct message *mp = message + *msgvec - 1;
                    548:
                    549:                touch(mp);
                    550:                printf(" %d", *msgvec);
1.18      millert   551:                if (sendmessage(mp, fp, ig, tabst) < 0) {
1.19      millert   552:                        warn("%s", fn);
1.1       deraadt   553:                        return(-1);
                    554:                }
                    555:        }
1.6       millert   556:        putchar('\n');
1.1       deraadt   557:        return(0);
                    558: }
                    559:
                    560: /*
1.22      millert   561:  * User aborted during message composition.
                    562:  * Save the partial message in ~/dead.letter.
1.1       deraadt   563:  */
1.22      millert   564: int
1.23      millert   565: collabort(void)
1.1       deraadt   566: {
                    567:        /*
                    568:         * the control flow is subtle, because we can be called from ~q.
                    569:         */
1.5       deraadt   570:        if (hadintr == 0 && isatty(0)) {
1.8       millert   571:                if (value("ignore") != NULL) {
1.1       deraadt   572:                        puts("@");
                    573:                        fflush(stdout);
                    574:                        clearerr(stdin);
1.22      millert   575:                } else {
                    576:                        fflush(stdout);
                    577:                        fputs("\n(Interrupt -- one more to kill letter)\n",
                    578:                            stderr);
                    579:                        hadintr++;
1.1       deraadt   580:                }
1.22      millert   581:                return(0);
1.1       deraadt   582:        }
1.22      millert   583:        fflush(stdout);
1.1       deraadt   584:        rewind(collf);
1.8       millert   585:        if (value("nosave") == NULL)
1.1       deraadt   586:                savedeadletter(collf);
1.22      millert   587:        return(1);
1.1       deraadt   588: }
                    589:
                    590: void
1.23      millert   591: savedeadletter(FILE *fp)
1.1       deraadt   592: {
1.15      millert   593:        FILE *dbuf;
                    594:        int c;
1.1       deraadt   595:        char *cp;
                    596:
                    597:        if (fsize(fp) == 0)
                    598:                return;
                    599:        cp = getdeadletter();
                    600:        c = umask(077);
                    601:        dbuf = Fopen(cp, "a");
1.7       millert   602:        (void)umask(c);
1.1       deraadt   603:        if (dbuf == NULL)
                    604:                return;
                    605:        while ((c = getc(fp)) != EOF)
1.7       millert   606:                (void)putc(c, dbuf);
1.6       millert   607:        (void)Fclose(dbuf);
1.1       deraadt   608:        rewind(fp);
1.11      millert   609: }
                    610:
1.22      millert   611: int
1.23      millert   612: gethfromtty(struct header *hp, int gflags)
1.11      millert   613: {
1.22      millert   614:
                    615:        hadintr = 0;
                    616:        while (grabh(hp, gflags) != 0) {
                    617:                if (collabort())
                    618:                        return(-1);
1.11      millert   619:        }
1.22      millert   620:        return(0);
1.1       deraadt   621: }