Annotation of src/usr.bin/mail/collect.c, Revision 1.20
1.20 ! millert 1: /* $OpenBSD: collect.c,v 1.19 2000/06/30 16:00:17 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
39: static char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94";
40: #else
1.20 ! millert 41: static char rcsid[] = "$OpenBSD: collect.c,v 1.19 2000/06/30 16:00:17 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:
66: static sig_t saveint; /* Previous SIGINT value */
67: static sig_t savehup; /* Previous SIGHUP value */
68: static sig_t savetstp; /* Previous SIGTSTP value */
69: static sig_t savettou; /* Previous SIGTTOU value */
70: static sig_t savettin; /* Previous SIGTTIN value */
71: static FILE *collf; /* File for saving away */
72: static int hadintr; /* Have seen one SIGINT so far */
73:
1.8 millert 74: static sigjmp_buf colljmp; /* To get back to work */
75: static int colljmp_p; /* whether to long jump */
76: static sigjmp_buf collabort; /* To end collection with error */
1.1 deraadt 77:
78: FILE *
79: collect(hp, printheaders)
80: struct header *hp;
81: int printheaders;
82: {
83: FILE *fbuf;
1.15 millert 84: int lc, cc, escape, eofcount, fd, c, t;
85: char linebuf[LINESIZE], tempname[PATHSIZE], *cp, getsub;
1.9 millert 86: sigset_t oset, nset;
1.6 millert 87: int longline, lastlong, rc; /* Can deal with lines > LINESIZE */
88:
1.2 deraadt 89: #if __GNUC__
1.8 millert 90: /* Avoid siglongjmp clobbering */
1.7 millert 91: (void)&escape;
92: (void)&eofcount;
93: (void)&getsub;
94: (void)&longline;
1.2 deraadt 95: #endif
1.1 deraadt 96:
97: collf = NULL;
98: /*
99: * Start catching signals from here, but we're still die on interrupts
100: * until we're in the main loop.
101: */
1.9 millert 102: sigemptyset(&nset);
103: sigaddset(&nset, SIGINT);
104: sigaddset(&nset, SIGHUP);
105: sigprocmask(SIG_BLOCK, &nset, &oset);
1.1 deraadt 106: if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
1.13 millert 107: (void)signal(SIGINT, collint);
1.1 deraadt 108: if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
1.13 millert 109: (void)signal(SIGHUP, collhup);
1.1 deraadt 110: savetstp = signal(SIGTSTP, collstop);
111: savettou = signal(SIGTTOU, collstop);
112: savettin = signal(SIGTTIN, collstop);
1.8 millert 113: if (sigsetjmp(collabort, 1) || sigsetjmp(colljmp, 1)) {
1.12 millert 114: (void)rm(tempname);
1.1 deraadt 115: goto err;
116: }
1.9 millert 117: sigdelset(&oset, SIGINT);
118: sigdelset(&oset, SIGHUP);
119: sigprocmask(SIG_SETMASK, &oset, NULL);
1.1 deraadt 120:
121: noreset++;
1.12 millert 122: (void)snprintf(tempname, sizeof(tempname),
123: "%s/mail.RsXXXXXXXXXX", tmpdir);
124: if ((fd = mkstemp(tempname)) == -1 ||
125: (collf = Fdopen(fd, "w+")) == NULL) {
1.19 millert 126: warn("%s", tempname);
1.1 deraadt 127: goto err;
128: }
1.12 millert 129: (void)rm(tempname);
1.1 deraadt 130:
131: /*
132: * If we are going to prompt for a subject,
133: * refrain from printing a newline after
134: * the headers (since some people mind).
135: */
136: t = GTO|GSUBJECT|GCC|GNL;
137: getsub = 0;
1.8 millert 138: if (hp->h_subject == NULL && value("interactive") != NULL &&
139: (value("ask") != NULL || value("asksub") != NULL))
1.1 deraadt 140: t &= ~GNL, getsub++;
141: if (printheaders) {
142: puthead(hp, stdout, t);
143: fflush(stdout);
144: }
1.8 millert 145: if ((cp = value("escape")) != NULL)
1.1 deraadt 146: escape = *cp;
147: else
148: escape = ESCAPE;
149: eofcount = 0;
150: hadintr = 0;
1.6 millert 151: lastlong = 0;
152: longline = 0;
1.1 deraadt 153:
1.8 millert 154: if (!sigsetjmp(colljmp, 1)) {
1.11 millert 155: if (getsub)
156: gethfromtty(hp, GSUBJECT);
1.1 deraadt 157: } else {
158: /*
159: * Come here for printing the after-signal message.
160: * Duplicate messages won't be printed because
161: * the write is aborted if we get a SIGTTOU.
162: */
163: cont:
164: if (hadintr) {
165: fflush(stdout);
1.6 millert 166: fputs("\n(Interrupt -- one more to kill letter)\n",
167: stderr);
1.1 deraadt 168: } else {
1.4 deraadt 169: if (isatty(0)) {
1.6 millert 170: puts("(continue)");
1.4 deraadt 171: fflush(stdout);
172: }
1.1 deraadt 173: }
174: }
175: for (;;) {
176: colljmp_p = 1;
177: c = readline(stdin, linebuf, LINESIZE);
178: colljmp_p = 0;
179: if (c < 0) {
1.8 millert 180: if (value("interactive") != NULL &&
181: value("ignoreeof") != NULL && ++eofcount < 25) {
1.6 millert 182: puts("Use \".\" to terminate letter");
1.1 deraadt 183: continue;
184: }
185: break;
186: }
1.6 millert 187: lastlong = longline;
188: longline = (c == LINESIZE - 1);
1.1 deraadt 189: eofcount = 0;
190: hadintr = 0;
191: if (linebuf[0] == '.' && linebuf[1] == '\0' &&
1.8 millert 192: value("interactive") != NULL && !lastlong &&
193: (value("dot") != NULL || value("ignoreeof") != NULL))
1.1 deraadt 194: break;
1.20 ! millert 195: if (linebuf[0] != escape || lastlong) {
1.6 millert 196: if (putline(collf, linebuf, !longline) < 0)
1.1 deraadt 197: goto err;
198: continue;
199: }
200: c = linebuf[1];
201: switch (c) {
202: default:
203: /*
204: * On double escape, just send the single one.
205: * Otherwise, it's an error.
206: */
207: if (c == escape) {
1.6 millert 208: if (putline(collf, &linebuf[1], !longline) < 0)
1.1 deraadt 209: goto err;
210: else
211: break;
212: }
1.6 millert 213: puts("Unknown tilde escape.");
1.1 deraadt 214: break;
215: case 'C':
216: /*
217: * Dump core.
218: */
1.2 deraadt 219: core(NULL);
1.1 deraadt 220: break;
221: case '!':
222: /*
223: * Shell escape, send the balance of the
224: * line to sh -c.
225: */
226: shell(&linebuf[2]);
227: break;
228: case ':':
229: case '_':
230: /*
231: * Escape to command mode, but be nice!
232: */
233: execute(&linebuf[2], 1);
234: goto cont;
235: case '.':
236: /*
237: * Simulate end of file on input.
238: */
239: goto out;
240: case 'q':
241: /*
242: * Force a quit of sending mail.
243: * Act like an interrupt happened.
244: */
245: hadintr++;
246: collint(SIGINT);
247: exit(1);
248: case 'h':
249: /*
250: * Grab a bunch of headers.
251: */
252: grabh(hp, GTO|GSUBJECT|GCC|GBCC);
253: goto cont;
254: case 't':
255: /*
256: * Add to the To list.
257: */
258: hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO));
259: break;
260: case 's':
261: /*
262: * Set the Subject list.
263: */
264: cp = &linebuf[2];
265: while (isspace(*cp))
266: cp++;
267: hp->h_subject = savestr(cp);
268: break;
269: case 'c':
270: /*
271: * Add to the CC list.
272: */
273: hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC));
274: break;
275: case 'b':
276: /*
277: * Add stuff to blind carbon copies list.
278: */
279: hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC));
280: break;
281: case 'd':
1.14 millert 282: strncpy(linebuf + 2, getdeadletter(), sizeof(linebuf) - 3);
283: linebuf[sizeof(linebuf) - 1] = '\0';
1.1 deraadt 284: /* fall into . . . */
285: case 'r':
286: case '<':
287: /*
288: * Invoke a file:
289: * Search for the file name,
290: * then open it and copy the contents to collf.
291: */
292: cp = &linebuf[2];
293: while (isspace(*cp))
294: cp++;
295: if (*cp == '\0') {
1.6 millert 296: puts("Interpolate what file?");
1.1 deraadt 297: break;
298: }
299: cp = expand(cp);
1.8 millert 300: if (cp == NULL)
1.1 deraadt 301: break;
302: if (isdir(cp)) {
303: printf("%s: Directory\n", cp);
304: break;
305: }
306: if ((fbuf = Fopen(cp, "r")) == NULL) {
1.19 millert 307: warn("%s", cp);
1.1 deraadt 308: break;
309: }
310: printf("\"%s\" ", cp);
311: fflush(stdout);
312: lc = 0;
313: cc = 0;
1.6 millert 314: while ((rc = readline(fbuf, linebuf, LINESIZE)) >= 0) {
315: if (rc != LINESIZE - 1)
316: lc++;
317: if ((t = putline(collf, linebuf,
318: rc != LINESIZE-1)) < 0) {
319: (void)Fclose(fbuf);
1.1 deraadt 320: goto err;
321: }
322: cc += t;
323: }
1.6 millert 324: (void)Fclose(fbuf);
1.1 deraadt 325: printf("%d/%d\n", lc, cc);
326: break;
327: case 'w':
328: /*
329: * Write the message on a file.
330: */
331: cp = &linebuf[2];
332: while (*cp == ' ' || *cp == '\t')
333: cp++;
334: if (*cp == '\0') {
1.6 millert 335: fputs("Write what file!?\n", stderr);
1.1 deraadt 336: break;
337: }
1.8 millert 338: if ((cp = expand(cp)) == NULL)
1.1 deraadt 339: break;
340: rewind(collf);
341: exwrite(cp, collf, 1);
342: break;
343: case 'm':
344: case 'M':
345: case 'f':
346: case 'F':
347: /*
348: * Interpolate the named messages, if we
349: * are in receiving mail mode. Does the
350: * standard list processing garbage.
351: * If ~f is given, we don't shift over.
352: */
1.12 millert 353: if (forward(linebuf + 2, collf, tempname, c) < 0)
1.1 deraadt 354: goto err;
355: goto cont;
356: case '?':
357: if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) {
1.6 millert 358: warn(_PATH_TILDE);
1.1 deraadt 359: break;
360: }
361: while ((t = getc(fbuf)) != EOF)
1.7 millert 362: (void)putchar(t);
1.6 millert 363: (void)Fclose(fbuf);
1.1 deraadt 364: break;
365: case 'p':
366: /*
367: * Print out the current state of the
368: * message without altering anything.
369: */
370: rewind(collf);
1.6 millert 371: puts("-------\nMessage contains:");
1.1 deraadt 372: puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL);
373: while ((t = getc(collf)) != EOF)
1.7 millert 374: (void)putchar(t);
1.1 deraadt 375: goto cont;
376: case '|':
377: /*
378: * Pipe message through command.
379: * Collect output as new message.
380: */
381: rewind(collf);
382: mespipe(collf, &linebuf[2]);
383: goto cont;
384: case 'v':
385: case 'e':
386: /*
387: * Edit the current message.
388: * 'e' means to use EDITOR
389: * 'v' means to use VISUAL
390: */
391: rewind(collf);
392: mesedit(collf, c);
393: goto cont;
394: }
395: }
1.11 millert 396:
397: if (value("interactive") != NULL) {
398: if (value("askcc") != NULL || value("askbcc") != NULL) {
399: if (value("askcc") != NULL)
400: gethfromtty(hp, GCC);
401: if (value("askbcc") != NULL)
402: gethfromtty(hp, GBCC);
403: } else {
404: puts("EOT");
405: (void)fflush(stdout);
406: }
407: }
1.1 deraadt 408: goto out;
409: err:
410: if (collf != NULL) {
1.6 millert 411: (void)Fclose(collf);
1.1 deraadt 412: collf = NULL;
413: }
414: out:
415: if (collf != NULL)
416: rewind(collf);
417: noreset--;
1.13 millert 418: (void)sigemptyset(&nset);
419: (void)sigaddset(&nset, SIGINT);
420: (void)sigaddset(&nset, SIGHUP);
421: (void)sigprocmask(SIG_BLOCK, &nset, &oset);
422: (void)signal(SIGINT, saveint);
423: (void)signal(SIGHUP, savehup);
424: (void)signal(SIGTSTP, savetstp);
425: (void)signal(SIGTTOU, savettou);
426: (void)signal(SIGTTIN, savettin);
427: (void)sigprocmask(SIG_SETMASK, &oset, NULL);
1.6 millert 428: return(collf);
1.1 deraadt 429: }
430:
431: /*
432: * Write a file, ex-like if f set.
433: */
434: int
435: exwrite(name, fp, f)
436: char name[];
437: FILE *fp;
438: int f;
439: {
1.15 millert 440: FILE *of;
441: int c;
1.11 millert 442: ssize_t cc, lc;
1.1 deraadt 443: struct stat junk;
444:
445: if (f) {
446: printf("\"%s\" ", name);
447: fflush(stdout);
448: }
1.15 millert 449: if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) {
1.1 deraadt 450: if (!f)
451: fprintf(stderr, "%s: ", name);
1.6 millert 452: fputs("File exists\n", stderr);
1.1 deraadt 453: return(-1);
454: }
455: if ((of = Fopen(name, "w")) == NULL) {
1.8 millert 456: warn(NULL);
1.1 deraadt 457: return(-1);
458: }
459: lc = 0;
460: cc = 0;
461: while ((c = getc(fp)) != EOF) {
462: cc++;
463: if (c == '\n')
464: lc++;
1.7 millert 465: (void)putc(c, of);
1.1 deraadt 466: if (ferror(of)) {
1.19 millert 467: warn("%s", name);
1.6 millert 468: (void)Fclose(of);
1.1 deraadt 469: return(-1);
470: }
471: }
1.6 millert 472: (void)Fclose(of);
1.11 millert 473: printf("%d/%d\n", lc, cc);
1.1 deraadt 474: fflush(stdout);
475: return(0);
476: }
477:
478: /*
479: * Edit the message being collected on fp.
480: * On return, make the edit file the new temp file.
481: */
482: void
483: mesedit(fp, c)
484: FILE *fp;
485: int c;
486: {
487: sig_t sigint = signal(SIGINT, SIG_IGN);
488: FILE *nf = run_editor(fp, (off_t)-1, c, 0);
489:
490: if (nf != NULL) {
491: fseek(nf, 0L, 2);
492: collf = nf;
1.6 millert 493: (void)Fclose(fp);
1.1 deraadt 494: }
1.7 millert 495: (void)signal(SIGINT, sigint);
1.1 deraadt 496: }
497:
498: /*
499: * Pipe the message through the command.
500: * Old message is on stdin of command;
501: * New message collected from stdout.
502: * Sh -c must return 0 to accept the new message.
503: */
504: void
505: mespipe(fp, cmd)
506: FILE *fp;
507: char cmd[];
508: {
509: FILE *nf;
1.12 millert 510: int fd;
1.1 deraadt 511: sig_t sigint = signal(SIGINT, SIG_IGN);
1.12 millert 512: char *shell, tempname[PATHSIZE];
1.1 deraadt 513:
1.12 millert 514: (void)snprintf(tempname, sizeof(tempname),
515: "%s/mail.ReXXXXXXXXXX", tmpdir);
516: if ((fd = mkstemp(tempname)) == -1 ||
517: (nf = Fdopen(fd, "w+")) == NULL) {
1.19 millert 518: warn("%s", tempname);
1.1 deraadt 519: goto out;
520: }
1.12 millert 521: (void)rm(tempname);
1.1 deraadt 522: /*
523: * stdin = current message.
524: * stdout = new message.
525: */
1.20 ! millert 526: shell = value("SHELL");
1.1 deraadt 527: if (run_command(shell,
1.8 millert 528: 0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) {
1.6 millert 529: (void)Fclose(nf);
1.1 deraadt 530: goto out;
531: }
532: if (fsize(nf) == 0) {
533: fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
1.6 millert 534: (void)Fclose(nf);
1.1 deraadt 535: goto out;
536: }
537: /*
538: * Take new files.
539: */
1.7 millert 540: (void)fseek(nf, 0L, 2);
1.1 deraadt 541: collf = nf;
1.6 millert 542: (void)Fclose(fp);
1.1 deraadt 543: out:
1.7 millert 544: (void)signal(SIGINT, sigint);
1.1 deraadt 545: }
546:
547: /*
548: * Interpolate the named messages into the current
549: * message, preceding each line with a tab.
550: * Return a count of the number of characters now in
551: * the message, or -1 if an error is encountered writing
552: * the message temporary. The flag argument is 'm' if we
553: * should shift over and 'f' if not.
554: */
555: int
1.12 millert 556: forward(ms, fp, fn, f)
1.1 deraadt 557: char ms[];
558: FILE *fp;
1.12 millert 559: char *fn;
1.1 deraadt 560: int f;
561: {
1.15 millert 562: int *msgvec;
1.1 deraadt 563: struct ignoretab *ig;
564: char *tabst;
565:
1.7 millert 566: msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec));
1.8 millert 567: if (msgvec == NULL)
1.1 deraadt 568: return(0);
569: if (getmsglist(ms, msgvec, 0) < 0)
570: return(0);
571: if (*msgvec == 0) {
572: *msgvec = first(0, MMNORM);
573: if (*msgvec == NULL) {
1.6 millert 574: puts("No appropriate messages");
1.1 deraadt 575: return(0);
576: }
577: msgvec[1] = NULL;
578: }
579: if (f == 'f' || f == 'F')
1.8 millert 580: tabst = NULL;
581: else if ((tabst = value("indentprefix")) == NULL)
1.1 deraadt 582: tabst = "\t";
583: ig = isupper(f) ? NULL : ignore;
1.6 millert 584: fputs("Interpolating:", stdout);
1.1 deraadt 585: for (; *msgvec != 0; msgvec++) {
586: struct message *mp = message + *msgvec - 1;
587:
588: touch(mp);
589: printf(" %d", *msgvec);
1.18 millert 590: if (sendmessage(mp, fp, ig, tabst) < 0) {
1.19 millert 591: warn("%s", fn);
1.1 deraadt 592: return(-1);
593: }
594: }
1.6 millert 595: putchar('\n');
1.1 deraadt 596: return(0);
597: }
598:
599: /*
600: * Print (continue) when continued after ^Z.
601: */
602: /*ARGSUSED*/
603: void
604: collstop(s)
605: int s;
606: {
607: sig_t old_action = signal(s, SIG_DFL);
1.2 deraadt 608: sigset_t nset;
1.1 deraadt 609:
1.13 millert 610: (void)sigemptyset(&nset);
611: (void)sigaddset(&nset, s);
612: (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
613: (void)kill(0, s);
614: (void)sigprocmask(SIG_BLOCK, &nset, NULL);
615: (void)signal(s, old_action);
1.1 deraadt 616: if (colljmp_p) {
617: colljmp_p = 0;
618: hadintr = 0;
1.8 millert 619: siglongjmp(colljmp, 1);
1.1 deraadt 620: }
621: }
622:
623: /*
624: * On interrupt, come here to save the partial message in ~/dead.letter.
625: * Then jump out of the collection loop.
626: */
627: /*ARGSUSED*/
628: void
629: collint(s)
630: int s;
631: {
632: /*
633: * the control flow is subtle, because we can be called from ~q.
634: */
1.5 deraadt 635: if (hadintr == 0 && isatty(0)) {
1.8 millert 636: if (value("ignore") != NULL) {
1.1 deraadt 637: puts("@");
638: fflush(stdout);
639: clearerr(stdin);
640: return;
641: }
642: hadintr = 1;
1.8 millert 643: siglongjmp(colljmp, 1);
1.1 deraadt 644: }
645: rewind(collf);
1.8 millert 646: if (value("nosave") == NULL)
1.1 deraadt 647: savedeadletter(collf);
1.8 millert 648: siglongjmp(collabort, 1);
1.1 deraadt 649: }
650:
651: /*ARGSUSED*/
652: void
653: collhup(s)
654: int s;
655: {
656: rewind(collf);
657: savedeadletter(collf);
658: /*
659: * Let's pretend nobody else wants to clean up,
660: * a true statement at this time.
661: */
662: exit(1);
663: }
664:
665: void
666: savedeadletter(fp)
1.15 millert 667: FILE *fp;
1.1 deraadt 668: {
1.15 millert 669: FILE *dbuf;
670: int c;
1.1 deraadt 671: char *cp;
672:
673: if (fsize(fp) == 0)
674: return;
675: cp = getdeadletter();
676: c = umask(077);
677: dbuf = Fopen(cp, "a");
1.7 millert 678: (void)umask(c);
1.1 deraadt 679: if (dbuf == NULL)
680: return;
681: while ((c = getc(fp)) != EOF)
1.7 millert 682: (void)putc(c, dbuf);
1.6 millert 683: (void)Fclose(dbuf);
1.1 deraadt 684: rewind(fp);
1.11 millert 685: }
686:
687: void
688: gethfromtty(hp, gflags)
689: struct header *hp;
690: int gflags;
691: {
692: if (grabh(hp, gflags) == SIGINT) {
693: fflush(stdout);
694: fputs("\n(Interrupt -- one more to kill letter)\n",
695: stderr);
696: if (grabh(hp, gflags) == SIGINT) {
697: hadintr++;
698: collint(SIGINT);
699: exit(1);
700: }
701: }
1.1 deraadt 702: }