xref: /onnv-gate/usr/src/cmd/mailx/collect.c (revision 13093:48f2dbca79a2)
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