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