xref: /onnv-gate/usr/src/cmd/mailx/cmd3.c (revision 18:7e2dc246c4e2)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
22*18Srobbin 
23*18Srobbin /*
24*18Srobbin  * Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
25*18Srobbin  * Use is subject to license terms.
26*18Srobbin  */
27*18Srobbin 
280Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
290Sstevel@tonic-gate /*	  All Rights Reserved  	*/
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
330Sstevel@tonic-gate  * The Regents of the University of California
340Sstevel@tonic-gate  * All Rights Reserved
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
370Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
380Sstevel@tonic-gate  * contributors.
390Sstevel@tonic-gate  */
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #include "rcv.h"
440Sstevel@tonic-gate #include <locale.h>
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * mailx -- a modified version of a University of California at Berkeley
480Sstevel@tonic-gate  *	mail program
490Sstevel@tonic-gate  *
500Sstevel@tonic-gate  * Still more user commands.
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate 
530Sstevel@tonic-gate static int	bangexp(char *str);
540Sstevel@tonic-gate static int	diction(const void *a, const void *b);
550Sstevel@tonic-gate static char	*getfilename(char *name, int *aedit);
560Sstevel@tonic-gate static int	resp1(int *msgvec, int useauthor);
570Sstevel@tonic-gate static int	Resp1(int *msgvec, int useauthor);
580Sstevel@tonic-gate static char	*reedit(char *subj);
590Sstevel@tonic-gate static int	shell1(char *str);
600Sstevel@tonic-gate static void	sort(char **list);
610Sstevel@tonic-gate static char	*replyto(struct message *mp, char **f);
620Sstevel@tonic-gate static int	reply2sender(void);
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static char	prevfile[PATHSIZE];
650Sstevel@tonic-gate static char	origprevfile[PATHSIZE];
660Sstevel@tonic-gate static char	lastbang[BUFSIZ];
670Sstevel@tonic-gate 
680Sstevel@tonic-gate /*
690Sstevel@tonic-gate  * Process a shell escape by saving signals, ignoring signals,
700Sstevel@tonic-gate  * and forking a sh -c
710Sstevel@tonic-gate  */
720Sstevel@tonic-gate 
730Sstevel@tonic-gate int
shell(char * str)740Sstevel@tonic-gate shell(char *str)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	shell1(str);
770Sstevel@tonic-gate 	printf("!\n");
780Sstevel@tonic-gate 	return(0);
790Sstevel@tonic-gate }
800Sstevel@tonic-gate 
810Sstevel@tonic-gate static int
shell1(char * str)820Sstevel@tonic-gate shell1(char *str)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate 	void (*sig[2])(int);
850Sstevel@tonic-gate 	register int t;
860Sstevel@tonic-gate 	register pid_t p;
870Sstevel@tonic-gate 	char *Shell;
880Sstevel@tonic-gate 	char cmd[BUFSIZ];
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	nstrcpy(cmd, sizeof (cmd), str);
910Sstevel@tonic-gate 	if (bangexp(cmd) < 0)
920Sstevel@tonic-gate 		return(-1);
930Sstevel@tonic-gate 	if ((Shell = value("SHELL")) == NOSTR || *Shell=='\0')
940Sstevel@tonic-gate 		Shell = SHELL;
950Sstevel@tonic-gate 	for (t = SIGINT; t <= SIGQUIT; t++)
960Sstevel@tonic-gate 		sig[t-SIGINT] = sigset(t, SIG_IGN);
970Sstevel@tonic-gate 	p = vfork();
980Sstevel@tonic-gate 	if (p == 0) {
990Sstevel@tonic-gate 		setuid(getuid());
1000Sstevel@tonic-gate 		sigchild();
1010Sstevel@tonic-gate 		for (t = SIGINT; t <= SIGQUIT; t++)
1020Sstevel@tonic-gate 			if (sig[t-SIGINT] != SIG_IGN)
1030Sstevel@tonic-gate 				sigsys(t, SIG_DFL);
1040Sstevel@tonic-gate 		execlp(Shell, Shell, "-c", cmd, (char *)0);
1050Sstevel@tonic-gate 		perror(Shell);
1060Sstevel@tonic-gate 		_exit(1);
1070Sstevel@tonic-gate 	}
1080Sstevel@tonic-gate 	while (wait(0) != p)
1090Sstevel@tonic-gate 		;
1100Sstevel@tonic-gate 	if (p == (pid_t)-1)
1110Sstevel@tonic-gate 		perror("fork");
1120Sstevel@tonic-gate 	for (t = SIGINT; t <= SIGQUIT; t++)
1130Sstevel@tonic-gate 		sigset(t, sig[t-SIGINT]);
1140Sstevel@tonic-gate 	return(0);
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate /*
1180Sstevel@tonic-gate  * Fork an interactive shell.
1190Sstevel@tonic-gate  */
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate int
1220Sstevel@tonic-gate #ifdef	__cplusplus
dosh(char *)1230Sstevel@tonic-gate dosh(char *)
1240Sstevel@tonic-gate #else
1250Sstevel@tonic-gate /* ARGSUSED */
1260Sstevel@tonic-gate dosh(char *s)
1270Sstevel@tonic-gate #endif
1280Sstevel@tonic-gate {
1290Sstevel@tonic-gate 	void (*sig[2])(int);
1300Sstevel@tonic-gate 	register int t;
1310Sstevel@tonic-gate 	register pid_t p;
1320Sstevel@tonic-gate 	char *Shell;
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	if ((Shell = value("SHELL")) == NOSTR || *Shell=='\0')
1350Sstevel@tonic-gate 		Shell = SHELL;
1360Sstevel@tonic-gate 	for (t = SIGINT; t <= SIGQUIT; t++)
1370Sstevel@tonic-gate 		sig[t-SIGINT] = sigset(t, SIG_IGN);
1380Sstevel@tonic-gate 	p = vfork();
1390Sstevel@tonic-gate 	if (p == 0) {
1400Sstevel@tonic-gate 		setuid(getuid());
1410Sstevel@tonic-gate 		sigchild();
1420Sstevel@tonic-gate 		for (t = SIGINT; t <= SIGQUIT; t++)
1430Sstevel@tonic-gate 			if (sig[t-SIGINT] != SIG_IGN)
1440Sstevel@tonic-gate 				sigset(t, SIG_DFL);
1450Sstevel@tonic-gate 		execlp(Shell, Shell, (char *)0);
1460Sstevel@tonic-gate 		perror(Shell);
1470Sstevel@tonic-gate 		_exit(1);
1480Sstevel@tonic-gate 	}
1490Sstevel@tonic-gate 	while (wait(0) != p)
1500Sstevel@tonic-gate 		;
1510Sstevel@tonic-gate 	if (p == (pid_t)-1)
1520Sstevel@tonic-gate 		perror("fork");
1530Sstevel@tonic-gate 	for (t = SIGINT; t <= SIGQUIT; t++)
1540Sstevel@tonic-gate 		sigset(t, sig[t-SIGINT]);
1550Sstevel@tonic-gate 	putchar('\n');
1560Sstevel@tonic-gate 	return(0);
1570Sstevel@tonic-gate }
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate  * Expand the shell escape by expanding unescaped !'s into the
1610Sstevel@tonic-gate  * last issued command where possible.
1620Sstevel@tonic-gate  */
1630Sstevel@tonic-gate static int
bangexp(char * str)1640Sstevel@tonic-gate bangexp(char *str)
1650Sstevel@tonic-gate {
1660Sstevel@tonic-gate 	char bangbuf[BUFSIZ];
1670Sstevel@tonic-gate 	register char *cp, *cp2;
1680Sstevel@tonic-gate 	register int n;
1690Sstevel@tonic-gate 	int changed = 0;
1700Sstevel@tonic-gate 	int bangit = (value("bang")!=NOSTR);
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	cp = str;
1730Sstevel@tonic-gate 	cp2 = bangbuf;
1740Sstevel@tonic-gate 	n = BUFSIZ;
1750Sstevel@tonic-gate 	while (*cp) {
1760Sstevel@tonic-gate 		if (*cp=='!' && bangit) {
1770Sstevel@tonic-gate 			if (n < (int)strlen(lastbang)) {
1780Sstevel@tonic-gate overf:
1790Sstevel@tonic-gate 				printf(gettext("Command buffer overflow\n"));
1800Sstevel@tonic-gate 				return(-1);
1810Sstevel@tonic-gate 			}
1820Sstevel@tonic-gate 			changed++;
1830Sstevel@tonic-gate 			strcpy(cp2, lastbang);
1840Sstevel@tonic-gate 			cp2 += strlen(lastbang);
1850Sstevel@tonic-gate 			n -= strlen(lastbang);
1860Sstevel@tonic-gate 			cp++;
1870Sstevel@tonic-gate 			continue;
1880Sstevel@tonic-gate 		}
1890Sstevel@tonic-gate 		if (*cp == '\\' && cp[1] == '!') {
1900Sstevel@tonic-gate 			if (--n <= 1)
1910Sstevel@tonic-gate 				goto overf;
1920Sstevel@tonic-gate 			*cp2++ = '!';
1930Sstevel@tonic-gate 			cp += 2;
1940Sstevel@tonic-gate 			changed++;
1950Sstevel@tonic-gate 		}
1960Sstevel@tonic-gate 		if (--n <= 1)
1970Sstevel@tonic-gate 			goto overf;
1980Sstevel@tonic-gate 		*cp2++ = *cp++;
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 	*cp2 = 0;
2010Sstevel@tonic-gate 	if (changed) {
2020Sstevel@tonic-gate 		printf("!%s\n", bangbuf);
2030Sstevel@tonic-gate 		fflush(stdout);
2040Sstevel@tonic-gate 	}
2050Sstevel@tonic-gate 	nstrcpy(str, BUFSIZ, bangbuf);
2060Sstevel@tonic-gate 	nstrcpy(lastbang, sizeof (lastbang), bangbuf);
2070Sstevel@tonic-gate 	return(0);
2080Sstevel@tonic-gate }
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate /*
2110Sstevel@tonic-gate  * Print out a nice help message from some file or another.
2120Sstevel@tonic-gate  */
2130Sstevel@tonic-gate 
2140Sstevel@tonic-gate int
help(void)2150Sstevel@tonic-gate help(void)
2160Sstevel@tonic-gate {
217*18Srobbin 	int c;
2180Sstevel@tonic-gate 	register FILE *f;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	if ((f = fopen(HELPFILE, "r")) == NULL) {
2210Sstevel@tonic-gate 		printf(gettext("No help just now.\n"));
2220Sstevel@tonic-gate 		return(1);
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 	while ((c = getc(f)) != EOF)
2250Sstevel@tonic-gate 		putchar(c);
2260Sstevel@tonic-gate 	fclose(f);
2270Sstevel@tonic-gate 	return(0);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate /*
2310Sstevel@tonic-gate  * Change user's working directory.
2320Sstevel@tonic-gate  */
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate int
schdir(char * str)2350Sstevel@tonic-gate schdir(char *str)
2360Sstevel@tonic-gate {
2370Sstevel@tonic-gate 	register char *cp;
2380Sstevel@tonic-gate 	char cwd[PATHSIZE], file[PATHSIZE];
2390Sstevel@tonic-gate 	static char efile[PATHSIZE];
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	for (cp = str; *cp == ' '; cp++)
2420Sstevel@tonic-gate 		;
2430Sstevel@tonic-gate 	if (*cp == '\0')
2440Sstevel@tonic-gate 		cp = homedir;
2450Sstevel@tonic-gate 	else
2460Sstevel@tonic-gate 		if ((cp = expand(cp)) == NOSTR)
2470Sstevel@tonic-gate 			return(1);
2480Sstevel@tonic-gate 	if (editfile != NOSTR && (*editfile != '/' || mailname[0] != '/')) {
2490Sstevel@tonic-gate 		if (getcwd(cwd, (int)sizeof (cwd)) == 0) {
2500Sstevel@tonic-gate 			fprintf(stderr,
2510Sstevel@tonic-gate 			    gettext("Can't get current directory: %s\n"), cwd);
2520Sstevel@tonic-gate 			return(1);
2530Sstevel@tonic-gate 		}
2540Sstevel@tonic-gate 	}
2550Sstevel@tonic-gate 	if (chdir(cp) < 0) {
2560Sstevel@tonic-gate 		perror(cp);
2570Sstevel@tonic-gate 		return(1);
2580Sstevel@tonic-gate 	}
2590Sstevel@tonic-gate 	/*
2600Sstevel@tonic-gate 	 * Convert previously relative names to absolute names.
2610Sstevel@tonic-gate 	 */
2620Sstevel@tonic-gate 	if (editfile != NOSTR && *editfile != '/') {
2630Sstevel@tonic-gate 		snprintf(file, sizeof (file), "%s/%s", cwd, editfile);
2640Sstevel@tonic-gate 		nstrcpy(efile, sizeof (efile), file);
2650Sstevel@tonic-gate 		editfile = efile;
2660Sstevel@tonic-gate 	}
2670Sstevel@tonic-gate 	if (mailname[0] != '/') {
2680Sstevel@tonic-gate 		snprintf(file, sizeof (file), "%s/%s", cwd, mailname);
2690Sstevel@tonic-gate 		nstrcpy(mailname, PATHSIZE, file);
2700Sstevel@tonic-gate 	}
2710Sstevel@tonic-gate 	return(0);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate  * Two versions of reply.  Reply to all names in message or reply
2760Sstevel@tonic-gate  * to only sender of message, depending on setting of "replyall".
2770Sstevel@tonic-gate  */
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate int
respond(int * msgvec)2800Sstevel@tonic-gate respond(int *msgvec)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	if (reply2sender())
2830Sstevel@tonic-gate 		return(resp1(msgvec, 0));
2840Sstevel@tonic-gate 	else
2850Sstevel@tonic-gate 		return(Resp1(msgvec, 0));
2860Sstevel@tonic-gate }
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate int
followup(int * msgvec)2890Sstevel@tonic-gate followup(int *msgvec)
2900Sstevel@tonic-gate {
2910Sstevel@tonic-gate 	if (reply2sender())
2920Sstevel@tonic-gate 		return(resp1(msgvec, 1));
2930Sstevel@tonic-gate 	else
2940Sstevel@tonic-gate 		return(Resp1(msgvec, 1));
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate int
replyall(int * msgvec)2980Sstevel@tonic-gate replyall(int *msgvec)
2990Sstevel@tonic-gate {
3000Sstevel@tonic-gate 	return(resp1(msgvec, 0));
3010Sstevel@tonic-gate }
3020Sstevel@tonic-gate 
3030Sstevel@tonic-gate static int
resp1(int * msgvec,int useauthor)3040Sstevel@tonic-gate resp1(int *msgvec, int useauthor)
3050Sstevel@tonic-gate {
3060Sstevel@tonic-gate 	struct message *mp;
3070Sstevel@tonic-gate 	char *cp, *buf, *rcv, *skin_rcv, *reply2, **ap, *returnaddr;
3080Sstevel@tonic-gate 	struct name *np;
3090Sstevel@tonic-gate 	struct header head;
3100Sstevel@tonic-gate 	char mylocalname[BUFSIZ], mydomname[BUFSIZ];
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	if (msgvec[1] != 0) {
3130Sstevel@tonic-gate 		printf(gettext(
3140Sstevel@tonic-gate 		    "Sorry, can't reply to multiple messages at once\n"));
3150Sstevel@tonic-gate 		return(1);
3160Sstevel@tonic-gate 	}
3170Sstevel@tonic-gate 	snprintf(mydomname, sizeof (mydomname), "%s@%s", myname, domain);
3180Sstevel@tonic-gate 	snprintf(mylocalname, sizeof (mylocalname), "%s@%s", myname, host);
3190Sstevel@tonic-gate 	returnaddr = value("returnaddr");
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	mp = &message[msgvec[0] - 1];
3220Sstevel@tonic-gate 	dot = mp;
3230Sstevel@tonic-gate 	reply2 = replyto(mp, &rcv);
3240Sstevel@tonic-gate 	cp = skin(hfield("to", mp, addto));
3250Sstevel@tonic-gate 	if (cp != NOSTR) {
3260Sstevel@tonic-gate 		buf = (char *)salloc(strlen(reply2) + strlen(cp) + 2);
3270Sstevel@tonic-gate 		strcpy(buf, reply2);
3280Sstevel@tonic-gate 		strcat(buf, " ");
3290Sstevel@tonic-gate 		strcat(buf, cp);
3300Sstevel@tonic-gate 	} else
3310Sstevel@tonic-gate 		buf = reply2;
3320Sstevel@tonic-gate 	np = elide(extract(buf, GTO));
3330Sstevel@tonic-gate #ifdef	OPTIM
3340Sstevel@tonic-gate 	/* rcv = netrename(rcv); */
3350Sstevel@tonic-gate #endif	/* OPTIM */
3360Sstevel@tonic-gate 	/*
3370Sstevel@tonic-gate 	 * Delete my name from the reply list,
3380Sstevel@tonic-gate 	 * and with it, all my alternate names.
3390Sstevel@tonic-gate 	 */
3400Sstevel@tonic-gate 	skin_rcv = skin(rcv);
3410Sstevel@tonic-gate 	mapf(np, skin_rcv);
3420Sstevel@tonic-gate 	np = delname(np, myname);
3430Sstevel@tonic-gate 	np = delname(np, mylocalname);
3440Sstevel@tonic-gate 	np = delname(np, mydomname);
3450Sstevel@tonic-gate 	if (returnaddr && *returnaddr)
3460Sstevel@tonic-gate 		np = delname(np, returnaddr);
3470Sstevel@tonic-gate 	if (altnames != 0)
3480Sstevel@tonic-gate 		for (ap = altnames; *ap; ap++)
3490Sstevel@tonic-gate 			np = delname(np, *ap);
3500Sstevel@tonic-gate 	head.h_seq = 1;
3510Sstevel@tonic-gate 	cp = detract(np, 0);
3520Sstevel@tonic-gate 	if (cp == NOSTR) {
3530Sstevel@tonic-gate 		if (reply2)
3540Sstevel@tonic-gate 			cp = unuucp(reply2);
3550Sstevel@tonic-gate 		else
3560Sstevel@tonic-gate 			cp = unuucp(rcv);
3570Sstevel@tonic-gate 	}
3580Sstevel@tonic-gate 	head.h_to = cp;
3590Sstevel@tonic-gate 	head.h_subject = hfield("subject", mp, addone);
3600Sstevel@tonic-gate 	if (head.h_subject == NOSTR)
3610Sstevel@tonic-gate 		head.h_subject = hfield("subj", mp, addone);
3620Sstevel@tonic-gate 	head.h_subject = reedit(head.h_subject);
3630Sstevel@tonic-gate 	head.h_cc = NOSTR;
3640Sstevel@tonic-gate 	cp = skin(hfield("cc", mp, addto));
3650Sstevel@tonic-gate 	if (cp != NOSTR) {
3660Sstevel@tonic-gate 		np = elide(extract(cp, GCC));
3670Sstevel@tonic-gate 		mapf(np, skin_rcv);
3680Sstevel@tonic-gate 		np = delname(np, myname);
3690Sstevel@tonic-gate 		np = delname(np, mylocalname);
3700Sstevel@tonic-gate 		np = delname(np, mydomname);
3710Sstevel@tonic-gate 		if (returnaddr && *returnaddr)
3720Sstevel@tonic-gate 			np = delname(np, returnaddr);
3730Sstevel@tonic-gate 		np = delname(np, skin_rcv);
3740Sstevel@tonic-gate 		if (altnames != 0)
3750Sstevel@tonic-gate 			for (ap = altnames; *ap; ap++)
3760Sstevel@tonic-gate 				np = delname(np, *ap);
3770Sstevel@tonic-gate 		head.h_cc = detract(np, 0);
3780Sstevel@tonic-gate 	}
3790Sstevel@tonic-gate 	head.h_bcc = NOSTR;
3800Sstevel@tonic-gate 	head.h_defopt = NOSTR;
3810Sstevel@tonic-gate 	head.h_others = NOSTRPTR;
3820Sstevel@tonic-gate 	mail1(&head, useauthor, useauthor ? rcv : NOSTR);
3830Sstevel@tonic-gate 	return(0);
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate void
getrecf(char * buf,char * recfile,int useauthor,int sz_recfile)3870Sstevel@tonic-gate getrecf(char *buf, char *recfile, int useauthor, int sz_recfile)
3880Sstevel@tonic-gate {
3890Sstevel@tonic-gate 	register char *bp, *cp;
3900Sstevel@tonic-gate 	register char *recf = recfile;
3910Sstevel@tonic-gate 	register int folderize;
3920Sstevel@tonic-gate 	char fldr[BUFSIZ];
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	folderize = (value("outfolder")!=NOSTR && getfold(fldr) == 0);
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	if (useauthor) {
3970Sstevel@tonic-gate 		if (folderize)
3980Sstevel@tonic-gate 			*recf++ = '+';
3990Sstevel@tonic-gate 		if (debug) fprintf(stderr, "buf='%s'\n", buf);
4000Sstevel@tonic-gate 		for (bp=skin(buf), cp=recf; *bp && !any(*bp, ", "); bp++) {
4010Sstevel@tonic-gate 			if (*bp=='!')
4020Sstevel@tonic-gate 				cp = recf;
4030Sstevel@tonic-gate 			else
4040Sstevel@tonic-gate 				*cp++ = *bp;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 			if (cp >= &recfile[sz_recfile - 1]) {
4070Sstevel@tonic-gate 				printf(gettext("File name buffer overflow\n"));
4080Sstevel@tonic-gate 				break;
4090Sstevel@tonic-gate 			}
4100Sstevel@tonic-gate 		}
4110Sstevel@tonic-gate 		*cp = '\0';
4120Sstevel@tonic-gate 		if (cp==recf)
4130Sstevel@tonic-gate 			*recfile = '\0';
4140Sstevel@tonic-gate 		/* now strip off any Internet host names */
4150Sstevel@tonic-gate 		if ((cp = strchr(recf, '%')) == NOSTR)
4160Sstevel@tonic-gate 			cp = strchr(recf, '@');
4170Sstevel@tonic-gate 		if (cp != NOSTR)
4180Sstevel@tonic-gate 			*cp = '\0';
4190Sstevel@tonic-gate 	} else {
4200Sstevel@tonic-gate 		if (cp = value("record")) {
4210Sstevel@tonic-gate 			int sz = PATHSIZE;
4220Sstevel@tonic-gate 			if (folderize && *cp!='+' && *cp!='/'
4230Sstevel@tonic-gate 			 && *safeexpand(cp)!='/') {
4240Sstevel@tonic-gate 				*recf++ = '+';
4250Sstevel@tonic-gate 				sz--;
4260Sstevel@tonic-gate 			}
4270Sstevel@tonic-gate 			nstrcpy(recf, sz, cp);
4280Sstevel@tonic-gate 		} else
4290Sstevel@tonic-gate 			*recf = '\0';
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 	if (debug) fprintf(stderr, "recfile='%s'\n", recfile);
4320Sstevel@tonic-gate }
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate /*
4350Sstevel@tonic-gate  * Modify the subject we are replying to to begin with Re: if
4360Sstevel@tonic-gate  * it does not already.
4370Sstevel@tonic-gate  */
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate static char *
reedit(char * subj)4400Sstevel@tonic-gate reedit(char *subj)
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate 	char sbuf[10];
4430Sstevel@tonic-gate 	register char *newsubj;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	if (subj == NOSTR)
4460Sstevel@tonic-gate 		return(NOSTR);
4470Sstevel@tonic-gate 	strncpy(sbuf, subj, 3);
4480Sstevel@tonic-gate 	sbuf[3] = 0;
4490Sstevel@tonic-gate 	if (icequal(sbuf, "re:"))
4500Sstevel@tonic-gate 		return(subj);
4510Sstevel@tonic-gate 	newsubj = (char *)salloc((unsigned)(strlen(subj) + 5));
4520Sstevel@tonic-gate 	sprintf(newsubj, "Re: %s", subj);
4530Sstevel@tonic-gate 	return(newsubj);
4540Sstevel@tonic-gate }
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate /*
4570Sstevel@tonic-gate  * Preserve the named messages, so that they will be sent
4580Sstevel@tonic-gate  * back to the system mailbox.
4590Sstevel@tonic-gate  */
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate int
preserve(int * msgvec)4620Sstevel@tonic-gate preserve(int *msgvec)
4630Sstevel@tonic-gate {
4640Sstevel@tonic-gate 	register struct message *mp;
4650Sstevel@tonic-gate 	register int *ip, mesg;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	if (edit) {
4680Sstevel@tonic-gate 		printf(gettext("Cannot \"preserve\" in edit mode\n"));
4690Sstevel@tonic-gate 		return(1);
4700Sstevel@tonic-gate 	}
4710Sstevel@tonic-gate 	for (ip = msgvec; *ip != NULL; ip++) {
4720Sstevel@tonic-gate 		mesg = *ip;
4730Sstevel@tonic-gate 		mp = &message[mesg-1];
4740Sstevel@tonic-gate 		mp->m_flag |= MPRESERVE;
4750Sstevel@tonic-gate 		mp->m_flag &= ~MBOX;
4760Sstevel@tonic-gate 		dot = mp;
4770Sstevel@tonic-gate 	}
4780Sstevel@tonic-gate 	return(0);
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate /*
4820Sstevel@tonic-gate  * Mark all given messages as unread.
4830Sstevel@tonic-gate  */
4840Sstevel@tonic-gate int
unread(int msgvec[])4850Sstevel@tonic-gate unread(int msgvec[])
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate 	register int *ip;
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	for (ip = msgvec; *ip != NULL; ip++) {
4900Sstevel@tonic-gate 		dot = &message[*ip-1];
4910Sstevel@tonic-gate 		dot->m_flag &= ~(MREAD|MTOUCH);
4920Sstevel@tonic-gate 		dot->m_flag |= MSTATUS;
4930Sstevel@tonic-gate 	}
4940Sstevel@tonic-gate 	return(0);
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate /*
4980Sstevel@tonic-gate  * Print the size of each message.
4990Sstevel@tonic-gate  */
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate int
messize(int * msgvec)5020Sstevel@tonic-gate messize(int *msgvec)
5030Sstevel@tonic-gate {
5040Sstevel@tonic-gate 	register struct message *mp;
5050Sstevel@tonic-gate 	register int *ip, mesg;
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	for (ip = msgvec; *ip != NULL; ip++) {
5080Sstevel@tonic-gate 		mesg = *ip;
5090Sstevel@tonic-gate 		mp = &message[mesg-1];
5100Sstevel@tonic-gate 		dot = mp;
5110Sstevel@tonic-gate 		printf("%d: %ld\n", mesg, mp->m_size);
5120Sstevel@tonic-gate 	}
5130Sstevel@tonic-gate 	return(0);
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate /*
5170Sstevel@tonic-gate  * Quit quickly.  If we are sourcing, just pop the input level
5180Sstevel@tonic-gate  * by returning an error.
5190Sstevel@tonic-gate  */
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate int
rexit(int e)5220Sstevel@tonic-gate rexit(int e)
5230Sstevel@tonic-gate {
5240Sstevel@tonic-gate 	if (sourcing)
5250Sstevel@tonic-gate 		return(1);
5260Sstevel@tonic-gate 	if (Tflag != NOSTR)
5270Sstevel@tonic-gate 		close(creat(Tflag, TEMPPERM));
5280Sstevel@tonic-gate 	if (!edit)
5290Sstevel@tonic-gate 		Verhogen();
5300Sstevel@tonic-gate 	exit(e ? e : rpterr);
5310Sstevel@tonic-gate 	/* NOTREACHED */
5320Sstevel@tonic-gate 	return (0);	/* shut up lint and CC */
5330Sstevel@tonic-gate }
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate /*
5360Sstevel@tonic-gate  * Set or display a variable value.  Syntax is similar to that
5370Sstevel@tonic-gate  * of csh.
5380Sstevel@tonic-gate  */
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate int
set(char ** arglist)5410Sstevel@tonic-gate set(char **arglist)
5420Sstevel@tonic-gate {
5430Sstevel@tonic-gate 	register struct var *vp;
5440Sstevel@tonic-gate 	register char *cp, *cp2;
5450Sstevel@tonic-gate 	char varbuf[BUFSIZ], **ap, **p;
5460Sstevel@tonic-gate 	int errs, h, s;
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	if (argcount(arglist) == 0) {
5490Sstevel@tonic-gate 		for (h = 0, s = 1; h < HSHSIZE; h++)
5500Sstevel@tonic-gate 			for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
5510Sstevel@tonic-gate 				s++;
5520Sstevel@tonic-gate 		ap = (char **) salloc(s * sizeof *ap);
5530Sstevel@tonic-gate 		for (h = 0, p = ap; h < HSHSIZE; h++)
5540Sstevel@tonic-gate 			for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
5550Sstevel@tonic-gate 				*p++ = vp->v_name;
5560Sstevel@tonic-gate 		*p = NOSTR;
5570Sstevel@tonic-gate 		sort(ap);
5580Sstevel@tonic-gate 		for (p = ap; *p != NOSTR; p++)
5590Sstevel@tonic-gate 			if (((cp = value(*p)) != 0) && *cp)
5600Sstevel@tonic-gate 				printf("%s=\"%s\"\n", *p, cp);
5610Sstevel@tonic-gate 			else
5620Sstevel@tonic-gate 				printf("%s\n", *p);
5630Sstevel@tonic-gate 		return(0);
5640Sstevel@tonic-gate 	}
5650Sstevel@tonic-gate 	errs = 0;
5660Sstevel@tonic-gate 	for (ap = arglist; *ap != NOSTR; ap++) {
5670Sstevel@tonic-gate 		cp = *ap;
5680Sstevel@tonic-gate 		cp2 = varbuf;
5690Sstevel@tonic-gate 		while (*cp != '=' && *cp != '\0')
5700Sstevel@tonic-gate 			*cp2++ = *cp++;
5710Sstevel@tonic-gate 		*cp2 = '\0';
5720Sstevel@tonic-gate 		if (*cp == '\0')
5730Sstevel@tonic-gate 			cp = "";
5740Sstevel@tonic-gate 		else
5750Sstevel@tonic-gate 			cp++;
5760Sstevel@tonic-gate 		if (equal(varbuf, "")) {
5770Sstevel@tonic-gate 			printf(gettext("Non-null variable name required\n"));
5780Sstevel@tonic-gate 			errs++;
5790Sstevel@tonic-gate 			continue;
5800Sstevel@tonic-gate 		}
5810Sstevel@tonic-gate 		assign(varbuf, cp);
5820Sstevel@tonic-gate 	}
5830Sstevel@tonic-gate 	return(errs);
5840Sstevel@tonic-gate }
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate /*
5870Sstevel@tonic-gate  * Unset a bunch of variable values.
5880Sstevel@tonic-gate  */
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate int
unset(char ** arglist)5910Sstevel@tonic-gate unset(char **arglist)
5920Sstevel@tonic-gate {
5930Sstevel@tonic-gate 	register int errs;
5940Sstevel@tonic-gate 	register char **ap;
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	errs = 0;
5970Sstevel@tonic-gate 	for (ap = arglist; *ap != NOSTR; ap++)
5980Sstevel@tonic-gate 		errs += deassign(*ap);
5990Sstevel@tonic-gate 	return(errs);
6000Sstevel@tonic-gate }
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate /*
6030Sstevel@tonic-gate  * Add users to a group.
6040Sstevel@tonic-gate  */
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate int
group(char ** argv)6070Sstevel@tonic-gate group(char **argv)
6080Sstevel@tonic-gate {
6090Sstevel@tonic-gate 	register struct grouphead *gh;
6100Sstevel@tonic-gate 	register struct mgroup *gp;
6110Sstevel@tonic-gate 	register int h;
6120Sstevel@tonic-gate 	int s;
6130Sstevel@tonic-gate 	char **ap, *gname, **p;
6140Sstevel@tonic-gate 
6150Sstevel@tonic-gate 	if (argcount(argv) == 0) {
6160Sstevel@tonic-gate 		for (h = 0, s = 1; h < HSHSIZE; h++)
6170Sstevel@tonic-gate 			for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
6180Sstevel@tonic-gate 				s++;
6190Sstevel@tonic-gate 		ap = (char **) salloc(s * sizeof *ap);
6200Sstevel@tonic-gate 		for (h = 0, p = ap; h < HSHSIZE; h++)
6210Sstevel@tonic-gate 			for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
6220Sstevel@tonic-gate 				*p++ = gh->g_name;
6230Sstevel@tonic-gate 		*p = NOSTR;
6240Sstevel@tonic-gate 		sort(ap);
6250Sstevel@tonic-gate 		for (p = ap; *p != NOSTR; p++)
6260Sstevel@tonic-gate 			printgroup(*p);
6270Sstevel@tonic-gate 		return(0);
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate 	if (argcount(argv) == 1) {
6300Sstevel@tonic-gate 		printgroup(*argv);
6310Sstevel@tonic-gate 		return(0);
6320Sstevel@tonic-gate 	}
6330Sstevel@tonic-gate 	gname = *argv;
6340Sstevel@tonic-gate 	h = hash(gname);
6350Sstevel@tonic-gate 	if ((gh = findgroup(gname)) == NOGRP) {
6360Sstevel@tonic-gate 		if ((gh = (struct grouphead *)
6370Sstevel@tonic-gate 		    calloc(sizeof (*gh), 1)) == NULL) {
6380Sstevel@tonic-gate 			panic("Failed to allocate memory for group");
6390Sstevel@tonic-gate 	}
6400Sstevel@tonic-gate 		gh->g_name = vcopy(gname);
6410Sstevel@tonic-gate 		gh->g_list = NOGE;
6420Sstevel@tonic-gate 		gh->g_link = groups[h];
6430Sstevel@tonic-gate 		groups[h] = gh;
6440Sstevel@tonic-gate 	}
6450Sstevel@tonic-gate 
6460Sstevel@tonic-gate 	/*
6470Sstevel@tonic-gate 	 * Insert names from the command list into the group.
6480Sstevel@tonic-gate 	 * Who cares if there are duplicates?  They get tossed
6490Sstevel@tonic-gate 	 * later anyway.
6500Sstevel@tonic-gate 	 */
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	for (ap = argv+1; *ap != NOSTR; ap++) {
6530Sstevel@tonic-gate 		if ((gp = (struct mgroup *)
6540Sstevel@tonic-gate 		    calloc(sizeof (*gp), 1)) == NULL) {
6550Sstevel@tonic-gate 			panic("Failed to allocate memory for group");
6560Sstevel@tonic-gate 	}
6570Sstevel@tonic-gate 	gp->ge_name = vcopy(*ap);
6580Sstevel@tonic-gate 		gp->ge_link = gh->g_list;
6590Sstevel@tonic-gate 		gh->g_list = gp;
6600Sstevel@tonic-gate 	}
6610Sstevel@tonic-gate 	return(0);
6620Sstevel@tonic-gate }
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate /*
6650Sstevel@tonic-gate  * Remove users from a group.
6660Sstevel@tonic-gate  */
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate int
ungroup(char ** argv)6690Sstevel@tonic-gate ungroup(char **argv)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	register struct grouphead *gh, **ghp;
6720Sstevel@tonic-gate 	register struct mgroup *gp, *gpnext;
6730Sstevel@tonic-gate 	register int h;
6740Sstevel@tonic-gate 	char **ap, *gname;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	if (argcount(argv) == 0) {
6770Sstevel@tonic-gate 		printf("Must specify alias or group to remove\n");
6780Sstevel@tonic-gate 		return(1);
6790Sstevel@tonic-gate 	}
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	/*
6820Sstevel@tonic-gate 	 * Remove names on the command list from the group list.
6830Sstevel@tonic-gate 	 */
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	for (ap = argv; *ap != NOSTR; ap++) {
6860Sstevel@tonic-gate 		gname = *ap;
6870Sstevel@tonic-gate 		h = hash(gname);
6880Sstevel@tonic-gate 		for (ghp = &groups[h]; *ghp != NOGRP; ghp = &((*ghp)->g_link)) {
6890Sstevel@tonic-gate 			gh = *ghp;
6900Sstevel@tonic-gate 			if (equal(gh->g_name, gname)) {
6910Sstevel@tonic-gate 				/* remove from list */
6920Sstevel@tonic-gate 				*ghp = gh->g_link;
6930Sstevel@tonic-gate 				/* free each member of gorup */
6940Sstevel@tonic-gate 				for (gp = gh->g_list; gp != NOGE; gp = gpnext) {
6950Sstevel@tonic-gate 					gpnext = gp->ge_link;
6960Sstevel@tonic-gate 					vfree(gp->ge_name);
6970Sstevel@tonic-gate 					free(gp);
6980Sstevel@tonic-gate 				}
6990Sstevel@tonic-gate 				vfree(gh->g_name);
7000Sstevel@tonic-gate 				free(gh);
7010Sstevel@tonic-gate 				break;
7020Sstevel@tonic-gate 			}
7030Sstevel@tonic-gate 		}
7040Sstevel@tonic-gate 	}
7050Sstevel@tonic-gate 	return(0);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate /*
7090Sstevel@tonic-gate  * Sort the passed string vecotor into ascending dictionary
7100Sstevel@tonic-gate  * order.
7110Sstevel@tonic-gate  */
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate static void
sort(char ** list)7140Sstevel@tonic-gate sort(char **list)
7150Sstevel@tonic-gate {
7160Sstevel@tonic-gate 	register char **ap;
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	for (ap = list; *ap != NOSTR; ap++)
7190Sstevel@tonic-gate 		;
7200Sstevel@tonic-gate 	if (ap-list < 2)
7210Sstevel@tonic-gate 		return;
7220Sstevel@tonic-gate 	qsort((char *) list, (unsigned) (ap-list), sizeof *list, diction);
7230Sstevel@tonic-gate }
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate /*
7260Sstevel@tonic-gate  * Do a dictionary order comparison of the arguments from
7270Sstevel@tonic-gate  * qsort.
7280Sstevel@tonic-gate  */
7290Sstevel@tonic-gate static int
diction(const void * a,const void * b)7300Sstevel@tonic-gate diction(const void *a, const void *b)
7310Sstevel@tonic-gate {
7320Sstevel@tonic-gate 	return(strcmp(*(char **)a, *(char **)b));
7330Sstevel@tonic-gate }
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate /*
7360Sstevel@tonic-gate  * The do nothing command for comments.
7370Sstevel@tonic-gate  */
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate int
7400Sstevel@tonic-gate #ifdef	__cplusplus
null(char *)7410Sstevel@tonic-gate null(char *)
7420Sstevel@tonic-gate #else
7430Sstevel@tonic-gate /* ARGSUSED */
7440Sstevel@tonic-gate null(char *s)
7450Sstevel@tonic-gate #endif
7460Sstevel@tonic-gate {
7470Sstevel@tonic-gate 	return(0);
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate /*
7510Sstevel@tonic-gate  * Print out the current edit file, if we are editing.
7520Sstevel@tonic-gate  * Otherwise, print the name of the person who's mail
7530Sstevel@tonic-gate  * we are reading.
7540Sstevel@tonic-gate  */
7550Sstevel@tonic-gate int
file(char ** argv)7560Sstevel@tonic-gate file(char **argv)
7570Sstevel@tonic-gate {
7580Sstevel@tonic-gate 	register char *cp;
7590Sstevel@tonic-gate 	int editing, mdot;
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	if (argv[0] == NOSTR) {
7620Sstevel@tonic-gate 		mdot = newfileinfo(1);
7630Sstevel@tonic-gate 		dot = &message[mdot - 1];
7640Sstevel@tonic-gate 		return(0);
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/*
7680Sstevel@tonic-gate 	 * Acker's!  Must switch to the new file.
7690Sstevel@tonic-gate 	 * We use a funny interpretation --
7700Sstevel@tonic-gate 	 *	# -- gets the previous file
7710Sstevel@tonic-gate 	 *	% -- gets the invoker's post office box
7720Sstevel@tonic-gate 	 *	%user -- gets someone else's post office box
7730Sstevel@tonic-gate 	 *	& -- gets invoker's mbox file
7740Sstevel@tonic-gate 	 *	string -- reads the given file
7750Sstevel@tonic-gate 	 */
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	cp = getfilename(argv[0], &editing);
7780Sstevel@tonic-gate 	if (cp == NOSTR)
7790Sstevel@tonic-gate 		return(-1);
7800Sstevel@tonic-gate 	if (setfile(cp, editing)) {
7810Sstevel@tonic-gate 		nstrcpy(origname, PATHSIZE, origprevfile);
7820Sstevel@tonic-gate 		return(-1);
7830Sstevel@tonic-gate 	}
7840Sstevel@tonic-gate 	mdot = newfileinfo(1);
7850Sstevel@tonic-gate 	dot = &message[mdot - 1];
7860Sstevel@tonic-gate 	return(0);
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate /*
7900Sstevel@tonic-gate  * Evaluate the string given as a new mailbox name.
7910Sstevel@tonic-gate  * Ultimately, we want this to support a number of meta characters.
7920Sstevel@tonic-gate  * Possibly:
7930Sstevel@tonic-gate  *	% -- for my system mail box
7940Sstevel@tonic-gate  *	%user -- for user's system mail box
7950Sstevel@tonic-gate  *	# -- for previous file
7960Sstevel@tonic-gate  *	& -- get's invoker's mbox file
7970Sstevel@tonic-gate  *	file name -- for any other file
7980Sstevel@tonic-gate  */
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate static char *
getfilename(char * name,int * aedit)8010Sstevel@tonic-gate getfilename(char *name, int *aedit)
8020Sstevel@tonic-gate {
8030Sstevel@tonic-gate 	register char *cp;
8040Sstevel@tonic-gate 	char savename[BUFSIZ];
8050Sstevel@tonic-gate 	char oldmailname[BUFSIZ];
8060Sstevel@tonic-gate 	char tmp[BUFSIZ];
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate 	/*
8090Sstevel@tonic-gate 	 * Assume we will be in "edit file" mode, until
8100Sstevel@tonic-gate 	 * proven wrong.
8110Sstevel@tonic-gate 	 */
8120Sstevel@tonic-gate 	*aedit = 1;
8130Sstevel@tonic-gate 	switch (*name) {
8140Sstevel@tonic-gate 	case '%':
8150Sstevel@tonic-gate 		*aedit = 0;
8160Sstevel@tonic-gate 		nstrcpy(prevfile, sizeof (prevfile), editfile);
8170Sstevel@tonic-gate 		nstrcpy(origprevfile, sizeof (origprevfile), origname);
8180Sstevel@tonic-gate 		if (name[1] != 0) {
8190Sstevel@tonic-gate 			nstrcpy(oldmailname, sizeof (oldmailname), mailname);
8200Sstevel@tonic-gate 			findmail(name+1);
8210Sstevel@tonic-gate 			cp = savestr(mailname);
8220Sstevel@tonic-gate 			nstrcpy(origname, PATHSIZE, cp);
8230Sstevel@tonic-gate 			nstrcpy(mailname, PATHSIZE, oldmailname);
8240Sstevel@tonic-gate 			return(cp);
8250Sstevel@tonic-gate 		}
8260Sstevel@tonic-gate 		nstrcpy(oldmailname, sizeof (oldmailname), mailname);
8270Sstevel@tonic-gate 		findmail(NULL);
8280Sstevel@tonic-gate 		cp = savestr(mailname);
8290Sstevel@tonic-gate 		nstrcpy(mailname, PATHSIZE, oldmailname);
8300Sstevel@tonic-gate 		nstrcpy(origname, PATHSIZE, cp);
8310Sstevel@tonic-gate 		return(cp);
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 	case '#':
8340Sstevel@tonic-gate 		if (name[1] != 0)
8350Sstevel@tonic-gate 			goto regular;
8360Sstevel@tonic-gate 		if (prevfile[0] == 0) {
8370Sstevel@tonic-gate 			printf(gettext("No previous file\n"));
8380Sstevel@tonic-gate 			return(NOSTR);
8390Sstevel@tonic-gate 		}
8400Sstevel@tonic-gate 		cp = savestr(prevfile);
8410Sstevel@tonic-gate 		nstrcpy(prevfile, sizeof (prevfile), editfile);
8420Sstevel@tonic-gate 		nstrcpy(tmp, sizeof (tmp), origname);
8430Sstevel@tonic-gate 		nstrcpy(origname, PATHSIZE, origprevfile);
8440Sstevel@tonic-gate 		nstrcpy(origprevfile, sizeof (origprevfile), tmp);
8450Sstevel@tonic-gate 		return(cp);
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	case '&':
8480Sstevel@tonic-gate 		nstrcpy(prevfile, sizeof (prevfile), editfile);
8490Sstevel@tonic-gate 		nstrcpy(origprevfile, sizeof (origprevfile), origname);
8500Sstevel@tonic-gate 		if (name[1] == 0) {
8510Sstevel@tonic-gate 			cp=Getf("MBOX");
8520Sstevel@tonic-gate 			nstrcpy(origname, PATHSIZE, cp);
8530Sstevel@tonic-gate 			return(cp);
8540Sstevel@tonic-gate 		}
8550Sstevel@tonic-gate 		/* Fall into . . . */
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	default:
8580Sstevel@tonic-gate regular:
8590Sstevel@tonic-gate 		nstrcpy(prevfile, sizeof (prevfile), editfile);
8600Sstevel@tonic-gate 		nstrcpy(origprevfile, sizeof (origprevfile), origname);
8610Sstevel@tonic-gate 		cp = safeexpand(name);
8620Sstevel@tonic-gate 		nstrcpy(origname, PATHSIZE, cp);
8630Sstevel@tonic-gate 		if (cp[0] != '/') {
8640Sstevel@tonic-gate 			name = getcwd(NOSTR, PATHSIZE);
8650Sstevel@tonic-gate 			nstrcat(name, PATHSIZE, "/");
8660Sstevel@tonic-gate 			nstrcat(name, PATHSIZE, cp);
8670Sstevel@tonic-gate 			cp = name;
8680Sstevel@tonic-gate 		}
8690Sstevel@tonic-gate 		return(cp);
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate }
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate /*
8740Sstevel@tonic-gate  * Expand file names like echo
8750Sstevel@tonic-gate  */
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate int
echo(register char ** argv)8780Sstevel@tonic-gate echo(register char **argv)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	register char *cp;
8810Sstevel@tonic-gate 	int neednl = 0;
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	while (*argv != NOSTR) {
8840Sstevel@tonic-gate 		cp = *argv++;
8850Sstevel@tonic-gate 		if ((cp = expand(cp)) != NOSTR) {
8860Sstevel@tonic-gate 			neednl++;
8870Sstevel@tonic-gate 			printf("%s", cp);
8880Sstevel@tonic-gate 			if (*argv!=NOSTR)
8890Sstevel@tonic-gate 				putchar(' ');
8900Sstevel@tonic-gate 		}
8910Sstevel@tonic-gate 	}
8920Sstevel@tonic-gate 	if (neednl)
8930Sstevel@tonic-gate 		putchar('\n');
8940Sstevel@tonic-gate 	return(0);
8950Sstevel@tonic-gate }
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate /*
8980Sstevel@tonic-gate  * Reply to a series of messages by simply mailing to the senders
8990Sstevel@tonic-gate  * and not messing around with the To: and Cc: lists as in normal
9000Sstevel@tonic-gate  * reply.
9010Sstevel@tonic-gate  */
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate int
Respond(int * msgvec)9040Sstevel@tonic-gate Respond(int *msgvec)
9050Sstevel@tonic-gate {
9060Sstevel@tonic-gate 	if (reply2sender())
9070Sstevel@tonic-gate 		return(Resp1(msgvec, 0));
9080Sstevel@tonic-gate 	else
9090Sstevel@tonic-gate 		return(resp1(msgvec, 0));
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate int
Followup(int * msgvec)9130Sstevel@tonic-gate Followup(int *msgvec)
9140Sstevel@tonic-gate {
9150Sstevel@tonic-gate 	if (reply2sender())
9160Sstevel@tonic-gate 		return(Resp1(msgvec, 1));
9170Sstevel@tonic-gate 	else
9180Sstevel@tonic-gate 		return(resp1(msgvec, 1));
9190Sstevel@tonic-gate }
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate int
replysender(int * msgvec)9220Sstevel@tonic-gate replysender(int *msgvec)
9230Sstevel@tonic-gate {
9240Sstevel@tonic-gate 	return(Resp1(msgvec, 0));
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate static int
Resp1(int * msgvec,int useauthor)9280Sstevel@tonic-gate Resp1(int *msgvec, int useauthor)
9290Sstevel@tonic-gate {
9300Sstevel@tonic-gate 	struct header head;
9310Sstevel@tonic-gate 	struct message *mp;
9320Sstevel@tonic-gate 	register int s, *ap;
9330Sstevel@tonic-gate 	register char *cp, *cp2, *subject;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	for (s = 0, ap = msgvec; *ap != 0; ap++) {
9360Sstevel@tonic-gate 		mp = &message[*ap - 1];
9370Sstevel@tonic-gate 		dot = mp;
9380Sstevel@tonic-gate 		cp = replyto(mp, NOSTRPTR);
9390Sstevel@tonic-gate 		s += strlen(cp) + 1;
9400Sstevel@tonic-gate 	}
9410Sstevel@tonic-gate 	if (s == 0)
9420Sstevel@tonic-gate 		return(0);
9430Sstevel@tonic-gate 	cp = (char *)salloc(s + 2);
9440Sstevel@tonic-gate 	head.h_to = cp;
9450Sstevel@tonic-gate 	for (ap = msgvec; *ap != 0; ap++) {
9460Sstevel@tonic-gate 		mp = &message[*ap - 1];
9470Sstevel@tonic-gate 		cp2 = replyto(mp, NOSTRPTR);
9480Sstevel@tonic-gate 		cp = copy(cp2, cp);
9490Sstevel@tonic-gate 		*cp++ = ' ';
9500Sstevel@tonic-gate 	}
9510Sstevel@tonic-gate 	*--cp = 0;
9520Sstevel@tonic-gate 	mp = &message[msgvec[0] - 1];
9530Sstevel@tonic-gate 	subject = hfield("subject", mp, addone);
9540Sstevel@tonic-gate 	head.h_seq = 1;
9550Sstevel@tonic-gate 	if (subject == NOSTR)
9560Sstevel@tonic-gate 		subject = hfield("subj", mp, addone);
9570Sstevel@tonic-gate 	head.h_subject = reedit(subject);
9580Sstevel@tonic-gate 	if (subject != NOSTR)
9590Sstevel@tonic-gate 		head.h_seq++;
9600Sstevel@tonic-gate 	head.h_cc = NOSTR;
9610Sstevel@tonic-gate 	head.h_bcc = NOSTR;
9620Sstevel@tonic-gate 	head.h_defopt = NOSTR;
9630Sstevel@tonic-gate 	head.h_others = NOSTRPTR;
9640Sstevel@tonic-gate 	mail1(&head, useauthor, NOSTR);
9650Sstevel@tonic-gate 	return(0);
9660Sstevel@tonic-gate }
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate /*
9690Sstevel@tonic-gate  * Conditional commands.  These allow one to parameterize one's
9700Sstevel@tonic-gate  * .mailrc and do some things if sending, others if receiving.
9710Sstevel@tonic-gate  */
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate int
ifcmd(char ** argv)9740Sstevel@tonic-gate ifcmd(char **argv)
9750Sstevel@tonic-gate {
9760Sstevel@tonic-gate 	register char *cp;
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	if (cond != CANY) {
9790Sstevel@tonic-gate 		printf(gettext("Illegal nested \"if\"\n"));
9800Sstevel@tonic-gate 		return(1);
9810Sstevel@tonic-gate 	}
9820Sstevel@tonic-gate 	cond = CANY;
9830Sstevel@tonic-gate 	cp = argv[0];
9840Sstevel@tonic-gate 	switch (*cp) {
9850Sstevel@tonic-gate 	case 'r': case 'R':
9860Sstevel@tonic-gate 		cond = CRCV;
9870Sstevel@tonic-gate 		break;
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	case 's': case 'S':
9900Sstevel@tonic-gate 		cond = CSEND;
9910Sstevel@tonic-gate 		break;
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 	case 't': case 'T':
9940Sstevel@tonic-gate 		cond = CTTY;
9950Sstevel@tonic-gate 		break;
9960Sstevel@tonic-gate 
9970Sstevel@tonic-gate 	default:
9980Sstevel@tonic-gate 		printf(gettext("Unrecognized if-keyword: \"%s\"\n"), cp);
9990Sstevel@tonic-gate 		return(1);
10000Sstevel@tonic-gate 	}
10010Sstevel@tonic-gate 	return(0);
10020Sstevel@tonic-gate }
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate /*
10050Sstevel@tonic-gate  * Implement 'else'.  This is pretty simple -- we just
10060Sstevel@tonic-gate  * flip over the conditional flag.
10070Sstevel@tonic-gate  */
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate int
elsecmd(void)10100Sstevel@tonic-gate elsecmd(void)
10110Sstevel@tonic-gate {
10120Sstevel@tonic-gate 
10130Sstevel@tonic-gate 	switch (cond) {
10140Sstevel@tonic-gate 	case CANY:
10150Sstevel@tonic-gate 		printf(gettext("\"Else\" without matching \"if\"\n"));
10160Sstevel@tonic-gate 		return(1);
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 	case CSEND:
10190Sstevel@tonic-gate 		cond = CRCV;
10200Sstevel@tonic-gate 		break;
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate 	case CRCV:
10230Sstevel@tonic-gate 		cond = CSEND;
10240Sstevel@tonic-gate 		break;
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	case CTTY:
10270Sstevel@tonic-gate 		cond = CNOTTY;
10280Sstevel@tonic-gate 		break;
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	case CNOTTY:
10310Sstevel@tonic-gate 		cond = CTTY;
10320Sstevel@tonic-gate 		break;
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	default:
10350Sstevel@tonic-gate 		printf(gettext("invalid condition encountered\n"));
10360Sstevel@tonic-gate 		cond = CANY;
10370Sstevel@tonic-gate 		break;
10380Sstevel@tonic-gate 	}
10390Sstevel@tonic-gate 	return(0);
10400Sstevel@tonic-gate }
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate /*
10430Sstevel@tonic-gate  * End of if statement.  Just set cond back to anything.
10440Sstevel@tonic-gate  */
10450Sstevel@tonic-gate 
10460Sstevel@tonic-gate int
endifcmd(void)10470Sstevel@tonic-gate endifcmd(void)
10480Sstevel@tonic-gate {
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	if (cond == CANY) {
10510Sstevel@tonic-gate 		printf(gettext("\"Endif\" without matching \"if\"\n"));
10520Sstevel@tonic-gate 		return(1);
10530Sstevel@tonic-gate 	}
10540Sstevel@tonic-gate 	cond = CANY;
10550Sstevel@tonic-gate 	return(0);
10560Sstevel@tonic-gate }
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate /*
10590Sstevel@tonic-gate  * Set the list of alternate names.
10600Sstevel@tonic-gate  */
10610Sstevel@tonic-gate int
alternates(char ** namelist)10620Sstevel@tonic-gate alternates(char **namelist)
10630Sstevel@tonic-gate {
10640Sstevel@tonic-gate 	register int c;
10650Sstevel@tonic-gate 	register char **ap, **ap2, *cp;
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	c = argcount(namelist) + 1;
10680Sstevel@tonic-gate 	if (c == 1) {
10690Sstevel@tonic-gate 		if (altnames == 0)
10700Sstevel@tonic-gate 			return(0);
10710Sstevel@tonic-gate 		for (ap = altnames; *ap; ap++)
10720Sstevel@tonic-gate 			printf("%s ", *ap);
10730Sstevel@tonic-gate 		printf("\n");
10740Sstevel@tonic-gate 		return (0);
10750Sstevel@tonic-gate 	}
10760Sstevel@tonic-gate 	if (altnames != 0)
10770Sstevel@tonic-gate 		free((char *)altnames);
10780Sstevel@tonic-gate 	if ((altnames = (char **)
10790Sstevel@tonic-gate 	    calloc((unsigned)c, sizeof (char *))) == NULL)
10800Sstevel@tonic-gate 		panic("Failed to allocate memory");
10810Sstevel@tonic-gate 	for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) {
10820Sstevel@tonic-gate 		if ((cp = (char *)
10830Sstevel@tonic-gate 		    calloc((unsigned)strlen(*ap) + 1, sizeof (char))) == NULL)
10840Sstevel@tonic-gate 			panic("Failed to allocate memory");
10850Sstevel@tonic-gate 		strcpy(cp, *ap);
10860Sstevel@tonic-gate 		*ap2 = cp;
10870Sstevel@tonic-gate 	}
10880Sstevel@tonic-gate 	*ap2 = 0;
10890Sstevel@tonic-gate 	return(0);
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate /*
10930Sstevel@tonic-gate  * Figure out who to reply to.
10940Sstevel@tonic-gate  * Return the real sender in *f.
10950Sstevel@tonic-gate  */
10960Sstevel@tonic-gate static char *
replyto(struct message * mp,char ** f)10970Sstevel@tonic-gate replyto(struct message *mp, char **f)
10980Sstevel@tonic-gate {
10990Sstevel@tonic-gate 	char *r, *rf;
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	if ((rf = skin(hfield("from", mp, addto)))==NOSTR)
11020Sstevel@tonic-gate 		rf = skin(addto(NOSTR, nameof(mp)));
11030Sstevel@tonic-gate 	if ((r = skin(hfield("reply-to", mp, addto)))==NOSTR)
11040Sstevel@tonic-gate 		r = rf;
11050Sstevel@tonic-gate 	if (f)
11060Sstevel@tonic-gate 		*f = rf;
11070Sstevel@tonic-gate 	return (r);
11080Sstevel@tonic-gate }
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate /*
11110Sstevel@tonic-gate  * reply2sender - determine whether a "reply" command should reply to the
11120Sstevel@tonic-gate  *                sender of the messages, or to all the recipients of the
11130Sstevel@tonic-gate  *                message.
11140Sstevel@tonic-gate  *
11150Sstevel@tonic-gate  *                With the advent of POSIX.2 compliance, this has become
11160Sstevel@tonic-gate  *                a bit more complicated, and so should be done in one
11170Sstevel@tonic-gate  *                place, for all to use.
11180Sstevel@tonic-gate  */
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate static int
reply2sender(void)11210Sstevel@tonic-gate reply2sender (void)
11220Sstevel@tonic-gate {
11230Sstevel@tonic-gate 	register int rep = (value("replyall") != NOSTR);
11240Sstevel@tonic-gate 	register int flp = (value("flipr") != NOSTR);
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	return((rep && !flp)|| (!rep && flp));
11270Sstevel@tonic-gate }
1128