cmd3.c revision 267654
18871Srgrimes/*
21558Srgrimes * Copyright (c) 1980, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * Redistribution and use in source and binary forms, with or without
61558Srgrimes * modification, are permitted provided that the following conditions
71558Srgrimes * are met:
81558Srgrimes * 1. Redistributions of source code must retain the above copyright
91558Srgrimes *    notice, this list of conditions and the following disclaimer.
101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111558Srgrimes *    notice, this list of conditions and the following disclaimer in the
121558Srgrimes *    documentation and/or other materials provided with the distribution.
131558Srgrimes * 4. Neither the name of the University nor the names of its contributors
141558Srgrimes *    may be used to endorse or promote products derived from this software
151558Srgrimes *    without specific prior written permission.
161558Srgrimes *
171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271558Srgrimes * SUCH DAMAGE.
281558Srgrimes */
291558Srgrimes
301558Srgrimes#ifndef lint
311558Srgrimes#if 0
321558Srgrimesstatic char sccsid[] = "@(#)cmd3.c	8.2 (Berkeley) 4/20/95";
331558Srgrimes#endif
341558Srgrimes#endif /* not lint */
3541477Sjulian#include <sys/cdefs.h>
3623675Speter__FBSDID("$FreeBSD: releng/9.3/usr.bin/mail/cmd3.c 216564 2010-12-19 16:25:23Z charnier $");
3741477Sjulian
3841477Sjulian#include "rcv.h"
3950476Speter#include "extern.h"
401558Srgrimes
411558Srgrimes/*
421558Srgrimes * Mail -- a mail program
4362668Smckusick *
4423675Speter * Still more user commands.
451558Srgrimes */
461558Srgrimes
471558Srgrimes/*
4823675Speter * Process a shell escape by saving signals, ignoring signals,
4923675Speter * and forking a sh -c
501558Srgrimes */
5123675Speterint
521558Srgrimesshell(char *str)
531558Srgrimes{
5423675Speter	sig_t sigint = signal(SIGINT, SIG_IGN);
5523675Speter	char *sh;
5641474Sjulian	char cmd[BUFSIZ];
571558Srgrimes
5823675Speter	if (strlcpy(cmd, str, sizeof(cmd)) >= sizeof(cmd))
597585Sbde		return (1);
607585Sbde	if (bangexp(cmd, sizeof(cmd)) < 0)
611558Srgrimes		return (1);
621558Srgrimes	if ((sh = value("SHELL")) == NULL)
6341474Sjulian		sh = _PATH_CSHELL;
641558Srgrimes	(void)run_command(sh, 0, -1, -1, "-c", cmd, NULL);
6541474Sjulian	(void)signal(SIGINT, sigint);
6641474Sjulian	printf("!\n");
671558Srgrimes	return (0);
681558Srgrimes}
691558Srgrimes
701558Srgrimes/*
711558Srgrimes * Fork an interactive shell.
721558Srgrimes */
731558Srgrimes/*ARGSUSED*/
741558Srgrimesint
751558Srgrimesdosh(char *str __unused)
761558Srgrimes{
771558Srgrimes	sig_t sigint = signal(SIGINT, SIG_IGN);
781558Srgrimes	char *sh;
791558Srgrimes
801558Srgrimes	if ((sh = value("SHELL")) == NULL)
811558Srgrimes		sh = _PATH_CSHELL;
821558Srgrimes	(void)run_command(sh, 0, -1, -1, NULL, NULL, NULL);
831558Srgrimes	(void)signal(SIGINT, sigint);
841558Srgrimes	printf("\n");
8523675Speter	return (0);
861558Srgrimes}
871558Srgrimes
881558Srgrimes/*
8941474Sjulian * Expand the shell escape by expanding unescaped !'s into the
9041474Sjulian * last issued command where possible.
9141474Sjulian */
9241474Sjulianint
9341474Sjulianbangexp(char *str, size_t strsize)
9441474Sjulian{
9541474Sjulian	char bangbuf[BUFSIZ];
9641474Sjulian	static char lastbang[BUFSIZ];
9741474Sjulian	char *cp, *cp2;
9841474Sjulian	int n, changed = 0;
9941474Sjulian
10041474Sjulian	cp = str;
10141474Sjulian	cp2 = bangbuf;
10241474Sjulian	n = sizeof(bangbuf);
10341474Sjulian	while (*cp != '\0') {
10441474Sjulian		if (*cp == '!') {
10541474Sjulian			if (n < strlen(lastbang)) {
10641474Sjulianoverf:
10741474Sjulian				printf("Command buffer overflow\n");
10841474Sjulian				return (-1);
10941474Sjulian			}
11041474Sjulian			changed++;
11141474Sjulian			if (strlcpy(cp2, lastbang, sizeof(bangbuf) - (cp2 - bangbuf))
11241474Sjulian			    >= sizeof(bangbuf) - (cp2 - bangbuf))
11341474Sjulian				goto overf;
11441474Sjulian			cp2 += strlen(lastbang);
11541474Sjulian			n -= strlen(lastbang);
11641474Sjulian			cp++;
11741474Sjulian			continue;
11841474Sjulian		}
11941474Sjulian		if (*cp == '\\' && cp[1] == '!') {
12041474Sjulian			if (--n <= 1)
12141474Sjulian				goto overf;
12241474Sjulian			*cp2++ = '!';
12341474Sjulian			cp += 2;
12441474Sjulian			changed++;
12541474Sjulian		}
12641474Sjulian		if (--n <= 1)
12741474Sjulian			goto overf;
12841474Sjulian		*cp2++ = *cp++;
12941474Sjulian	}
13041474Sjulian	*cp2 = 0;
13141474Sjulian	if (changed) {
13241474Sjulian		printf("!%s\n", bangbuf);
13341474Sjulian		(void)fflush(stdout);
13441474Sjulian	}
13541474Sjulian	if (strlcpy(str, bangbuf, strsize) >= strsize)
1361558Srgrimes		goto overf;
13741474Sjulian	if (strlcpy(lastbang, bangbuf, sizeof(lastbang)) >= sizeof(lastbang))
1381558Srgrimes		goto overf;
1391558Srgrimes	return (0);
14041474Sjulian}
14141474Sjulian
14241474Sjulian/*
14341474Sjulian * Print out a nice help message from some file or another.
14441474Sjulian */
14541474Sjulian
14641474Sjulianint
14741474Sjulianhelp(void)
14841474Sjulian{
14941474Sjulian	int c;
15041474Sjulian	FILE *f;
15141474Sjulian
15241474Sjulian	if ((f = Fopen(_PATH_HELP, "r")) == NULL) {
15341474Sjulian		warn("%s", _PATH_HELP);
15441474Sjulian		return (1);
15541474Sjulian	}
15641474Sjulian	while ((c = getc(f)) != EOF)
15741474Sjulian		putchar(c);
15841474Sjulian	(void)Fclose(f);
15941474Sjulian	return (0);
16041474Sjulian}
16141474Sjulian
16241474Sjulian/*
16341474Sjulian * Change user's working directory.
16441474Sjulian */
1651558Srgrimesint
1661558Srgrimesschdir(char **arglist)
1671558Srgrimes{
1681558Srgrimes	char *cp;
16923675Speter
1701558Srgrimes	if (*arglist == NULL) {
1711558Srgrimes		if (homedir == NULL)
1721558Srgrimes			return (1);
1731558Srgrimes		cp = homedir;
1741558Srgrimes	} else
1751558Srgrimes		if ((cp = expand(*arglist)) == NULL)
1761558Srgrimes			return (1);
1771558Srgrimes	if (chdir(cp) < 0) {
1782603Sdg		warn("%s", cp);
1791558Srgrimes		return (1);
1801558Srgrimes	}
1811558Srgrimes	return (0);
1821558Srgrimes}
18323675Speter
18423675Speterint
18523675Speterrespond(int *msgvec)
18623675Speter{
1871558Srgrimes	if (value("Replyall") == NULL && value("flipr") == NULL)
1881558Srgrimes		return (dorespond(msgvec));
1891558Srgrimes	else
1901558Srgrimes		return (doRespond(msgvec));
1911558Srgrimes}
1921558Srgrimes
1931558Srgrimes/*
1941558Srgrimes * Reply to a list of messages.  Extract each name from the
19541474Sjulian * message header and send them off to mail1()
1961558Srgrimes */
1971558Srgrimesint
1981558Srgrimesdorespond(int *msgvec)
1991558Srgrimes{
20023999Speter	struct message *mp;
20123999Speter	char *cp, *rcv, *replyto;
2021558Srgrimes	char **ap;
2031558Srgrimes	struct name *np;
2041558Srgrimes	struct header head;
2051558Srgrimes
2061558Srgrimes	if (msgvec[1] != 0) {
2071558Srgrimes		printf("Sorry, can't reply to multiple messages at once\n");
2081558Srgrimes		return (1);
2091558Srgrimes	}
2101558Srgrimes	mp = &message[msgvec[0] - 1];
2111558Srgrimes	touch(mp);
2121558Srgrimes	dot = mp;
2131558Srgrimes	if ((rcv = skin(hfield("from", mp))) == NULL)
2141558Srgrimes		rcv = skin(nameof(mp, 1));
2151558Srgrimes	if ((replyto = skin(hfield("reply-to", mp))) != NULL)
2161558Srgrimes		np = extract(replyto, GTO);
2171558Srgrimes	else if ((cp = skin(hfield("to", mp))) != NULL)
2181558Srgrimes		np = extract(cp, GTO);
2191558Srgrimes	else
2201558Srgrimes		np = NULL;
2211558Srgrimes	np = elide(np);
2221558Srgrimes	/*
2231558Srgrimes	 * Delete my name from the reply list,
2241558Srgrimes	 * and with it, all my alternate names.
2252603Sdg	 */
2261558Srgrimes	np = delname(np, myname);
2271558Srgrimes	if (altnames)
2282603Sdg		for (ap = altnames; *ap != NULL; ap++)
22923675Speter			np = delname(np, *ap);
2301558Srgrimes	if (np != NULL && replyto == NULL)
2311558Srgrimes		np = cat(np, extract(rcv, GTO));
23237236Sbde	else if (np == NULL) {
23341474Sjulian		if (replyto != NULL)
2341558Srgrimes			printf("Empty reply-to field -- replying to author\n");
2351558Srgrimes		np = extract(rcv, GTO);
23623675Speter	}
2371558Srgrimes	head.h_to = np;
2381558Srgrimes	if ((head.h_subject = hfield("subject", mp)) == NULL)
2391558Srgrimes		head.h_subject = hfield("subj", mp);
2401558Srgrimes	head.h_subject = reedit(head.h_subject);
2411558Srgrimes	if (replyto == NULL && (cp = skin(hfield("cc", mp))) != NULL) {
2421558Srgrimes		np = elide(extract(cp, GCC));
2431558Srgrimes		np = delname(np, myname);
24441474Sjulian		if (altnames != 0)
24523675Speter			for (ap = altnames; *ap != NULL; ap++)
2461558Srgrimes				np = delname(np, *ap);
2471558Srgrimes		head.h_cc = np;
2481558Srgrimes	} else
2491558Srgrimes		head.h_cc = NULL;
2501558Srgrimes	head.h_bcc = NULL;
2511558Srgrimes	head.h_smopts = NULL;
2521558Srgrimes	head.h_replyto = value("REPLYTO");
2531558Srgrimes	head.h_inreplyto = skin(hfield("message-id", mp));
2541558Srgrimes	mail1(&head, 1);
2551558Srgrimes	return (0);
2561558Srgrimes}
25737236Sbde
25837236Sbde/*
2591558Srgrimes * Modify the subject we are replying to to begin with Re: if
2601558Srgrimes * it does not already.
2611558Srgrimes */
2621558Srgrimeschar *
2631558Srgrimesreedit(char *subj)
2641558Srgrimes{
2651558Srgrimes	char *newsubj;
2661558Srgrimes
26737236Sbde	if (subj == NULL)
2681558Srgrimes		return (NULL);
2691558Srgrimes	if ((subj[0] == 'r' || subj[0] == 'R') &&
2701558Srgrimes	    (subj[1] == 'e' || subj[1] == 'E') &&
2711558Srgrimes	    subj[2] == ':')
2721558Srgrimes		return (subj);
27341474Sjulian	newsubj = salloc(strlen(subj) + 5);
2741558Srgrimes	sprintf(newsubj, "Re: %s", subj);
2751558Srgrimes	return (newsubj);
2761558Srgrimes}
2771558Srgrimes
27834266Sjulian/*
27934266Sjulian * Preserve the named messages, so that they will be sent
28023675Speter * back to the system mailbox.
28134266Sjulian */
2821558Srgrimesint
2831558Srgrimespreserve(int *msgvec)
2841558Srgrimes{
2851558Srgrimes	int *ip, mesg;
2861558Srgrimes	struct message *mp;
2871558Srgrimes
2881558Srgrimes	if (edit) {
2891558Srgrimes		printf("Cannot \"preserve\" in edit mode\n");
29041474Sjulian		return (1);
2911558Srgrimes	}
29241474Sjulian	for (ip = msgvec; *ip != 0; ip++) {
2931558Srgrimes		mesg = *ip;
29441474Sjulian		mp = &message[mesg-1];
2951558Srgrimes		mp->m_flag |= MPRESERVE;
29641474Sjulian		mp->m_flag &= ~MBOX;
29741474Sjulian		dot = mp;
2981558Srgrimes	}
2991558Srgrimes	return (0);
3001558Srgrimes}
3011558Srgrimes
3021558Srgrimes/*
3031558Srgrimes * Mark all given messages as unread.
3041558Srgrimes */
3051558Srgrimesint
3061558Srgrimesunread(int msgvec[])
3071558Srgrimes{
3081558Srgrimes	int *ip;
30962668Smckusick
31062668Smckusick	for (ip = msgvec; *ip != 0; ip++) {
31162668Smckusick		dot = &message[*ip-1];
31262668Smckusick		dot->m_flag &= ~(MREAD|MTOUCH);
3131558Srgrimes		dot->m_flag |= MSTATUS;
3141558Srgrimes	}
3151558Srgrimes	return (0);
3161558Srgrimes}
3171558Srgrimes
3181558Srgrimes/*
3191558Srgrimes * Print the size of each message.
3201558Srgrimes */
3211558Srgrimesint
3221558Srgrimesmessize(int *msgvec)
3231558Srgrimes{
3241558Srgrimes	struct message *mp;
3251558Srgrimes	int *ip, mesg;
3261558Srgrimes
3271558Srgrimes	for (ip = msgvec; *ip != 0; ip++) {
3281558Srgrimes		mesg = *ip;
32941474Sjulian		mp = &message[mesg-1];
3301558Srgrimes		printf("%d: %ld/%ld\n", mesg, mp->m_lines, mp->m_size);
33141474Sjulian	}
3321558Srgrimes	return (0);
3331558Srgrimes}
3341558Srgrimes
3351558Srgrimes/*
3361558Srgrimes * Quit quickly.  If we are sourcing, just pop the input level
3371558Srgrimes * by returning an error.
3387585Sbde */
3391558Srgrimesint
3401558Srgrimesrexit(int e __unused)
3411558Srgrimes{
3421558Srgrimes	if (sourcing)
3431558Srgrimes		return (1);
34423675Speter	exit(0);
3451558Srgrimes	/*NOTREACHED*/
3461558Srgrimes}
3471558Srgrimes
34862668Smckusick/*
34962668Smckusick * Set or display a variable value.  Syntax is similar to that
35062668Smckusick * of csh.
35162668Smckusick */
35262668Smckusickint
35362668Smckusickset(char **arglist)
35462668Smckusick{
35562668Smckusick	struct var *vp;
35662668Smckusick	char *cp, *cp2;
35762668Smckusick	char varbuf[BUFSIZ], **ap, **p;
35862668Smckusick	int errs, h, s;
35962668Smckusick
36062668Smckusick	if (*arglist == NULL) {
36162668Smckusick		for (h = 0, s = 1; h < HSHSIZE; h++)
36262668Smckusick			for (vp = variables[h]; vp != NULL; vp = vp->v_link)
3631558Srgrimes				s++;
3641558Srgrimes		ap = (char **)salloc(s * sizeof(*ap));
3651558Srgrimes		for (h = 0, p = ap; h < HSHSIZE; h++)
3661558Srgrimes			for (vp = variables[h]; vp != NULL; vp = vp->v_link)
3671558Srgrimes				*p++ = vp->v_name;
3681558Srgrimes		*p = NULL;
3691558Srgrimes		sort(ap);
37034266Sjulian		for (p = ap; *p != NULL; p++)
37134266Sjulian			printf("%s\t%s\n", *p, value(*p));
37223675Speter		return (0);
37334266Sjulian	}
3741558Srgrimes	errs = 0;
3751558Srgrimes	for (ap = arglist; *ap != NULL; ap++) {
3761558Srgrimes		cp = *ap;
3771558Srgrimes		cp2 = varbuf;
3781558Srgrimes		while (cp2 < varbuf + sizeof(varbuf) - 1 && *cp != '=' && *cp != '\0')
3791558Srgrimes			*cp2++ = *cp++;
3801558Srgrimes		*cp2 = '\0';
3811558Srgrimes		if (*cp == '\0')
3821558Srgrimes			cp = "";
3831558Srgrimes		else
3841558Srgrimes			cp++;
3851558Srgrimes		if (equal(varbuf, "")) {
3861558Srgrimes			printf("Non-null variable name required\n");
3871558Srgrimes			errs++;
3881558Srgrimes			continue;
3891558Srgrimes		}
39034266Sjulian		assign(varbuf, cp);
39134266Sjulian	}
39223675Speter	return (errs);
39334266Sjulian}
3941558Srgrimes
3951558Srgrimes/*
3961558Srgrimes * Unset a bunch of variable values.
3971558Srgrimes */
3981558Srgrimesint
39934266Sjulianunset(char **arglist)
40034266Sjulian{
40123675Speter	struct var *vp, *vp2;
40234266Sjulian	int errs, h;
4031558Srgrimes	char **ap;
4041558Srgrimes
4051558Srgrimes	errs = 0;
4061558Srgrimes	for (ap = arglist; *ap != NULL; ap++) {
4071558Srgrimes		if ((vp2 = lookup(*ap)) == NULL) {
4081558Srgrimes			if (getenv(*ap))
4091558Srgrimes				unsetenv(*ap);
4101558Srgrimes			else if (!sourcing) {
4111558Srgrimes				printf("\"%s\": undefined variable\n", *ap);
4121558Srgrimes				errs++;
4131558Srgrimes			}
4141558Srgrimes			continue;
4151558Srgrimes		}
4161558Srgrimes		h = hash(*ap);
4171558Srgrimes		if (vp2 == variables[h]) {
4181558Srgrimes			variables[h] = variables[h]->v_link;
4191558Srgrimes			vfree(vp2->v_name);
4201558Srgrimes			vfree(vp2->v_value);
4211558Srgrimes			(void)free(vp2);
4221558Srgrimes			continue;
4231558Srgrimes		}
4241558Srgrimes		for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
4251558Srgrimes			;
426		vp->v_link = vp2->v_link;
427		vfree(vp2->v_name);
428		vfree(vp2->v_value);
429		(void)free(vp2);
430	}
431	return (errs);
432}
433
434/*
435 * Put add users to a group.
436 */
437int
438group(char **argv)
439{
440	struct grouphead *gh;
441	struct group *gp;
442	char **ap, *gname, **p;
443	int h, s;
444
445	if (*argv == NULL) {
446		for (h = 0, s = 1; h < HSHSIZE; h++)
447			for (gh = groups[h]; gh != NULL; gh = gh->g_link)
448				s++;
449		ap = (char **)salloc(s * sizeof(*ap));
450		for (h = 0, p = ap; h < HSHSIZE; h++)
451			for (gh = groups[h]; gh != NULL; gh = gh->g_link)
452				*p++ = gh->g_name;
453		*p = NULL;
454		sort(ap);
455		for (p = ap; *p != NULL; p++)
456			printgroup(*p);
457		return (0);
458	}
459	if (argv[1] == NULL) {
460		printgroup(*argv);
461		return (0);
462	}
463	gname = *argv;
464	h = hash(gname);
465	if ((gh = findgroup(gname)) == NULL) {
466		gh = calloc(sizeof(*gh), 1);
467		gh->g_name = vcopy(gname);
468		gh->g_list = NULL;
469		gh->g_link = groups[h];
470		groups[h] = gh;
471	}
472
473	/*
474	 * Insert names from the command list into the group.
475	 * Who cares if there are duplicates?  They get tossed
476	 * later anyway.
477	 */
478
479	for (ap = argv+1; *ap != NULL; ap++) {
480		gp = calloc(sizeof(*gp), 1);
481		gp->ge_name = vcopy(*ap);
482		gp->ge_link = gh->g_list;
483		gh->g_list = gp;
484	}
485	return (0);
486}
487
488/*
489 * Sort the passed string vecotor into ascending dictionary
490 * order.
491 */
492void
493sort(char **list)
494{
495	char **ap;
496
497	for (ap = list; *ap != NULL; ap++)
498		;
499	if (ap-list < 2)
500		return;
501	qsort(list, ap-list, sizeof(*list), diction);
502}
503
504/*
505 * Do a dictionary order comparison of the arguments from
506 * qsort.
507 */
508int
509diction(const void *a, const void *b)
510{
511	return (strcmp(*(const char **)a, *(const char **)b));
512}
513
514/*
515 * The do nothing command for comments.
516 */
517
518/*ARGSUSED*/
519int
520null(int e __unused)
521{
522	return (0);
523}
524
525/*
526 * Change to another file.  With no argument, print information about
527 * the current file.
528 */
529int
530file(char **argv)
531{
532
533	if (argv[0] == NULL) {
534		newfileinfo(0);
535		return (0);
536	}
537	if (setfile(*argv) < 0)
538		return (1);
539	announce();
540	return (0);
541}
542
543/*
544 * Expand file names like echo
545 */
546int
547echo(char **argv)
548{
549	char **ap, *cp;
550
551	for (ap = argv; *ap != NULL; ap++) {
552		cp = *ap;
553		if ((cp = expand(cp)) != NULL) {
554			if (ap != argv)
555				printf(" ");
556			printf("%s", cp);
557		}
558	}
559	printf("\n");
560	return (0);
561}
562
563int
564Respond(int *msgvec)
565{
566	if (value("Replyall") == NULL && value("flipr") == NULL)
567		return (doRespond(msgvec));
568	else
569		return (dorespond(msgvec));
570}
571
572/*
573 * Reply to a series of messages by simply mailing to the senders
574 * and not messing around with the To: and Cc: lists as in normal
575 * reply.
576 */
577int
578doRespond(int msgvec[])
579{
580	struct header head;
581	struct message *mp;
582	int *ap;
583	char *cp, *mid;
584
585	head.h_to = NULL;
586	for (ap = msgvec; *ap != 0; ap++) {
587		mp = &message[*ap - 1];
588		touch(mp);
589		dot = mp;
590		if ((cp = skin(hfield("from", mp))) == NULL)
591			cp = skin(nameof(mp, 2));
592		head.h_to = cat(head.h_to, extract(cp, GTO));
593		mid = skin(hfield("message-id", mp));
594	}
595	if (head.h_to == NULL)
596		return (0);
597	mp = &message[msgvec[0] - 1];
598	if ((head.h_subject = hfield("subject", mp)) == NULL)
599		head.h_subject = hfield("subj", mp);
600	head.h_subject = reedit(head.h_subject);
601	head.h_cc = NULL;
602	head.h_bcc = NULL;
603	head.h_smopts = NULL;
604	head.h_replyto = value("REPLYTO");
605	head.h_inreplyto = mid;
606	mail1(&head, 1);
607	return (0);
608}
609
610/*
611 * Conditional commands.  These allow one to parameterize one's
612 * .mailrc and do some things if sending, others if receiving.
613 */
614int
615ifcmd(char **argv)
616{
617	char *cp;
618
619	if (cond != CANY) {
620		printf("Illegal nested \"if\"\n");
621		return (1);
622	}
623	cond = CANY;
624	cp = argv[0];
625	switch (*cp) {
626	case 'r': case 'R':
627		cond = CRCV;
628		break;
629
630	case 's': case 'S':
631		cond = CSEND;
632		break;
633
634	default:
635		printf("Unrecognized if-keyword: \"%s\"\n", cp);
636		return (1);
637	}
638	return (0);
639}
640
641/*
642 * Implement 'else'.  This is pretty simple -- we just
643 * flip over the conditional flag.
644 */
645int
646elsecmd(void)
647{
648
649	switch (cond) {
650	case CANY:
651		printf("\"Else\" without matching \"if\"\n");
652		return (1);
653
654	case CSEND:
655		cond = CRCV;
656		break;
657
658	case CRCV:
659		cond = CSEND;
660		break;
661
662	default:
663		printf("Mail's idea of conditions is screwed up\n");
664		cond = CANY;
665		break;
666	}
667	return (0);
668}
669
670/*
671 * End of if statement.  Just set cond back to anything.
672 */
673int
674endifcmd(void)
675{
676
677	if (cond == CANY) {
678		printf("\"Endif\" without matching \"if\"\n");
679		return (1);
680	}
681	cond = CANY;
682	return (0);
683}
684
685/*
686 * Set the list of alternate names.
687 */
688int
689alternates(char **namelist)
690{
691	int c;
692	char **ap, **ap2, *cp;
693
694	c = argcount(namelist) + 1;
695	if (c == 1) {
696		if (altnames == 0)
697			return (0);
698		for (ap = altnames; *ap != NULL; ap++)
699			printf("%s ", *ap);
700		printf("\n");
701		return (0);
702	}
703	if (altnames != 0)
704		(void)free(altnames);
705	altnames = calloc((unsigned)c, sizeof(char *));
706	for (ap = namelist, ap2 = altnames; *ap != NULL; ap++, ap2++) {
707		cp = calloc((unsigned)strlen(*ap) + 1, sizeof(char));
708		strcpy(cp, *ap);
709		*ap2 = cp;
710	}
711	*ap2 = 0;
712	return (0);
713}
714