cmd3.c revision 32189
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
351590Srgrimesstatic char sccsid[] = "@(#)cmd3.c	8.1 (Berkeley) 6/6/93";
361590Srgrimes#endif /* not lint */
371590Srgrimes
381590Srgrimes#include "rcv.h"
391590Srgrimes#include "extern.h"
401590Srgrimes
411590Srgrimes/*
421590Srgrimes * Mail -- a mail program
431590Srgrimes *
441590Srgrimes * Still more user commands.
451590Srgrimes */
461590Srgrimes
471590Srgrimes/*
481590Srgrimes * Process a shell escape by saving signals, ignoring signals,
491590Srgrimes * and forking a sh -c
501590Srgrimes */
511590Srgrimesint
521590Srgrimesshell(str)
531590Srgrimes	char *str;
541590Srgrimes{
551590Srgrimes	sig_t sigint = signal(SIGINT, SIG_IGN);
561590Srgrimes	char *shell;
571590Srgrimes	char cmd[BUFSIZ];
581590Srgrimes
591590Srgrimes	(void) strcpy(cmd, str);
601590Srgrimes	if (bangexp(cmd) < 0)
611590Srgrimes		return 1;
621590Srgrimes	if ((shell = value("SHELL")) == NOSTR)
631590Srgrimes		shell = _PATH_CSHELL;
641590Srgrimes	(void) run_command(shell, 0, -1, -1, "-c", cmd, NOSTR);
651590Srgrimes	(void) signal(SIGINT, sigint);
661590Srgrimes	printf("!\n");
671590Srgrimes	return 0;
681590Srgrimes}
691590Srgrimes
701590Srgrimes/*
711590Srgrimes * Fork an interactive shell.
721590Srgrimes */
731590Srgrimes/*ARGSUSED*/
741590Srgrimesint
751590Srgrimesdosh(str)
761590Srgrimes	char *str;
771590Srgrimes{
781590Srgrimes	sig_t sigint = signal(SIGINT, SIG_IGN);
791590Srgrimes	char *shell;
801590Srgrimes
811590Srgrimes	if ((shell = value("SHELL")) == NOSTR)
821590Srgrimes		shell = _PATH_CSHELL;
831590Srgrimes	(void) run_command(shell, 0, -1, -1, NOSTR, NOSTR, NOSTR);
841590Srgrimes	(void) signal(SIGINT, sigint);
851590Srgrimes	putchar('\n');
861590Srgrimes	return 0;
871590Srgrimes}
881590Srgrimes
891590Srgrimes/*
901590Srgrimes * Expand the shell escape by expanding unescaped !'s into the
911590Srgrimes * last issued command where possible.
921590Srgrimes */
931590Srgrimes
941590Srgrimeschar	lastbang[128];
951590Srgrimes
961590Srgrimesint
971590Srgrimesbangexp(str)
981590Srgrimes	char *str;
991590Srgrimes{
1001590Srgrimes	char bangbuf[BUFSIZ];
1011590Srgrimes	register char *cp, *cp2;
1021590Srgrimes	register int n;
1031590Srgrimes	int changed = 0;
1041590Srgrimes
1051590Srgrimes	cp = str;
1061590Srgrimes	cp2 = bangbuf;
1071590Srgrimes	n = BUFSIZ;
1081590Srgrimes	while (*cp) {
1091590Srgrimes		if (*cp == '!') {
1101590Srgrimes			if (n < strlen(lastbang)) {
1111590Srgrimesoverf:
1121590Srgrimes				printf("Command buffer overflow\n");
1131590Srgrimes				return(-1);
1141590Srgrimes			}
1151590Srgrimes			changed++;
1161590Srgrimes			strcpy(cp2, lastbang);
1171590Srgrimes			cp2 += strlen(lastbang);
1181590Srgrimes			n -= strlen(lastbang);
1191590Srgrimes			cp++;
1201590Srgrimes			continue;
1211590Srgrimes		}
1221590Srgrimes		if (*cp == '\\' && cp[1] == '!') {
1231590Srgrimes			if (--n <= 1)
1241590Srgrimes				goto overf;
1251590Srgrimes			*cp2++ = '!';
1261590Srgrimes			cp += 2;
1271590Srgrimes			changed++;
1281590Srgrimes		}
1291590Srgrimes		if (--n <= 1)
1301590Srgrimes			goto overf;
1311590Srgrimes		*cp2++ = *cp++;
1321590Srgrimes	}
1331590Srgrimes	*cp2 = 0;
1341590Srgrimes	if (changed) {
1351590Srgrimes		printf("!%s\n", bangbuf);
1361590Srgrimes		fflush(stdout);
1371590Srgrimes	}
1381590Srgrimes	strcpy(str, bangbuf);
1391590Srgrimes	strncpy(lastbang, bangbuf, 128);
1401590Srgrimes	lastbang[127] = 0;
1411590Srgrimes	return(0);
1421590Srgrimes}
1431590Srgrimes
1441590Srgrimes/*
1451590Srgrimes * Print out a nice help message from some file or another.
1461590Srgrimes */
1471590Srgrimes
1481590Srgrimesint
1491590Srgrimeshelp()
1501590Srgrimes{
1511590Srgrimes	register c;
1521590Srgrimes	register FILE *f;
1531590Srgrimes
1541590Srgrimes	if ((f = Fopen(_PATH_HELP, "r")) == NULL) {
1551590Srgrimes		perror(_PATH_HELP);
1561590Srgrimes		return(1);
1571590Srgrimes	}
1581590Srgrimes	while ((c = getc(f)) != EOF)
1591590Srgrimes		putchar(c);
1601590Srgrimes	Fclose(f);
1611590Srgrimes	return(0);
1621590Srgrimes}
1631590Srgrimes
1641590Srgrimes/*
1651590Srgrimes * Change user's working directory.
1661590Srgrimes */
1671590Srgrimesint
1681590Srgrimesschdir(arglist)
1691590Srgrimes	char **arglist;
1701590Srgrimes{
1711590Srgrimes	char *cp;
1721590Srgrimes
1731590Srgrimes	if (*arglist == NOSTR)
1741590Srgrimes		cp = homedir;
1751590Srgrimes	else
1761590Srgrimes		if ((cp = expand(*arglist)) == NOSTR)
1771590Srgrimes			return(1);
1781590Srgrimes	if (chdir(cp) < 0) {
1791590Srgrimes		perror(cp);
1801590Srgrimes		return(1);
1811590Srgrimes	}
1821590Srgrimes	return 0;
1831590Srgrimes}
1841590Srgrimes
1851590Srgrimesint
1861590Srgrimesrespond(msgvec)
1871590Srgrimes	int *msgvec;
1881590Srgrimes{
1891590Srgrimes	if (value("Replyall") == NOSTR)
19032189Sjoerg		return (dorespond(msgvec));
1911590Srgrimes	else
19232189Sjoerg		return (doRespond(msgvec));
1931590Srgrimes}
1941590Srgrimes
1951590Srgrimes/*
1961590Srgrimes * Reply to a list of messages.  Extract each name from the
1971590Srgrimes * message header and send them off to mail1()
1981590Srgrimes */
1991590Srgrimesint
20032189Sjoergdorespond(msgvec)
2011590Srgrimes	int *msgvec;
2021590Srgrimes{
2031590Srgrimes	struct message *mp;
2041590Srgrimes	char *cp, *rcv, *replyto;
2051590Srgrimes	char **ap;
2061590Srgrimes	struct name *np;
2071590Srgrimes	struct header head;
2081590Srgrimes
2091590Srgrimes	if (msgvec[1] != 0) {
2101590Srgrimes		printf("Sorry, can't reply to multiple messages at once\n");
2111590Srgrimes		return(1);
2121590Srgrimes	}
2131590Srgrimes	mp = &message[msgvec[0] - 1];
2141590Srgrimes	touch(mp);
2151590Srgrimes	dot = mp;
2161590Srgrimes	if ((rcv = skin(hfield("from", mp))) == NOSTR)
2171590Srgrimes		rcv = skin(nameof(mp, 1));
2181590Srgrimes	if ((replyto = skin(hfield("reply-to", mp))) != NOSTR)
2191590Srgrimes		np = extract(replyto, GTO);
2201590Srgrimes	else if ((cp = skin(hfield("to", mp))) != NOSTR)
2211590Srgrimes		np = extract(cp, GTO);
2221590Srgrimes	else
2231590Srgrimes		np = NIL;
2241590Srgrimes	np = elide(np);
2251590Srgrimes	/*
2261590Srgrimes	 * Delete my name from the reply list,
2271590Srgrimes	 * and with it, all my alternate names.
2281590Srgrimes	 */
2291590Srgrimes	np = delname(np, myname);
2301590Srgrimes	if (altnames)
2311590Srgrimes		for (ap = altnames; *ap; ap++)
2321590Srgrimes			np = delname(np, *ap);
2331590Srgrimes	if (np != NIL && replyto == NOSTR)
2341590Srgrimes		np = cat(np, extract(rcv, GTO));
2351590Srgrimes	else if (np == NIL) {
2361590Srgrimes		if (replyto != NOSTR)
2371590Srgrimes			printf("Empty reply-to field -- replying to author\n");
2381590Srgrimes		np = extract(rcv, GTO);
2391590Srgrimes	}
2401590Srgrimes	head.h_to = np;
2411590Srgrimes	if ((head.h_subject = hfield("subject", mp)) == NOSTR)
2421590Srgrimes		head.h_subject = hfield("subj", mp);
2431590Srgrimes	head.h_subject = reedit(head.h_subject);
2441590Srgrimes	if (replyto == NOSTR && (cp = skin(hfield("cc", mp))) != NOSTR) {
2451590Srgrimes		np = elide(extract(cp, GCC));
2461590Srgrimes		np = delname(np, myname);
2471590Srgrimes		if (altnames != 0)
2481590Srgrimes			for (ap = altnames; *ap; ap++)
2491590Srgrimes				np = delname(np, *ap);
2501590Srgrimes		head.h_cc = np;
2511590Srgrimes	} else
2521590Srgrimes		head.h_cc = NIL;
2531590Srgrimes	head.h_bcc = NIL;
2541590Srgrimes	head.h_smopts = NIL;
25532189Sjoerg	if ((head.h_replyto = getenv("REPLYTO")) == NULL)
25632189Sjoerg		head.h_replyto = NOSTR;
25732189Sjoerg	head.h_inreplyto = skin(hfield("message-id", mp));
2581590Srgrimes	mail1(&head, 1);
2591590Srgrimes	return(0);
2601590Srgrimes}
2611590Srgrimes
2621590Srgrimes/*
2631590Srgrimes * Modify the subject we are replying to to begin with Re: if
2641590Srgrimes * it does not already.
2651590Srgrimes */
2661590Srgrimeschar *
2671590Srgrimesreedit(subj)
2681590Srgrimes	register char *subj;
2691590Srgrimes{
2701590Srgrimes	char *newsubj;
2711590Srgrimes
2721590Srgrimes	if (subj == NOSTR)
2731590Srgrimes		return NOSTR;
2741590Srgrimes	if ((subj[0] == 'r' || subj[0] == 'R') &&
2751590Srgrimes	    (subj[1] == 'e' || subj[1] == 'E') &&
2761590Srgrimes	    subj[2] == ':')
2771590Srgrimes		return subj;
2781590Srgrimes	newsubj = salloc(strlen(subj) + 5);
2791590Srgrimes	strcpy(newsubj, "Re: ");
2801590Srgrimes	strcpy(newsubj + 4, subj);
2811590Srgrimes	return newsubj;
2821590Srgrimes}
2831590Srgrimes
2841590Srgrimes/*
2851590Srgrimes * Preserve the named messages, so that they will be sent
2861590Srgrimes * back to the system mailbox.
2871590Srgrimes */
2881590Srgrimesint
2891590Srgrimespreserve(msgvec)
2901590Srgrimes	int *msgvec;
2911590Srgrimes{
2921590Srgrimes	register struct message *mp;
2931590Srgrimes	register int *ip, mesg;
2941590Srgrimes
2951590Srgrimes	if (edit) {
2961590Srgrimes		printf("Cannot \"preserve\" in edit mode\n");
2971590Srgrimes		return(1);
2981590Srgrimes	}
29929574Sphk	for (ip = msgvec; *ip != 0; ip++) {
3001590Srgrimes		mesg = *ip;
3011590Srgrimes		mp = &message[mesg-1];
3021590Srgrimes		mp->m_flag |= MPRESERVE;
3031590Srgrimes		mp->m_flag &= ~MBOX;
3041590Srgrimes		dot = mp;
3051590Srgrimes	}
3061590Srgrimes	return(0);
3071590Srgrimes}
3081590Srgrimes
3091590Srgrimes/*
3101590Srgrimes * Mark all given messages as unread.
3111590Srgrimes */
3121590Srgrimesint
3131590Srgrimesunread(msgvec)
3141590Srgrimes	int	msgvec[];
3151590Srgrimes{
3161590Srgrimes	register int *ip;
3171590Srgrimes
31829574Sphk	for (ip = msgvec; *ip != 0; ip++) {
3191590Srgrimes		dot = &message[*ip-1];
3201590Srgrimes		dot->m_flag &= ~(MREAD|MTOUCH);
3211590Srgrimes		dot->m_flag |= MSTATUS;
3221590Srgrimes	}
3231590Srgrimes	return(0);
3241590Srgrimes}
3251590Srgrimes
3261590Srgrimes/*
3271590Srgrimes * Print the size of each message.
3281590Srgrimes */
3291590Srgrimesint
3301590Srgrimesmessize(msgvec)
3311590Srgrimes	int *msgvec;
3321590Srgrimes{
3331590Srgrimes	register struct message *mp;
3341590Srgrimes	register int *ip, mesg;
3351590Srgrimes
33629574Sphk	for (ip = msgvec; *ip != 0; ip++) {
3371590Srgrimes		mesg = *ip;
3381590Srgrimes		mp = &message[mesg-1];
3391590Srgrimes		printf("%d: %d/%ld\n", mesg, mp->m_lines, mp->m_size);
3401590Srgrimes	}
3411590Srgrimes	return(0);
3421590Srgrimes}
3431590Srgrimes
3441590Srgrimes/*
3451590Srgrimes * Quit quickly.  If we are sourcing, just pop the input level
3461590Srgrimes * by returning an error.
3471590Srgrimes */
3481590Srgrimesint
3491590Srgrimesrexit(e)
3501590Srgrimes	int e;
3511590Srgrimes{
3521590Srgrimes	if (sourcing)
3531590Srgrimes		return(1);
3541590Srgrimes	exit(e);
3551590Srgrimes	/*NOTREACHED*/
3561590Srgrimes}
3571590Srgrimes
3581590Srgrimes/*
3591590Srgrimes * Set or display a variable value.  Syntax is similar to that
3601590Srgrimes * of csh.
3611590Srgrimes */
3621590Srgrimesint
3631590Srgrimesset(arglist)
3641590Srgrimes	char **arglist;
3651590Srgrimes{
3661590Srgrimes	register struct var *vp;
3671590Srgrimes	register char *cp, *cp2;
3681590Srgrimes	char varbuf[BUFSIZ], **ap, **p;
3691590Srgrimes	int errs, h, s;
3701590Srgrimes
3711590Srgrimes	if (*arglist == NOSTR) {
3721590Srgrimes		for (h = 0, s = 1; h < HSHSIZE; h++)
3731590Srgrimes			for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
3741590Srgrimes				s++;
3751590Srgrimes		ap = (char **) salloc(s * sizeof *ap);
3761590Srgrimes		for (h = 0, p = ap; h < HSHSIZE; h++)
3771590Srgrimes			for (vp = variables[h]; vp != NOVAR; vp = vp->v_link)
3781590Srgrimes				*p++ = vp->v_name;
3791590Srgrimes		*p = NOSTR;
3801590Srgrimes		sort(ap);
3811590Srgrimes		for (p = ap; *p != NOSTR; p++)
3821590Srgrimes			printf("%s\t%s\n", *p, value(*p));
3831590Srgrimes		return(0);
3841590Srgrimes	}
3851590Srgrimes	errs = 0;
3861590Srgrimes	for (ap = arglist; *ap != NOSTR; ap++) {
3871590Srgrimes		cp = *ap;
3881590Srgrimes		cp2 = varbuf;
3891590Srgrimes		while (*cp != '=' && *cp != '\0')
3901590Srgrimes			*cp2++ = *cp++;
3911590Srgrimes		*cp2 = '\0';
3921590Srgrimes		if (*cp == '\0')
3931590Srgrimes			cp = "";
3941590Srgrimes		else
3951590Srgrimes			cp++;
3961590Srgrimes		if (equal(varbuf, "")) {
3971590Srgrimes			printf("Non-null variable name required\n");
3981590Srgrimes			errs++;
3991590Srgrimes			continue;
4001590Srgrimes		}
4011590Srgrimes		assign(varbuf, cp);
4021590Srgrimes	}
4031590Srgrimes	return(errs);
4041590Srgrimes}
4051590Srgrimes
4061590Srgrimes/*
4071590Srgrimes * Unset a bunch of variable values.
4081590Srgrimes */
4091590Srgrimesint
4101590Srgrimesunset(arglist)
4111590Srgrimes	char **arglist;
4121590Srgrimes{
4131590Srgrimes	register struct var *vp, *vp2;
4141590Srgrimes	int errs, h;
4151590Srgrimes	char **ap;
4161590Srgrimes
4171590Srgrimes	errs = 0;
4181590Srgrimes	for (ap = arglist; *ap != NOSTR; ap++) {
4191590Srgrimes		if ((vp2 = lookup(*ap)) == NOVAR) {
4201590Srgrimes			if (!sourcing) {
4211590Srgrimes				printf("\"%s\": undefined variable\n", *ap);
4221590Srgrimes				errs++;
4231590Srgrimes			}
4241590Srgrimes			continue;
4251590Srgrimes		}
4261590Srgrimes		h = hash(*ap);
4271590Srgrimes		if (vp2 == variables[h]) {
4281590Srgrimes			variables[h] = variables[h]->v_link;
4291590Srgrimes			vfree(vp2->v_name);
4301590Srgrimes			vfree(vp2->v_value);
4311590Srgrimes			free((char *)vp2);
4321590Srgrimes			continue;
4331590Srgrimes		}
4341590Srgrimes		for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
4351590Srgrimes			;
4361590Srgrimes		vp->v_link = vp2->v_link;
4371590Srgrimes		vfree(vp2->v_name);
4381590Srgrimes		vfree(vp2->v_value);
4391590Srgrimes		free((char *) vp2);
4401590Srgrimes	}
4411590Srgrimes	return(errs);
4421590Srgrimes}
4431590Srgrimes
4441590Srgrimes/*
4451590Srgrimes * Put add users to a group.
4461590Srgrimes */
4471590Srgrimesint
4481590Srgrimesgroup(argv)
4491590Srgrimes	char **argv;
4501590Srgrimes{
4511590Srgrimes	register struct grouphead *gh;
4521590Srgrimes	register struct group *gp;
4531590Srgrimes	register int h;
4541590Srgrimes	int s;
4551590Srgrimes	char **ap, *gname, **p;
4561590Srgrimes
4571590Srgrimes	if (*argv == NOSTR) {
4581590Srgrimes		for (h = 0, s = 1; h < HSHSIZE; h++)
4591590Srgrimes			for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
4601590Srgrimes				s++;
4611590Srgrimes		ap = (char **) salloc(s * sizeof *ap);
4621590Srgrimes		for (h = 0, p = ap; h < HSHSIZE; h++)
4631590Srgrimes			for (gh = groups[h]; gh != NOGRP; gh = gh->g_link)
4641590Srgrimes				*p++ = gh->g_name;
4651590Srgrimes		*p = NOSTR;
4661590Srgrimes		sort(ap);
4671590Srgrimes		for (p = ap; *p != NOSTR; p++)
4681590Srgrimes			printgroup(*p);
4691590Srgrimes		return(0);
4701590Srgrimes	}
4711590Srgrimes	if (argv[1] == NOSTR) {
4721590Srgrimes		printgroup(*argv);
4731590Srgrimes		return(0);
4741590Srgrimes	}
4751590Srgrimes	gname = *argv;
4761590Srgrimes	h = hash(gname);
4771590Srgrimes	if ((gh = findgroup(gname)) == NOGRP) {
4781590Srgrimes		gh = (struct grouphead *) calloc(sizeof *gh, 1);
4791590Srgrimes		gh->g_name = vcopy(gname);
4801590Srgrimes		gh->g_list = NOGE;
4811590Srgrimes		gh->g_link = groups[h];
4821590Srgrimes		groups[h] = gh;
4831590Srgrimes	}
4841590Srgrimes
4851590Srgrimes	/*
4861590Srgrimes	 * Insert names from the command list into the group.
4871590Srgrimes	 * Who cares if there are duplicates?  They get tossed
4881590Srgrimes	 * later anyway.
4891590Srgrimes	 */
4901590Srgrimes
4911590Srgrimes	for (ap = argv+1; *ap != NOSTR; ap++) {
4921590Srgrimes		gp = (struct group *) calloc(sizeof *gp, 1);
4931590Srgrimes		gp->ge_name = vcopy(*ap);
4941590Srgrimes		gp->ge_link = gh->g_list;
4951590Srgrimes		gh->g_list = gp;
4961590Srgrimes	}
4971590Srgrimes	return(0);
4981590Srgrimes}
4991590Srgrimes
5001590Srgrimes/*
5011590Srgrimes * Sort the passed string vecotor into ascending dictionary
5021590Srgrimes * order.
5031590Srgrimes */
5041590Srgrimesvoid
5051590Srgrimessort(list)
5061590Srgrimes	char **list;
5071590Srgrimes{
5081590Srgrimes	register char **ap;
5091590Srgrimes	int diction();
5101590Srgrimes
5111590Srgrimes	for (ap = list; *ap != NOSTR; ap++)
5121590Srgrimes		;
5131590Srgrimes	if (ap-list < 2)
5141590Srgrimes		return;
5151590Srgrimes	qsort(list, ap-list, sizeof(*list), diction);
5161590Srgrimes}
5171590Srgrimes
5181590Srgrimes/*
5191590Srgrimes * Do a dictionary order comparison of the arguments from
5201590Srgrimes * qsort.
5211590Srgrimes */
5221590Srgrimesint
5231590Srgrimesdiction(a, b)
5241590Srgrimes	const void *a, *b;
5251590Srgrimes{
5261590Srgrimes	return(strcmp(*(char **)a, *(char **)b));
5271590Srgrimes}
5281590Srgrimes
5291590Srgrimes/*
5301590Srgrimes * The do nothing command for comments.
5311590Srgrimes */
5321590Srgrimes
5331590Srgrimes/*ARGSUSED*/
5341590Srgrimesint
5351590Srgrimesnull(e)
5361590Srgrimes	int e;
5371590Srgrimes{
5381590Srgrimes	return 0;
5391590Srgrimes}
5401590Srgrimes
5411590Srgrimes/*
5421590Srgrimes * Change to another file.  With no argument, print information about
5431590Srgrimes * the current file.
5441590Srgrimes */
5451590Srgrimesint
5461590Srgrimesfile(argv)
5471590Srgrimes	register char **argv;
5481590Srgrimes{
5491590Srgrimes
5501590Srgrimes	if (argv[0] == NOSTR) {
5511590Srgrimes		newfileinfo();
5521590Srgrimes		return 0;
5531590Srgrimes	}
5541590Srgrimes	if (setfile(*argv) < 0)
5551590Srgrimes		return 1;
5561590Srgrimes	announce();
5571590Srgrimes	return 0;
5581590Srgrimes}
5591590Srgrimes
5601590Srgrimes/*
5611590Srgrimes * Expand file names like echo
5621590Srgrimes */
5631590Srgrimesint
5641590Srgrimesecho(argv)
5651590Srgrimes	char **argv;
5661590Srgrimes{
5671590Srgrimes	register char **ap;
5681590Srgrimes	register char *cp;
5691590Srgrimes
5701590Srgrimes	for (ap = argv; *ap != NOSTR; ap++) {
5711590Srgrimes		cp = *ap;
5721590Srgrimes		if ((cp = expand(cp)) != NOSTR) {
5731590Srgrimes			if (ap != argv)
5741590Srgrimes				putchar(' ');
5751590Srgrimes			printf("%s", cp);
5761590Srgrimes		}
5771590Srgrimes	}
5781590Srgrimes	putchar('\n');
5791590Srgrimes	return 0;
5801590Srgrimes}
5811590Srgrimes
5821590Srgrimesint
5831590SrgrimesRespond(msgvec)
5841590Srgrimes	int *msgvec;
5851590Srgrimes{
5861590Srgrimes	if (value("Replyall") == NOSTR)
58732189Sjoerg		return (doRespond(msgvec));
5881590Srgrimes	else
58932189Sjoerg		return (dorespond(msgvec));
5901590Srgrimes}
5911590Srgrimes
5921590Srgrimes/*
5931590Srgrimes * Reply to a series of messages by simply mailing to the senders
5941590Srgrimes * and not messing around with the To: and Cc: lists as in normal
5951590Srgrimes * reply.
5961590Srgrimes */
5971590Srgrimesint
59832189SjoergdoRespond(msgvec)
5991590Srgrimes	int msgvec[];
6001590Srgrimes{
6011590Srgrimes	struct header head;
6021590Srgrimes	struct message *mp;
6031590Srgrimes	register int *ap;
6041590Srgrimes	register char *cp;
60532189Sjoerg	char *mid;
6061590Srgrimes
6071590Srgrimes	head.h_to = NIL;
6081590Srgrimes	for (ap = msgvec; *ap != 0; ap++) {
6091590Srgrimes		mp = &message[*ap - 1];
6101590Srgrimes		touch(mp);
6111590Srgrimes		dot = mp;
6121590Srgrimes		if ((cp = skin(hfield("from", mp))) == NOSTR)
6131590Srgrimes			cp = skin(nameof(mp, 2));
6141590Srgrimes		head.h_to = cat(head.h_to, extract(cp, GTO));
61532189Sjoerg		mid = skin(hfield("message-id", mp));
6161590Srgrimes	}
6171590Srgrimes	if (head.h_to == NIL)
6181590Srgrimes		return 0;
6191590Srgrimes	mp = &message[msgvec[0] - 1];
6201590Srgrimes	if ((head.h_subject = hfield("subject", mp)) == NOSTR)
6211590Srgrimes		head.h_subject = hfield("subj", mp);
6221590Srgrimes	head.h_subject = reedit(head.h_subject);
6231590Srgrimes	head.h_cc = NIL;
6241590Srgrimes	head.h_bcc = NIL;
6251590Srgrimes	head.h_smopts = NIL;
62632189Sjoerg	if ((head.h_replyto = getenv("REPLYTO")) == NULL)
62732189Sjoerg		head.h_replyto = NOSTR;
62832189Sjoerg	head.h_inreplyto = mid;
6291590Srgrimes	mail1(&head, 1);
6301590Srgrimes	return 0;
6311590Srgrimes}
6321590Srgrimes
6331590Srgrimes/*
6341590Srgrimes * Conditional commands.  These allow one to parameterize one's
6351590Srgrimes * .mailrc and do some things if sending, others if receiving.
6361590Srgrimes */
6371590Srgrimesint
6381590Srgrimesifcmd(argv)
6391590Srgrimes	char **argv;
6401590Srgrimes{
6411590Srgrimes	register char *cp;
6421590Srgrimes
6431590Srgrimes	if (cond != CANY) {
6441590Srgrimes		printf("Illegal nested \"if\"\n");
6451590Srgrimes		return(1);
6461590Srgrimes	}
6471590Srgrimes	cond = CANY;
6481590Srgrimes	cp = argv[0];
6491590Srgrimes	switch (*cp) {
6501590Srgrimes	case 'r': case 'R':
6511590Srgrimes		cond = CRCV;
6521590Srgrimes		break;
6531590Srgrimes
6541590Srgrimes	case 's': case 'S':
6551590Srgrimes		cond = CSEND;
6561590Srgrimes		break;
6571590Srgrimes
6581590Srgrimes	default:
6591590Srgrimes		printf("Unrecognized if-keyword: \"%s\"\n", cp);
6601590Srgrimes		return(1);
6611590Srgrimes	}
6621590Srgrimes	return(0);
6631590Srgrimes}
6641590Srgrimes
6651590Srgrimes/*
6661590Srgrimes * Implement 'else'.  This is pretty simple -- we just
6671590Srgrimes * flip over the conditional flag.
6681590Srgrimes */
6691590Srgrimesint
6701590Srgrimeselsecmd()
6711590Srgrimes{
6721590Srgrimes
6731590Srgrimes	switch (cond) {
6741590Srgrimes	case CANY:
6751590Srgrimes		printf("\"Else\" without matching \"if\"\n");
6761590Srgrimes		return(1);
6771590Srgrimes
6781590Srgrimes	case CSEND:
6791590Srgrimes		cond = CRCV;
6801590Srgrimes		break;
6811590Srgrimes
6821590Srgrimes	case CRCV:
6831590Srgrimes		cond = CSEND;
6841590Srgrimes		break;
6851590Srgrimes
6861590Srgrimes	default:
6871590Srgrimes		printf("Mail's idea of conditions is screwed up\n");
6881590Srgrimes		cond = CANY;
6891590Srgrimes		break;
6901590Srgrimes	}
6911590Srgrimes	return(0);
6921590Srgrimes}
6931590Srgrimes
6941590Srgrimes/*
6951590Srgrimes * End of if statement.  Just set cond back to anything.
6961590Srgrimes */
6971590Srgrimesint
6981590Srgrimesendifcmd()
6991590Srgrimes{
7001590Srgrimes
7011590Srgrimes	if (cond == CANY) {
7021590Srgrimes		printf("\"Endif\" without matching \"if\"\n");
7031590Srgrimes		return(1);
7041590Srgrimes	}
7051590Srgrimes	cond = CANY;
7061590Srgrimes	return(0);
7071590Srgrimes}
7081590Srgrimes
7091590Srgrimes/*
7101590Srgrimes * Set the list of alternate names.
7111590Srgrimes */
7121590Srgrimesint
7131590Srgrimesalternates(namelist)
7141590Srgrimes	char **namelist;
7151590Srgrimes{
7161590Srgrimes	register int c;
7171590Srgrimes	register char **ap, **ap2, *cp;
7181590Srgrimes
7191590Srgrimes	c = argcount(namelist) + 1;
7201590Srgrimes	if (c == 1) {
7211590Srgrimes		if (altnames == 0)
7221590Srgrimes			return(0);
7231590Srgrimes		for (ap = altnames; *ap; ap++)
7241590Srgrimes			printf("%s ", *ap);
7251590Srgrimes		printf("\n");
7261590Srgrimes		return(0);
7271590Srgrimes	}
7281590Srgrimes	if (altnames != 0)
7291590Srgrimes		free((char *) altnames);
7301590Srgrimes	altnames = (char **) calloc((unsigned) c, sizeof (char *));
7311590Srgrimes	for (ap = namelist, ap2 = altnames; *ap; ap++, ap2++) {
7321590Srgrimes		cp = (char *) calloc((unsigned) strlen(*ap) + 1, sizeof (char));
7331590Srgrimes		strcpy(cp, *ap);
7341590Srgrimes		*ap2 = cp;
7351590Srgrimes	}
7361590Srgrimes	*ap2 = 0;
7371590Srgrimes	return(0);
7381590Srgrimes}
739