xref: /titanic_53/usr/src/cmd/mailx/collect.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 1998 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate /*
32*7c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
33*7c478bd9Sstevel@tonic-gate  * The Regents of the University of California
34*7c478bd9Sstevel@tonic-gate  * All Rights Reserved
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
37*7c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
38*7c478bd9Sstevel@tonic-gate  * contributors.
39*7c478bd9Sstevel@tonic-gate  */
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
42*7c478bd9Sstevel@tonic-gate 
43*7c478bd9Sstevel@tonic-gate /*
44*7c478bd9Sstevel@tonic-gate  * mailx -- a modified version of a University of California at Berkeley
45*7c478bd9Sstevel@tonic-gate  *	mail program
46*7c478bd9Sstevel@tonic-gate  *
47*7c478bd9Sstevel@tonic-gate  * Collect input from standard input, handling
48*7c478bd9Sstevel@tonic-gate  * ~ escapes.
49*7c478bd9Sstevel@tonic-gate  */
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate #include "rcv.h"
52*7c478bd9Sstevel@tonic-gate #include <locale.h>
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #ifdef SIGCONT
55*7c478bd9Sstevel@tonic-gate static void	collcont(int);
56*7c478bd9Sstevel@tonic-gate #endif
57*7c478bd9Sstevel@tonic-gate static void	collrub(int s);
58*7c478bd9Sstevel@tonic-gate static void	cpout(char *str, FILE *ofd);
59*7c478bd9Sstevel@tonic-gate static int	exwrite(char name[], FILE *ibuf);
60*7c478bd9Sstevel@tonic-gate static int	forward(char ms[], FILE *obuf, int f);
61*7c478bd9Sstevel@tonic-gate static void	intack(int);
62*7c478bd9Sstevel@tonic-gate static int	forward(char ms[], FILE *obuf, int f);
63*7c478bd9Sstevel@tonic-gate static FILE	*mesedit(FILE *ibuf, FILE *obuf, int c, struct header *hp);
64*7c478bd9Sstevel@tonic-gate static FILE	*mespipe(FILE *ibuf, FILE *obuf, char cmd[]);
65*7c478bd9Sstevel@tonic-gate static void	resetsigs(int resethup);
66*7c478bd9Sstevel@tonic-gate static int	stripnulls(register char *linebuf, register int nread);
67*7c478bd9Sstevel@tonic-gate static void	xhalt(void);
68*7c478bd9Sstevel@tonic-gate static char	**Xaddone(char **hf, char news[]);
69*7c478bd9Sstevel@tonic-gate static int	tabputs(const char *line, FILE *obuf);
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /*
72*7c478bd9Sstevel@tonic-gate  * Read a message from standard output and return a read file to it
73*7c478bd9Sstevel@tonic-gate  * or NULL on error.
74*7c478bd9Sstevel@tonic-gate  */
75*7c478bd9Sstevel@tonic-gate 
76*7c478bd9Sstevel@tonic-gate /*
77*7c478bd9Sstevel@tonic-gate  * The following hokiness with global variables is so that on
78*7c478bd9Sstevel@tonic-gate  * receipt of an interrupt signal, the partial message can be salted
79*7c478bd9Sstevel@tonic-gate  * away on dead.letter.  The output file must be available to flush,
80*7c478bd9Sstevel@tonic-gate  * and the input to read.  Several open files could be saved all through
81*7c478bd9Sstevel@tonic-gate  * mailx if stdio allowed simultaneous read/write access.
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate 
84*7c478bd9Sstevel@tonic-gate static void		(*savesig)(int);	/* Previous SIGINT value */
85*7c478bd9Sstevel@tonic-gate static void		(*savehup)(int);	/* Previous SIGHUP value */
86*7c478bd9Sstevel@tonic-gate #ifdef SIGCONT
87*7c478bd9Sstevel@tonic-gate static void		(*savecont)(int);	/* Previous SIGCONT value */
88*7c478bd9Sstevel@tonic-gate #endif
89*7c478bd9Sstevel@tonic-gate static FILE		*newi;		/* File for saving away */
90*7c478bd9Sstevel@tonic-gate static FILE		*newo;		/* Output side of same */
91*7c478bd9Sstevel@tonic-gate static int		ignintr;	/* Ignore interrups */
92*7c478bd9Sstevel@tonic-gate static int		hadintr;	/* Have seen one SIGINT so far */
93*7c478bd9Sstevel@tonic-gate static struct header	*savehp;
94*7c478bd9Sstevel@tonic-gate static jmp_buf		coljmp;		/* To get back to work */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate FILE *
97*7c478bd9Sstevel@tonic-gate collect(struct header *hp)
98*7c478bd9Sstevel@tonic-gate {
99*7c478bd9Sstevel@tonic-gate 	FILE *ibuf, *fbuf, *obuf;
100*7c478bd9Sstevel@tonic-gate 	int escape, eof;
101*7c478bd9Sstevel@tonic-gate 	long lc, cc;
102*7c478bd9Sstevel@tonic-gate 	register int c, t;
103*7c478bd9Sstevel@tonic-gate 	int hdrs;
104*7c478bd9Sstevel@tonic-gate 	char linebuf[LINESIZE+1], *cp;
105*7c478bd9Sstevel@tonic-gate 	char *iprompt;
106*7c478bd9Sstevel@tonic-gate 	int inhead;
107*7c478bd9Sstevel@tonic-gate 	void (*sigpipe)(int), (*sigint)(int);
108*7c478bd9Sstevel@tonic-gate 	int fd = -1;
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	noreset++;
111*7c478bd9Sstevel@tonic-gate 	ibuf = obuf = NULL;
112*7c478bd9Sstevel@tonic-gate 	newi = newo = NULL;
113*7c478bd9Sstevel@tonic-gate 	if ((fd = open(tempMail, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
114*7c478bd9Sstevel@tonic-gate 	(obuf = fdopen(fd, "w")) == NULL) {
115*7c478bd9Sstevel@tonic-gate 		perror(tempMail);
116*7c478bd9Sstevel@tonic-gate 		goto err;
117*7c478bd9Sstevel@tonic-gate 	}
118*7c478bd9Sstevel@tonic-gate 	newo = obuf;
119*7c478bd9Sstevel@tonic-gate 	if ((ibuf = fopen(tempMail, "r")) == NULL) {
120*7c478bd9Sstevel@tonic-gate 		perror(tempMail);
121*7c478bd9Sstevel@tonic-gate 		newo = NULL;
122*7c478bd9Sstevel@tonic-gate 		fclose(obuf);
123*7c478bd9Sstevel@tonic-gate 		goto err;
124*7c478bd9Sstevel@tonic-gate 	}
125*7c478bd9Sstevel@tonic-gate 	newi = ibuf;
126*7c478bd9Sstevel@tonic-gate 	removefile(tempMail);
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	ignintr = (int)value("ignore");
129*7c478bd9Sstevel@tonic-gate 	hadintr = 1;
130*7c478bd9Sstevel@tonic-gate 	inhead = 1;
131*7c478bd9Sstevel@tonic-gate 	savehp = hp;
132*7c478bd9Sstevel@tonic-gate # ifdef VMUNIX
133*7c478bd9Sstevel@tonic-gate 	if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
134*7c478bd9Sstevel@tonic-gate 		sigset(SIGINT, ignintr ? intack : collrub), sigblock(sigmask(SIGINT));
135*7c478bd9Sstevel@tonic-gate 	if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN)
136*7c478bd9Sstevel@tonic-gate 		sigset(SIGHUP, collrub), sigblock(sigmask(SIGHUP));
137*7c478bd9Sstevel@tonic-gate # else VMUNIX
138*7c478bd9Sstevel@tonic-gate # ifdef OLD_BSD_SIGS
139*7c478bd9Sstevel@tonic-gate 	if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN)
140*7c478bd9Sstevel@tonic-gate 		sigset(SIGINT, ignintr ? intack : collrub);
141*7c478bd9Sstevel@tonic-gate 	if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN)
142*7c478bd9Sstevel@tonic-gate 		sigset(SIGHUP, collrub);
143*7c478bd9Sstevel@tonic-gate # else
144*7c478bd9Sstevel@tonic-gate 	if ((savesig = sigset(SIGINT, SIG_IGN)) != SIG_IGN) {
145*7c478bd9Sstevel@tonic-gate 		sigset_t mask;
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 		sigemptyset(&mask);
148*7c478bd9Sstevel@tonic-gate 		sigaddset(&mask, SIGINT);
149*7c478bd9Sstevel@tonic-gate 		sigset(SIGINT, ignintr ? intack : collrub);
150*7c478bd9Sstevel@tonic-gate 		sigprocmask(SIG_BLOCK, &mask, NULL);
151*7c478bd9Sstevel@tonic-gate 	}
152*7c478bd9Sstevel@tonic-gate 	if ((savehup = sigset(SIGHUP, SIG_IGN)) != SIG_IGN) {
153*7c478bd9Sstevel@tonic-gate 		sigset_t mask;
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 		sigemptyset(&mask);
156*7c478bd9Sstevel@tonic-gate 		sigaddset(&mask, SIGHUP);
157*7c478bd9Sstevel@tonic-gate 		sigset(SIGHUP, collrub);
158*7c478bd9Sstevel@tonic-gate 		sigprocmask(SIG_BLOCK, &mask, NULL);
159*7c478bd9Sstevel@tonic-gate 	}
160*7c478bd9Sstevel@tonic-gate # endif
161*7c478bd9Sstevel@tonic-gate # endif VMUNIX
162*7c478bd9Sstevel@tonic-gate #ifdef SIGCONT
163*7c478bd9Sstevel@tonic-gate 	savecont = sigset(SIGCONT, collcont);
164*7c478bd9Sstevel@tonic-gate #endif
165*7c478bd9Sstevel@tonic-gate 	/*
166*7c478bd9Sstevel@tonic-gate 	 * If we are going to prompt for subject/cc/bcc,
167*7c478bd9Sstevel@tonic-gate 	 * refrain from printing a newline after
168*7c478bd9Sstevel@tonic-gate 	 * the headers (since some people mind).
169*7c478bd9Sstevel@tonic-gate 	 */
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	if (hp->h_subject == NOSTR) {
172*7c478bd9Sstevel@tonic-gate 		hp->h_subject = sflag;
173*7c478bd9Sstevel@tonic-gate 		sflag = NOSTR;
174*7c478bd9Sstevel@tonic-gate 	}
175*7c478bd9Sstevel@tonic-gate 	if (hp->h_cc == NOSTR) {
176*7c478bd9Sstevel@tonic-gate 		hp->h_cc = cflag;
177*7c478bd9Sstevel@tonic-gate 		cflag = NOSTR;
178*7c478bd9Sstevel@tonic-gate 	}
179*7c478bd9Sstevel@tonic-gate 	if (hp->h_bcc == NOSTR) {
180*7c478bd9Sstevel@tonic-gate 		hp->h_bcc = bflag;
181*7c478bd9Sstevel@tonic-gate 		bflag = NOSTR;
182*7c478bd9Sstevel@tonic-gate 	}
183*7c478bd9Sstevel@tonic-gate 	t = GMASK;
184*7c478bd9Sstevel@tonic-gate 	hdrs = 0;
185*7c478bd9Sstevel@tonic-gate 	if (intty && !tflag) {
186*7c478bd9Sstevel@tonic-gate 		if (hp->h_to == NOSTR)
187*7c478bd9Sstevel@tonic-gate 			hdrs |= GTO;
188*7c478bd9Sstevel@tonic-gate 		if (hp->h_subject == NOSTR && value("asksub"))
189*7c478bd9Sstevel@tonic-gate 			hdrs |= GSUBJECT;
190*7c478bd9Sstevel@tonic-gate 		if (hp->h_cc == NOSTR && value("askcc"))
191*7c478bd9Sstevel@tonic-gate 			hdrs |= GCC;
192*7c478bd9Sstevel@tonic-gate 		if (hp->h_bcc == NOSTR && value("askbcc"))
193*7c478bd9Sstevel@tonic-gate 			hdrs |= GBCC;
194*7c478bd9Sstevel@tonic-gate 		if (hdrs)
195*7c478bd9Sstevel@tonic-gate 			t &= ~GNL;
196*7c478bd9Sstevel@tonic-gate 	}
197*7c478bd9Sstevel@tonic-gate 	if (hp->h_seq != 0) {
198*7c478bd9Sstevel@tonic-gate 		puthead(hp, stdout, t, 0);
199*7c478bd9Sstevel@tonic-gate 		fflush(stdout);
200*7c478bd9Sstevel@tonic-gate 	}
201*7c478bd9Sstevel@tonic-gate 	if (setjmp(coljmp))
202*7c478bd9Sstevel@tonic-gate 		goto err;
203*7c478bd9Sstevel@tonic-gate 	escape = SENDESC;
204*7c478bd9Sstevel@tonic-gate 	if ((cp = value("escape")) != NOSTR)
205*7c478bd9Sstevel@tonic-gate 		escape = *cp;
206*7c478bd9Sstevel@tonic-gate 	eof = 0;
207*7c478bd9Sstevel@tonic-gate 	if ((cp = value("MAILX_HEAD")) != NOSTR) {
208*7c478bd9Sstevel@tonic-gate 	      cpout( cp, obuf);
209*7c478bd9Sstevel@tonic-gate 	      if (isatty(fileno(stdin)))
210*7c478bd9Sstevel@tonic-gate 		    cpout( cp, stdout);
211*7c478bd9Sstevel@tonic-gate 	}
212*7c478bd9Sstevel@tonic-gate 	iprompt = value("iprompt");
213*7c478bd9Sstevel@tonic-gate 	fflush(obuf);
214*7c478bd9Sstevel@tonic-gate 	hadintr = 0;
215*7c478bd9Sstevel@tonic-gate 	for (;;) {
216*7c478bd9Sstevel@tonic-gate 		int nread, hasnulls;
217*7c478bd9Sstevel@tonic-gate # ifdef VMUNIX
218*7c478bd9Sstevel@tonic-gate 		int omask = sigblock(0) &~ (sigmask(SIGINT)|sigmask(SIGHUP));
219*7c478bd9Sstevel@tonic-gate # else
220*7c478bd9Sstevel@tonic-gate # ifndef OLD_BSD_SIGS
221*7c478bd9Sstevel@tonic-gate 		sigset_t omask;
222*7c478bd9Sstevel@tonic-gate 		sigprocmask(0, NULL, &omask);
223*7c478bd9Sstevel@tonic-gate 		sigdelset(&omask, SIGINT);
224*7c478bd9Sstevel@tonic-gate 		sigdelset(&omask, SIGHUP);
225*7c478bd9Sstevel@tonic-gate # endif
226*7c478bd9Sstevel@tonic-gate # endif
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 		setjmp(coljmp);
229*7c478bd9Sstevel@tonic-gate # ifdef VMUNIX
230*7c478bd9Sstevel@tonic-gate 		sigsetmask(omask);
231*7c478bd9Sstevel@tonic-gate # else VMUNIX
232*7c478bd9Sstevel@tonic-gate # ifdef OLD_BSD_SIGS
233*7c478bd9Sstevel@tonic-gate 		sigrelse(SIGINT);
234*7c478bd9Sstevel@tonic-gate 		sigrelse(SIGHUP);
235*7c478bd9Sstevel@tonic-gate # else
236*7c478bd9Sstevel@tonic-gate 		sigprocmask(SIG_SETMASK, &omask, NULL);
237*7c478bd9Sstevel@tonic-gate # endif
238*7c478bd9Sstevel@tonic-gate # endif VMUNIX
239*7c478bd9Sstevel@tonic-gate 		if (intty && !tflag && outtty && iprompt)
240*7c478bd9Sstevel@tonic-gate 			fputs(iprompt, stdout);
241*7c478bd9Sstevel@tonic-gate 		flush();
242*7c478bd9Sstevel@tonic-gate 		if (hdrs) {
243*7c478bd9Sstevel@tonic-gate 			grabh(hp, hdrs, 1);
244*7c478bd9Sstevel@tonic-gate 			hdrs = 0;
245*7c478bd9Sstevel@tonic-gate 			continue;
246*7c478bd9Sstevel@tonic-gate 		}
247*7c478bd9Sstevel@tonic-gate 		if ((nread = getline(linebuf,LINESIZE,stdin,&hasnulls)) == NULL) {
248*7c478bd9Sstevel@tonic-gate 			if (intty && value("ignoreeof") != NOSTR) {
249*7c478bd9Sstevel@tonic-gate 				if (++eof > 35)
250*7c478bd9Sstevel@tonic-gate 					break;
251*7c478bd9Sstevel@tonic-gate 				printf(gettext(
252*7c478bd9Sstevel@tonic-gate 				    "Use \".\" to terminate letter\n"));
253*7c478bd9Sstevel@tonic-gate 				continue;
254*7c478bd9Sstevel@tonic-gate 			}
255*7c478bd9Sstevel@tonic-gate 			break;
256*7c478bd9Sstevel@tonic-gate 		}
257*7c478bd9Sstevel@tonic-gate 		eof = 0;
258*7c478bd9Sstevel@tonic-gate 		hadintr = 0;
259*7c478bd9Sstevel@tonic-gate 		if (intty && equal(".\n", linebuf) &&
260*7c478bd9Sstevel@tonic-gate 		    (value("dot") != NOSTR || value("ignoreeof") != NOSTR))
261*7c478bd9Sstevel@tonic-gate 			break;
262*7c478bd9Sstevel@tonic-gate 		/*
263*7c478bd9Sstevel@tonic-gate 		 * If -t, scan text for headers.
264*7c478bd9Sstevel@tonic-gate 		 */
265*7c478bd9Sstevel@tonic-gate 		if (tflag) {
266*7c478bd9Sstevel@tonic-gate 			char *cp2;
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 			if (!inhead) {
269*7c478bd9Sstevel@tonic-gate 			writeit:
270*7c478bd9Sstevel@tonic-gate 				if (write(fileno(obuf),linebuf,nread) != nread)
271*7c478bd9Sstevel@tonic-gate 					goto werr;
272*7c478bd9Sstevel@tonic-gate 				continue;
273*7c478bd9Sstevel@tonic-gate 			}
274*7c478bd9Sstevel@tonic-gate 			if (linebuf[0] == '\n') {
275*7c478bd9Sstevel@tonic-gate 				/* got blank line after header, ignore it */
276*7c478bd9Sstevel@tonic-gate 				inhead = 0;
277*7c478bd9Sstevel@tonic-gate 				continue;
278*7c478bd9Sstevel@tonic-gate 			}
279*7c478bd9Sstevel@tonic-gate 			if (!headerp(linebuf)) {
280*7c478bd9Sstevel@tonic-gate 				/* got non-header line, save it */
281*7c478bd9Sstevel@tonic-gate 				inhead = 0;
282*7c478bd9Sstevel@tonic-gate 				goto writeit;
283*7c478bd9Sstevel@tonic-gate 			}
284*7c478bd9Sstevel@tonic-gate 			if (hasnulls)
285*7c478bd9Sstevel@tonic-gate 				nread = stripnulls(linebuf, nread);
286*7c478bd9Sstevel@tonic-gate 			for (;;) {
287*7c478bd9Sstevel@tonic-gate 				char line2[LINESIZE];
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate 				c = getc(stdin);
290*7c478bd9Sstevel@tonic-gate 				ungetc(c, stdin);
291*7c478bd9Sstevel@tonic-gate 				if (!isspace(c) || c == '\n')
292*7c478bd9Sstevel@tonic-gate 					break;
293*7c478bd9Sstevel@tonic-gate 				if (readline(stdin, line2) < 0)
294*7c478bd9Sstevel@tonic-gate 					break;
295*7c478bd9Sstevel@tonic-gate 				for (cp2 = line2; *cp2 != 0 && isspace(*cp2);
296*7c478bd9Sstevel@tonic-gate 				    cp2++)
297*7c478bd9Sstevel@tonic-gate 					;
298*7c478bd9Sstevel@tonic-gate 				if (strlen(linebuf) + strlen(cp2) >=
299*7c478bd9Sstevel@tonic-gate 				    (unsigned)LINESIZE-2)
300*7c478bd9Sstevel@tonic-gate 					break;
301*7c478bd9Sstevel@tonic-gate 				cp = &linebuf[strlen(linebuf)];
302*7c478bd9Sstevel@tonic-gate 				while (cp > linebuf &&
303*7c478bd9Sstevel@tonic-gate 				    (isspace(cp[-1]) || cp[-1] == '\\'))
304*7c478bd9Sstevel@tonic-gate 					cp--;
305*7c478bd9Sstevel@tonic-gate 				*cp++ = ' ';
306*7c478bd9Sstevel@tonic-gate 				strcpy(cp, cp2);
307*7c478bd9Sstevel@tonic-gate 			}
308*7c478bd9Sstevel@tonic-gate 			if ((c = strlen(linebuf)) > 0) {
309*7c478bd9Sstevel@tonic-gate 				cp = &linebuf[c-1];
310*7c478bd9Sstevel@tonic-gate 				while (cp > linebuf && isspace(*cp))
311*7c478bd9Sstevel@tonic-gate 					cp--;
312*7c478bd9Sstevel@tonic-gate 				*++cp = 0;
313*7c478bd9Sstevel@tonic-gate 			}
314*7c478bd9Sstevel@tonic-gate 			if (ishfield(linebuf, "to"))
315*7c478bd9Sstevel@tonic-gate 				hp->h_to = addto(hp->h_to, hcontents(linebuf));
316*7c478bd9Sstevel@tonic-gate 			else if (ishfield(linebuf, "subject"))
317*7c478bd9Sstevel@tonic-gate 				hp->h_subject =
318*7c478bd9Sstevel@tonic-gate 				    addone(hp->h_subject, hcontents(linebuf));
319*7c478bd9Sstevel@tonic-gate 			else if (ishfield(linebuf, "cc"))
320*7c478bd9Sstevel@tonic-gate 				hp->h_cc = addto(hp->h_cc, hcontents(linebuf));
321*7c478bd9Sstevel@tonic-gate 			else if (ishfield(linebuf, "bcc"))
322*7c478bd9Sstevel@tonic-gate 				hp->h_bcc =
323*7c478bd9Sstevel@tonic-gate 				    addto(hp->h_bcc, hcontents(linebuf));
324*7c478bd9Sstevel@tonic-gate 			else if (ishfield(linebuf, "default-options"))
325*7c478bd9Sstevel@tonic-gate 				hp->h_defopt =
326*7c478bd9Sstevel@tonic-gate 				    addone(hp->h_defopt, hcontents(linebuf));
327*7c478bd9Sstevel@tonic-gate 			else
328*7c478bd9Sstevel@tonic-gate 				hp->h_others = Xaddone(hp->h_others, linebuf);
329*7c478bd9Sstevel@tonic-gate 			hp->h_seq++;
330*7c478bd9Sstevel@tonic-gate 			continue;
331*7c478bd9Sstevel@tonic-gate 		}
332*7c478bd9Sstevel@tonic-gate 		if ((linebuf[0] != escape) || (rflag != NOSTR) ||
333*7c478bd9Sstevel@tonic-gate 		    (!intty && !(int)value("escapeok"))) {
334*7c478bd9Sstevel@tonic-gate 			if (write(fileno(obuf),linebuf,nread) != nread)
335*7c478bd9Sstevel@tonic-gate 				goto werr;
336*7c478bd9Sstevel@tonic-gate 			continue;
337*7c478bd9Sstevel@tonic-gate 		}
338*7c478bd9Sstevel@tonic-gate 		/*
339*7c478bd9Sstevel@tonic-gate 		 * On double escape, just send the single one.
340*7c478bd9Sstevel@tonic-gate 		 */
341*7c478bd9Sstevel@tonic-gate 		if ((nread > 1) && (linebuf[1] == escape)) {
342*7c478bd9Sstevel@tonic-gate 			if (write(fileno(obuf),linebuf+1,nread-1) != (nread-1))
343*7c478bd9Sstevel@tonic-gate 				goto werr;
344*7c478bd9Sstevel@tonic-gate 			continue;
345*7c478bd9Sstevel@tonic-gate 		}
346*7c478bd9Sstevel@tonic-gate 		if (hasnulls)
347*7c478bd9Sstevel@tonic-gate 			nread = stripnulls(linebuf, nread);
348*7c478bd9Sstevel@tonic-gate 		c = linebuf[1];
349*7c478bd9Sstevel@tonic-gate 		linebuf[nread - 1] = '\0';
350*7c478bd9Sstevel@tonic-gate 		switch (c) {
351*7c478bd9Sstevel@tonic-gate 		default:
352*7c478bd9Sstevel@tonic-gate 			/*
353*7c478bd9Sstevel@tonic-gate 			 * Otherwise, it's an error.
354*7c478bd9Sstevel@tonic-gate 			 */
355*7c478bd9Sstevel@tonic-gate 			printf(gettext("Unknown tilde escape.\n"));
356*7c478bd9Sstevel@tonic-gate 			break;
357*7c478bd9Sstevel@tonic-gate 
358*7c478bd9Sstevel@tonic-gate 		case 'a':
359*7c478bd9Sstevel@tonic-gate 		case 'A':
360*7c478bd9Sstevel@tonic-gate 			/*
361*7c478bd9Sstevel@tonic-gate 			 * autograph; sign the letter.
362*7c478bd9Sstevel@tonic-gate 			 */
363*7c478bd9Sstevel@tonic-gate 
364*7c478bd9Sstevel@tonic-gate 			if (cp = value(c=='a' ? "sign":"Sign")) {
365*7c478bd9Sstevel@tonic-gate 			      if (*cp)
366*7c478bd9Sstevel@tonic-gate 			          cpout( cp, obuf);
367*7c478bd9Sstevel@tonic-gate 			      if (isatty(fileno(stdin))) {
368*7c478bd9Sstevel@tonic-gate 			          if (*cp)
369*7c478bd9Sstevel@tonic-gate 				      cpout( cp, stdout);
370*7c478bd9Sstevel@tonic-gate 			    }
371*7c478bd9Sstevel@tonic-gate 			}
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 			break;
374*7c478bd9Sstevel@tonic-gate 
375*7c478bd9Sstevel@tonic-gate 		case 'i':
376*7c478bd9Sstevel@tonic-gate 			/*
377*7c478bd9Sstevel@tonic-gate 			 * insert string
378*7c478bd9Sstevel@tonic-gate 			 */
379*7c478bd9Sstevel@tonic-gate 			for (cp = &linebuf[2]; any(*cp, " \t"); cp++)
380*7c478bd9Sstevel@tonic-gate 				;
381*7c478bd9Sstevel@tonic-gate 			if (*cp)
382*7c478bd9Sstevel@tonic-gate 				cp = value(cp);
383*7c478bd9Sstevel@tonic-gate 			if (cp != NOSTR) {
384*7c478bd9Sstevel@tonic-gate 				if (*cp)
385*7c478bd9Sstevel@tonic-gate 				    cpout(cp, obuf);
386*7c478bd9Sstevel@tonic-gate 				if (isatty(fileno(stdout))) {
387*7c478bd9Sstevel@tonic-gate 					if (*cp)
388*7c478bd9Sstevel@tonic-gate 					    cpout(cp, stdout);
389*7c478bd9Sstevel@tonic-gate 				}
390*7c478bd9Sstevel@tonic-gate 			}
391*7c478bd9Sstevel@tonic-gate 			break;
392*7c478bd9Sstevel@tonic-gate 
393*7c478bd9Sstevel@tonic-gate 		case '!':
394*7c478bd9Sstevel@tonic-gate 			/*
395*7c478bd9Sstevel@tonic-gate 			 * Shell escape, send the balance of the
396*7c478bd9Sstevel@tonic-gate 			 * line to sh -c.
397*7c478bd9Sstevel@tonic-gate 			 */
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 			shell(&linebuf[2]);
400*7c478bd9Sstevel@tonic-gate 			break;
401*7c478bd9Sstevel@tonic-gate 
402*7c478bd9Sstevel@tonic-gate 		case ':':
403*7c478bd9Sstevel@tonic-gate 		case '_':
404*7c478bd9Sstevel@tonic-gate 			/*
405*7c478bd9Sstevel@tonic-gate 			 * Escape to command mode, but be nice!
406*7c478bd9Sstevel@tonic-gate 			 */
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 			execute(&linebuf[2], 1);
409*7c478bd9Sstevel@tonic-gate 			iprompt = value("iprompt");
410*7c478bd9Sstevel@tonic-gate 			if (cp = value("escape"))
411*7c478bd9Sstevel@tonic-gate 				escape = *cp;
412*7c478bd9Sstevel@tonic-gate 			printf(gettext("(continue)\n"));
413*7c478bd9Sstevel@tonic-gate 			break;
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 		case '.':
416*7c478bd9Sstevel@tonic-gate 			/*
417*7c478bd9Sstevel@tonic-gate 			 * Simulate end of file on input.
418*7c478bd9Sstevel@tonic-gate 			 */
419*7c478bd9Sstevel@tonic-gate 			goto eofl;
420*7c478bd9Sstevel@tonic-gate 
421*7c478bd9Sstevel@tonic-gate 		case 'q':
422*7c478bd9Sstevel@tonic-gate 		case 'Q':
423*7c478bd9Sstevel@tonic-gate 			/*
424*7c478bd9Sstevel@tonic-gate 			 * Force a quit of sending mail.
425*7c478bd9Sstevel@tonic-gate 			 * Act like an interrupt happened.
426*7c478bd9Sstevel@tonic-gate 			 */
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 			hadintr++;
429*7c478bd9Sstevel@tonic-gate 			collrub(SIGINT);
430*7c478bd9Sstevel@tonic-gate 			exit(1);
431*7c478bd9Sstevel@tonic-gate 			/* NOTREACHED */
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 		case 'x':
434*7c478bd9Sstevel@tonic-gate 			xhalt();
435*7c478bd9Sstevel@tonic-gate 			break; 	/* not reached */
436*7c478bd9Sstevel@tonic-gate 
437*7c478bd9Sstevel@tonic-gate 		case 'h':
438*7c478bd9Sstevel@tonic-gate 			/*
439*7c478bd9Sstevel@tonic-gate 			 * Grab a bunch of headers.
440*7c478bd9Sstevel@tonic-gate 			 */
441*7c478bd9Sstevel@tonic-gate 			if (!intty || !outtty) {
442*7c478bd9Sstevel@tonic-gate 				printf(gettext("~h: no can do!?\n"));
443*7c478bd9Sstevel@tonic-gate 				break;
444*7c478bd9Sstevel@tonic-gate 			}
445*7c478bd9Sstevel@tonic-gate 			grabh(hp, GMASK, (int)value("bsdcompat"));
446*7c478bd9Sstevel@tonic-gate 			printf(gettext("(continue)\n"));
447*7c478bd9Sstevel@tonic-gate 			break;
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 		case 't':
450*7c478bd9Sstevel@tonic-gate 			/*
451*7c478bd9Sstevel@tonic-gate 			 * Add to the To list.
452*7c478bd9Sstevel@tonic-gate 			 */
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 			hp->h_to = addto(hp->h_to, &linebuf[2]);
455*7c478bd9Sstevel@tonic-gate 			hp->h_seq++;
456*7c478bd9Sstevel@tonic-gate 			break;
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 		case 's':
459*7c478bd9Sstevel@tonic-gate 			/*
460*7c478bd9Sstevel@tonic-gate 			 * Set the Subject list.
461*7c478bd9Sstevel@tonic-gate 			 */
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 			cp = &linebuf[2];
464*7c478bd9Sstevel@tonic-gate 			while (any(*cp, " \t"))
465*7c478bd9Sstevel@tonic-gate 				cp++;
466*7c478bd9Sstevel@tonic-gate 			hp->h_subject = savestr(cp);
467*7c478bd9Sstevel@tonic-gate 			hp->h_seq++;
468*7c478bd9Sstevel@tonic-gate 			break;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 		case 'c':
471*7c478bd9Sstevel@tonic-gate 			/*
472*7c478bd9Sstevel@tonic-gate 			 * Add to the CC list.
473*7c478bd9Sstevel@tonic-gate 			 */
474*7c478bd9Sstevel@tonic-gate 
475*7c478bd9Sstevel@tonic-gate 			hp->h_cc = addto(hp->h_cc, &linebuf[2]);
476*7c478bd9Sstevel@tonic-gate 			hp->h_seq++;
477*7c478bd9Sstevel@tonic-gate 			break;
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 		case 'b':
480*7c478bd9Sstevel@tonic-gate 			/*
481*7c478bd9Sstevel@tonic-gate 			 * Add stuff to blind carbon copies list.
482*7c478bd9Sstevel@tonic-gate 			 */
483*7c478bd9Sstevel@tonic-gate 			hp->h_bcc = addto(hp->h_bcc, &linebuf[2]);
484*7c478bd9Sstevel@tonic-gate 			hp->h_seq++;
485*7c478bd9Sstevel@tonic-gate 			break;
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 		case 'R':
488*7c478bd9Sstevel@tonic-gate 			hp->h_defopt = addone(hp->h_defopt, myname);
489*7c478bd9Sstevel@tonic-gate 			hp->h_seq++;
490*7c478bd9Sstevel@tonic-gate 			fprintf(stderr, gettext("Return receipt marked.\n"));
491*7c478bd9Sstevel@tonic-gate 			receipt_flg = 1;
492*7c478bd9Sstevel@tonic-gate 			break;
493*7c478bd9Sstevel@tonic-gate 
494*7c478bd9Sstevel@tonic-gate 		case 'd':
495*7c478bd9Sstevel@tonic-gate 			copy(Getf("DEAD"), &linebuf[2]);
496*7c478bd9Sstevel@tonic-gate 			/* FALLTHROUGH */
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate 		case '<':
499*7c478bd9Sstevel@tonic-gate 		case 'r': {
500*7c478bd9Sstevel@tonic-gate 			int	ispip;
501*7c478bd9Sstevel@tonic-gate 			/*
502*7c478bd9Sstevel@tonic-gate 			 * Invoke a file:
503*7c478bd9Sstevel@tonic-gate 			 * Search for the file name,
504*7c478bd9Sstevel@tonic-gate 			 * then open it and copy the contents to obuf.
505*7c478bd9Sstevel@tonic-gate 			 *
506*7c478bd9Sstevel@tonic-gate 			 * if name begins with '!', read from a command
507*7c478bd9Sstevel@tonic-gate 			 */
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate 			cp = &linebuf[2];
510*7c478bd9Sstevel@tonic-gate 			while (any(*cp, " \t"))
511*7c478bd9Sstevel@tonic-gate 				cp++;
512*7c478bd9Sstevel@tonic-gate 			if (*cp == '\0') {
513*7c478bd9Sstevel@tonic-gate 				printf(gettext("Interpolate what file?\n"));
514*7c478bd9Sstevel@tonic-gate 				break;
515*7c478bd9Sstevel@tonic-gate 			}
516*7c478bd9Sstevel@tonic-gate 			if (*cp=='!') {
517*7c478bd9Sstevel@tonic-gate 				/* take input from a command */
518*7c478bd9Sstevel@tonic-gate 				ispip = 1;
519*7c478bd9Sstevel@tonic-gate 				if ((fbuf = npopen(++cp, "r"))==NULL) {
520*7c478bd9Sstevel@tonic-gate 					perror("");
521*7c478bd9Sstevel@tonic-gate 					break;
522*7c478bd9Sstevel@tonic-gate 				}
523*7c478bd9Sstevel@tonic-gate 				sigint = sigset(SIGINT, SIG_IGN);
524*7c478bd9Sstevel@tonic-gate 			} else {
525*7c478bd9Sstevel@tonic-gate 				ispip = 0;
526*7c478bd9Sstevel@tonic-gate 				cp = expand(cp);
527*7c478bd9Sstevel@tonic-gate 				if (cp == NOSTR)
528*7c478bd9Sstevel@tonic-gate 					break;
529*7c478bd9Sstevel@tonic-gate 				if (isdir(cp)) {
530*7c478bd9Sstevel@tonic-gate 					printf(gettext("%s: directory\n"), cp);
531*7c478bd9Sstevel@tonic-gate 					break;
532*7c478bd9Sstevel@tonic-gate 				}
533*7c478bd9Sstevel@tonic-gate 				if ((fbuf = fopen(cp, "r")) == NULL) {
534*7c478bd9Sstevel@tonic-gate 					perror(cp);
535*7c478bd9Sstevel@tonic-gate 					break;
536*7c478bd9Sstevel@tonic-gate 				}
537*7c478bd9Sstevel@tonic-gate 			}
538*7c478bd9Sstevel@tonic-gate 			printf("\"%s\" ", cp);
539*7c478bd9Sstevel@tonic-gate 			flush();
540*7c478bd9Sstevel@tonic-gate 			lc = cc = 0;
541*7c478bd9Sstevel@tonic-gate 			while ((t = getc(fbuf)) != EOF) {
542*7c478bd9Sstevel@tonic-gate 				if (t == '\n')
543*7c478bd9Sstevel@tonic-gate 					lc++;
544*7c478bd9Sstevel@tonic-gate 				if (putc(t, obuf) == EOF) {
545*7c478bd9Sstevel@tonic-gate 					if (ispip) {
546*7c478bd9Sstevel@tonic-gate 						npclose(fbuf);
547*7c478bd9Sstevel@tonic-gate 						sigset(SIGINT, sigint);
548*7c478bd9Sstevel@tonic-gate 					} else
549*7c478bd9Sstevel@tonic-gate 						fclose(fbuf);
550*7c478bd9Sstevel@tonic-gate 					goto werr;
551*7c478bd9Sstevel@tonic-gate 				}
552*7c478bd9Sstevel@tonic-gate 				cc++;
553*7c478bd9Sstevel@tonic-gate 			}
554*7c478bd9Sstevel@tonic-gate 			if (ispip) {
555*7c478bd9Sstevel@tonic-gate 				npclose(fbuf);
556*7c478bd9Sstevel@tonic-gate 				sigset(SIGINT, sigint);
557*7c478bd9Sstevel@tonic-gate 			} else
558*7c478bd9Sstevel@tonic-gate 				fclose(fbuf);
559*7c478bd9Sstevel@tonic-gate 			printf("%ld/%ld\n", lc, cc);
560*7c478bd9Sstevel@tonic-gate 			fflush(obuf);
561*7c478bd9Sstevel@tonic-gate 			break;
562*7c478bd9Sstevel@tonic-gate 			}
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 		case 'w':
565*7c478bd9Sstevel@tonic-gate 			/*
566*7c478bd9Sstevel@tonic-gate 			 * Write the message on a file.
567*7c478bd9Sstevel@tonic-gate 			 */
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 			cp = &linebuf[2];
570*7c478bd9Sstevel@tonic-gate 			while (any(*cp, " \t"))
571*7c478bd9Sstevel@tonic-gate 				cp++;
572*7c478bd9Sstevel@tonic-gate 			if (*cp == '\0') {
573*7c478bd9Sstevel@tonic-gate 				fprintf(stderr, gettext("Write what file!?\n"));
574*7c478bd9Sstevel@tonic-gate 				break;
575*7c478bd9Sstevel@tonic-gate 			}
576*7c478bd9Sstevel@tonic-gate 			if ((cp = expand(cp)) == NOSTR)
577*7c478bd9Sstevel@tonic-gate 				break;
578*7c478bd9Sstevel@tonic-gate 			fflush(obuf);
579*7c478bd9Sstevel@tonic-gate 			rewind(ibuf);
580*7c478bd9Sstevel@tonic-gate 			exwrite(cp, ibuf);
581*7c478bd9Sstevel@tonic-gate 			break;
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 		case 'm':
584*7c478bd9Sstevel@tonic-gate 		case 'M':
585*7c478bd9Sstevel@tonic-gate 		case 'f':
586*7c478bd9Sstevel@tonic-gate 		case 'F':
587*7c478bd9Sstevel@tonic-gate 			/*
588*7c478bd9Sstevel@tonic-gate 			 * Interpolate the named messages, if we
589*7c478bd9Sstevel@tonic-gate 			 * are in receiving mail mode.  Does the
590*7c478bd9Sstevel@tonic-gate 			 * standard list processing garbage.
591*7c478bd9Sstevel@tonic-gate 			 * If ~f or ~F is given, we don't shift over.
592*7c478bd9Sstevel@tonic-gate 			 */
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 			if (!rcvmode) {
595*7c478bd9Sstevel@tonic-gate 				printf(gettext(
596*7c478bd9Sstevel@tonic-gate 				    "No messages to send from!?!\n"));
597*7c478bd9Sstevel@tonic-gate 				break;
598*7c478bd9Sstevel@tonic-gate 			}
599*7c478bd9Sstevel@tonic-gate 			cp = &linebuf[2];
600*7c478bd9Sstevel@tonic-gate 			while (any(*cp, " \t"))
601*7c478bd9Sstevel@tonic-gate 				cp++;
602*7c478bd9Sstevel@tonic-gate 			if (forward(cp, obuf, c) < 0)
603*7c478bd9Sstevel@tonic-gate 				goto werr;
604*7c478bd9Sstevel@tonic-gate 			fflush(obuf);
605*7c478bd9Sstevel@tonic-gate 			printf(gettext("(continue)\n"));
606*7c478bd9Sstevel@tonic-gate 			break;
607*7c478bd9Sstevel@tonic-gate 
608*7c478bd9Sstevel@tonic-gate 		case '?':
609*7c478bd9Sstevel@tonic-gate 			if ((fbuf = fopen(THELPFILE, "r")) == NULL) {
610*7c478bd9Sstevel@tonic-gate 				printf(gettext("No help just now.\n"));
611*7c478bd9Sstevel@tonic-gate 				break;
612*7c478bd9Sstevel@tonic-gate 			}
613*7c478bd9Sstevel@tonic-gate 			t = getc(fbuf);
614*7c478bd9Sstevel@tonic-gate 			while (t != -1) {
615*7c478bd9Sstevel@tonic-gate 				putchar(t);
616*7c478bd9Sstevel@tonic-gate 				t = getc(fbuf);
617*7c478bd9Sstevel@tonic-gate 			}
618*7c478bd9Sstevel@tonic-gate 			fclose(fbuf);
619*7c478bd9Sstevel@tonic-gate 			break;
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 		case 'p': {
622*7c478bd9Sstevel@tonic-gate 			/*
623*7c478bd9Sstevel@tonic-gate 			 * Print out the current state of the
624*7c478bd9Sstevel@tonic-gate 			 * message without altering anything.
625*7c478bd9Sstevel@tonic-gate 			 */
626*7c478bd9Sstevel@tonic-gate 			int nlines;
627*7c478bd9Sstevel@tonic-gate 			extern jmp_buf pipestop;
628*7c478bd9Sstevel@tonic-gate 			extern void brokpipe(int);
629*7c478bd9Sstevel@tonic-gate 
630*7c478bd9Sstevel@tonic-gate 			fflush(obuf);
631*7c478bd9Sstevel@tonic-gate 			rewind(ibuf);
632*7c478bd9Sstevel@tonic-gate 			fbuf = stdout;
633*7c478bd9Sstevel@tonic-gate 			if (setjmp(pipestop))
634*7c478bd9Sstevel@tonic-gate 				goto ret0;
635*7c478bd9Sstevel@tonic-gate 			if (intty && outtty && (cp = value("crt")) != NOSTR) {
636*7c478bd9Sstevel@tonic-gate 				nlines =
637*7c478bd9Sstevel@tonic-gate 				    (*cp == '\0' ? screensize() : atoi(cp)) - 7;
638*7c478bd9Sstevel@tonic-gate 				    /* 7 for hdr lines */
639*7c478bd9Sstevel@tonic-gate 				while ((t = getc(ibuf)) != EOF) {
640*7c478bd9Sstevel@tonic-gate 					if (t == '\n')
641*7c478bd9Sstevel@tonic-gate 						if (--nlines <= 0)
642*7c478bd9Sstevel@tonic-gate 							break;
643*7c478bd9Sstevel@tonic-gate 				}
644*7c478bd9Sstevel@tonic-gate 				rewind(ibuf);
645*7c478bd9Sstevel@tonic-gate 				if (nlines <= 0) {
646*7c478bd9Sstevel@tonic-gate 					fbuf = npopen(MORE, "w");
647*7c478bd9Sstevel@tonic-gate 					if (fbuf == NULL) {
648*7c478bd9Sstevel@tonic-gate 						perror(MORE);
649*7c478bd9Sstevel@tonic-gate 						fbuf = stdout;
650*7c478bd9Sstevel@tonic-gate 					} else {
651*7c478bd9Sstevel@tonic-gate 						sigint = sigset(SIGINT, SIG_IGN);
652*7c478bd9Sstevel@tonic-gate 						sigpipe = sigset(SIGPIPE, brokpipe);
653*7c478bd9Sstevel@tonic-gate 					}
654*7c478bd9Sstevel@tonic-gate 				}
655*7c478bd9Sstevel@tonic-gate 			}
656*7c478bd9Sstevel@tonic-gate 			fprintf(fbuf, gettext("-------\nMessage contains:\n"));
657*7c478bd9Sstevel@tonic-gate 			puthead(hp, fbuf, GMASK, 0);
658*7c478bd9Sstevel@tonic-gate 			while ((t = getc(ibuf))!=EOF)
659*7c478bd9Sstevel@tonic-gate 				putc(t, fbuf);
660*7c478bd9Sstevel@tonic-gate 		ret0:
661*7c478bd9Sstevel@tonic-gate 			if (fbuf != stdout) {
662*7c478bd9Sstevel@tonic-gate 				npclose(fbuf);
663*7c478bd9Sstevel@tonic-gate 				sigset(SIGPIPE, sigpipe);
664*7c478bd9Sstevel@tonic-gate 				sigset(SIGINT, sigint);
665*7c478bd9Sstevel@tonic-gate 			}
666*7c478bd9Sstevel@tonic-gate 			printf(gettext("(continue)\n"));
667*7c478bd9Sstevel@tonic-gate 			break;
668*7c478bd9Sstevel@tonic-gate 		}
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 		case '^':
671*7c478bd9Sstevel@tonic-gate 		case '|':
672*7c478bd9Sstevel@tonic-gate 			/*
673*7c478bd9Sstevel@tonic-gate 			 * Pipe message through command.
674*7c478bd9Sstevel@tonic-gate 			 * Collect output as new message.
675*7c478bd9Sstevel@tonic-gate 			 */
676*7c478bd9Sstevel@tonic-gate 
677*7c478bd9Sstevel@tonic-gate 			obuf = mespipe(ibuf, obuf, &linebuf[2]);
678*7c478bd9Sstevel@tonic-gate 			newo = obuf;
679*7c478bd9Sstevel@tonic-gate 			ibuf = newi;
680*7c478bd9Sstevel@tonic-gate 			newi = ibuf;
681*7c478bd9Sstevel@tonic-gate 			printf(gettext("(continue)\n"));
682*7c478bd9Sstevel@tonic-gate 			break;
683*7c478bd9Sstevel@tonic-gate 
684*7c478bd9Sstevel@tonic-gate 		case 'v':
685*7c478bd9Sstevel@tonic-gate 		case 'e':
686*7c478bd9Sstevel@tonic-gate 			/*
687*7c478bd9Sstevel@tonic-gate 			 * Edit the current message.
688*7c478bd9Sstevel@tonic-gate 			 * 'e' means to use EDITOR
689*7c478bd9Sstevel@tonic-gate 			 * 'v' means to use VISUAL
690*7c478bd9Sstevel@tonic-gate 			 */
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 			if ((obuf = mesedit(ibuf, obuf, c, hp)) == NULL)
693*7c478bd9Sstevel@tonic-gate 				goto err;
694*7c478bd9Sstevel@tonic-gate 			newo = obuf;
695*7c478bd9Sstevel@tonic-gate 			ibuf = newi;
696*7c478bd9Sstevel@tonic-gate 			printf(gettext("(continue)\n"));
697*7c478bd9Sstevel@tonic-gate 			break;
698*7c478bd9Sstevel@tonic-gate 		}
699*7c478bd9Sstevel@tonic-gate 		fflush(obuf);
700*7c478bd9Sstevel@tonic-gate 	}
701*7c478bd9Sstevel@tonic-gate eofl:
702*7c478bd9Sstevel@tonic-gate 	fflush(obuf);
703*7c478bd9Sstevel@tonic-gate 	if ((cp = value("MAILX_TAIL")) != NOSTR) {
704*7c478bd9Sstevel@tonic-gate 	      cpout( cp, obuf);
705*7c478bd9Sstevel@tonic-gate 	      if (isatty(fileno(stdin)))
706*7c478bd9Sstevel@tonic-gate 		    cpout( cp, stdout);
707*7c478bd9Sstevel@tonic-gate 	}
708*7c478bd9Sstevel@tonic-gate 	fclose(obuf);
709*7c478bd9Sstevel@tonic-gate 	rewind(ibuf);
710*7c478bd9Sstevel@tonic-gate 	resetsigs(0);
711*7c478bd9Sstevel@tonic-gate 	noreset = 0;
712*7c478bd9Sstevel@tonic-gate 	return(ibuf);
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate werr:
715*7c478bd9Sstevel@tonic-gate 	/*
716*7c478bd9Sstevel@tonic-gate 	 * Write error occurred on tmp file, save partial
717*7c478bd9Sstevel@tonic-gate 	 * message in dead.letter.
718*7c478bd9Sstevel@tonic-gate 	 */
719*7c478bd9Sstevel@tonic-gate 	perror(tempMail);
720*7c478bd9Sstevel@tonic-gate 	fflush(obuf);
721*7c478bd9Sstevel@tonic-gate 	rewind(ibuf);
722*7c478bd9Sstevel@tonic-gate 	if (fsize(ibuf) > 0) {
723*7c478bd9Sstevel@tonic-gate 		char *deadletter;
724*7c478bd9Sstevel@tonic-gate 
725*7c478bd9Sstevel@tonic-gate 		deadletter = Getf("DEAD");
726*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("Saving partial message in %s\n"),
727*7c478bd9Sstevel@tonic-gate 		    deadletter);
728*7c478bd9Sstevel@tonic-gate 		if ((fbuf = fopen(deadletter,
729*7c478bd9Sstevel@tonic-gate 		    value("appenddeadletter") == NOSTR ? "w" : "a")) != NULL) {
730*7c478bd9Sstevel@tonic-gate 			chmod(deadletter, DEADPERM);
731*7c478bd9Sstevel@tonic-gate 			puthead(hp, fbuf, GMASK|GCLEN, fsize(ibuf));
732*7c478bd9Sstevel@tonic-gate 			lcwrite(deadletter, ibuf, fbuf, value("appenddeadletter") != NOSTR);
733*7c478bd9Sstevel@tonic-gate 			fclose(fbuf);
734*7c478bd9Sstevel@tonic-gate 		} else
735*7c478bd9Sstevel@tonic-gate 			perror(deadletter);
736*7c478bd9Sstevel@tonic-gate 	}
737*7c478bd9Sstevel@tonic-gate 
738*7c478bd9Sstevel@tonic-gate err:
739*7c478bd9Sstevel@tonic-gate 	if (ibuf != NULL)
740*7c478bd9Sstevel@tonic-gate 		fclose(ibuf);
741*7c478bd9Sstevel@tonic-gate 	if (obuf != NULL)
742*7c478bd9Sstevel@tonic-gate 		fclose(obuf);
743*7c478bd9Sstevel@tonic-gate 	resetsigs(0);
744*7c478bd9Sstevel@tonic-gate 	noreset = 0;
745*7c478bd9Sstevel@tonic-gate 	return(NULL);
746*7c478bd9Sstevel@tonic-gate }
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate static void
749*7c478bd9Sstevel@tonic-gate resetsigs(int resethup)
750*7c478bd9Sstevel@tonic-gate {
751*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGINT, savesig);
752*7c478bd9Sstevel@tonic-gate 	if (resethup)
753*7c478bd9Sstevel@tonic-gate 		(void) sigset(SIGHUP, savehup);
754*7c478bd9Sstevel@tonic-gate #ifdef SIGCONT
755*7c478bd9Sstevel@tonic-gate # ifdef preSVr4
756*7c478bd9Sstevel@tonic-gate 	(void) sigset(SIGCONT, savecont);
757*7c478bd9Sstevel@tonic-gate # else
758*7c478bd9Sstevel@tonic-gate 	{
759*7c478bd9Sstevel@tonic-gate 	struct sigaction nsig;
760*7c478bd9Sstevel@tonic-gate 	nsig.sa_handler = (void (*)())savecont;
761*7c478bd9Sstevel@tonic-gate 	sigemptyset(&nsig.sa_mask);
762*7c478bd9Sstevel@tonic-gate 	nsig.sa_flags = SA_RESTART;
763*7c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGCONT, &nsig, (struct sigaction*)0);
764*7c478bd9Sstevel@tonic-gate 	}
765*7c478bd9Sstevel@tonic-gate # endif
766*7c478bd9Sstevel@tonic-gate #endif
767*7c478bd9Sstevel@tonic-gate }
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate /*
770*7c478bd9Sstevel@tonic-gate  * Write a file ex-like.
771*7c478bd9Sstevel@tonic-gate  */
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate static int
774*7c478bd9Sstevel@tonic-gate exwrite(char name[], FILE *ibuf)
775*7c478bd9Sstevel@tonic-gate {
776*7c478bd9Sstevel@tonic-gate 	register FILE *of;
777*7c478bd9Sstevel@tonic-gate 	struct stat junk;
778*7c478bd9Sstevel@tonic-gate 	void (*sigint)(int), (*sigpipe)(int);
779*7c478bd9Sstevel@tonic-gate 	int pi = (*name == '!');
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 	if ((of = pi ? npopen(++name, "w") : fopen(name, "a")) == NULL) {
782*7c478bd9Sstevel@tonic-gate 		perror(name);
783*7c478bd9Sstevel@tonic-gate 		return(-1);
784*7c478bd9Sstevel@tonic-gate 	}
785*7c478bd9Sstevel@tonic-gate 	if (pi) {
786*7c478bd9Sstevel@tonic-gate 		sigint = sigset(SIGINT, SIG_IGN);
787*7c478bd9Sstevel@tonic-gate 		sigpipe = sigset(SIGPIPE, SIG_IGN);
788*7c478bd9Sstevel@tonic-gate 	}
789*7c478bd9Sstevel@tonic-gate 	lcwrite(name, ibuf, of, 0);
790*7c478bd9Sstevel@tonic-gate 	pi ? npclose(of) : fclose(of);
791*7c478bd9Sstevel@tonic-gate 	if (pi) {
792*7c478bd9Sstevel@tonic-gate 		sigset(SIGPIPE, sigpipe);
793*7c478bd9Sstevel@tonic-gate 		sigset(SIGINT, sigint);
794*7c478bd9Sstevel@tonic-gate 	}
795*7c478bd9Sstevel@tonic-gate 	return(0);
796*7c478bd9Sstevel@tonic-gate }
797*7c478bd9Sstevel@tonic-gate 
798*7c478bd9Sstevel@tonic-gate void
799*7c478bd9Sstevel@tonic-gate lcwrite(char *fn, FILE *fi, FILE *fo, int addnl)
800*7c478bd9Sstevel@tonic-gate {
801*7c478bd9Sstevel@tonic-gate 	register int c;
802*7c478bd9Sstevel@tonic-gate 	long lc, cc;
803*7c478bd9Sstevel@tonic-gate 
804*7c478bd9Sstevel@tonic-gate 	printf("\"%s\" ", fn);
805*7c478bd9Sstevel@tonic-gate 	fflush(stdout);
806*7c478bd9Sstevel@tonic-gate 	lc = cc = 0;
807*7c478bd9Sstevel@tonic-gate 	while ((c = getc(fi)) != EOF) {
808*7c478bd9Sstevel@tonic-gate 		cc++;
809*7c478bd9Sstevel@tonic-gate 		if (putc(c, fo) == '\n')
810*7c478bd9Sstevel@tonic-gate 			lc++;
811*7c478bd9Sstevel@tonic-gate 		if (ferror(fo)) {
812*7c478bd9Sstevel@tonic-gate 			perror("");
813*7c478bd9Sstevel@tonic-gate 			return;
814*7c478bd9Sstevel@tonic-gate 		}
815*7c478bd9Sstevel@tonic-gate 	}
816*7c478bd9Sstevel@tonic-gate 	if (addnl) {
817*7c478bd9Sstevel@tonic-gate 		putc('\n', fo);
818*7c478bd9Sstevel@tonic-gate 		lc++;
819*7c478bd9Sstevel@tonic-gate 		cc++;
820*7c478bd9Sstevel@tonic-gate 	}
821*7c478bd9Sstevel@tonic-gate 	fflush(fo);
822*7c478bd9Sstevel@tonic-gate 	if (fferror(fo)) {
823*7c478bd9Sstevel@tonic-gate 		perror("");
824*7c478bd9Sstevel@tonic-gate 		return;
825*7c478bd9Sstevel@tonic-gate 	}
826*7c478bd9Sstevel@tonic-gate 	printf("%ld/%ld\n", lc, cc);
827*7c478bd9Sstevel@tonic-gate 	fflush(stdout);
828*7c478bd9Sstevel@tonic-gate }
829*7c478bd9Sstevel@tonic-gate 
830*7c478bd9Sstevel@tonic-gate /*
831*7c478bd9Sstevel@tonic-gate  * Edit the message being collected on ibuf and obuf.
832*7c478bd9Sstevel@tonic-gate  * Write the message out onto some poorly-named temp file
833*7c478bd9Sstevel@tonic-gate  * and point an editor at it.
834*7c478bd9Sstevel@tonic-gate  *
835*7c478bd9Sstevel@tonic-gate  * On return, make the edit file the new temp file.
836*7c478bd9Sstevel@tonic-gate  */
837*7c478bd9Sstevel@tonic-gate 
838*7c478bd9Sstevel@tonic-gate static FILE *
839*7c478bd9Sstevel@tonic-gate mesedit(FILE *ibuf, FILE *obuf, int c, struct header *hp)
840*7c478bd9Sstevel@tonic-gate {
841*7c478bd9Sstevel@tonic-gate 	pid_t pid;
842*7c478bd9Sstevel@tonic-gate 	FILE *fbuf;
843*7c478bd9Sstevel@tonic-gate 	register int t;
844*7c478bd9Sstevel@tonic-gate 	void (*sigint)(int);
845*7c478bd9Sstevel@tonic-gate #ifdef SIGCONT
846*7c478bd9Sstevel@tonic-gate 	void (*sigcont)(int);
847*7c478bd9Sstevel@tonic-gate #endif
848*7c478bd9Sstevel@tonic-gate 	struct stat sbuf;
849*7c478bd9Sstevel@tonic-gate 	register char *edit;
850*7c478bd9Sstevel@tonic-gate 	char hdr[LINESIZE];
851*7c478bd9Sstevel@tonic-gate 	char *oto, *osubject, *occ, *obcc, **oothers;
852*7c478bd9Sstevel@tonic-gate 	int fd = -1;
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	if (stat(tempEdit, &sbuf) >= 0) {
855*7c478bd9Sstevel@tonic-gate 		printf(gettext("%s: file exists\n"), tempEdit);
856*7c478bd9Sstevel@tonic-gate 		goto out;
857*7c478bd9Sstevel@tonic-gate 	}
858*7c478bd9Sstevel@tonic-gate 	if ((fd = open(tempEdit, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
859*7c478bd9Sstevel@tonic-gate 	(fbuf = fdopen(fd, "w")) == NULL) {
860*7c478bd9Sstevel@tonic-gate 		perror(tempEdit);
861*7c478bd9Sstevel@tonic-gate 		goto out;
862*7c478bd9Sstevel@tonic-gate 	}
863*7c478bd9Sstevel@tonic-gate 	fflush(obuf);
864*7c478bd9Sstevel@tonic-gate 	rewind(ibuf);
865*7c478bd9Sstevel@tonic-gate 	puthead(hp, fbuf, GMASK, 0);
866*7c478bd9Sstevel@tonic-gate 	while ((t = getc(ibuf)) != EOF)
867*7c478bd9Sstevel@tonic-gate 		putc(t, fbuf);
868*7c478bd9Sstevel@tonic-gate 	fflush(fbuf);
869*7c478bd9Sstevel@tonic-gate 	if (fferror(fbuf)) {
870*7c478bd9Sstevel@tonic-gate 		perror(tempEdit);
871*7c478bd9Sstevel@tonic-gate 		removefile(tempEdit);
872*7c478bd9Sstevel@tonic-gate 		goto out;
873*7c478bd9Sstevel@tonic-gate 	}
874*7c478bd9Sstevel@tonic-gate 	fclose(fbuf);
875*7c478bd9Sstevel@tonic-gate 	if ((edit = value(c == 'e' ? "EDITOR" : "VISUAL")) == NOSTR ||
876*7c478bd9Sstevel@tonic-gate 	    *edit == '\0')
877*7c478bd9Sstevel@tonic-gate 		edit = c == 'e' ? EDITOR : VISUAL;
878*7c478bd9Sstevel@tonic-gate 	edit = safeexpand(edit);
879*7c478bd9Sstevel@tonic-gate 
880*7c478bd9Sstevel@tonic-gate 	/*
881*7c478bd9Sstevel@tonic-gate 	 * Fork/execlp the editor on the edit file
882*7c478bd9Sstevel@tonic-gate 	*/
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate 	pid = vfork();
885*7c478bd9Sstevel@tonic-gate 	if (pid == (pid_t)-1) {
886*7c478bd9Sstevel@tonic-gate 		perror("fork");
887*7c478bd9Sstevel@tonic-gate 		removefile(tempEdit);
888*7c478bd9Sstevel@tonic-gate 		goto out;
889*7c478bd9Sstevel@tonic-gate 	}
890*7c478bd9Sstevel@tonic-gate 	if (pid == 0) {
891*7c478bd9Sstevel@tonic-gate 		char ecmd[BUFSIZ];
892*7c478bd9Sstevel@tonic-gate 		char *Shell;
893*7c478bd9Sstevel@tonic-gate 
894*7c478bd9Sstevel@tonic-gate 		sigchild();
895*7c478bd9Sstevel@tonic-gate 		execlp(edit, edit, tempEdit, (char *)0);
896*7c478bd9Sstevel@tonic-gate 		/*
897*7c478bd9Sstevel@tonic-gate 		 * If execlp fails, "edit" might really be a complete
898*7c478bd9Sstevel@tonic-gate 		 * shell command, not a simple pathname.  Try using
899*7c478bd9Sstevel@tonic-gate 		 * the shell to run it.
900*7c478bd9Sstevel@tonic-gate 		 */
901*7c478bd9Sstevel@tonic-gate 		snprintf(ecmd, sizeof (ecmd), "exec %s %s", edit, tempEdit);
902*7c478bd9Sstevel@tonic-gate 		if ((Shell = value("SHELL")) == NULL || *Shell=='\0')
903*7c478bd9Sstevel@tonic-gate 			Shell = SHELL;
904*7c478bd9Sstevel@tonic-gate 		execlp(Shell, Shell, "-c", ecmd, NULL);
905*7c478bd9Sstevel@tonic-gate 		perror(edit);
906*7c478bd9Sstevel@tonic-gate 		_exit(1);
907*7c478bd9Sstevel@tonic-gate 	}
908*7c478bd9Sstevel@tonic-gate 	sigint = sigset(SIGINT, SIG_IGN);
909*7c478bd9Sstevel@tonic-gate #ifdef SIGCONT
910*7c478bd9Sstevel@tonic-gate 	sigcont = sigset(SIGCONT, SIG_DFL);
911*7c478bd9Sstevel@tonic-gate #endif
912*7c478bd9Sstevel@tonic-gate 	while (wait((int *)0) != pid)
913*7c478bd9Sstevel@tonic-gate 		;
914*7c478bd9Sstevel@tonic-gate 	sigset(SIGINT, sigint);
915*7c478bd9Sstevel@tonic-gate #ifdef SIGCONT
916*7c478bd9Sstevel@tonic-gate 	sigset(SIGCONT, sigcont);
917*7c478bd9Sstevel@tonic-gate #endif
918*7c478bd9Sstevel@tonic-gate 	/*
919*7c478bd9Sstevel@tonic-gate 	 * Now switch to new file.
920*7c478bd9Sstevel@tonic-gate 	 */
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	if ((fbuf = fopen(tempEdit, "r")) == NULL) {
923*7c478bd9Sstevel@tonic-gate 		perror(tempEdit);
924*7c478bd9Sstevel@tonic-gate 		removefile(tempEdit);
925*7c478bd9Sstevel@tonic-gate 		goto out;
926*7c478bd9Sstevel@tonic-gate 	}
927*7c478bd9Sstevel@tonic-gate 	removefile(tempEdit);
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 	/* save the old headers, in case they are accidentally deleted */
930*7c478bd9Sstevel@tonic-gate 	osubject = hp->h_subject;
931*7c478bd9Sstevel@tonic-gate 	oto = hp->h_to;
932*7c478bd9Sstevel@tonic-gate 	occ = hp->h_cc;
933*7c478bd9Sstevel@tonic-gate 	obcc = hp->h_bcc;
934*7c478bd9Sstevel@tonic-gate 	oothers = hp->h_others;
935*7c478bd9Sstevel@tonic-gate 	hp->h_to = hp->h_subject = hp->h_cc = hp->h_bcc = hp->h_defopt = NOSTR;
936*7c478bd9Sstevel@tonic-gate 	hp->h_others = NOSTRPTR;
937*7c478bd9Sstevel@tonic-gate 	hp->h_seq = 0;
938*7c478bd9Sstevel@tonic-gate 	while (gethfield(fbuf, hdr, 9999L) > 0) {
939*7c478bd9Sstevel@tonic-gate 		if (ishfield(hdr, "to"))
940*7c478bd9Sstevel@tonic-gate 			hp->h_to = addto(hp->h_to, hcontents(hdr));
941*7c478bd9Sstevel@tonic-gate 		else if (ishfield(hdr, "subject"))
942*7c478bd9Sstevel@tonic-gate 			hp->h_subject = addone(hp->h_subject, hcontents(hdr));
943*7c478bd9Sstevel@tonic-gate 		else if (ishfield(hdr, "cc"))
944*7c478bd9Sstevel@tonic-gate 			hp->h_cc = addto(hp->h_cc, hcontents(hdr));
945*7c478bd9Sstevel@tonic-gate 		else if (ishfield(hdr, "bcc"))
946*7c478bd9Sstevel@tonic-gate 			hp->h_bcc = addto(hp->h_bcc, hcontents(hdr));
947*7c478bd9Sstevel@tonic-gate 		else if (ishfield(hdr, "default-options"))
948*7c478bd9Sstevel@tonic-gate 			hp->h_defopt = addone(hp->h_defopt, hcontents(hdr));
949*7c478bd9Sstevel@tonic-gate 		else
950*7c478bd9Sstevel@tonic-gate 			hp->h_others = Xaddone(hp->h_others, hdr);
951*7c478bd9Sstevel@tonic-gate 		hp->h_seq++;
952*7c478bd9Sstevel@tonic-gate 	}
953*7c478bd9Sstevel@tonic-gate 	if (hp->h_seq == 0) {
954*7c478bd9Sstevel@tonic-gate 		/* if we didn't see any headers, restore the original headers */
955*7c478bd9Sstevel@tonic-gate 		hp->h_subject = osubject;
956*7c478bd9Sstevel@tonic-gate 		hp->h_to = oto;
957*7c478bd9Sstevel@tonic-gate 		hp->h_cc = occ;
958*7c478bd9Sstevel@tonic-gate 		hp->h_bcc = obcc;
959*7c478bd9Sstevel@tonic-gate 		hp->h_others = oothers;
960*7c478bd9Sstevel@tonic-gate 		printf(gettext(
961*7c478bd9Sstevel@tonic-gate 		    "(Deleted headers restored to original values)\n"));
962*7c478bd9Sstevel@tonic-gate 	}
963*7c478bd9Sstevel@tonic-gate 	if ((fd = open(tempMail, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
964*7c478bd9Sstevel@tonic-gate 	(obuf = fdopen(fd, "w")) == NULL) {
965*7c478bd9Sstevel@tonic-gate 		perror(tempMail);
966*7c478bd9Sstevel@tonic-gate 		fclose(fbuf);
967*7c478bd9Sstevel@tonic-gate 		goto out;
968*7c478bd9Sstevel@tonic-gate 	}
969*7c478bd9Sstevel@tonic-gate 	if ((ibuf = fopen(tempMail, "r")) == NULL) {
970*7c478bd9Sstevel@tonic-gate 		perror(tempMail);
971*7c478bd9Sstevel@tonic-gate 		removefile(tempMail);
972*7c478bd9Sstevel@tonic-gate 		fclose(fbuf);
973*7c478bd9Sstevel@tonic-gate 		fclose(obuf);
974*7c478bd9Sstevel@tonic-gate 		goto out;
975*7c478bd9Sstevel@tonic-gate 	}
976*7c478bd9Sstevel@tonic-gate 	removefile(tempMail);
977*7c478bd9Sstevel@tonic-gate 	if (strlen(hdr) != 0) {
978*7c478bd9Sstevel@tonic-gate 		fputs(hdr, obuf);
979*7c478bd9Sstevel@tonic-gate 		putc('\n', obuf);
980*7c478bd9Sstevel@tonic-gate 	}
981*7c478bd9Sstevel@tonic-gate 	while ((t = getc(fbuf)) != EOF)
982*7c478bd9Sstevel@tonic-gate 		putc(t, obuf);
983*7c478bd9Sstevel@tonic-gate 	fclose(fbuf);
984*7c478bd9Sstevel@tonic-gate 	fclose(newo);
985*7c478bd9Sstevel@tonic-gate 	fclose(newi);
986*7c478bd9Sstevel@tonic-gate 	newo = obuf;
987*7c478bd9Sstevel@tonic-gate 	newi = ibuf;
988*7c478bd9Sstevel@tonic-gate out:
989*7c478bd9Sstevel@tonic-gate 	return(newo);
990*7c478bd9Sstevel@tonic-gate }
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate /*
993*7c478bd9Sstevel@tonic-gate  * Pipe the message through the command.
994*7c478bd9Sstevel@tonic-gate  * Old message is on stdin of command;
995*7c478bd9Sstevel@tonic-gate  * New message collected from stdout.
996*7c478bd9Sstevel@tonic-gate  * Sh -c must return 0 to accept the new message.
997*7c478bd9Sstevel@tonic-gate  */
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate static FILE *
1000*7c478bd9Sstevel@tonic-gate mespipe(FILE *ibuf, FILE *obuf, char cmd[])
1001*7c478bd9Sstevel@tonic-gate {
1002*7c478bd9Sstevel@tonic-gate 	register FILE *ni, *no;
1003*7c478bd9Sstevel@tonic-gate 	pid_t pid;
1004*7c478bd9Sstevel@tonic-gate 	int s;
1005*7c478bd9Sstevel@tonic-gate 	void (*sigint)(int);
1006*7c478bd9Sstevel@tonic-gate 	char *Shell;
1007*7c478bd9Sstevel@tonic-gate 	int fd = -1;
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	newi = ibuf;
1010*7c478bd9Sstevel@tonic-gate 	if ((fd = open(tempEdit, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0 ||
1011*7c478bd9Sstevel@tonic-gate 	(no = fdopen(fd, "w")) == NULL) {
1012*7c478bd9Sstevel@tonic-gate 		perror(tempEdit);
1013*7c478bd9Sstevel@tonic-gate 		return(obuf);
1014*7c478bd9Sstevel@tonic-gate 	}
1015*7c478bd9Sstevel@tonic-gate 	if ((ni = fopen(tempEdit, "r")) == NULL) {
1016*7c478bd9Sstevel@tonic-gate 		perror(tempEdit);
1017*7c478bd9Sstevel@tonic-gate 		fclose(no);
1018*7c478bd9Sstevel@tonic-gate 		removefile(tempEdit);
1019*7c478bd9Sstevel@tonic-gate 		return(obuf);
1020*7c478bd9Sstevel@tonic-gate 	}
1021*7c478bd9Sstevel@tonic-gate 	removefile(tempEdit);
1022*7c478bd9Sstevel@tonic-gate 	fflush(obuf);
1023*7c478bd9Sstevel@tonic-gate 	rewind(ibuf);
1024*7c478bd9Sstevel@tonic-gate 	if ((Shell = value("SHELL")) == NULL || *Shell=='\0')
1025*7c478bd9Sstevel@tonic-gate 		Shell = SHELL;
1026*7c478bd9Sstevel@tonic-gate 	if ((pid = vfork()) == (pid_t)-1) {
1027*7c478bd9Sstevel@tonic-gate 		perror("fork");
1028*7c478bd9Sstevel@tonic-gate 		goto err;
1029*7c478bd9Sstevel@tonic-gate 	}
1030*7c478bd9Sstevel@tonic-gate 	if (pid == 0) {
1031*7c478bd9Sstevel@tonic-gate 		/*
1032*7c478bd9Sstevel@tonic-gate 		 * stdin = current message.
1033*7c478bd9Sstevel@tonic-gate 		 * stdout = new message.
1034*7c478bd9Sstevel@tonic-gate 		 */
1035*7c478bd9Sstevel@tonic-gate 
1036*7c478bd9Sstevel@tonic-gate 		sigchild();
1037*7c478bd9Sstevel@tonic-gate 		close(0);
1038*7c478bd9Sstevel@tonic-gate 		dup(fileno(ibuf));
1039*7c478bd9Sstevel@tonic-gate 		close(1);
1040*7c478bd9Sstevel@tonic-gate 		dup(fileno(no));
1041*7c478bd9Sstevel@tonic-gate 		for (s = 4; s < 15; s++)
1042*7c478bd9Sstevel@tonic-gate 			close(s);
1043*7c478bd9Sstevel@tonic-gate 		execlp(Shell, Shell, "-c", cmd, (char *)0);
1044*7c478bd9Sstevel@tonic-gate 		perror(Shell);
1045*7c478bd9Sstevel@tonic-gate 		_exit(1);
1046*7c478bd9Sstevel@tonic-gate 	}
1047*7c478bd9Sstevel@tonic-gate 	sigint = sigset(SIGINT, SIG_IGN);
1048*7c478bd9Sstevel@tonic-gate 	while (wait(&s) != pid)
1049*7c478bd9Sstevel@tonic-gate 		;
1050*7c478bd9Sstevel@tonic-gate 	sigset(SIGINT, sigint);
1051*7c478bd9Sstevel@tonic-gate 	if (s != 0 || pid == (pid_t)-1) {
1052*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("\"%s\" failed!?\n"), cmd);
1053*7c478bd9Sstevel@tonic-gate 		goto err;
1054*7c478bd9Sstevel@tonic-gate 	}
1055*7c478bd9Sstevel@tonic-gate 	if (fsize(ni) == 0) {
1056*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("No bytes from \"%s\" !?\n"), cmd);
1057*7c478bd9Sstevel@tonic-gate 		goto err;
1058*7c478bd9Sstevel@tonic-gate 	}
1059*7c478bd9Sstevel@tonic-gate 
1060*7c478bd9Sstevel@tonic-gate 	/*
1061*7c478bd9Sstevel@tonic-gate 	 * Take new files.
1062*7c478bd9Sstevel@tonic-gate 	 */
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate 	newi = ni;
1065*7c478bd9Sstevel@tonic-gate 	fclose(ibuf);
1066*7c478bd9Sstevel@tonic-gate 	fclose(obuf);
1067*7c478bd9Sstevel@tonic-gate 	return(no);
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate err:
1070*7c478bd9Sstevel@tonic-gate 	fclose(no);
1071*7c478bd9Sstevel@tonic-gate 	fclose(ni);
1072*7c478bd9Sstevel@tonic-gate 	return(obuf);
1073*7c478bd9Sstevel@tonic-gate }
1074*7c478bd9Sstevel@tonic-gate 
1075*7c478bd9Sstevel@tonic-gate static char *indentprefix;	/* used instead of tab by tabputs */
1076*7c478bd9Sstevel@tonic-gate 
1077*7c478bd9Sstevel@tonic-gate /*
1078*7c478bd9Sstevel@tonic-gate  * Interpolate the named messages into the current
1079*7c478bd9Sstevel@tonic-gate  * message, preceding each line with a tab.
1080*7c478bd9Sstevel@tonic-gate  * Return a count of the number of characters now in
1081*7c478bd9Sstevel@tonic-gate  * the message, or -1 if an error is encountered writing
1082*7c478bd9Sstevel@tonic-gate  * the message temporary.  The flag argument is 'm' if we
1083*7c478bd9Sstevel@tonic-gate  * should shift over and 'f' if not.
1084*7c478bd9Sstevel@tonic-gate  */
1085*7c478bd9Sstevel@tonic-gate static int
1086*7c478bd9Sstevel@tonic-gate forward(char ms[], FILE *obuf, int f)
1087*7c478bd9Sstevel@tonic-gate {
1088*7c478bd9Sstevel@tonic-gate 	register int *msgvec, *ip;
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 	msgvec = (int *) salloc((msgCount+1) * sizeof *msgvec);
1091*7c478bd9Sstevel@tonic-gate 	if (msgvec == NOINTPTR)
1092*7c478bd9Sstevel@tonic-gate 		return(0);
1093*7c478bd9Sstevel@tonic-gate 	if (getmsglist(ms, msgvec, 0) < 0)
1094*7c478bd9Sstevel@tonic-gate 		return(0);
1095*7c478bd9Sstevel@tonic-gate 	if (*msgvec == NULL) {
1096*7c478bd9Sstevel@tonic-gate 		*msgvec = first(0, MMNORM);
1097*7c478bd9Sstevel@tonic-gate 		if (*msgvec == NULL) {
1098*7c478bd9Sstevel@tonic-gate 			printf(gettext("No appropriate messages\n"));
1099*7c478bd9Sstevel@tonic-gate 			return(0);
1100*7c478bd9Sstevel@tonic-gate 		}
1101*7c478bd9Sstevel@tonic-gate 		msgvec[1] = NULL;
1102*7c478bd9Sstevel@tonic-gate 	}
1103*7c478bd9Sstevel@tonic-gate 	if (tolower(f) == 'm')
1104*7c478bd9Sstevel@tonic-gate 		indentprefix = value("indentprefix");
1105*7c478bd9Sstevel@tonic-gate 	printf(gettext("Interpolating:"));
1106*7c478bd9Sstevel@tonic-gate 	for (ip = msgvec; *ip != NULL; ip++) {
1107*7c478bd9Sstevel@tonic-gate 		touch(*ip);
1108*7c478bd9Sstevel@tonic-gate 		printf(" %d", *ip);
1109*7c478bd9Sstevel@tonic-gate 		if (msend(&message[*ip-1], obuf, islower(f) ? M_IGNORE : 0,
1110*7c478bd9Sstevel@tonic-gate 		    tolower(f) == 'm' ? tabputs : fputs) < 0) {
1111*7c478bd9Sstevel@tonic-gate 			perror(tempMail);
1112*7c478bd9Sstevel@tonic-gate 			return(-1);
1113*7c478bd9Sstevel@tonic-gate 		}
1114*7c478bd9Sstevel@tonic-gate 	}
1115*7c478bd9Sstevel@tonic-gate 	fflush(obuf);
1116*7c478bd9Sstevel@tonic-gate 	if (fferror(obuf)) {
1117*7c478bd9Sstevel@tonic-gate 		perror(tempMail);
1118*7c478bd9Sstevel@tonic-gate 		return(-1);
1119*7c478bd9Sstevel@tonic-gate 	}
1120*7c478bd9Sstevel@tonic-gate 	printf("\n");
1121*7c478bd9Sstevel@tonic-gate 	return(0);
1122*7c478bd9Sstevel@tonic-gate }
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate static int
1125*7c478bd9Sstevel@tonic-gate tabputs(const char *line, FILE *obuf)
1126*7c478bd9Sstevel@tonic-gate {
1127*7c478bd9Sstevel@tonic-gate 
1128*7c478bd9Sstevel@tonic-gate 	if (indentprefix)
1129*7c478bd9Sstevel@tonic-gate 		fputs(indentprefix, obuf);
1130*7c478bd9Sstevel@tonic-gate 	/* Don't create lines with only a tab on them */
1131*7c478bd9Sstevel@tonic-gate 	else if (line[0] != '\n')
1132*7c478bd9Sstevel@tonic-gate 		fputc('\t', obuf);
1133*7c478bd9Sstevel@tonic-gate 	return (fputs(line, obuf));
1134*7c478bd9Sstevel@tonic-gate }
1135*7c478bd9Sstevel@tonic-gate 
1136*7c478bd9Sstevel@tonic-gate /*
1137*7c478bd9Sstevel@tonic-gate  * Print (continue) when continued after ^Z.
1138*7c478bd9Sstevel@tonic-gate  */
1139*7c478bd9Sstevel@tonic-gate #ifdef SIGCONT
1140*7c478bd9Sstevel@tonic-gate static void
1141*7c478bd9Sstevel@tonic-gate #ifdef	__cplusplus
1142*7c478bd9Sstevel@tonic-gate collcont(int)
1143*7c478bd9Sstevel@tonic-gate #else
1144*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1145*7c478bd9Sstevel@tonic-gate collcont(int s)
1146*7c478bd9Sstevel@tonic-gate #endif
1147*7c478bd9Sstevel@tonic-gate {
1148*7c478bd9Sstevel@tonic-gate 	printf(gettext("(continue)\n"));
1149*7c478bd9Sstevel@tonic-gate 	fflush(stdout);
1150*7c478bd9Sstevel@tonic-gate }
1151*7c478bd9Sstevel@tonic-gate #endif /* SIGCONT */
1152*7c478bd9Sstevel@tonic-gate 
1153*7c478bd9Sstevel@tonic-gate /*
1154*7c478bd9Sstevel@tonic-gate  * On interrupt, go here to save the partial
1155*7c478bd9Sstevel@tonic-gate  * message on ~/dead.letter.
1156*7c478bd9Sstevel@tonic-gate  * Then restore signals and execute the normal
1157*7c478bd9Sstevel@tonic-gate  * signal routine.  We only come here if signals
1158*7c478bd9Sstevel@tonic-gate  * were previously set anyway.
1159*7c478bd9Sstevel@tonic-gate  */
1160*7c478bd9Sstevel@tonic-gate static void
1161*7c478bd9Sstevel@tonic-gate collrub(int s)
1162*7c478bd9Sstevel@tonic-gate {
1163*7c478bd9Sstevel@tonic-gate 	register FILE *dbuf;
1164*7c478bd9Sstevel@tonic-gate 	register char *deadletter;
1165*7c478bd9Sstevel@tonic-gate 
1166*7c478bd9Sstevel@tonic-gate # ifdef OLD_BSD_SIGS
1167*7c478bd9Sstevel@tonic-gate 	if (s == SIGHUP)
1168*7c478bd9Sstevel@tonic-gate 		sigignore(SIGHUP);
1169*7c478bd9Sstevel@tonic-gate # endif
1170*7c478bd9Sstevel@tonic-gate 	if (s == SIGINT && hadintr == 0) {
1171*7c478bd9Sstevel@tonic-gate 		hadintr++;
1172*7c478bd9Sstevel@tonic-gate 		fflush(stdout);
1173*7c478bd9Sstevel@tonic-gate 		fprintf(stderr,
1174*7c478bd9Sstevel@tonic-gate 		    gettext("\n(Interrupt -- one more to kill letter)\n"));
1175*7c478bd9Sstevel@tonic-gate # ifdef OLD_BSD_SIGS
1176*7c478bd9Sstevel@tonic-gate 		sigrelse(s);
1177*7c478bd9Sstevel@tonic-gate # endif
1178*7c478bd9Sstevel@tonic-gate 		longjmp(coljmp, 1);
1179*7c478bd9Sstevel@tonic-gate 	}
1180*7c478bd9Sstevel@tonic-gate 	fclose(newo);
1181*7c478bd9Sstevel@tonic-gate 	rewind(newi);
1182*7c478bd9Sstevel@tonic-gate 	if (s == SIGINT && value("save")==NOSTR || fsize(newi) == 0)
1183*7c478bd9Sstevel@tonic-gate 		goto done;
1184*7c478bd9Sstevel@tonic-gate 	deadletter = Getf("DEAD");
1185*7c478bd9Sstevel@tonic-gate 	if ((dbuf = fopen(deadletter,
1186*7c478bd9Sstevel@tonic-gate 	    (value("appenddeadletter") == NOSTR ? "w" : "a"))) == NULL) {
1187*7c478bd9Sstevel@tonic-gate 		perror(deadletter);
1188*7c478bd9Sstevel@tonic-gate 		goto done;
1189*7c478bd9Sstevel@tonic-gate 	}
1190*7c478bd9Sstevel@tonic-gate 	chmod(deadletter, DEADPERM);
1191*7c478bd9Sstevel@tonic-gate 	puthead(savehp, dbuf, GMASK|GCLEN, fsize(newi));
1192*7c478bd9Sstevel@tonic-gate 	lcwrite(deadletter, newi, dbuf, value("appenddeadletter") != NOSTR);
1193*7c478bd9Sstevel@tonic-gate 	fclose(dbuf);
1194*7c478bd9Sstevel@tonic-gate done:
1195*7c478bd9Sstevel@tonic-gate 	fclose(newi);
1196*7c478bd9Sstevel@tonic-gate 	resetsigs(1);
1197*7c478bd9Sstevel@tonic-gate 	if (rcvmode) {
1198*7c478bd9Sstevel@tonic-gate 		if (s == SIGHUP)
1199*7c478bd9Sstevel@tonic-gate 			hangup(s);
1200*7c478bd9Sstevel@tonic-gate 		else
1201*7c478bd9Sstevel@tonic-gate 			stop(s);
1202*7c478bd9Sstevel@tonic-gate 	}
1203*7c478bd9Sstevel@tonic-gate 	else
1204*7c478bd9Sstevel@tonic-gate 		exit(1);
1205*7c478bd9Sstevel@tonic-gate }
1206*7c478bd9Sstevel@tonic-gate 
1207*7c478bd9Sstevel@tonic-gate /*
1208*7c478bd9Sstevel@tonic-gate  * Acknowledge an interrupt signal from the tty by typing an @
1209*7c478bd9Sstevel@tonic-gate  */
1210*7c478bd9Sstevel@tonic-gate static void
1211*7c478bd9Sstevel@tonic-gate #ifdef	__cplusplus
1212*7c478bd9Sstevel@tonic-gate intack(int)
1213*7c478bd9Sstevel@tonic-gate #else
1214*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1215*7c478bd9Sstevel@tonic-gate intack(int s)
1216*7c478bd9Sstevel@tonic-gate #endif
1217*7c478bd9Sstevel@tonic-gate {
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate 	puts("@");
1220*7c478bd9Sstevel@tonic-gate 	fflush(stdout);
1221*7c478bd9Sstevel@tonic-gate 	clearerr(stdin);
1222*7c478bd9Sstevel@tonic-gate 	longjmp(coljmp,1);
1223*7c478bd9Sstevel@tonic-gate }
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate /* Read line from stdin, noting any NULL characters.
1226*7c478bd9Sstevel@tonic-gate    Return the number of characters read. Note that the buffer
1227*7c478bd9Sstevel@tonic-gate    passed must be 1 larger than "size" for the trailing NUL byte.
1228*7c478bd9Sstevel@tonic-gate  */
1229*7c478bd9Sstevel@tonic-gate int
1230*7c478bd9Sstevel@tonic-gate getline(char *line, int size, FILE *f, int *hasnulls)
1231*7c478bd9Sstevel@tonic-gate {
1232*7c478bd9Sstevel@tonic-gate 	register int i, ch;
1233*7c478bd9Sstevel@tonic-gate 	for (i = 0; (i < size) && ((ch=getc(f)) != EOF); ) {
1234*7c478bd9Sstevel@tonic-gate 		if ( ch == '\0' )
1235*7c478bd9Sstevel@tonic-gate 			*hasnulls = 1;
1236*7c478bd9Sstevel@tonic-gate 		if ((line[i++] = (char)ch) == '\n') break;
1237*7c478bd9Sstevel@tonic-gate 	}
1238*7c478bd9Sstevel@tonic-gate 	line[i] = '\0';
1239*7c478bd9Sstevel@tonic-gate 	return(i);
1240*7c478bd9Sstevel@tonic-gate }
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate void
1243*7c478bd9Sstevel@tonic-gate #ifdef	__cplusplus
1244*7c478bd9Sstevel@tonic-gate savedead(int)
1245*7c478bd9Sstevel@tonic-gate #else
1246*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
1247*7c478bd9Sstevel@tonic-gate savedead(int s)
1248*7c478bd9Sstevel@tonic-gate #endif
1249*7c478bd9Sstevel@tonic-gate {
1250*7c478bd9Sstevel@tonic-gate 	collrub(SIGINT);
1251*7c478bd9Sstevel@tonic-gate 	exit(1);
1252*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1253*7c478bd9Sstevel@tonic-gate }
1254*7c478bd9Sstevel@tonic-gate 
1255*7c478bd9Sstevel@tonic-gate /*
1256*7c478bd9Sstevel@tonic-gate  * Add a list of addresses to the end of a header entry field.
1257*7c478bd9Sstevel@tonic-gate  */
1258*7c478bd9Sstevel@tonic-gate char *
1259*7c478bd9Sstevel@tonic-gate addto(char hf[], char news[])
1260*7c478bd9Sstevel@tonic-gate {
1261*7c478bd9Sstevel@tonic-gate 	char name[LINESIZE];
1262*7c478bd9Sstevel@tonic-gate 	int comma = docomma(news);
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 	while (news = yankword(news, name, sizeof (name), comma)) {
1265*7c478bd9Sstevel@tonic-gate 		nstrcat(name, sizeof (name), ", ");
1266*7c478bd9Sstevel@tonic-gate 		hf = addone(hf, name);
1267*7c478bd9Sstevel@tonic-gate 	}
1268*7c478bd9Sstevel@tonic-gate 	return hf;
1269*7c478bd9Sstevel@tonic-gate }
1270*7c478bd9Sstevel@tonic-gate 
1271*7c478bd9Sstevel@tonic-gate /*
1272*7c478bd9Sstevel@tonic-gate  * Add a string to the end of a header entry field.
1273*7c478bd9Sstevel@tonic-gate  */
1274*7c478bd9Sstevel@tonic-gate char *
1275*7c478bd9Sstevel@tonic-gate addone(char hf[], char news[])
1276*7c478bd9Sstevel@tonic-gate {
1277*7c478bd9Sstevel@tonic-gate 	register char *cp, *cp2, *linebuf;
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate 	if (hf == NOSTR)
1280*7c478bd9Sstevel@tonic-gate 		hf = savestr("");
1281*7c478bd9Sstevel@tonic-gate 	if (*news == '\0')
1282*7c478bd9Sstevel@tonic-gate 		return(hf);
1283*7c478bd9Sstevel@tonic-gate 	linebuf = (char *)srealloc(hf, (unsigned)(strlen(hf) + strlen(news) + 2));
1284*7c478bd9Sstevel@tonic-gate 	cp2 = strchr(linebuf, '\0');
1285*7c478bd9Sstevel@tonic-gate 	if (cp2 > linebuf && cp2[-1] != ' ')
1286*7c478bd9Sstevel@tonic-gate 		*cp2++ = ' ';
1287*7c478bd9Sstevel@tonic-gate 	for (cp = news; any(*cp, " \t"); cp++)
1288*7c478bd9Sstevel@tonic-gate 		;
1289*7c478bd9Sstevel@tonic-gate 	while (*cp != '\0')
1290*7c478bd9Sstevel@tonic-gate 		*cp2++ = *cp++;
1291*7c478bd9Sstevel@tonic-gate 	*cp2 = '\0';
1292*7c478bd9Sstevel@tonic-gate 	return(linebuf);
1293*7c478bd9Sstevel@tonic-gate }
1294*7c478bd9Sstevel@tonic-gate 
1295*7c478bd9Sstevel@tonic-gate static int
1296*7c478bd9Sstevel@tonic-gate nptrs(char **hf)
1297*7c478bd9Sstevel@tonic-gate {
1298*7c478bd9Sstevel@tonic-gate 	register int i;
1299*7c478bd9Sstevel@tonic-gate 
1300*7c478bd9Sstevel@tonic-gate 	if (!hf)
1301*7c478bd9Sstevel@tonic-gate 		return(0);
1302*7c478bd9Sstevel@tonic-gate 	for (i = 0; *hf; hf++)
1303*7c478bd9Sstevel@tonic-gate 		i++;
1304*7c478bd9Sstevel@tonic-gate 	return(i);
1305*7c478bd9Sstevel@tonic-gate }
1306*7c478bd9Sstevel@tonic-gate 
1307*7c478bd9Sstevel@tonic-gate /*
1308*7c478bd9Sstevel@tonic-gate  * Add a non-standard header to the end of the non-standard headers.
1309*7c478bd9Sstevel@tonic-gate  */
1310*7c478bd9Sstevel@tonic-gate static char **
1311*7c478bd9Sstevel@tonic-gate Xaddone(char **hf, char news[])
1312*7c478bd9Sstevel@tonic-gate {
1313*7c478bd9Sstevel@tonic-gate 	register char *linebuf;
1314*7c478bd9Sstevel@tonic-gate 	char **ohf = hf;
1315*7c478bd9Sstevel@tonic-gate 	int nhf = nptrs(hf);
1316*7c478bd9Sstevel@tonic-gate 
1317*7c478bd9Sstevel@tonic-gate 	if (hf == NOSTRPTR)
1318*7c478bd9Sstevel@tonic-gate 		hf = (char**)salloc(sizeof(char*) * 2);
1319*7c478bd9Sstevel@tonic-gate 	else
1320*7c478bd9Sstevel@tonic-gate 		hf = (char**)srealloc(hf, sizeof(char*) * (nhf + 2));
1321*7c478bd9Sstevel@tonic-gate 	if (hf == NOSTRPTR) {
1322*7c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("No room, header lost: %s\n"), news);
1323*7c478bd9Sstevel@tonic-gate 		return(ohf);
1324*7c478bd9Sstevel@tonic-gate 	}
1325*7c478bd9Sstevel@tonic-gate 	linebuf = (char *)salloc((unsigned)(strlen(news) + 1));
1326*7c478bd9Sstevel@tonic-gate 	strcpy(linebuf, news);
1327*7c478bd9Sstevel@tonic-gate 	hf[nhf++] = linebuf;
1328*7c478bd9Sstevel@tonic-gate 	hf[nhf] = NOSTR;
1329*7c478bd9Sstevel@tonic-gate 	return(hf);
1330*7c478bd9Sstevel@tonic-gate }
1331*7c478bd9Sstevel@tonic-gate 
1332*7c478bd9Sstevel@tonic-gate static void
1333*7c478bd9Sstevel@tonic-gate cpout(char *str, FILE *ofd)
1334*7c478bd9Sstevel@tonic-gate {
1335*7c478bd9Sstevel@tonic-gate 	register char *cp = str;
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate 	while (*cp) {
1338*7c478bd9Sstevel@tonic-gate 		if (*cp == '\\') {
1339*7c478bd9Sstevel@tonic-gate 			switch (*(cp+1)) {
1340*7c478bd9Sstevel@tonic-gate 			case 'n':
1341*7c478bd9Sstevel@tonic-gate 				putc('\n', ofd);
1342*7c478bd9Sstevel@tonic-gate 				cp++;
1343*7c478bd9Sstevel@tonic-gate 				break;
1344*7c478bd9Sstevel@tonic-gate 			case 't':
1345*7c478bd9Sstevel@tonic-gate 				putc('\t', ofd);
1346*7c478bd9Sstevel@tonic-gate 				cp++;
1347*7c478bd9Sstevel@tonic-gate 				break;
1348*7c478bd9Sstevel@tonic-gate 			default:
1349*7c478bd9Sstevel@tonic-gate 				putc('\\', ofd);
1350*7c478bd9Sstevel@tonic-gate 			}
1351*7c478bd9Sstevel@tonic-gate 		} else {
1352*7c478bd9Sstevel@tonic-gate 			putc(*cp, ofd);
1353*7c478bd9Sstevel@tonic-gate 		}
1354*7c478bd9Sstevel@tonic-gate 		cp++;
1355*7c478bd9Sstevel@tonic-gate 	}
1356*7c478bd9Sstevel@tonic-gate 	putc('\n', ofd);
1357*7c478bd9Sstevel@tonic-gate 	fflush(ofd);
1358*7c478bd9Sstevel@tonic-gate }
1359*7c478bd9Sstevel@tonic-gate 
1360*7c478bd9Sstevel@tonic-gate static void
1361*7c478bd9Sstevel@tonic-gate xhalt(void)
1362*7c478bd9Sstevel@tonic-gate {
1363*7c478bd9Sstevel@tonic-gate 	fclose(newo);
1364*7c478bd9Sstevel@tonic-gate 	fclose(newi);
1365*7c478bd9Sstevel@tonic-gate 	sigset(SIGINT, savesig);
1366*7c478bd9Sstevel@tonic-gate 	sigset(SIGHUP, savehup);
1367*7c478bd9Sstevel@tonic-gate 	if (rcvmode)
1368*7c478bd9Sstevel@tonic-gate 		stop(0);
1369*7c478bd9Sstevel@tonic-gate 	exit(1);
1370*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
1371*7c478bd9Sstevel@tonic-gate }
1372*7c478bd9Sstevel@tonic-gate 
1373*7c478bd9Sstevel@tonic-gate /*
1374*7c478bd9Sstevel@tonic-gate  * Strip the nulls from a buffer of length n
1375*7c478bd9Sstevel@tonic-gate  */
1376*7c478bd9Sstevel@tonic-gate static int
1377*7c478bd9Sstevel@tonic-gate stripnulls(register char *linebuf, register int nread)
1378*7c478bd9Sstevel@tonic-gate {
1379*7c478bd9Sstevel@tonic-gate 	register int i, j;
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < nread; i++)
1382*7c478bd9Sstevel@tonic-gate 		if (linebuf[i] == '\0')
1383*7c478bd9Sstevel@tonic-gate 			break;
1384*7c478bd9Sstevel@tonic-gate 	for (j = i; j < nread; j++)
1385*7c478bd9Sstevel@tonic-gate 		if (linebuf[j] != '\0')
1386*7c478bd9Sstevel@tonic-gate 			linebuf[i++] = linebuf[j];
1387*7c478bd9Sstevel@tonic-gate 	linebuf[i] = '\0';
1388*7c478bd9Sstevel@tonic-gate 	return(i);
1389*7c478bd9Sstevel@tonic-gate }
1390