19b50d902SRodney W. Grimes /* 29b50d902SRodney W. Grimes * Copyright (c) 1980, 1993 39b50d902SRodney W. Grimes * The Regents of the University of California. All rights reserved. 49b50d902SRodney W. Grimes * 59b50d902SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 69b50d902SRodney W. Grimes * modification, are permitted provided that the following conditions 79b50d902SRodney W. Grimes * are met: 89b50d902SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 99b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 109b50d902SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 119b50d902SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 129b50d902SRodney W. Grimes * documentation and/or other materials provided with the distribution. 139b50d902SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 149b50d902SRodney W. Grimes * must display the following acknowledgement: 159b50d902SRodney W. Grimes * This product includes software developed by the University of 169b50d902SRodney W. Grimes * California, Berkeley and its contributors. 179b50d902SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 189b50d902SRodney W. Grimes * may be used to endorse or promote products derived from this software 199b50d902SRodney W. Grimes * without specific prior written permission. 209b50d902SRodney W. Grimes * 219b50d902SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 229b50d902SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 239b50d902SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 249b50d902SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 259b50d902SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 269b50d902SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 279b50d902SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 289b50d902SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 299b50d902SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 309b50d902SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 319b50d902SRodney W. Grimes * SUCH DAMAGE. 329b50d902SRodney W. Grimes */ 339b50d902SRodney W. Grimes 349b50d902SRodney W. Grimes #ifndef lint 350c3a8314SMike Heffner #if 0 369b50d902SRodney W. Grimes static char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94"; 370c3a8314SMike Heffner #endif 380c3a8314SMike Heffner static const char rcsid[] = 390c3a8314SMike Heffner "$FreeBSD$"; 409b50d902SRodney W. Grimes #endif /* not lint */ 419b50d902SRodney W. Grimes 429b50d902SRodney W. Grimes /* 439b50d902SRodney W. Grimes * Mail -- a mail program 449b50d902SRodney W. Grimes * 459b50d902SRodney W. Grimes * Collect input from standard input, handling 469b50d902SRodney W. Grimes * ~ escapes. 479b50d902SRodney W. Grimes */ 489b50d902SRodney W. Grimes 499b50d902SRodney W. Grimes #include "rcv.h" 5069131e40SMike Heffner #include <fcntl.h> 519b50d902SRodney W. Grimes #include "extern.h" 529b50d902SRodney W. Grimes 539b50d902SRodney W. Grimes /* 549b50d902SRodney W. Grimes * Read a message from standard output and return a read file to it 559b50d902SRodney W. Grimes * or NULL on error. 569b50d902SRodney W. Grimes */ 579b50d902SRodney W. Grimes 589b50d902SRodney W. Grimes /* 599b50d902SRodney W. Grimes * The following hokiness with global variables is so that on 609b50d902SRodney W. Grimes * receipt of an interrupt signal, the partial message can be salted 619b50d902SRodney W. Grimes * away on dead.letter. 629b50d902SRodney W. Grimes */ 639b50d902SRodney W. Grimes 649b50d902SRodney W. Grimes static sig_t saveint; /* Previous SIGINT value */ 659b50d902SRodney W. Grimes static sig_t savehup; /* Previous SIGHUP value */ 669b50d902SRodney W. Grimes static sig_t savetstp; /* Previous SIGTSTP value */ 679b50d902SRodney W. Grimes static sig_t savettou; /* Previous SIGTTOU value */ 689b50d902SRodney W. Grimes static sig_t savettin; /* Previous SIGTTIN value */ 699b50d902SRodney W. Grimes static FILE *collf; /* File for saving away */ 709b50d902SRodney W. Grimes static int hadintr; /* Have seen one SIGINT so far */ 719b50d902SRodney W. Grimes 729b50d902SRodney W. Grimes static jmp_buf colljmp; /* To get back to work */ 739b50d902SRodney W. Grimes static int colljmp_p; /* whether to long jump */ 749b50d902SRodney W. Grimes static jmp_buf collabort; /* To end collection with error */ 759b50d902SRodney W. Grimes 769b50d902SRodney W. Grimes FILE * 779b50d902SRodney W. Grimes collect(hp, printheaders) 789b50d902SRodney W. Grimes struct header *hp; 799b50d902SRodney W. Grimes int printheaders; 809b50d902SRodney W. Grimes { 819b50d902SRodney W. Grimes FILE *fbuf; 829ce73e90SMike Heffner int lc, cc, escape, eofcount, fd, c, t; 839ce73e90SMike Heffner char linebuf[LINESIZE], tempname[PATHSIZE], *cp, getsub; 84856f23edSMike Heffner sigset_t nset; 85856f23edSMike Heffner int longline, lastlong, rc; /* So we don't make 2 or more lines 86856f23edSMike Heffner out of a long input line. */ 879b50d902SRodney W. Grimes 889b50d902SRodney W. Grimes collf = NULL; 899b50d902SRodney W. Grimes /* 909b50d902SRodney W. Grimes * Start catching signals from here, but we're still die on interrupts 919b50d902SRodney W. Grimes * until we're in the main loop. 929b50d902SRodney W. Grimes */ 93856f23edSMike Heffner (void)sigemptyset(&nset); 94856f23edSMike Heffner (void)sigaddset(&nset, SIGINT); 95856f23edSMike Heffner (void)sigaddset(&nset, SIGHUP); 96856f23edSMike Heffner (void)sigprocmask(SIG_BLOCK, &nset, NULL); 979b50d902SRodney W. Grimes if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) 989ce73e90SMike Heffner (void)signal(SIGINT, collint); 999b50d902SRodney W. Grimes if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) 1009ce73e90SMike Heffner (void)signal(SIGHUP, collhup); 1019b50d902SRodney W. Grimes savetstp = signal(SIGTSTP, collstop); 1029b50d902SRodney W. Grimes savettou = signal(SIGTTOU, collstop); 1039b50d902SRodney W. Grimes savettin = signal(SIGTTIN, collstop); 1049b50d902SRodney W. Grimes if (setjmp(collabort) || setjmp(colljmp)) { 1059ce73e90SMike Heffner (void)rm(tempname); 1069b50d902SRodney W. Grimes goto err; 1079b50d902SRodney W. Grimes } 108856f23edSMike Heffner (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 1099b50d902SRodney W. Grimes 1109b50d902SRodney W. Grimes noreset++; 1119ce73e90SMike Heffner (void)snprintf(tempname, sizeof(tempname), 1129ce73e90SMike Heffner "%s/mail.RsXXXXXXXXXX", tmpdir); 1130c3a8314SMike Heffner if ((fd = mkstemp(tempname)) == -1 || 1140c3a8314SMike Heffner (collf = Fdopen(fd, "w+")) == NULL) { 1150c3a8314SMike Heffner warn("%s", tempname); 1169b50d902SRodney W. Grimes goto err; 1179b50d902SRodney W. Grimes } 1189ce73e90SMike Heffner (void)rm(tempname); 1199b50d902SRodney W. Grimes 1209b50d902SRodney W. Grimes /* 1219b50d902SRodney W. Grimes * If we are going to prompt for a subject, 1229b50d902SRodney W. Grimes * refrain from printing a newline after 1239b50d902SRodney W. Grimes * the headers (since some people mind). 1249b50d902SRodney W. Grimes */ 1259b50d902SRodney W. Grimes t = GTO|GSUBJECT|GCC|GNL; 1269b50d902SRodney W. Grimes getsub = 0; 1279ce73e90SMike Heffner if (hp->h_subject == NULL && value("interactive") != NULL && 1289ce73e90SMike Heffner (value("ask") != NULL || value("asksub") != NULL)) 1299b50d902SRodney W. Grimes t &= ~GNL, getsub++; 1309b50d902SRodney W. Grimes if (printheaders) { 1319b50d902SRodney W. Grimes puthead(hp, stdout, t); 1329ce73e90SMike Heffner (void)fflush(stdout); 1339b50d902SRodney W. Grimes } 1349ce73e90SMike Heffner if ((cp = value("escape")) != NULL) 1359b50d902SRodney W. Grimes escape = *cp; 1369b50d902SRodney W. Grimes else 1379b50d902SRodney W. Grimes escape = ESCAPE; 1389b50d902SRodney W. Grimes eofcount = 0; 1399b50d902SRodney W. Grimes hadintr = 0; 140856f23edSMike Heffner lastlong = 0; 141856f23edSMike Heffner longline = 0; 1429b50d902SRodney W. Grimes 1439b50d902SRodney W. Grimes if (!setjmp(colljmp)) { 1449b50d902SRodney W. Grimes if (getsub) 1459b50d902SRodney W. Grimes grabh(hp, GSUBJECT); 1469b50d902SRodney W. Grimes } else { 1479b50d902SRodney W. Grimes /* 1489b50d902SRodney W. Grimes * Come here for printing the after-signal message. 1499b50d902SRodney W. Grimes * Duplicate messages won't be printed because 1509b50d902SRodney W. Grimes * the write is aborted if we get a SIGTTOU. 1519b50d902SRodney W. Grimes */ 1529b50d902SRodney W. Grimes cont: 1539b50d902SRodney W. Grimes if (hadintr) { 1549ce73e90SMike Heffner (void)fflush(stdout); 1559b50d902SRodney W. Grimes fprintf(stderr, 1569b50d902SRodney W. Grimes "\n(Interrupt -- one more to kill letter)\n"); 1579b50d902SRodney W. Grimes } else { 1589b50d902SRodney W. Grimes printf("(continue)\n"); 1599ce73e90SMike Heffner (void)fflush(stdout); 1609b50d902SRodney W. Grimes } 1619b50d902SRodney W. Grimes } 1629b50d902SRodney W. Grimes for (;;) { 1639b50d902SRodney W. Grimes colljmp_p = 1; 1649b50d902SRodney W. Grimes c = readline(stdin, linebuf, LINESIZE); 1659b50d902SRodney W. Grimes colljmp_p = 0; 1669b50d902SRodney W. Grimes if (c < 0) { 1679ce73e90SMike Heffner if (value("interactive") != NULL && 1689ce73e90SMike Heffner value("ignoreeof") != NULL && ++eofcount < 25) { 1699b50d902SRodney W. Grimes printf("Use \".\" to terminate letter\n"); 1709b50d902SRodney W. Grimes continue; 1719b50d902SRodney W. Grimes } 1729b50d902SRodney W. Grimes break; 1739b50d902SRodney W. Grimes } 174856f23edSMike Heffner lastlong = longline; 175856f23edSMike Heffner longline = c == LINESIZE - 1; 1769b50d902SRodney W. Grimes eofcount = 0; 1779b50d902SRodney W. Grimes hadintr = 0; 1789b50d902SRodney W. Grimes if (linebuf[0] == '.' && linebuf[1] == '\0' && 179856f23edSMike Heffner value("interactive") != NULL && !lastlong && 1809ce73e90SMike Heffner (value("dot") != NULL || value("ignoreeof") != NULL)) 1819b50d902SRodney W. Grimes break; 182856f23edSMike Heffner if (linebuf[0] != escape || value("interactive") == NULL || 183856f23edSMike Heffner lastlong) { 184856f23edSMike Heffner if (putline(collf, linebuf, !longline) < 0) 1859b50d902SRodney W. Grimes goto err; 1869b50d902SRodney W. Grimes continue; 1879b50d902SRodney W. Grimes } 1889b50d902SRodney W. Grimes c = linebuf[1]; 1899b50d902SRodney W. Grimes switch (c) { 1909b50d902SRodney W. Grimes default: 1919b50d902SRodney W. Grimes /* 1929b50d902SRodney W. Grimes * On double escape, just send the single one. 1939b50d902SRodney W. Grimes * Otherwise, it's an error. 1949b50d902SRodney W. Grimes */ 1959b50d902SRodney W. Grimes if (c == escape) { 196856f23edSMike Heffner if (putline(collf, &linebuf[1], !longline) < 0) 1979b50d902SRodney W. Grimes goto err; 1989b50d902SRodney W. Grimes else 1999b50d902SRodney W. Grimes break; 2009b50d902SRodney W. Grimes } 2019b50d902SRodney W. Grimes printf("Unknown tilde escape.\n"); 2029b50d902SRodney W. Grimes break; 2039b50d902SRodney W. Grimes case 'C': 2049b50d902SRodney W. Grimes /* 2059b50d902SRodney W. Grimes * Dump core. 2069b50d902SRodney W. Grimes */ 2079b50d902SRodney W. Grimes core(); 2089b50d902SRodney W. Grimes break; 2099b50d902SRodney W. Grimes case '!': 2109b50d902SRodney W. Grimes /* 2119b50d902SRodney W. Grimes * Shell escape, send the balance of the 2129b50d902SRodney W. Grimes * line to sh -c. 2139b50d902SRodney W. Grimes */ 2149b50d902SRodney W. Grimes shell(&linebuf[2]); 2159b50d902SRodney W. Grimes break; 2169b50d902SRodney W. Grimes case ':': 21769131e40SMike Heffner case '_': 2189b50d902SRodney W. Grimes /* 2199b50d902SRodney W. Grimes * Escape to command mode, but be nice! 2209b50d902SRodney W. Grimes */ 2219b50d902SRodney W. Grimes execute(&linebuf[2], 1); 2229b50d902SRodney W. Grimes goto cont; 2239b50d902SRodney W. Grimes case '.': 2249b50d902SRodney W. Grimes /* 2259b50d902SRodney W. Grimes * Simulate end of file on input. 2269b50d902SRodney W. Grimes */ 2279b50d902SRodney W. Grimes goto out; 2289b50d902SRodney W. Grimes case 'q': 2299b50d902SRodney W. Grimes /* 2309b50d902SRodney W. Grimes * Force a quit of sending mail. 2319b50d902SRodney W. Grimes * Act like an interrupt happened. 2329b50d902SRodney W. Grimes */ 2339b50d902SRodney W. Grimes hadintr++; 2349b50d902SRodney W. Grimes collint(SIGINT); 2359b50d902SRodney W. Grimes exit(1); 23669131e40SMike Heffner case 'x': 23769131e40SMike Heffner /* 23869131e40SMike Heffner * Exit, do not save in dead.letter. 23969131e40SMike Heffner */ 24069131e40SMike Heffner goto err; 2419b50d902SRodney W. Grimes case 'h': 2429b50d902SRodney W. Grimes /* 2439b50d902SRodney W. Grimes * Grab a bunch of headers. 2449b50d902SRodney W. Grimes */ 2459b50d902SRodney W. Grimes grabh(hp, GTO|GSUBJECT|GCC|GBCC); 2469b50d902SRodney W. Grimes goto cont; 2479b50d902SRodney W. Grimes case 't': 2489b50d902SRodney W. Grimes /* 2499b50d902SRodney W. Grimes * Add to the To list. 2509b50d902SRodney W. Grimes */ 2519b50d902SRodney W. Grimes hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); 2529b50d902SRodney W. Grimes break; 2539b50d902SRodney W. Grimes case 's': 2549b50d902SRodney W. Grimes /* 25599bd6601SJoerg Wunsch * Set the Subject line. 2569b50d902SRodney W. Grimes */ 2579b50d902SRodney W. Grimes cp = &linebuf[2]; 2586d48fa43SAndrey A. Chernov while (isspace((unsigned char)*cp)) 2599b50d902SRodney W. Grimes cp++; 2609b50d902SRodney W. Grimes hp->h_subject = savestr(cp); 2619b50d902SRodney W. Grimes break; 26299bd6601SJoerg Wunsch case 'R': 26399bd6601SJoerg Wunsch /* 26499bd6601SJoerg Wunsch * Set the Reply-To line. 26599bd6601SJoerg Wunsch */ 26699bd6601SJoerg Wunsch cp = &linebuf[2]; 2676d48fa43SAndrey A. Chernov while (isspace((unsigned char)*cp)) 26899bd6601SJoerg Wunsch cp++; 26999bd6601SJoerg Wunsch hp->h_replyto = savestr(cp); 27099bd6601SJoerg Wunsch break; 2719b50d902SRodney W. Grimes case 'c': 2729b50d902SRodney W. Grimes /* 2739b50d902SRodney W. Grimes * Add to the CC list. 2749b50d902SRodney W. Grimes */ 2759b50d902SRodney W. Grimes hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); 2769b50d902SRodney W. Grimes break; 2779b50d902SRodney W. Grimes case 'b': 2789b50d902SRodney W. Grimes /* 27969131e40SMike Heffner * Add to the BCC list. 2809b50d902SRodney W. Grimes */ 2819b50d902SRodney W. Grimes hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); 2829b50d902SRodney W. Grimes break; 28369131e40SMike Heffner case 'i': 28469131e40SMike Heffner case 'A': 28569131e40SMike Heffner case 'a': 28669131e40SMike Heffner /* 28769131e40SMike Heffner * Insert named variable in message 28869131e40SMike Heffner */ 28969131e40SMike Heffner switch(c) { 29069131e40SMike Heffner case 'i': 29169131e40SMike Heffner cp = &linebuf[2]; 29269131e40SMike Heffner while(isspace((unsigned char)*cp)) 29369131e40SMike Heffner cp++; 29469131e40SMike Heffner break; 29569131e40SMike Heffner case 'a': 29669131e40SMike Heffner cp = "sign"; 29769131e40SMike Heffner break; 29869131e40SMike Heffner case 'A': 29969131e40SMike Heffner cp = "Sign"; 30069131e40SMike Heffner break; 30169131e40SMike Heffner default: 30269131e40SMike Heffner goto err; 30369131e40SMike Heffner } 30469131e40SMike Heffner 30569131e40SMike Heffner if(*cp != '\0' && (cp = value(cp)) != NULL) { 30669131e40SMike Heffner printf("%s\n", cp); 30769131e40SMike Heffner if(putline(collf, cp, 1) < 0) 30869131e40SMike Heffner goto err; 30969131e40SMike Heffner } 31069131e40SMike Heffner 31169131e40SMike Heffner break; 3129b50d902SRodney W. Grimes case 'd': 31369131e40SMike Heffner /* 31469131e40SMike Heffner * Read in the dead letter file. 31569131e40SMike Heffner */ 31669131e40SMike Heffner if (strlcpy(linebuf + 2, getdeadletter(), 31769131e40SMike Heffner sizeof(linebuf) - 2) 3180c3a8314SMike Heffner >= sizeof(linebuf) - 2) { 3190c3a8314SMike Heffner printf("Line buffer overflow\n"); 3200c3a8314SMike Heffner break; 3210c3a8314SMike Heffner } 32269131e40SMike Heffner /* FALLTHROUGH */ 3239b50d902SRodney W. Grimes case 'r': 32469131e40SMike Heffner case '<': 3259b50d902SRodney W. Grimes /* 3269b50d902SRodney W. Grimes * Invoke a file: 3279b50d902SRodney W. Grimes * Search for the file name, 3289b50d902SRodney W. Grimes * then open it and copy the contents to collf. 3299b50d902SRodney W. Grimes */ 3309b50d902SRodney W. Grimes cp = &linebuf[2]; 3316d48fa43SAndrey A. Chernov while (isspace((unsigned char)*cp)) 3329b50d902SRodney W. Grimes cp++; 3339b50d902SRodney W. Grimes if (*cp == '\0') { 3349b50d902SRodney W. Grimes printf("Interpolate what file?\n"); 3359b50d902SRodney W. Grimes break; 3369b50d902SRodney W. Grimes } 3379b50d902SRodney W. Grimes cp = expand(cp); 3389ce73e90SMike Heffner if (cp == NULL) 3399b50d902SRodney W. Grimes break; 34069131e40SMike Heffner if (*cp == '!') { 34169131e40SMike Heffner /* 34269131e40SMike Heffner * Insert stdout of command. 34369131e40SMike Heffner */ 34469131e40SMike Heffner char *sh; 34569131e40SMike Heffner int nullfd, tempfd, rc; 34669131e40SMike Heffner char tempname2[PATHSIZE]; 34769131e40SMike Heffner 34869131e40SMike Heffner if ((nullfd = open("/dev/null", O_RDONLY, 0)) 34969131e40SMike Heffner == -1) { 35069131e40SMike Heffner warn("/dev/null"); 3519b50d902SRodney W. Grimes break; 3529b50d902SRodney W. Grimes } 35369131e40SMike Heffner 35469131e40SMike Heffner (void)snprintf(tempname2, sizeof(tempname2), 35569131e40SMike Heffner "%s/mail.ReXXXXXXXXXX", tmpdir); 35669131e40SMike Heffner if ((tempfd = mkstemp(tempname2)) == -1 || 35769131e40SMike Heffner (fbuf = Fdopen(tempfd, "w+")) == NULL) { 35869131e40SMike Heffner warn("%s", tempname2); 35969131e40SMike Heffner break; 36069131e40SMike Heffner } 36169131e40SMike Heffner (void)unlink(tempname2); 36269131e40SMike Heffner 36369131e40SMike Heffner if ((sh = value("SHELL")) == NULL) 36469131e40SMike Heffner sh = _PATH_CSHELL; 36569131e40SMike Heffner 36669131e40SMike Heffner rc = run_command(sh, 0, nullfd, fileno(fbuf), 36769131e40SMike Heffner "-c", cp+1, NULL); 36869131e40SMike Heffner 36969131e40SMike Heffner close(nullfd); 37069131e40SMike Heffner 37169131e40SMike Heffner if (rc < 0) { 37269131e40SMike Heffner (void)Fclose(fbuf); 37369131e40SMike Heffner break; 37469131e40SMike Heffner } 37569131e40SMike Heffner 37669131e40SMike Heffner if (fsize(fbuf) == 0) { 37769131e40SMike Heffner fprintf(stderr, 37869131e40SMike Heffner "No bytes from command \"%s\"\n", 37969131e40SMike Heffner cp+1); 38069131e40SMike Heffner (void)Fclose(fbuf); 38169131e40SMike Heffner break; 38269131e40SMike Heffner } 38369131e40SMike Heffner 38469131e40SMike Heffner rewind(fbuf); 38569131e40SMike Heffner } else if (isdir(cp)) { 38669131e40SMike Heffner printf("%s: Directory\n", cp); 38769131e40SMike Heffner break; 38869131e40SMike Heffner } else if ((fbuf = Fopen(cp, "r")) == NULL) { 3890c3a8314SMike Heffner warn("%s", cp); 3909b50d902SRodney W. Grimes break; 3919b50d902SRodney W. Grimes } 3929b50d902SRodney W. Grimes printf("\"%s\" ", cp); 3939ce73e90SMike Heffner (void)fflush(stdout); 3949b50d902SRodney W. Grimes lc = 0; 3959b50d902SRodney W. Grimes cc = 0; 396856f23edSMike Heffner while ((rc = readline(fbuf, linebuf, LINESIZE)) >= 0) { 397856f23edSMike Heffner if (rc != LINESIZE - 1) 3989b50d902SRodney W. Grimes lc++; 399856f23edSMike Heffner if ((t = putline(collf, linebuf, 400856f23edSMike Heffner rc != LINESIZE - 1)) < 0) { 4019ce73e90SMike Heffner (void)Fclose(fbuf); 4029b50d902SRodney W. Grimes goto err; 4039b50d902SRodney W. Grimes } 4049b50d902SRodney W. Grimes cc += t; 4059b50d902SRodney W. Grimes } 4069ce73e90SMike Heffner (void)Fclose(fbuf); 4079b50d902SRodney W. Grimes printf("%d/%d\n", lc, cc); 4089b50d902SRodney W. Grimes break; 4099b50d902SRodney W. Grimes case 'w': 4109b50d902SRodney W. Grimes /* 4119b50d902SRodney W. Grimes * Write the message on a file. 4129b50d902SRodney W. Grimes */ 4139b50d902SRodney W. Grimes cp = &linebuf[2]; 4149b50d902SRodney W. Grimes while (*cp == ' ' || *cp == '\t') 4159b50d902SRodney W. Grimes cp++; 4169b50d902SRodney W. Grimes if (*cp == '\0') { 4179b50d902SRodney W. Grimes fprintf(stderr, "Write what file!?\n"); 4189b50d902SRodney W. Grimes break; 4199b50d902SRodney W. Grimes } 4209ce73e90SMike Heffner if ((cp = expand(cp)) == NULL) 4219b50d902SRodney W. Grimes break; 4229b50d902SRodney W. Grimes rewind(collf); 4239b50d902SRodney W. Grimes exwrite(cp, collf, 1); 4249b50d902SRodney W. Grimes break; 4259b50d902SRodney W. Grimes case 'm': 4269b50d902SRodney W. Grimes case 'M': 4279b50d902SRodney W. Grimes case 'f': 4289b50d902SRodney W. Grimes case 'F': 4299b50d902SRodney W. Grimes /* 4309b50d902SRodney W. Grimes * Interpolate the named messages, if we 4319b50d902SRodney W. Grimes * are in receiving mail mode. Does the 4329b50d902SRodney W. Grimes * standard list processing garbage. 4339b50d902SRodney W. Grimes * If ~f is given, we don't shift over. 4349b50d902SRodney W. Grimes */ 4350c3a8314SMike Heffner if (forward(linebuf + 2, collf, tempname, c) < 0) 4369b50d902SRodney W. Grimes goto err; 4379b50d902SRodney W. Grimes goto cont; 4389b50d902SRodney W. Grimes case '?': 4399b50d902SRodney W. Grimes if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { 4400c3a8314SMike Heffner warn("%s", _PATH_TILDE); 4419b50d902SRodney W. Grimes break; 4429b50d902SRodney W. Grimes } 4439b50d902SRodney W. Grimes while ((t = getc(fbuf)) != EOF) 4449b50d902SRodney W. Grimes (void)putchar(t); 4459ce73e90SMike Heffner (void)Fclose(fbuf); 4469b50d902SRodney W. Grimes break; 4479b50d902SRodney W. Grimes case 'p': 4489b50d902SRodney W. Grimes /* 4499b50d902SRodney W. Grimes * Print out the current state of the 4509b50d902SRodney W. Grimes * message without altering anything. 4519b50d902SRodney W. Grimes */ 4529b50d902SRodney W. Grimes rewind(collf); 4539b50d902SRodney W. Grimes printf("-------\nMessage contains:\n"); 4549b50d902SRodney W. Grimes puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); 4559b50d902SRodney W. Grimes while ((t = getc(collf)) != EOF) 4569b50d902SRodney W. Grimes (void)putchar(t); 4579b50d902SRodney W. Grimes goto cont; 4589b50d902SRodney W. Grimes case '|': 4599b50d902SRodney W. Grimes /* 4609b50d902SRodney W. Grimes * Pipe message through command. 4619b50d902SRodney W. Grimes * Collect output as new message. 4629b50d902SRodney W. Grimes */ 4639b50d902SRodney W. Grimes rewind(collf); 4649b50d902SRodney W. Grimes mespipe(collf, &linebuf[2]); 4659b50d902SRodney W. Grimes goto cont; 4669b50d902SRodney W. Grimes case 'v': 4679b50d902SRodney W. Grimes case 'e': 4689b50d902SRodney W. Grimes /* 4699b50d902SRodney W. Grimes * Edit the current message. 4709b50d902SRodney W. Grimes * 'e' means to use EDITOR 4719b50d902SRodney W. Grimes * 'v' means to use VISUAL 4729b50d902SRodney W. Grimes */ 4739b50d902SRodney W. Grimes rewind(collf); 4749b50d902SRodney W. Grimes mesedit(collf, c); 4759b50d902SRodney W. Grimes goto cont; 4769b50d902SRodney W. Grimes } 4779b50d902SRodney W. Grimes } 4789b50d902SRodney W. Grimes goto out; 4799b50d902SRodney W. Grimes err: 4809b50d902SRodney W. Grimes if (collf != NULL) { 4819ce73e90SMike Heffner (void)Fclose(collf); 4829b50d902SRodney W. Grimes collf = NULL; 4839b50d902SRodney W. Grimes } 4849b50d902SRodney W. Grimes out: 4859b50d902SRodney W. Grimes if (collf != NULL) 4869b50d902SRodney W. Grimes rewind(collf); 4879b50d902SRodney W. Grimes noreset--; 488856f23edSMike Heffner (void)sigprocmask(SIG_BLOCK, &nset, NULL); 4899ce73e90SMike Heffner (void)signal(SIGINT, saveint); 4909ce73e90SMike Heffner (void)signal(SIGHUP, savehup); 4919ce73e90SMike Heffner (void)signal(SIGTSTP, savetstp); 4929ce73e90SMike Heffner (void)signal(SIGTTOU, savettou); 4939ce73e90SMike Heffner (void)signal(SIGTTIN, savettin); 494856f23edSMike Heffner (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 4959ce73e90SMike Heffner return (collf); 4969b50d902SRodney W. Grimes } 4979b50d902SRodney W. Grimes 4989b50d902SRodney W. Grimes /* 4999b50d902SRodney W. Grimes * Write a file, ex-like if f set. 5009b50d902SRodney W. Grimes */ 5019b50d902SRodney W. Grimes int 5029b50d902SRodney W. Grimes exwrite(name, fp, f) 5039b50d902SRodney W. Grimes char name[]; 5049b50d902SRodney W. Grimes FILE *fp; 5059b50d902SRodney W. Grimes int f; 5069b50d902SRodney W. Grimes { 5079ce73e90SMike Heffner FILE *of; 5089ce73e90SMike Heffner int c, lc; 5099b50d902SRodney W. Grimes long cc; 5109b50d902SRodney W. Grimes struct stat junk; 5119b50d902SRodney W. Grimes 5129b50d902SRodney W. Grimes if (f) { 5139b50d902SRodney W. Grimes printf("\"%s\" ", name); 5149ce73e90SMike Heffner (void)fflush(stdout); 5159b50d902SRodney W. Grimes } 5160c3a8314SMike Heffner if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) { 5179b50d902SRodney W. Grimes if (!f) 5189b50d902SRodney W. Grimes fprintf(stderr, "%s: ", name); 5199b50d902SRodney W. Grimes fprintf(stderr, "File exists\n"); 5209b50d902SRodney W. Grimes return (-1); 5219b50d902SRodney W. Grimes } 5229b50d902SRodney W. Grimes if ((of = Fopen(name, "w")) == NULL) { 5239ce73e90SMike Heffner warn((char *)NULL); 5249b50d902SRodney W. Grimes return (-1); 5259b50d902SRodney W. Grimes } 5269b50d902SRodney W. Grimes lc = 0; 5279b50d902SRodney W. Grimes cc = 0; 5289b50d902SRodney W. Grimes while ((c = getc(fp)) != EOF) { 5299b50d902SRodney W. Grimes cc++; 5309b50d902SRodney W. Grimes if (c == '\n') 5319b50d902SRodney W. Grimes lc++; 5329b50d902SRodney W. Grimes (void)putc(c, of); 5339b50d902SRodney W. Grimes if (ferror(of)) { 5340c3a8314SMike Heffner warnx("%s", name); 5359ce73e90SMike Heffner (void)Fclose(of); 5369b50d902SRodney W. Grimes return (-1); 5379b50d902SRodney W. Grimes } 5389b50d902SRodney W. Grimes } 5399ce73e90SMike Heffner (void)Fclose(of); 5409b50d902SRodney W. Grimes printf("%d/%ld\n", lc, cc); 5419ce73e90SMike Heffner (void)fflush(stdout); 5429b50d902SRodney W. Grimes return (0); 5439b50d902SRodney W. Grimes } 5449b50d902SRodney W. Grimes 5459b50d902SRodney W. Grimes /* 5469b50d902SRodney W. Grimes * Edit the message being collected on fp. 5479b50d902SRodney W. Grimes * On return, make the edit file the new temp file. 5489b50d902SRodney W. Grimes */ 5499b50d902SRodney W. Grimes void 5509b50d902SRodney W. Grimes mesedit(fp, c) 5519b50d902SRodney W. Grimes FILE *fp; 5529b50d902SRodney W. Grimes int c; 5539b50d902SRodney W. Grimes { 5549b50d902SRodney W. Grimes sig_t sigint = signal(SIGINT, SIG_IGN); 5559b50d902SRodney W. Grimes FILE *nf = run_editor(fp, (off_t)-1, c, 0); 5569b50d902SRodney W. Grimes 5579b50d902SRodney W. Grimes if (nf != NULL) { 558af8c3262SAndrey A. Chernov (void)fseeko(nf, (off_t)0, SEEK_END); 5599b50d902SRodney W. Grimes collf = nf; 5609ce73e90SMike Heffner (void)Fclose(fp); 5619b50d902SRodney W. Grimes } 5629b50d902SRodney W. Grimes (void)signal(SIGINT, sigint); 5639b50d902SRodney W. Grimes } 5649b50d902SRodney W. Grimes 5659b50d902SRodney W. Grimes /* 5669b50d902SRodney W. Grimes * Pipe the message through the command. 5679b50d902SRodney W. Grimes * Old message is on stdin of command; 5689b50d902SRodney W. Grimes * New message collected from stdout. 5699b50d902SRodney W. Grimes * Sh -c must return 0 to accept the new message. 5709b50d902SRodney W. Grimes */ 5719b50d902SRodney W. Grimes void 5729b50d902SRodney W. Grimes mespipe(fp, cmd) 5739b50d902SRodney W. Grimes FILE *fp; 5749b50d902SRodney W. Grimes char cmd[]; 5759b50d902SRodney W. Grimes { 5769b50d902SRodney W. Grimes FILE *nf; 5770c3a8314SMike Heffner int fd; 5789b50d902SRodney W. Grimes sig_t sigint = signal(SIGINT, SIG_IGN); 5799ce73e90SMike Heffner char *sh, tempname[PATHSIZE]; 5809b50d902SRodney W. Grimes 5819ce73e90SMike Heffner (void)snprintf(tempname, sizeof(tempname), 5829ce73e90SMike Heffner "%s/mail.ReXXXXXXXXXX", tmpdir); 5830c3a8314SMike Heffner if ((fd = mkstemp(tempname)) == -1 || 5840c3a8314SMike Heffner (nf = Fdopen(fd, "w+")) == NULL) { 5850c3a8314SMike Heffner warn("%s", tempname); 5869b50d902SRodney W. Grimes goto out; 5879b50d902SRodney W. Grimes } 5880c3a8314SMike Heffner (void)rm(tempname); 5899b50d902SRodney W. Grimes /* 5909b50d902SRodney W. Grimes * stdin = current message. 5919b50d902SRodney W. Grimes * stdout = new message. 5929b50d902SRodney W. Grimes */ 5939ce73e90SMike Heffner if ((sh = value("SHELL")) == NULL) 5949ce73e90SMike Heffner sh = _PATH_CSHELL; 5959ce73e90SMike Heffner if (run_command(sh, 5969ce73e90SMike Heffner 0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) { 5979b50d902SRodney W. Grimes (void)Fclose(nf); 5989b50d902SRodney W. Grimes goto out; 5999b50d902SRodney W. Grimes } 6009b50d902SRodney W. Grimes if (fsize(nf) == 0) { 6019b50d902SRodney W. Grimes fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); 6029b50d902SRodney W. Grimes (void)Fclose(nf); 6039b50d902SRodney W. Grimes goto out; 6049b50d902SRodney W. Grimes } 6059b50d902SRodney W. Grimes /* 6069b50d902SRodney W. Grimes * Take new files. 6079b50d902SRodney W. Grimes */ 608af8c3262SAndrey A. Chernov (void)fseeko(nf, (off_t)0, SEEK_END); 6099b50d902SRodney W. Grimes collf = nf; 6109b50d902SRodney W. Grimes (void)Fclose(fp); 6119b50d902SRodney W. Grimes out: 6129b50d902SRodney W. Grimes (void)signal(SIGINT, sigint); 6139b50d902SRodney W. Grimes } 6149b50d902SRodney W. Grimes 6159b50d902SRodney W. Grimes /* 6169b50d902SRodney W. Grimes * Interpolate the named messages into the current 6179b50d902SRodney W. Grimes * message, preceding each line with a tab. 6189b50d902SRodney W. Grimes * Return a count of the number of characters now in 6199b50d902SRodney W. Grimes * the message, or -1 if an error is encountered writing 6209b50d902SRodney W. Grimes * the message temporary. The flag argument is 'm' if we 6219b50d902SRodney W. Grimes * should shift over and 'f' if not. 6229b50d902SRodney W. Grimes */ 6239b50d902SRodney W. Grimes int 6240c3a8314SMike Heffner forward(ms, fp, fn, f) 6259b50d902SRodney W. Grimes char ms[]; 6269b50d902SRodney W. Grimes FILE *fp; 6270c3a8314SMike Heffner char *fn; 6289b50d902SRodney W. Grimes int f; 6299b50d902SRodney W. Grimes { 6309ce73e90SMike Heffner int *msgvec; 6319b50d902SRodney W. Grimes struct ignoretab *ig; 6329b50d902SRodney W. Grimes char *tabst; 6339b50d902SRodney W. Grimes 6349ce73e90SMike Heffner msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec)); 6359ce73e90SMike Heffner if (msgvec == NULL) 6369b50d902SRodney W. Grimes return (0); 6379b50d902SRodney W. Grimes if (getmsglist(ms, msgvec, 0) < 0) 6389b50d902SRodney W. Grimes return (0); 6399b50d902SRodney W. Grimes if (*msgvec == 0) { 6409b50d902SRodney W. Grimes *msgvec = first(0, MMNORM); 641d030d2d2SPoul-Henning Kamp if (*msgvec == 0) { 6429b50d902SRodney W. Grimes printf("No appropriate messages\n"); 6439b50d902SRodney W. Grimes return (0); 6449b50d902SRodney W. Grimes } 645d030d2d2SPoul-Henning Kamp msgvec[1] = 0; 6469b50d902SRodney W. Grimes } 6479b50d902SRodney W. Grimes if (f == 'f' || f == 'F') 6489ce73e90SMike Heffner tabst = NULL; 6499ce73e90SMike Heffner else if ((tabst = value("indentprefix")) == NULL) 6509b50d902SRodney W. Grimes tabst = "\t"; 6516d48fa43SAndrey A. Chernov ig = isupper((unsigned char)f) ? NULL : ignore; 6529b50d902SRodney W. Grimes printf("Interpolating:"); 6539b50d902SRodney W. Grimes for (; *msgvec != 0; msgvec++) { 6549b50d902SRodney W. Grimes struct message *mp = message + *msgvec - 1; 6559b50d902SRodney W. Grimes 6569b50d902SRodney W. Grimes touch(mp); 6579b50d902SRodney W. Grimes printf(" %d", *msgvec); 6580c3a8314SMike Heffner if (sendmessage(mp, fp, ig, tabst) < 0) { 6590c3a8314SMike Heffner warnx("%s", fn); 6609b50d902SRodney W. Grimes return (-1); 6619b50d902SRodney W. Grimes } 6629b50d902SRodney W. Grimes } 6639b50d902SRodney W. Grimes printf("\n"); 6649b50d902SRodney W. Grimes return (0); 6659b50d902SRodney W. Grimes } 6669b50d902SRodney W. Grimes 6679b50d902SRodney W. Grimes /* 6689b50d902SRodney W. Grimes * Print (continue) when continued after ^Z. 6699b50d902SRodney W. Grimes */ 6709b50d902SRodney W. Grimes /*ARGSUSED*/ 6719b50d902SRodney W. Grimes void 6729b50d902SRodney W. Grimes collstop(s) 6739b50d902SRodney W. Grimes int s; 6749b50d902SRodney W. Grimes { 6759b50d902SRodney W. Grimes sig_t old_action = signal(s, SIG_DFL); 676856f23edSMike Heffner sigset_t nset; 6779b50d902SRodney W. Grimes 678856f23edSMike Heffner (void)sigemptyset(&nset); 679856f23edSMike Heffner (void)sigaddset(&nset, s); 680856f23edSMike Heffner (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 6819ce73e90SMike Heffner (void)kill(0, s); 682856f23edSMike Heffner (void)sigprocmask(SIG_BLOCK, &nset, NULL); 6839ce73e90SMike Heffner (void)signal(s, old_action); 6849b50d902SRodney W. Grimes if (colljmp_p) { 6859b50d902SRodney W. Grimes colljmp_p = 0; 6869b50d902SRodney W. Grimes hadintr = 0; 6879b50d902SRodney W. Grimes longjmp(colljmp, 1); 6889b50d902SRodney W. Grimes } 6899b50d902SRodney W. Grimes } 6909b50d902SRodney W. Grimes 6919b50d902SRodney W. Grimes /* 6929b50d902SRodney W. Grimes * On interrupt, come here to save the partial message in ~/dead.letter. 6939b50d902SRodney W. Grimes * Then jump out of the collection loop. 6949b50d902SRodney W. Grimes */ 6959b50d902SRodney W. Grimes /*ARGSUSED*/ 6969b50d902SRodney W. Grimes void 6979b50d902SRodney W. Grimes collint(s) 6989b50d902SRodney W. Grimes int s; 6999b50d902SRodney W. Grimes { 7009b50d902SRodney W. Grimes /* 7019b50d902SRodney W. Grimes * the control flow is subtle, because we can be called from ~q. 7029b50d902SRodney W. Grimes */ 7039b50d902SRodney W. Grimes if (!hadintr) { 7049ce73e90SMike Heffner if (value("ignore") != NULL) { 7059ce73e90SMike Heffner printf("@"); 7069ce73e90SMike Heffner (void)fflush(stdout); 7079b50d902SRodney W. Grimes clearerr(stdin); 7089b50d902SRodney W. Grimes return; 7099b50d902SRodney W. Grimes } 7109b50d902SRodney W. Grimes hadintr = 1; 7119b50d902SRodney W. Grimes longjmp(colljmp, 1); 7129b50d902SRodney W. Grimes } 7139b50d902SRodney W. Grimes rewind(collf); 7149ce73e90SMike Heffner if (value("nosave") == NULL) 7159b50d902SRodney W. Grimes savedeadletter(collf); 7169b50d902SRodney W. Grimes longjmp(collabort, 1); 7179b50d902SRodney W. Grimes } 7189b50d902SRodney W. Grimes 7199b50d902SRodney W. Grimes /*ARGSUSED*/ 7209b50d902SRodney W. Grimes void 7219b50d902SRodney W. Grimes collhup(s) 7229b50d902SRodney W. Grimes int s; 7239b50d902SRodney W. Grimes { 7249b50d902SRodney W. Grimes rewind(collf); 7259b50d902SRodney W. Grimes savedeadletter(collf); 7269b50d902SRodney W. Grimes /* 7279b50d902SRodney W. Grimes * Let's pretend nobody else wants to clean up, 7289b50d902SRodney W. Grimes * a true statement at this time. 7299b50d902SRodney W. Grimes */ 7309b50d902SRodney W. Grimes exit(1); 7319b50d902SRodney W. Grimes } 7329b50d902SRodney W. Grimes 7339b50d902SRodney W. Grimes void 7349b50d902SRodney W. Grimes savedeadletter(fp) 7359ce73e90SMike Heffner FILE *fp; 7369b50d902SRodney W. Grimes { 7379ce73e90SMike Heffner FILE *dbuf; 7389ce73e90SMike Heffner int c; 7399b50d902SRodney W. Grimes char *cp; 7409b50d902SRodney W. Grimes 7419b50d902SRodney W. Grimes if (fsize(fp) == 0) 7429b50d902SRodney W. Grimes return; 7439b50d902SRodney W. Grimes cp = getdeadletter(); 7449b50d902SRodney W. Grimes c = umask(077); 7459b50d902SRodney W. Grimes dbuf = Fopen(cp, "a"); 7469b50d902SRodney W. Grimes (void)umask(c); 7479b50d902SRodney W. Grimes if (dbuf == NULL) 7489b50d902SRodney W. Grimes return; 7499b50d902SRodney W. Grimes while ((c = getc(fp)) != EOF) 7509b50d902SRodney W. Grimes (void)putc(c, dbuf); 7519ce73e90SMike Heffner (void)Fclose(dbuf); 7529b50d902SRodney W. Grimes rewind(fp); 7539b50d902SRodney W. Grimes } 754