122712Sdist /*
222712Sdist **  Sendmail
322712Sdist **  Copyright (c) 1983  Eric P. Allman
422712Sdist **  Berkeley, California
522712Sdist **
622712Sdist **  Copyright (c) 1983 Regents of the University of California.
722712Sdist **  All rights reserved.  The Berkeley software License Agreement
822712Sdist **  specifies the terms and conditions for redistribution.
922712Sdist */
1022712Sdist 
1122712Sdist 
129339Seric # include <errno.h>
134549Seric # include "sendmail.h"
1411728Seric # include <signal.h>
154549Seric 
165181Seric # ifndef SMTP
1723122Seric # ifndef lint
18*24943Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.5.1.1 (Berkeley) 09/19/85	(no SMTP)";
1923122Seric # endif not lint
205181Seric # else SMTP
214556Seric 
2223122Seric # ifndef lint
23*24943Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.5.1.1 (Berkeley) 09/19/85";
2423122Seric # endif not lint
255181Seric 
264549Seric /*
274549Seric **  SMTP -- run the SMTP protocol.
284549Seric **
294549Seric **	Parameters:
304549Seric **		none.
314549Seric **
324549Seric **	Returns:
334549Seric **		never.
344549Seric **
354549Seric **	Side Effects:
364549Seric **		Reads commands from the input channel and processes
374549Seric **			them.
384549Seric */
394549Seric 
404549Seric struct cmd
414549Seric {
424549Seric 	char	*cmdname;	/* command name */
434549Seric 	int	cmdcode;	/* internal code, see below */
444549Seric };
454549Seric 
464549Seric /* values for cmdcode */
474549Seric # define CMDERROR	0	/* bad command */
484549Seric # define CMDMAIL	1	/* mail -- designate sender */
494976Seric # define CMDRCPT	2	/* rcpt -- designate recipient */
504549Seric # define CMDDATA	3	/* data -- send message text */
519339Seric # define CMDRSET	4	/* rset -- reset state */
529339Seric # define CMDVRFY	5	/* vrfy -- verify address */
539339Seric # define CMDHELP	6	/* help -- give usage info */
549339Seric # define CMDNOOP	7	/* noop -- do nothing */
559339Seric # define CMDQUIT	8	/* quit -- close connection and die */
569339Seric # define CMDHELO	9	/* helo -- be polite */
579339Seric # define CMDDBGQSHOW	10	/* showq -- show send queue (DEBUG) */
589339Seric # define CMDDBGDEBUG	11	/* debug -- set debug mode */
599339Seric # define CMDVERB	12	/* verb -- go into verbose mode */
609339Seric # define CMDDBGKILL	13	/* kill -- kill sendmail */
619339Seric # define CMDDBGWIZ	14	/* wiz -- become a wizard */
629339Seric # define CMDONEX	15	/* onex -- sending one transaction only */
634549Seric 
644549Seric static struct cmd	CmdTab[] =
654549Seric {
664549Seric 	"mail",		CMDMAIL,
674976Seric 	"rcpt",		CMDRCPT,
684549Seric 	"data",		CMDDATA,
694549Seric 	"rset",		CMDRSET,
704549Seric 	"vrfy",		CMDVRFY,
717762Seric 	"expn",		CMDVRFY,
724549Seric 	"help",		CMDHELP,
734549Seric 	"noop",		CMDNOOP,
744549Seric 	"quit",		CMDQUIT,
754976Seric 	"helo",		CMDHELO,
768544Seric 	"verb",		CMDVERB,
779314Seric 	"onex",		CMDONEX,
785003Seric # ifdef DEBUG
799339Seric 	"showq",	CMDDBGQSHOW,
808544Seric 	"debug",	CMDDBGDEBUG,
818544Seric 	"kill",		CMDDBGKILL,
828544Seric 	"wiz",		CMDDBGWIZ,
83*24943Seric # endif DEBUG
844549Seric 	NULL,		CMDERROR,
854549Seric };
864549Seric 
878544Seric bool	IsWiz = FALSE;			/* set if we are a wizard */
8815596Seric char	*WizWord;			/* the wizard word to compare against */
899339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
909378Seric bool	OneXact = FALSE;		/* one xaction only this run */
9111146Seric 
929339Seric #define EX_QUIT		22		/* special code for QUIT command */
938544Seric 
944549Seric smtp()
954549Seric {
964549Seric 	register char *p;
978544Seric 	register struct cmd *c;
984549Seric 	char *cmd;
994549Seric 	extern char *skipword();
1004549Seric 	extern bool sameword();
1014549Seric 	bool hasmail;			/* mail command received */
1024713Seric 	int rcps;			/* number of recipients */
1035003Seric 	auto ADDRESS *vrfyqueue;
10412612Seric 	ADDRESS *a;
1058544Seric 	char inp[MAXLINE];
1067124Seric 	extern char Version[];
1077356Seric 	extern tick();
1088544Seric 	extern bool iswiz();
1099349Seric 	extern char *arpadate();
11011151Seric 	extern char *macvalue();
11112612Seric 	extern ADDRESS *recipient();
112*24943Seric 	extern ENVELOPE BlankEnvelope;
113*24943Seric 	extern ENVELOPE *newenvelope();
1144549Seric 
1155003Seric 	hasmail = FALSE;
1164713Seric 	rcps = 0;
1177363Seric 	if (OutChannel != stdout)
1187363Seric 	{
1197363Seric 		/* arrange for debugging output to go to remote host */
1207363Seric 		(void) close(1);
1217363Seric 		(void) dup(fileno(OutChannel));
1227363Seric 	}
12311931Seric 	settime();
12416153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
12510708Seric 	message("220", inp);
126*24943Seric 	SmtpPhase = "startup";
1274549Seric 	for (;;)
1284549Seric 	{
12912612Seric 		/* arrange for backout */
13012612Seric 		if (setjmp(TopFrame) > 0 && InChild)
13112612Seric 			finis();
13212612Seric 		QuickAbort = FALSE;
13312612Seric 		HoldErrs = FALSE;
13412612Seric 
1357356Seric 		/* setup for the read */
1366907Seric 		CurEnv->e_to = NULL;
1374577Seric 		Errors = 0;
1387275Seric 		(void) fflush(stdout);
1397356Seric 
1407356Seric 		/* read the input line */
1417685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1427356Seric 
1437685Seric 		/* handle errors */
1447356Seric 		if (p == NULL)
1457356Seric 		{
1464549Seric 			/* end of file, just die */
1474558Seric 			message("421", "%s Lost input channel", HostName);
1484549Seric 			finis();
1494549Seric 		}
1504549Seric 
1514549Seric 		/* clean up end of line */
1524558Seric 		fixcrlf(inp, TRUE);
1534549Seric 
1544713Seric 		/* echo command to transcript */
1559545Seric 		if (CurEnv->e_xfp != NULL)
1569545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1574713Seric 
1584549Seric 		/* break off command */
1594549Seric 		for (p = inp; isspace(*p); p++)
1604549Seric 			continue;
1614549Seric 		cmd = p;
1624549Seric 		while (*++p != '\0' && !isspace(*p))
1634549Seric 			continue;
1644549Seric 		if (*p != '\0')
1654549Seric 			*p++ = '\0';
1664549Seric 
1674549Seric 		/* decode command */
1684549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1694549Seric 		{
1704549Seric 			if (sameword(c->cmdname, cmd))
1714549Seric 				break;
1724549Seric 		}
1734549Seric 
1744549Seric 		/* process command */
1754549Seric 		switch (c->cmdcode)
1764549Seric 		{
1774976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
178*24943Seric 			SmtpPhase = "HELO";
17914877Seric 			if (sameword(p, HostName))
18014877Seric 			{
18114877Seric 				/* connected to an echo server */
18214877Seric 				message("553", "%s I refuse to talk to myself",
18314877Seric 					HostName);
18414877Seric 				break;
18514877Seric 			}
18611146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
18711146Seric 			{
18811146Seric 				char buf[MAXNAME];
18911146Seric 
19011146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
19111146Seric 				define('s', newstr(buf), CurEnv);
19211146Seric 			}
19311146Seric 			else
19411146Seric 				define('s', newstr(p), CurEnv);
1954997Seric 			message("250", "%s Hello %s, pleased to meet you",
1964997Seric 				HostName, p);
1974976Seric 			break;
1984976Seric 
1994549Seric 		  case CMDMAIL:		/* mail -- designate sender */
200*24943Seric 			SmtpPhase = "MAIL";
201*24943Seric 
20211151Seric 			/* force a sending host even if no HELO given */
20311151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
20411151Seric 				define('s', RealHostName, CurEnv);
20511151Seric 
2069314Seric 			/* check for validity of this command */
2074558Seric 			if (hasmail)
2084558Seric 			{
2094558Seric 				message("503", "Sender already specified");
2104558Seric 				break;
2114558Seric 			}
2129339Seric 			if (InChild)
2139339Seric 			{
2149339Seric 				syserr("Nested MAIL command");
2159339Seric 				exit(0);
2169339Seric 			}
2179339Seric 
2189339Seric 			/* fork a subprocess to process this command */
2199339Seric 			if (runinchild("SMTP-MAIL") > 0)
2209339Seric 				break;
2219339Seric 			initsys();
2229339Seric 
2239339Seric 			/* child -- go do the processing */
2244549Seric 			p = skipword(p, "from");
2254549Seric 			if (p == NULL)
2264549Seric 				break;
2274549Seric 			setsender(p);
2284577Seric 			if (Errors == 0)
2294549Seric 			{
2304549Seric 				message("250", "Sender ok");
2314549Seric 				hasmail = TRUE;
2324549Seric 			}
2339339Seric 			else if (InChild)
2349339Seric 				finis();
2354549Seric 			break;
2364549Seric 
2374976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
238*24943Seric 			SmtpPhase = "RCPT";
23912612Seric 			if (setjmp(TopFrame) > 0)
24014785Seric 			{
24114785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
24212612Seric 				break;
24314785Seric 			}
24412612Seric 			QuickAbort = TRUE;
2454549Seric 			p = skipword(p, "to");
2464549Seric 			if (p == NULL)
2474549Seric 				break;
24816140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
24912612Seric 			if (a == NULL)
25012612Seric 				break;
25116886Seric 			a->q_flags |= QPRIMARY;
25212612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
25312612Seric 			if (Errors != 0)
25412612Seric 				break;
25512612Seric 
25612612Seric 			/* no errors during parsing, but might be a duplicate */
25712612Seric 			CurEnv->e_to = p;
25812612Seric 			if (!bitset(QBADADDR, a->q_flags))
25912612Seric 				message("250", "Recipient ok");
26012612Seric 			else
2614549Seric 			{
26212612Seric 				/* punt -- should keep message in ADDRESS.... */
26312612Seric 				message("550", "Addressee unknown");
2644549Seric 			}
26512612Seric 			CurEnv->e_to = NULL;
26612612Seric 			rcps++;
2674549Seric 			break;
2684549Seric 
2694549Seric 		  case CMDDATA:		/* data -- text of mail */
270*24943Seric 			SmtpPhase = "DATA";
2714976Seric 			if (!hasmail)
2724549Seric 			{
2734976Seric 				message("503", "Need MAIL command");
2744976Seric 				break;
2754549Seric 			}
276*24943Seric 			else if (CurEnv->e_nrcpts <= 0)
2774549Seric 			{
2784976Seric 				message("503", "Need RCPT (recipient)");
2794976Seric 				break;
2804549Seric 			}
2814976Seric 
2824976Seric 			/* collect the text of the message */
283*24943Seric 			SmtpPhase = "collect";
2844976Seric 			collect(TRUE);
2854976Seric 			if (Errors != 0)
2864976Seric 				break;
2874976Seric 
2888238Seric 			/*
2898238Seric 			**  Arrange to send to everyone.
2908238Seric 			**	If sending to multiple people, mail back
2918238Seric 			**		errors rather than reporting directly.
2928238Seric 			**	In any case, don't mail back errors for
2938238Seric 			**		anything that has happened up to
2948238Seric 			**		now (the other end will do this).
29510197Seric 			**	Truncate our transcript -- the mail has gotten
29610197Seric 			**		to us successfully, and if we have
29710197Seric 			**		to mail this back, it will be easier
29810197Seric 			**		on the reader.
2998238Seric 			**	Then send to everyone.
3008238Seric 			**	Finally give a reply code.  If an error has
3018238Seric 			**		already been given, don't mail a
3028238Seric 			**		message back.
3039339Seric 			**	We goose error returns by clearing error bit.
3048238Seric 			*/
3058238Seric 
306*24943Seric 			SmtpPhase = "delivery";
307*24943Seric 			if (CurEnv->e_nrcpts != 1)
3089378Seric 			{
3099378Seric 				HoldErrs = TRUE;
31016886Seric 				ErrorMode = EM_MAIL;
3119378Seric 			}
3129339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
31310197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
3144976Seric 
3154976Seric 			/* send to all recipients */
31614877Seric 			sendall(CurEnv, SM_DEFAULT);
3176907Seric 			CurEnv->e_to = NULL;
3184976Seric 
31923516Seric 			/* save statistics */
32023516Seric 			markstats(CurEnv, (ADDRESS *) NULL);
32123516Seric 
3228238Seric 			/* issue success if appropriate and reset */
3238238Seric 			if (Errors == 0 || HoldErrs)
3249283Seric 				message("250", "Ok");
3258238Seric 			else
3269339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3279339Seric 
3289339Seric 			/* if in a child, pop back to our parent */
3299339Seric 			if (InChild)
3309339Seric 				finis();
331*24943Seric 
332*24943Seric 			/* clean up a bit */
333*24943Seric 			hasmail = 0;
334*24943Seric 			rcps = 0;
335*24943Seric 			dropenvelope(CurEnv);
336*24943Seric 			CurEnv = newenvelope(CurEnv);
337*24943Seric 			CurEnv->e_flags = BlankEnvelope.e_flags;
3384549Seric 			break;
3394549Seric 
3404549Seric 		  case CMDRSET:		/* rset -- reset state */
3414549Seric 			message("250", "Reset state");
3429339Seric 			if (InChild)
3439339Seric 				finis();
3449339Seric 			break;
3454549Seric 
3464549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3479339Seric 			if (runinchild("SMTP-VRFY") > 0)
3489339Seric 				break;
3495003Seric 			vrfyqueue = NULL;
3507762Seric 			QuickAbort = TRUE;
3519619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3527762Seric 			if (Errors != 0)
3539339Seric 			{
3549339Seric 				if (InChild)
3559339Seric 					finis();
3567762Seric 				break;
3579339Seric 			}
3585003Seric 			while (vrfyqueue != NULL)
3595003Seric 			{
3605003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3615003Seric 				char *code;
3625003Seric 
3637685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3645003Seric 					a = a->q_next;
3655003Seric 
3667685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3675003Seric 				{
3685003Seric 					if (a != NULL)
3695003Seric 						code = "250-";
3705003Seric 					else
3715003Seric 						code = "250";
3725003Seric 					if (vrfyqueue->q_fullname == NULL)
3735003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3745003Seric 					else
3755003Seric 						message(code, "%s <%s>",
3765003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3775003Seric 				}
3785003Seric 				else if (a == NULL)
3795003Seric 					message("554", "Self destructive alias loop");
3805003Seric 				vrfyqueue = a;
3815003Seric 			}
3829339Seric 			if (InChild)
3839339Seric 				finis();
3844549Seric 			break;
3854549Seric 
3864549Seric 		  case CMDHELP:		/* help -- give user info */
3874577Seric 			if (*p == '\0')
3884577Seric 				p = "SMTP";
3894577Seric 			help(p);
3904549Seric 			break;
3914549Seric 
3924549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3934549Seric 			message("200", "OK");
3944549Seric 			break;
3954549Seric 
3964549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3974549Seric 			message("221", "%s closing connection", HostName);
3989339Seric 			if (InChild)
3999339Seric 				ExitStat = EX_QUIT;
4004549Seric 			finis();
4014549Seric 
4028544Seric 		  case CMDVERB:		/* set verbose mode */
4038544Seric 			Verbose = TRUE;
4048544Seric 			message("200", "Verbose mode");
4058544Seric 			break;
4068544Seric 
4079314Seric 		  case CMDONEX:		/* doing one transaction only */
4089378Seric 			OneXact = TRUE;
4099314Seric 			message("200", "Only one transaction");
4109314Seric 			break;
4119314Seric 
4125003Seric # ifdef DEBUG
4139339Seric 		  case CMDDBGQSHOW:	/* show queues */
4146907Seric 			printf("Send Queue=");
4156907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
4165003Seric 			break;
4177275Seric 
4187275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
4197676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
4207676Seric 			tTflag(p);
4217676Seric 			message("200", "Debug set");
4227275Seric 			break;
4237275Seric 
4247282Seric 		  case CMDDBGKILL:	/* kill the parent */
4258544Seric 			if (!iswiz())
4268544Seric 				break;
4277282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
4287282Seric 				message("200", "Mother is dead");
4297282Seric 			else
4307282Seric 				message("500", "Can't kill Mom");
4317282Seric 			break;
4328544Seric 
4338544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4348544Seric 			if (WizWord != NULL)
4358544Seric 			{
4368544Seric 				char seed[3];
4378544Seric 				extern char *crypt();
4388544Seric 
43923106Seric 				(void) strncpy(seed, WizWord, 2);
44015596Seric 				if (strcmp(WizWord, crypt(p, seed)) == 0)
4418544Seric 				{
44215596Seric 					IsWiz = TRUE;
44315596Seric 					message("200", "Please pass, oh mighty wizard");
4448544Seric 					break;
4458544Seric 				}
4468544Seric 			}
44715596Seric 			message("500", "You are no wizard!");
4488544Seric 			break;
449*24943Seric # endif DEBUG
4505003Seric 
4514549Seric 		  case CMDERROR:	/* unknown command */
4524549Seric 			message("500", "Command unrecognized");
4534549Seric 			break;
4544549Seric 
4554549Seric 		  default:
4564549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4574549Seric 			break;
4584549Seric 		}
4594549Seric 	}
4604549Seric }
4614549Seric /*
4624549Seric **  SKIPWORD -- skip a fixed word.
4634549Seric **
4644549Seric **	Parameters:
4654549Seric **		p -- place to start looking.
4664549Seric **		w -- word to skip.
4674549Seric **
4684549Seric **	Returns:
4694549Seric **		p following w.
4704549Seric **		NULL on error.
4714549Seric **
4724549Seric **	Side Effects:
4734549Seric **		clobbers the p data area.
4744549Seric */
4754549Seric 
4764549Seric static char *
4774549Seric skipword(p, w)
4784549Seric 	register char *p;
4794549Seric 	char *w;
4804549Seric {
4814549Seric 	register char *q;
4824549Seric 	extern bool sameword();
4834549Seric 
4844549Seric 	/* find beginning of word */
4854549Seric 	while (isspace(*p))
4864549Seric 		p++;
4874549Seric 	q = p;
4884549Seric 
4894549Seric 	/* find end of word */
4904549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4914549Seric 		p++;
4924549Seric 	while (isspace(*p))
4934549Seric 		*p++ = '\0';
4944549Seric 	if (*p != ':')
4954549Seric 	{
4964549Seric 	  syntax:
4974549Seric 		message("501", "Syntax error");
4984549Seric 		Errors++;
4994549Seric 		return (NULL);
5004549Seric 	}
5014549Seric 	*p++ = '\0';
5024549Seric 	while (isspace(*p))
5034549Seric 		p++;
5044549Seric 
5054549Seric 	/* see if the input word matches desired word */
5064549Seric 	if (!sameword(q, w))
5074549Seric 		goto syntax;
5084549Seric 
5094549Seric 	return (p);
5104549Seric }
5114577Seric /*
5124577Seric **  HELP -- implement the HELP command.
5134577Seric **
5144577Seric **	Parameters:
5154577Seric **		topic -- the topic we want help for.
5164577Seric **
5174577Seric **	Returns:
5184577Seric **		none.
5194577Seric **
5204577Seric **	Side Effects:
5214577Seric **		outputs the help file to message output.
5224577Seric */
5234577Seric 
5244577Seric help(topic)
5254577Seric 	char *topic;
5264577Seric {
5274577Seric 	register FILE *hf;
5284577Seric 	int len;
5294577Seric 	char buf[MAXLINE];
5304577Seric 	bool noinfo;
5314577Seric 
5328269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5334577Seric 	{
5344577Seric 		/* no help */
53511931Seric 		errno = 0;
5364577Seric 		message("502", "HELP not implemented");
5374577Seric 		return;
5384577Seric 	}
5394577Seric 
5404577Seric 	len = strlen(topic);
5414577Seric 	makelower(topic);
5424577Seric 	noinfo = TRUE;
5434577Seric 
5444577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5454577Seric 	{
5464577Seric 		if (strncmp(buf, topic, len) == 0)
5474577Seric 		{
5484577Seric 			register char *p;
5494577Seric 
5504577Seric 			p = index(buf, '\t');
5514577Seric 			if (p == NULL)
5524577Seric 				p = buf;
5534577Seric 			else
5544577Seric 				p++;
5554577Seric 			fixcrlf(p, TRUE);
5564577Seric 			message("214-", p);
5574577Seric 			noinfo = FALSE;
5584577Seric 		}
5594577Seric 	}
5604577Seric 
5614577Seric 	if (noinfo)
5624577Seric 		message("504", "HELP topic unknown");
5634577Seric 	else
5644577Seric 		message("214", "End of HELP info");
5654628Seric 	(void) fclose(hf);
5664577Seric }
5678544Seric /*
5688544Seric **  ISWIZ -- tell us if we are a wizard
5698544Seric **
5708544Seric **	If not, print a nasty message.
5718544Seric **
5728544Seric **	Parameters:
5738544Seric **		none.
5748544Seric **
5758544Seric **	Returns:
5768544Seric **		TRUE if we are a wizard.
5778544Seric **		FALSE if we are not a wizard.
5788544Seric **
5798544Seric **	Side Effects:
5808544Seric **		Prints a 500 exit stat if we are not a wizard.
5818544Seric */
5825181Seric 
583*24943Seric #ifdef DEBUG
58419038Seric 
5858544Seric bool
5868544Seric iswiz()
5878544Seric {
5888544Seric 	if (!IsWiz)
5898544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5908544Seric 	return (IsWiz);
5918544Seric }
59219038Seric 
593*24943Seric #endif DEBUG
5949339Seric /*
5959339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5969339Seric **
5979339Seric **	Parameters:
5989339Seric **		label -- a string used in error messages
5999339Seric **
6009339Seric **	Returns:
6019339Seric **		zero in the child
6029339Seric **		one in the parent
6039339Seric **
6049339Seric **	Side Effects:
6059339Seric **		none.
6069339Seric */
6078544Seric 
6089339Seric runinchild(label)
6099339Seric 	char *label;
6109339Seric {
6119339Seric 	int childpid;
6129339Seric 
61316158Seric 	if (!OneXact)
6149339Seric 	{
61516158Seric 		childpid = dofork();
61616158Seric 		if (childpid < 0)
61716158Seric 		{
61816158Seric 			syserr("%s: cannot fork", label);
61916158Seric 			return (1);
62016158Seric 		}
62116158Seric 		if (childpid > 0)
62216158Seric 		{
62316158Seric 			auto int st;
6249339Seric 
62516158Seric 			/* parent -- wait for child to complete */
62616158Seric 			st = waitfor(childpid);
62716158Seric 			if (st == -1)
62816158Seric 				syserr("%s: lost child", label);
6299339Seric 
63016158Seric 			/* if we exited on a QUIT command, complete the process */
63116158Seric 			if (st == (EX_QUIT << 8))
63216158Seric 				finis();
6339339Seric 
63416158Seric 			return (1);
63516158Seric 		}
63616158Seric 		else
63716158Seric 		{
63816158Seric 			/* child */
63916158Seric 			InChild = TRUE;
64016158Seric 		}
6419339Seric 	}
64215256Seric 
643*24943Seric 	/* child (or ONEX command specified) */
644*24943Seric 	clearenvelope(CurEnv);
645*24943Seric 
64616158Seric 	/* open alias database */
64716158Seric 	initaliases(AliasFile, FALSE);
64816158Seric 
64916158Seric 	return (0);
6509339Seric }
6519339Seric 
6525181Seric # endif SMTP
653