cmd3.c revision 77274
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
361590Srgrimesstatic char sccsid[] = "@(#)cmd3.c	8.1 (Berkeley) 6/6/93";
3774769Smikeh#endif
3874769Smikehstatic const char rcsid[] =
3974769Smikeh  "$FreeBSD: head/usr.bin/mail/cmd3.c 77274 2001-05-27 20:26:22Z 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;
26332189Sjoerg	if ((head.h_replyto = getenv("REPLYTO")) == NULL)
26477274Smikeh		head.h_replyto = NULL;
26532189Sjoerg	head.h_inreplyto = skin(hfield("message-id", mp));
2661590Srgrimes	mail1(&head, 1);
26777274Smikeh	return (0);
2681590Srgrimes}
2691590Srgrimes
2701590Srgrimes/*
2711590Srgrimes * Modify the subject we are replying to to begin with Re: if
2721590Srgrimes * it does not already.
2731590Srgrimes */
2741590Srgrimeschar *
2751590Srgrimesreedit(subj)
27677274Smikeh	char *subj;
2771590Srgrimes{
2781590Srgrimes	char *newsubj;
2791590Srgrimes
28077274Smikeh	if (subj == NULL)
28177274Smikeh		return (NULL);
2821590Srgrimes	if ((subj[0] == 'r' || subj[0] == 'R') &&
2831590Srgrimes	    (subj[1] == 'e' || subj[1] == 'E') &&
2841590Srgrimes	    subj[2] == ':')
28577274Smikeh		return (subj);
2861590Srgrimes	newsubj = salloc(strlen(subj) + 5);
28774769Smikeh	sprintf(newsubj, "Re: %s", subj);
28877274Smikeh	return (newsubj);
2891590Srgrimes}
2901590Srgrimes
2911590Srgrimes/*
2921590Srgrimes * Preserve the named messages, so that they will be sent
2931590Srgrimes * back to the system mailbox.
2941590Srgrimes */
2951590Srgrimesint
2961590Srgrimespreserve(msgvec)
2971590Srgrimes	int *msgvec;
2981590Srgrimes{
29977274Smikeh	int *ip, mesg;
30077274Smikeh	struct message *mp;
3011590Srgrimes
3021590Srgrimes	if (edit) {
3031590Srgrimes		printf("Cannot \"preserve\" in edit mode\n");
30477274Smikeh		return (1);
3051590Srgrimes	}
30629574Sphk	for (ip = msgvec; *ip != 0; ip++) {
3071590Srgrimes		mesg = *ip;
3081590Srgrimes		mp = &message[mesg-1];
3091590Srgrimes		mp->m_flag |= MPRESERVE;
3101590Srgrimes		mp->m_flag &= ~MBOX;
3111590Srgrimes		dot = mp;
3121590Srgrimes	}
31377274Smikeh	return (0);
3141590Srgrimes}
3151590Srgrimes
3161590Srgrimes/*
3171590Srgrimes * Mark all given messages as unread.
3181590Srgrimes */
3191590Srgrimesint
3201590Srgrimesunread(msgvec)
3211590Srgrimes	int	msgvec[];
3221590Srgrimes{
32377274Smikeh	int *ip;
3241590Srgrimes
32529574Sphk	for (ip = msgvec; *ip != 0; ip++) {
3261590Srgrimes		dot = &message[*ip-1];
3271590Srgrimes		dot->m_flag &= ~(MREAD|MTOUCH);
3281590Srgrimes		dot->m_flag |= MSTATUS;
3291590Srgrimes	}
33077274Smikeh	return (0);
3311590Srgrimes}
3321590Srgrimes
3331590Srgrimes/*
3341590Srgrimes * Print the size of each message.
3351590Srgrimes */
3361590Srgrimesint
3371590Srgrimesmessize(msgvec)
3381590Srgrimes	int *msgvec;
3391590Srgrimes{
34077274Smikeh	struct message *mp;
34177274Smikeh	int *ip, mesg;
3421590Srgrimes
34329574Sphk	for (ip = msgvec; *ip != 0; ip++) {
3441590Srgrimes		mesg = *ip;
3451590Srgrimes		mp = &message[mesg-1];
34637453Sbde		printf("%d: %ld/%ld\n", mesg, mp->m_lines, mp->m_size);
3471590Srgrimes	}
34877274Smikeh	return (0);
3491590Srgrimes}
3501590Srgrimes
3511590Srgrimes/*
3521590Srgrimes * Quit quickly.  If we are sourcing, just pop the input level
3531590Srgrimes * by returning an error.
3541590Srgrimes */
3551590Srgrimesint
3561590Srgrimesrexit(e)
3571590Srgrimes	int e;
3581590Srgrimes{
3591590Srgrimes	if (sourcing)
36077274Smikeh		return (1);
3611590Srgrimes	exit(e);
3621590Srgrimes	/*NOTREACHED*/
3631590Srgrimes}
3641590Srgrimes
3651590Srgrimes/*
3661590Srgrimes * Set or display a variable value.  Syntax is similar to that
3671590Srgrimes * of csh.
3681590Srgrimes */
3691590Srgrimesint
3701590Srgrimesset(arglist)
3711590Srgrimes	char **arglist;
3721590Srgrimes{
37377274Smikeh	struct var *vp;
37477274Smikeh	char *cp, *cp2;
3751590Srgrimes	char varbuf[BUFSIZ], **ap, **p;
3761590Srgrimes	int errs, h, s;
3771590Srgrimes
37877274Smikeh	if (*arglist == NULL) {
3791590Srgrimes		for (h = 0, s = 1; h < HSHSIZE; h++)
38077274Smikeh			for (vp = variables[h]; vp != NULL; vp = vp->v_link)
3811590Srgrimes				s++;
38277274Smikeh		ap = (char **)salloc(s * sizeof(*ap));
3831590Srgrimes		for (h = 0, p = ap; h < HSHSIZE; h++)
38477274Smikeh			for (vp = variables[h]; vp != NULL; vp = vp->v_link)
3851590Srgrimes				*p++ = vp->v_name;
38677274Smikeh		*p = NULL;
3871590Srgrimes		sort(ap);
38877274Smikeh		for (p = ap; *p != NULL; p++)
3891590Srgrimes			printf("%s\t%s\n", *p, value(*p));
39077274Smikeh		return (0);
3911590Srgrimes	}
3921590Srgrimes	errs = 0;
39377274Smikeh	for (ap = arglist; *ap != NULL; ap++) {
3941590Srgrimes		cp = *ap;
3951590Srgrimes		cp2 = varbuf;
39674769Smikeh		while (cp2 < varbuf + sizeof(varbuf) - 1 && *cp != '=' && *cp != '\0')
3971590Srgrimes			*cp2++ = *cp++;
3981590Srgrimes		*cp2 = '\0';
3991590Srgrimes		if (*cp == '\0')
4001590Srgrimes			cp = "";
4011590Srgrimes		else
4021590Srgrimes			cp++;
4031590Srgrimes		if (equal(varbuf, "")) {
4041590Srgrimes			printf("Non-null variable name required\n");
4051590Srgrimes			errs++;
4061590Srgrimes			continue;
4071590Srgrimes		}
4081590Srgrimes		assign(varbuf, cp);
4091590Srgrimes	}
41077274Smikeh	return (errs);
4111590Srgrimes}
4121590Srgrimes
4131590Srgrimes/*
4141590Srgrimes * Unset a bunch of variable values.
4151590Srgrimes */
4161590Srgrimesint
4171590Srgrimesunset(arglist)
4181590Srgrimes	char **arglist;
4191590Srgrimes{
42077274Smikeh	struct var *vp, *vp2;
4211590Srgrimes	int errs, h;
4221590Srgrimes	char **ap;
4231590Srgrimes
4241590Srgrimes	errs = 0;
42577274Smikeh	for (ap = arglist; *ap != NULL; ap++) {
42677274Smikeh		if ((vp2 = lookup(*ap)) == NULL) {
4271590Srgrimes			if (!sourcing) {
4281590Srgrimes				printf("\"%s\": undefined variable\n", *ap);
4291590Srgrimes				errs++;
4301590Srgrimes			}
4311590Srgrimes			continue;
4321590Srgrimes		}
4331590Srgrimes		h = hash(*ap);
4341590Srgrimes		if (vp2 == variables[h]) {
4351590Srgrimes			variables[h] = variables[h]->v_link;
4361590Srgrimes			vfree(vp2->v_name);
4371590Srgrimes			vfree(vp2->v_value);
43877274Smikeh			(void)free(vp2);
4391590Srgrimes			continue;
4401590Srgrimes		}
4411590Srgrimes		for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
4421590Srgrimes			;
4431590Srgrimes		vp->v_link = vp2->v_link;
4441590Srgrimes		vfree(vp2->v_name);
4451590Srgrimes		vfree(vp2->v_value);
44677274Smikeh		(void)free(vp2);
4471590Srgrimes	}
44877274Smikeh	return (errs);
4491590Srgrimes}
4501590Srgrimes
4511590Srgrimes/*
4521590Srgrimes * Put add users to a group.
4531590Srgrimes */
4541590Srgrimesint
4551590Srgrimesgroup(argv)
4561590Srgrimes	char **argv;
4571590Srgrimes{
45877274Smikeh	struct grouphead *gh;
45977274Smikeh	struct group *gp;
4601590Srgrimes	char **ap, *gname, **p;
46177274Smikeh	int h, s;
4621590Srgrimes
46377274Smikeh	if (*argv == NULL) {
4641590Srgrimes		for (h = 0, s = 1; h < HSHSIZE; h++)
46577274Smikeh			for (gh = groups[h]; gh != NULL; gh = gh->g_link)
4661590Srgrimes				s++;
46777274Smikeh		ap = (char **)salloc(s * sizeof(*ap));
4681590Srgrimes		for (h = 0, p = ap; h < HSHSIZE; h++)
46977274Smikeh			for (gh = groups[h]; gh != NULL; gh = gh->g_link)
4701590Srgrimes				*p++ = gh->g_name;
47177274Smikeh		*p = NULL;
4721590Srgrimes		sort(ap);
47377274Smikeh		for (p = ap; *p != NULL; p++)
4741590Srgrimes			printgroup(*p);
47577274Smikeh		return (0);
4761590Srgrimes	}
47777274Smikeh	if (argv[1] == NULL) {
4781590Srgrimes		printgroup(*argv);
47977274Smikeh		return (0);
4801590Srgrimes	}
4811590Srgrimes	gname = *argv;
4821590Srgrimes	h = hash(gname);
48377274Smikeh	if ((gh = findgroup(gname)) == NULL) {
48477274Smikeh		gh = calloc(sizeof(*gh), 1);
4851590Srgrimes		gh->g_name = vcopy(gname);
48677274Smikeh		gh->g_list = NULL;
4871590Srgrimes		gh->g_link = groups[h];
4881590Srgrimes		groups[h] = gh;
4891590Srgrimes	}
4901590Srgrimes
4911590Srgrimes	/*
4921590Srgrimes	 * Insert names from the command list into the group.
4931590Srgrimes	 * Who cares if there are duplicates?  They get tossed
4941590Srgrimes	 * later anyway.
4951590Srgrimes	 */
4961590Srgrimes
49777274Smikeh	for (ap = argv+1; *ap != NULL; ap++) {
49877274Smikeh		gp = calloc(sizeof(*gp), 1);
4991590Srgrimes		gp->ge_name = vcopy(*ap);
5001590Srgrimes		gp->ge_link = gh->g_list;
5011590Srgrimes		gh->g_list = gp;
5021590Srgrimes	}
50377274Smikeh	return (0);
5041590Srgrimes}
5051590Srgrimes
5061590Srgrimes/*
5071590Srgrimes * Sort the passed string vecotor into ascending dictionary
5081590Srgrimes * order.
5091590Srgrimes */
5101590Srgrimesvoid
5111590Srgrimessort(list)
5121590Srgrimes	char **list;
5131590Srgrimes{
51477274Smikeh	char **ap;
5151590Srgrimes
51677274Smikeh	for (ap = list; *ap != NULL; ap++)
5171590Srgrimes		;
5181590Srgrimes	if (ap-list < 2)
5191590Srgrimes		return;
5201590Srgrimes	qsort(list, ap-list, sizeof(*list), diction);
5211590Srgrimes}
5221590Srgrimes
5231590Srgrimes/*
5241590Srgrimes * Do a dictionary order comparison of the arguments from
5251590Srgrimes * qsort.
5261590Srgrimes */
5271590Srgrimesint
5281590Srgrimesdiction(a, b)
5291590Srgrimes	const void *a, *b;
5301590Srgrimes{
53177274Smikeh	return (strcmp(*(const char **)a, *(const char **)b));
5321590Srgrimes}
5331590Srgrimes
5341590Srgrimes/*
5351590Srgrimes * The do nothing command for comments.
5361590Srgrimes */
5371590Srgrimes
5381590Srgrimes/*ARGSUSED*/
5391590Srgrimesint
5401590Srgrimesnull(e)
5411590Srgrimes	int e;
5421590Srgrimes{
54377274Smikeh	return (0);
5441590Srgrimes}
5451590Srgrimes
5461590Srgrimes/*
5471590Srgrimes * Change to another file.  With no argument, print information about
5481590Srgrimes * the current file.
5491590Srgrimes */
5501590Srgrimesint
5511590Srgrimesfile(argv)
55277274Smikeh	char **argv;
5531590Srgrimes{
5541590Srgrimes
55577274Smikeh	if (argv[0] == NULL) {
5561590Srgrimes		newfileinfo();
55777274Smikeh		return (0);
5581590Srgrimes	}
5591590Srgrimes	if (setfile(*argv) < 0)
56077274Smikeh		return (1);
5611590Srgrimes	announce();
56277274Smikeh	return (0);
5631590Srgrimes}
5641590Srgrimes
5651590Srgrimes/*
5661590Srgrimes * Expand file names like echo
5671590Srgrimes */
5681590Srgrimesint
5691590Srgrimesecho(argv)
5701590Srgrimes	char **argv;
5711590Srgrimes{
57277274Smikeh	char **ap, *cp;
5731590Srgrimes
57477274Smikeh	for (ap = argv; *ap != NULL; ap++) {
5751590Srgrimes		cp = *ap;
57677274Smikeh		if ((cp = expand(cp)) != NULL) {
5771590Srgrimes			if (ap != argv)
57877274Smikeh				printf(" ");
5791590Srgrimes			printf("%s", cp);
5801590Srgrimes		}
5811590Srgrimes	}
58277274Smikeh	printf("\n");
58377274Smikeh	return (0);
5841590Srgrimes}
5851590Srgrimes
5861590Srgrimesint
5871590SrgrimesRespond(msgvec)
5881590Srgrimes	int *msgvec;
5891590Srgrimes{
59077274Smikeh	if (value("Replyall") == NULL)
59132189Sjoerg		return (doRespond(msgvec));
5921590Srgrimes	else
59332189Sjoerg		return (dorespond(msgvec));
5941590Srgrimes}
5951590Srgrimes
5961590Srgrimes/*
5971590Srgrimes * Reply to a series of messages by simply mailing to the senders
5981590Srgrimes * and not messing around with the To: and Cc: lists as in normal
5991590Srgrimes * reply.
6001590Srgrimes */
6011590Srgrimesint
60232189SjoergdoRespond(msgvec)
6031590Srgrimes	int msgvec[];
6041590Srgrimes{
6051590Srgrimes	struct header head;
6061590Srgrimes	struct message *mp;
60777274Smikeh	int *ap;
60877274Smikeh	char *cp, *mid;
6091590Srgrimes
61077274Smikeh	head.h_to = NULL;
6111590Srgrimes	for (ap = msgvec; *ap != 0; ap++) {
6121590Srgrimes		mp = &message[*ap - 1];
6131590Srgrimes		touch(mp);
6141590Srgrimes		dot = mp;
61577274Smikeh		if ((cp = skin(hfield("from", mp))) == NULL)
6161590Srgrimes			cp = skin(nameof(mp, 2));
6171590Srgrimes		head.h_to = cat(head.h_to, extract(cp, GTO));
61832189Sjoerg		mid = skin(hfield("message-id", mp));
6191590Srgrimes	}
62077274Smikeh	if (head.h_to == NULL)
62177274Smikeh		return (0);
6221590Srgrimes	mp = &message[msgvec[0] - 1];
62377274Smikeh	if ((head.h_subject = hfield("subject", mp)) == NULL)
6241590Srgrimes		head.h_subject = hfield("subj", mp);
6251590Srgrimes	head.h_subject = reedit(head.h_subject);
62677274Smikeh	head.h_cc = NULL;
62777274Smikeh	head.h_bcc = NULL;
62877274Smikeh	head.h_smopts = NULL;
62932189Sjoerg	if ((head.h_replyto = getenv("REPLYTO")) == NULL)
63077274Smikeh		head.h_replyto = NULL;
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