collect.c revision 77274
11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3574769Smikeh#if 0 361590Srgrimesstatic char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94"; 3774769Smikeh#endif 3874769Smikehstatic const char rcsid[] = 3974769Smikeh "$FreeBSD: head/usr.bin/mail/collect.c 77274 2001-05-27 20:26:22Z mikeh $"; 401590Srgrimes#endif /* not lint */ 411590Srgrimes 421590Srgrimes/* 431590Srgrimes * Mail -- a mail program 441590Srgrimes * 451590Srgrimes * Collect input from standard input, handling 461590Srgrimes * ~ escapes. 471590Srgrimes */ 481590Srgrimes 491590Srgrimes#include "rcv.h" 501590Srgrimes#include "extern.h" 511590Srgrimes 521590Srgrimes/* 531590Srgrimes * Read a message from standard output and return a read file to it 541590Srgrimes * or NULL on error. 551590Srgrimes */ 561590Srgrimes 571590Srgrimes/* 581590Srgrimes * The following hokiness with global variables is so that on 591590Srgrimes * receipt of an interrupt signal, the partial message can be salted 601590Srgrimes * away on dead.letter. 611590Srgrimes */ 621590Srgrimes 631590Srgrimesstatic sig_t saveint; /* Previous SIGINT value */ 641590Srgrimesstatic sig_t savehup; /* Previous SIGHUP value */ 651590Srgrimesstatic sig_t savetstp; /* Previous SIGTSTP value */ 661590Srgrimesstatic sig_t savettou; /* Previous SIGTTOU value */ 671590Srgrimesstatic sig_t savettin; /* Previous SIGTTIN value */ 681590Srgrimesstatic FILE *collf; /* File for saving away */ 691590Srgrimesstatic int hadintr; /* Have seen one SIGINT so far */ 701590Srgrimes 711590Srgrimesstatic jmp_buf colljmp; /* To get back to work */ 721590Srgrimesstatic int colljmp_p; /* whether to long jump */ 731590Srgrimesstatic jmp_buf collabort; /* To end collection with error */ 741590Srgrimes 751590SrgrimesFILE * 761590Srgrimescollect(hp, printheaders) 771590Srgrimes struct header *hp; 781590Srgrimes int printheaders; 791590Srgrimes{ 801590Srgrimes FILE *fbuf; 8177274Smikeh int lc, cc, escape, eofcount, fd, c, t; 8277274Smikeh char linebuf[LINESIZE], tempname[PATHSIZE], *cp, getsub; 831590Srgrimes int omask; 841590Srgrimes 851590Srgrimes collf = NULL; 861590Srgrimes /* 871590Srgrimes * Start catching signals from here, but we're still die on interrupts 881590Srgrimes * until we're in the main loop. 891590Srgrimes */ 901590Srgrimes omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); 911590Srgrimes if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) 9277274Smikeh (void)signal(SIGINT, collint); 931590Srgrimes if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) 9477274Smikeh (void)signal(SIGHUP, collhup); 951590Srgrimes savetstp = signal(SIGTSTP, collstop); 961590Srgrimes savettou = signal(SIGTTOU, collstop); 971590Srgrimes savettin = signal(SIGTTIN, collstop); 981590Srgrimes if (setjmp(collabort) || setjmp(colljmp)) { 9977274Smikeh (void)rm(tempname); 1001590Srgrimes goto err; 1011590Srgrimes } 1021590Srgrimes sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP))); 1031590Srgrimes 1041590Srgrimes noreset++; 10577274Smikeh (void)snprintf(tempname, sizeof(tempname), 10677274Smikeh "%s/mail.RsXXXXXXXXXX", tmpdir); 10774769Smikeh if ((fd = mkstemp(tempname)) == -1 || 10874769Smikeh (collf = Fdopen(fd, "w+")) == NULL) { 10974769Smikeh warn("%s", tempname); 1101590Srgrimes goto err; 1111590Srgrimes } 11277274Smikeh (void)rm(tempname); 1131590Srgrimes 1141590Srgrimes /* 1151590Srgrimes * If we are going to prompt for a subject, 1161590Srgrimes * refrain from printing a newline after 1171590Srgrimes * the headers (since some people mind). 1181590Srgrimes */ 1191590Srgrimes t = GTO|GSUBJECT|GCC|GNL; 1201590Srgrimes getsub = 0; 12177274Smikeh if (hp->h_subject == NULL && value("interactive") != NULL && 12277274Smikeh (value("ask") != NULL || value("asksub") != NULL)) 1231590Srgrimes t &= ~GNL, getsub++; 1241590Srgrimes if (printheaders) { 1251590Srgrimes puthead(hp, stdout, t); 12677274Smikeh (void)fflush(stdout); 1271590Srgrimes } 12877274Smikeh if ((cp = value("escape")) != NULL) 1291590Srgrimes escape = *cp; 1301590Srgrimes else 1311590Srgrimes escape = ESCAPE; 1321590Srgrimes eofcount = 0; 1331590Srgrimes hadintr = 0; 1341590Srgrimes 1351590Srgrimes if (!setjmp(colljmp)) { 1361590Srgrimes if (getsub) 1371590Srgrimes grabh(hp, GSUBJECT); 1381590Srgrimes } else { 1391590Srgrimes /* 1401590Srgrimes * Come here for printing the after-signal message. 1411590Srgrimes * Duplicate messages won't be printed because 1421590Srgrimes * the write is aborted if we get a SIGTTOU. 1431590Srgrimes */ 1441590Srgrimescont: 1451590Srgrimes if (hadintr) { 14677274Smikeh (void)fflush(stdout); 1471590Srgrimes fprintf(stderr, 1481590Srgrimes "\n(Interrupt -- one more to kill letter)\n"); 1491590Srgrimes } else { 1501590Srgrimes printf("(continue)\n"); 15177274Smikeh (void)fflush(stdout); 1521590Srgrimes } 1531590Srgrimes } 1541590Srgrimes for (;;) { 1551590Srgrimes colljmp_p = 1; 1561590Srgrimes c = readline(stdin, linebuf, LINESIZE); 1571590Srgrimes colljmp_p = 0; 1581590Srgrimes if (c < 0) { 15977274Smikeh if (value("interactive") != NULL && 16077274Smikeh value("ignoreeof") != NULL && ++eofcount < 25) { 1611590Srgrimes printf("Use \".\" to terminate letter\n"); 1621590Srgrimes continue; 1631590Srgrimes } 1641590Srgrimes break; 1651590Srgrimes } 1661590Srgrimes eofcount = 0; 1671590Srgrimes hadintr = 0; 1681590Srgrimes if (linebuf[0] == '.' && linebuf[1] == '\0' && 16977274Smikeh value("interactive") != NULL && 17077274Smikeh (value("dot") != NULL || value("ignoreeof") != NULL)) 1711590Srgrimes break; 17277274Smikeh if (linebuf[0] != escape || value("interactive") == NULL) { 1731590Srgrimes if (putline(collf, linebuf) < 0) 1741590Srgrimes goto err; 1751590Srgrimes continue; 1761590Srgrimes } 1771590Srgrimes c = linebuf[1]; 1781590Srgrimes switch (c) { 1791590Srgrimes default: 1801590Srgrimes /* 1811590Srgrimes * On double escape, just send the single one. 1821590Srgrimes * Otherwise, it's an error. 1831590Srgrimes */ 1841590Srgrimes if (c == escape) { 1851590Srgrimes if (putline(collf, &linebuf[1]) < 0) 1861590Srgrimes goto err; 1871590Srgrimes else 1881590Srgrimes break; 1891590Srgrimes } 1901590Srgrimes printf("Unknown tilde escape.\n"); 1911590Srgrimes break; 1921590Srgrimes case 'C': 1931590Srgrimes /* 1941590Srgrimes * Dump core. 1951590Srgrimes */ 1961590Srgrimes core(); 1971590Srgrimes break; 1981590Srgrimes case '!': 1991590Srgrimes /* 2001590Srgrimes * Shell escape, send the balance of the 2011590Srgrimes * line to sh -c. 2021590Srgrimes */ 2031590Srgrimes shell(&linebuf[2]); 2041590Srgrimes break; 2051590Srgrimes case ':': 2061590Srgrimes /* 2071590Srgrimes * Escape to command mode, but be nice! 2081590Srgrimes */ 2091590Srgrimes execute(&linebuf[2], 1); 2101590Srgrimes goto cont; 2111590Srgrimes case '.': 2121590Srgrimes /* 2131590Srgrimes * Simulate end of file on input. 2141590Srgrimes */ 2151590Srgrimes goto out; 2161590Srgrimes case 'q': 2171590Srgrimes /* 2181590Srgrimes * Force a quit of sending mail. 2191590Srgrimes * Act like an interrupt happened. 2201590Srgrimes */ 2211590Srgrimes hadintr++; 2221590Srgrimes collint(SIGINT); 2231590Srgrimes exit(1); 2241590Srgrimes case 'h': 2251590Srgrimes /* 2261590Srgrimes * Grab a bunch of headers. 2271590Srgrimes */ 2281590Srgrimes grabh(hp, GTO|GSUBJECT|GCC|GBCC); 2291590Srgrimes goto cont; 2301590Srgrimes case 't': 2311590Srgrimes /* 2321590Srgrimes * Add to the To list. 2331590Srgrimes */ 2341590Srgrimes hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); 2351590Srgrimes break; 2361590Srgrimes case 's': 2371590Srgrimes /* 23832189Sjoerg * Set the Subject line. 2391590Srgrimes */ 2401590Srgrimes cp = &linebuf[2]; 2411590Srgrimes while (isspace(*cp)) 2421590Srgrimes cp++; 2431590Srgrimes hp->h_subject = savestr(cp); 2441590Srgrimes break; 24532189Sjoerg case 'R': 24632189Sjoerg /* 24732189Sjoerg * Set the Reply-To line. 24832189Sjoerg */ 24932189Sjoerg cp = &linebuf[2]; 25032189Sjoerg while (isspace(*cp)) 25132189Sjoerg cp++; 25232189Sjoerg hp->h_replyto = savestr(cp); 25332189Sjoerg break; 2541590Srgrimes case 'c': 2551590Srgrimes /* 2561590Srgrimes * Add to the CC list. 2571590Srgrimes */ 2581590Srgrimes hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); 2591590Srgrimes break; 2601590Srgrimes case 'b': 2611590Srgrimes /* 2621590Srgrimes * Add stuff to blind carbon copies list. 2631590Srgrimes */ 2641590Srgrimes hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); 2651590Srgrimes break; 2661590Srgrimes case 'd': 26774769Smikeh if (strlcpy(linebuf + 2, getdeadletter(), sizeof(linebuf) - 2) 26874769Smikeh >= sizeof(linebuf) - 2) { 26974769Smikeh printf("Line buffer overflow\n"); 27074769Smikeh break; 27174769Smikeh } 2721590Srgrimes /* fall into . . . */ 2731590Srgrimes case 'r': 2741590Srgrimes /* 2751590Srgrimes * Invoke a file: 2761590Srgrimes * Search for the file name, 2771590Srgrimes * then open it and copy the contents to collf. 2781590Srgrimes */ 2791590Srgrimes cp = &linebuf[2]; 2801590Srgrimes while (isspace(*cp)) 2811590Srgrimes cp++; 2821590Srgrimes if (*cp == '\0') { 2831590Srgrimes printf("Interpolate what file?\n"); 2841590Srgrimes break; 2851590Srgrimes } 2861590Srgrimes cp = expand(cp); 28777274Smikeh if (cp == NULL) 2881590Srgrimes break; 2891590Srgrimes if (isdir(cp)) { 2901590Srgrimes printf("%s: Directory\n", cp); 2911590Srgrimes break; 2921590Srgrimes } 2931590Srgrimes if ((fbuf = Fopen(cp, "r")) == NULL) { 29474769Smikeh warn("%s", cp); 2951590Srgrimes break; 2961590Srgrimes } 2971590Srgrimes printf("\"%s\" ", cp); 29877274Smikeh (void)fflush(stdout); 2991590Srgrimes lc = 0; 3001590Srgrimes cc = 0; 3011590Srgrimes while (readline(fbuf, linebuf, LINESIZE) >= 0) { 3021590Srgrimes lc++; 3031590Srgrimes if ((t = putline(collf, linebuf)) < 0) { 30477274Smikeh (void)Fclose(fbuf); 3051590Srgrimes goto err; 3061590Srgrimes } 3071590Srgrimes cc += t; 3081590Srgrimes } 30977274Smikeh (void)Fclose(fbuf); 3101590Srgrimes printf("%d/%d\n", lc, cc); 3111590Srgrimes break; 3121590Srgrimes case 'w': 3131590Srgrimes /* 3141590Srgrimes * Write the message on a file. 3151590Srgrimes */ 3161590Srgrimes cp = &linebuf[2]; 3171590Srgrimes while (*cp == ' ' || *cp == '\t') 3181590Srgrimes cp++; 3191590Srgrimes if (*cp == '\0') { 3201590Srgrimes fprintf(stderr, "Write what file!?\n"); 3211590Srgrimes break; 3221590Srgrimes } 32377274Smikeh if ((cp = expand(cp)) == NULL) 3241590Srgrimes break; 3251590Srgrimes rewind(collf); 3261590Srgrimes exwrite(cp, collf, 1); 3271590Srgrimes break; 3281590Srgrimes case 'm': 3291590Srgrimes case 'M': 3301590Srgrimes case 'f': 3311590Srgrimes case 'F': 3321590Srgrimes /* 3331590Srgrimes * Interpolate the named messages, if we 3341590Srgrimes * are in receiving mail mode. Does the 3351590Srgrimes * standard list processing garbage. 3361590Srgrimes * If ~f is given, we don't shift over. 3371590Srgrimes */ 33874769Smikeh if (forward(linebuf + 2, collf, tempname, c) < 0) 3391590Srgrimes goto err; 3401590Srgrimes goto cont; 3411590Srgrimes case '?': 3421590Srgrimes if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { 34374769Smikeh warn("%s", _PATH_TILDE); 3441590Srgrimes break; 3451590Srgrimes } 3461590Srgrimes while ((t = getc(fbuf)) != EOF) 34777274Smikeh (void)putchar(t); 34877274Smikeh (void)Fclose(fbuf); 3491590Srgrimes break; 3501590Srgrimes case 'p': 3511590Srgrimes /* 3521590Srgrimes * Print out the current state of the 3531590Srgrimes * message without altering anything. 3541590Srgrimes */ 3551590Srgrimes rewind(collf); 3561590Srgrimes printf("-------\nMessage contains:\n"); 3571590Srgrimes puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); 3581590Srgrimes while ((t = getc(collf)) != EOF) 35977274Smikeh (void)putchar(t); 3601590Srgrimes goto cont; 3611590Srgrimes case '|': 3621590Srgrimes /* 3631590Srgrimes * Pipe message through command. 3641590Srgrimes * Collect output as new message. 3651590Srgrimes */ 3661590Srgrimes rewind(collf); 3671590Srgrimes mespipe(collf, &linebuf[2]); 3681590Srgrimes goto cont; 3691590Srgrimes case 'v': 3701590Srgrimes case 'e': 3711590Srgrimes /* 3721590Srgrimes * Edit the current message. 3731590Srgrimes * 'e' means to use EDITOR 3741590Srgrimes * 'v' means to use VISUAL 3751590Srgrimes */ 3761590Srgrimes rewind(collf); 3771590Srgrimes mesedit(collf, c); 3781590Srgrimes goto cont; 3791590Srgrimes } 3801590Srgrimes } 3811590Srgrimes goto out; 3821590Srgrimeserr: 3831590Srgrimes if (collf != NULL) { 38477274Smikeh (void)Fclose(collf); 3851590Srgrimes collf = NULL; 3861590Srgrimes } 3871590Srgrimesout: 3881590Srgrimes if (collf != NULL) 3891590Srgrimes rewind(collf); 3901590Srgrimes noreset--; 39177274Smikeh (void)sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); 39277274Smikeh (void)signal(SIGINT, saveint); 39377274Smikeh (void)signal(SIGHUP, savehup); 39477274Smikeh (void)signal(SIGTSTP, savetstp); 39577274Smikeh (void)signal(SIGTTOU, savettou); 39677274Smikeh (void)signal(SIGTTIN, savettin); 39777274Smikeh (void)sigsetmask(omask); 39877274Smikeh return (collf); 3991590Srgrimes} 4001590Srgrimes 4011590Srgrimes/* 4021590Srgrimes * Write a file, ex-like if f set. 4031590Srgrimes */ 4041590Srgrimesint 4051590Srgrimesexwrite(name, fp, f) 4061590Srgrimes char name[]; 4071590Srgrimes FILE *fp; 4081590Srgrimes int f; 4091590Srgrimes{ 41077274Smikeh FILE *of; 41177274Smikeh int c, lc; 4121590Srgrimes long cc; 4131590Srgrimes struct stat junk; 4141590Srgrimes 4151590Srgrimes if (f) { 4161590Srgrimes printf("\"%s\" ", name); 41777274Smikeh (void)fflush(stdout); 4181590Srgrimes } 41974769Smikeh if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) { 4201590Srgrimes if (!f) 4211590Srgrimes fprintf(stderr, "%s: ", name); 4221590Srgrimes fprintf(stderr, "File exists\n"); 42377274Smikeh return (-1); 4241590Srgrimes } 4251590Srgrimes if ((of = Fopen(name, "w")) == NULL) { 42677274Smikeh warn((char *)NULL); 42777274Smikeh return (-1); 4281590Srgrimes } 4291590Srgrimes lc = 0; 4301590Srgrimes cc = 0; 4311590Srgrimes while ((c = getc(fp)) != EOF) { 4321590Srgrimes cc++; 4331590Srgrimes if (c == '\n') 4341590Srgrimes lc++; 43577274Smikeh (void)putc(c, of); 4361590Srgrimes if (ferror(of)) { 43774769Smikeh warnx("%s", name); 43877274Smikeh (void)Fclose(of); 43977274Smikeh return (-1); 4401590Srgrimes } 4411590Srgrimes } 44277274Smikeh (void)Fclose(of); 4431590Srgrimes printf("%d/%ld\n", lc, cc); 44477274Smikeh (void)fflush(stdout); 44577274Smikeh return (0); 4461590Srgrimes} 4471590Srgrimes 4481590Srgrimes/* 4491590Srgrimes * Edit the message being collected on fp. 4501590Srgrimes * On return, make the edit file the new temp file. 4511590Srgrimes */ 4521590Srgrimesvoid 4531590Srgrimesmesedit(fp, c) 4541590Srgrimes FILE *fp; 4551590Srgrimes int c; 4561590Srgrimes{ 4571590Srgrimes sig_t sigint = signal(SIGINT, SIG_IGN); 4581590Srgrimes FILE *nf = run_editor(fp, (off_t)-1, c, 0); 4591590Srgrimes 4601590Srgrimes if (nf != NULL) { 46177274Smikeh (void)fseek(nf, 0L, 2); 4621590Srgrimes collf = nf; 46377274Smikeh (void)Fclose(fp); 4641590Srgrimes } 46577274Smikeh (void)signal(SIGINT, sigint); 4661590Srgrimes} 4671590Srgrimes 4681590Srgrimes/* 4691590Srgrimes * Pipe the message through the command. 4701590Srgrimes * Old message is on stdin of command; 4711590Srgrimes * New message collected from stdout. 4721590Srgrimes * Sh -c must return 0 to accept the new message. 4731590Srgrimes */ 4741590Srgrimesvoid 4751590Srgrimesmespipe(fp, cmd) 4761590Srgrimes FILE *fp; 4771590Srgrimes char cmd[]; 4781590Srgrimes{ 4791590Srgrimes FILE *nf; 48074769Smikeh int fd; 4811590Srgrimes sig_t sigint = signal(SIGINT, SIG_IGN); 48277274Smikeh char *sh, tempname[PATHSIZE]; 4831590Srgrimes 48477274Smikeh (void)snprintf(tempname, sizeof(tempname), 48577274Smikeh "%s/mail.ReXXXXXXXXXX", tmpdir); 48674769Smikeh if ((fd = mkstemp(tempname)) == -1 || 48774769Smikeh (nf = Fdopen(fd, "w+")) == NULL) { 48874769Smikeh warn("%s", tempname); 4891590Srgrimes goto out; 4901590Srgrimes } 49177274Smikeh (void)rm(tempname); 4921590Srgrimes /* 4931590Srgrimes * stdin = current message. 4941590Srgrimes * stdout = new message. 4951590Srgrimes */ 49677274Smikeh if ((sh = value("SHELL")) == NULL) 49777274Smikeh sh = _PATH_CSHELL; 49877274Smikeh if (run_command(sh, 49977274Smikeh 0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) { 50077274Smikeh (void)Fclose(nf); 5011590Srgrimes goto out; 5021590Srgrimes } 5031590Srgrimes if (fsize(nf) == 0) { 5041590Srgrimes fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); 50577274Smikeh (void)Fclose(nf); 5061590Srgrimes goto out; 5071590Srgrimes } 5081590Srgrimes /* 5091590Srgrimes * Take new files. 5101590Srgrimes */ 51177274Smikeh (void)fseek(nf, 0L, 2); 5121590Srgrimes collf = nf; 51377274Smikeh (void)Fclose(fp); 5141590Srgrimesout: 51577274Smikeh (void)signal(SIGINT, sigint); 5161590Srgrimes} 5171590Srgrimes 5181590Srgrimes/* 5191590Srgrimes * Interpolate the named messages into the current 5201590Srgrimes * message, preceding each line with a tab. 5211590Srgrimes * Return a count of the number of characters now in 5221590Srgrimes * the message, or -1 if an error is encountered writing 5231590Srgrimes * the message temporary. The flag argument is 'm' if we 5241590Srgrimes * should shift over and 'f' if not. 5251590Srgrimes */ 5261590Srgrimesint 52774769Smikehforward(ms, fp, fn, f) 5281590Srgrimes char ms[]; 5291590Srgrimes FILE *fp; 53074769Smikeh char *fn; 5311590Srgrimes int f; 5321590Srgrimes{ 53377274Smikeh int *msgvec; 5341590Srgrimes struct ignoretab *ig; 5351590Srgrimes char *tabst; 5361590Srgrimes 53777274Smikeh msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec)); 53877274Smikeh if (msgvec == NULL) 53977274Smikeh return (0); 5401590Srgrimes if (getmsglist(ms, msgvec, 0) < 0) 54177274Smikeh return (0); 5421590Srgrimes if (*msgvec == 0) { 5431590Srgrimes *msgvec = first(0, MMNORM); 54429574Sphk if (*msgvec == 0) { 5451590Srgrimes printf("No appropriate messages\n"); 54677274Smikeh return (0); 5471590Srgrimes } 54829574Sphk msgvec[1] = 0; 5491590Srgrimes } 5501590Srgrimes if (f == 'f' || f == 'F') 55177274Smikeh tabst = NULL; 55277274Smikeh else if ((tabst = value("indentprefix")) == NULL) 5531590Srgrimes tabst = "\t"; 5541590Srgrimes ig = isupper(f) ? NULL : ignore; 5551590Srgrimes printf("Interpolating:"); 5561590Srgrimes for (; *msgvec != 0; msgvec++) { 5571590Srgrimes struct message *mp = message + *msgvec - 1; 5581590Srgrimes 5591590Srgrimes touch(mp); 5601590Srgrimes printf(" %d", *msgvec); 56174769Smikeh if (sendmessage(mp, fp, ig, tabst) < 0) { 56274769Smikeh warnx("%s", fn); 56377274Smikeh return (-1); 5641590Srgrimes } 5651590Srgrimes } 5661590Srgrimes printf("\n"); 56777274Smikeh return (0); 5681590Srgrimes} 5691590Srgrimes 5701590Srgrimes/* 5711590Srgrimes * Print (continue) when continued after ^Z. 5721590Srgrimes */ 5731590Srgrimes/*ARGSUSED*/ 5741590Srgrimesvoid 5751590Srgrimescollstop(s) 5761590Srgrimes int s; 5771590Srgrimes{ 5781590Srgrimes sig_t old_action = signal(s, SIG_DFL); 5791590Srgrimes 58077274Smikeh (void)sigsetmask(sigblock(0) & ~sigmask(s)); 58177274Smikeh (void)kill(0, s); 58277274Smikeh (void)sigblock(sigmask(s)); 58377274Smikeh (void)signal(s, old_action); 5841590Srgrimes if (colljmp_p) { 5851590Srgrimes colljmp_p = 0; 5861590Srgrimes hadintr = 0; 5871590Srgrimes longjmp(colljmp, 1); 5881590Srgrimes } 5891590Srgrimes} 5901590Srgrimes 5911590Srgrimes/* 5921590Srgrimes * On interrupt, come here to save the partial message in ~/dead.letter. 5931590Srgrimes * Then jump out of the collection loop. 5941590Srgrimes */ 5951590Srgrimes/*ARGSUSED*/ 5961590Srgrimesvoid 5971590Srgrimescollint(s) 5981590Srgrimes int s; 5991590Srgrimes{ 6001590Srgrimes /* 6011590Srgrimes * the control flow is subtle, because we can be called from ~q. 6021590Srgrimes */ 6031590Srgrimes if (!hadintr) { 60477274Smikeh if (value("ignore") != NULL) { 60577274Smikeh printf("@"); 60677274Smikeh (void)fflush(stdout); 6071590Srgrimes clearerr(stdin); 6081590Srgrimes return; 6091590Srgrimes } 6101590Srgrimes hadintr = 1; 6111590Srgrimes longjmp(colljmp, 1); 6121590Srgrimes } 6131590Srgrimes rewind(collf); 61477274Smikeh if (value("nosave") == NULL) 6151590Srgrimes savedeadletter(collf); 6161590Srgrimes longjmp(collabort, 1); 6171590Srgrimes} 6181590Srgrimes 6191590Srgrimes/*ARGSUSED*/ 6201590Srgrimesvoid 6211590Srgrimescollhup(s) 6221590Srgrimes int s; 6231590Srgrimes{ 6241590Srgrimes rewind(collf); 6251590Srgrimes savedeadletter(collf); 6261590Srgrimes /* 6271590Srgrimes * Let's pretend nobody else wants to clean up, 6281590Srgrimes * a true statement at this time. 6291590Srgrimes */ 6301590Srgrimes exit(1); 6311590Srgrimes} 6321590Srgrimes 6331590Srgrimesvoid 6341590Srgrimessavedeadletter(fp) 63577274Smikeh FILE *fp; 6361590Srgrimes{ 63777274Smikeh FILE *dbuf; 63877274Smikeh int c; 6391590Srgrimes char *cp; 6401590Srgrimes 6411590Srgrimes if (fsize(fp) == 0) 6421590Srgrimes return; 6431590Srgrimes cp = getdeadletter(); 6441590Srgrimes c = umask(077); 6451590Srgrimes dbuf = Fopen(cp, "a"); 64677274Smikeh (void)umask(c); 6471590Srgrimes if (dbuf == NULL) 6481590Srgrimes return; 6491590Srgrimes while ((c = getc(fp)) != EOF) 65077274Smikeh (void)putc(c, dbuf); 65177274Smikeh (void)Fclose(dbuf); 6521590Srgrimes rewind(fp); 6531590Srgrimes} 654