cmd3.c revision 88150
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1980, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes *
51590Srgrimes * Redistribution and use in source and binary forms, with or without
61590Srgrimes * modification, are permitted provided that the following conditions
71590Srgrimes * are met:
81590Srgrimes * 1. Redistributions of source code must retain the above copyright
91590Srgrimes *    notice, this list of conditions and the following disclaimer.
101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111590Srgrimes *    notice, this list of conditions and the following disclaimer in the
121590Srgrimes *    documentation and/or other materials provided with the distribution.
131590Srgrimes * 3. All advertising materials mentioning features or use of this software
141590Srgrimes *    must display the following acknowledgement:
151590Srgrimes *	This product includes software developed by the University of
161590Srgrimes *	California, Berkeley and its contributors.
171590Srgrimes * 4. Neither the name of the University nor the names of its contributors
181590Srgrimes *    may be used to endorse or promote products derived from this software
191590Srgrimes *    without specific prior written permission.
201590Srgrimes *
211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311590Srgrimes * SUCH DAMAGE.
321590Srgrimes */
331590Srgrimes
341590Srgrimes#ifndef lint
3574769Smikeh#if 0
3688150Smikehstatic char sccsid[] = "@(#)cmd3.c	8.2 (Berkeley) 4/20/95";
3774769Smikeh#endif
3874769Smikehstatic const char rcsid[] =
3974769Smikeh  "$FreeBSD: head/usr.bin/mail/cmd3.c 88150 2001-12-18 20:52:09Z mikeh $";
401590Srgrimes#endif /* not lint */
411590Srgrimes
421590Srgrimes#include "rcv.h"
431590Srgrimes#include "extern.h"
441590Srgrimes
451590Srgrimes/*
461590Srgrimes * Mail -- a mail program
471590Srgrimes *
481590Srgrimes * Still more user commands.
491590Srgrimes */
501590Srgrimes
511590Srgrimes/*
521590Srgrimes * Process a shell escape by saving signals, ignoring signals,
531590Srgrimes * and forking a sh -c
541590Srgrimes */
551590Srgrimesint
561590Srgrimesshell(str)
571590Srgrimes	char *str;
581590Srgrimes{
591590Srgrimes	sig_t sigint = signal(SIGINT, SIG_IGN);
6077274Smikeh	char *sh;
611590Srgrimes	char cmd[BUFSIZ];
621590Srgrimes
6374769Smikeh	if (strlcpy(cmd, str, sizeof(cmd)) >= sizeof(cmd))
6477274Smikeh		return (1);
6574769Smikeh	if (bangexp(cmd, sizeof(cmd)) < 0)
6677274Smikeh		return (1);
6777274Smikeh	if ((sh = value("SHELL")) == NULL)
6877274Smikeh		sh = _PATH_CSHELL;
6977274Smikeh	(void)run_command(sh, 0, -1, -1, "-c", cmd, NULL);
7077274Smikeh	(void)signal(SIGINT, sigint);
711590Srgrimes	printf("!\n");
7277274Smikeh	return (0);
731590Srgrimes}
741590Srgrimes
751590Srgrimes/*
761590Srgrimes * Fork an interactive shell.
771590Srgrimes */
781590Srgrimes/*ARGSUSED*/
791590Srgrimesint
801590Srgrimesdosh(str)
811590Srgrimes	char *str;
821590Srgrimes{
831590Srgrimes	sig_t sigint = signal(SIGINT, SIG_IGN);
8477274Smikeh	char *sh;
851590Srgrimes
8677274Smikeh	if ((sh = value("SHELL")) == NULL)
8777274Smikeh		sh = _PATH_CSHELL;
8877274Smikeh	(void)run_command(sh, 0, -1, -1, NULL, NULL, NULL);
8977274Smikeh	(void)signal(SIGINT, sigint);
9077274Smikeh	printf("\n");
9177274Smikeh	return (0);
921590Srgrimes}
931590Srgrimes
941590Srgrimes/*
951590Srgrimes * Expand the shell escape by expanding unescaped !'s into the
961590Srgrimes * last issued command where possible.
971590Srgrimes */
981590Srgrimesint
9974769Smikehbangexp(str, strsize)
1001590Srgrimes	char *str;
10174769Smikeh	size_t strsize;
1021590Srgrimes{
1031590Srgrimes	char bangbuf[BUFSIZ];
10474769Smikeh	static char lastbang[BUFSIZ];
10577274Smikeh	char *cp, *cp2;
10677274Smikeh	int n, changed = 0;
1071590Srgrimes
1081590Srgrimes	cp = str;
1091590Srgrimes	cp2 = bangbuf;
11074769Smikeh	n = sizeof(bangbuf);
11177274Smikeh	while (*cp != '\0') {
1121590Srgrimes		if (*cp == '!') {
1131590Srgrimes			if (n < strlen(lastbang)) {
1141590Srgrimesoverf:
1151590Srgrimes				printf("Command buffer overflow\n");
11677274Smikeh				return (-1);
1171590Srgrimes			}
1181590Srgrimes			changed++;
11974769Smikeh			if (strlcpy(cp2, lastbang, sizeof(bangbuf) - (cp2 - bangbuf))
12074769Smikeh			    >= sizeof(bangbuf) - (cp2 - bangbuf))
12174769Smikeh				goto overf;
1221590Srgrimes			cp2 += strlen(lastbang);
1231590Srgrimes			n -= strlen(lastbang);
1241590Srgrimes			cp++;
1251590Srgrimes			continue;
1261590Srgrimes		}
1271590Srgrimes		if (*cp == '\\' && cp[1] == '!') {
1281590Srgrimes			if (--n <= 1)
1291590Srgrimes				goto overf;
1301590Srgrimes			*cp2++ = '!';
1311590Srgrimes			cp += 2;
1321590Srgrimes			changed++;
1331590Srgrimes		}
1341590Srgrimes		if (--n <= 1)
1351590Srgrimes			goto overf;
1361590Srgrimes		*cp2++ = *cp++;
1371590Srgrimes	}
1381590Srgrimes	*cp2 = 0;
1391590Srgrimes	if (changed) {
1401590Srgrimes		printf("!%s\n", bangbuf);
14177274Smikeh		(void)fflush(stdout);
1421590Srgrimes	}
14374769Smikeh	if (strlcpy(str, bangbuf, strsize) >= strsize)
14474769Smikeh		goto overf;
14574769Smikeh	if (strlcpy(lastbang, bangbuf, sizeof(lastbang)) >= sizeof(lastbang))
14674769Smikeh		goto overf;
14777274Smikeh	return (0);
1481590Srgrimes}
1491590Srgrimes
1501590Srgrimes/*
1511590Srgrimes * Print out a nice help message from some file or another.
1521590Srgrimes */
1531590Srgrimes
1541590Srgrimesint
1551590Srgrimeshelp()
1561590Srgrimes{
15777274Smikeh	int c;
15877274Smikeh	FILE *f;
1591590Srgrimes
1601590Srgrimes	if ((f = Fopen(_PATH_HELP, "r")) == NULL) {
16174769Smikeh		warn("%s", _PATH_HELP);
16277274Smikeh		return (1);
1631590Srgrimes	}
1641590Srgrimes	while ((c = getc(f)) != EOF)
1651590Srgrimes		putchar(c);
16677274Smikeh	(void)Fclose(f);
16777274Smikeh	return (0);
1681590Srgrimes}
1691590Srgrimes
1701590Srgrimes/*
1711590Srgrimes * Change user's working directory.
1721590Srgrimes */
1731590Srgrimesint
1741590Srgrimesschdir(arglist)
1751590Srgrimes	char **arglist;
1761590Srgrimes{
1771590Srgrimes	char *cp;
1781590Srgrimes
17977274Smikeh	if (*arglist == NULL) {
18077274Smikeh		if (homedir == NULL)
18177274Smikeh			return (1);
1821590Srgrimes		cp = homedir;
18374769Smikeh	} else
18477274Smikeh		if ((cp = expand(*arglist)) == NULL)
18577274Smikeh			return (1);
1861590Srgrimes	if (chdir(cp) < 0) {
18774769Smikeh		warn("%s", cp);
18877274Smikeh		return (1);
1891590Srgrimes	}
19077274Smikeh	return (0);
1911590Srgrimes}
1921590Srgrimes
1931590Srgrimesint
1941590Srgrimesrespond(msgvec)
1951590Srgrimes	int *msgvec;
1961590Srgrimes{
19777274Smikeh	if (value("Replyall") == NULL)
19832189Sjoerg		return (dorespond(msgvec));
1991590Srgrimes	else
20032189Sjoerg		return (doRespond(msgvec));
2011590Srgrimes}
2021590Srgrimes
2031590Srgrimes/*
2041590Srgrimes * Reply to a list of messages.  Extract each name from the
2051590Srgrimes * message header and send them off to mail1()
2061590Srgrimes */
2071590Srgrimesint
20832189Sjoergdorespond(msgvec)
2091590Srgrimes	int *msgvec;
2101590Srgrimes{
2111590Srgrimes	struct message *mp;
2121590Srgrimes	char *cp, *rcv, *replyto;
2131590Srgrimes	char **ap;
2141590Srgrimes	struct name *np;
2151590Srgrimes	struct header head;
2161590Srgrimes
2171590Srgrimes	if (msgvec[1] != 0) {
2181590Srgrimes		printf("Sorry, can't reply to multiple messages at once\n");
21977274Smikeh		return (1);
2201590Srgrimes	}
2211590Srgrimes	mp = &message[msgvec[0] - 1];
2221590Srgrimes	touch(mp);
2231590Srgrimes	dot = mp;
22477274Smikeh	if ((rcv = skin(hfield("from", mp))) == NULL)
2251590Srgrimes		rcv = skin(nameof(mp, 1));
22677274Smikeh	if ((replyto = skin(hfield("reply-to", mp))) != NULL)
2271590Srgrimes		np = extract(replyto, GTO);
22877274Smikeh	else if ((cp = skin(hfield("to", mp))) != NULL)
2291590Srgrimes		np = extract(cp, GTO);
2301590Srgrimes	else
23177274Smikeh		np = NULL;
2321590Srgrimes	np = elide(np);
2331590Srgrimes	/*
2341590Srgrimes	 * Delete my name from the reply list,
2351590Srgrimes	 * and with it, all my alternate names.
2361590Srgrimes	 */
2371590Srgrimes	np = delname(np, myname);
2381590Srgrimes	if (altnames)
23977274Smikeh		for (ap = altnames; *ap != NULL; ap++)
2401590Srgrimes			np = delname(np, *ap);
24177274Smikeh	if (np != NULL && replyto == NULL)
2421590Srgrimes		np = cat(np, extract(rcv, GTO));
24377274Smikeh	else if (np == NULL) {
24477274Smikeh		if (replyto != NULL)
2451590Srgrimes			printf("Empty reply-to field -- replying to author\n");
2461590Srgrimes		np = extract(rcv, GTO);
2471590Srgrimes	}
2481590Srgrimes	head.h_to = np;
24977274Smikeh	if ((head.h_subject = hfield("subject", mp)) == NULL)
2501590Srgrimes		head.h_subject = hfield("subj", mp);
2511590Srgrimes	head.h_subject = reedit(head.h_subject);
25277274Smikeh	if (replyto == NULL && (cp = skin(hfield("cc", mp))) != NULL) {
2531590Srgrimes		np = elide(extract(cp, GCC));
2541590Srgrimes		np = delname(np, myname);
2551590Srgrimes		if (altnames != 0)
25677274Smikeh			for (ap = altnames; *ap != NULL; ap++)
2571590Srgrimes				np = delname(np, *ap);
2581590Srgrimes		head.h_cc = np;
2591590Srgrimes	} else
26077274Smikeh		head.h_cc = NULL;
26177274Smikeh	head.h_bcc = NULL;
26277274Smikeh	head.h_smopts = NULL;
26378193Smikeh	head.h_replyto = value("REPLYTO");
26432189Sjoerg	head.h_inreplyto = skin(hfield("message-id", mp));
2651590Srgrimes	mail1(&head, 1);
26677274Smikeh	return (0);
2671590Srgrimes}
2681590Srgrimes
2691590Srgrimes/*
2701590Srgrimes * Modify the subject we are replying to to begin with Re: if
2711590Srgrimes * it does not already.
2721590Srgrimes */
2731590Srgrimeschar *
2741590Srgrimesreedit(subj)
27577274Smikeh	char *subj;
2761590Srgrimes{
2771590Srgrimes	char *newsubj;
2781590Srgrimes
27977274Smikeh	if (subj == NULL)
28077274Smikeh		return (NULL);
2811590Srgrimes	if ((subj[0] == 'r' || subj[0] == 'R') &&
2821590Srgrimes	    (subj[1] == 'e' || subj[1] == 'E') &&
2831590Srgrimes	    subj[2] == ':')
28477274Smikeh		return (subj);
2851590Srgrimes	newsubj = salloc(strlen(subj) + 5);
28674769Smikeh	sprintf(newsubj, "Re: %s", subj);
28777274Smikeh	return (newsubj);
2881590Srgrimes}
2891590Srgrimes
2901590Srgrimes/*
2911590Srgrimes * Preserve the named messages, so that they will be sent
2921590Srgrimes * back to the system mailbox.
2931590Srgrimes */
2941590Srgrimesint
2951590Srgrimespreserve(msgvec)
2961590Srgrimes	int *msgvec;
2971590Srgrimes{
29877274Smikeh	int *ip, mesg;
29977274Smikeh	struct message *mp;
3001590Srgrimes
3011590Srgrimes	if (edit) {
3021590Srgrimes		printf("Cannot \"preserve\" in edit mode\n");
30377274Smikeh		return (1);
3041590Srgrimes	}
30529574Sphk	for (ip = msgvec; *ip != 0; ip++) {
3061590Srgrimes		mesg = *ip;
3071590Srgrimes		mp = &message[mesg-1];
3081590Srgrimes		mp->m_flag |= MPRESERVE;
3091590Srgrimes		mp->m_flag &= ~MBOX;
3101590Srgrimes		dot = mp;
3111590Srgrimes	}
31277274Smikeh	return (0);
3131590Srgrimes}
3141590Srgrimes
3151590Srgrimes/*
3161590Srgrimes * Mark all given messages as unread.
3171590Srgrimes */
3181590Srgrimesint
3191590Srgrimesunread(msgvec)
3201590Srgrimes	int	msgvec[];
3211590Srgrimes{
32277274Smikeh	int *ip;
3231590Srgrimes
32429574Sphk	for (ip = msgvec; *ip != 0; ip++) {
3251590Srgrimes		dot = &message[*ip-1];
3261590Srgrimes		dot->m_flag &= ~(MREAD|MTOUCH);
3271590Srgrimes		dot->m_flag |= MSTATUS;
3281590Srgrimes	}
32977274Smikeh	return (0);
3301590Srgrimes}
3311590Srgrimes
3321590Srgrimes/*
3331590Srgrimes * Print the size of each message.
3341590Srgrimes */
3351590Srgrimesint
3361590Srgrimesmessize(msgvec)
3371590Srgrimes	int *msgvec;
3381590Srgrimes{
33977274Smikeh	struct message *mp;
34077274Smikeh	int *ip, mesg;
3411590Srgrimes
34229574Sphk	for (ip = msgvec; *ip != 0; ip++) {
3431590Srgrimes		mesg = *ip;
3441590Srgrimes		mp = &message[mesg-1];
34537453Sbde		printf("%d: %ld/%ld\n", mesg, mp->m_lines, mp->m_size);
3461590Srgrimes	}
34777274Smikeh	return (0);
3481590Srgrimes}
3491590Srgrimes
3501590Srgrimes/*
3511590Srgrimes * Quit quickly.  If we are sourcing, just pop the input level
3521590Srgrimes * by returning an error.
3531590Srgrimes */
3541590Srgrimesint
3551590Srgrimesrexit(e)
3561590Srgrimes	int e;
3571590Srgrimes{
3581590Srgrimes	if (sourcing)
35977274Smikeh		return (1);
36088150Smikeh	exit(0);
3611590Srgrimes	/*NOTREACHED*/
3621590Srgrimes}
3631590Srgrimes
3641590Srgrimes/*
3651590Srgrimes * Set or display a variable value.  Syntax is similar to that
3661590Srgrimes * of csh.
3671590Srgrimes */
3681590Srgrimesint
3691590Srgrimesset(arglist)
3701590Srgrimes	char **arglist;
3711590Srgrimes{
37277274Smikeh	struct var *vp;
37377274Smikeh	char *cp, *cp2;
3741590Srgrimes	char varbuf[BUFSIZ], **ap, **p;
3751590Srgrimes	int errs, h, s;
3761590Srgrimes
37777274Smikeh	if (*arglist == NULL) {
3781590Srgrimes		for (h = 0, s = 1; h < HSHSIZE; h++)
37977274Smikeh			for (vp = variables[h]; vp != NULL; vp = vp->v_link)
3801590Srgrimes				s++;
38177274Smikeh		ap = (char **)salloc(s * sizeof(*ap));
3821590Srgrimes		for (h = 0, p = ap; h < HSHSIZE; h++)
38377274Smikeh			for (vp = variables[h]; vp != NULL; vp = vp->v_link)
3841590Srgrimes				*p++ = vp->v_name;
38577274Smikeh		*p = NULL;
3861590Srgrimes		sort(ap);
38777274Smikeh		for (p = ap; *p != NULL; p++)
3881590Srgrimes			printf("%s\t%s\n", *p, value(*p));
38977274Smikeh		return (0);
3901590Srgrimes	}
3911590Srgrimes	errs = 0;
39277274Smikeh	for (ap = arglist; *ap != NULL; ap++) {
3931590Srgrimes		cp = *ap;
3941590Srgrimes		cp2 = varbuf;
39574769Smikeh		while (cp2 < varbuf + sizeof(varbuf) - 1 && *cp != '=' && *cp != '\0')
3961590Srgrimes			*cp2++ = *cp++;
3971590Srgrimes		*cp2 = '\0';
3981590Srgrimes		if (*cp == '\0')
3991590Srgrimes			cp = "";
4001590Srgrimes		else
4011590Srgrimes			cp++;
4021590Srgrimes		if (equal(varbuf, "")) {
4031590Srgrimes			printf("Non-null variable name required\n");
4041590Srgrimes			errs++;
4051590Srgrimes			continue;
4061590Srgrimes		}
4071590Srgrimes		assign(varbuf, cp);
4081590Srgrimes	}
40977274Smikeh	return (errs);
4101590Srgrimes}
4111590Srgrimes
4121590Srgrimes/*
4131590Srgrimes * Unset a bunch of variable values.
4141590Srgrimes */
4151590Srgrimesint
4161590Srgrimesunset(arglist)
4171590Srgrimes	char **arglist;
4181590Srgrimes{
41977274Smikeh	struct var *vp, *vp2;
4201590Srgrimes	int errs, h;
4211590Srgrimes	char **ap;
4221590Srgrimes
4231590Srgrimes	errs = 0;
42477274Smikeh	for (ap = arglist; *ap != NULL; ap++) {
42577274Smikeh		if ((vp2 = lookup(*ap)) == NULL) {
42688150Smikeh			if (getenv(*ap))
42788150Smikeh				unsetenv(*ap);
42888150Smikeh			else if (!sourcing) {
4291590Srgrimes				printf("\"%s\": undefined variable\n", *ap);
4301590Srgrimes				errs++;
4311590Srgrimes			}
4321590Srgrimes			continue;
4331590Srgrimes		}
4341590Srgrimes		h = hash(*ap);
4351590Srgrimes		if (vp2 == variables[h]) {
4361590Srgrimes			variables[h] = variables[h]->v_link;
4371590Srgrimes			vfree(vp2->v_name);
4381590Srgrimes			vfree(vp2->v_value);
43977274Smikeh			(void)free(vp2);
4401590Srgrimes			continue;
4411590Srgrimes		}
4421590Srgrimes		for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
4431590Srgrimes			;
4441590Srgrimes		vp->v_link = vp2->v_link;
4451590Srgrimes		vfree(vp2->v_name);
4461590Srgrimes		vfree(vp2->v_value);
44777274Smikeh		(void)free(vp2);
4481590Srgrimes	}
44977274Smikeh	return (errs);
4501590Srgrimes}
4511590Srgrimes
4521590Srgrimes/*
4531590Srgrimes * Put add users to a group.
4541590Srgrimes */
4551590Srgrimesint
4561590Srgrimesgroup(argv)
4571590Srgrimes	char **argv;
4581590Srgrimes{
45977274Smikeh	struct grouphead *gh;
46077274Smikeh	struct group *gp;
4611590Srgrimes	char **ap, *gname, **p;
46277274Smikeh	int h, s;
4631590Srgrimes
46477274Smikeh	if (*argv == NULL) {
4651590Srgrimes		for (h = 0, s = 1; h < HSHSIZE; h++)
46677274Smikeh			for (gh = groups[h]; gh != NULL; gh = gh->g_link)
4671590Srgrimes				s++;
46877274Smikeh		ap = (char **)salloc(s * sizeof(*ap));
4691590Srgrimes		for (h = 0, p = ap; h < HSHSIZE; h++)
47077274Smikeh			for (gh = groups[h]; gh != NULL; gh = gh->g_link)
4711590Srgrimes				*p++ = gh->g_name;
47277274Smikeh		*p = NULL;
4731590Srgrimes		sort(ap);
47477274Smikeh		for (p = ap; *p != NULL; p++)
4751590Srgrimes			printgroup(*p);
47677274Smikeh		return (0);
4771590Srgrimes	}
47877274Smikeh	if (argv[1] == NULL) {
4791590Srgrimes		printgroup(*argv);
48077274Smikeh		return (0);
4811590Srgrimes	}
4821590Srgrimes	gname = *argv;
4831590Srgrimes	h = hash(gname);
48477274Smikeh	if ((gh = findgroup(gname)) == NULL) {
48577274Smikeh		gh = calloc(sizeof(*gh), 1);
4861590Srgrimes		gh->g_name = vcopy(gname);
48777274Smikeh		gh->g_list = NULL;
4881590Srgrimes		gh->g_link = groups[h];
4891590Srgrimes		groups[h] = gh;
4901590Srgrimes	}
4911590Srgrimes
4921590Srgrimes	/*
4931590Srgrimes	 * Insert names from the command list into the group.
4941590Srgrimes	 * Who cares if there are duplicates?  They get tossed
4951590Srgrimes	 * later anyway.
4961590Srgrimes	 */
4971590Srgrimes
49877274Smikeh	for (ap = argv+1; *ap != NULL; ap++) {
49977274Smikeh		gp = calloc(sizeof(*gp), 1);
5001590Srgrimes		gp->ge_name = vcopy(*ap);
5011590Srgrimes		gp->ge_link = gh->g_list;
5021590Srgrimes		gh->g_list = gp;
5031590Srgrimes	}
50477274Smikeh	return (0);
5051590Srgrimes}
5061590Srgrimes
5071590Srgrimes/*
5081590Srgrimes * Sort the passed string vecotor into ascending dictionary
5091590Srgrimes * order.
5101590Srgrimes */
5111590Srgrimesvoid
5121590Srgrimessort(list)
5131590Srgrimes	char **list;
5141590Srgrimes{
51577274Smikeh	char **ap;
5161590Srgrimes
51777274Smikeh	for (ap = list; *ap != NULL; ap++)
5181590Srgrimes		;
5191590Srgrimes	if (ap-list < 2)
5201590Srgrimes		return;
5211590Srgrimes	qsort(list, ap-list, sizeof(*list), diction);
5221590Srgrimes}
5231590Srgrimes
5241590Srgrimes/*
5251590Srgrimes * Do a dictionary order comparison of the arguments from
5261590Srgrimes * qsort.
5271590Srgrimes */
5281590Srgrimesint
5291590Srgrimesdiction(a, b)
5301590Srgrimes	const void *a, *b;
5311590Srgrimes{
53277274Smikeh	return (strcmp(*(const char **)a, *(const char **)b));
5331590Srgrimes}
5341590Srgrimes
5351590Srgrimes/*
5361590Srgrimes * The do nothing command for comments.
5371590Srgrimes */
5381590Srgrimes
5391590Srgrimes/*ARGSUSED*/
5401590Srgrimesint
5411590Srgrimesnull(e)
5421590Srgrimes	int e;
5431590Srgrimes{
54477274Smikeh	return (0);
5451590Srgrimes}
5461590Srgrimes
5471590Srgrimes/*
5481590Srgrimes * Change to another file.  With no argument, print information about
5491590Srgrimes * the current file.
5501590Srgrimes */
5511590Srgrimesint
5521590Srgrimesfile(argv)
55377274Smikeh	char **argv;
5541590Srgrimes{
5551590Srgrimes
55677274Smikeh	if (argv[0] == NULL) {
55788150Smikeh		newfileinfo(0);
55877274Smikeh		return (0);
5591590Srgrimes	}
5601590Srgrimes	if (setfile(*argv) < 0)
56177274Smikeh		return (1);
5621590Srgrimes	announce();
56377274Smikeh	return (0);
5641590Srgrimes}
5651590Srgrimes
5661590Srgrimes/*
5671590Srgrimes * Expand file names like echo
5681590Srgrimes */
5691590Srgrimesint
5701590Srgrimesecho(argv)
5711590Srgrimes	char **argv;
5721590Srgrimes{
57377274Smikeh	char **ap, *cp;
5741590Srgrimes
57577274Smikeh	for (ap = argv; *ap != NULL; ap++) {
5761590Srgrimes		cp = *ap;
57777274Smikeh		if ((cp = expand(cp)) != NULL) {
5781590Srgrimes			if (ap != argv)
57977274Smikeh				printf(" ");
5801590Srgrimes			printf("%s", cp);
5811590Srgrimes		}
5821590Srgrimes	}
58377274Smikeh	printf("\n");
58477274Smikeh	return (0);
5851590Srgrimes}
5861590Srgrimes
5871590Srgrimesint
5881590SrgrimesRespond(msgvec)
5891590Srgrimes	int *msgvec;
5901590Srgrimes{
59177274Smikeh	if (value("Replyall") == NULL)
59232189Sjoerg		return (doRespond(msgvec));
5931590Srgrimes	else
59432189Sjoerg		return (dorespond(msgvec));
5951590Srgrimes}
5961590Srgrimes
5971590Srgrimes/*
5981590Srgrimes * Reply to a series of messages by simply mailing to the senders
5991590Srgrimes * and not messing around with the To: and Cc: lists as in normal
6001590Srgrimes * reply.
6011590Srgrimes */
6021590Srgrimesint
60332189SjoergdoRespond(msgvec)
6041590Srgrimes	int msgvec[];
6051590Srgrimes{
6061590Srgrimes	struct header head;
6071590Srgrimes	struct message *mp;
60877274Smikeh	int *ap;
60977274Smikeh	char *cp, *mid;
6101590Srgrimes
61177274Smikeh	head.h_to = NULL;
6121590Srgrimes	for (ap = msgvec; *ap != 0; ap++) {
6131590Srgrimes		mp = &message[*ap - 1];
6141590Srgrimes		touch(mp);
6151590Srgrimes		dot = mp;
61677274Smikeh		if ((cp = skin(hfield("from", mp))) == NULL)
6171590Srgrimes			cp = skin(nameof(mp, 2));
6181590Srgrimes		head.h_to = cat(head.h_to, extract(cp, GTO));
61932189Sjoerg		mid = skin(hfield("message-id", mp));
6201590Srgrimes	}
62177274Smikeh	if (head.h_to == NULL)
62277274Smikeh		return (0);
6231590Srgrimes	mp = &message[msgvec[0] - 1];
62477274Smikeh	if ((head.h_subject = hfield("subject", mp)) == NULL)
6251590Srgrimes		head.h_subject = hfield("subj", mp);
6261590Srgrimes	head.h_subject = reedit(head.h_subject);
62777274Smikeh	head.h_cc = NULL;
62877274Smikeh	head.h_bcc = NULL;
62977274Smikeh	head.h_smopts = NULL;
63078193Smikeh	head.h_replyto = value("REPLYTO");
63132189Sjoerg	head.h_inreplyto = mid;
6321590Srgrimes	mail1(&head, 1);
63377274Smikeh	return (0);
6341590Srgrimes}
6351590Srgrimes
6361590Srgrimes/*
6371590Srgrimes * Conditional commands.  These allow one to parameterize one's
6381590Srgrimes * .mailrc and do some things if sending, others if receiving.
6391590Srgrimes */
6401590Srgrimesint
6411590Srgrimesifcmd(argv)
6421590Srgrimes	char **argv;
6431590Srgrimes{
64477274Smikeh	char *cp;
6451590Srgrimes
6461590Srgrimes	if (cond != CANY) {
6471590Srgrimes		printf("Illegal nested \"if\"\n");
64877274Smikeh		return (1);
6491590Srgrimes	}
6501590Srgrimes	cond = CANY;
6511590Srgrimes	cp = argv[0];
6521590Srgrimes	switch (*cp) {
6531590Srgrimes	case 'r': case 'R':
6541590Srgrimes		cond = CRCV;
6551590Srgrimes		break;
6561590Srgrimes
6571590Srgrimes	case 's': case 'S':
6581590Srgrimes		cond = CSEND;
6591590Srgrimes		break;
6601590Srgrimes
6611590Srgrimes	default:
6621590Srgrimes		printf("Unrecognized if-keyword: \"%s\"\n", cp);
66377274Smikeh		return (1);
6641590Srgrimes	}
66577274Smikeh	return (0);
6661590Srgrimes}
6671590Srgrimes
6681590Srgrimes/*
6691590Srgrimes * Implement 'else'.  This is pretty simple -- we just
6701590Srgrimes * flip over the conditional flag.
6711590Srgrimes */
6721590Srgrimesint
6731590Srgrimeselsecmd()
6741590Srgrimes{
6751590Srgrimes
6761590Srgrimes	switch (cond) {
6771590Srgrimes	case CANY:
6781590Srgrimes		printf("\"Else\" without matching \"if\"\n");
67977274Smikeh		return (1);
6801590Srgrimes
6811590Srgrimes	case CSEND:
6821590Srgrimes		cond = CRCV;
6831590Srgrimes		break;
6841590Srgrimes
6851590Srgrimes	case CRCV:
6861590Srgrimes		cond = CSEND;
6871590Srgrimes		break;
6881590Srgrimes
6891590Srgrimes	default:
6901590Srgrimes		printf("Mail's idea of conditions is screwed up\n");
6911590Srgrimes		cond = CANY;
6921590Srgrimes		break;
6931590Srgrimes	}
69477274Smikeh	return (0);
6951590Srgrimes}
6961590Srgrimes
6971590Srgrimes/*
6981590Srgrimes * End of if statement.  Just set cond back to anything.
6991590Srgrimes */
7001590Srgrimesint
7011590Srgrimesendifcmd()
7021590Srgrimes{
7031590Srgrimes
7041590Srgrimes	if (cond == CANY) {
7051590Srgrimes		printf("\"Endif\" without matching \"if\"\n");
70677274Smikeh		return (1);
7071590Srgrimes	}
7081590Srgrimes	cond = CANY;
70977274Smikeh	return (0);
7101590Srgrimes}
7111590Srgrimes
7121590Srgrimes/*
7131590Srgrimes * Set the list of alternate names.
7141590Srgrimes */
7151590Srgrimesint
7161590Srgrimesalternates(namelist)
7171590Srgrimes	char **namelist;
7181590Srgrimes{
71977274Smikeh	int c;
72077274Smikeh	char **ap, **ap2, *cp;
7211590Srgrimes
7221590Srgrimes	c = argcount(namelist) + 1;
7231590Srgrimes	if (c == 1) {
7241590Srgrimes		if (altnames == 0)
72577274Smikeh			return (0);
72677274Smikeh		for (ap = altnames; *ap != NULL; ap++)
7271590Srgrimes			printf("%s ", *ap);
7281590Srgrimes		printf("\n");
72977274Smikeh		return (0);
7301590Srgrimes	}
7311590Srgrimes	if (altnames != 0)
73277274Smikeh		(void)free(altnames);
73377274Smikeh	altnames = calloc((unsigned)c, sizeof(char *));
73477274Smikeh	for (ap = namelist, ap2 = altnames; *ap != NULL; ap++, ap2++) {
73577274Smikeh		cp = calloc((unsigned)strlen(*ap) + 1, sizeof(char));
7361590Srgrimes		strcpy(cp, *ap);
7371590Srgrimes		*ap2 = cp;
7381590Srgrimes	}
7391590Srgrimes	*ap2 = 0;
74077274Smikeh	return (0);
7411590Srgrimes}
742