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 * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3174769Smikeh#if 0 321590Srgrimesstatic char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94"; 3374769Smikeh#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes/* 391590Srgrimes * Mail -- a mail program 401590Srgrimes * 411590Srgrimes * Collect input from standard input, handling 421590Srgrimes * ~ escapes. 431590Srgrimes */ 441590Srgrimes 451590Srgrimes#include "rcv.h" 4688428Smikeh#include <fcntl.h> 471590Srgrimes#include "extern.h" 481590Srgrimes 491590Srgrimes/* 501590Srgrimes * Read a message from standard output and return a read file to it 511590Srgrimes * or NULL on error. 521590Srgrimes */ 531590Srgrimes 541590Srgrimes/* 551590Srgrimes * The following hokiness with global variables is so that on 561590Srgrimes * receipt of an interrupt signal, the partial message can be salted 571590Srgrimes * away on dead.letter. 581590Srgrimes */ 591590Srgrimes 601590Srgrimesstatic sig_t saveint; /* Previous SIGINT value */ 611590Srgrimesstatic sig_t savehup; /* Previous SIGHUP value */ 621590Srgrimesstatic sig_t savetstp; /* Previous SIGTSTP value */ 631590Srgrimesstatic sig_t savettou; /* Previous SIGTTOU value */ 641590Srgrimesstatic sig_t savettin; /* Previous SIGTTIN value */ 651590Srgrimesstatic FILE *collf; /* File for saving away */ 661590Srgrimesstatic int hadintr; /* Have seen one SIGINT so far */ 671590Srgrimes 681590Srgrimesstatic jmp_buf colljmp; /* To get back to work */ 691590Srgrimesstatic int colljmp_p; /* whether to long jump */ 701590Srgrimesstatic jmp_buf collabort; /* To end collection with error */ 711590Srgrimes 721590SrgrimesFILE * 73216564Scharniercollect(struct header *hp, int printheaders) 741590Srgrimes{ 751590Srgrimes FILE *fbuf; 7677274Smikeh int lc, cc, escape, eofcount, fd, c, t; 7777274Smikeh char linebuf[LINESIZE], tempname[PATHSIZE], *cp, getsub; 7888150Smikeh sigset_t nset; 7988150Smikeh int longline, lastlong, rc; /* So we don't make 2 or more lines 8088150Smikeh out of a long input line. */ 811590Srgrimes 821590Srgrimes collf = NULL; 831590Srgrimes /* 841590Srgrimes * Start catching signals from here, but we're still die on interrupts 851590Srgrimes * until we're in the main loop. 861590Srgrimes */ 8788150Smikeh (void)sigemptyset(&nset); 8888150Smikeh (void)sigaddset(&nset, SIGINT); 8988150Smikeh (void)sigaddset(&nset, SIGHUP); 9088150Smikeh (void)sigprocmask(SIG_BLOCK, &nset, NULL); 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 } 10288150Smikeh (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 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; 13488150Smikeh lastlong = 0; 13588150Smikeh longline = 0; 1361590Srgrimes 1371590Srgrimes if (!setjmp(colljmp)) { 1381590Srgrimes if (getsub) 1391590Srgrimes grabh(hp, GSUBJECT); 1401590Srgrimes } else { 1411590Srgrimes /* 1421590Srgrimes * Come here for printing the after-signal message. 1431590Srgrimes * Duplicate messages won't be printed because 1441590Srgrimes * the write is aborted if we get a SIGTTOU. 1451590Srgrimes */ 1461590Srgrimescont: 1471590Srgrimes if (hadintr) { 14877274Smikeh (void)fflush(stdout); 1491590Srgrimes fprintf(stderr, 1501590Srgrimes "\n(Interrupt -- one more to kill letter)\n"); 1511590Srgrimes } else { 1521590Srgrimes printf("(continue)\n"); 15377274Smikeh (void)fflush(stdout); 1541590Srgrimes } 1551590Srgrimes } 1561590Srgrimes for (;;) { 1571590Srgrimes colljmp_p = 1; 1581590Srgrimes c = readline(stdin, linebuf, LINESIZE); 1591590Srgrimes colljmp_p = 0; 1601590Srgrimes if (c < 0) { 16177274Smikeh if (value("interactive") != NULL && 16277274Smikeh value("ignoreeof") != NULL && ++eofcount < 25) { 1631590Srgrimes printf("Use \".\" to terminate letter\n"); 1641590Srgrimes continue; 1651590Srgrimes } 1661590Srgrimes break; 1671590Srgrimes } 16888150Smikeh lastlong = longline; 16988150Smikeh longline = c == LINESIZE - 1; 1701590Srgrimes eofcount = 0; 1711590Srgrimes hadintr = 0; 1721590Srgrimes if (linebuf[0] == '.' && linebuf[1] == '\0' && 17388150Smikeh value("interactive") != NULL && !lastlong && 17477274Smikeh (value("dot") != NULL || value("ignoreeof") != NULL)) 1751590Srgrimes break; 17688150Smikeh if (linebuf[0] != escape || value("interactive") == NULL || 17788150Smikeh lastlong) { 17888150Smikeh if (putline(collf, linebuf, !longline) < 0) 1791590Srgrimes goto err; 1801590Srgrimes continue; 1811590Srgrimes } 1821590Srgrimes c = linebuf[1]; 1831590Srgrimes switch (c) { 1841590Srgrimes default: 1851590Srgrimes /* 1861590Srgrimes * On double escape, just send the single one. 1871590Srgrimes * Otherwise, it's an error. 1881590Srgrimes */ 1891590Srgrimes if (c == escape) { 19088150Smikeh if (putline(collf, &linebuf[1], !longline) < 0) 1911590Srgrimes goto err; 1921590Srgrimes else 1931590Srgrimes break; 1941590Srgrimes } 1951590Srgrimes printf("Unknown tilde escape.\n"); 1961590Srgrimes break; 1971590Srgrimes case 'C': 1981590Srgrimes /* 1991590Srgrimes * Dump core. 2001590Srgrimes */ 2011590Srgrimes core(); 2021590Srgrimes break; 2031590Srgrimes case '!': 2041590Srgrimes /* 2051590Srgrimes * Shell escape, send the balance of the 2061590Srgrimes * line to sh -c. 2071590Srgrimes */ 2081590Srgrimes shell(&linebuf[2]); 2091590Srgrimes break; 2101590Srgrimes case ':': 21188428Smikeh case '_': 2121590Srgrimes /* 2131590Srgrimes * Escape to command mode, but be nice! 2141590Srgrimes */ 2151590Srgrimes execute(&linebuf[2], 1); 2161590Srgrimes goto cont; 2171590Srgrimes case '.': 2181590Srgrimes /* 2191590Srgrimes * Simulate end of file on input. 2201590Srgrimes */ 2211590Srgrimes goto out; 2221590Srgrimes case 'q': 2231590Srgrimes /* 2241590Srgrimes * Force a quit of sending mail. 2251590Srgrimes * Act like an interrupt happened. 2261590Srgrimes */ 2271590Srgrimes hadintr++; 2281590Srgrimes collint(SIGINT); 2291590Srgrimes exit(1); 23088428Smikeh case 'x': 23188428Smikeh /* 23288428Smikeh * Exit, do not save in dead.letter. 23388428Smikeh */ 23488428Smikeh goto err; 2351590Srgrimes case 'h': 2361590Srgrimes /* 2371590Srgrimes * Grab a bunch of headers. 2381590Srgrimes */ 2391590Srgrimes grabh(hp, GTO|GSUBJECT|GCC|GBCC); 2401590Srgrimes goto cont; 2411590Srgrimes case 't': 2421590Srgrimes /* 2431590Srgrimes * Add to the To list. 2441590Srgrimes */ 2451590Srgrimes hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); 2461590Srgrimes break; 2471590Srgrimes case 's': 2481590Srgrimes /* 24932189Sjoerg * Set the Subject line. 2501590Srgrimes */ 2511590Srgrimes cp = &linebuf[2]; 25288227Sache while (isspace((unsigned char)*cp)) 2531590Srgrimes cp++; 2541590Srgrimes hp->h_subject = savestr(cp); 2551590Srgrimes break; 25632189Sjoerg case 'R': 25732189Sjoerg /* 25832189Sjoerg * Set the Reply-To line. 25932189Sjoerg */ 26032189Sjoerg cp = &linebuf[2]; 26188227Sache while (isspace((unsigned char)*cp)) 26232189Sjoerg cp++; 26332189Sjoerg hp->h_replyto = savestr(cp); 26432189Sjoerg break; 2651590Srgrimes case 'c': 2661590Srgrimes /* 2671590Srgrimes * Add to the CC list. 2681590Srgrimes */ 2691590Srgrimes hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); 2701590Srgrimes break; 2711590Srgrimes case 'b': 2721590Srgrimes /* 27388428Smikeh * Add to the BCC list. 2741590Srgrimes */ 2751590Srgrimes hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); 2761590Srgrimes break; 27788428Smikeh case 'i': 27888428Smikeh case 'A': 27988428Smikeh case 'a': 28088428Smikeh /* 28188434Smikeh * Insert named variable in message. 28288428Smikeh */ 28388428Smikeh switch(c) { 28488428Smikeh case 'i': 28588428Smikeh cp = &linebuf[2]; 28688428Smikeh while(isspace((unsigned char)*cp)) 28788428Smikeh cp++; 28888428Smikeh break; 28988428Smikeh case 'a': 29088428Smikeh cp = "sign"; 29188428Smikeh break; 29288428Smikeh case 'A': 29388428Smikeh cp = "Sign"; 29488428Smikeh break; 29588428Smikeh default: 29688428Smikeh goto err; 29788428Smikeh } 29888428Smikeh 29988428Smikeh if(*cp != '\0' && (cp = value(cp)) != NULL) { 30088428Smikeh printf("%s\n", cp); 30188428Smikeh if(putline(collf, cp, 1) < 0) 30288428Smikeh goto err; 30388428Smikeh } 30488428Smikeh 30588428Smikeh break; 3061590Srgrimes case 'd': 30788428Smikeh /* 30888428Smikeh * Read in the dead letter file. 30988428Smikeh */ 31088428Smikeh if (strlcpy(linebuf + 2, getdeadletter(), 31188428Smikeh sizeof(linebuf) - 2) 31274769Smikeh >= sizeof(linebuf) - 2) { 31374769Smikeh printf("Line buffer overflow\n"); 31474769Smikeh break; 31574769Smikeh } 31688428Smikeh /* FALLTHROUGH */ 3171590Srgrimes case 'r': 31888428Smikeh case '<': 3191590Srgrimes /* 3201590Srgrimes * Invoke a file: 3211590Srgrimes * Search for the file name, 3221590Srgrimes * then open it and copy the contents to collf. 3231590Srgrimes */ 3241590Srgrimes cp = &linebuf[2]; 32588227Sache while (isspace((unsigned char)*cp)) 3261590Srgrimes cp++; 3271590Srgrimes if (*cp == '\0') { 3281590Srgrimes printf("Interpolate what file?\n"); 3291590Srgrimes break; 3301590Srgrimes } 3311590Srgrimes cp = expand(cp); 33277274Smikeh if (cp == NULL) 3331590Srgrimes break; 33488428Smikeh if (*cp == '!') { 33588428Smikeh /* 33688428Smikeh * Insert stdout of command. 33788428Smikeh */ 33888428Smikeh char *sh; 33988428Smikeh int nullfd, tempfd, rc; 34088428Smikeh char tempname2[PATHSIZE]; 34188428Smikeh 34288428Smikeh if ((nullfd = open("/dev/null", O_RDONLY, 0)) 34388428Smikeh == -1) { 34488428Smikeh warn("/dev/null"); 34588428Smikeh break; 34688428Smikeh } 34788428Smikeh 34888428Smikeh (void)snprintf(tempname2, sizeof(tempname2), 34988428Smikeh "%s/mail.ReXXXXXXXXXX", tmpdir); 35088428Smikeh if ((tempfd = mkstemp(tempname2)) == -1 || 35188428Smikeh (fbuf = Fdopen(tempfd, "w+")) == NULL) { 35288428Smikeh warn("%s", tempname2); 35388428Smikeh break; 35488428Smikeh } 35588428Smikeh (void)unlink(tempname2); 35688428Smikeh 35788428Smikeh if ((sh = value("SHELL")) == NULL) 35888428Smikeh sh = _PATH_CSHELL; 35988428Smikeh 36088428Smikeh rc = run_command(sh, 0, nullfd, fileno(fbuf), 36188428Smikeh "-c", cp+1, NULL); 36288428Smikeh 36388428Smikeh close(nullfd); 36488428Smikeh 36588428Smikeh if (rc < 0) { 36688428Smikeh (void)Fclose(fbuf); 36788428Smikeh break; 36888428Smikeh } 36988428Smikeh 37088428Smikeh if (fsize(fbuf) == 0) { 37188428Smikeh fprintf(stderr, 37288428Smikeh "No bytes from command \"%s\"\n", 37388428Smikeh cp+1); 37488428Smikeh (void)Fclose(fbuf); 37588428Smikeh break; 37688428Smikeh } 37788428Smikeh 37888428Smikeh rewind(fbuf); 37988428Smikeh } else if (isdir(cp)) { 3801590Srgrimes printf("%s: Directory\n", cp); 3811590Srgrimes break; 38288428Smikeh } else if ((fbuf = Fopen(cp, "r")) == NULL) { 38374769Smikeh warn("%s", cp); 3841590Srgrimes break; 3851590Srgrimes } 3861590Srgrimes printf("\"%s\" ", cp); 38777274Smikeh (void)fflush(stdout); 3881590Srgrimes lc = 0; 3891590Srgrimes cc = 0; 39088150Smikeh while ((rc = readline(fbuf, linebuf, LINESIZE)) >= 0) { 39188150Smikeh if (rc != LINESIZE - 1) 39288150Smikeh lc++; 39388150Smikeh if ((t = putline(collf, linebuf, 39488150Smikeh rc != LINESIZE - 1)) < 0) { 39577274Smikeh (void)Fclose(fbuf); 3961590Srgrimes goto err; 3971590Srgrimes } 3981590Srgrimes cc += t; 3991590Srgrimes } 40077274Smikeh (void)Fclose(fbuf); 4011590Srgrimes printf("%d/%d\n", lc, cc); 4021590Srgrimes break; 4031590Srgrimes case 'w': 4041590Srgrimes /* 4051590Srgrimes * Write the message on a file. 4061590Srgrimes */ 4071590Srgrimes cp = &linebuf[2]; 4081590Srgrimes while (*cp == ' ' || *cp == '\t') 4091590Srgrimes cp++; 4101590Srgrimes if (*cp == '\0') { 4111590Srgrimes fprintf(stderr, "Write what file!?\n"); 4121590Srgrimes break; 4131590Srgrimes } 41477274Smikeh if ((cp = expand(cp)) == NULL) 4151590Srgrimes break; 4161590Srgrimes rewind(collf); 4171590Srgrimes exwrite(cp, collf, 1); 4181590Srgrimes break; 4191590Srgrimes case 'm': 4201590Srgrimes case 'M': 4211590Srgrimes case 'f': 4221590Srgrimes case 'F': 4231590Srgrimes /* 4241590Srgrimes * Interpolate the named messages, if we 4251590Srgrimes * are in receiving mail mode. Does the 4261590Srgrimes * standard list processing garbage. 4271590Srgrimes * If ~f is given, we don't shift over. 4281590Srgrimes */ 42974769Smikeh if (forward(linebuf + 2, collf, tempname, c) < 0) 4301590Srgrimes goto err; 4311590Srgrimes goto cont; 4321590Srgrimes case '?': 4331590Srgrimes if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { 43474769Smikeh warn("%s", _PATH_TILDE); 4351590Srgrimes break; 4361590Srgrimes } 4371590Srgrimes while ((t = getc(fbuf)) != EOF) 43877274Smikeh (void)putchar(t); 43977274Smikeh (void)Fclose(fbuf); 4401590Srgrimes break; 4411590Srgrimes case 'p': 4421590Srgrimes /* 4431590Srgrimes * Print out the current state of the 4441590Srgrimes * message without altering anything. 4451590Srgrimes */ 4461590Srgrimes rewind(collf); 4471590Srgrimes printf("-------\nMessage contains:\n"); 4481590Srgrimes puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); 4491590Srgrimes while ((t = getc(collf)) != EOF) 45077274Smikeh (void)putchar(t); 4511590Srgrimes goto cont; 4521590Srgrimes case '|': 4531590Srgrimes /* 4541590Srgrimes * Pipe message through command. 4551590Srgrimes * Collect output as new message. 4561590Srgrimes */ 4571590Srgrimes rewind(collf); 4581590Srgrimes mespipe(collf, &linebuf[2]); 4591590Srgrimes goto cont; 4601590Srgrimes case 'v': 4611590Srgrimes case 'e': 4621590Srgrimes /* 4631590Srgrimes * Edit the current message. 4641590Srgrimes * 'e' means to use EDITOR 4651590Srgrimes * 'v' means to use VISUAL 4661590Srgrimes */ 4671590Srgrimes rewind(collf); 4681590Srgrimes mesedit(collf, c); 4691590Srgrimes goto cont; 4701590Srgrimes } 4711590Srgrimes } 4721590Srgrimes goto out; 4731590Srgrimeserr: 4741590Srgrimes if (collf != NULL) { 47577274Smikeh (void)Fclose(collf); 4761590Srgrimes collf = NULL; 4771590Srgrimes } 4781590Srgrimesout: 4791590Srgrimes if (collf != NULL) 4801590Srgrimes rewind(collf); 4811590Srgrimes noreset--; 48288150Smikeh (void)sigprocmask(SIG_BLOCK, &nset, NULL); 48377274Smikeh (void)signal(SIGINT, saveint); 48477274Smikeh (void)signal(SIGHUP, savehup); 48577274Smikeh (void)signal(SIGTSTP, savetstp); 48677274Smikeh (void)signal(SIGTTOU, savettou); 48777274Smikeh (void)signal(SIGTTIN, savettin); 48888150Smikeh (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 48977274Smikeh return (collf); 4901590Srgrimes} 4911590Srgrimes 4921590Srgrimes/* 4931590Srgrimes * Write a file, ex-like if f set. 4941590Srgrimes */ 4951590Srgrimesint 496216564Scharnierexwrite(char name[], FILE *fp, int f) 4971590Srgrimes{ 49877274Smikeh FILE *of; 49977274Smikeh int c, lc; 5001590Srgrimes long cc; 5011590Srgrimes struct stat junk; 5021590Srgrimes 5031590Srgrimes if (f) { 5041590Srgrimes printf("\"%s\" ", name); 50577274Smikeh (void)fflush(stdout); 5061590Srgrimes } 50774769Smikeh if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) { 5081590Srgrimes if (!f) 5091590Srgrimes fprintf(stderr, "%s: ", name); 5101590Srgrimes fprintf(stderr, "File exists\n"); 51177274Smikeh return (-1); 5121590Srgrimes } 5131590Srgrimes if ((of = Fopen(name, "w")) == NULL) { 51477274Smikeh warn((char *)NULL); 51577274Smikeh return (-1); 5161590Srgrimes } 5171590Srgrimes lc = 0; 5181590Srgrimes cc = 0; 5191590Srgrimes while ((c = getc(fp)) != EOF) { 5201590Srgrimes cc++; 5211590Srgrimes if (c == '\n') 5221590Srgrimes lc++; 52377274Smikeh (void)putc(c, of); 5241590Srgrimes if (ferror(of)) { 52574769Smikeh warnx("%s", name); 52677274Smikeh (void)Fclose(of); 52777274Smikeh return (-1); 5281590Srgrimes } 5291590Srgrimes } 53077274Smikeh (void)Fclose(of); 5311590Srgrimes printf("%d/%ld\n", lc, cc); 53277274Smikeh (void)fflush(stdout); 53377274Smikeh return (0); 5341590Srgrimes} 5351590Srgrimes 5361590Srgrimes/* 5371590Srgrimes * Edit the message being collected on fp. 5381590Srgrimes * On return, make the edit file the new temp file. 5391590Srgrimes */ 5401590Srgrimesvoid 541216564Scharniermesedit(FILE *fp, int c) 5421590Srgrimes{ 5431590Srgrimes sig_t sigint = signal(SIGINT, SIG_IGN); 5441590Srgrimes FILE *nf = run_editor(fp, (off_t)-1, c, 0); 5451590Srgrimes 5461590Srgrimes if (nf != NULL) { 54782793Sache (void)fseeko(nf, (off_t)0, SEEK_END); 5481590Srgrimes collf = nf; 54977274Smikeh (void)Fclose(fp); 5501590Srgrimes } 55177274Smikeh (void)signal(SIGINT, sigint); 5521590Srgrimes} 5531590Srgrimes 5541590Srgrimes/* 5551590Srgrimes * Pipe the message through the command. 5561590Srgrimes * Old message is on stdin of command; 5571590Srgrimes * New message collected from stdout. 5581590Srgrimes * Sh -c must return 0 to accept the new message. 5591590Srgrimes */ 5601590Srgrimesvoid 561216564Scharniermespipe(FILE *fp, char cmd[]) 5621590Srgrimes{ 5631590Srgrimes FILE *nf; 56474769Smikeh int fd; 5651590Srgrimes sig_t sigint = signal(SIGINT, SIG_IGN); 56677274Smikeh char *sh, tempname[PATHSIZE]; 5671590Srgrimes 56877274Smikeh (void)snprintf(tempname, sizeof(tempname), 56977274Smikeh "%s/mail.ReXXXXXXXXXX", tmpdir); 57074769Smikeh if ((fd = mkstemp(tempname)) == -1 || 57174769Smikeh (nf = Fdopen(fd, "w+")) == NULL) { 57274769Smikeh warn("%s", tempname); 5731590Srgrimes goto out; 5741590Srgrimes } 57577274Smikeh (void)rm(tempname); 5761590Srgrimes /* 5771590Srgrimes * stdin = current message. 5781590Srgrimes * stdout = new message. 5791590Srgrimes */ 58077274Smikeh if ((sh = value("SHELL")) == NULL) 58177274Smikeh sh = _PATH_CSHELL; 58277274Smikeh if (run_command(sh, 58377274Smikeh 0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) { 58477274Smikeh (void)Fclose(nf); 5851590Srgrimes goto out; 5861590Srgrimes } 5871590Srgrimes if (fsize(nf) == 0) { 5881590Srgrimes fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); 58977274Smikeh (void)Fclose(nf); 5901590Srgrimes goto out; 5911590Srgrimes } 5921590Srgrimes /* 5931590Srgrimes * Take new files. 5941590Srgrimes */ 59582793Sache (void)fseeko(nf, (off_t)0, SEEK_END); 5961590Srgrimes collf = nf; 59777274Smikeh (void)Fclose(fp); 5981590Srgrimesout: 59977274Smikeh (void)signal(SIGINT, sigint); 6001590Srgrimes} 6011590Srgrimes 6021590Srgrimes/* 6031590Srgrimes * Interpolate the named messages into the current 6041590Srgrimes * message, preceding each line with a tab. 6051590Srgrimes * Return a count of the number of characters now in 6061590Srgrimes * the message, or -1 if an error is encountered writing 6071590Srgrimes * the message temporary. The flag argument is 'm' if we 6081590Srgrimes * should shift over and 'f' if not. 6091590Srgrimes */ 6101590Srgrimesint 611216564Scharnierforward(char ms[], FILE *fp, char *fn, int f) 6121590Srgrimes{ 61377274Smikeh int *msgvec; 6141590Srgrimes struct ignoretab *ig; 6151590Srgrimes char *tabst; 6161590Srgrimes 61777274Smikeh msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec)); 61877274Smikeh if (msgvec == NULL) 61977274Smikeh return (0); 6201590Srgrimes if (getmsglist(ms, msgvec, 0) < 0) 62177274Smikeh return (0); 6221590Srgrimes if (*msgvec == 0) { 6231590Srgrimes *msgvec = first(0, MMNORM); 62429574Sphk if (*msgvec == 0) { 6251590Srgrimes printf("No appropriate messages\n"); 62677274Smikeh return (0); 6271590Srgrimes } 62829574Sphk msgvec[1] = 0; 6291590Srgrimes } 6301590Srgrimes if (f == 'f' || f == 'F') 63177274Smikeh tabst = NULL; 63277274Smikeh else if ((tabst = value("indentprefix")) == NULL) 6331590Srgrimes tabst = "\t"; 63488227Sache ig = isupper((unsigned char)f) ? NULL : ignore; 6351590Srgrimes printf("Interpolating:"); 6361590Srgrimes for (; *msgvec != 0; msgvec++) { 6371590Srgrimes struct message *mp = message + *msgvec - 1; 6381590Srgrimes 6391590Srgrimes touch(mp); 6401590Srgrimes printf(" %d", *msgvec); 64174769Smikeh if (sendmessage(mp, fp, ig, tabst) < 0) { 64274769Smikeh warnx("%s", fn); 64377274Smikeh return (-1); 6441590Srgrimes } 6451590Srgrimes } 6461590Srgrimes printf("\n"); 64777274Smikeh return (0); 6481590Srgrimes} 6491590Srgrimes 6501590Srgrimes/* 6511590Srgrimes * Print (continue) when continued after ^Z. 6521590Srgrimes */ 6531590Srgrimes/*ARGSUSED*/ 6541590Srgrimesvoid 655216564Scharniercollstop(int s) 6561590Srgrimes{ 6571590Srgrimes sig_t old_action = signal(s, SIG_DFL); 65888150Smikeh sigset_t nset; 6591590Srgrimes 66088150Smikeh (void)sigemptyset(&nset); 66188150Smikeh (void)sigaddset(&nset, s); 66288150Smikeh (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 66377274Smikeh (void)kill(0, s); 66488150Smikeh (void)sigprocmask(SIG_BLOCK, &nset, NULL); 66577274Smikeh (void)signal(s, old_action); 6661590Srgrimes if (colljmp_p) { 6671590Srgrimes colljmp_p = 0; 6681590Srgrimes hadintr = 0; 6691590Srgrimes longjmp(colljmp, 1); 6701590Srgrimes } 6711590Srgrimes} 6721590Srgrimes 6731590Srgrimes/* 6741590Srgrimes * On interrupt, come here to save the partial message in ~/dead.letter. 6751590Srgrimes * Then jump out of the collection loop. 6761590Srgrimes */ 6771590Srgrimes/*ARGSUSED*/ 6781590Srgrimesvoid 679216564Scharniercollint(int s __unused) 6801590Srgrimes{ 6811590Srgrimes /* 6821590Srgrimes * the control flow is subtle, because we can be called from ~q. 6831590Srgrimes */ 6841590Srgrimes if (!hadintr) { 68577274Smikeh if (value("ignore") != NULL) { 68677274Smikeh printf("@"); 68777274Smikeh (void)fflush(stdout); 6881590Srgrimes clearerr(stdin); 6891590Srgrimes return; 6901590Srgrimes } 6911590Srgrimes hadintr = 1; 6921590Srgrimes longjmp(colljmp, 1); 6931590Srgrimes } 6941590Srgrimes rewind(collf); 69577274Smikeh if (value("nosave") == NULL) 6961590Srgrimes savedeadletter(collf); 6971590Srgrimes longjmp(collabort, 1); 6981590Srgrimes} 6991590Srgrimes 7001590Srgrimes/*ARGSUSED*/ 7011590Srgrimesvoid 702216564Scharniercollhup(int s __unused) 7031590Srgrimes{ 7041590Srgrimes rewind(collf); 7051590Srgrimes savedeadletter(collf); 7061590Srgrimes /* 7071590Srgrimes * Let's pretend nobody else wants to clean up, 7081590Srgrimes * a true statement at this time. 7091590Srgrimes */ 7101590Srgrimes exit(1); 7111590Srgrimes} 7121590Srgrimes 7131590Srgrimesvoid 714216564Scharniersavedeadletter(FILE *fp) 7151590Srgrimes{ 71677274Smikeh FILE *dbuf; 71777274Smikeh int c; 7181590Srgrimes char *cp; 7191590Srgrimes 7201590Srgrimes if (fsize(fp) == 0) 7211590Srgrimes return; 7221590Srgrimes cp = getdeadletter(); 7231590Srgrimes c = umask(077); 7241590Srgrimes dbuf = Fopen(cp, "a"); 72577274Smikeh (void)umask(c); 7261590Srgrimes if (dbuf == NULL) 7271590Srgrimes return; 7281590Srgrimes while ((c = getc(fp)) != EOF) 72977274Smikeh (void)putc(c, dbuf); 73077274Smikeh (void)Fclose(dbuf); 7311590Srgrimes rewind(fp); 7321590Srgrimes} 733