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" 509b50d902SRodney W. Grimes #include "extern.h" 519b50d902SRodney W. Grimes 529b50d902SRodney W. Grimes /* 539b50d902SRodney W. Grimes * Read a message from standard output and return a read file to it 549b50d902SRodney W. Grimes * or NULL on error. 559b50d902SRodney W. Grimes */ 569b50d902SRodney W. Grimes 579b50d902SRodney W. Grimes /* 589b50d902SRodney W. Grimes * The following hokiness with global variables is so that on 599b50d902SRodney W. Grimes * receipt of an interrupt signal, the partial message can be salted 609b50d902SRodney W. Grimes * away on dead.letter. 619b50d902SRodney W. Grimes */ 629b50d902SRodney W. Grimes 639b50d902SRodney W. Grimes static sig_t saveint; /* Previous SIGINT value */ 649b50d902SRodney W. Grimes static sig_t savehup; /* Previous SIGHUP value */ 659b50d902SRodney W. Grimes static sig_t savetstp; /* Previous SIGTSTP value */ 669b50d902SRodney W. Grimes static sig_t savettou; /* Previous SIGTTOU value */ 679b50d902SRodney W. Grimes static sig_t savettin; /* Previous SIGTTIN value */ 689b50d902SRodney W. Grimes static FILE *collf; /* File for saving away */ 699b50d902SRodney W. Grimes static int hadintr; /* Have seen one SIGINT so far */ 709b50d902SRodney W. Grimes 719b50d902SRodney W. Grimes static jmp_buf colljmp; /* To get back to work */ 729b50d902SRodney W. Grimes static int colljmp_p; /* whether to long jump */ 739b50d902SRodney W. Grimes static jmp_buf collabort; /* To end collection with error */ 749b50d902SRodney W. Grimes 759b50d902SRodney W. Grimes FILE * 769b50d902SRodney W. Grimes collect(hp, printheaders) 779b50d902SRodney W. Grimes struct header *hp; 789b50d902SRodney W. Grimes int printheaders; 799b50d902SRodney W. Grimes { 809b50d902SRodney W. Grimes FILE *fbuf; 819ce73e90SMike Heffner int lc, cc, escape, eofcount, fd, c, t; 829ce73e90SMike Heffner char linebuf[LINESIZE], tempname[PATHSIZE], *cp, getsub; 83856f23edSMike Heffner sigset_t nset; 84856f23edSMike Heffner int longline, lastlong, rc; /* So we don't make 2 or more lines 85856f23edSMike Heffner out of a long input line. */ 869b50d902SRodney W. Grimes 879b50d902SRodney W. Grimes collf = NULL; 889b50d902SRodney W. Grimes /* 899b50d902SRodney W. Grimes * Start catching signals from here, but we're still die on interrupts 909b50d902SRodney W. Grimes * until we're in the main loop. 919b50d902SRodney W. Grimes */ 92856f23edSMike Heffner (void)sigemptyset(&nset); 93856f23edSMike Heffner (void)sigaddset(&nset, SIGINT); 94856f23edSMike Heffner (void)sigaddset(&nset, SIGHUP); 95856f23edSMike Heffner (void)sigprocmask(SIG_BLOCK, &nset, NULL); 969b50d902SRodney W. Grimes if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) 979ce73e90SMike Heffner (void)signal(SIGINT, collint); 989b50d902SRodney W. Grimes if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) 999ce73e90SMike Heffner (void)signal(SIGHUP, collhup); 1009b50d902SRodney W. Grimes savetstp = signal(SIGTSTP, collstop); 1019b50d902SRodney W. Grimes savettou = signal(SIGTTOU, collstop); 1029b50d902SRodney W. Grimes savettin = signal(SIGTTIN, collstop); 1039b50d902SRodney W. Grimes if (setjmp(collabort) || setjmp(colljmp)) { 1049ce73e90SMike Heffner (void)rm(tempname); 1059b50d902SRodney W. Grimes goto err; 1069b50d902SRodney W. Grimes } 107856f23edSMike Heffner (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 1089b50d902SRodney W. Grimes 1099b50d902SRodney W. Grimes noreset++; 1109ce73e90SMike Heffner (void)snprintf(tempname, sizeof(tempname), 1119ce73e90SMike Heffner "%s/mail.RsXXXXXXXXXX", tmpdir); 1120c3a8314SMike Heffner if ((fd = mkstemp(tempname)) == -1 || 1130c3a8314SMike Heffner (collf = Fdopen(fd, "w+")) == NULL) { 1140c3a8314SMike Heffner warn("%s", tempname); 1159b50d902SRodney W. Grimes goto err; 1169b50d902SRodney W. Grimes } 1179ce73e90SMike Heffner (void)rm(tempname); 1189b50d902SRodney W. Grimes 1199b50d902SRodney W. Grimes /* 1209b50d902SRodney W. Grimes * If we are going to prompt for a subject, 1219b50d902SRodney W. Grimes * refrain from printing a newline after 1229b50d902SRodney W. Grimes * the headers (since some people mind). 1239b50d902SRodney W. Grimes */ 1249b50d902SRodney W. Grimes t = GTO|GSUBJECT|GCC|GNL; 1259b50d902SRodney W. Grimes getsub = 0; 1269ce73e90SMike Heffner if (hp->h_subject == NULL && value("interactive") != NULL && 1279ce73e90SMike Heffner (value("ask") != NULL || value("asksub") != NULL)) 1289b50d902SRodney W. Grimes t &= ~GNL, getsub++; 1299b50d902SRodney W. Grimes if (printheaders) { 1309b50d902SRodney W. Grimes puthead(hp, stdout, t); 1319ce73e90SMike Heffner (void)fflush(stdout); 1329b50d902SRodney W. Grimes } 1339ce73e90SMike Heffner if ((cp = value("escape")) != NULL) 1349b50d902SRodney W. Grimes escape = *cp; 1359b50d902SRodney W. Grimes else 1369b50d902SRodney W. Grimes escape = ESCAPE; 1379b50d902SRodney W. Grimes eofcount = 0; 1389b50d902SRodney W. Grimes hadintr = 0; 139856f23edSMike Heffner lastlong = 0; 140856f23edSMike Heffner longline = 0; 1419b50d902SRodney W. Grimes 1429b50d902SRodney W. Grimes if (!setjmp(colljmp)) { 1439b50d902SRodney W. Grimes if (getsub) 1449b50d902SRodney W. Grimes grabh(hp, GSUBJECT); 1459b50d902SRodney W. Grimes } else { 1469b50d902SRodney W. Grimes /* 1479b50d902SRodney W. Grimes * Come here for printing the after-signal message. 1489b50d902SRodney W. Grimes * Duplicate messages won't be printed because 1499b50d902SRodney W. Grimes * the write is aborted if we get a SIGTTOU. 1509b50d902SRodney W. Grimes */ 1519b50d902SRodney W. Grimes cont: 1529b50d902SRodney W. Grimes if (hadintr) { 1539ce73e90SMike Heffner (void)fflush(stdout); 1549b50d902SRodney W. Grimes fprintf(stderr, 1559b50d902SRodney W. Grimes "\n(Interrupt -- one more to kill letter)\n"); 1569b50d902SRodney W. Grimes } else { 1579b50d902SRodney W. Grimes printf("(continue)\n"); 1589ce73e90SMike Heffner (void)fflush(stdout); 1599b50d902SRodney W. Grimes } 1609b50d902SRodney W. Grimes } 1619b50d902SRodney W. Grimes for (;;) { 1629b50d902SRodney W. Grimes colljmp_p = 1; 1639b50d902SRodney W. Grimes c = readline(stdin, linebuf, LINESIZE); 1649b50d902SRodney W. Grimes colljmp_p = 0; 1659b50d902SRodney W. Grimes if (c < 0) { 1669ce73e90SMike Heffner if (value("interactive") != NULL && 1679ce73e90SMike Heffner value("ignoreeof") != NULL && ++eofcount < 25) { 1689b50d902SRodney W. Grimes printf("Use \".\" to terminate letter\n"); 1699b50d902SRodney W. Grimes continue; 1709b50d902SRodney W. Grimes } 1719b50d902SRodney W. Grimes break; 1729b50d902SRodney W. Grimes } 173856f23edSMike Heffner lastlong = longline; 174856f23edSMike Heffner longline = c == LINESIZE - 1; 1759b50d902SRodney W. Grimes eofcount = 0; 1769b50d902SRodney W. Grimes hadintr = 0; 1779b50d902SRodney W. Grimes if (linebuf[0] == '.' && linebuf[1] == '\0' && 178856f23edSMike Heffner value("interactive") != NULL && !lastlong && 1799ce73e90SMike Heffner (value("dot") != NULL || value("ignoreeof") != NULL)) 1809b50d902SRodney W. Grimes break; 181856f23edSMike Heffner if (linebuf[0] != escape || value("interactive") == NULL || 182856f23edSMike Heffner lastlong) { 183856f23edSMike Heffner if (putline(collf, linebuf, !longline) < 0) 1849b50d902SRodney W. Grimes goto err; 1859b50d902SRodney W. Grimes continue; 1869b50d902SRodney W. Grimes } 1879b50d902SRodney W. Grimes c = linebuf[1]; 1889b50d902SRodney W. Grimes switch (c) { 1899b50d902SRodney W. Grimes default: 1909b50d902SRodney W. Grimes /* 1919b50d902SRodney W. Grimes * On double escape, just send the single one. 1929b50d902SRodney W. Grimes * Otherwise, it's an error. 1939b50d902SRodney W. Grimes */ 1949b50d902SRodney W. Grimes if (c == escape) { 195856f23edSMike Heffner if (putline(collf, &linebuf[1], !longline) < 0) 1969b50d902SRodney W. Grimes goto err; 1979b50d902SRodney W. Grimes else 1989b50d902SRodney W. Grimes break; 1999b50d902SRodney W. Grimes } 2009b50d902SRodney W. Grimes printf("Unknown tilde escape.\n"); 2019b50d902SRodney W. Grimes break; 2029b50d902SRodney W. Grimes case 'C': 2039b50d902SRodney W. Grimes /* 2049b50d902SRodney W. Grimes * Dump core. 2059b50d902SRodney W. Grimes */ 2069b50d902SRodney W. Grimes core(); 2079b50d902SRodney W. Grimes break; 2089b50d902SRodney W. Grimes case '!': 2099b50d902SRodney W. Grimes /* 2109b50d902SRodney W. Grimes * Shell escape, send the balance of the 2119b50d902SRodney W. Grimes * line to sh -c. 2129b50d902SRodney W. Grimes */ 2139b50d902SRodney W. Grimes shell(&linebuf[2]); 2149b50d902SRodney W. Grimes break; 2159b50d902SRodney W. Grimes case ':': 2169b50d902SRodney W. Grimes /* 2179b50d902SRodney W. Grimes * Escape to command mode, but be nice! 2189b50d902SRodney W. Grimes */ 2199b50d902SRodney W. Grimes execute(&linebuf[2], 1); 2209b50d902SRodney W. Grimes goto cont; 2219b50d902SRodney W. Grimes case '.': 2229b50d902SRodney W. Grimes /* 2239b50d902SRodney W. Grimes * Simulate end of file on input. 2249b50d902SRodney W. Grimes */ 2259b50d902SRodney W. Grimes goto out; 2269b50d902SRodney W. Grimes case 'q': 2279b50d902SRodney W. Grimes /* 2289b50d902SRodney W. Grimes * Force a quit of sending mail. 2299b50d902SRodney W. Grimes * Act like an interrupt happened. 2309b50d902SRodney W. Grimes */ 2319b50d902SRodney W. Grimes hadintr++; 2329b50d902SRodney W. Grimes collint(SIGINT); 2339b50d902SRodney W. Grimes exit(1); 2349b50d902SRodney W. Grimes case 'h': 2359b50d902SRodney W. Grimes /* 2369b50d902SRodney W. Grimes * Grab a bunch of headers. 2379b50d902SRodney W. Grimes */ 2389b50d902SRodney W. Grimes grabh(hp, GTO|GSUBJECT|GCC|GBCC); 2399b50d902SRodney W. Grimes goto cont; 2409b50d902SRodney W. Grimes case 't': 2419b50d902SRodney W. Grimes /* 2429b50d902SRodney W. Grimes * Add to the To list. 2439b50d902SRodney W. Grimes */ 2449b50d902SRodney W. Grimes hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); 2459b50d902SRodney W. Grimes break; 2469b50d902SRodney W. Grimes case 's': 2479b50d902SRodney W. Grimes /* 24899bd6601SJoerg Wunsch * Set the Subject line. 2499b50d902SRodney W. Grimes */ 2509b50d902SRodney W. Grimes cp = &linebuf[2]; 2516d48fa43SAndrey A. Chernov while (isspace((unsigned char)*cp)) 2529b50d902SRodney W. Grimes cp++; 2539b50d902SRodney W. Grimes hp->h_subject = savestr(cp); 2549b50d902SRodney W. Grimes break; 25599bd6601SJoerg Wunsch case 'R': 25699bd6601SJoerg Wunsch /* 25799bd6601SJoerg Wunsch * Set the Reply-To line. 25899bd6601SJoerg Wunsch */ 25999bd6601SJoerg Wunsch cp = &linebuf[2]; 2606d48fa43SAndrey A. Chernov while (isspace((unsigned char)*cp)) 26199bd6601SJoerg Wunsch cp++; 26299bd6601SJoerg Wunsch hp->h_replyto = savestr(cp); 26399bd6601SJoerg Wunsch break; 2649b50d902SRodney W. Grimes case 'c': 2659b50d902SRodney W. Grimes /* 2669b50d902SRodney W. Grimes * Add to the CC list. 2679b50d902SRodney W. Grimes */ 2689b50d902SRodney W. Grimes hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); 2699b50d902SRodney W. Grimes break; 2709b50d902SRodney W. Grimes case 'b': 2719b50d902SRodney W. Grimes /* 2729b50d902SRodney W. Grimes * Add stuff to blind carbon copies list. 2739b50d902SRodney W. Grimes */ 2749b50d902SRodney W. Grimes hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); 2759b50d902SRodney W. Grimes break; 2769b50d902SRodney W. Grimes case 'd': 2770c3a8314SMike Heffner if (strlcpy(linebuf + 2, getdeadletter(), sizeof(linebuf) - 2) 2780c3a8314SMike Heffner >= sizeof(linebuf) - 2) { 2790c3a8314SMike Heffner printf("Line buffer overflow\n"); 2800c3a8314SMike Heffner break; 2810c3a8314SMike Heffner } 2829b50d902SRodney W. Grimes /* fall into . . . */ 2839b50d902SRodney W. Grimes case 'r': 2849b50d902SRodney W. Grimes /* 2859b50d902SRodney W. Grimes * Invoke a file: 2869b50d902SRodney W. Grimes * Search for the file name, 2879b50d902SRodney W. Grimes * then open it and copy the contents to collf. 2889b50d902SRodney W. Grimes */ 2899b50d902SRodney W. Grimes cp = &linebuf[2]; 2906d48fa43SAndrey A. Chernov while (isspace((unsigned char)*cp)) 2919b50d902SRodney W. Grimes cp++; 2929b50d902SRodney W. Grimes if (*cp == '\0') { 2939b50d902SRodney W. Grimes printf("Interpolate what file?\n"); 2949b50d902SRodney W. Grimes break; 2959b50d902SRodney W. Grimes } 2969b50d902SRodney W. Grimes cp = expand(cp); 2979ce73e90SMike Heffner if (cp == NULL) 2989b50d902SRodney W. Grimes break; 2999b50d902SRodney W. Grimes if (isdir(cp)) { 3009b50d902SRodney W. Grimes printf("%s: Directory\n", cp); 3019b50d902SRodney W. Grimes break; 3029b50d902SRodney W. Grimes } 3039b50d902SRodney W. Grimes if ((fbuf = Fopen(cp, "r")) == NULL) { 3040c3a8314SMike Heffner warn("%s", cp); 3059b50d902SRodney W. Grimes break; 3069b50d902SRodney W. Grimes } 3079b50d902SRodney W. Grimes printf("\"%s\" ", cp); 3089ce73e90SMike Heffner (void)fflush(stdout); 3099b50d902SRodney W. Grimes lc = 0; 3109b50d902SRodney W. Grimes cc = 0; 311856f23edSMike Heffner while ((rc = readline(fbuf, linebuf, LINESIZE)) >= 0) { 312856f23edSMike Heffner if (rc != LINESIZE - 1) 3139b50d902SRodney W. Grimes lc++; 314856f23edSMike Heffner if ((t = putline(collf, linebuf, 315856f23edSMike Heffner rc != LINESIZE - 1)) < 0) { 3169ce73e90SMike Heffner (void)Fclose(fbuf); 3179b50d902SRodney W. Grimes goto err; 3189b50d902SRodney W. Grimes } 3199b50d902SRodney W. Grimes cc += t; 3209b50d902SRodney W. Grimes } 3219ce73e90SMike Heffner (void)Fclose(fbuf); 3229b50d902SRodney W. Grimes printf("%d/%d\n", lc, cc); 3239b50d902SRodney W. Grimes break; 3249b50d902SRodney W. Grimes case 'w': 3259b50d902SRodney W. Grimes /* 3269b50d902SRodney W. Grimes * Write the message on a file. 3279b50d902SRodney W. Grimes */ 3289b50d902SRodney W. Grimes cp = &linebuf[2]; 3299b50d902SRodney W. Grimes while (*cp == ' ' || *cp == '\t') 3309b50d902SRodney W. Grimes cp++; 3319b50d902SRodney W. Grimes if (*cp == '\0') { 3329b50d902SRodney W. Grimes fprintf(stderr, "Write what file!?\n"); 3339b50d902SRodney W. Grimes break; 3349b50d902SRodney W. Grimes } 3359ce73e90SMike Heffner if ((cp = expand(cp)) == NULL) 3369b50d902SRodney W. Grimes break; 3379b50d902SRodney W. Grimes rewind(collf); 3389b50d902SRodney W. Grimes exwrite(cp, collf, 1); 3399b50d902SRodney W. Grimes break; 3409b50d902SRodney W. Grimes case 'm': 3419b50d902SRodney W. Grimes case 'M': 3429b50d902SRodney W. Grimes case 'f': 3439b50d902SRodney W. Grimes case 'F': 3449b50d902SRodney W. Grimes /* 3459b50d902SRodney W. Grimes * Interpolate the named messages, if we 3469b50d902SRodney W. Grimes * are in receiving mail mode. Does the 3479b50d902SRodney W. Grimes * standard list processing garbage. 3489b50d902SRodney W. Grimes * If ~f is given, we don't shift over. 3499b50d902SRodney W. Grimes */ 3500c3a8314SMike Heffner if (forward(linebuf + 2, collf, tempname, c) < 0) 3519b50d902SRodney W. Grimes goto err; 3529b50d902SRodney W. Grimes goto cont; 3539b50d902SRodney W. Grimes case '?': 3549b50d902SRodney W. Grimes if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { 3550c3a8314SMike Heffner warn("%s", _PATH_TILDE); 3569b50d902SRodney W. Grimes break; 3579b50d902SRodney W. Grimes } 3589b50d902SRodney W. Grimes while ((t = getc(fbuf)) != EOF) 3599b50d902SRodney W. Grimes (void)putchar(t); 3609ce73e90SMike Heffner (void)Fclose(fbuf); 3619b50d902SRodney W. Grimes break; 3629b50d902SRodney W. Grimes case 'p': 3639b50d902SRodney W. Grimes /* 3649b50d902SRodney W. Grimes * Print out the current state of the 3659b50d902SRodney W. Grimes * message without altering anything. 3669b50d902SRodney W. Grimes */ 3679b50d902SRodney W. Grimes rewind(collf); 3689b50d902SRodney W. Grimes printf("-------\nMessage contains:\n"); 3699b50d902SRodney W. Grimes puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); 3709b50d902SRodney W. Grimes while ((t = getc(collf)) != EOF) 3719b50d902SRodney W. Grimes (void)putchar(t); 3729b50d902SRodney W. Grimes goto cont; 3739b50d902SRodney W. Grimes case '|': 3749b50d902SRodney W. Grimes /* 3759b50d902SRodney W. Grimes * Pipe message through command. 3769b50d902SRodney W. Grimes * Collect output as new message. 3779b50d902SRodney W. Grimes */ 3789b50d902SRodney W. Grimes rewind(collf); 3799b50d902SRodney W. Grimes mespipe(collf, &linebuf[2]); 3809b50d902SRodney W. Grimes goto cont; 3819b50d902SRodney W. Grimes case 'v': 3829b50d902SRodney W. Grimes case 'e': 3839b50d902SRodney W. Grimes /* 3849b50d902SRodney W. Grimes * Edit the current message. 3859b50d902SRodney W. Grimes * 'e' means to use EDITOR 3869b50d902SRodney W. Grimes * 'v' means to use VISUAL 3879b50d902SRodney W. Grimes */ 3889b50d902SRodney W. Grimes rewind(collf); 3899b50d902SRodney W. Grimes mesedit(collf, c); 3909b50d902SRodney W. Grimes goto cont; 3919b50d902SRodney W. Grimes } 3929b50d902SRodney W. Grimes } 3939b50d902SRodney W. Grimes goto out; 3949b50d902SRodney W. Grimes err: 3959b50d902SRodney W. Grimes if (collf != NULL) { 3969ce73e90SMike Heffner (void)Fclose(collf); 3979b50d902SRodney W. Grimes collf = NULL; 3989b50d902SRodney W. Grimes } 3999b50d902SRodney W. Grimes out: 4009b50d902SRodney W. Grimes if (collf != NULL) 4019b50d902SRodney W. Grimes rewind(collf); 4029b50d902SRodney W. Grimes noreset--; 403856f23edSMike Heffner (void)sigprocmask(SIG_BLOCK, &nset, NULL); 4049ce73e90SMike Heffner (void)signal(SIGINT, saveint); 4059ce73e90SMike Heffner (void)signal(SIGHUP, savehup); 4069ce73e90SMike Heffner (void)signal(SIGTSTP, savetstp); 4079ce73e90SMike Heffner (void)signal(SIGTTOU, savettou); 4089ce73e90SMike Heffner (void)signal(SIGTTIN, savettin); 409856f23edSMike Heffner (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 4109ce73e90SMike Heffner return (collf); 4119b50d902SRodney W. Grimes } 4129b50d902SRodney W. Grimes 4139b50d902SRodney W. Grimes /* 4149b50d902SRodney W. Grimes * Write a file, ex-like if f set. 4159b50d902SRodney W. Grimes */ 4169b50d902SRodney W. Grimes int 4179b50d902SRodney W. Grimes exwrite(name, fp, f) 4189b50d902SRodney W. Grimes char name[]; 4199b50d902SRodney W. Grimes FILE *fp; 4209b50d902SRodney W. Grimes int f; 4219b50d902SRodney W. Grimes { 4229ce73e90SMike Heffner FILE *of; 4239ce73e90SMike Heffner int c, lc; 4249b50d902SRodney W. Grimes long cc; 4259b50d902SRodney W. Grimes struct stat junk; 4269b50d902SRodney W. Grimes 4279b50d902SRodney W. Grimes if (f) { 4289b50d902SRodney W. Grimes printf("\"%s\" ", name); 4299ce73e90SMike Heffner (void)fflush(stdout); 4309b50d902SRodney W. Grimes } 4310c3a8314SMike Heffner if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) { 4329b50d902SRodney W. Grimes if (!f) 4339b50d902SRodney W. Grimes fprintf(stderr, "%s: ", name); 4349b50d902SRodney W. Grimes fprintf(stderr, "File exists\n"); 4359b50d902SRodney W. Grimes return (-1); 4369b50d902SRodney W. Grimes } 4379b50d902SRodney W. Grimes if ((of = Fopen(name, "w")) == NULL) { 4389ce73e90SMike Heffner warn((char *)NULL); 4399b50d902SRodney W. Grimes return (-1); 4409b50d902SRodney W. Grimes } 4419b50d902SRodney W. Grimes lc = 0; 4429b50d902SRodney W. Grimes cc = 0; 4439b50d902SRodney W. Grimes while ((c = getc(fp)) != EOF) { 4449b50d902SRodney W. Grimes cc++; 4459b50d902SRodney W. Grimes if (c == '\n') 4469b50d902SRodney W. Grimes lc++; 4479b50d902SRodney W. Grimes (void)putc(c, of); 4489b50d902SRodney W. Grimes if (ferror(of)) { 4490c3a8314SMike Heffner warnx("%s", name); 4509ce73e90SMike Heffner (void)Fclose(of); 4519b50d902SRodney W. Grimes return (-1); 4529b50d902SRodney W. Grimes } 4539b50d902SRodney W. Grimes } 4549ce73e90SMike Heffner (void)Fclose(of); 4559b50d902SRodney W. Grimes printf("%d/%ld\n", lc, cc); 4569ce73e90SMike Heffner (void)fflush(stdout); 4579b50d902SRodney W. Grimes return (0); 4589b50d902SRodney W. Grimes } 4599b50d902SRodney W. Grimes 4609b50d902SRodney W. Grimes /* 4619b50d902SRodney W. Grimes * Edit the message being collected on fp. 4629b50d902SRodney W. Grimes * On return, make the edit file the new temp file. 4639b50d902SRodney W. Grimes */ 4649b50d902SRodney W. Grimes void 4659b50d902SRodney W. Grimes mesedit(fp, c) 4669b50d902SRodney W. Grimes FILE *fp; 4679b50d902SRodney W. Grimes int c; 4689b50d902SRodney W. Grimes { 4699b50d902SRodney W. Grimes sig_t sigint = signal(SIGINT, SIG_IGN); 4709b50d902SRodney W. Grimes FILE *nf = run_editor(fp, (off_t)-1, c, 0); 4719b50d902SRodney W. Grimes 4729b50d902SRodney W. Grimes if (nf != NULL) { 473af8c3262SAndrey A. Chernov (void)fseeko(nf, (off_t)0, SEEK_END); 4749b50d902SRodney W. Grimes collf = nf; 4759ce73e90SMike Heffner (void)Fclose(fp); 4769b50d902SRodney W. Grimes } 4779b50d902SRodney W. Grimes (void)signal(SIGINT, sigint); 4789b50d902SRodney W. Grimes } 4799b50d902SRodney W. Grimes 4809b50d902SRodney W. Grimes /* 4819b50d902SRodney W. Grimes * Pipe the message through the command. 4829b50d902SRodney W. Grimes * Old message is on stdin of command; 4839b50d902SRodney W. Grimes * New message collected from stdout. 4849b50d902SRodney W. Grimes * Sh -c must return 0 to accept the new message. 4859b50d902SRodney W. Grimes */ 4869b50d902SRodney W. Grimes void 4879b50d902SRodney W. Grimes mespipe(fp, cmd) 4889b50d902SRodney W. Grimes FILE *fp; 4899b50d902SRodney W. Grimes char cmd[]; 4909b50d902SRodney W. Grimes { 4919b50d902SRodney W. Grimes FILE *nf; 4920c3a8314SMike Heffner int fd; 4939b50d902SRodney W. Grimes sig_t sigint = signal(SIGINT, SIG_IGN); 4949ce73e90SMike Heffner char *sh, tempname[PATHSIZE]; 4959b50d902SRodney W. Grimes 4969ce73e90SMike Heffner (void)snprintf(tempname, sizeof(tempname), 4979ce73e90SMike Heffner "%s/mail.ReXXXXXXXXXX", tmpdir); 4980c3a8314SMike Heffner if ((fd = mkstemp(tempname)) == -1 || 4990c3a8314SMike Heffner (nf = Fdopen(fd, "w+")) == NULL) { 5000c3a8314SMike Heffner warn("%s", tempname); 5019b50d902SRodney W. Grimes goto out; 5029b50d902SRodney W. Grimes } 5030c3a8314SMike Heffner (void)rm(tempname); 5049b50d902SRodney W. Grimes /* 5059b50d902SRodney W. Grimes * stdin = current message. 5069b50d902SRodney W. Grimes * stdout = new message. 5079b50d902SRodney W. Grimes */ 5089ce73e90SMike Heffner if ((sh = value("SHELL")) == NULL) 5099ce73e90SMike Heffner sh = _PATH_CSHELL; 5109ce73e90SMike Heffner if (run_command(sh, 5119ce73e90SMike Heffner 0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) { 5129b50d902SRodney W. Grimes (void)Fclose(nf); 5139b50d902SRodney W. Grimes goto out; 5149b50d902SRodney W. Grimes } 5159b50d902SRodney W. Grimes if (fsize(nf) == 0) { 5169b50d902SRodney W. Grimes fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); 5179b50d902SRodney W. Grimes (void)Fclose(nf); 5189b50d902SRodney W. Grimes goto out; 5199b50d902SRodney W. Grimes } 5209b50d902SRodney W. Grimes /* 5219b50d902SRodney W. Grimes * Take new files. 5229b50d902SRodney W. Grimes */ 523af8c3262SAndrey A. Chernov (void)fseeko(nf, (off_t)0, SEEK_END); 5249b50d902SRodney W. Grimes collf = nf; 5259b50d902SRodney W. Grimes (void)Fclose(fp); 5269b50d902SRodney W. Grimes out: 5279b50d902SRodney W. Grimes (void)signal(SIGINT, sigint); 5289b50d902SRodney W. Grimes } 5299b50d902SRodney W. Grimes 5309b50d902SRodney W. Grimes /* 5319b50d902SRodney W. Grimes * Interpolate the named messages into the current 5329b50d902SRodney W. Grimes * message, preceding each line with a tab. 5339b50d902SRodney W. Grimes * Return a count of the number of characters now in 5349b50d902SRodney W. Grimes * the message, or -1 if an error is encountered writing 5359b50d902SRodney W. Grimes * the message temporary. The flag argument is 'm' if we 5369b50d902SRodney W. Grimes * should shift over and 'f' if not. 5379b50d902SRodney W. Grimes */ 5389b50d902SRodney W. Grimes int 5390c3a8314SMike Heffner forward(ms, fp, fn, f) 5409b50d902SRodney W. Grimes char ms[]; 5419b50d902SRodney W. Grimes FILE *fp; 5420c3a8314SMike Heffner char *fn; 5439b50d902SRodney W. Grimes int f; 5449b50d902SRodney W. Grimes { 5459ce73e90SMike Heffner int *msgvec; 5469b50d902SRodney W. Grimes struct ignoretab *ig; 5479b50d902SRodney W. Grimes char *tabst; 5489b50d902SRodney W. Grimes 5499ce73e90SMike Heffner msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec)); 5509ce73e90SMike Heffner if (msgvec == NULL) 5519b50d902SRodney W. Grimes return (0); 5529b50d902SRodney W. Grimes if (getmsglist(ms, msgvec, 0) < 0) 5539b50d902SRodney W. Grimes return (0); 5549b50d902SRodney W. Grimes if (*msgvec == 0) { 5559b50d902SRodney W. Grimes *msgvec = first(0, MMNORM); 556d030d2d2SPoul-Henning Kamp if (*msgvec == 0) { 5579b50d902SRodney W. Grimes printf("No appropriate messages\n"); 5589b50d902SRodney W. Grimes return (0); 5599b50d902SRodney W. Grimes } 560d030d2d2SPoul-Henning Kamp msgvec[1] = 0; 5619b50d902SRodney W. Grimes } 5629b50d902SRodney W. Grimes if (f == 'f' || f == 'F') 5639ce73e90SMike Heffner tabst = NULL; 5649ce73e90SMike Heffner else if ((tabst = value("indentprefix")) == NULL) 5659b50d902SRodney W. Grimes tabst = "\t"; 5666d48fa43SAndrey A. Chernov ig = isupper((unsigned char)f) ? NULL : ignore; 5679b50d902SRodney W. Grimes printf("Interpolating:"); 5689b50d902SRodney W. Grimes for (; *msgvec != 0; msgvec++) { 5699b50d902SRodney W. Grimes struct message *mp = message + *msgvec - 1; 5709b50d902SRodney W. Grimes 5719b50d902SRodney W. Grimes touch(mp); 5729b50d902SRodney W. Grimes printf(" %d", *msgvec); 5730c3a8314SMike Heffner if (sendmessage(mp, fp, ig, tabst) < 0) { 5740c3a8314SMike Heffner warnx("%s", fn); 5759b50d902SRodney W. Grimes return (-1); 5769b50d902SRodney W. Grimes } 5779b50d902SRodney W. Grimes } 5789b50d902SRodney W. Grimes printf("\n"); 5799b50d902SRodney W. Grimes return (0); 5809b50d902SRodney W. Grimes } 5819b50d902SRodney W. Grimes 5829b50d902SRodney W. Grimes /* 5839b50d902SRodney W. Grimes * Print (continue) when continued after ^Z. 5849b50d902SRodney W. Grimes */ 5859b50d902SRodney W. Grimes /*ARGSUSED*/ 5869b50d902SRodney W. Grimes void 5879b50d902SRodney W. Grimes collstop(s) 5889b50d902SRodney W. Grimes int s; 5899b50d902SRodney W. Grimes { 5909b50d902SRodney W. Grimes sig_t old_action = signal(s, SIG_DFL); 591856f23edSMike Heffner sigset_t nset; 5929b50d902SRodney W. Grimes 593856f23edSMike Heffner (void)sigemptyset(&nset); 594856f23edSMike Heffner (void)sigaddset(&nset, s); 595856f23edSMike Heffner (void)sigprocmask(SIG_UNBLOCK, &nset, NULL); 5969ce73e90SMike Heffner (void)kill(0, s); 597856f23edSMike Heffner (void)sigprocmask(SIG_BLOCK, &nset, NULL); 5989ce73e90SMike Heffner (void)signal(s, old_action); 5999b50d902SRodney W. Grimes if (colljmp_p) { 6009b50d902SRodney W. Grimes colljmp_p = 0; 6019b50d902SRodney W. Grimes hadintr = 0; 6029b50d902SRodney W. Grimes longjmp(colljmp, 1); 6039b50d902SRodney W. Grimes } 6049b50d902SRodney W. Grimes } 6059b50d902SRodney W. Grimes 6069b50d902SRodney W. Grimes /* 6079b50d902SRodney W. Grimes * On interrupt, come here to save the partial message in ~/dead.letter. 6089b50d902SRodney W. Grimes * Then jump out of the collection loop. 6099b50d902SRodney W. Grimes */ 6109b50d902SRodney W. Grimes /*ARGSUSED*/ 6119b50d902SRodney W. Grimes void 6129b50d902SRodney W. Grimes collint(s) 6139b50d902SRodney W. Grimes int s; 6149b50d902SRodney W. Grimes { 6159b50d902SRodney W. Grimes /* 6169b50d902SRodney W. Grimes * the control flow is subtle, because we can be called from ~q. 6179b50d902SRodney W. Grimes */ 6189b50d902SRodney W. Grimes if (!hadintr) { 6199ce73e90SMike Heffner if (value("ignore") != NULL) { 6209ce73e90SMike Heffner printf("@"); 6219ce73e90SMike Heffner (void)fflush(stdout); 6229b50d902SRodney W. Grimes clearerr(stdin); 6239b50d902SRodney W. Grimes return; 6249b50d902SRodney W. Grimes } 6259b50d902SRodney W. Grimes hadintr = 1; 6269b50d902SRodney W. Grimes longjmp(colljmp, 1); 6279b50d902SRodney W. Grimes } 6289b50d902SRodney W. Grimes rewind(collf); 6299ce73e90SMike Heffner if (value("nosave") == NULL) 6309b50d902SRodney W. Grimes savedeadletter(collf); 6319b50d902SRodney W. Grimes longjmp(collabort, 1); 6329b50d902SRodney W. Grimes } 6339b50d902SRodney W. Grimes 6349b50d902SRodney W. Grimes /*ARGSUSED*/ 6359b50d902SRodney W. Grimes void 6369b50d902SRodney W. Grimes collhup(s) 6379b50d902SRodney W. Grimes int s; 6389b50d902SRodney W. Grimes { 6399b50d902SRodney W. Grimes rewind(collf); 6409b50d902SRodney W. Grimes savedeadletter(collf); 6419b50d902SRodney W. Grimes /* 6429b50d902SRodney W. Grimes * Let's pretend nobody else wants to clean up, 6439b50d902SRodney W. Grimes * a true statement at this time. 6449b50d902SRodney W. Grimes */ 6459b50d902SRodney W. Grimes exit(1); 6469b50d902SRodney W. Grimes } 6479b50d902SRodney W. Grimes 6489b50d902SRodney W. Grimes void 6499b50d902SRodney W. Grimes savedeadletter(fp) 6509ce73e90SMike Heffner FILE *fp; 6519b50d902SRodney W. Grimes { 6529ce73e90SMike Heffner FILE *dbuf; 6539ce73e90SMike Heffner int c; 6549b50d902SRodney W. Grimes char *cp; 6559b50d902SRodney W. Grimes 6569b50d902SRodney W. Grimes if (fsize(fp) == 0) 6579b50d902SRodney W. Grimes return; 6589b50d902SRodney W. Grimes cp = getdeadletter(); 6599b50d902SRodney W. Grimes c = umask(077); 6609b50d902SRodney W. Grimes dbuf = Fopen(cp, "a"); 6619b50d902SRodney W. Grimes (void)umask(c); 6629b50d902SRodney W. Grimes if (dbuf == NULL) 6639b50d902SRodney W. Grimes return; 6649b50d902SRodney W. Grimes while ((c = getc(fp)) != EOF) 6659b50d902SRodney W. Grimes (void)putc(c, dbuf); 6669ce73e90SMike Heffner (void)Fclose(dbuf); 6679b50d902SRodney W. Grimes rewind(fp); 6689b50d902SRodney W. Grimes } 669