10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*13093SRoger.Faulkner@Oracle.COM * Common Development and Distribution License (the "License").
6*13093SRoger.Faulkner@Oracle.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
21*13093SRoger.Faulkner@Oracle.COM
220Sstevel@tonic-gate /*
23*13093SRoger.Faulkner@Oracle.COM * Copyright (c) 1985, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
270Sstevel@tonic-gate /* All Rights Reserved */
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
310Sstevel@tonic-gate * The Regents of the University of California
320Sstevel@tonic-gate * All Rights Reserved
330Sstevel@tonic-gate *
340Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
350Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
360Sstevel@tonic-gate * contributors.
370Sstevel@tonic-gate */
380Sstevel@tonic-gate
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate * mailx -- a modified version of a University of California at Berkeley
410Sstevel@tonic-gate * mail program
420Sstevel@tonic-gate *
430Sstevel@tonic-gate * Collect input from standard input, handling
440Sstevel@tonic-gate * ~ escapes.
450Sstevel@tonic-gate */
460Sstevel@tonic-gate
470Sstevel@tonic-gate #include "rcv.h"
480Sstevel@tonic-gate #include <locale.h>
490Sstevel@tonic-gate
500Sstevel@tonic-gate #ifdef SIGCONT
510Sstevel@tonic-gate static void collcont(int);
520Sstevel@tonic-gate #endif
530Sstevel@tonic-gate static void collrub(int s);
540Sstevel@tonic-gate static void cpout(char *str, FILE *ofd);
550Sstevel@tonic-gate static int exwrite(char name[], FILE *ibuf);
560Sstevel@tonic-gate static int forward(char ms[], FILE *obuf, int f);
570Sstevel@tonic-gate static void intack(int);
580Sstevel@tonic-gate static int forward(char ms[], FILE *obuf, int f);
590Sstevel@tonic-gate static FILE *mesedit(FILE *ibuf, FILE *obuf, int c, struct header *hp);
600Sstevel@tonic-gate static FILE *mespipe(FILE *ibuf, FILE *obuf, char cmd[]);
610Sstevel@tonic-gate static void resetsigs(int resethup);
620Sstevel@tonic-gate static int stripnulls(register char *linebuf, register int nread);
630Sstevel@tonic-gate static void xhalt(void);
640Sstevel@tonic-gate static char **Xaddone(char **hf, char news[]);
650Sstevel@tonic-gate static int tabputs(const char *line, FILE *obuf);
660Sstevel@tonic-gate
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate * Read a message from standard output and return a read file to it
690Sstevel@tonic-gate * or NULL on error.
700Sstevel@tonic-gate */
710Sstevel@tonic-gate
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate * The following hokiness with global variables is so that on
740Sstevel@tonic-gate * receipt of an interrupt signal, the partial message can be salted
750Sstevel@tonic-gate * away on dead.letter. The output file must be available to flush,
760Sstevel@tonic-gate * and the input to read. Several open files could be saved all through
770Sstevel@tonic-gate * mailx if stdio allowed simultaneous read/write access.
780Sstevel@tonic-gate */
790Sstevel@tonic-gate
800Sstevel@tonic-gate static void (*savesig)(int); /* Previous SIGINT value */
810Sstevel@tonic-gate static void (*savehup)(int); /* Previous SIGHUP value */
820Sstevel@tonic-gate #ifdef SIGCONT
830Sstevel@tonic-gate static void (*savecont)(int); /* Previous SIGCONT value */
840Sstevel@tonic-gate #endif
850Sstevel@tonic-gate static FILE *newi; /* File for saving away */
860Sstevel@tonic-gate static FILE *newo; /* Output side of same */
870Sstevel@tonic-gate static int ignintr; /* Ignore interrups */
880Sstevel@tonic-gate static int hadintr; /* Have seen one SIGINT so far */
890Sstevel@tonic-gate static struct header *savehp;
900Sstevel@tonic-gate static jmp_buf coljmp; /* To get back to work */
910Sstevel@tonic-gate
920Sstevel@tonic-gate FILE *
collect(struct header * hp)930Sstevel@tonic-gate collect(struct header *hp)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate FILE *ibuf, *fbuf, *obuf;
960Sstevel@tonic-gate int escape, eof;
970Sstevel@tonic-gate long lc, cc;
980Sstevel@tonic-gate register int c, t;
990Sstevel@tonic-gate int hdrs;
1000Sstevel@tonic-gate char linebuf[LINESIZE+1], *cp;
1010Sstevel@tonic-gate char *iprompt;
1020Sstevel@tonic-gate int inhead;
1030Sstevel@tonic-gate void (*sigpipe)(int), (*sigint)(int);
1040Sstevel@tonic-gate int fd = -1;
1050Sstevel@tonic-gate
1060Sstevel@tonic-gate noreset++;
1070Sstevel@tonic-gate ibuf = obuf = NULL;
1080Sstevel@tonic-gate newi = newo = NULL;
1090Sstevel@tonic-gate if ((fd = open(tempMail, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
1100Sstevel@tonic-gate (obuf = fdopen(fd, "w")) == NULL) {
1110Sstevel@tonic-gate perror(tempMail);
1120Sstevel@tonic-gate goto err;
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate newo = obuf;
1150Sstevel@tonic-gate if ((ibuf = fopen(tempMail, "r")) == NULL) {
1160Sstevel@tonic-gate perror(tempMail);
1170Sstevel@tonic-gate newo = NULL;
1180Sstevel@tonic-gate fclose(obuf);
1190Sstevel@tonic-gate goto err;
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate newi = ibuf;
1220Sstevel@tonic-gate removefile(tempMail);
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate ignintr = (int)value("ignore");
1250Sstevel@tonic-gate hadintr = 1;
1260Sstevel@tonic-gate inhead = 1;
1270Sstevel@tonic-gate savehp = hp;
1280Sstevel@tonic-gate # ifdef VMUNIX
1290Sstevel@tonic-gate if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
1300Sstevel@tonic-gate sigset(SIGINT, ignintr ? intack : collrub), sigblock(sigmask(SIGINT));
1310Sstevel@tonic-gate if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN)
1320Sstevel@tonic-gate sigset(SIGHUP, collrub), sigblock(sigmask(SIGHUP));
13318Srobbin # else /* VMUNIX */
1340Sstevel@tonic-gate # ifdef OLD_BSD_SIGS
1350Sstevel@tonic-gate if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
1360Sstevel@tonic-gate sigset(SIGINT, ignintr ? intack : collrub);
1370Sstevel@tonic-gate if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN)
1380Sstevel@tonic-gate sigset(SIGHUP, collrub);
1390Sstevel@tonic-gate # else
1400Sstevel@tonic-gate if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN) {
1410Sstevel@tonic-gate sigset_t mask;
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate sigemptyset(&mask);
1440Sstevel@tonic-gate sigaddset(&mask, SIGINT);
1450Sstevel@tonic-gate sigset(SIGINT, ignintr ? intack : collrub);
1460Sstevel@tonic-gate sigprocmask(SIG_BLOCK, &mask, NULL);
1470Sstevel@tonic-gate }
1480Sstevel@tonic-gate if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN) {
1490Sstevel@tonic-gate sigset_t mask;
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate sigemptyset(&mask);
1520Sstevel@tonic-gate sigaddset(&mask, SIGHUP);
1530Sstevel@tonic-gate sigset(SIGHUP, collrub);
1540Sstevel@tonic-gate sigprocmask(SIG_BLOCK, &mask, NULL);
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate # endif
15718Srobbin # endif /* VMUNIX */
1580Sstevel@tonic-gate #ifdef SIGCONT
1590Sstevel@tonic-gate savecont = sigset(SIGCONT, collcont);
1600Sstevel@tonic-gate #endif
1610Sstevel@tonic-gate /*
1620Sstevel@tonic-gate * If we are going to prompt for subject/cc/bcc,
1630Sstevel@tonic-gate * refrain from printing a newline after
1640Sstevel@tonic-gate * the headers (since some people mind).
1650Sstevel@tonic-gate */
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate if (hp->h_subject == NOSTR) {
1680Sstevel@tonic-gate hp->h_subject = sflag;
1690Sstevel@tonic-gate sflag = NOSTR;
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate if (hp->h_cc == NOSTR) {
1720Sstevel@tonic-gate hp->h_cc = cflag;
1730Sstevel@tonic-gate cflag = NOSTR;
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate if (hp->h_bcc == NOSTR) {
1760Sstevel@tonic-gate hp->h_bcc = bflag;
1770Sstevel@tonic-gate bflag = NOSTR;
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate t = GMASK;
1800Sstevel@tonic-gate hdrs = 0;
1810Sstevel@tonic-gate if (intty && !tflag) {
1820Sstevel@tonic-gate if (hp->h_to == NOSTR)
1830Sstevel@tonic-gate hdrs |= GTO;
1840Sstevel@tonic-gate if (hp->h_subject == NOSTR && value("asksub"))
1850Sstevel@tonic-gate hdrs |= GSUBJECT;
1860Sstevel@tonic-gate if (hp->h_cc == NOSTR && value("askcc"))
1870Sstevel@tonic-gate hdrs |= GCC;
1880Sstevel@tonic-gate if (hp->h_bcc == NOSTR && value("askbcc"))
1890Sstevel@tonic-gate hdrs |= GBCC;
1900Sstevel@tonic-gate if (hdrs)
1910Sstevel@tonic-gate t &= ~GNL;
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate if (hp->h_seq != 0) {
1940Sstevel@tonic-gate puthead(hp, stdout, t, 0);
1950Sstevel@tonic-gate fflush(stdout);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate if (setjmp(coljmp))
1980Sstevel@tonic-gate goto err;
1990Sstevel@tonic-gate escape = SENDESC;
2000Sstevel@tonic-gate if ((cp = value("escape")) != NOSTR)
2010Sstevel@tonic-gate escape = *cp;
2020Sstevel@tonic-gate eof = 0;
2030Sstevel@tonic-gate if ((cp = value("MAILX_HEAD")) != NOSTR) {
2040Sstevel@tonic-gate cpout( cp, obuf);
2050Sstevel@tonic-gate if (isatty(fileno(stdin)))
2060Sstevel@tonic-gate cpout( cp, stdout);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate iprompt = value("iprompt");
2090Sstevel@tonic-gate fflush(obuf);
2100Sstevel@tonic-gate hadintr = 0;
2110Sstevel@tonic-gate for (;;) {
2120Sstevel@tonic-gate int nread, hasnulls;
2130Sstevel@tonic-gate # ifdef VMUNIX
2140Sstevel@tonic-gate int omask = sigblock(0) &~ (sigmask(SIGINT)|sigmask(SIGHUP));
2150Sstevel@tonic-gate # else
2160Sstevel@tonic-gate # ifndef OLD_BSD_SIGS
2170Sstevel@tonic-gate sigset_t omask;
2180Sstevel@tonic-gate sigprocmask(0, NULL, &omask);
2190Sstevel@tonic-gate sigdelset(&omask, SIGINT);
2200Sstevel@tonic-gate sigdelset(&omask, SIGHUP);
2210Sstevel@tonic-gate # endif
2220Sstevel@tonic-gate # endif
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate setjmp(coljmp);
2250Sstevel@tonic-gate # ifdef VMUNIX
2260Sstevel@tonic-gate sigsetmask(omask);
22718Srobbin # else /* VMUNIX */
2280Sstevel@tonic-gate # ifdef OLD_BSD_SIGS
2290Sstevel@tonic-gate sigrelse(SIGINT);
2300Sstevel@tonic-gate sigrelse(SIGHUP);
2310Sstevel@tonic-gate # else
2320Sstevel@tonic-gate sigprocmask(SIG_SETMASK, &omask, NULL);
2330Sstevel@tonic-gate # endif
23418Srobbin # endif /* VMUNIX */
2350Sstevel@tonic-gate if (intty && !tflag && outtty && iprompt)
2360Sstevel@tonic-gate fputs(iprompt, stdout);
2370Sstevel@tonic-gate flush();
2380Sstevel@tonic-gate if (hdrs) {
2390Sstevel@tonic-gate grabh(hp, hdrs, 1);
2400Sstevel@tonic-gate hdrs = 0;
2410Sstevel@tonic-gate continue;
2420Sstevel@tonic-gate }
243*13093SRoger.Faulkner@Oracle.COM if ((nread = getaline(linebuf,LINESIZE,stdin,&hasnulls)) == NULL) {
2440Sstevel@tonic-gate if (intty && value("ignoreeof") != NOSTR) {
2450Sstevel@tonic-gate if (++eof > 35)
2460Sstevel@tonic-gate break;
2470Sstevel@tonic-gate printf(gettext(
2480Sstevel@tonic-gate "Use \".\" to terminate letter\n"));
2490Sstevel@tonic-gate continue;
2500Sstevel@tonic-gate }
2510Sstevel@tonic-gate break;
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate eof = 0;
2540Sstevel@tonic-gate hadintr = 0;
2550Sstevel@tonic-gate if (intty && equal(".\n", linebuf) &&
2560Sstevel@tonic-gate (value("dot") != NOSTR || value("ignoreeof") != NOSTR))
2570Sstevel@tonic-gate break;
2580Sstevel@tonic-gate /*
2590Sstevel@tonic-gate * If -t, scan text for headers.
2600Sstevel@tonic-gate */
2610Sstevel@tonic-gate if (tflag) {
2620Sstevel@tonic-gate char *cp2;
2630Sstevel@tonic-gate
2640Sstevel@tonic-gate if (!inhead) {
2650Sstevel@tonic-gate writeit:
2660Sstevel@tonic-gate if (write(fileno(obuf),linebuf,nread) != nread)
2670Sstevel@tonic-gate goto werr;
2680Sstevel@tonic-gate continue;
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate if (linebuf[0] == '\n') {
2710Sstevel@tonic-gate /* got blank line after header, ignore it */
2720Sstevel@tonic-gate inhead = 0;
2730Sstevel@tonic-gate continue;
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate if (!headerp(linebuf)) {
2760Sstevel@tonic-gate /* got non-header line, save it */
2770Sstevel@tonic-gate inhead = 0;
2780Sstevel@tonic-gate goto writeit;
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate if (hasnulls)
2810Sstevel@tonic-gate nread = stripnulls(linebuf, nread);
2820Sstevel@tonic-gate for (;;) {
2830Sstevel@tonic-gate char line2[LINESIZE];
2840Sstevel@tonic-gate
2850Sstevel@tonic-gate c = getc(stdin);
2860Sstevel@tonic-gate ungetc(c, stdin);
2870Sstevel@tonic-gate if (!isspace(c) || c == '\n')
2880Sstevel@tonic-gate break;
2890Sstevel@tonic-gate if (readline(stdin, line2) < 0)
2900Sstevel@tonic-gate break;
2910Sstevel@tonic-gate for (cp2 = line2; *cp2 != 0 && isspace(*cp2);
2920Sstevel@tonic-gate cp2++)
2930Sstevel@tonic-gate ;
2940Sstevel@tonic-gate if (strlen(linebuf) + strlen(cp2) >=
2950Sstevel@tonic-gate (unsigned)LINESIZE-2)
2960Sstevel@tonic-gate break;
2970Sstevel@tonic-gate cp = &linebuf[strlen(linebuf)];
2980Sstevel@tonic-gate while (cp > linebuf &&
2990Sstevel@tonic-gate (isspace(cp[-1]) || cp[-1] == '\\'))
3000Sstevel@tonic-gate cp--;
3010Sstevel@tonic-gate *cp++ = ' ';
3020Sstevel@tonic-gate strcpy(cp, cp2);
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate if ((c = strlen(linebuf)) > 0) {
3050Sstevel@tonic-gate cp = &linebuf[c-1];
3060Sstevel@tonic-gate while (cp > linebuf && isspace(*cp))
3070Sstevel@tonic-gate cp--;
3080Sstevel@tonic-gate *++cp = 0;
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate if (ishfield(linebuf, "to"))
3110Sstevel@tonic-gate hp->h_to = addto(hp->h_to, hcontents(linebuf));
3120Sstevel@tonic-gate else if (ishfield(linebuf, "subject"))
3130Sstevel@tonic-gate hp->h_subject =
3140Sstevel@tonic-gate addone(hp->h_subject, hcontents(linebuf));
3150Sstevel@tonic-gate else if (ishfield(linebuf, "cc"))
3160Sstevel@tonic-gate hp->h_cc = addto(hp->h_cc, hcontents(linebuf));
3170Sstevel@tonic-gate else if (ishfield(linebuf, "bcc"))
3180Sstevel@tonic-gate hp->h_bcc =
3190Sstevel@tonic-gate addto(hp->h_bcc, hcontents(linebuf));
3200Sstevel@tonic-gate else if (ishfield(linebuf, "default-options"))
3210Sstevel@tonic-gate hp->h_defopt =
3220Sstevel@tonic-gate addone(hp->h_defopt, hcontents(linebuf));
3230Sstevel@tonic-gate else
3240Sstevel@tonic-gate hp->h_others = Xaddone(hp->h_others, linebuf);
3250Sstevel@tonic-gate hp->h_seq++;
3260Sstevel@tonic-gate continue;
3270Sstevel@tonic-gate }
3280Sstevel@tonic-gate if ((linebuf[0] != escape) || (rflag != NOSTR) ||
3290Sstevel@tonic-gate (!intty && !(int)value("escapeok"))) {
3300Sstevel@tonic-gate if (write(fileno(obuf),linebuf,nread) != nread)
3310Sstevel@tonic-gate goto werr;
3320Sstevel@tonic-gate continue;
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate /*
3350Sstevel@tonic-gate * On double escape, just send the single one.
3360Sstevel@tonic-gate */
3370Sstevel@tonic-gate if ((nread > 1) && (linebuf[1] == escape)) {
3380Sstevel@tonic-gate if (write(fileno(obuf),linebuf+1,nread-1) != (nread-1))
3390Sstevel@tonic-gate goto werr;
3400Sstevel@tonic-gate continue;
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate if (hasnulls)
3430Sstevel@tonic-gate nread = stripnulls(linebuf, nread);
3440Sstevel@tonic-gate c = linebuf[1];
3450Sstevel@tonic-gate linebuf[nread - 1] = '\0';
3460Sstevel@tonic-gate switch (c) {
3470Sstevel@tonic-gate default:
3480Sstevel@tonic-gate /*
3490Sstevel@tonic-gate * Otherwise, it's an error.
3500Sstevel@tonic-gate */
3510Sstevel@tonic-gate printf(gettext("Unknown tilde escape.\n"));
3520Sstevel@tonic-gate break;
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate case 'a':
3550Sstevel@tonic-gate case 'A':
3560Sstevel@tonic-gate /*
3570Sstevel@tonic-gate * autograph; sign the letter.
3580Sstevel@tonic-gate */
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate if (cp = value(c=='a' ? "sign":"Sign")) {
3610Sstevel@tonic-gate if (*cp)
3620Sstevel@tonic-gate cpout( cp, obuf);
3630Sstevel@tonic-gate if (isatty(fileno(stdin))) {
3640Sstevel@tonic-gate if (*cp)
3650Sstevel@tonic-gate cpout( cp, stdout);
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate
3690Sstevel@tonic-gate break;
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate case 'i':
3720Sstevel@tonic-gate /*
3730Sstevel@tonic-gate * insert string
3740Sstevel@tonic-gate */
3750Sstevel@tonic-gate for (cp = &linebuf[2]; any(*cp, " \t"); cp++)
3760Sstevel@tonic-gate ;
3770Sstevel@tonic-gate if (*cp)
3780Sstevel@tonic-gate cp = value(cp);
3790Sstevel@tonic-gate if (cp != NOSTR) {
3800Sstevel@tonic-gate if (*cp)
3810Sstevel@tonic-gate cpout(cp, obuf);
3820Sstevel@tonic-gate if (isatty(fileno(stdout))) {
3830Sstevel@tonic-gate if (*cp)
3840Sstevel@tonic-gate cpout(cp, stdout);
3850Sstevel@tonic-gate }
3860Sstevel@tonic-gate }
3870Sstevel@tonic-gate break;
3880Sstevel@tonic-gate
3890Sstevel@tonic-gate case '!':
3900Sstevel@tonic-gate /*
3910Sstevel@tonic-gate * Shell escape, send the balance of the
3920Sstevel@tonic-gate * line to sh -c.
3930Sstevel@tonic-gate */
3940Sstevel@tonic-gate
3950Sstevel@tonic-gate shell(&linebuf[2]);
3960Sstevel@tonic-gate break;
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate case ':':
3990Sstevel@tonic-gate case '_':
4000Sstevel@tonic-gate /*
4010Sstevel@tonic-gate * Escape to command mode, but be nice!
4020Sstevel@tonic-gate */
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate execute(&linebuf[2], 1);
4050Sstevel@tonic-gate iprompt = value("iprompt");
4060Sstevel@tonic-gate if (cp = value("escape"))
4070Sstevel@tonic-gate escape = *cp;
4080Sstevel@tonic-gate printf(gettext("(continue)\n"));
4090Sstevel@tonic-gate break;
4100Sstevel@tonic-gate
4110Sstevel@tonic-gate case '.':
4120Sstevel@tonic-gate /*
4130Sstevel@tonic-gate * Simulate end of file on input.
4140Sstevel@tonic-gate */
4150Sstevel@tonic-gate goto eofl;
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate case 'q':
4180Sstevel@tonic-gate case 'Q':
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate * Force a quit of sending mail.
4210Sstevel@tonic-gate * Act like an interrupt happened.
4220Sstevel@tonic-gate */
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate hadintr++;
4250Sstevel@tonic-gate collrub(SIGINT);
4260Sstevel@tonic-gate exit(1);
4270Sstevel@tonic-gate /* NOTREACHED */
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate case 'x':
4300Sstevel@tonic-gate xhalt();
4310Sstevel@tonic-gate break; /* not reached */
4320Sstevel@tonic-gate
4330Sstevel@tonic-gate case 'h':
4340Sstevel@tonic-gate /*
4350Sstevel@tonic-gate * Grab a bunch of headers.
4360Sstevel@tonic-gate */
4370Sstevel@tonic-gate if (!intty || !outtty) {
4380Sstevel@tonic-gate printf(gettext("~h: no can do!?\n"));
4390Sstevel@tonic-gate break;
4400Sstevel@tonic-gate }
4410Sstevel@tonic-gate grabh(hp, GMASK, (int)value("bsdcompat"));
4420Sstevel@tonic-gate printf(gettext("(continue)\n"));
4430Sstevel@tonic-gate break;
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate case 't':
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate * Add to the To list.
4480Sstevel@tonic-gate */
4490Sstevel@tonic-gate
4500Sstevel@tonic-gate hp->h_to = addto(hp->h_to, &linebuf[2]);
4510Sstevel@tonic-gate hp->h_seq++;
4520Sstevel@tonic-gate break;
4530Sstevel@tonic-gate
4540Sstevel@tonic-gate case 's':
4550Sstevel@tonic-gate /*
4560Sstevel@tonic-gate * Set the Subject list.
4570Sstevel@tonic-gate */
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate cp = &linebuf[2];
4600Sstevel@tonic-gate while (any(*cp, " \t"))
4610Sstevel@tonic-gate cp++;
4620Sstevel@tonic-gate hp->h_subject = savestr(cp);
4630Sstevel@tonic-gate hp->h_seq++;
4640Sstevel@tonic-gate break;
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate case 'c':
4670Sstevel@tonic-gate /*
4680Sstevel@tonic-gate * Add to the CC list.
4690Sstevel@tonic-gate */
4700Sstevel@tonic-gate
4710Sstevel@tonic-gate hp->h_cc = addto(hp->h_cc, &linebuf[2]);
4720Sstevel@tonic-gate hp->h_seq++;
4730Sstevel@tonic-gate break;
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate case 'b':
4760Sstevel@tonic-gate /*
4770Sstevel@tonic-gate * Add stuff to blind carbon copies list.
4780Sstevel@tonic-gate */
4790Sstevel@tonic-gate hp->h_bcc = addto(hp->h_bcc, &linebuf[2]);
4800Sstevel@tonic-gate hp->h_seq++;
4810Sstevel@tonic-gate break;
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate case 'R':
4840Sstevel@tonic-gate hp->h_defopt = addone(hp->h_defopt, myname);
4850Sstevel@tonic-gate hp->h_seq++;
4860Sstevel@tonic-gate fprintf(stderr, gettext("Return receipt marked.\n"));
4870Sstevel@tonic-gate receipt_flg = 1;
4880Sstevel@tonic-gate break;
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate case 'd':
4910Sstevel@tonic-gate copy(Getf("DEAD"), &linebuf[2]);
4920Sstevel@tonic-gate /* FALLTHROUGH */
4930Sstevel@tonic-gate
4940Sstevel@tonic-gate case '<':
4950Sstevel@tonic-gate case 'r': {
4960Sstevel@tonic-gate int ispip;
4970Sstevel@tonic-gate /*
4980Sstevel@tonic-gate * Invoke a file:
4990Sstevel@tonic-gate * Search for the file name,
5000Sstevel@tonic-gate * then open it and copy the contents to obuf.
5010Sstevel@tonic-gate *
5020Sstevel@tonic-gate * if name begins with '!', read from a command
5030Sstevel@tonic-gate */
5040Sstevel@tonic-gate
5050Sstevel@tonic-gate cp = &linebuf[2];
5060Sstevel@tonic-gate while (any(*cp, " \t"))
5070Sstevel@tonic-gate cp++;
5080Sstevel@tonic-gate if (*cp == '\0') {
5090Sstevel@tonic-gate printf(gettext("Interpolate what file?\n"));
5100Sstevel@tonic-gate break;
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate if (*cp=='!') {
5130Sstevel@tonic-gate /* take input from a command */
5140Sstevel@tonic-gate ispip = 1;
5150Sstevel@tonic-gate if ((fbuf = npopen(++cp, "r"))==NULL) {
5160Sstevel@tonic-gate perror("");
5170Sstevel@tonic-gate break;
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate sigint = sigset(SIGINT, SIG_IGN);
5200Sstevel@tonic-gate } else {
5210Sstevel@tonic-gate ispip = 0;
5220Sstevel@tonic-gate cp = expand(cp);
5230Sstevel@tonic-gate if (cp == NOSTR)
5240Sstevel@tonic-gate break;
5250Sstevel@tonic-gate if (isdir(cp)) {
5260Sstevel@tonic-gate printf(gettext("%s: directory\n"), cp);
5270Sstevel@tonic-gate break;
5280Sstevel@tonic-gate }
5290Sstevel@tonic-gate if ((fbuf = fopen(cp, "r")) == NULL) {
5300Sstevel@tonic-gate perror(cp);
5310Sstevel@tonic-gate break;
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate printf("\"%s\" ", cp);
5350Sstevel@tonic-gate flush();
5360Sstevel@tonic-gate lc = cc = 0;
5370Sstevel@tonic-gate while ((t = getc(fbuf)) != EOF) {
5380Sstevel@tonic-gate if (t == '\n')
5390Sstevel@tonic-gate lc++;
5400Sstevel@tonic-gate if (putc(t, obuf) == EOF) {
5410Sstevel@tonic-gate if (ispip) {
5420Sstevel@tonic-gate npclose(fbuf);
5430Sstevel@tonic-gate sigset(SIGINT, sigint);
5440Sstevel@tonic-gate } else
5450Sstevel@tonic-gate fclose(fbuf);
5460Sstevel@tonic-gate goto werr;
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate cc++;
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate if (ispip) {
5510Sstevel@tonic-gate npclose(fbuf);
5520Sstevel@tonic-gate sigset(SIGINT, sigint);
5530Sstevel@tonic-gate } else
5540Sstevel@tonic-gate fclose(fbuf);
5550Sstevel@tonic-gate printf("%ld/%ld\n", lc, cc);
5560Sstevel@tonic-gate fflush(obuf);
5570Sstevel@tonic-gate break;
5580Sstevel@tonic-gate }
5590Sstevel@tonic-gate
5600Sstevel@tonic-gate case 'w':
5610Sstevel@tonic-gate /*
5620Sstevel@tonic-gate * Write the message on a file.
5630Sstevel@tonic-gate */
5640Sstevel@tonic-gate
5650Sstevel@tonic-gate cp = &linebuf[2];
5660Sstevel@tonic-gate while (any(*cp, " \t"))
5670Sstevel@tonic-gate cp++;
5680Sstevel@tonic-gate if (*cp == '\0') {
5690Sstevel@tonic-gate fprintf(stderr, gettext("Write what file!?\n"));
5700Sstevel@tonic-gate break;
5710Sstevel@tonic-gate }
5720Sstevel@tonic-gate if ((cp = expand(cp)) == NOSTR)
5730Sstevel@tonic-gate break;
5740Sstevel@tonic-gate fflush(obuf);
5750Sstevel@tonic-gate rewind(ibuf);
5760Sstevel@tonic-gate exwrite(cp, ibuf);
5770Sstevel@tonic-gate break;
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate case 'm':
5800Sstevel@tonic-gate case 'M':
5810Sstevel@tonic-gate case 'f':
5820Sstevel@tonic-gate case 'F':
5830Sstevel@tonic-gate /*
5840Sstevel@tonic-gate * Interpolate the named messages, if we
5850Sstevel@tonic-gate * are in receiving mail mode. Does the
5860Sstevel@tonic-gate * standard list processing garbage.
5870Sstevel@tonic-gate * If ~f or ~F is given, we don't shift over.
5880Sstevel@tonic-gate */
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate if (!rcvmode) {
5910Sstevel@tonic-gate printf(gettext(
5920Sstevel@tonic-gate "No messages to send from!?!\n"));
5930Sstevel@tonic-gate break;
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate cp = &linebuf[2];
5960Sstevel@tonic-gate while (any(*cp, " \t"))
5970Sstevel@tonic-gate cp++;
5980Sstevel@tonic-gate if (forward(cp, obuf, c) < 0)
5990Sstevel@tonic-gate goto werr;
6000Sstevel@tonic-gate fflush(obuf);
6010Sstevel@tonic-gate printf(gettext("(continue)\n"));
6020Sstevel@tonic-gate break;
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate case '?':
6050Sstevel@tonic-gate if ((fbuf = fopen(THELPFILE, "r")) == NULL) {
6060Sstevel@tonic-gate printf(gettext("No help just now.\n"));
6070Sstevel@tonic-gate break;
6080Sstevel@tonic-gate }
6090Sstevel@tonic-gate t = getc(fbuf);
6100Sstevel@tonic-gate while (t != -1) {
6110Sstevel@tonic-gate putchar(t);
6120Sstevel@tonic-gate t = getc(fbuf);
6130Sstevel@tonic-gate }
6140Sstevel@tonic-gate fclose(fbuf);
6150Sstevel@tonic-gate break;
6160Sstevel@tonic-gate
6170Sstevel@tonic-gate case 'p': {
6180Sstevel@tonic-gate /*
6190Sstevel@tonic-gate * Print out the current state of the
6200Sstevel@tonic-gate * message without altering anything.
6210Sstevel@tonic-gate */
6220Sstevel@tonic-gate int nlines;
6230Sstevel@tonic-gate extern jmp_buf pipestop;
6240Sstevel@tonic-gate extern void brokpipe(int);
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate fflush(obuf);
6270Sstevel@tonic-gate rewind(ibuf);
6280Sstevel@tonic-gate fbuf = stdout;
6290Sstevel@tonic-gate if (setjmp(pipestop))
6300Sstevel@tonic-gate goto ret0;
6310Sstevel@tonic-gate if (intty && outtty && (cp = value("crt")) != NOSTR) {
6320Sstevel@tonic-gate nlines =
6330Sstevel@tonic-gate (*cp == '\0' ? screensize() : atoi(cp)) - 7;
6340Sstevel@tonic-gate /* 7 for hdr lines */
6350Sstevel@tonic-gate while ((t = getc(ibuf)) != EOF) {
6360Sstevel@tonic-gate if (t == '\n')
6370Sstevel@tonic-gate if (--nlines <= 0)
6380Sstevel@tonic-gate break;
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate rewind(ibuf);
6410Sstevel@tonic-gate if (nlines <= 0) {
6420Sstevel@tonic-gate fbuf = npopen(MORE, "w");
6430Sstevel@tonic-gate if (fbuf == NULL) {
6440Sstevel@tonic-gate perror(MORE);
6450Sstevel@tonic-gate fbuf = stdout;
6460Sstevel@tonic-gate } else {
6470Sstevel@tonic-gate sigint = sigset(SIGINT, SIG_IGN);
6480Sstevel@tonic-gate sigpipe = sigset(SIGPIPE, brokpipe);
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate }
6510Sstevel@tonic-gate }
6520Sstevel@tonic-gate fprintf(fbuf, gettext("-------\nMessage contains:\n"));
6530Sstevel@tonic-gate puthead(hp, fbuf, GMASK, 0);
6540Sstevel@tonic-gate while ((t = getc(ibuf))!=EOF)
6550Sstevel@tonic-gate putc(t, fbuf);
6560Sstevel@tonic-gate ret0:
6570Sstevel@tonic-gate if (fbuf != stdout) {
6580Sstevel@tonic-gate npclose(fbuf);
6590Sstevel@tonic-gate sigset(SIGPIPE, sigpipe);
6600Sstevel@tonic-gate sigset(SIGINT, sigint);
6610Sstevel@tonic-gate }
6620Sstevel@tonic-gate printf(gettext("(continue)\n"));
6630Sstevel@tonic-gate break;
6640Sstevel@tonic-gate }
6650Sstevel@tonic-gate
6660Sstevel@tonic-gate case '^':
6670Sstevel@tonic-gate case '|':
6680Sstevel@tonic-gate /*
6690Sstevel@tonic-gate * Pipe message through command.
6700Sstevel@tonic-gate * Collect output as new message.
6710Sstevel@tonic-gate */
6720Sstevel@tonic-gate
6730Sstevel@tonic-gate obuf = mespipe(ibuf, obuf, &linebuf[2]);
6740Sstevel@tonic-gate newo = obuf;
6750Sstevel@tonic-gate ibuf = newi;
6760Sstevel@tonic-gate newi = ibuf;
6770Sstevel@tonic-gate printf(gettext("(continue)\n"));
6780Sstevel@tonic-gate break;
6790Sstevel@tonic-gate
6800Sstevel@tonic-gate case 'v':
6810Sstevel@tonic-gate case 'e':
6820Sstevel@tonic-gate /*
6830Sstevel@tonic-gate * Edit the current message.
6840Sstevel@tonic-gate * 'e' means to use EDITOR
6850Sstevel@tonic-gate * 'v' means to use VISUAL
6860Sstevel@tonic-gate */
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate if ((obuf = mesedit(ibuf, obuf, c, hp)) == NULL)
6890Sstevel@tonic-gate goto err;
6900Sstevel@tonic-gate newo = obuf;
6910Sstevel@tonic-gate ibuf = newi;
6920Sstevel@tonic-gate printf(gettext("(continue)\n"));
6930Sstevel@tonic-gate break;
6940Sstevel@tonic-gate }
6950Sstevel@tonic-gate fflush(obuf);
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate eofl:
6980Sstevel@tonic-gate fflush(obuf);
6990Sstevel@tonic-gate if ((cp = value("MAILX_TAIL")) != NOSTR) {
7000Sstevel@tonic-gate cpout( cp, obuf);
7010Sstevel@tonic-gate if (isatty(fileno(stdin)))
7020Sstevel@tonic-gate cpout( cp, stdout);
7030Sstevel@tonic-gate }
7040Sstevel@tonic-gate fclose(obuf);
7050Sstevel@tonic-gate rewind(ibuf);
7060Sstevel@tonic-gate resetsigs(0);
7070Sstevel@tonic-gate noreset = 0;
7080Sstevel@tonic-gate return(ibuf);
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate werr:
7110Sstevel@tonic-gate /*
7120Sstevel@tonic-gate * Write error occurred on tmp file, save partial
7130Sstevel@tonic-gate * message in dead.letter.
7140Sstevel@tonic-gate */
7150Sstevel@tonic-gate perror(tempMail);
7160Sstevel@tonic-gate fflush(obuf);
7170Sstevel@tonic-gate rewind(ibuf);
7180Sstevel@tonic-gate if (fsize(ibuf) > 0) {
7190Sstevel@tonic-gate char *deadletter;
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate deadletter = Getf("DEAD");
7220Sstevel@tonic-gate fprintf(stderr, gettext("Saving partial message in %s\n"),
7230Sstevel@tonic-gate deadletter);
7240Sstevel@tonic-gate if ((fbuf = fopen(deadletter,
7250Sstevel@tonic-gate value("appenddeadletter") == NOSTR ? "w" : "a")) != NULL) {
7260Sstevel@tonic-gate chmod(deadletter, DEADPERM);
7270Sstevel@tonic-gate puthead(hp, fbuf, GMASK|GCLEN, fsize(ibuf));
7280Sstevel@tonic-gate lcwrite(deadletter, ibuf, fbuf, value("appenddeadletter") != NOSTR);
7290Sstevel@tonic-gate fclose(fbuf);
7300Sstevel@tonic-gate } else
7310Sstevel@tonic-gate perror(deadletter);
7320Sstevel@tonic-gate }
7330Sstevel@tonic-gate
7340Sstevel@tonic-gate err:
7350Sstevel@tonic-gate if (ibuf != NULL)
7360Sstevel@tonic-gate fclose(ibuf);
7370Sstevel@tonic-gate if (obuf != NULL)
7380Sstevel@tonic-gate fclose(obuf);
7390Sstevel@tonic-gate resetsigs(0);
7400Sstevel@tonic-gate noreset = 0;
7410Sstevel@tonic-gate return(NULL);
7420Sstevel@tonic-gate }
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate static void
resetsigs(int resethup)7450Sstevel@tonic-gate resetsigs(int resethup)
7460Sstevel@tonic-gate {
7470Sstevel@tonic-gate (void) sigset(SIGINT, savesig);
7480Sstevel@tonic-gate if (resethup)
7490Sstevel@tonic-gate (void) sigset(SIGHUP, savehup);
7500Sstevel@tonic-gate #ifdef SIGCONT
7510Sstevel@tonic-gate # ifdef preSVr4
7520Sstevel@tonic-gate (void) sigset(SIGCONT, savecont);
7530Sstevel@tonic-gate # else
7540Sstevel@tonic-gate {
7550Sstevel@tonic-gate struct sigaction nsig;
7560Sstevel@tonic-gate nsig.sa_handler = (void (*)())savecont;
7570Sstevel@tonic-gate sigemptyset(&nsig.sa_mask);
7580Sstevel@tonic-gate nsig.sa_flags = SA_RESTART;
7590Sstevel@tonic-gate (void) sigaction(SIGCONT, &nsig, (struct sigaction*)0);
7600Sstevel@tonic-gate }
7610Sstevel@tonic-gate # endif
7620Sstevel@tonic-gate #endif
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate /*
7660Sstevel@tonic-gate * Write a file ex-like.
7670Sstevel@tonic-gate */
7680Sstevel@tonic-gate
7690Sstevel@tonic-gate static int
exwrite(char name[],FILE * ibuf)7700Sstevel@tonic-gate exwrite(char name[], FILE *ibuf)
7710Sstevel@tonic-gate {
7720Sstevel@tonic-gate register FILE *of;
7730Sstevel@tonic-gate struct stat junk;
7740Sstevel@tonic-gate void (*sigint)(int), (*sigpipe)(int);
7750Sstevel@tonic-gate int pi = (*name == '!');
7760Sstevel@tonic-gate
7770Sstevel@tonic-gate if ((of = pi ? npopen(++name, "w") : fopen(name, "a")) == NULL) {
7780Sstevel@tonic-gate perror(name);
7790Sstevel@tonic-gate return(-1);
7800Sstevel@tonic-gate }
7810Sstevel@tonic-gate if (pi) {
7820Sstevel@tonic-gate sigint = sigset(SIGINT, SIG_IGN);
7830Sstevel@tonic-gate sigpipe = sigset(SIGPIPE, SIG_IGN);
7840Sstevel@tonic-gate }
7850Sstevel@tonic-gate lcwrite(name, ibuf, of, 0);
7860Sstevel@tonic-gate pi ? npclose(of) : fclose(of);
7870Sstevel@tonic-gate if (pi) {
7880Sstevel@tonic-gate sigset(SIGPIPE, sigpipe);
7890Sstevel@tonic-gate sigset(SIGINT, sigint);
7900Sstevel@tonic-gate }
7910Sstevel@tonic-gate return(0);
7920Sstevel@tonic-gate }
7930Sstevel@tonic-gate
7940Sstevel@tonic-gate void
lcwrite(char * fn,FILE * fi,FILE * fo,int addnl)7950Sstevel@tonic-gate lcwrite(char *fn, FILE *fi, FILE *fo, int addnl)
7960Sstevel@tonic-gate {
7970Sstevel@tonic-gate register int c;
7980Sstevel@tonic-gate long lc, cc;
7990Sstevel@tonic-gate
8000Sstevel@tonic-gate printf("\"%s\" ", fn);
8010Sstevel@tonic-gate fflush(stdout);
8020Sstevel@tonic-gate lc = cc = 0;
8030Sstevel@tonic-gate while ((c = getc(fi)) != EOF) {
8040Sstevel@tonic-gate cc++;
8050Sstevel@tonic-gate if (putc(c, fo) == '\n')
8060Sstevel@tonic-gate lc++;
8070Sstevel@tonic-gate if (ferror(fo)) {
8080Sstevel@tonic-gate perror("");
8090Sstevel@tonic-gate return;
8100Sstevel@tonic-gate }
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate if (addnl) {
8130Sstevel@tonic-gate putc('\n', fo);
8140Sstevel@tonic-gate lc++;
8150Sstevel@tonic-gate cc++;
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate fflush(fo);
8180Sstevel@tonic-gate if (fferror(fo)) {
8190Sstevel@tonic-gate perror("");
8200Sstevel@tonic-gate return;
8210Sstevel@tonic-gate }
8220Sstevel@tonic-gate printf("%ld/%ld\n", lc, cc);
8230Sstevel@tonic-gate fflush(stdout);
8240Sstevel@tonic-gate }
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate /*
8270Sstevel@tonic-gate * Edit the message being collected on ibuf and obuf.
8280Sstevel@tonic-gate * Write the message out onto some poorly-named temp file
8290Sstevel@tonic-gate * and point an editor at it.
8300Sstevel@tonic-gate *
8310Sstevel@tonic-gate * On return, make the edit file the new temp file.
8320Sstevel@tonic-gate */
8330Sstevel@tonic-gate
8340Sstevel@tonic-gate static FILE *
mesedit(FILE * ibuf,FILE * obuf,int c,struct header * hp)8350Sstevel@tonic-gate mesedit(FILE *ibuf, FILE *obuf, int c, struct header *hp)
8360Sstevel@tonic-gate {
8370Sstevel@tonic-gate pid_t pid;
8380Sstevel@tonic-gate FILE *fbuf;
8390Sstevel@tonic-gate register int t;
8400Sstevel@tonic-gate void (*sigint)(int);
8410Sstevel@tonic-gate #ifdef SIGCONT
8420Sstevel@tonic-gate void (*sigcont)(int);
8430Sstevel@tonic-gate #endif
8440Sstevel@tonic-gate struct stat sbuf;
8450Sstevel@tonic-gate register char *edit;
8460Sstevel@tonic-gate char hdr[LINESIZE];
8470Sstevel@tonic-gate char *oto, *osubject, *occ, *obcc, **oothers;
8480Sstevel@tonic-gate int fd = -1;
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate if (stat(tempEdit, &sbuf) >= 0) {
8510Sstevel@tonic-gate printf(gettext("%s: file exists\n"), tempEdit);
8520Sstevel@tonic-gate goto out;
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate if ((fd = open(tempEdit, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
8550Sstevel@tonic-gate (fbuf = fdopen(fd, "w")) == NULL) {
8560Sstevel@tonic-gate perror(tempEdit);
8570Sstevel@tonic-gate goto out;
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate fflush(obuf);
8600Sstevel@tonic-gate rewind(ibuf);
8610Sstevel@tonic-gate puthead(hp, fbuf, GMASK, 0);
8620Sstevel@tonic-gate while ((t = getc(ibuf)) != EOF)
8630Sstevel@tonic-gate putc(t, fbuf);
8640Sstevel@tonic-gate fflush(fbuf);
8650Sstevel@tonic-gate if (fferror(fbuf)) {
8660Sstevel@tonic-gate perror(tempEdit);
8670Sstevel@tonic-gate removefile(tempEdit);
8680Sstevel@tonic-gate goto out;
8690Sstevel@tonic-gate }
8700Sstevel@tonic-gate fclose(fbuf);
8710Sstevel@tonic-gate if ((edit = value(c == 'e' ? "EDITOR" : "VISUAL")) == NOSTR ||
8720Sstevel@tonic-gate *edit == '\0')
8730Sstevel@tonic-gate edit = c == 'e' ? EDITOR : VISUAL;
8740Sstevel@tonic-gate edit = safeexpand(edit);
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate /*
8770Sstevel@tonic-gate * Fork/execlp the editor on the edit file
8780Sstevel@tonic-gate */
8790Sstevel@tonic-gate
8800Sstevel@tonic-gate pid = vfork();
8810Sstevel@tonic-gate if (pid == (pid_t)-1) {
8820Sstevel@tonic-gate perror("fork");
8830Sstevel@tonic-gate removefile(tempEdit);
8840Sstevel@tonic-gate goto out;
8850Sstevel@tonic-gate }
8860Sstevel@tonic-gate if (pid == 0) {
8870Sstevel@tonic-gate char ecmd[BUFSIZ];
8880Sstevel@tonic-gate char *Shell;
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate sigchild();
8910Sstevel@tonic-gate execlp(edit, edit, tempEdit, (char *)0);
8920Sstevel@tonic-gate /*
8930Sstevel@tonic-gate * If execlp fails, "edit" might really be a complete
8940Sstevel@tonic-gate * shell command, not a simple pathname. Try using
8950Sstevel@tonic-gate * the shell to run it.
8960Sstevel@tonic-gate */
8970Sstevel@tonic-gate snprintf(ecmd, sizeof (ecmd), "exec %s %s", edit, tempEdit);
8980Sstevel@tonic-gate if ((Shell = value("SHELL")) == NULL || *Shell=='\0')
8990Sstevel@tonic-gate Shell = SHELL;
9000Sstevel@tonic-gate execlp(Shell, Shell, "-c", ecmd, NULL);
9010Sstevel@tonic-gate perror(edit);
9020Sstevel@tonic-gate _exit(1);
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate sigint = sigset(SIGINT, SIG_IGN);
9050Sstevel@tonic-gate #ifdef SIGCONT
9060Sstevel@tonic-gate sigcont = sigset(SIGCONT, SIG_DFL);
9070Sstevel@tonic-gate #endif
9080Sstevel@tonic-gate while (wait((int *)0) != pid)
9090Sstevel@tonic-gate ;
9100Sstevel@tonic-gate sigset(SIGINT, sigint);
9110Sstevel@tonic-gate #ifdef SIGCONT
9120Sstevel@tonic-gate sigset(SIGCONT, sigcont);
9130Sstevel@tonic-gate #endif
9140Sstevel@tonic-gate /*
9150Sstevel@tonic-gate * Now switch to new file.
9160Sstevel@tonic-gate */
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate if ((fbuf = fopen(tempEdit, "r")) == NULL) {
9190Sstevel@tonic-gate perror(tempEdit);
9200Sstevel@tonic-gate removefile(tempEdit);
9210Sstevel@tonic-gate goto out;
9220Sstevel@tonic-gate }
9230Sstevel@tonic-gate removefile(tempEdit);
9240Sstevel@tonic-gate
9250Sstevel@tonic-gate /* save the old headers, in case they are accidentally deleted */
9260Sstevel@tonic-gate osubject = hp->h_subject;
9270Sstevel@tonic-gate oto = hp->h_to;
9280Sstevel@tonic-gate occ = hp->h_cc;
9290Sstevel@tonic-gate obcc = hp->h_bcc;
9300Sstevel@tonic-gate oothers = hp->h_others;
9310Sstevel@tonic-gate hp->h_to = hp->h_subject = hp->h_cc = hp->h_bcc = hp->h_defopt = NOSTR;
9320Sstevel@tonic-gate hp->h_others = NOSTRPTR;
9330Sstevel@tonic-gate hp->h_seq = 0;
9340Sstevel@tonic-gate while (gethfield(fbuf, hdr, 9999L) > 0) {
9350Sstevel@tonic-gate if (ishfield(hdr, "to"))
9360Sstevel@tonic-gate hp->h_to = addto(hp->h_to, hcontents(hdr));
9370Sstevel@tonic-gate else if (ishfield(hdr, "subject"))
9380Sstevel@tonic-gate hp->h_subject = addone(hp->h_subject, hcontents(hdr));
9390Sstevel@tonic-gate else if (ishfield(hdr, "cc"))
9400Sstevel@tonic-gate hp->h_cc = addto(hp->h_cc, hcontents(hdr));
9410Sstevel@tonic-gate else if (ishfield(hdr, "bcc"))
9420Sstevel@tonic-gate hp->h_bcc = addto(hp->h_bcc, hcontents(hdr));
9430Sstevel@tonic-gate else if (ishfield(hdr, "default-options"))
9440Sstevel@tonic-gate hp->h_defopt = addone(hp->h_defopt, hcontents(hdr));
9450Sstevel@tonic-gate else
9460Sstevel@tonic-gate hp->h_others = Xaddone(hp->h_others, hdr);
9470Sstevel@tonic-gate hp->h_seq++;
9480Sstevel@tonic-gate }
9490Sstevel@tonic-gate if (hp->h_seq == 0) {
9500Sstevel@tonic-gate /* if we didn't see any headers, restore the original headers */
9510Sstevel@tonic-gate hp->h_subject = osubject;
9520Sstevel@tonic-gate hp->h_to = oto;
9530Sstevel@tonic-gate hp->h_cc = occ;
9540Sstevel@tonic-gate hp->h_bcc = obcc;
9550Sstevel@tonic-gate hp->h_others = oothers;
9560Sstevel@tonic-gate printf(gettext(
9570Sstevel@tonic-gate "(Deleted headers restored to original values)\n"));
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate if ((fd = open(tempMail, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
9600Sstevel@tonic-gate (obuf = fdopen(fd, "w")) == NULL) {
9610Sstevel@tonic-gate perror(tempMail);
9620Sstevel@tonic-gate fclose(fbuf);
9630Sstevel@tonic-gate goto out;
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate if ((ibuf = fopen(tempMail, "r")) == NULL) {
9660Sstevel@tonic-gate perror(tempMail);
9670Sstevel@tonic-gate removefile(tempMail);
9680Sstevel@tonic-gate fclose(fbuf);
9690Sstevel@tonic-gate fclose(obuf);
9700Sstevel@tonic-gate goto out;
9710Sstevel@tonic-gate }
9720Sstevel@tonic-gate removefile(tempMail);
9730Sstevel@tonic-gate if (strlen(hdr) != 0) {
9740Sstevel@tonic-gate fputs(hdr, obuf);
9750Sstevel@tonic-gate putc('\n', obuf);
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate while ((t = getc(fbuf)) != EOF)
9780Sstevel@tonic-gate putc(t, obuf);
9790Sstevel@tonic-gate fclose(fbuf);
9800Sstevel@tonic-gate fclose(newo);
9810Sstevel@tonic-gate fclose(newi);
9820Sstevel@tonic-gate newo = obuf;
9830Sstevel@tonic-gate newi = ibuf;
9840Sstevel@tonic-gate out:
9850Sstevel@tonic-gate return(newo);
9860Sstevel@tonic-gate }
9870Sstevel@tonic-gate
9880Sstevel@tonic-gate /*
9890Sstevel@tonic-gate * Pipe the message through the command.
9900Sstevel@tonic-gate * Old message is on stdin of command;
9910Sstevel@tonic-gate * New message collected from stdout.
9920Sstevel@tonic-gate * Sh -c must return 0 to accept the new message.
9930Sstevel@tonic-gate */
9940Sstevel@tonic-gate
9950Sstevel@tonic-gate static FILE *
mespipe(FILE * ibuf,FILE * obuf,char cmd[])9960Sstevel@tonic-gate mespipe(FILE *ibuf, FILE *obuf, char cmd[])
9970Sstevel@tonic-gate {
9980Sstevel@tonic-gate register FILE *ni, *no;
9990Sstevel@tonic-gate pid_t pid;
10000Sstevel@tonic-gate int s;
10010Sstevel@tonic-gate void (*sigint)(int);
10020Sstevel@tonic-gate char *Shell;
10030Sstevel@tonic-gate int fd = -1;
10040Sstevel@tonic-gate
10050Sstevel@tonic-gate newi = ibuf;
10060Sstevel@tonic-gate if ((fd = open(tempEdit, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
10070Sstevel@tonic-gate (no = fdopen(fd, "w")) == NULL) {
10080Sstevel@tonic-gate perror(tempEdit);
10090Sstevel@tonic-gate return(obuf);
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate if ((ni = fopen(tempEdit, "r")) == NULL) {
10120Sstevel@tonic-gate perror(tempEdit);
10130Sstevel@tonic-gate fclose(no);
10140Sstevel@tonic-gate removefile(tempEdit);
10150Sstevel@tonic-gate return(obuf);
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate removefile(tempEdit);
10180Sstevel@tonic-gate fflush(obuf);
10190Sstevel@tonic-gate rewind(ibuf);
10200Sstevel@tonic-gate if ((Shell = value("SHELL")) == NULL || *Shell=='\0')
10210Sstevel@tonic-gate Shell = SHELL;
10220Sstevel@tonic-gate if ((pid = vfork()) == (pid_t)-1) {
10230Sstevel@tonic-gate perror("fork");
10240Sstevel@tonic-gate goto err;
10250Sstevel@tonic-gate }
10260Sstevel@tonic-gate if (pid == 0) {
10270Sstevel@tonic-gate /*
10280Sstevel@tonic-gate * stdin = current message.
10290Sstevel@tonic-gate * stdout = new message.
10300Sstevel@tonic-gate */
10310Sstevel@tonic-gate
10320Sstevel@tonic-gate sigchild();
10330Sstevel@tonic-gate close(0);
10340Sstevel@tonic-gate dup(fileno(ibuf));
10350Sstevel@tonic-gate close(1);
10360Sstevel@tonic-gate dup(fileno(no));
10370Sstevel@tonic-gate for (s = 4; s < 15; s++)
10380Sstevel@tonic-gate close(s);
10390Sstevel@tonic-gate execlp(Shell, Shell, "-c", cmd, (char *)0);
10400Sstevel@tonic-gate perror(Shell);
10410Sstevel@tonic-gate _exit(1);
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate sigint = sigset(SIGINT, SIG_IGN);
10440Sstevel@tonic-gate while (wait(&s) != pid)
10450Sstevel@tonic-gate ;
10460Sstevel@tonic-gate sigset(SIGINT, sigint);
10470Sstevel@tonic-gate if (s != 0 || pid == (pid_t)-1) {
10480Sstevel@tonic-gate fprintf(stderr, gettext("\"%s\" failed!?\n"), cmd);
10490Sstevel@tonic-gate goto err;
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate if (fsize(ni) == 0) {
10520Sstevel@tonic-gate fprintf(stderr, gettext("No bytes from \"%s\" !?\n"), cmd);
10530Sstevel@tonic-gate goto err;
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate /*
10570Sstevel@tonic-gate * Take new files.
10580Sstevel@tonic-gate */
10590Sstevel@tonic-gate
10600Sstevel@tonic-gate newi = ni;
10610Sstevel@tonic-gate fclose(ibuf);
10620Sstevel@tonic-gate fclose(obuf);
10630Sstevel@tonic-gate return(no);
10640Sstevel@tonic-gate
10650Sstevel@tonic-gate err:
10660Sstevel@tonic-gate fclose(no);
10670Sstevel@tonic-gate fclose(ni);
10680Sstevel@tonic-gate return(obuf);
10690Sstevel@tonic-gate }
10700Sstevel@tonic-gate
10710Sstevel@tonic-gate static char *indentprefix; /* used instead of tab by tabputs */
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate /*
10740Sstevel@tonic-gate * Interpolate the named messages into the current
10750Sstevel@tonic-gate * message, preceding each line with a tab.
10760Sstevel@tonic-gate * Return a count of the number of characters now in
10770Sstevel@tonic-gate * the message, or -1 if an error is encountered writing
10780Sstevel@tonic-gate * the message temporary. The flag argument is 'm' if we
10790Sstevel@tonic-gate * should shift over and 'f' if not.
10800Sstevel@tonic-gate */
10810Sstevel@tonic-gate static int
forward(char ms[],FILE * obuf,int f)10820Sstevel@tonic-gate forward(char ms[], FILE *obuf, int f)
10830Sstevel@tonic-gate {
10840Sstevel@tonic-gate register int *msgvec, *ip;
10850Sstevel@tonic-gate
10860Sstevel@tonic-gate msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec);
10870Sstevel@tonic-gate if (msgvec == NOINTPTR)
10880Sstevel@tonic-gate return(0);
10890Sstevel@tonic-gate if (getmsglist(ms, msgvec, 0) < 0)
10900Sstevel@tonic-gate return(0);
10910Sstevel@tonic-gate if (*msgvec == NULL) {
10920Sstevel@tonic-gate *msgvec = first(0, MMNORM);
10930Sstevel@tonic-gate if (*msgvec == NULL) {
10940Sstevel@tonic-gate printf(gettext("No appropriate messages\n"));
10950Sstevel@tonic-gate return(0);
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate msgvec[1] = NULL;
10980Sstevel@tonic-gate }
10990Sstevel@tonic-gate if (tolower(f) == 'm')
11000Sstevel@tonic-gate indentprefix = value("indentprefix");
11010Sstevel@tonic-gate printf(gettext("Interpolating:"));
11020Sstevel@tonic-gate for (ip = msgvec; *ip != NULL; ip++) {
11030Sstevel@tonic-gate touch(*ip);
11040Sstevel@tonic-gate printf(" %d", *ip);
11050Sstevel@tonic-gate if (msend(&message[*ip-1], obuf, islower(f) ? M_IGNORE : 0,
11060Sstevel@tonic-gate tolower(f) == 'm' ? tabputs : fputs) < 0) {
11070Sstevel@tonic-gate perror(tempMail);
11080Sstevel@tonic-gate return(-1);
11090Sstevel@tonic-gate }
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate fflush(obuf);
11120Sstevel@tonic-gate if (fferror(obuf)) {
11130Sstevel@tonic-gate perror(tempMail);
11140Sstevel@tonic-gate return(-1);
11150Sstevel@tonic-gate }
11160Sstevel@tonic-gate printf("\n");
11170Sstevel@tonic-gate return(0);
11180Sstevel@tonic-gate }
11190Sstevel@tonic-gate
11200Sstevel@tonic-gate static int
tabputs(const char * line,FILE * obuf)11210Sstevel@tonic-gate tabputs(const char *line, FILE *obuf)
11220Sstevel@tonic-gate {
11230Sstevel@tonic-gate
11240Sstevel@tonic-gate if (indentprefix)
11250Sstevel@tonic-gate fputs(indentprefix, obuf);
11260Sstevel@tonic-gate /* Don't create lines with only a tab on them */
11270Sstevel@tonic-gate else if (line[0] != '\n')
11280Sstevel@tonic-gate fputc('\t', obuf);
11290Sstevel@tonic-gate return (fputs(line, obuf));
11300Sstevel@tonic-gate }
11310Sstevel@tonic-gate
11320Sstevel@tonic-gate /*
11330Sstevel@tonic-gate * Print (continue) when continued after ^Z.
11340Sstevel@tonic-gate */
11350Sstevel@tonic-gate #ifdef SIGCONT
11360Sstevel@tonic-gate static void
11370Sstevel@tonic-gate #ifdef __cplusplus
collcont(int)11380Sstevel@tonic-gate collcont(int)
11390Sstevel@tonic-gate #else
11400Sstevel@tonic-gate /* ARGSUSED */
11410Sstevel@tonic-gate collcont(int s)
11420Sstevel@tonic-gate #endif
11430Sstevel@tonic-gate {
11440Sstevel@tonic-gate printf(gettext("(continue)\n"));
11450Sstevel@tonic-gate fflush(stdout);
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate #endif /* SIGCONT */
11480Sstevel@tonic-gate
11490Sstevel@tonic-gate /*
11500Sstevel@tonic-gate * On interrupt, go here to save the partial
11510Sstevel@tonic-gate * message on ~/dead.letter.
11520Sstevel@tonic-gate * Then restore signals and execute the normal
11530Sstevel@tonic-gate * signal routine. We only come here if signals
11540Sstevel@tonic-gate * were previously set anyway.
11550Sstevel@tonic-gate */
11560Sstevel@tonic-gate static void
collrub(int s)11570Sstevel@tonic-gate collrub(int s)
11580Sstevel@tonic-gate {
11590Sstevel@tonic-gate register FILE *dbuf;
11600Sstevel@tonic-gate register char *deadletter;
11610Sstevel@tonic-gate
11620Sstevel@tonic-gate # ifdef OLD_BSD_SIGS
11630Sstevel@tonic-gate if (s == SIGHUP)
11640Sstevel@tonic-gate sigignore(SIGHUP);
11650Sstevel@tonic-gate # endif
11660Sstevel@tonic-gate if (s == SIGINT && hadintr == 0) {
11670Sstevel@tonic-gate hadintr++;
11680Sstevel@tonic-gate fflush(stdout);
11690Sstevel@tonic-gate fprintf(stderr,
11700Sstevel@tonic-gate gettext("\n(Interrupt -- one more to kill letter)\n"));
11710Sstevel@tonic-gate # ifdef OLD_BSD_SIGS
11720Sstevel@tonic-gate sigrelse(s);
11730Sstevel@tonic-gate # endif
11740Sstevel@tonic-gate longjmp(coljmp, 1);
11750Sstevel@tonic-gate }
11760Sstevel@tonic-gate fclose(newo);
11770Sstevel@tonic-gate rewind(newi);
11780Sstevel@tonic-gate if (s == SIGINT && value("save")==NOSTR || fsize(newi) == 0)
11790Sstevel@tonic-gate goto done;
11800Sstevel@tonic-gate deadletter = Getf("DEAD");
11810Sstevel@tonic-gate if ((dbuf = fopen(deadletter,
11820Sstevel@tonic-gate (value("appenddeadletter") == NOSTR ? "w" : "a"))) == NULL) {
11830Sstevel@tonic-gate perror(deadletter);
11840Sstevel@tonic-gate goto done;
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate chmod(deadletter, DEADPERM);
11870Sstevel@tonic-gate puthead(savehp, dbuf, GMASK|GCLEN, fsize(newi));
11880Sstevel@tonic-gate lcwrite(deadletter, newi, dbuf, value("appenddeadletter") != NOSTR);
11890Sstevel@tonic-gate fclose(dbuf);
11900Sstevel@tonic-gate done:
11910Sstevel@tonic-gate fclose(newi);
11920Sstevel@tonic-gate resetsigs(1);
11930Sstevel@tonic-gate if (rcvmode) {
11940Sstevel@tonic-gate if (s == SIGHUP)
11950Sstevel@tonic-gate hangup(s);
11960Sstevel@tonic-gate else
11970Sstevel@tonic-gate stop(s);
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate else
12000Sstevel@tonic-gate exit(1);
12010Sstevel@tonic-gate }
12020Sstevel@tonic-gate
12030Sstevel@tonic-gate /*
12040Sstevel@tonic-gate * Acknowledge an interrupt signal from the tty by typing an @
12050Sstevel@tonic-gate */
12060Sstevel@tonic-gate static void
12070Sstevel@tonic-gate #ifdef __cplusplus
intack(int)12080Sstevel@tonic-gate intack(int)
12090Sstevel@tonic-gate #else
12100Sstevel@tonic-gate /* ARGSUSED */
12110Sstevel@tonic-gate intack(int s)
12120Sstevel@tonic-gate #endif
12130Sstevel@tonic-gate {
12140Sstevel@tonic-gate
12150Sstevel@tonic-gate puts("@");
12160Sstevel@tonic-gate fflush(stdout);
12170Sstevel@tonic-gate clearerr(stdin);
12180Sstevel@tonic-gate longjmp(coljmp,1);
12190Sstevel@tonic-gate }
12200Sstevel@tonic-gate
12210Sstevel@tonic-gate /* Read line from stdin, noting any NULL characters.
12220Sstevel@tonic-gate Return the number of characters read. Note that the buffer
12230Sstevel@tonic-gate passed must be 1 larger than "size" for the trailing NUL byte.
12240Sstevel@tonic-gate */
12250Sstevel@tonic-gate int
getaline(char * line,int size,FILE * f,int * hasnulls)1226*13093SRoger.Faulkner@Oracle.COM getaline(char *line, int size, FILE *f, int *hasnulls)
12270Sstevel@tonic-gate {
12280Sstevel@tonic-gate register int i, ch;
12290Sstevel@tonic-gate for (i = 0; (i < size) && ((ch=getc(f)) != EOF); ) {
12300Sstevel@tonic-gate if ( ch == '\0' )
12310Sstevel@tonic-gate *hasnulls = 1;
12320Sstevel@tonic-gate if ((line[i++] = (char)ch) == '\n') break;
12330Sstevel@tonic-gate }
12340Sstevel@tonic-gate line[i] = '\0';
12350Sstevel@tonic-gate return(i);
12360Sstevel@tonic-gate }
12370Sstevel@tonic-gate
12380Sstevel@tonic-gate void
12390Sstevel@tonic-gate #ifdef __cplusplus
savedead(int)12400Sstevel@tonic-gate savedead(int)
12410Sstevel@tonic-gate #else
12420Sstevel@tonic-gate /* ARGSUSED */
12430Sstevel@tonic-gate savedead(int s)
12440Sstevel@tonic-gate #endif
12450Sstevel@tonic-gate {
12460Sstevel@tonic-gate collrub(SIGINT);
12470Sstevel@tonic-gate exit(1);
12480Sstevel@tonic-gate /* NOTREACHED */
12490Sstevel@tonic-gate }
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate /*
12520Sstevel@tonic-gate * Add a list of addresses to the end of a header entry field.
12530Sstevel@tonic-gate */
12540Sstevel@tonic-gate char *
addto(char hf[],char news[])12550Sstevel@tonic-gate addto(char hf[], char news[])
12560Sstevel@tonic-gate {
12570Sstevel@tonic-gate char name[LINESIZE];
12580Sstevel@tonic-gate int comma = docomma(news);
12590Sstevel@tonic-gate
12600Sstevel@tonic-gate while (news = yankword(news, name, sizeof (name), comma)) {
12610Sstevel@tonic-gate nstrcat(name, sizeof (name), ", ");
12620Sstevel@tonic-gate hf = addone(hf, name);
12630Sstevel@tonic-gate }
12640Sstevel@tonic-gate return hf;
12650Sstevel@tonic-gate }
12660Sstevel@tonic-gate
12670Sstevel@tonic-gate /*
12680Sstevel@tonic-gate * Add a string to the end of a header entry field.
12690Sstevel@tonic-gate */
12700Sstevel@tonic-gate char *
addone(char hf[],char news[])12710Sstevel@tonic-gate addone(char hf[], char news[])
12720Sstevel@tonic-gate {
12730Sstevel@tonic-gate register char *cp, *cp2, *linebuf;
12740Sstevel@tonic-gate
12750Sstevel@tonic-gate if (hf == NOSTR)
12760Sstevel@tonic-gate hf = savestr("");
12770Sstevel@tonic-gate if (*news == '\0')
12780Sstevel@tonic-gate return(hf);
12790Sstevel@tonic-gate linebuf = (char *)srealloc(hf, (unsigned)(strlen(hf) + strlen(news) + 2));
12800Sstevel@tonic-gate cp2 = strchr(linebuf, '\0');
12810Sstevel@tonic-gate if (cp2 > linebuf && cp2[-1] != ' ')
12820Sstevel@tonic-gate *cp2++ = ' ';
12830Sstevel@tonic-gate for (cp = news; any(*cp, " \t"); cp++)
12840Sstevel@tonic-gate ;
12850Sstevel@tonic-gate while (*cp != '\0')
12860Sstevel@tonic-gate *cp2++ = *cp++;
12870Sstevel@tonic-gate *cp2 = '\0';
12880Sstevel@tonic-gate return(linebuf);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate static int
nptrs(char ** hf)12920Sstevel@tonic-gate nptrs(char **hf)
12930Sstevel@tonic-gate {
12940Sstevel@tonic-gate register int i;
12950Sstevel@tonic-gate
12960Sstevel@tonic-gate if (!hf)
12970Sstevel@tonic-gate return(0);
12980Sstevel@tonic-gate for (i = 0; *hf; hf++)
12990Sstevel@tonic-gate i++;
13000Sstevel@tonic-gate return(i);
13010Sstevel@tonic-gate }
13020Sstevel@tonic-gate
13030Sstevel@tonic-gate /*
13040Sstevel@tonic-gate * Add a non-standard header to the end of the non-standard headers.
13050Sstevel@tonic-gate */
13060Sstevel@tonic-gate static char **
Xaddone(char ** hf,char news[])13070Sstevel@tonic-gate Xaddone(char **hf, char news[])
13080Sstevel@tonic-gate {
13090Sstevel@tonic-gate register char *linebuf;
13100Sstevel@tonic-gate char **ohf = hf;
13110Sstevel@tonic-gate int nhf = nptrs(hf);
13120Sstevel@tonic-gate
13130Sstevel@tonic-gate if (hf == NOSTRPTR)
13140Sstevel@tonic-gate hf = (char**)salloc(sizeof(char*) * 2);
13150Sstevel@tonic-gate else
13160Sstevel@tonic-gate hf = (char**)srealloc(hf, sizeof(char*) * (nhf + 2));
13170Sstevel@tonic-gate if (hf == NOSTRPTR) {
13180Sstevel@tonic-gate fprintf(stderr, gettext("No room, header lost: %s\n"), news);
13190Sstevel@tonic-gate return(ohf);
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate linebuf = (char *)salloc((unsigned)(strlen(news) + 1));
13220Sstevel@tonic-gate strcpy(linebuf, news);
13230Sstevel@tonic-gate hf[nhf++] = linebuf;
13240Sstevel@tonic-gate hf[nhf] = NOSTR;
13250Sstevel@tonic-gate return(hf);
13260Sstevel@tonic-gate }
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate static void
cpout(char * str,FILE * ofd)13290Sstevel@tonic-gate cpout(char *str, FILE *ofd)
13300Sstevel@tonic-gate {
13310Sstevel@tonic-gate register char *cp = str;
13320Sstevel@tonic-gate
13330Sstevel@tonic-gate while (*cp) {
13340Sstevel@tonic-gate if (*cp == '\\') {
13350Sstevel@tonic-gate switch (*(cp+1)) {
13360Sstevel@tonic-gate case 'n':
13370Sstevel@tonic-gate putc('\n', ofd);
13380Sstevel@tonic-gate cp++;
13390Sstevel@tonic-gate break;
13400Sstevel@tonic-gate case 't':
13410Sstevel@tonic-gate putc('\t', ofd);
13420Sstevel@tonic-gate cp++;
13430Sstevel@tonic-gate break;
13440Sstevel@tonic-gate default:
13450Sstevel@tonic-gate putc('\\', ofd);
13460Sstevel@tonic-gate }
13470Sstevel@tonic-gate } else {
13480Sstevel@tonic-gate putc(*cp, ofd);
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate cp++;
13510Sstevel@tonic-gate }
13520Sstevel@tonic-gate putc('\n', ofd);
13530Sstevel@tonic-gate fflush(ofd);
13540Sstevel@tonic-gate }
13550Sstevel@tonic-gate
13560Sstevel@tonic-gate static void
xhalt(void)13570Sstevel@tonic-gate xhalt(void)
13580Sstevel@tonic-gate {
13590Sstevel@tonic-gate fclose(newo);
13600Sstevel@tonic-gate fclose(newi);
13610Sstevel@tonic-gate sigset(SIGINT, savesig);
13620Sstevel@tonic-gate sigset(SIGHUP, savehup);
13630Sstevel@tonic-gate if (rcvmode)
13640Sstevel@tonic-gate stop(0);
13650Sstevel@tonic-gate exit(1);
13660Sstevel@tonic-gate /* NOTREACHED */
13670Sstevel@tonic-gate }
13680Sstevel@tonic-gate
13690Sstevel@tonic-gate /*
13700Sstevel@tonic-gate * Strip the nulls from a buffer of length n
13710Sstevel@tonic-gate */
13720Sstevel@tonic-gate static int
stripnulls(register char * linebuf,register int nread)13730Sstevel@tonic-gate stripnulls(register char *linebuf, register int nread)
13740Sstevel@tonic-gate {
13750Sstevel@tonic-gate register int i, j;
13760Sstevel@tonic-gate
13770Sstevel@tonic-gate for (i = 0; i < nread; i++)
13780Sstevel@tonic-gate if (linebuf[i] == '\0')
13790Sstevel@tonic-gate break;
13800Sstevel@tonic-gate for (j = i; j < nread; j++)
13810Sstevel@tonic-gate if (linebuf[j] != '\0')
13820Sstevel@tonic-gate linebuf[i++] = linebuf[j];
13830Sstevel@tonic-gate linebuf[i] = '\0';
13840Sstevel@tonic-gate return(i);
13850Sstevel@tonic-gate }
1386