xref: /onnv-gate/usr/src/cmd/mailx/cmd3.c (revision 0)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*0Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*0Sstevel@tonic-gate 
25*0Sstevel@tonic-gate 
26*0Sstevel@tonic-gate /*
27*0Sstevel@tonic-gate  * Copyright 1985-2002 Sun Microsystems, Inc.  All rights reserved.
28*0Sstevel@tonic-gate  * Use is subject to license terms.
29*0Sstevel@tonic-gate  */
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate /*
32*0Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
33*0Sstevel@tonic-gate  * The Regents of the University of California
34*0Sstevel@tonic-gate  * All Rights Reserved
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
37*0Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
38*0Sstevel@tonic-gate  * contributors.
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
42*0Sstevel@tonic-gate 
43*0Sstevel@tonic-gate #include "rcv.h"
44*0Sstevel@tonic-gate #include <locale.h>
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate /*
47*0Sstevel@tonic-gate  * mailx -- a modified version of a University of California at Berkeley
48*0Sstevel@tonic-gate  *	mail program
49*0Sstevel@tonic-gate  *
50*0Sstevel@tonic-gate  * Still more user commands.
51*0Sstevel@tonic-gate  */
52*0Sstevel@tonic-gate 
53*0Sstevel@tonic-gate static int	bangexp(char *str);
54*0Sstevel@tonic-gate static int	diction(const void *a, const void *b);
55*0Sstevel@tonic-gate static char	*getfilename(char *name, int *aedit);
56*0Sstevel@tonic-gate static int	resp1(int *msgvec, int useauthor);
57*0Sstevel@tonic-gate static int	Resp1(int *msgvec, int useauthor);
58*0Sstevel@tonic-gate static char	*reedit(char *subj);
59*0Sstevel@tonic-gate static int	shell1(char *str);
60*0Sstevel@tonic-gate static void	sort(char **list);
61*0Sstevel@tonic-gate static char	*replyto(struct message *mp, char **f);
62*0Sstevel@tonic-gate static int	reply2sender(void);
63*0Sstevel@tonic-gate 
64*0Sstevel@tonic-gate static char	prevfile[PATHSIZE];
65*0Sstevel@tonic-gate static char	origprevfile[PATHSIZE];
66*0Sstevel@tonic-gate static char	lastbang[BUFSIZ];
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /*
69*0Sstevel@tonic-gate  * Process a shell escape by saving signals, ignoring signals,
70*0Sstevel@tonic-gate  * and forking a sh -c
71*0Sstevel@tonic-gate  */
72*0Sstevel@tonic-gate 
73*0Sstevel@tonic-gate int
74*0Sstevel@tonic-gate shell(char *str)
75*0Sstevel@tonic-gate {
76*0Sstevel@tonic-gate 	shell1(str);
77*0Sstevel@tonic-gate 	printf("!\n");
78*0Sstevel@tonic-gate 	return(0);
79*0Sstevel@tonic-gate }
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate static int
82*0Sstevel@tonic-gate shell1(char *str)
83*0Sstevel@tonic-gate {
84*0Sstevel@tonic-gate 	void (*sig[2])(int);
85*0Sstevel@tonic-gate 	register int t;
86*0Sstevel@tonic-gate 	register pid_t p;
87*0Sstevel@tonic-gate 	char *Shell;
88*0Sstevel@tonic-gate 	char cmd[BUFSIZ];
89*0Sstevel@tonic-gate 
90*0Sstevel@tonic-gate 	nstrcpy(cmd, sizeof (cmd), str);
91*0Sstevel@tonic-gate 	if (bangexp(cmd) < 0)
92*0Sstevel@tonic-gate 		return(-1);
93*0Sstevel@tonic-gate 	if ((Shell = value("SHELL")) == NOSTR || *Shell=='\0')
94*0Sstevel@tonic-gate 		Shell = SHELL;
95*0Sstevel@tonic-gate 	for (t = SIGINT; t <= SIGQUIT; t++)
96*0Sstevel@tonic-gate 		sig[t-SIGINT] = sigset(t, SIG_IGN);
97*0Sstevel@tonic-gate 	p = vfork();
98*0Sstevel@tonic-gate 	if (p == 0) {
99*0Sstevel@tonic-gate 		setuid(getuid());
100*0Sstevel@tonic-gate 		sigchild();
101*0Sstevel@tonic-gate 		for (t = SIGINT; t <= SIGQUIT; t++)
102*0Sstevel@tonic-gate 			if (sig[t-SIGINT] != SIG_IGN)
103*0Sstevel@tonic-gate 				sigsys(t, SIG_DFL);
104*0Sstevel@tonic-gate 		execlp(Shell, Shell, "-c", cmd, (char *)0);
105*0Sstevel@tonic-gate 		perror(Shell);
106*0Sstevel@tonic-gate 		_exit(1);
107*0Sstevel@tonic-gate 	}
108*0Sstevel@tonic-gate 	while (wait(0) != p)
109*0Sstevel@tonic-gate 		;
110*0Sstevel@tonic-gate 	if (p == (pid_t)-1)
111*0Sstevel@tonic-gate 		perror("fork");
112*0Sstevel@tonic-gate 	for (t = SIGINT; t <= SIGQUIT; t++)
113*0Sstevel@tonic-gate 		sigset(t, sig[t-SIGINT]);
114*0Sstevel@tonic-gate 	return(0);
115*0Sstevel@tonic-gate }
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate /*
118*0Sstevel@tonic-gate  * Fork an interactive shell.
119*0Sstevel@tonic-gate  */
120*0Sstevel@tonic-gate 
121*0Sstevel@tonic-gate int
122*0Sstevel@tonic-gate #ifdef	__cplusplus
123*0Sstevel@tonic-gate dosh(char *)
124*0Sstevel@tonic-gate #else
125*0Sstevel@tonic-gate /* ARGSUSED */
126*0Sstevel@tonic-gate dosh(char *s)
127*0Sstevel@tonic-gate #endif
128*0Sstevel@tonic-gate {
129*0Sstevel@tonic-gate 	void (*sig[2])(int);
130*0Sstevel@tonic-gate 	register int t;
131*0Sstevel@tonic-gate 	register pid_t p;
132*0Sstevel@tonic-gate 	char *Shell;
133*0Sstevel@tonic-gate 
134*0Sstevel@tonic-gate 	if ((Shell = value("SHELL")) == NOSTR || *Shell=='\0')
135*0Sstevel@tonic-gate 		Shell = SHELL;
136*0Sstevel@tonic-gate 	for (t = SIGINT; t <= SIGQUIT; t++)
137*0Sstevel@tonic-gate 		sig[t-SIGINT] = sigset(t, SIG_IGN);
138*0Sstevel@tonic-gate 	p = vfork();
139*0Sstevel@tonic-gate 	if (p == 0) {
140*0Sstevel@tonic-gate 		setuid(getuid());
141*0Sstevel@tonic-gate 		sigchild();
142*0Sstevel@tonic-gate 		for (t = SIGINT; t <= SIGQUIT; t++)
143*0Sstevel@tonic-gate 			if (sig[t-SIGINT] != SIG_IGN)
144*0Sstevel@tonic-gate 				sigset(t, SIG_DFL);
145*0Sstevel@tonic-gate 		execlp(Shell, Shell, (char *)0);
146*0Sstevel@tonic-gate 		perror(Shell);
147*0Sstevel@tonic-gate 		_exit(1);
148*0Sstevel@tonic-gate 	}
149*0Sstevel@tonic-gate 	while (wait(0) != p)
150*0Sstevel@tonic-gate 		;
151*0Sstevel@tonic-gate 	if (p == (pid_t)-1)
152*0Sstevel@tonic-gate 		perror("fork");
153*0Sstevel@tonic-gate 	for (t = SIGINT; t <= SIGQUIT; t++)
154*0Sstevel@tonic-gate 		sigset(t, sig[t-SIGINT]);
155*0Sstevel@tonic-gate 	putchar('\n');
156*0Sstevel@tonic-gate 	return(0);
157*0Sstevel@tonic-gate }
158*0Sstevel@tonic-gate 
159*0Sstevel@tonic-gate /*
160*0Sstevel@tonic-gate  * Expand the shell escape by expanding unescaped !'s into the
161*0Sstevel@tonic-gate  * last issued command where possible.
162*0Sstevel@tonic-gate  */
163*0Sstevel@tonic-gate static int
164*0Sstevel@tonic-gate bangexp(char *str)
165*0Sstevel@tonic-gate {
166*0Sstevel@tonic-gate 	char bangbuf[BUFSIZ];
167*0Sstevel@tonic-gate 	register char *cp, *cp2;
168*0Sstevel@tonic-gate 	register int n;
169*0Sstevel@tonic-gate 	int changed = 0;
170*0Sstevel@tonic-gate 	int bangit = (value("bang")!=NOSTR);
171*0Sstevel@tonic-gate 
172*0Sstevel@tonic-gate 	cp = str;
173*0Sstevel@tonic-gate 	cp2 = bangbuf;
174*0Sstevel@tonic-gate 	n = BUFSIZ;
175*0Sstevel@tonic-gate 	while (*cp) {
176*0Sstevel@tonic-gate 		if (*cp=='!' && bangit) {
177*0Sstevel@tonic-gate 			if (n < (int)strlen(lastbang)) {
178*0Sstevel@tonic-gate overf:
179*0Sstevel@tonic-gate 				printf(gettext("Command buffer overflow\n"));
180*0Sstevel@tonic-gate 				return(-1);
181*0Sstevel@tonic-gate 			}
182*0Sstevel@tonic-gate 			changed++;
183*0Sstevel@tonic-gate 			strcpy(cp2, lastbang);
184*0Sstevel@tonic-gate 			cp2 += strlen(lastbang);
185*0Sstevel@tonic-gate 			n -= strlen(lastbang);
186*0Sstevel@tonic-gate 			cp++;
187*0Sstevel@tonic-gate 			continue;
188*0Sstevel@tonic-gate 		}
189*0Sstevel@tonic-gate 		if (*cp == '\\' && cp[1] == '!') {
190*0Sstevel@tonic-gate 			if (--n <= 1)
191*0Sstevel@tonic-gate 				goto overf;
192*0Sstevel@tonic-gate 			*cp2++ = '!';
193*0Sstevel@tonic-gate 			cp += 2;
194*0Sstevel@tonic-gate 			changed++;
195*0Sstevel@tonic-gate 		}
196*0Sstevel@tonic-gate 		if (--n <= 1)
197*0Sstevel@tonic-gate 			goto overf;
198*0Sstevel@tonic-gate 		*cp2++ = *cp++;
199*0Sstevel@tonic-gate 	}
200*0Sstevel@tonic-gate 	*cp2 = 0;
201*0Sstevel@tonic-gate 	if (changed) {
202*0Sstevel@tonic-gate 		printf("!%s\n", bangbuf);
203*0Sstevel@tonic-gate 		fflush(stdout);
204*0Sstevel@tonic-gate 	}
205*0Sstevel@tonic-gate 	nstrcpy(str, BUFSIZ, bangbuf);
206*0Sstevel@tonic-gate 	nstrcpy(lastbang, sizeof (lastbang), bangbuf);
207*0Sstevel@tonic-gate 	return(0);
208*0Sstevel@tonic-gate }
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate /*
211*0Sstevel@tonic-gate  * Print out a nice help message from some file or another.
212*0Sstevel@tonic-gate  */
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate int
215*0Sstevel@tonic-gate help(void)
216*0Sstevel@tonic-gate {
217*0Sstevel@tonic-gate 	register c;
218*0Sstevel@tonic-gate 	register FILE *f;
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	if ((f = fopen(HELPFILE, "r")) == NULL) {
221*0Sstevel@tonic-gate 		printf(gettext("No help just now.\n"));
222*0Sstevel@tonic-gate 		return(1);
223*0Sstevel@tonic-gate 	}
224*0Sstevel@tonic-gate 	while ((c = getc(f)) != EOF)
225*0Sstevel@tonic-gate 		putchar(c);
226*0Sstevel@tonic-gate 	fclose(f);
227*0Sstevel@tonic-gate 	return(0);
228*0Sstevel@tonic-gate }
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate /*
231*0Sstevel@tonic-gate  * Change user's working directory.
232*0Sstevel@tonic-gate  */
233*0Sstevel@tonic-gate 
234*0Sstevel@tonic-gate int
235*0Sstevel@tonic-gate schdir(char *str)
236*0Sstevel@tonic-gate {
237*0Sstevel@tonic-gate 	register char *cp;
238*0Sstevel@tonic-gate 	char cwd[PATHSIZE], file[PATHSIZE];
239*0Sstevel@tonic-gate 	static char efile[PATHSIZE];
240*0Sstevel@tonic-gate 
241*0Sstevel@tonic-gate 	for (cp = str; *cp == ' '; cp++)
242*0Sstevel@tonic-gate 		;
243*0Sstevel@tonic-gate 	if (*cp == '\0')
244*0Sstevel@tonic-gate 		cp = homedir;
245*0Sstevel@tonic-gate 	else
246*0Sstevel@tonic-gate 		if ((cp = expand(cp)) == NOSTR)
247*0Sstevel@tonic-gate 			return(1);
248*0Sstevel@tonic-gate 	if (editfile != NOSTR && (*editfile != '/' || mailname[0] != '/')) {
249*0Sstevel@tonic-gate 		if (getcwd(cwd, (int)sizeof (cwd)) == 0) {
250*0Sstevel@tonic-gate 			fprintf(stderr,
251*0Sstevel@tonic-gate 			    gettext("Can't get current directory: %s\n"), cwd);
252*0Sstevel@tonic-gate 			return(1);
253*0Sstevel@tonic-gate 		}
254*0Sstevel@tonic-gate 	}
255*0Sstevel@tonic-gate 	if (chdir(cp) < 0) {
256*0Sstevel@tonic-gate 		perror(cp);
257*0Sstevel@tonic-gate 		return(1);
258*0Sstevel@tonic-gate 	}
259*0Sstevel@tonic-gate 	/*
260*0Sstevel@tonic-gate 	 * Convert previously relative names to absolute names.
261*0Sstevel@tonic-gate 	 */
262*0Sstevel@tonic-gate 	if (editfile != NOSTR && *editfile != '/') {
263*0Sstevel@tonic-gate 		snprintf(file, sizeof (file), "%s/%s", cwd, editfile);
264*0Sstevel@tonic-gate 		nstrcpy(efile, sizeof (efile), file);
265*0Sstevel@tonic-gate 		editfile = efile;
266*0Sstevel@tonic-gate 	}
267*0Sstevel@tonic-gate 	if (mailname[0] != '/') {
268*0Sstevel@tonic-gate 		snprintf(file, sizeof (file), "%s/%s", cwd, mailname);
269*0Sstevel@tonic-gate 		nstrcpy(mailname, PATHSIZE, file);
270*0Sstevel@tonic-gate 	}
271*0Sstevel@tonic-gate 	return(0);
272*0Sstevel@tonic-gate }
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate /*
275*0Sstevel@tonic-gate  * Two versions of reply.  Reply to all names in message or reply
276*0Sstevel@tonic-gate  * to only sender of message, depending on setting of "replyall".
277*0Sstevel@tonic-gate  */
278*0Sstevel@tonic-gate 
279*0Sstevel@tonic-gate int
280*0Sstevel@tonic-gate respond(int *msgvec)
281*0Sstevel@tonic-gate {
282*0Sstevel@tonic-gate 	if (reply2sender())
283*0Sstevel@tonic-gate 		return(resp1(msgvec, 0));
284*0Sstevel@tonic-gate 	else
285*0Sstevel@tonic-gate 		return(Resp1(msgvec, 0));
286*0Sstevel@tonic-gate }
287*0Sstevel@tonic-gate 
288*0Sstevel@tonic-gate int
289*0Sstevel@tonic-gate followup(int *msgvec)
290*0Sstevel@tonic-gate {
291*0Sstevel@tonic-gate 	if (reply2sender())
292*0Sstevel@tonic-gate 		return(resp1(msgvec, 1));
293*0Sstevel@tonic-gate 	else
294*0Sstevel@tonic-gate 		return(Resp1(msgvec, 1));
295*0Sstevel@tonic-gate }
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate int
298*0Sstevel@tonic-gate replyall(int *msgvec)
299*0Sstevel@tonic-gate {
300*0Sstevel@tonic-gate 	return(resp1(msgvec, 0));
301*0Sstevel@tonic-gate }
302*0Sstevel@tonic-gate 
303*0Sstevel@tonic-gate static int
304*0Sstevel@tonic-gate resp1(int *msgvec, int useauthor)
305*0Sstevel@tonic-gate {
306*0Sstevel@tonic-gate 	struct message *mp;
307*0Sstevel@tonic-gate 	char *cp, *buf, *rcv, *skin_rcv, *reply2, **ap, *returnaddr;
308*0Sstevel@tonic-gate 	struct name *np;
309*0Sstevel@tonic-gate 	struct header head;
310*0Sstevel@tonic-gate 	char mylocalname[BUFSIZ], mydomname[BUFSIZ];
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	if (msgvec[1] != 0) {
313*0Sstevel@tonic-gate 		printf(gettext(
314*0Sstevel@tonic-gate 		    "Sorry, can't reply to multiple messages at once\n"));
315*0Sstevel@tonic-gate 		return(1);
316*0Sstevel@tonic-gate 	}
317*0Sstevel@tonic-gate 	snprintf(mydomname, sizeof (mydomname), "%s@%s", myname, domain);
318*0Sstevel@tonic-gate 	snprintf(mylocalname, sizeof (mylocalname), "%s@%s", myname, host);
319*0Sstevel@tonic-gate 	returnaddr = value("returnaddr");
320*0Sstevel@tonic-gate 
321*0Sstevel@tonic-gate 	mp = &message[msgvec[0] - 1];
322*0Sstevel@tonic-gate 	dot = mp;
323*0Sstevel@tonic-gate 	reply2 = replyto(mp, &rcv);
324*0Sstevel@tonic-gate 	cp = skin(hfield("to", mp, addto));
325*0Sstevel@tonic-gate 	if (cp != NOSTR) {
326*0Sstevel@tonic-gate 		buf = (char *)salloc(strlen(reply2) + strlen(cp) + 2);
327*0Sstevel@tonic-gate 		strcpy(buf, reply2);
328*0Sstevel@tonic-gate 		strcat(buf, " ");
329*0Sstevel@tonic-gate 		strcat(buf, cp);
330*0Sstevel@tonic-gate 	} else
331*0Sstevel@tonic-gate 		buf = reply2;
332*0Sstevel@tonic-gate 	np = elide(extract(buf, GTO));
333*0Sstevel@tonic-gate #ifdef	OPTIM
334*0Sstevel@tonic-gate 	/* rcv = netrename(rcv); */
335*0Sstevel@tonic-gate #endif	/* OPTIM */
336*0Sstevel@tonic-gate 	/*
337*0Sstevel@tonic-gate 	 * Delete my name from the reply list,
338*0Sstevel@tonic-gate 	 * and with it, all my alternate names.
339*0Sstevel@tonic-gate 	 */
340*0Sstevel@tonic-gate 	skin_rcv = skin(rcv);
341*0Sstevel@tonic-gate 	mapf(np, skin_rcv);
342*0Sstevel@tonic-gate 	np = delname(np, myname);
343*0Sstevel@tonic-gate 	np = delname(np, mylocalname);
344*0Sstevel@tonic-gate 	np = delname(np, mydomname);
345*0Sstevel@tonic-gate 	if (returnaddr && *returnaddr)
346*0Sstevel@tonic-gate 		np = delname(np, returnaddr);
347*0Sstevel@tonic-gate 	if (altnames != 0)
348*0Sstevel@tonic-gate 		for (ap = altnames; *ap; ap++)
349*0Sstevel@tonic-gate 			np = delname(np, *ap);
350*0Sstevel@tonic-gate 	head.h_seq = 1;
351*0Sstevel@tonic-gate 	cp = detract(np, 0);
352*0Sstevel@tonic-gate 	if (cp == NOSTR) {
353*0Sstevel@tonic-gate 		if (reply2)
354*0Sstevel@tonic-gate 			cp = unuucp(reply2);
355*0Sstevel@tonic-gate 		else
356*0Sstevel@tonic-gate 			cp = unuucp(rcv);
357*0Sstevel@tonic-gate 	}
358*0Sstevel@tonic-gate 	head.h_to = cp;
359*0Sstevel@tonic-gate 	head.h_subject = hfield("subject", mp, addone);
360*0Sstevel@tonic-gate 	if (head.h_subject == NOSTR)
361*0Sstevel@tonic-gate 		head.h_subject = hfield("subj", mp, addone);
362*0Sstevel@tonic-gate 	head.h_subject = reedit(head.h_subject);
363*0Sstevel@tonic-gate 	head.h_cc = NOSTR;
364*0Sstevel@tonic-gate 	cp = skin(hfield("cc", mp, addto));
365*0Sstevel@tonic-gate 	if (cp != NOSTR) {
366*0Sstevel@tonic-gate 		np = elide(extract(cp, GCC));
367*0Sstevel@tonic-gate 		mapf(np, skin_rcv);
368*0Sstevel@tonic-gate 		np = delname(np, myname);
369*0Sstevel@tonic-gate 		np = delname(np, mylocalname);
370*0Sstevel@tonic-gate 		np = delname(np, mydomname);
371*0Sstevel@tonic-gate 		if (returnaddr && *returnaddr)
372*0Sstevel@tonic-gate 			np = delname(np, returnaddr);
373*0Sstevel@tonic-gate 		np = delname(np, skin_rcv);
374*0Sstevel@tonic-gate 		if (altnames != 0)
375*0Sstevel@tonic-gate 			for (ap = altnames; *ap; ap++)
376*0Sstevel@tonic-gate 				np = delname(np, *ap);
377*0Sstevel@tonic-gate 		head.h_cc = detract(np, 0);
378*0Sstevel@tonic-gate 	}
379*0Sstevel@tonic-gate 	head.h_bcc = NOSTR;
380*0Sstevel@tonic-gate 	head.h_defopt = NOSTR;
381*0Sstevel@tonic-gate 	head.h_others = NOSTRPTR;
382*0Sstevel@tonic-gate 	mail1(&head, useauthor, useauthor ? rcv : NOSTR);
383*0Sstevel@tonic-gate 	return(0);
384*0Sstevel@tonic-gate }
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate void
387*0Sstevel@tonic-gate getrecf(char *buf, char *recfile, int useauthor, int sz_recfile)
388*0Sstevel@tonic-gate {
389*0Sstevel@tonic-gate 	register char *bp, *cp;
390*0Sstevel@tonic-gate 	register char *recf = recfile;
391*0Sstevel@tonic-gate 	register int folderize;
392*0Sstevel@tonic-gate 	char fldr[BUFSIZ];
393*0Sstevel@tonic-gate 
394*0Sstevel@tonic-gate 	folderize = (value("outfolder")!=NOSTR && getfold(fldr) == 0);
395*0Sstevel@tonic-gate 
396*0Sstevel@tonic-gate 	if (useauthor) {
397*0Sstevel@tonic-gate 		if (folderize)
398*0Sstevel@tonic-gate 			*recf++ = '+';
399*0Sstevel@tonic-gate 		if (debug) fprintf(stderr, "buf='%s'\n", buf);
400*0Sstevel@tonic-gate 		for (bp=skin(buf), cp=recf; *bp && !any(*bp, ", "); bp++) {
401*0Sstevel@tonic-gate 			if (*bp=='!')
402*0Sstevel@tonic-gate 				cp = recf;
403*0Sstevel@tonic-gate 			else
404*0Sstevel@tonic-gate 				*cp++ = *bp;
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 			if (cp >= &recfile[sz_recfile - 1]) {
407*0Sstevel@tonic-gate 				printf(gettext("File name buffer overflow\n"));
408*0Sstevel@tonic-gate 				break;
409*0Sstevel@tonic-gate 			}
410*0Sstevel@tonic-gate 		}
411*0Sstevel@tonic-gate 		*cp = '\0';
412*0Sstevel@tonic-gate 		if (cp==recf)
413*0Sstevel@tonic-gate 			*recfile = '\0';
414*0Sstevel@tonic-gate 		/* now strip off any Internet host names */
415*0Sstevel@tonic-gate 		if ((cp = strchr(recf, '%')) == NOSTR)
416*0Sstevel@tonic-gate 			cp = strchr(recf, '@');
417*0Sstevel@tonic-gate 		if (cp != NOSTR)
418*0Sstevel@tonic-gate 			*cp = '\0';
419*0Sstevel@tonic-gate 	} else {
420*0Sstevel@tonic-gate 		if (cp = value("record")) {
421*0Sstevel@tonic-gate 			int sz = PATHSIZE;
422*0Sstevel@tonic-gate 			if (folderize && *cp!='+' && *cp!='/'
423*0Sstevel@tonic-gate 			 && *safeexpand(cp)!='/') {
424*0Sstevel@tonic-gate 				*recf++ = '+';
425*0Sstevel@tonic-gate 				sz--;
426*0Sstevel@tonic-gate 			}
427*0Sstevel@tonic-gate 			nstrcpy(recf, sz, cp);
428*0Sstevel@tonic-gate 		} else
429*0Sstevel@tonic-gate 			*recf = '\0';
430*0Sstevel@tonic-gate 	}
431*0Sstevel@tonic-gate 	if (debug) fprintf(stderr, "recfile='%s'\n", recfile);
432*0Sstevel@tonic-gate }
433*0Sstevel@tonic-gate 
434*0Sstevel@tonic-gate /*
435*0Sstevel@tonic-gate  * Modify the subject we are replying to to begin with Re: if
436*0Sstevel@tonic-gate  * it does not already.
437*0Sstevel@tonic-gate  */
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate static char *
440*0Sstevel@tonic-gate reedit(char *subj)
441*0Sstevel@tonic-gate {
442*0Sstevel@tonic-gate 	char sbuf[10];
443*0Sstevel@tonic-gate 	register char *newsubj;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 	if (subj == NOSTR)
446*0Sstevel@tonic-gate 		return(NOSTR);
447*0Sstevel@tonic-gate 	strncpy(sbuf, subj, 3);
448*0Sstevel@tonic-gate 	sbuf[3] = 0;
449*0Sstevel@tonic-gate 	if (icequal(sbuf, "re:"))
450*0Sstevel@tonic-gate 		return(subj);
451*0Sstevel@tonic-gate 	newsubj = (char *)salloc((unsigned)(strlen(subj) + 5));
452*0Sstevel@tonic-gate 	sprintf(newsubj, "Re: %s", subj);
453*0Sstevel@tonic-gate 	return(newsubj);
454*0Sstevel@tonic-gate }
455*0Sstevel@tonic-gate 
456*0Sstevel@tonic-gate /*
457*0Sstevel@tonic-gate  * Preserve the named messages, so that they will be sent
458*0Sstevel@tonic-gate  * back to the system mailbox.
459*0Sstevel@tonic-gate  */
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate int
462*0Sstevel@tonic-gate preserve(int *msgvec)
463*0Sstevel@tonic-gate {
464*0Sstevel@tonic-gate 	register struct message *mp;
465*0Sstevel@tonic-gate 	register int *ip, mesg;
466*0Sstevel@tonic-gate 
467*0Sstevel@tonic-gate 	if (edit) {
468*0Sstevel@tonic-gate 		printf(gettext("Cannot \"preserve\" in edit mode\n"));
469*0Sstevel@tonic-gate 		return(1);
470*0Sstevel@tonic-gate 	}
471*0Sstevel@tonic-gate 	for (ip = msgvec; *ip != NULL; ip++) {
472*0Sstevel@tonic-gate 		mesg = *ip;
473*0Sstevel@tonic-gate 		mp = &message[mesg-1];
474*0Sstevel@tonic-gate 		mp->m_flag |= MPRESERVE;
475*0Sstevel@tonic-gate 		mp->m_flag &= ~MBOX;
476*0Sstevel@tonic-gate 		dot = mp;
477*0Sstevel@tonic-gate 	}
478*0Sstevel@tonic-gate 	return(0);
479*0Sstevel@tonic-gate }
480*0Sstevel@tonic-gate 
481*0Sstevel@tonic-gate /*
482*0Sstevel@tonic-gate  * Mark all given messages as unread.
483*0Sstevel@tonic-gate  */
484*0Sstevel@tonic-gate int
485*0Sstevel@tonic-gate unread(int msgvec[])
486*0Sstevel@tonic-gate {
487*0Sstevel@tonic-gate 	register int *ip;
488*0Sstevel@tonic-gate 
489*0Sstevel@tonic-gate 	for (ip = msgvec; *ip != NULL; ip++) {
490*0Sstevel@tonic-gate 		dot = &message[*ip-1];
491*0Sstevel@tonic-gate 		dot->m_flag &= ~(MREAD|MTOUCH);
492*0Sstevel@tonic-gate 		dot->m_flag |= MSTATUS;
493*0Sstevel@tonic-gate 	}
494*0Sstevel@tonic-gate 	return(0);
495*0Sstevel@tonic-gate }
496*0Sstevel@tonic-gate 
497*0Sstevel@tonic-gate /*
498*0Sstevel@tonic-gate  * Print the size of each message.
499*0Sstevel@tonic-gate  */
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate int
502*0Sstevel@tonic-gate messize(int *msgvec)
503*0Sstevel@tonic-gate {
504*0Sstevel@tonic-gate 	register struct message *mp;
505*0Sstevel@tonic-gate 	register int *ip, mesg;
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 	for (ip = msgvec; *ip != NULL; ip++) {
508*0Sstevel@tonic-gate 		mesg = *ip;
509*0Sstevel@tonic-gate 		mp = &message[mesg-1];
510*0Sstevel@tonic-gate 		dot = mp;
511*0Sstevel@tonic-gate 		printf("%d: %ld\n", mesg, mp->m_size);
512*0Sstevel@tonic-gate 	}
513*0Sstevel@tonic-gate 	return(0);
514*0Sstevel@tonic-gate }
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate /*
517*0Sstevel@tonic-gate  * Quit quickly.  If we are sourcing, just pop the input level
518*0Sstevel@tonic-gate  * by returning an error.
519*0Sstevel@tonic-gate  */
520*0Sstevel@tonic-gate 
521*0Sstevel@tonic-gate int
522*0Sstevel@tonic-gate rexit(int e)
523*0Sstevel@tonic-gate {
524*0Sstevel@tonic-gate 	if (sourcing)
525*0Sstevel@tonic-gate 		return(1);
526*0Sstevel@tonic-gate 	if (Tflag != NOSTR)
527*0Sstevel@tonic-gate 		close(creat(Tflag, TEMPPERM));
528*0Sstevel@tonic-gate 	if (!edit)
529*0Sstevel@tonic-gate 		Verhogen();
530*0Sstevel@tonic-gate 	exit(e ? e : rpterr);
531*0Sstevel@tonic-gate 	/* NOTREACHED */
532*0Sstevel@tonic-gate 	return (0);	/* shut up lint and CC */
533*0Sstevel@tonic-gate }
534*0Sstevel@tonic-gate 
535*0Sstevel@tonic-gate /*
536*0Sstevel@tonic-gate  * Set or display a variable value.  Syntax is similar to that
537*0Sstevel@tonic-gate  * of csh.
538*0Sstevel@tonic-gate  */
539*0Sstevel@tonic-gate 
540*0Sstevel@tonic-gate int
541*0Sstevel@tonic-gate set(char **arglist)
542*0Sstevel@tonic-gate {
543*0Sstevel@tonic-gate 	register struct var *vp;
544*0Sstevel@tonic-gate 	register char *cp, *cp2;
545*0Sstevel@tonic-gate 	char varbuf[BUFSIZ], **ap, **p;
546*0Sstevel@tonic-gate 	int errs, h, s;
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 	if (argcount(arglist) == 0) {
549*0Sstevel@tonic-gate 		for (h = 0, s = 1; h < HSHSIZE; h++)
550*0Sstevel@tonic-gate 			for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
551*0Sstevel@tonic-gate 				s++;
552*0Sstevel@tonic-gate 		ap = (char **) salloc(s * sizeof *ap);
553*0Sstevel@tonic-gate 		for (h = 0, p = ap; h < HSHSIZE; h++)
554*0Sstevel@tonic-gate 			for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
555*0Sstevel@tonic-gate 				*p++ = vp->v_name;
556*0Sstevel@tonic-gate 		*p = NOSTR;
557*0Sstevel@tonic-gate 		sort(ap);
558*0Sstevel@tonic-gate 		for (p = ap; *p != NOSTR; p++)
559*0Sstevel@tonic-gate 			if (((cp = value(*p)) != 0) && *cp)
560*0Sstevel@tonic-gate 				printf("%s=\"%s\"\n", *p, cp);
561*0Sstevel@tonic-gate 			else
562*0Sstevel@tonic-gate 				printf("%s\n", *p);
563*0Sstevel@tonic-gate 		return(0);
564*0Sstevel@tonic-gate 	}
565*0Sstevel@tonic-gate 	errs = 0;
566*0Sstevel@tonic-gate 	for (ap = arglist; *ap != NOSTR; ap++) {
567*0Sstevel@tonic-gate 		cp = *ap;
568*0Sstevel@tonic-gate 		cp2 = varbuf;
569*0Sstevel@tonic-gate 		while (*cp != '=' && *cp != '\0')
570*0Sstevel@tonic-gate 			*cp2++ = *cp++;
571*0Sstevel@tonic-gate 		*cp2 = '\0';
572*0Sstevel@tonic-gate 		if (*cp == '\0')
573*0Sstevel@tonic-gate 			cp = "";
574*0Sstevel@tonic-gate 		else
575*0Sstevel@tonic-gate 			cp++;
576*0Sstevel@tonic-gate 		if (equal(varbuf, "")) {
577*0Sstevel@tonic-gate 			printf(gettext("Non-null variable name required\n"));
578*0Sstevel@tonic-gate 			errs++;
579*0Sstevel@tonic-gate 			continue;
580*0Sstevel@tonic-gate 		}
581*0Sstevel@tonic-gate 		assign(varbuf, cp);
582*0Sstevel@tonic-gate 	}
583*0Sstevel@tonic-gate 	return(errs);
584*0Sstevel@tonic-gate }
585*0Sstevel@tonic-gate 
586*0Sstevel@tonic-gate /*
587*0Sstevel@tonic-gate  * Unset a bunch of variable values.
588*0Sstevel@tonic-gate  */
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate int
591*0Sstevel@tonic-gate unset(char **arglist)
592*0Sstevel@tonic-gate {
593*0Sstevel@tonic-gate 	register int errs;
594*0Sstevel@tonic-gate 	register char **ap;
595*0Sstevel@tonic-gate 
596*0Sstevel@tonic-gate 	errs = 0;
597*0Sstevel@tonic-gate 	for (ap = arglist; *ap != NOSTR; ap++)
598*0Sstevel@tonic-gate 		errs += deassign(*ap);
599*0Sstevel@tonic-gate 	return(errs);
600*0Sstevel@tonic-gate }
601*0Sstevel@tonic-gate 
602*0Sstevel@tonic-gate /*
603*0Sstevel@tonic-gate  * Add users to a group.
604*0Sstevel@tonic-gate  */
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate int
607*0Sstevel@tonic-gate group(char **argv)
608*0Sstevel@tonic-gate {
609*0Sstevel@tonic-gate 	register struct grouphead *gh;
610*0Sstevel@tonic-gate 	register struct mgroup *gp;
611*0Sstevel@tonic-gate 	register int h;
612*0Sstevel@tonic-gate 	int s;
613*0Sstevel@tonic-gate 	char **ap, *gname, **p;
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	if (argcount(argv) == 0) {
616*0Sstevel@tonic-gate 		for (h = 0, s = 1; h < HSHSIZE; h++)
617*0Sstevel@tonic-gate 			for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
618*0Sstevel@tonic-gate 				s++;
619*0Sstevel@tonic-gate 		ap = (char **) salloc(s * sizeof *ap);
620*0Sstevel@tonic-gate 		for (h = 0, p = ap; h < HSHSIZE; h++)
621*0Sstevel@tonic-gate 			for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
622*0Sstevel@tonic-gate 				*p++ = gh->g_name;
623*0Sstevel@tonic-gate 		*p = NOSTR;
624*0Sstevel@tonic-gate 		sort(ap);
625*0Sstevel@tonic-gate 		for (p = ap; *p != NOSTR; p++)
626*0Sstevel@tonic-gate 			printgroup(*p);
627*0Sstevel@tonic-gate 		return(0);
628*0Sstevel@tonic-gate 	}
629*0Sstevel@tonic-gate 	if (argcount(argv) == 1) {
630*0Sstevel@tonic-gate 		printgroup(*argv);
631*0Sstevel@tonic-gate 		return(0);
632*0Sstevel@tonic-gate 	}
633*0Sstevel@tonic-gate 	gname = *argv;
634*0Sstevel@tonic-gate 	h = hash(gname);
635*0Sstevel@tonic-gate 	if ((gh = findgroup(gname)) == NOGRP) {
636*0Sstevel@tonic-gate 		if ((gh = (struct grouphead *)
637*0Sstevel@tonic-gate 		    calloc(sizeof (*gh), 1)) == NULL) {
638*0Sstevel@tonic-gate 			panic("Failed to allocate memory for group");
639*0Sstevel@tonic-gate 	}
640*0Sstevel@tonic-gate 		gh->g_name = vcopy(gname);
641*0Sstevel@tonic-gate 		gh->g_list = NOGE;
642*0Sstevel@tonic-gate 		gh->g_link = groups[h];
643*0Sstevel@tonic-gate 		groups[h] = gh;
644*0Sstevel@tonic-gate 	}
645*0Sstevel@tonic-gate 
646*0Sstevel@tonic-gate 	/*
647*0Sstevel@tonic-gate 	 * Insert names from the command list into the group.
648*0Sstevel@tonic-gate 	 * Who cares if there are duplicates?  They get tossed
649*0Sstevel@tonic-gate 	 * later anyway.
650*0Sstevel@tonic-gate 	 */
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate 	for (ap = argv+1; *ap != NOSTR; ap++) {
653*0Sstevel@tonic-gate 		if ((gp = (struct mgroup *)
654*0Sstevel@tonic-gate 		    calloc(sizeof (*gp), 1)) == NULL) {
655*0Sstevel@tonic-gate 			panic("Failed to allocate memory for group");
656*0Sstevel@tonic-gate 	}
657*0Sstevel@tonic-gate 	gp->ge_name = vcopy(*ap);
658*0Sstevel@tonic-gate 		gp->ge_link = gh->g_list;
659*0Sstevel@tonic-gate 		gh->g_list = gp;
660*0Sstevel@tonic-gate 	}
661*0Sstevel@tonic-gate 	return(0);
662*0Sstevel@tonic-gate }
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate /*
665*0Sstevel@tonic-gate  * Remove users from a group.
666*0Sstevel@tonic-gate  */
667*0Sstevel@tonic-gate 
668*0Sstevel@tonic-gate int
669*0Sstevel@tonic-gate ungroup(char **argv)
670*0Sstevel@tonic-gate {
671*0Sstevel@tonic-gate 	register struct grouphead *gh, **ghp;
672*0Sstevel@tonic-gate 	register struct mgroup *gp, *gpnext;
673*0Sstevel@tonic-gate 	register int h;
674*0Sstevel@tonic-gate 	char **ap, *gname;
675*0Sstevel@tonic-gate 
676*0Sstevel@tonic-gate 	if (argcount(argv) == 0) {
677*0Sstevel@tonic-gate 		printf("Must specify alias or group to remove\n");
678*0Sstevel@tonic-gate 		return(1);
679*0Sstevel@tonic-gate 	}
680*0Sstevel@tonic-gate 
681*0Sstevel@tonic-gate 	/*
682*0Sstevel@tonic-gate 	 * Remove names on the command list from the group list.
683*0Sstevel@tonic-gate 	 */
684*0Sstevel@tonic-gate 
685*0Sstevel@tonic-gate 	for (ap = argv; *ap != NOSTR; ap++) {
686*0Sstevel@tonic-gate 		gname = *ap;
687*0Sstevel@tonic-gate 		h = hash(gname);
688*0Sstevel@tonic-gate 		for (ghp = &groups[h]; *ghp != NOGRP; ghp = &((*ghp)->g_link)) {
689*0Sstevel@tonic-gate 			gh = *ghp;
690*0Sstevel@tonic-gate 			if (equal(gh->g_name, gname)) {
691*0Sstevel@tonic-gate 				/* remove from list */
692*0Sstevel@tonic-gate 				*ghp = gh->g_link;
693*0Sstevel@tonic-gate 				/* free each member of gorup */
694*0Sstevel@tonic-gate 				for (gp = gh->g_list; gp != NOGE; gp = gpnext) {
695*0Sstevel@tonic-gate 					gpnext = gp->ge_link;
696*0Sstevel@tonic-gate 					vfree(gp->ge_name);
697*0Sstevel@tonic-gate 					free(gp);
698*0Sstevel@tonic-gate 				}
699*0Sstevel@tonic-gate 				vfree(gh->g_name);
700*0Sstevel@tonic-gate 				free(gh);
701*0Sstevel@tonic-gate 				break;
702*0Sstevel@tonic-gate 			}
703*0Sstevel@tonic-gate 		}
704*0Sstevel@tonic-gate 	}
705*0Sstevel@tonic-gate 	return(0);
706*0Sstevel@tonic-gate }
707*0Sstevel@tonic-gate 
708*0Sstevel@tonic-gate /*
709*0Sstevel@tonic-gate  * Sort the passed string vecotor into ascending dictionary
710*0Sstevel@tonic-gate  * order.
711*0Sstevel@tonic-gate  */
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate static void
714*0Sstevel@tonic-gate sort(char **list)
715*0Sstevel@tonic-gate {
716*0Sstevel@tonic-gate 	register char **ap;
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate 	for (ap = list; *ap != NOSTR; ap++)
719*0Sstevel@tonic-gate 		;
720*0Sstevel@tonic-gate 	if (ap-list < 2)
721*0Sstevel@tonic-gate 		return;
722*0Sstevel@tonic-gate 	qsort((char *) list, (unsigned) (ap-list), sizeof *list, diction);
723*0Sstevel@tonic-gate }
724*0Sstevel@tonic-gate 
725*0Sstevel@tonic-gate /*
726*0Sstevel@tonic-gate  * Do a dictionary order comparison of the arguments from
727*0Sstevel@tonic-gate  * qsort.
728*0Sstevel@tonic-gate  */
729*0Sstevel@tonic-gate static int
730*0Sstevel@tonic-gate diction(const void *a, const void *b)
731*0Sstevel@tonic-gate {
732*0Sstevel@tonic-gate 	return(strcmp(*(char **)a, *(char **)b));
733*0Sstevel@tonic-gate }
734*0Sstevel@tonic-gate 
735*0Sstevel@tonic-gate /*
736*0Sstevel@tonic-gate  * The do nothing command for comments.
737*0Sstevel@tonic-gate  */
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate int
740*0Sstevel@tonic-gate #ifdef	__cplusplus
741*0Sstevel@tonic-gate null(char *)
742*0Sstevel@tonic-gate #else
743*0Sstevel@tonic-gate /* ARGSUSED */
744*0Sstevel@tonic-gate null(char *s)
745*0Sstevel@tonic-gate #endif
746*0Sstevel@tonic-gate {
747*0Sstevel@tonic-gate 	return(0);
748*0Sstevel@tonic-gate }
749*0Sstevel@tonic-gate 
750*0Sstevel@tonic-gate /*
751*0Sstevel@tonic-gate  * Print out the current edit file, if we are editing.
752*0Sstevel@tonic-gate  * Otherwise, print the name of the person who's mail
753*0Sstevel@tonic-gate  * we are reading.
754*0Sstevel@tonic-gate  */
755*0Sstevel@tonic-gate int
756*0Sstevel@tonic-gate file(char **argv)
757*0Sstevel@tonic-gate {
758*0Sstevel@tonic-gate 	register char *cp;
759*0Sstevel@tonic-gate 	int editing, mdot;
760*0Sstevel@tonic-gate 
761*0Sstevel@tonic-gate 	if (argv[0] == NOSTR) {
762*0Sstevel@tonic-gate 		mdot = newfileinfo(1);
763*0Sstevel@tonic-gate 		dot = &message[mdot - 1];
764*0Sstevel@tonic-gate 		return(0);
765*0Sstevel@tonic-gate 	}
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 	/*
768*0Sstevel@tonic-gate 	 * Acker's!  Must switch to the new file.
769*0Sstevel@tonic-gate 	 * We use a funny interpretation --
770*0Sstevel@tonic-gate 	 *	# -- gets the previous file
771*0Sstevel@tonic-gate 	 *	% -- gets the invoker's post office box
772*0Sstevel@tonic-gate 	 *	%user -- gets someone else's post office box
773*0Sstevel@tonic-gate 	 *	& -- gets invoker's mbox file
774*0Sstevel@tonic-gate 	 *	string -- reads the given file
775*0Sstevel@tonic-gate 	 */
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 	cp = getfilename(argv[0], &editing);
778*0Sstevel@tonic-gate 	if (cp == NOSTR)
779*0Sstevel@tonic-gate 		return(-1);
780*0Sstevel@tonic-gate 	if (setfile(cp, editing)) {
781*0Sstevel@tonic-gate 		nstrcpy(origname, PATHSIZE, origprevfile);
782*0Sstevel@tonic-gate 		return(-1);
783*0Sstevel@tonic-gate 	}
784*0Sstevel@tonic-gate 	mdot = newfileinfo(1);
785*0Sstevel@tonic-gate 	dot = &message[mdot - 1];
786*0Sstevel@tonic-gate 	return(0);
787*0Sstevel@tonic-gate }
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate /*
790*0Sstevel@tonic-gate  * Evaluate the string given as a new mailbox name.
791*0Sstevel@tonic-gate  * Ultimately, we want this to support a number of meta characters.
792*0Sstevel@tonic-gate  * Possibly:
793*0Sstevel@tonic-gate  *	% -- for my system mail box
794*0Sstevel@tonic-gate  *	%user -- for user's system mail box
795*0Sstevel@tonic-gate  *	# -- for previous file
796*0Sstevel@tonic-gate  *	& -- get's invoker's mbox file
797*0Sstevel@tonic-gate  *	file name -- for any other file
798*0Sstevel@tonic-gate  */
799*0Sstevel@tonic-gate 
800*0Sstevel@tonic-gate static char *
801*0Sstevel@tonic-gate getfilename(char *name, int *aedit)
802*0Sstevel@tonic-gate {
803*0Sstevel@tonic-gate 	register char *cp;
804*0Sstevel@tonic-gate 	char savename[BUFSIZ];
805*0Sstevel@tonic-gate 	char oldmailname[BUFSIZ];
806*0Sstevel@tonic-gate 	char tmp[BUFSIZ];
807*0Sstevel@tonic-gate 
808*0Sstevel@tonic-gate 	/*
809*0Sstevel@tonic-gate 	 * Assume we will be in "edit file" mode, until
810*0Sstevel@tonic-gate 	 * proven wrong.
811*0Sstevel@tonic-gate 	 */
812*0Sstevel@tonic-gate 	*aedit = 1;
813*0Sstevel@tonic-gate 	switch (*name) {
814*0Sstevel@tonic-gate 	case '%':
815*0Sstevel@tonic-gate 		*aedit = 0;
816*0Sstevel@tonic-gate 		nstrcpy(prevfile, sizeof (prevfile), editfile);
817*0Sstevel@tonic-gate 		nstrcpy(origprevfile, sizeof (origprevfile), origname);
818*0Sstevel@tonic-gate 		if (name[1] != 0) {
819*0Sstevel@tonic-gate 			nstrcpy(oldmailname, sizeof (oldmailname), mailname);
820*0Sstevel@tonic-gate 			findmail(name+1);
821*0Sstevel@tonic-gate 			cp = savestr(mailname);
822*0Sstevel@tonic-gate 			nstrcpy(origname, PATHSIZE, cp);
823*0Sstevel@tonic-gate 			nstrcpy(mailname, PATHSIZE, oldmailname);
824*0Sstevel@tonic-gate 			return(cp);
825*0Sstevel@tonic-gate 		}
826*0Sstevel@tonic-gate 		nstrcpy(oldmailname, sizeof (oldmailname), mailname);
827*0Sstevel@tonic-gate 		findmail(NULL);
828*0Sstevel@tonic-gate 		cp = savestr(mailname);
829*0Sstevel@tonic-gate 		nstrcpy(mailname, PATHSIZE, oldmailname);
830*0Sstevel@tonic-gate 		nstrcpy(origname, PATHSIZE, cp);
831*0Sstevel@tonic-gate 		return(cp);
832*0Sstevel@tonic-gate 
833*0Sstevel@tonic-gate 	case '#':
834*0Sstevel@tonic-gate 		if (name[1] != 0)
835*0Sstevel@tonic-gate 			goto regular;
836*0Sstevel@tonic-gate 		if (prevfile[0] == 0) {
837*0Sstevel@tonic-gate 			printf(gettext("No previous file\n"));
838*0Sstevel@tonic-gate 			return(NOSTR);
839*0Sstevel@tonic-gate 		}
840*0Sstevel@tonic-gate 		cp = savestr(prevfile);
841*0Sstevel@tonic-gate 		nstrcpy(prevfile, sizeof (prevfile), editfile);
842*0Sstevel@tonic-gate 		nstrcpy(tmp, sizeof (tmp), origname);
843*0Sstevel@tonic-gate 		nstrcpy(origname, PATHSIZE, origprevfile);
844*0Sstevel@tonic-gate 		nstrcpy(origprevfile, sizeof (origprevfile), tmp);
845*0Sstevel@tonic-gate 		return(cp);
846*0Sstevel@tonic-gate 
847*0Sstevel@tonic-gate 	case '&':
848*0Sstevel@tonic-gate 		nstrcpy(prevfile, sizeof (prevfile), editfile);
849*0Sstevel@tonic-gate 		nstrcpy(origprevfile, sizeof (origprevfile), origname);
850*0Sstevel@tonic-gate 		if (name[1] == 0) {
851*0Sstevel@tonic-gate 			cp=Getf("MBOX");
852*0Sstevel@tonic-gate 			nstrcpy(origname, PATHSIZE, cp);
853*0Sstevel@tonic-gate 			return(cp);
854*0Sstevel@tonic-gate 		}
855*0Sstevel@tonic-gate 		/* Fall into . . . */
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate 	default:
858*0Sstevel@tonic-gate regular:
859*0Sstevel@tonic-gate 		nstrcpy(prevfile, sizeof (prevfile), editfile);
860*0Sstevel@tonic-gate 		nstrcpy(origprevfile, sizeof (origprevfile), origname);
861*0Sstevel@tonic-gate 		cp = safeexpand(name);
862*0Sstevel@tonic-gate 		nstrcpy(origname, PATHSIZE, cp);
863*0Sstevel@tonic-gate 		if (cp[0] != '/') {
864*0Sstevel@tonic-gate 			name = getcwd(NOSTR, PATHSIZE);
865*0Sstevel@tonic-gate 			nstrcat(name, PATHSIZE, "/");
866*0Sstevel@tonic-gate 			nstrcat(name, PATHSIZE, cp);
867*0Sstevel@tonic-gate 			cp = name;
868*0Sstevel@tonic-gate 		}
869*0Sstevel@tonic-gate 		return(cp);
870*0Sstevel@tonic-gate 	}
871*0Sstevel@tonic-gate }
872*0Sstevel@tonic-gate 
873*0Sstevel@tonic-gate /*
874*0Sstevel@tonic-gate  * Expand file names like echo
875*0Sstevel@tonic-gate  */
876*0Sstevel@tonic-gate 
877*0Sstevel@tonic-gate int
878*0Sstevel@tonic-gate echo(register char **argv)
879*0Sstevel@tonic-gate {
880*0Sstevel@tonic-gate 	register char *cp;
881*0Sstevel@tonic-gate 	int neednl = 0;
882*0Sstevel@tonic-gate 
883*0Sstevel@tonic-gate 	while (*argv != NOSTR) {
884*0Sstevel@tonic-gate 		cp = *argv++;
885*0Sstevel@tonic-gate 		if ((cp = expand(cp)) != NOSTR) {
886*0Sstevel@tonic-gate 			neednl++;
887*0Sstevel@tonic-gate 			printf("%s", cp);
888*0Sstevel@tonic-gate 			if (*argv!=NOSTR)
889*0Sstevel@tonic-gate 				putchar(' ');
890*0Sstevel@tonic-gate 		}
891*0Sstevel@tonic-gate 	}
892*0Sstevel@tonic-gate 	if (neednl)
893*0Sstevel@tonic-gate 		putchar('\n');
894*0Sstevel@tonic-gate 	return(0);
895*0Sstevel@tonic-gate }
896*0Sstevel@tonic-gate 
897*0Sstevel@tonic-gate /*
898*0Sstevel@tonic-gate  * Reply to a series of messages by simply mailing to the senders
899*0Sstevel@tonic-gate  * and not messing around with the To: and Cc: lists as in normal
900*0Sstevel@tonic-gate  * reply.
901*0Sstevel@tonic-gate  */
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate int
904*0Sstevel@tonic-gate Respond(int *msgvec)
905*0Sstevel@tonic-gate {
906*0Sstevel@tonic-gate 	if (reply2sender())
907*0Sstevel@tonic-gate 		return(Resp1(msgvec, 0));
908*0Sstevel@tonic-gate 	else
909*0Sstevel@tonic-gate 		return(resp1(msgvec, 0));
910*0Sstevel@tonic-gate }
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate int
913*0Sstevel@tonic-gate Followup(int *msgvec)
914*0Sstevel@tonic-gate {
915*0Sstevel@tonic-gate 	if (reply2sender())
916*0Sstevel@tonic-gate 		return(Resp1(msgvec, 1));
917*0Sstevel@tonic-gate 	else
918*0Sstevel@tonic-gate 		return(resp1(msgvec, 1));
919*0Sstevel@tonic-gate }
920*0Sstevel@tonic-gate 
921*0Sstevel@tonic-gate int
922*0Sstevel@tonic-gate replysender(int *msgvec)
923*0Sstevel@tonic-gate {
924*0Sstevel@tonic-gate 	return(Resp1(msgvec, 0));
925*0Sstevel@tonic-gate }
926*0Sstevel@tonic-gate 
927*0Sstevel@tonic-gate static int
928*0Sstevel@tonic-gate Resp1(int *msgvec, int useauthor)
929*0Sstevel@tonic-gate {
930*0Sstevel@tonic-gate 	struct header head;
931*0Sstevel@tonic-gate 	struct message *mp;
932*0Sstevel@tonic-gate 	register int s, *ap;
933*0Sstevel@tonic-gate 	register char *cp, *cp2, *subject;
934*0Sstevel@tonic-gate 
935*0Sstevel@tonic-gate 	for (s = 0, ap = msgvec; *ap != 0; ap++) {
936*0Sstevel@tonic-gate 		mp = &message[*ap - 1];
937*0Sstevel@tonic-gate 		dot = mp;
938*0Sstevel@tonic-gate 		cp = replyto(mp, NOSTRPTR);
939*0Sstevel@tonic-gate 		s += strlen(cp) + 1;
940*0Sstevel@tonic-gate 	}
941*0Sstevel@tonic-gate 	if (s == 0)
942*0Sstevel@tonic-gate 		return(0);
943*0Sstevel@tonic-gate 	cp = (char *)salloc(s + 2);
944*0Sstevel@tonic-gate 	head.h_to = cp;
945*0Sstevel@tonic-gate 	for (ap = msgvec; *ap != 0; ap++) {
946*0Sstevel@tonic-gate 		mp = &message[*ap - 1];
947*0Sstevel@tonic-gate 		cp2 = replyto(mp, NOSTRPTR);
948*0Sstevel@tonic-gate 		cp = copy(cp2, cp);
949*0Sstevel@tonic-gate 		*cp++ = ' ';
950*0Sstevel@tonic-gate 	}
951*0Sstevel@tonic-gate 	*--cp = 0;
952*0Sstevel@tonic-gate 	mp = &message[msgvec[0] - 1];
953*0Sstevel@tonic-gate 	subject = hfield("subject", mp, addone);
954*0Sstevel@tonic-gate 	head.h_seq = 1;
955*0Sstevel@tonic-gate 	if (subject == NOSTR)
956*0Sstevel@tonic-gate 		subject = hfield("subj", mp, addone);
957*0Sstevel@tonic-gate 	head.h_subject = reedit(subject);
958*0Sstevel@tonic-gate 	if (subject != NOSTR)
959*0Sstevel@tonic-gate 		head.h_seq++;
960*0Sstevel@tonic-gate 	head.h_cc = NOSTR;
961*0Sstevel@tonic-gate 	head.h_bcc = NOSTR;
962*0Sstevel@tonic-gate 	head.h_defopt = NOSTR;
963*0Sstevel@tonic-gate 	head.h_others = NOSTRPTR;
964*0Sstevel@tonic-gate 	mail1(&head, useauthor, NOSTR);
965*0Sstevel@tonic-gate 	return(0);
966*0Sstevel@tonic-gate }
967*0Sstevel@tonic-gate 
968*0Sstevel@tonic-gate /*
969*0Sstevel@tonic-gate  * Conditional commands.  These allow one to parameterize one's
970*0Sstevel@tonic-gate  * .mailrc and do some things if sending, others if receiving.
971*0Sstevel@tonic-gate  */
972*0Sstevel@tonic-gate 
973*0Sstevel@tonic-gate int
974*0Sstevel@tonic-gate ifcmd(char **argv)
975*0Sstevel@tonic-gate {
976*0Sstevel@tonic-gate 	register char *cp;
977*0Sstevel@tonic-gate 
978*0Sstevel@tonic-gate 	if (cond != CANY) {
979*0Sstevel@tonic-gate 		printf(gettext("Illegal nested \"if\"\n"));
980*0Sstevel@tonic-gate 		return(1);
981*0Sstevel@tonic-gate 	}
982*0Sstevel@tonic-gate 	cond = CANY;
983*0Sstevel@tonic-gate 	cp = argv[0];
984*0Sstevel@tonic-gate 	switch (*cp) {
985*0Sstevel@tonic-gate 	case 'r': case 'R':
986*0Sstevel@tonic-gate 		cond = CRCV;
987*0Sstevel@tonic-gate 		break;
988*0Sstevel@tonic-gate 
989*0Sstevel@tonic-gate 	case 's': case 'S':
990*0Sstevel@tonic-gate 		cond = CSEND;
991*0Sstevel@tonic-gate 		break;
992*0Sstevel@tonic-gate 
993*0Sstevel@tonic-gate 	case 't': case 'T':
994*0Sstevel@tonic-gate 		cond = CTTY;
995*0Sstevel@tonic-gate 		break;
996*0Sstevel@tonic-gate 
997*0Sstevel@tonic-gate 	default:
998*0Sstevel@tonic-gate 		printf(gettext("Unrecognized if-keyword: \"%s\"\n"), cp);
999*0Sstevel@tonic-gate 		return(1);
1000*0Sstevel@tonic-gate 	}
1001*0Sstevel@tonic-gate 	return(0);
1002*0Sstevel@tonic-gate }
1003*0Sstevel@tonic-gate 
1004*0Sstevel@tonic-gate /*
1005*0Sstevel@tonic-gate  * Implement 'else'.  This is pretty simple -- we just
1006*0Sstevel@tonic-gate  * flip over the conditional flag.
1007*0Sstevel@tonic-gate  */
1008*0Sstevel@tonic-gate 
1009*0Sstevel@tonic-gate int
1010*0Sstevel@tonic-gate elsecmd(void)
1011*0Sstevel@tonic-gate {
1012*0Sstevel@tonic-gate 
1013*0Sstevel@tonic-gate 	switch (cond) {
1014*0Sstevel@tonic-gate 	case CANY:
1015*0Sstevel@tonic-gate 		printf(gettext("\"Else\" without matching \"if\"\n"));
1016*0Sstevel@tonic-gate 		return(1);
1017*0Sstevel@tonic-gate 
1018*0Sstevel@tonic-gate 	case CSEND:
1019*0Sstevel@tonic-gate 		cond = CRCV;
1020*0Sstevel@tonic-gate 		break;
1021*0Sstevel@tonic-gate 
1022*0Sstevel@tonic-gate 	case CRCV:
1023*0Sstevel@tonic-gate 		cond = CSEND;
1024*0Sstevel@tonic-gate 		break;
1025*0Sstevel@tonic-gate 
1026*0Sstevel@tonic-gate 	case CTTY:
1027*0Sstevel@tonic-gate 		cond = CNOTTY;
1028*0Sstevel@tonic-gate 		break;
1029*0Sstevel@tonic-gate 
1030*0Sstevel@tonic-gate 	case CNOTTY:
1031*0Sstevel@tonic-gate 		cond = CTTY;
1032*0Sstevel@tonic-gate 		break;
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate 	default:
1035*0Sstevel@tonic-gate 		printf(gettext("invalid condition encountered\n"));
1036*0Sstevel@tonic-gate 		cond = CANY;
1037*0Sstevel@tonic-gate 		break;
1038*0Sstevel@tonic-gate 	}
1039*0Sstevel@tonic-gate 	return(0);
1040*0Sstevel@tonic-gate }
1041*0Sstevel@tonic-gate 
1042*0Sstevel@tonic-gate /*
1043*0Sstevel@tonic-gate  * End of if statement.  Just set cond back to anything.
1044*0Sstevel@tonic-gate  */
1045*0Sstevel@tonic-gate 
1046*0Sstevel@tonic-gate int
1047*0Sstevel@tonic-gate endifcmd(void)
1048*0Sstevel@tonic-gate {
1049*0Sstevel@tonic-gate 
1050*0Sstevel@tonic-gate 	if (cond == CANY) {
1051*0Sstevel@tonic-gate 		printf(gettext("\"Endif\" without matching \"if\"\n"));
1052*0Sstevel@tonic-gate 		return(1);
1053*0Sstevel@tonic-gate 	}
1054*0Sstevel@tonic-gate 	cond = CANY;
1055*0Sstevel@tonic-gate 	return(0);
1056*0Sstevel@tonic-gate }
1057*0Sstevel@tonic-gate 
1058*0Sstevel@tonic-gate /*
1059*0Sstevel@tonic-gate  * Set the list of alternate names.
1060*0Sstevel@tonic-gate  */
1061*0Sstevel@tonic-gate int
1062*0Sstevel@tonic-gate alternates(char **namelist)
1063*0Sstevel@tonic-gate {
1064*0Sstevel@tonic-gate 	register int c;
1065*0Sstevel@tonic-gate 	register char **ap, **ap2, *cp;
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	c = argcount(namelist) + 1;
1068*0Sstevel@tonic-gate 	if (c == 1) {
1069*0Sstevel@tonic-gate 		if (altnames == 0)
1070*0Sstevel@tonic-gate 			return(0);
1071*0Sstevel@tonic-gate 		for (ap = altnames; *ap; ap++)
1072*0Sstevel@tonic-gate 			printf("%s ", *ap);
1073*0Sstevel@tonic-gate 		printf("\n");
1074*0Sstevel@tonic-gate 		return (0);
1075*0Sstevel@tonic-gate 	}
1076*0Sstevel@tonic-gate 	if (altnames != 0)
1077*0Sstevel@tonic-gate 		free((char *)altnames);
1078*0Sstevel@tonic-gate 	if ((altnames = (char **)
1079*0Sstevel@tonic-gate 	    calloc((unsigned)c, sizeof (char *))) == NULL)
1080*0Sstevel@tonic-gate 		panic("Failed to allocate memory");
1081*0Sstevel@tonic-gate 	for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) {
1082*0Sstevel@tonic-gate 		if ((cp = (char *)
1083*0Sstevel@tonic-gate 		    calloc((unsigned)strlen(*ap) + 1, sizeof (char))) == NULL)
1084*0Sstevel@tonic-gate 			panic("Failed to allocate memory");
1085*0Sstevel@tonic-gate 		strcpy(cp, *ap);
1086*0Sstevel@tonic-gate 		*ap2 = cp;
1087*0Sstevel@tonic-gate 	}
1088*0Sstevel@tonic-gate 	*ap2 = 0;
1089*0Sstevel@tonic-gate 	return(0);
1090*0Sstevel@tonic-gate }
1091*0Sstevel@tonic-gate 
1092*0Sstevel@tonic-gate /*
1093*0Sstevel@tonic-gate  * Figure out who to reply to.
1094*0Sstevel@tonic-gate  * Return the real sender in *f.
1095*0Sstevel@tonic-gate  */
1096*0Sstevel@tonic-gate static char *
1097*0Sstevel@tonic-gate replyto(struct message *mp, char **f)
1098*0Sstevel@tonic-gate {
1099*0Sstevel@tonic-gate 	char *r, *rf;
1100*0Sstevel@tonic-gate 
1101*0Sstevel@tonic-gate 	if ((rf = skin(hfield("from", mp, addto)))==NOSTR)
1102*0Sstevel@tonic-gate 		rf = skin(addto(NOSTR, nameof(mp)));
1103*0Sstevel@tonic-gate 	if ((r = skin(hfield("reply-to", mp, addto)))==NOSTR)
1104*0Sstevel@tonic-gate 		r = rf;
1105*0Sstevel@tonic-gate 	if (f)
1106*0Sstevel@tonic-gate 		*f = rf;
1107*0Sstevel@tonic-gate 	return (r);
1108*0Sstevel@tonic-gate }
1109*0Sstevel@tonic-gate 
1110*0Sstevel@tonic-gate /*
1111*0Sstevel@tonic-gate  * reply2sender - determine whether a "reply" command should reply to the
1112*0Sstevel@tonic-gate  *                sender of the messages, or to all the recipients of the
1113*0Sstevel@tonic-gate  *                message.
1114*0Sstevel@tonic-gate  *
1115*0Sstevel@tonic-gate  *                With the advent of POSIX.2 compliance, this has become
1116*0Sstevel@tonic-gate  *                a bit more complicated, and so should be done in one
1117*0Sstevel@tonic-gate  *                place, for all to use.
1118*0Sstevel@tonic-gate  */
1119*0Sstevel@tonic-gate 
1120*0Sstevel@tonic-gate static int
1121*0Sstevel@tonic-gate reply2sender (void)
1122*0Sstevel@tonic-gate {
1123*0Sstevel@tonic-gate 	register int rep = (value("replyall") != NOSTR);
1124*0Sstevel@tonic-gate 	register int flp = (value("flipr") != NOSTR);
1125*0Sstevel@tonic-gate 
1126*0Sstevel@tonic-gate 	return((rep && !flp)|| (!rep && flp));
1127*0Sstevel@tonic-gate }
1128