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; 839b50d902SRodney W. Grimes int omask; 849b50d902SRodney W. Grimes 859b50d902SRodney W. Grimes collf = NULL; 869b50d902SRodney W. Grimes /* 879b50d902SRodney W. Grimes * Start catching signals from here, but we're still die on interrupts 889b50d902SRodney W. Grimes * until we're in the main loop. 899b50d902SRodney W. Grimes */ 909b50d902SRodney W. Grimes omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); 919b50d902SRodney W. Grimes if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN) 929ce73e90SMike Heffner (void)signal(SIGINT, collint); 939b50d902SRodney W. Grimes if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN) 949ce73e90SMike Heffner (void)signal(SIGHUP, collhup); 959b50d902SRodney W. Grimes savetstp = signal(SIGTSTP, collstop); 969b50d902SRodney W. Grimes savettou = signal(SIGTTOU, collstop); 979b50d902SRodney W. Grimes savettin = signal(SIGTTIN, collstop); 989b50d902SRodney W. Grimes if (setjmp(collabort) || setjmp(colljmp)) { 999ce73e90SMike Heffner (void)rm(tempname); 1009b50d902SRodney W. Grimes goto err; 1019b50d902SRodney W. Grimes } 1029b50d902SRodney W. Grimes sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP))); 1039b50d902SRodney W. Grimes 1049b50d902SRodney W. Grimes noreset++; 1059ce73e90SMike Heffner (void)snprintf(tempname, sizeof(tempname), 1069ce73e90SMike Heffner "%s/mail.RsXXXXXXXXXX", tmpdir); 1070c3a8314SMike Heffner if ((fd = mkstemp(tempname)) == -1 || 1080c3a8314SMike Heffner (collf = Fdopen(fd, "w+")) == NULL) { 1090c3a8314SMike Heffner warn("%s", tempname); 1109b50d902SRodney W. Grimes goto err; 1119b50d902SRodney W. Grimes } 1129ce73e90SMike Heffner (void)rm(tempname); 1139b50d902SRodney W. Grimes 1149b50d902SRodney W. Grimes /* 1159b50d902SRodney W. Grimes * If we are going to prompt for a subject, 1169b50d902SRodney W. Grimes * refrain from printing a newline after 1179b50d902SRodney W. Grimes * the headers (since some people mind). 1189b50d902SRodney W. Grimes */ 1199b50d902SRodney W. Grimes t = GTO|GSUBJECT|GCC|GNL; 1209b50d902SRodney W. Grimes getsub = 0; 1219ce73e90SMike Heffner if (hp->h_subject == NULL && value("interactive") != NULL && 1229ce73e90SMike Heffner (value("ask") != NULL || value("asksub") != NULL)) 1239b50d902SRodney W. Grimes t &= ~GNL, getsub++; 1249b50d902SRodney W. Grimes if (printheaders) { 1259b50d902SRodney W. Grimes puthead(hp, stdout, t); 1269ce73e90SMike Heffner (void)fflush(stdout); 1279b50d902SRodney W. Grimes } 1289ce73e90SMike Heffner if ((cp = value("escape")) != NULL) 1299b50d902SRodney W. Grimes escape = *cp; 1309b50d902SRodney W. Grimes else 1319b50d902SRodney W. Grimes escape = ESCAPE; 1329b50d902SRodney W. Grimes eofcount = 0; 1339b50d902SRodney W. Grimes hadintr = 0; 1349b50d902SRodney W. Grimes 1359b50d902SRodney W. Grimes if (!setjmp(colljmp)) { 1369b50d902SRodney W. Grimes if (getsub) 1379b50d902SRodney W. Grimes grabh(hp, GSUBJECT); 1389b50d902SRodney W. Grimes } else { 1399b50d902SRodney W. Grimes /* 1409b50d902SRodney W. Grimes * Come here for printing the after-signal message. 1419b50d902SRodney W. Grimes * Duplicate messages won't be printed because 1429b50d902SRodney W. Grimes * the write is aborted if we get a SIGTTOU. 1439b50d902SRodney W. Grimes */ 1449b50d902SRodney W. Grimes cont: 1459b50d902SRodney W. Grimes if (hadintr) { 1469ce73e90SMike Heffner (void)fflush(stdout); 1479b50d902SRodney W. Grimes fprintf(stderr, 1489b50d902SRodney W. Grimes "\n(Interrupt -- one more to kill letter)\n"); 1499b50d902SRodney W. Grimes } else { 1509b50d902SRodney W. Grimes printf("(continue)\n"); 1519ce73e90SMike Heffner (void)fflush(stdout); 1529b50d902SRodney W. Grimes } 1539b50d902SRodney W. Grimes } 1549b50d902SRodney W. Grimes for (;;) { 1559b50d902SRodney W. Grimes colljmp_p = 1; 1569b50d902SRodney W. Grimes c = readline(stdin, linebuf, LINESIZE); 1579b50d902SRodney W. Grimes colljmp_p = 0; 1589b50d902SRodney W. Grimes if (c < 0) { 1599ce73e90SMike Heffner if (value("interactive") != NULL && 1609ce73e90SMike Heffner value("ignoreeof") != NULL && ++eofcount < 25) { 1619b50d902SRodney W. Grimes printf("Use \".\" to terminate letter\n"); 1629b50d902SRodney W. Grimes continue; 1639b50d902SRodney W. Grimes } 1649b50d902SRodney W. Grimes break; 1659b50d902SRodney W. Grimes } 1669b50d902SRodney W. Grimes eofcount = 0; 1679b50d902SRodney W. Grimes hadintr = 0; 1689b50d902SRodney W. Grimes if (linebuf[0] == '.' && linebuf[1] == '\0' && 1699ce73e90SMike Heffner value("interactive") != NULL && 1709ce73e90SMike Heffner (value("dot") != NULL || value("ignoreeof") != NULL)) 1719b50d902SRodney W. Grimes break; 1729ce73e90SMike Heffner if (linebuf[0] != escape || value("interactive") == NULL) { 1739b50d902SRodney W. Grimes if (putline(collf, linebuf) < 0) 1749b50d902SRodney W. Grimes goto err; 1759b50d902SRodney W. Grimes continue; 1769b50d902SRodney W. Grimes } 1779b50d902SRodney W. Grimes c = linebuf[1]; 1789b50d902SRodney W. Grimes switch (c) { 1799b50d902SRodney W. Grimes default: 1809b50d902SRodney W. Grimes /* 1819b50d902SRodney W. Grimes * On double escape, just send the single one. 1829b50d902SRodney W. Grimes * Otherwise, it's an error. 1839b50d902SRodney W. Grimes */ 1849b50d902SRodney W. Grimes if (c == escape) { 1859b50d902SRodney W. Grimes if (putline(collf, &linebuf[1]) < 0) 1869b50d902SRodney W. Grimes goto err; 1879b50d902SRodney W. Grimes else 1889b50d902SRodney W. Grimes break; 1899b50d902SRodney W. Grimes } 1909b50d902SRodney W. Grimes printf("Unknown tilde escape.\n"); 1919b50d902SRodney W. Grimes break; 1929b50d902SRodney W. Grimes case 'C': 1939b50d902SRodney W. Grimes /* 1949b50d902SRodney W. Grimes * Dump core. 1959b50d902SRodney W. Grimes */ 1969b50d902SRodney W. Grimes core(); 1979b50d902SRodney W. Grimes break; 1989b50d902SRodney W. Grimes case '!': 1999b50d902SRodney W. Grimes /* 2009b50d902SRodney W. Grimes * Shell escape, send the balance of the 2019b50d902SRodney W. Grimes * line to sh -c. 2029b50d902SRodney W. Grimes */ 2039b50d902SRodney W. Grimes shell(&linebuf[2]); 2049b50d902SRodney W. Grimes break; 2059b50d902SRodney W. Grimes case ':': 2069b50d902SRodney W. Grimes /* 2079b50d902SRodney W. Grimes * Escape to command mode, but be nice! 2089b50d902SRodney W. Grimes */ 2099b50d902SRodney W. Grimes execute(&linebuf[2], 1); 2109b50d902SRodney W. Grimes goto cont; 2119b50d902SRodney W. Grimes case '.': 2129b50d902SRodney W. Grimes /* 2139b50d902SRodney W. Grimes * Simulate end of file on input. 2149b50d902SRodney W. Grimes */ 2159b50d902SRodney W. Grimes goto out; 2169b50d902SRodney W. Grimes case 'q': 2179b50d902SRodney W. Grimes /* 2189b50d902SRodney W. Grimes * Force a quit of sending mail. 2199b50d902SRodney W. Grimes * Act like an interrupt happened. 2209b50d902SRodney W. Grimes */ 2219b50d902SRodney W. Grimes hadintr++; 2229b50d902SRodney W. Grimes collint(SIGINT); 2239b50d902SRodney W. Grimes exit(1); 2249b50d902SRodney W. Grimes case 'h': 2259b50d902SRodney W. Grimes /* 2269b50d902SRodney W. Grimes * Grab a bunch of headers. 2279b50d902SRodney W. Grimes */ 2289b50d902SRodney W. Grimes grabh(hp, GTO|GSUBJECT|GCC|GBCC); 2299b50d902SRodney W. Grimes goto cont; 2309b50d902SRodney W. Grimes case 't': 2319b50d902SRodney W. Grimes /* 2329b50d902SRodney W. Grimes * Add to the To list. 2339b50d902SRodney W. Grimes */ 2349b50d902SRodney W. Grimes hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO)); 2359b50d902SRodney W. Grimes break; 2369b50d902SRodney W. Grimes case 's': 2379b50d902SRodney W. Grimes /* 23899bd6601SJoerg Wunsch * Set the Subject line. 2399b50d902SRodney W. Grimes */ 2409b50d902SRodney W. Grimes cp = &linebuf[2]; 2419b50d902SRodney W. Grimes while (isspace(*cp)) 2429b50d902SRodney W. Grimes cp++; 2439b50d902SRodney W. Grimes hp->h_subject = savestr(cp); 2449b50d902SRodney W. Grimes break; 24599bd6601SJoerg Wunsch case 'R': 24699bd6601SJoerg Wunsch /* 24799bd6601SJoerg Wunsch * Set the Reply-To line. 24899bd6601SJoerg Wunsch */ 24999bd6601SJoerg Wunsch cp = &linebuf[2]; 25099bd6601SJoerg Wunsch while (isspace(*cp)) 25199bd6601SJoerg Wunsch cp++; 25299bd6601SJoerg Wunsch hp->h_replyto = savestr(cp); 25399bd6601SJoerg Wunsch break; 2549b50d902SRodney W. Grimes case 'c': 2559b50d902SRodney W. Grimes /* 2569b50d902SRodney W. Grimes * Add to the CC list. 2579b50d902SRodney W. Grimes */ 2589b50d902SRodney W. Grimes hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC)); 2599b50d902SRodney W. Grimes break; 2609b50d902SRodney W. Grimes case 'b': 2619b50d902SRodney W. Grimes /* 2629b50d902SRodney W. Grimes * Add stuff to blind carbon copies list. 2639b50d902SRodney W. Grimes */ 2649b50d902SRodney W. Grimes hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC)); 2659b50d902SRodney W. Grimes break; 2669b50d902SRodney W. Grimes case 'd': 2670c3a8314SMike Heffner if (strlcpy(linebuf + 2, getdeadletter(), sizeof(linebuf) - 2) 2680c3a8314SMike Heffner >= sizeof(linebuf) - 2) { 2690c3a8314SMike Heffner printf("Line buffer overflow\n"); 2700c3a8314SMike Heffner break; 2710c3a8314SMike Heffner } 2729b50d902SRodney W. Grimes /* fall into . . . */ 2739b50d902SRodney W. Grimes case 'r': 2749b50d902SRodney W. Grimes /* 2759b50d902SRodney W. Grimes * Invoke a file: 2769b50d902SRodney W. Grimes * Search for the file name, 2779b50d902SRodney W. Grimes * then open it and copy the contents to collf. 2789b50d902SRodney W. Grimes */ 2799b50d902SRodney W. Grimes cp = &linebuf[2]; 2809b50d902SRodney W. Grimes while (isspace(*cp)) 2819b50d902SRodney W. Grimes cp++; 2829b50d902SRodney W. Grimes if (*cp == '\0') { 2839b50d902SRodney W. Grimes printf("Interpolate what file?\n"); 2849b50d902SRodney W. Grimes break; 2859b50d902SRodney W. Grimes } 2869b50d902SRodney W. Grimes cp = expand(cp); 2879ce73e90SMike Heffner if (cp == NULL) 2889b50d902SRodney W. Grimes break; 2899b50d902SRodney W. Grimes if (isdir(cp)) { 2909b50d902SRodney W. Grimes printf("%s: Directory\n", cp); 2919b50d902SRodney W. Grimes break; 2929b50d902SRodney W. Grimes } 2939b50d902SRodney W. Grimes if ((fbuf = Fopen(cp, "r")) == NULL) { 2940c3a8314SMike Heffner warn("%s", cp); 2959b50d902SRodney W. Grimes break; 2969b50d902SRodney W. Grimes } 2979b50d902SRodney W. Grimes printf("\"%s\" ", cp); 2989ce73e90SMike Heffner (void)fflush(stdout); 2999b50d902SRodney W. Grimes lc = 0; 3009b50d902SRodney W. Grimes cc = 0; 3019b50d902SRodney W. Grimes while (readline(fbuf, linebuf, LINESIZE) >= 0) { 3029b50d902SRodney W. Grimes lc++; 3039b50d902SRodney W. Grimes if ((t = putline(collf, linebuf)) < 0) { 3049ce73e90SMike Heffner (void)Fclose(fbuf); 3059b50d902SRodney W. Grimes goto err; 3069b50d902SRodney W. Grimes } 3079b50d902SRodney W. Grimes cc += t; 3089b50d902SRodney W. Grimes } 3099ce73e90SMike Heffner (void)Fclose(fbuf); 3109b50d902SRodney W. Grimes printf("%d/%d\n", lc, cc); 3119b50d902SRodney W. Grimes break; 3129b50d902SRodney W. Grimes case 'w': 3139b50d902SRodney W. Grimes /* 3149b50d902SRodney W. Grimes * Write the message on a file. 3159b50d902SRodney W. Grimes */ 3169b50d902SRodney W. Grimes cp = &linebuf[2]; 3179b50d902SRodney W. Grimes while (*cp == ' ' || *cp == '\t') 3189b50d902SRodney W. Grimes cp++; 3199b50d902SRodney W. Grimes if (*cp == '\0') { 3209b50d902SRodney W. Grimes fprintf(stderr, "Write what file!?\n"); 3219b50d902SRodney W. Grimes break; 3229b50d902SRodney W. Grimes } 3239ce73e90SMike Heffner if ((cp = expand(cp)) == NULL) 3249b50d902SRodney W. Grimes break; 3259b50d902SRodney W. Grimes rewind(collf); 3269b50d902SRodney W. Grimes exwrite(cp, collf, 1); 3279b50d902SRodney W. Grimes break; 3289b50d902SRodney W. Grimes case 'm': 3299b50d902SRodney W. Grimes case 'M': 3309b50d902SRodney W. Grimes case 'f': 3319b50d902SRodney W. Grimes case 'F': 3329b50d902SRodney W. Grimes /* 3339b50d902SRodney W. Grimes * Interpolate the named messages, if we 3349b50d902SRodney W. Grimes * are in receiving mail mode. Does the 3359b50d902SRodney W. Grimes * standard list processing garbage. 3369b50d902SRodney W. Grimes * If ~f is given, we don't shift over. 3379b50d902SRodney W. Grimes */ 3380c3a8314SMike Heffner if (forward(linebuf + 2, collf, tempname, c) < 0) 3399b50d902SRodney W. Grimes goto err; 3409b50d902SRodney W. Grimes goto cont; 3419b50d902SRodney W. Grimes case '?': 3429b50d902SRodney W. Grimes if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) { 3430c3a8314SMike Heffner warn("%s", _PATH_TILDE); 3449b50d902SRodney W. Grimes break; 3459b50d902SRodney W. Grimes } 3469b50d902SRodney W. Grimes while ((t = getc(fbuf)) != EOF) 3479b50d902SRodney W. Grimes (void)putchar(t); 3489ce73e90SMike Heffner (void)Fclose(fbuf); 3499b50d902SRodney W. Grimes break; 3509b50d902SRodney W. Grimes case 'p': 3519b50d902SRodney W. Grimes /* 3529b50d902SRodney W. Grimes * Print out the current state of the 3539b50d902SRodney W. Grimes * message without altering anything. 3549b50d902SRodney W. Grimes */ 3559b50d902SRodney W. Grimes rewind(collf); 3569b50d902SRodney W. Grimes printf("-------\nMessage contains:\n"); 3579b50d902SRodney W. Grimes puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL); 3589b50d902SRodney W. Grimes while ((t = getc(collf)) != EOF) 3599b50d902SRodney W. Grimes (void)putchar(t); 3609b50d902SRodney W. Grimes goto cont; 3619b50d902SRodney W. Grimes case '|': 3629b50d902SRodney W. Grimes /* 3639b50d902SRodney W. Grimes * Pipe message through command. 3649b50d902SRodney W. Grimes * Collect output as new message. 3659b50d902SRodney W. Grimes */ 3669b50d902SRodney W. Grimes rewind(collf); 3679b50d902SRodney W. Grimes mespipe(collf, &linebuf[2]); 3689b50d902SRodney W. Grimes goto cont; 3699b50d902SRodney W. Grimes case 'v': 3709b50d902SRodney W. Grimes case 'e': 3719b50d902SRodney W. Grimes /* 3729b50d902SRodney W. Grimes * Edit the current message. 3739b50d902SRodney W. Grimes * 'e' means to use EDITOR 3749b50d902SRodney W. Grimes * 'v' means to use VISUAL 3759b50d902SRodney W. Grimes */ 3769b50d902SRodney W. Grimes rewind(collf); 3779b50d902SRodney W. Grimes mesedit(collf, c); 3789b50d902SRodney W. Grimes goto cont; 3799b50d902SRodney W. Grimes } 3809b50d902SRodney W. Grimes } 3819b50d902SRodney W. Grimes goto out; 3829b50d902SRodney W. Grimes err: 3839b50d902SRodney W. Grimes if (collf != NULL) { 3849ce73e90SMike Heffner (void)Fclose(collf); 3859b50d902SRodney W. Grimes collf = NULL; 3869b50d902SRodney W. Grimes } 3879b50d902SRodney W. Grimes out: 3889b50d902SRodney W. Grimes if (collf != NULL) 3899b50d902SRodney W. Grimes rewind(collf); 3909b50d902SRodney W. Grimes noreset--; 3919ce73e90SMike Heffner (void)sigblock(sigmask(SIGINT) | sigmask(SIGHUP)); 3929ce73e90SMike Heffner (void)signal(SIGINT, saveint); 3939ce73e90SMike Heffner (void)signal(SIGHUP, savehup); 3949ce73e90SMike Heffner (void)signal(SIGTSTP, savetstp); 3959ce73e90SMike Heffner (void)signal(SIGTTOU, savettou); 3969ce73e90SMike Heffner (void)signal(SIGTTIN, savettin); 3979ce73e90SMike Heffner (void)sigsetmask(omask); 3989ce73e90SMike Heffner return (collf); 3999b50d902SRodney W. Grimes } 4009b50d902SRodney W. Grimes 4019b50d902SRodney W. Grimes /* 4029b50d902SRodney W. Grimes * Write a file, ex-like if f set. 4039b50d902SRodney W. Grimes */ 4049b50d902SRodney W. Grimes int 4059b50d902SRodney W. Grimes exwrite(name, fp, f) 4069b50d902SRodney W. Grimes char name[]; 4079b50d902SRodney W. Grimes FILE *fp; 4089b50d902SRodney W. Grimes int f; 4099b50d902SRodney W. Grimes { 4109ce73e90SMike Heffner FILE *of; 4119ce73e90SMike Heffner int c, lc; 4129b50d902SRodney W. Grimes long cc; 4139b50d902SRodney W. Grimes struct stat junk; 4149b50d902SRodney W. Grimes 4159b50d902SRodney W. Grimes if (f) { 4169b50d902SRodney W. Grimes printf("\"%s\" ", name); 4179ce73e90SMike Heffner (void)fflush(stdout); 4189b50d902SRodney W. Grimes } 4190c3a8314SMike Heffner if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) { 4209b50d902SRodney W. Grimes if (!f) 4219b50d902SRodney W. Grimes fprintf(stderr, "%s: ", name); 4229b50d902SRodney W. Grimes fprintf(stderr, "File exists\n"); 4239b50d902SRodney W. Grimes return (-1); 4249b50d902SRodney W. Grimes } 4259b50d902SRodney W. Grimes if ((of = Fopen(name, "w")) == NULL) { 4269ce73e90SMike Heffner warn((char *)NULL); 4279b50d902SRodney W. Grimes return (-1); 4289b50d902SRodney W. Grimes } 4299b50d902SRodney W. Grimes lc = 0; 4309b50d902SRodney W. Grimes cc = 0; 4319b50d902SRodney W. Grimes while ((c = getc(fp)) != EOF) { 4329b50d902SRodney W. Grimes cc++; 4339b50d902SRodney W. Grimes if (c == '\n') 4349b50d902SRodney W. Grimes lc++; 4359b50d902SRodney W. Grimes (void)putc(c, of); 4369b50d902SRodney W. Grimes if (ferror(of)) { 4370c3a8314SMike Heffner warnx("%s", name); 4389ce73e90SMike Heffner (void)Fclose(of); 4399b50d902SRodney W. Grimes return (-1); 4409b50d902SRodney W. Grimes } 4419b50d902SRodney W. Grimes } 4429ce73e90SMike Heffner (void)Fclose(of); 4439b50d902SRodney W. Grimes printf("%d/%ld\n", lc, cc); 4449ce73e90SMike Heffner (void)fflush(stdout); 4459b50d902SRodney W. Grimes return (0); 4469b50d902SRodney W. Grimes } 4479b50d902SRodney W. Grimes 4489b50d902SRodney W. Grimes /* 4499b50d902SRodney W. Grimes * Edit the message being collected on fp. 4509b50d902SRodney W. Grimes * On return, make the edit file the new temp file. 4519b50d902SRodney W. Grimes */ 4529b50d902SRodney W. Grimes void 4539b50d902SRodney W. Grimes mesedit(fp, c) 4549b50d902SRodney W. Grimes FILE *fp; 4559b50d902SRodney W. Grimes int c; 4569b50d902SRodney W. Grimes { 4579b50d902SRodney W. Grimes sig_t sigint = signal(SIGINT, SIG_IGN); 4589b50d902SRodney W. Grimes FILE *nf = run_editor(fp, (off_t)-1, c, 0); 4599b50d902SRodney W. Grimes 4609b50d902SRodney W. Grimes if (nf != NULL) { 4619ce73e90SMike Heffner (void)fseek(nf, 0L, 2); 4629b50d902SRodney W. Grimes collf = nf; 4639ce73e90SMike Heffner (void)Fclose(fp); 4649b50d902SRodney W. Grimes } 4659b50d902SRodney W. Grimes (void)signal(SIGINT, sigint); 4669b50d902SRodney W. Grimes } 4679b50d902SRodney W. Grimes 4689b50d902SRodney W. Grimes /* 4699b50d902SRodney W. Grimes * Pipe the message through the command. 4709b50d902SRodney W. Grimes * Old message is on stdin of command; 4719b50d902SRodney W. Grimes * New message collected from stdout. 4729b50d902SRodney W. Grimes * Sh -c must return 0 to accept the new message. 4739b50d902SRodney W. Grimes */ 4749b50d902SRodney W. Grimes void 4759b50d902SRodney W. Grimes mespipe(fp, cmd) 4769b50d902SRodney W. Grimes FILE *fp; 4779b50d902SRodney W. Grimes char cmd[]; 4789b50d902SRodney W. Grimes { 4799b50d902SRodney W. Grimes FILE *nf; 4800c3a8314SMike Heffner int fd; 4819b50d902SRodney W. Grimes sig_t sigint = signal(SIGINT, SIG_IGN); 4829ce73e90SMike Heffner char *sh, tempname[PATHSIZE]; 4839b50d902SRodney W. Grimes 4849ce73e90SMike Heffner (void)snprintf(tempname, sizeof(tempname), 4859ce73e90SMike Heffner "%s/mail.ReXXXXXXXXXX", tmpdir); 4860c3a8314SMike Heffner if ((fd = mkstemp(tempname)) == -1 || 4870c3a8314SMike Heffner (nf = Fdopen(fd, "w+")) == NULL) { 4880c3a8314SMike Heffner warn("%s", tempname); 4899b50d902SRodney W. Grimes goto out; 4909b50d902SRodney W. Grimes } 4910c3a8314SMike Heffner (void)rm(tempname); 4929b50d902SRodney W. Grimes /* 4939b50d902SRodney W. Grimes * stdin = current message. 4949b50d902SRodney W. Grimes * stdout = new message. 4959b50d902SRodney W. Grimes */ 4969ce73e90SMike Heffner if ((sh = value("SHELL")) == NULL) 4979ce73e90SMike Heffner sh = _PATH_CSHELL; 4989ce73e90SMike Heffner if (run_command(sh, 4999ce73e90SMike Heffner 0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) { 5009b50d902SRodney W. Grimes (void)Fclose(nf); 5019b50d902SRodney W. Grimes goto out; 5029b50d902SRodney W. Grimes } 5039b50d902SRodney W. Grimes if (fsize(nf) == 0) { 5049b50d902SRodney W. Grimes fprintf(stderr, "No bytes from \"%s\" !?\n", cmd); 5059b50d902SRodney W. Grimes (void)Fclose(nf); 5069b50d902SRodney W. Grimes goto out; 5079b50d902SRodney W. Grimes } 5089b50d902SRodney W. Grimes /* 5099b50d902SRodney W. Grimes * Take new files. 5109b50d902SRodney W. Grimes */ 5119b50d902SRodney W. Grimes (void)fseek(nf, 0L, 2); 5129b50d902SRodney W. Grimes collf = nf; 5139b50d902SRodney W. Grimes (void)Fclose(fp); 5149b50d902SRodney W. Grimes out: 5159b50d902SRodney W. Grimes (void)signal(SIGINT, sigint); 5169b50d902SRodney W. Grimes } 5179b50d902SRodney W. Grimes 5189b50d902SRodney W. Grimes /* 5199b50d902SRodney W. Grimes * Interpolate the named messages into the current 5209b50d902SRodney W. Grimes * message, preceding each line with a tab. 5219b50d902SRodney W. Grimes * Return a count of the number of characters now in 5229b50d902SRodney W. Grimes * the message, or -1 if an error is encountered writing 5239b50d902SRodney W. Grimes * the message temporary. The flag argument is 'm' if we 5249b50d902SRodney W. Grimes * should shift over and 'f' if not. 5259b50d902SRodney W. Grimes */ 5269b50d902SRodney W. Grimes int 5270c3a8314SMike Heffner forward(ms, fp, fn, f) 5289b50d902SRodney W. Grimes char ms[]; 5299b50d902SRodney W. Grimes FILE *fp; 5300c3a8314SMike Heffner char *fn; 5319b50d902SRodney W. Grimes int f; 5329b50d902SRodney W. Grimes { 5339ce73e90SMike Heffner int *msgvec; 5349b50d902SRodney W. Grimes struct ignoretab *ig; 5359b50d902SRodney W. Grimes char *tabst; 5369b50d902SRodney W. Grimes 5379ce73e90SMike Heffner msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec)); 5389ce73e90SMike Heffner if (msgvec == NULL) 5399b50d902SRodney W. Grimes return (0); 5409b50d902SRodney W. Grimes if (getmsglist(ms, msgvec, 0) < 0) 5419b50d902SRodney W. Grimes return (0); 5429b50d902SRodney W. Grimes if (*msgvec == 0) { 5439b50d902SRodney W. Grimes *msgvec = first(0, MMNORM); 544d030d2d2SPoul-Henning Kamp if (*msgvec == 0) { 5459b50d902SRodney W. Grimes printf("No appropriate messages\n"); 5469b50d902SRodney W. Grimes return (0); 5479b50d902SRodney W. Grimes } 548d030d2d2SPoul-Henning Kamp msgvec[1] = 0; 5499b50d902SRodney W. Grimes } 5509b50d902SRodney W. Grimes if (f == 'f' || f == 'F') 5519ce73e90SMike Heffner tabst = NULL; 5529ce73e90SMike Heffner else if ((tabst = value("indentprefix")) == NULL) 5539b50d902SRodney W. Grimes tabst = "\t"; 5549b50d902SRodney W. Grimes ig = isupper(f) ? NULL : ignore; 5559b50d902SRodney W. Grimes printf("Interpolating:"); 5569b50d902SRodney W. Grimes for (; *msgvec != 0; msgvec++) { 5579b50d902SRodney W. Grimes struct message *mp = message + *msgvec - 1; 5589b50d902SRodney W. Grimes 5599b50d902SRodney W. Grimes touch(mp); 5609b50d902SRodney W. Grimes printf(" %d", *msgvec); 5610c3a8314SMike Heffner if (sendmessage(mp, fp, ig, tabst) < 0) { 5620c3a8314SMike Heffner warnx("%s", fn); 5639b50d902SRodney W. Grimes return (-1); 5649b50d902SRodney W. Grimes } 5659b50d902SRodney W. Grimes } 5669b50d902SRodney W. Grimes printf("\n"); 5679b50d902SRodney W. Grimes return (0); 5689b50d902SRodney W. Grimes } 5699b50d902SRodney W. Grimes 5709b50d902SRodney W. Grimes /* 5719b50d902SRodney W. Grimes * Print (continue) when continued after ^Z. 5729b50d902SRodney W. Grimes */ 5739b50d902SRodney W. Grimes /*ARGSUSED*/ 5749b50d902SRodney W. Grimes void 5759b50d902SRodney W. Grimes collstop(s) 5769b50d902SRodney W. Grimes int s; 5779b50d902SRodney W. Grimes { 5789b50d902SRodney W. Grimes sig_t old_action = signal(s, SIG_DFL); 5799b50d902SRodney W. Grimes 5809ce73e90SMike Heffner (void)sigsetmask(sigblock(0) & ~sigmask(s)); 5819ce73e90SMike Heffner (void)kill(0, s); 5829ce73e90SMike Heffner (void)sigblock(sigmask(s)); 5839ce73e90SMike Heffner (void)signal(s, old_action); 5849b50d902SRodney W. Grimes if (colljmp_p) { 5859b50d902SRodney W. Grimes colljmp_p = 0; 5869b50d902SRodney W. Grimes hadintr = 0; 5879b50d902SRodney W. Grimes longjmp(colljmp, 1); 5889b50d902SRodney W. Grimes } 5899b50d902SRodney W. Grimes } 5909b50d902SRodney W. Grimes 5919b50d902SRodney W. Grimes /* 5929b50d902SRodney W. Grimes * On interrupt, come here to save the partial message in ~/dead.letter. 5939b50d902SRodney W. Grimes * Then jump out of the collection loop. 5949b50d902SRodney W. Grimes */ 5959b50d902SRodney W. Grimes /*ARGSUSED*/ 5969b50d902SRodney W. Grimes void 5979b50d902SRodney W. Grimes collint(s) 5989b50d902SRodney W. Grimes int s; 5999b50d902SRodney W. Grimes { 6009b50d902SRodney W. Grimes /* 6019b50d902SRodney W. Grimes * the control flow is subtle, because we can be called from ~q. 6029b50d902SRodney W. Grimes */ 6039b50d902SRodney W. Grimes if (!hadintr) { 6049ce73e90SMike Heffner if (value("ignore") != NULL) { 6059ce73e90SMike Heffner printf("@"); 6069ce73e90SMike Heffner (void)fflush(stdout); 6079b50d902SRodney W. Grimes clearerr(stdin); 6089b50d902SRodney W. Grimes return; 6099b50d902SRodney W. Grimes } 6109b50d902SRodney W. Grimes hadintr = 1; 6119b50d902SRodney W. Grimes longjmp(colljmp, 1); 6129b50d902SRodney W. Grimes } 6139b50d902SRodney W. Grimes rewind(collf); 6149ce73e90SMike Heffner if (value("nosave") == NULL) 6159b50d902SRodney W. Grimes savedeadletter(collf); 6169b50d902SRodney W. Grimes longjmp(collabort, 1); 6179b50d902SRodney W. Grimes } 6189b50d902SRodney W. Grimes 6199b50d902SRodney W. Grimes /*ARGSUSED*/ 6209b50d902SRodney W. Grimes void 6219b50d902SRodney W. Grimes collhup(s) 6229b50d902SRodney W. Grimes int s; 6239b50d902SRodney W. Grimes { 6249b50d902SRodney W. Grimes rewind(collf); 6259b50d902SRodney W. Grimes savedeadletter(collf); 6269b50d902SRodney W. Grimes /* 6279b50d902SRodney W. Grimes * Let's pretend nobody else wants to clean up, 6289b50d902SRodney W. Grimes * a true statement at this time. 6299b50d902SRodney W. Grimes */ 6309b50d902SRodney W. Grimes exit(1); 6319b50d902SRodney W. Grimes } 6329b50d902SRodney W. Grimes 6339b50d902SRodney W. Grimes void 6349b50d902SRodney W. Grimes savedeadletter(fp) 6359ce73e90SMike Heffner FILE *fp; 6369b50d902SRodney W. Grimes { 6379ce73e90SMike Heffner FILE *dbuf; 6389ce73e90SMike Heffner int c; 6399b50d902SRodney W. Grimes char *cp; 6409b50d902SRodney W. Grimes 6419b50d902SRodney W. Grimes if (fsize(fp) == 0) 6429b50d902SRodney W. Grimes return; 6439b50d902SRodney W. Grimes cp = getdeadletter(); 6449b50d902SRodney W. Grimes c = umask(077); 6459b50d902SRodney W. Grimes dbuf = Fopen(cp, "a"); 6469b50d902SRodney W. Grimes (void)umask(c); 6479b50d902SRodney W. Grimes if (dbuf == NULL) 6489b50d902SRodney W. Grimes return; 6499b50d902SRodney W. Grimes while ((c = getc(fp)) != EOF) 6509b50d902SRodney W. Grimes (void)putc(c, dbuf); 6519ce73e90SMike Heffner (void)Fclose(dbuf); 6529b50d902SRodney W. Grimes rewind(fp); 6539b50d902SRodney W. Grimes } 654