18a16b7a1SPedro F. Giffuni /*- 28a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 38a16b7a1SPedro F. Giffuni * 49b50d902SRodney W. Grimes * Copyright (c) 1980, 1993 59b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 69b50d902SRodney W. Grimes * 79b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 89b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 99b50d902SRodney W. Grimes * are met: 109b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 129b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 139b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 149b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 169b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 179b50d902SRodney W. Grimes * without specific prior written permission. 189b50d902SRodney W. Grimes * 199b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 209b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 219b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 229b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 239b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 249b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 259b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 269b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 279b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 289b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 299b50d902SRodney W. Grimes * SUCH DAMAGE. 309b50d902SRodney W. Grimes */ 319b50d902SRodney W. Grimes 329b50d902SRodney W. Grimes #ifndef lint 330c3a8314SMike Heffner #if 0 349b50d902SRodney W. Grimes static char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94"; 350c3a8314SMike Heffner #endif 369b50d902SRodney W. Grimes #endif /* not lint */ 37e026a48cSDavid E. O'Brien #include <sys/cdefs.h> 38e026a48cSDavid E. O'Brien __FBSDID("$FreeBSD$"); 399b50d902SRodney W. Grimes 409b50d902SRodney W. Grimes /* 419b50d902SRodney W. Grimes * Mail -- a mail program 429b50d902SRodney W. Grimes * 439b50d902SRodney W. Grimes * Collect input from standard input, handling 449b50d902SRodney W. Grimes * ~ escapes. 459b50d902SRodney W. Grimes */ 469b50d902SRodney W. Grimes 479b50d902SRodney W. Grimes #include "rcv.h" 4869131e40SMike Heffner #include <fcntl.h> 499b50d902SRodney W. Grimes #include "extern.h" 509b50d902SRodney W. Grimes 519b50d902SRodney W. Grimes /* 5224b797ccSPedro F. Giffuni * Read a message from standard input and return a read file to it 539b50d902SRodney W. Grimes * or NULL on error. 549b50d902SRodney W. Grimes */ 559b50d902SRodney W. Grimes 569b50d902SRodney W. Grimes /* 579b50d902SRodney W. Grimes * The following hokiness with global variables is so that on 589b50d902SRodney W. Grimes * receipt of an interrupt signal, the partial message can be salted 599b50d902SRodney W. Grimes * away on dead.letter. 609b50d902SRodney W. Grimes */ 619b50d902SRodney W. Grimes 629b50d902SRodney W. Grimes static sig_t saveint; /* Previous SIGINT value */ 639b50d902SRodney W. Grimes static sig_t savehup; /* Previous SIGHUP value */ 649b50d902SRodney W. Grimes static sig_t savetstp; /* Previous SIGTSTP value */ 659b50d902SRodney W. Grimes static sig_t savettou; /* Previous SIGTTOU value */ 669b50d902SRodney W. Grimes static sig_t savettin; /* Previous SIGTTIN value */ 679b50d902SRodney W. Grimes static FILE *collf; /* File for saving away */ 689b50d902SRodney W. Grimes static int hadintr; /* Have seen one SIGINT so far */ 699b50d902SRodney W. Grimes 709b50d902SRodney W. Grimes static jmp_buf colljmp; /* To get back to work */ 719b50d902SRodney W. Grimes static int colljmp_p; /* whether to long jump */ 729b50d902SRodney W. Grimes static jmp_buf collabort; /* To end collection with error */ 739b50d902SRodney W. Grimes 749b50d902SRodney W. Grimes FILE * 756d8484b0SPhilippe Charnier collect(struct header *hp, int printheaders) 769b50d902SRodney W. Grimes { 779b50d902SRodney W. Grimes FILE *fbuf; 789ce73e90SMike Heffner int lc, cc, escape, eofcount, fd, c, t; 799ce73e90SMike Heffner char linebuf[LINESIZE], tempname[PATHSIZE], *cp, getsub; 80856f23edSMike Heffner sigset_t nset; 81856f23edSMike Heffner int longline, lastlong, rc; /* So we don't make 2 or more lines 82856f23edSMike Heffner out of a long input line. */ 839b50d902SRodney W. Grimes 849b50d902SRodney W. Grimes collf = NULL; 859b50d902SRodney W. Grimes /* 869b50d902SRodney W. Grimes * Start catching signals from here, but we're still die on interrupts 879b50d902SRodney W. Grimes * until we're in the main loop. 889b50d902SRodney W. Grimes */ 89856f23edSMike Heffner (void)sigemptyset(&nset); 90856f23edSMike Heffner (void)sigaddset(&nset, SIGINT); 91856f23edSMike Heffner (void)sigaddset(&nset, SIGHUP); 92856f23edSMike Heffner (void)sigprocmask(SIG_BLOCK, &nset, NULL); 939b50d902SRodney W. Grimes if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) 949ce73e90SMike Heffner (void)signal(SIGINT, collint); 959b50d902SRodney W. Grimes if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) 969ce73e90SMike Heffner (void)signal(SIGHUP, collhup); 979b50d902SRodney W. Grimes savetstp = signal(SIGTSTP, collstop); 989b50d902SRodney W. Grimes savettou = signal(SIGTTOU, collstop); 999b50d902SRodney W. Grimes savettin = signal(SIGTTIN, collstop); 1009b50d902SRodney W. Grimes if (setjmp(collabort) || setjmp(colljmp)) { 1019ce73e90SMike Heffner (void)rm(tempname); 1029b50d902SRodney W. Grimes goto err; 1039b50d902SRodney W. Grimes } 104856f23edSMike Heffner (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 1059b50d902SRodney W. Grimes 1069b50d902SRodney W. Grimes noreset++; 1079ce73e90SMike Heffner (void)snprintf(tempname, sizeof(tempname), 1089ce73e90SMike Heffner "%s/mail.RsXXXXXXXXXX", tmpdir); 1090c3a8314SMike Heffner if ((fd = mkstemp(tempname)) == -1 || 1100c3a8314SMike Heffner (collf = Fdopen(fd, "w+")) == NULL) { 1110c3a8314SMike Heffner warn("%s", tempname); 1129b50d902SRodney W. Grimes goto err; 1139b50d902SRodney W. Grimes } 1149ce73e90SMike Heffner (void)rm(tempname); 1159b50d902SRodney W. Grimes 1169b50d902SRodney W. Grimes /* 1179b50d902SRodney W. Grimes * If we are going to prompt for a subject, 1189b50d902SRodney W. Grimes * refrain from printing a newline after 1199b50d902SRodney W. Grimes * the headers (since some people mind). 1209b50d902SRodney W. Grimes */ 1219b50d902SRodney W. Grimes t = GTO|GSUBJECT|GCC|GNL; 1229b50d902SRodney W. Grimes getsub = 0; 1239ce73e90SMike Heffner if (hp->h_subject == NULL && value("interactive") != NULL && 1249ce73e90SMike Heffner (value("ask") != NULL || value("asksub") != NULL)) 1259b50d902SRodney W. Grimes t &= ~GNL, getsub++; 1269b50d902SRodney W. Grimes if (printheaders) { 1279b50d902SRodney W. Grimes puthead(hp, stdout, t); 1289ce73e90SMike Heffner (void)fflush(stdout); 1299b50d902SRodney W. Grimes } 1309ce73e90SMike Heffner if ((cp = value("escape")) != NULL) 1319b50d902SRodney W. Grimes escape = *cp; 1329b50d902SRodney W. Grimes else 1339b50d902SRodney W. Grimes escape = ESCAPE; 1349b50d902SRodney W. Grimes eofcount = 0; 1359b50d902SRodney W. Grimes hadintr = 0; 136856f23edSMike Heffner longline = 0; 1379b50d902SRodney W. Grimes 1389b50d902SRodney W. Grimes if (!setjmp(colljmp)) { 1399b50d902SRodney W. Grimes if (getsub) 1409b50d902SRodney W. Grimes grabh(hp, GSUBJECT); 1419b50d902SRodney W. Grimes } else { 1429b50d902SRodney W. Grimes /* 1439b50d902SRodney W. Grimes * Come here for printing the after-signal message. 1449b50d902SRodney W. Grimes * Duplicate messages won't be printed because 1459b50d902SRodney W. Grimes * the write is aborted if we get a SIGTTOU. 1469b50d902SRodney W. Grimes */ 1479b50d902SRodney W. Grimes cont: 1489b50d902SRodney W. Grimes if (hadintr) { 1499ce73e90SMike Heffner (void)fflush(stdout); 1509b50d902SRodney W. Grimes fprintf(stderr, 1519b50d902SRodney W. Grimes "\n(Interrupt -- one more to kill letter)\n"); 1529b50d902SRodney W. Grimes } else { 1539b50d902SRodney W. Grimes printf("(continue)\n"); 1549ce73e90SMike Heffner (void)fflush(stdout); 1559b50d902SRodney W. Grimes } 1569b50d902SRodney W. Grimes } 1579b50d902SRodney W. Grimes for (;;) { 1589b50d902SRodney W. Grimes colljmp_p = 1; 1599b50d902SRodney W. Grimes c = readline(stdin, linebuf, LINESIZE); 1609b50d902SRodney W. Grimes colljmp_p = 0; 1619b50d902SRodney W. Grimes if (c < 0) { 1629ce73e90SMike Heffner if (value("interactive") != NULL && 1639ce73e90SMike Heffner value("ignoreeof") != NULL && ++eofcount < 25) { 1649b50d902SRodney W. Grimes printf("Use \".\" to terminate letter\n"); 1659b50d902SRodney W. Grimes continue; 1669b50d902SRodney W. Grimes } 1679b50d902SRodney W. Grimes break; 1689b50d902SRodney W. Grimes } 169856f23edSMike Heffner lastlong = longline; 170856f23edSMike Heffner longline = c == LINESIZE - 1; 1719b50d902SRodney W. Grimes eofcount = 0; 1729b50d902SRodney W. Grimes hadintr = 0; 1739b50d902SRodney W. Grimes if (linebuf[0] == '.' && linebuf[1] == '\0' && 174856f23edSMike Heffner value("interactive") != NULL && !lastlong && 1759ce73e90SMike Heffner (value("dot") != NULL || value("ignoreeof") != NULL)) 1769b50d902SRodney W. Grimes break; 177856f23edSMike Heffner if (linebuf[0] != escape || value("interactive") == NULL || 178856f23edSMike Heffner lastlong) { 179856f23edSMike Heffner if (putline(collf, linebuf, !longline) < 0) 1809b50d902SRodney W. Grimes goto err; 1819b50d902SRodney W. Grimes continue; 1829b50d902SRodney W. Grimes } 1839b50d902SRodney W. Grimes c = linebuf[1]; 1849b50d902SRodney W. Grimes switch (c) { 1859b50d902SRodney W. Grimes default: 1869b50d902SRodney W. Grimes /* 1879b50d902SRodney W. Grimes * On double escape, just send the single one. 1889b50d902SRodney W. Grimes * Otherwise, it's an error. 1899b50d902SRodney W. Grimes */ 1909b50d902SRodney W. Grimes if (c == escape) { 191856f23edSMike Heffner if (putline(collf, &linebuf[1], !longline) < 0) 1929b50d902SRodney W. Grimes goto err; 1939b50d902SRodney W. Grimes else 1949b50d902SRodney W. Grimes break; 1959b50d902SRodney W. Grimes } 1969b50d902SRodney W. Grimes printf("Unknown tilde escape.\n"); 1979b50d902SRodney W. Grimes break; 1989b50d902SRodney W. Grimes case 'C': 1999b50d902SRodney W. Grimes /* 2009b50d902SRodney W. Grimes * Dump core. 2019b50d902SRodney W. Grimes */ 202*d28a9551SJohn Baldwin core(NULL); 2039b50d902SRodney W. Grimes break; 2049b50d902SRodney W. Grimes case '!': 2059b50d902SRodney W. Grimes /* 2069b50d902SRodney W. Grimes * Shell escape, send the balance of the 2079b50d902SRodney W. Grimes * line to sh -c. 2089b50d902SRodney W. Grimes */ 2099b50d902SRodney W. Grimes shell(&linebuf[2]); 2109b50d902SRodney W. Grimes break; 2119b50d902SRodney W. Grimes case ':': 21269131e40SMike Heffner case '_': 2139b50d902SRodney W. Grimes /* 2149b50d902SRodney W. Grimes * Escape to command mode, but be nice! 2159b50d902SRodney W. Grimes */ 2169b50d902SRodney W. Grimes execute(&linebuf[2], 1); 2179b50d902SRodney W. Grimes goto cont; 2189b50d902SRodney W. Grimes case '.': 2199b50d902SRodney W. Grimes /* 2209b50d902SRodney W. Grimes * Simulate end of file on input. 2219b50d902SRodney W. Grimes */ 2229b50d902SRodney W. Grimes goto out; 2239b50d902SRodney W. Grimes case 'q': 2249b50d902SRodney W. Grimes /* 2259b50d902SRodney W. Grimes * Force a quit of sending mail. 2269b50d902SRodney W. Grimes * Act like an interrupt happened. 2279b50d902SRodney W. Grimes */ 2289b50d902SRodney W. Grimes hadintr++; 2299b50d902SRodney W. Grimes collint(SIGINT); 2309b50d902SRodney W. Grimes exit(1); 23169131e40SMike Heffner case 'x': 23269131e40SMike Heffner /* 23369131e40SMike Heffner * Exit, do not save in dead.letter. 23469131e40SMike Heffner */ 23569131e40SMike Heffner goto err; 2369b50d902SRodney W. Grimes case 'h': 2379b50d902SRodney W. Grimes /* 2389b50d902SRodney W. Grimes * Grab a bunch of headers. 2399b50d902SRodney W. Grimes */ 2409b50d902SRodney W. Grimes grabh(hp, GTO|GSUBJECT|GCC|GBCC); 2419b50d902SRodney W. Grimes goto cont; 2429b50d902SRodney W. Grimes case 't': 2439b50d902SRodney W. Grimes /* 2449b50d902SRodney W. Grimes * Add to the To list. 2459b50d902SRodney W. Grimes */ 2469b50d902SRodney W. Grimes hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); 2479b50d902SRodney W. Grimes break; 2489b50d902SRodney W. Grimes case 's': 2499b50d902SRodney W. Grimes /* 25099bd6601SJoerg Wunsch * Set the Subject line. 2519b50d902SRodney W. Grimes */ 2529b50d902SRodney W. Grimes cp = &linebuf[2]; 2536d48fa43SAndrey A. Chernov while (isspace((unsigned char)*cp)) 2549b50d902SRodney W. Grimes cp++; 2559b50d902SRodney W. Grimes hp->h_subject = savestr(cp); 2569b50d902SRodney W. Grimes break; 25799bd6601SJoerg Wunsch case 'R': 25899bd6601SJoerg Wunsch /* 25999bd6601SJoerg Wunsch * Set the Reply-To line. 26099bd6601SJoerg Wunsch */ 26199bd6601SJoerg Wunsch cp = &linebuf[2]; 2626d48fa43SAndrey A. Chernov while (isspace((unsigned char)*cp)) 26399bd6601SJoerg Wunsch cp++; 26499bd6601SJoerg Wunsch hp->h_replyto = savestr(cp); 26599bd6601SJoerg Wunsch break; 2669b50d902SRodney W. Grimes case 'c': 2679b50d902SRodney W. Grimes /* 2689b50d902SRodney W. Grimes * Add to the CC list. 2699b50d902SRodney W. Grimes */ 2709b50d902SRodney W. Grimes hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); 2719b50d902SRodney W. Grimes break; 2729b50d902SRodney W. Grimes case 'b': 2739b50d902SRodney W. Grimes /* 27469131e40SMike Heffner * Add to the BCC list. 2759b50d902SRodney W. Grimes */ 2769b50d902SRodney W. Grimes hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); 2779b50d902SRodney W. Grimes break; 27869131e40SMike Heffner case 'i': 27969131e40SMike Heffner case 'A': 28069131e40SMike Heffner case 'a': 28169131e40SMike Heffner /* 2829b12c3f3SMike Heffner * Insert named variable in message. 28369131e40SMike Heffner */ 28469131e40SMike Heffner switch(c) { 28569131e40SMike Heffner case 'i': 28669131e40SMike Heffner cp = &linebuf[2]; 28769131e40SMike Heffner while(isspace((unsigned char)*cp)) 28869131e40SMike Heffner cp++; 28969131e40SMike Heffner break; 29069131e40SMike Heffner case 'a': 29169131e40SMike Heffner cp = "sign"; 29269131e40SMike Heffner break; 29369131e40SMike Heffner case 'A': 29469131e40SMike Heffner cp = "Sign"; 29569131e40SMike Heffner break; 29669131e40SMike Heffner default: 29769131e40SMike Heffner goto err; 29869131e40SMike Heffner } 29969131e40SMike Heffner 30069131e40SMike Heffner if(*cp != '\0' && (cp = value(cp)) != NULL) { 30169131e40SMike Heffner printf("%s\n", cp); 30269131e40SMike Heffner if(putline(collf, cp, 1) < 0) 30369131e40SMike Heffner goto err; 30469131e40SMike Heffner } 30569131e40SMike Heffner 30669131e40SMike Heffner break; 3079b50d902SRodney W. Grimes case 'd': 30869131e40SMike Heffner /* 30969131e40SMike Heffner * Read in the dead letter file. 31069131e40SMike Heffner */ 31169131e40SMike Heffner if (strlcpy(linebuf + 2, getdeadletter(), 31269131e40SMike Heffner sizeof(linebuf) - 2) 3130c3a8314SMike Heffner >= sizeof(linebuf) - 2) { 3140c3a8314SMike Heffner printf("Line buffer overflow\n"); 3150c3a8314SMike Heffner break; 3160c3a8314SMike Heffner } 31769131e40SMike Heffner /* FALLTHROUGH */ 3189b50d902SRodney W. Grimes case 'r': 31969131e40SMike Heffner case '<': 3209b50d902SRodney W. Grimes /* 3219b50d902SRodney W. Grimes * Invoke a file: 3229b50d902SRodney W. Grimes * Search for the file name, 3239b50d902SRodney W. Grimes * then open it and copy the contents to collf. 3249b50d902SRodney W. Grimes */ 3259b50d902SRodney W. Grimes cp = &linebuf[2]; 3266d48fa43SAndrey A. Chernov while (isspace((unsigned char)*cp)) 3279b50d902SRodney W. Grimes cp++; 3289b50d902SRodney W. Grimes if (*cp == '\0') { 3299b50d902SRodney W. Grimes printf("Interpolate what file?\n"); 3309b50d902SRodney W. Grimes break; 3319b50d902SRodney W. Grimes } 3329b50d902SRodney W. Grimes cp = expand(cp); 3339ce73e90SMike Heffner if (cp == NULL) 3349b50d902SRodney W. Grimes break; 33569131e40SMike Heffner if (*cp == '!') { 33669131e40SMike Heffner /* 33769131e40SMike Heffner * Insert stdout of command. 33869131e40SMike Heffner */ 33969131e40SMike Heffner char *sh; 34069131e40SMike Heffner int nullfd, tempfd, rc; 34169131e40SMike Heffner char tempname2[PATHSIZE]; 34269131e40SMike Heffner 34356858424SXin LI if ((nullfd = open(_PATH_DEVNULL, O_RDONLY, 0)) 34469131e40SMike Heffner == -1) { 34556858424SXin LI warn(_PATH_DEVNULL); 3469b50d902SRodney W. Grimes break; 3479b50d902SRodney W. Grimes } 34869131e40SMike Heffner 34969131e40SMike Heffner (void)snprintf(tempname2, sizeof(tempname2), 35069131e40SMike Heffner "%s/mail.ReXXXXXXXXXX", tmpdir); 35169131e40SMike Heffner if ((tempfd = mkstemp(tempname2)) == -1 || 35269131e40SMike Heffner (fbuf = Fdopen(tempfd, "w+")) == NULL) { 35369131e40SMike Heffner warn("%s", tempname2); 35469131e40SMike Heffner break; 35569131e40SMike Heffner } 35669131e40SMike Heffner (void)unlink(tempname2); 35769131e40SMike Heffner 35869131e40SMike Heffner if ((sh = value("SHELL")) == NULL) 35969131e40SMike Heffner sh = _PATH_CSHELL; 36069131e40SMike Heffner 36169131e40SMike Heffner rc = run_command(sh, 0, nullfd, fileno(fbuf), 36269131e40SMike Heffner "-c", cp+1, NULL); 36369131e40SMike Heffner 36469131e40SMike Heffner close(nullfd); 36569131e40SMike Heffner 36669131e40SMike Heffner if (rc < 0) { 36769131e40SMike Heffner (void)Fclose(fbuf); 36869131e40SMike Heffner break; 36969131e40SMike Heffner } 37069131e40SMike Heffner 37169131e40SMike Heffner if (fsize(fbuf) == 0) { 37269131e40SMike Heffner fprintf(stderr, 37369131e40SMike Heffner "No bytes from command \"%s\"\n", 37469131e40SMike Heffner cp+1); 37569131e40SMike Heffner (void)Fclose(fbuf); 37669131e40SMike Heffner break; 37769131e40SMike Heffner } 37869131e40SMike Heffner 37969131e40SMike Heffner rewind(fbuf); 38069131e40SMike Heffner } else if (isdir(cp)) { 38169131e40SMike Heffner printf("%s: Directory\n", cp); 38269131e40SMike Heffner break; 38369131e40SMike Heffner } else if ((fbuf = Fopen(cp, "r")) == NULL) { 3840c3a8314SMike Heffner warn("%s", cp); 3859b50d902SRodney W. Grimes break; 3869b50d902SRodney W. Grimes } 3879b50d902SRodney W. Grimes printf("\"%s\" ", cp); 3889ce73e90SMike Heffner (void)fflush(stdout); 3899b50d902SRodney W. Grimes lc = 0; 3909b50d902SRodney W. Grimes cc = 0; 391856f23edSMike Heffner while ((rc = readline(fbuf, linebuf, LINESIZE)) >= 0) { 392856f23edSMike Heffner if (rc != LINESIZE - 1) 3939b50d902SRodney W. Grimes lc++; 394856f23edSMike Heffner if ((t = putline(collf, linebuf, 395856f23edSMike Heffner rc != LINESIZE - 1)) < 0) { 3969ce73e90SMike Heffner (void)Fclose(fbuf); 3979b50d902SRodney W. Grimes goto err; 3989b50d902SRodney W. Grimes } 3999b50d902SRodney W. Grimes cc += t; 4009b50d902SRodney W. Grimes } 4019ce73e90SMike Heffner (void)Fclose(fbuf); 4029b50d902SRodney W. Grimes printf("%d/%d\n", lc, cc); 4039b50d902SRodney W. Grimes break; 4049b50d902SRodney W. Grimes case 'w': 4059b50d902SRodney W. Grimes /* 4069b50d902SRodney W. Grimes * Write the message on a file. 4079b50d902SRodney W. Grimes */ 4089b50d902SRodney W. Grimes cp = &linebuf[2]; 4099b50d902SRodney W. Grimes while (*cp == ' ' || *cp == '\t') 4109b50d902SRodney W. Grimes cp++; 4119b50d902SRodney W. Grimes if (*cp == '\0') { 4129b50d902SRodney W. Grimes fprintf(stderr, "Write what file!?\n"); 4139b50d902SRodney W. Grimes break; 4149b50d902SRodney W. Grimes } 4159ce73e90SMike Heffner if ((cp = expand(cp)) == NULL) 4169b50d902SRodney W. Grimes break; 4179b50d902SRodney W. Grimes rewind(collf); 4189b50d902SRodney W. Grimes exwrite(cp, collf, 1); 4199b50d902SRodney W. Grimes break; 4209b50d902SRodney W. Grimes case 'm': 4219b50d902SRodney W. Grimes case 'M': 4229b50d902SRodney W. Grimes case 'f': 4239b50d902SRodney W. Grimes case 'F': 4249b50d902SRodney W. Grimes /* 4259b50d902SRodney W. Grimes * Interpolate the named messages, if we 4269b50d902SRodney W. Grimes * are in receiving mail mode. Does the 4279b50d902SRodney W. Grimes * standard list processing garbage. 4289b50d902SRodney W. Grimes * If ~f is given, we don't shift over. 4299b50d902SRodney W. Grimes */ 4300c3a8314SMike Heffner if (forward(linebuf + 2, collf, tempname, c) < 0) 4319b50d902SRodney W. Grimes goto err; 4329b50d902SRodney W. Grimes goto cont; 4339b50d902SRodney W. Grimes case '?': 4349b50d902SRodney W. Grimes if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { 4350c3a8314SMike Heffner warn("%s", _PATH_TILDE); 4369b50d902SRodney W. Grimes break; 4379b50d902SRodney W. Grimes } 4389b50d902SRodney W. Grimes while ((t = getc(fbuf)) != EOF) 4399b50d902SRodney W. Grimes (void)putchar(t); 4409ce73e90SMike Heffner (void)Fclose(fbuf); 4419b50d902SRodney W. Grimes break; 4429b50d902SRodney W. Grimes case 'p': 4439b50d902SRodney W. Grimes /* 4449b50d902SRodney W. Grimes * Print out the current state of the 4459b50d902SRodney W. Grimes * message without altering anything. 4469b50d902SRodney W. Grimes */ 4479b50d902SRodney W. Grimes rewind(collf); 4489b50d902SRodney W. Grimes printf("-------\nMessage contains:\n"); 4499b50d902SRodney W. Grimes puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); 4509b50d902SRodney W. Grimes while ((t = getc(collf)) != EOF) 4519b50d902SRodney W. Grimes (void)putchar(t); 4529b50d902SRodney W. Grimes goto cont; 4539b50d902SRodney W. Grimes case '|': 4549b50d902SRodney W. Grimes /* 4559b50d902SRodney W. Grimes * Pipe message through command. 4569b50d902SRodney W. Grimes * Collect output as new message. 4579b50d902SRodney W. Grimes */ 4589b50d902SRodney W. Grimes rewind(collf); 4599b50d902SRodney W. Grimes mespipe(collf, &linebuf[2]); 4609b50d902SRodney W. Grimes goto cont; 4619b50d902SRodney W. Grimes case 'v': 4629b50d902SRodney W. Grimes case 'e': 4639b50d902SRodney W. Grimes /* 4649b50d902SRodney W. Grimes * Edit the current message. 4659b50d902SRodney W. Grimes * 'e' means to use EDITOR 4669b50d902SRodney W. Grimes * 'v' means to use VISUAL 4679b50d902SRodney W. Grimes */ 4689b50d902SRodney W. Grimes rewind(collf); 4699b50d902SRodney W. Grimes mesedit(collf, c); 4709b50d902SRodney W. Grimes goto cont; 4719b50d902SRodney W. Grimes } 4729b50d902SRodney W. Grimes } 4739b50d902SRodney W. Grimes goto out; 4749b50d902SRodney W. Grimes err: 4759b50d902SRodney W. Grimes if (collf != NULL) { 4769ce73e90SMike Heffner (void)Fclose(collf); 4779b50d902SRodney W. Grimes collf = NULL; 4789b50d902SRodney W. Grimes } 4799b50d902SRodney W. Grimes out: 4809b50d902SRodney W. Grimes if (collf != NULL) 4819b50d902SRodney W. Grimes rewind(collf); 4829b50d902SRodney W. Grimes noreset--; 483856f23edSMike Heffner (void)sigprocmask(SIG_BLOCK, &nset, NULL); 4849ce73e90SMike Heffner (void)signal(SIGINT, saveint); 4859ce73e90SMike Heffner (void)signal(SIGHUP, savehup); 4869ce73e90SMike Heffner (void)signal(SIGTSTP, savetstp); 4879ce73e90SMike Heffner (void)signal(SIGTTOU, savettou); 4889ce73e90SMike Heffner (void)signal(SIGTTIN, savettin); 489856f23edSMike Heffner (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 4909ce73e90SMike Heffner return (collf); 4919b50d902SRodney W. Grimes } 4929b50d902SRodney W. Grimes 4939b50d902SRodney W. Grimes /* 4949b50d902SRodney W. Grimes * Write a file, ex-like if f set. 4959b50d902SRodney W. Grimes */ 4969b50d902SRodney W. Grimes int 4976d8484b0SPhilippe Charnier exwrite(char name[], FILE *fp, int f) 4989b50d902SRodney W. Grimes { 4999ce73e90SMike Heffner FILE *of; 5009ce73e90SMike Heffner int c, lc; 5019b50d902SRodney W. Grimes long cc; 5029b50d902SRodney W. Grimes struct stat junk; 5039b50d902SRodney W. Grimes 5049b50d902SRodney W. Grimes if (f) { 5059b50d902SRodney W. Grimes printf("\"%s\" ", name); 5069ce73e90SMike Heffner (void)fflush(stdout); 5079b50d902SRodney W. Grimes } 5080c3a8314SMike Heffner if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) { 5099b50d902SRodney W. Grimes if (!f) 5109b50d902SRodney W. Grimes fprintf(stderr, "%s: ", name); 5119b50d902SRodney W. Grimes fprintf(stderr, "File exists\n"); 5129b50d902SRodney W. Grimes return (-1); 5139b50d902SRodney W. Grimes } 5149b50d902SRodney W. Grimes if ((of = Fopen(name, "w")) == NULL) { 5159ce73e90SMike Heffner warn((char *)NULL); 5169b50d902SRodney W. Grimes return (-1); 5179b50d902SRodney W. Grimes } 5189b50d902SRodney W. Grimes lc = 0; 5199b50d902SRodney W. Grimes cc = 0; 5209b50d902SRodney W. Grimes while ((c = getc(fp)) != EOF) { 5219b50d902SRodney W. Grimes cc++; 5229b50d902SRodney W. Grimes if (c == '\n') 5239b50d902SRodney W. Grimes lc++; 5249b50d902SRodney W. Grimes (void)putc(c, of); 5259b50d902SRodney W. Grimes if (ferror(of)) { 5260c3a8314SMike Heffner warnx("%s", name); 5279ce73e90SMike Heffner (void)Fclose(of); 5289b50d902SRodney W. Grimes return (-1); 5299b50d902SRodney W. Grimes } 5309b50d902SRodney W. Grimes } 5319ce73e90SMike Heffner (void)Fclose(of); 5329b50d902SRodney W. Grimes printf("%d/%ld\n", lc, cc); 5339ce73e90SMike Heffner (void)fflush(stdout); 5349b50d902SRodney W. Grimes return (0); 5359b50d902SRodney W. Grimes } 5369b50d902SRodney W. Grimes 5379b50d902SRodney W. Grimes /* 5389b50d902SRodney W. Grimes * Edit the message being collected on fp. 5399b50d902SRodney W. Grimes * On return, make the edit file the new temp file. 5409b50d902SRodney W. Grimes */ 5419b50d902SRodney W. Grimes void 5426d8484b0SPhilippe Charnier mesedit(FILE *fp, int c) 5439b50d902SRodney W. Grimes { 5449b50d902SRodney W. Grimes sig_t sigint = signal(SIGINT, SIG_IGN); 5459b50d902SRodney W. Grimes FILE *nf = run_editor(fp, (off_t)-1, c, 0); 5469b50d902SRodney W. Grimes 5479b50d902SRodney W. Grimes if (nf != NULL) { 548af8c3262SAndrey A. Chernov (void)fseeko(nf, (off_t)0, SEEK_END); 5499b50d902SRodney W. Grimes collf = nf; 5509ce73e90SMike Heffner (void)Fclose(fp); 5519b50d902SRodney W. Grimes } 5529b50d902SRodney W. Grimes (void)signal(SIGINT, sigint); 5539b50d902SRodney W. Grimes } 5549b50d902SRodney W. Grimes 5559b50d902SRodney W. Grimes /* 5569b50d902SRodney W. Grimes * Pipe the message through the command. 5579b50d902SRodney W. Grimes * Old message is on stdin of command; 5589b50d902SRodney W. Grimes * New message collected from stdout. 5599b50d902SRodney W. Grimes * Sh -c must return 0 to accept the new message. 5609b50d902SRodney W. Grimes */ 5619b50d902SRodney W. Grimes void 5626d8484b0SPhilippe Charnier mespipe(FILE *fp, char cmd[]) 5639b50d902SRodney W. Grimes { 5649b50d902SRodney W. Grimes FILE *nf; 5650c3a8314SMike Heffner int fd; 5669b50d902SRodney W. Grimes sig_t sigint = signal(SIGINT, SIG_IGN); 5679ce73e90SMike Heffner char *sh, tempname[PATHSIZE]; 5689b50d902SRodney W. Grimes 5699ce73e90SMike Heffner (void)snprintf(tempname, sizeof(tempname), 5709ce73e90SMike Heffner "%s/mail.ReXXXXXXXXXX", tmpdir); 5710c3a8314SMike Heffner if ((fd = mkstemp(tempname)) == -1 || 5720c3a8314SMike Heffner (nf = Fdopen(fd, "w+")) == NULL) { 5730c3a8314SMike Heffner warn("%s", tempname); 5749b50d902SRodney W. Grimes goto out; 5759b50d902SRodney W. Grimes } 5760c3a8314SMike Heffner (void)rm(tempname); 5779b50d902SRodney W. Grimes /* 5789b50d902SRodney W. Grimes * stdin = current message. 5799b50d902SRodney W. Grimes * stdout = new message. 5809b50d902SRodney W. Grimes */ 5819ce73e90SMike Heffner if ((sh = value("SHELL")) == NULL) 5829ce73e90SMike Heffner sh = _PATH_CSHELL; 5839ce73e90SMike Heffner if (run_command(sh, 5849ce73e90SMike Heffner 0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) { 5859b50d902SRodney W. Grimes (void)Fclose(nf); 5869b50d902SRodney W. Grimes goto out; 5879b50d902SRodney W. Grimes } 5889b50d902SRodney W. Grimes if (fsize(nf) == 0) { 5899b50d902SRodney W. Grimes fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); 5909b50d902SRodney W. Grimes (void)Fclose(nf); 5919b50d902SRodney W. Grimes goto out; 5929b50d902SRodney W. Grimes } 5939b50d902SRodney W. Grimes /* 5949b50d902SRodney W. Grimes * Take new files. 5959b50d902SRodney W. Grimes */ 596af8c3262SAndrey A. Chernov (void)fseeko(nf, (off_t)0, SEEK_END); 5979b50d902SRodney W. Grimes collf = nf; 5989b50d902SRodney W. Grimes (void)Fclose(fp); 5999b50d902SRodney W. Grimes out: 6009b50d902SRodney W. Grimes (void)signal(SIGINT, sigint); 6019b50d902SRodney W. Grimes } 6029b50d902SRodney W. Grimes 6039b50d902SRodney W. Grimes /* 6049b50d902SRodney W. Grimes * Interpolate the named messages into the current 6059b50d902SRodney W. Grimes * message, preceding each line with a tab. 6069b50d902SRodney W. Grimes * Return a count of the number of characters now in 6079b50d902SRodney W. Grimes * the message, or -1 if an error is encountered writing 6089b50d902SRodney W. Grimes * the message temporary. The flag argument is 'm' if we 6099b50d902SRodney W. Grimes * should shift over and 'f' if not. 6109b50d902SRodney W. Grimes */ 6119b50d902SRodney W. Grimes int 6126d8484b0SPhilippe Charnier forward(char ms[], FILE *fp, char *fn, int f) 6139b50d902SRodney W. Grimes { 6149ce73e90SMike Heffner int *msgvec; 6159b50d902SRodney W. Grimes struct ignoretab *ig; 6169b50d902SRodney W. Grimes char *tabst; 6179b50d902SRodney W. Grimes 6189ce73e90SMike Heffner msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec)); 6199ce73e90SMike Heffner if (msgvec == NULL) 6209b50d902SRodney W. Grimes return (0); 6219b50d902SRodney W. Grimes if (getmsglist(ms, msgvec, 0) < 0) 6229b50d902SRodney W. Grimes return (0); 6239b50d902SRodney W. Grimes if (*msgvec == 0) { 6249b50d902SRodney W. Grimes *msgvec = first(0, MMNORM); 625d030d2d2SPoul-Henning Kamp if (*msgvec == 0) { 6269b50d902SRodney W. Grimes printf("No appropriate messages\n"); 6279b50d902SRodney W. Grimes return (0); 6289b50d902SRodney W. Grimes } 629d030d2d2SPoul-Henning Kamp msgvec[1] = 0; 6309b50d902SRodney W. Grimes } 6319b50d902SRodney W. Grimes if (f == 'f' || f == 'F') 6329ce73e90SMike Heffner tabst = NULL; 6339ce73e90SMike Heffner else if ((tabst = value("indentprefix")) == NULL) 6349b50d902SRodney W. Grimes tabst = "\t"; 6356d48fa43SAndrey A. Chernov ig = isupper((unsigned char)f) ? NULL : ignore; 6369b50d902SRodney W. Grimes printf("Interpolating:"); 6379b50d902SRodney W. Grimes for (; *msgvec != 0; msgvec++) { 6389b50d902SRodney W. Grimes struct message *mp = message + *msgvec - 1; 6399b50d902SRodney W. Grimes 6409b50d902SRodney W. Grimes touch(mp); 6419b50d902SRodney W. Grimes printf(" %d", *msgvec); 6420c3a8314SMike Heffner if (sendmessage(mp, fp, ig, tabst) < 0) { 6430c3a8314SMike Heffner warnx("%s", fn); 6449b50d902SRodney W. Grimes return (-1); 6459b50d902SRodney W. Grimes } 6469b50d902SRodney W. Grimes } 6479b50d902SRodney W. Grimes printf("\n"); 6489b50d902SRodney W. Grimes return (0); 6499b50d902SRodney W. Grimes } 6509b50d902SRodney W. Grimes 6519b50d902SRodney W. Grimes /* 6529b50d902SRodney W. Grimes * Print (continue) when continued after ^Z. 6539b50d902SRodney W. Grimes */ 6549b50d902SRodney W. Grimes /*ARGSUSED*/ 6559b50d902SRodney W. Grimes void 6566d8484b0SPhilippe Charnier collstop(int s) 6579b50d902SRodney W. Grimes { 6589b50d902SRodney W. Grimes sig_t old_action = signal(s, SIG_DFL); 659856f23edSMike Heffner sigset_t nset; 6609b50d902SRodney W. Grimes 661856f23edSMike Heffner (void)sigemptyset(&nset); 662856f23edSMike Heffner (void)sigaddset(&nset, s); 663856f23edSMike Heffner (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 6649ce73e90SMike Heffner (void)kill(0, s); 665856f23edSMike Heffner (void)sigprocmask(SIG_BLOCK, &nset, NULL); 6669ce73e90SMike Heffner (void)signal(s, old_action); 6679b50d902SRodney W. Grimes if (colljmp_p) { 6689b50d902SRodney W. Grimes colljmp_p = 0; 6699b50d902SRodney W. Grimes hadintr = 0; 6709b50d902SRodney W. Grimes longjmp(colljmp, 1); 6719b50d902SRodney W. Grimes } 6729b50d902SRodney W. Grimes } 6739b50d902SRodney W. Grimes 6749b50d902SRodney W. Grimes /* 6759b50d902SRodney W. Grimes * On interrupt, come here to save the partial message in ~/dead.letter. 6769b50d902SRodney W. Grimes * Then jump out of the collection loop. 6779b50d902SRodney W. Grimes */ 6789b50d902SRodney W. Grimes /*ARGSUSED*/ 6799b50d902SRodney W. Grimes void 6806d8484b0SPhilippe Charnier collint(int s __unused) 6819b50d902SRodney W. Grimes { 6829b50d902SRodney W. Grimes /* 6839b50d902SRodney W. Grimes * the control flow is subtle, because we can be called from ~q. 6849b50d902SRodney W. Grimes */ 6859b50d902SRodney W. Grimes if (!hadintr) { 6869ce73e90SMike Heffner if (value("ignore") != NULL) { 6879ce73e90SMike Heffner printf("@"); 6889ce73e90SMike Heffner (void)fflush(stdout); 6899b50d902SRodney W. Grimes clearerr(stdin); 6909b50d902SRodney W. Grimes return; 6919b50d902SRodney W. Grimes } 6929b50d902SRodney W. Grimes hadintr = 1; 6939b50d902SRodney W. Grimes longjmp(colljmp, 1); 6949b50d902SRodney W. Grimes } 6959b50d902SRodney W. Grimes rewind(collf); 6969ce73e90SMike Heffner if (value("nosave") == NULL) 6979b50d902SRodney W. Grimes savedeadletter(collf); 6989b50d902SRodney W. Grimes longjmp(collabort, 1); 6999b50d902SRodney W. Grimes } 7009b50d902SRodney W. Grimes 7019b50d902SRodney W. Grimes /*ARGSUSED*/ 7029b50d902SRodney W. Grimes void 7036d8484b0SPhilippe Charnier collhup(int s __unused) 7049b50d902SRodney W. Grimes { 7059b50d902SRodney W. Grimes rewind(collf); 7069b50d902SRodney W. Grimes savedeadletter(collf); 7079b50d902SRodney W. Grimes /* 7089b50d902SRodney W. Grimes * Let's pretend nobody else wants to clean up, 7099b50d902SRodney W. Grimes * a true statement at this time. 7109b50d902SRodney W. Grimes */ 7119b50d902SRodney W. Grimes exit(1); 7129b50d902SRodney W. Grimes } 7139b50d902SRodney W. Grimes 7149b50d902SRodney W. Grimes void 7156d8484b0SPhilippe Charnier savedeadletter(FILE *fp) 7169b50d902SRodney W. Grimes { 7179ce73e90SMike Heffner FILE *dbuf; 7189ce73e90SMike Heffner int c; 7199b50d902SRodney W. Grimes char *cp; 7209b50d902SRodney W. Grimes 7219b50d902SRodney W. Grimes if (fsize(fp) == 0) 7229b50d902SRodney W. Grimes return; 7239b50d902SRodney W. Grimes cp = getdeadletter(); 7249b50d902SRodney W. Grimes c = umask(077); 7259b50d902SRodney W. Grimes dbuf = Fopen(cp, "a"); 7269b50d902SRodney W. Grimes (void)umask(c); 7279b50d902SRodney W. Grimes if (dbuf == NULL) 7289b50d902SRodney W. Grimes return; 7299b50d902SRodney W. Grimes while ((c = getc(fp)) != EOF) 7309b50d902SRodney W. Grimes (void)putc(c, dbuf); 7319ce73e90SMike Heffner (void)Fclose(dbuf); 7329b50d902SRodney W. Grimes rewind(fp); 7339b50d902SRodney W. Grimes } 734