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*24971Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.11 (Berkeley) 09/20/85	(no SMTP)";
1923122Seric # endif not lint
205181Seric # else SMTP
214556Seric 
2223122Seric # ifndef lint
23*24971Seric static char	SccsId[] = "@(#)srvrsmtp.c	5.11 (Berkeley) 09/20/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,
8124945Seric # endif DEBUG
8224945Seric # ifdef WIZ
838544Seric 	"kill",		CMDDBGKILL,
8424945Seric # endif WIZ
858544Seric 	"wiz",		CMDDBGWIZ,
864549Seric 	NULL,		CMDERROR,
874549Seric };
884549Seric 
8924955Seric # ifdef WIZ
908544Seric bool	IsWiz = FALSE;			/* set if we are a wizard */
9124955Seric # endif WIZ
9215596Seric char	*WizWord;			/* the wizard word to compare against */
939339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
949378Seric bool	OneXact = FALSE;		/* one xaction only this run */
9511146Seric 
969339Seric #define EX_QUIT		22		/* special code for QUIT command */
978544Seric 
984549Seric smtp()
994549Seric {
1004549Seric 	register char *p;
1018544Seric 	register struct cmd *c;
1024549Seric 	char *cmd;
1034549Seric 	extern char *skipword();
1044549Seric 	extern bool sameword();
1054549Seric 	bool hasmail;			/* mail command received */
1065003Seric 	auto ADDRESS *vrfyqueue;
10712612Seric 	ADDRESS *a;
10824969Seric 	char state[100];
1098544Seric 	char inp[MAXLINE];
1107124Seric 	extern char Version[];
1117356Seric 	extern tick();
1128544Seric 	extern bool iswiz();
1139349Seric 	extern char *arpadate();
11411151Seric 	extern char *macvalue();
11512612Seric 	extern ADDRESS *recipient();
11624943Seric 	extern ENVELOPE BlankEnvelope;
11724943Seric 	extern ENVELOPE *newenvelope();
1184549Seric 
1195003Seric 	hasmail = FALSE;
1207363Seric 	if (OutChannel != stdout)
1217363Seric 	{
1227363Seric 		/* arrange for debugging output to go to remote host */
1237363Seric 		(void) close(1);
1247363Seric 		(void) dup(fileno(OutChannel));
1257363Seric 	}
12611931Seric 	settime();
127*24971Seric 	if (RealHostName != NULL)
128*24971Seric 	{
129*24971Seric 		static char status[100];
130*24971Seric 
131*24971Seric 		(void) sprintf(status, "talking to %s", RealHostName);
132*24971Seric 		setproctitle(status);
133*24971Seric 	}
13416153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
13510708Seric 	message("220", inp);
13624943Seric 	SmtpPhase = "startup";
1374549Seric 	for (;;)
1384549Seric 	{
13912612Seric 		/* arrange for backout */
14012612Seric 		if (setjmp(TopFrame) > 0 && InChild)
14112612Seric 			finis();
14212612Seric 		QuickAbort = FALSE;
14312612Seric 		HoldErrs = FALSE;
14412612Seric 
1457356Seric 		/* setup for the read */
1466907Seric 		CurEnv->e_to = NULL;
1474577Seric 		Errors = 0;
1487275Seric 		(void) fflush(stdout);
1497356Seric 
1507356Seric 		/* read the input line */
1517685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1527356Seric 
1537685Seric 		/* handle errors */
1547356Seric 		if (p == NULL)
1557356Seric 		{
1564549Seric 			/* end of file, just die */
1574558Seric 			message("421", "%s Lost input channel", HostName);
1584549Seric 			finis();
1594549Seric 		}
1604549Seric 
1614549Seric 		/* clean up end of line */
1624558Seric 		fixcrlf(inp, TRUE);
1634549Seric 
1644713Seric 		/* echo command to transcript */
1659545Seric 		if (CurEnv->e_xfp != NULL)
1669545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1674713Seric 
1684549Seric 		/* break off command */
1694549Seric 		for (p = inp; isspace(*p); p++)
1704549Seric 			continue;
1714549Seric 		cmd = p;
1724549Seric 		while (*++p != '\0' && !isspace(*p))
1734549Seric 			continue;
1744549Seric 		if (*p != '\0')
1754549Seric 			*p++ = '\0';
1764549Seric 
1774549Seric 		/* decode command */
1784549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1794549Seric 		{
1804549Seric 			if (sameword(c->cmdname, cmd))
1814549Seric 				break;
1824549Seric 		}
1834549Seric 
1844549Seric 		/* process command */
1854549Seric 		switch (c->cmdcode)
1864549Seric 		{
1874976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
18824943Seric 			SmtpPhase = "HELO";
18914877Seric 			if (sameword(p, HostName))
19014877Seric 			{
19114877Seric 				/* connected to an echo server */
19214877Seric 				message("553", "%s I refuse to talk to myself",
19314877Seric 					HostName);
19414877Seric 				break;
19514877Seric 			}
19611146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
19711146Seric 			{
19811146Seric 				char buf[MAXNAME];
19911146Seric 
20011146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
20111146Seric 				define('s', newstr(buf), CurEnv);
20211146Seric 			}
20311146Seric 			else
20411146Seric 				define('s', newstr(p), CurEnv);
2054997Seric 			message("250", "%s Hello %s, pleased to meet you",
2064997Seric 				HostName, p);
2074976Seric 			break;
2084976Seric 
2094549Seric 		  case CMDMAIL:		/* mail -- designate sender */
21024943Seric 			SmtpPhase = "MAIL";
21124943Seric 
21211151Seric 			/* force a sending host even if no HELO given */
21311151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
21411151Seric 				define('s', RealHostName, CurEnv);
21511151Seric 
2169314Seric 			/* check for validity of this command */
2174558Seric 			if (hasmail)
2184558Seric 			{
2194558Seric 				message("503", "Sender already specified");
2204558Seric 				break;
2214558Seric 			}
2229339Seric 			if (InChild)
2239339Seric 			{
2249339Seric 				syserr("Nested MAIL command");
2259339Seric 				exit(0);
2269339Seric 			}
2279339Seric 
2289339Seric 			/* fork a subprocess to process this command */
2299339Seric 			if (runinchild("SMTP-MAIL") > 0)
2309339Seric 				break;
2319339Seric 			initsys();
23224969Seric 			(void) sprintf(state, "srvrsmtp %s", CurEnv->e_id);
23324969Seric 			setproctitle(state);
2349339Seric 
2359339Seric 			/* child -- go do the processing */
2364549Seric 			p = skipword(p, "from");
2374549Seric 			if (p == NULL)
2384549Seric 				break;
2394549Seric 			setsender(p);
2404577Seric 			if (Errors == 0)
2414549Seric 			{
2424549Seric 				message("250", "Sender ok");
2434549Seric 				hasmail = TRUE;
2444549Seric 			}
2459339Seric 			else if (InChild)
2469339Seric 				finis();
2474549Seric 			break;
2484549Seric 
2494976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
25024943Seric 			SmtpPhase = "RCPT";
25112612Seric 			if (setjmp(TopFrame) > 0)
25214785Seric 			{
25314785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
25412612Seric 				break;
25514785Seric 			}
25612612Seric 			QuickAbort = TRUE;
2574549Seric 			p = skipword(p, "to");
2584549Seric 			if (p == NULL)
2594549Seric 				break;
26016140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
26112612Seric 			if (a == NULL)
26212612Seric 				break;
26316886Seric 			a->q_flags |= QPRIMARY;
26412612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
26512612Seric 			if (Errors != 0)
26612612Seric 				break;
26712612Seric 
26812612Seric 			/* no errors during parsing, but might be a duplicate */
26912612Seric 			CurEnv->e_to = p;
27012612Seric 			if (!bitset(QBADADDR, a->q_flags))
27112612Seric 				message("250", "Recipient ok");
27212612Seric 			else
2734549Seric 			{
27412612Seric 				/* punt -- should keep message in ADDRESS.... */
27512612Seric 				message("550", "Addressee unknown");
2764549Seric 			}
27712612Seric 			CurEnv->e_to = NULL;
2784549Seric 			break;
2794549Seric 
2804549Seric 		  case CMDDATA:		/* data -- text of mail */
28124943Seric 			SmtpPhase = "DATA";
2824976Seric 			if (!hasmail)
2834549Seric 			{
2844976Seric 				message("503", "Need MAIL command");
2854976Seric 				break;
2864549Seric 			}
28724943Seric 			else if (CurEnv->e_nrcpts <= 0)
2884549Seric 			{
2894976Seric 				message("503", "Need RCPT (recipient)");
2904976Seric 				break;
2914549Seric 			}
2924976Seric 
2934976Seric 			/* collect the text of the message */
29424943Seric 			SmtpPhase = "collect";
2954976Seric 			collect(TRUE);
2964976Seric 			if (Errors != 0)
2974976Seric 				break;
2984976Seric 
2998238Seric 			/*
3008238Seric 			**  Arrange to send to everyone.
3018238Seric 			**	If sending to multiple people, mail back
3028238Seric 			**		errors rather than reporting directly.
3038238Seric 			**	In any case, don't mail back errors for
3048238Seric 			**		anything that has happened up to
3058238Seric 			**		now (the other end will do this).
30610197Seric 			**	Truncate our transcript -- the mail has gotten
30710197Seric 			**		to us successfully, and if we have
30810197Seric 			**		to mail this back, it will be easier
30910197Seric 			**		on the reader.
3108238Seric 			**	Then send to everyone.
3118238Seric 			**	Finally give a reply code.  If an error has
3128238Seric 			**		already been given, don't mail a
3138238Seric 			**		message back.
3149339Seric 			**	We goose error returns by clearing error bit.
3158238Seric 			*/
3168238Seric 
31724943Seric 			SmtpPhase = "delivery";
31824943Seric 			if (CurEnv->e_nrcpts != 1)
3199378Seric 			{
3209378Seric 				HoldErrs = TRUE;
32116886Seric 				ErrorMode = EM_MAIL;
3229378Seric 			}
3239339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
32410197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
3254976Seric 
3264976Seric 			/* send to all recipients */
32714877Seric 			sendall(CurEnv, SM_DEFAULT);
3286907Seric 			CurEnv->e_to = NULL;
3294976Seric 
33023516Seric 			/* save statistics */
33123516Seric 			markstats(CurEnv, (ADDRESS *) NULL);
33223516Seric 
3338238Seric 			/* issue success if appropriate and reset */
3348238Seric 			if (Errors == 0 || HoldErrs)
3359283Seric 				message("250", "Ok");
3368238Seric 			else
3379339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3389339Seric 
3399339Seric 			/* if in a child, pop back to our parent */
3409339Seric 			if (InChild)
3419339Seric 				finis();
34224943Seric 
34324943Seric 			/* clean up a bit */
34424943Seric 			hasmail = 0;
34524943Seric 			dropenvelope(CurEnv);
34624943Seric 			CurEnv = newenvelope(CurEnv);
34724943Seric 			CurEnv->e_flags = BlankEnvelope.e_flags;
3484549Seric 			break;
3494549Seric 
3504549Seric 		  case CMDRSET:		/* rset -- reset state */
3514549Seric 			message("250", "Reset state");
3529339Seric 			if (InChild)
3539339Seric 				finis();
3549339Seric 			break;
3554549Seric 
3564549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3579339Seric 			if (runinchild("SMTP-VRFY") > 0)
3589339Seric 				break;
35924969Seric 			setproctitle("SMTP-VRFY");
3605003Seric 			vrfyqueue = NULL;
3617762Seric 			QuickAbort = TRUE;
3629619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3637762Seric 			if (Errors != 0)
3649339Seric 			{
3659339Seric 				if (InChild)
3669339Seric 					finis();
3677762Seric 				break;
3689339Seric 			}
3695003Seric 			while (vrfyqueue != NULL)
3705003Seric 			{
3715003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3725003Seric 				char *code;
3735003Seric 
3747685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3755003Seric 					a = a->q_next;
3765003Seric 
3777685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3785003Seric 				{
3795003Seric 					if (a != NULL)
3805003Seric 						code = "250-";
3815003Seric 					else
3825003Seric 						code = "250";
3835003Seric 					if (vrfyqueue->q_fullname == NULL)
3845003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3855003Seric 					else
3865003Seric 						message(code, "%s <%s>",
3875003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3885003Seric 				}
3895003Seric 				else if (a == NULL)
3905003Seric 					message("554", "Self destructive alias loop");
3915003Seric 				vrfyqueue = a;
3925003Seric 			}
3939339Seric 			if (InChild)
3949339Seric 				finis();
3954549Seric 			break;
3964549Seric 
3974549Seric 		  case CMDHELP:		/* help -- give user info */
3984577Seric 			if (*p == '\0')
3994577Seric 				p = "SMTP";
4004577Seric 			help(p);
4014549Seric 			break;
4024549Seric 
4034549Seric 		  case CMDNOOP:		/* noop -- do nothing */
4044549Seric 			message("200", "OK");
4054549Seric 			break;
4064549Seric 
4074549Seric 		  case CMDQUIT:		/* quit -- leave mail */
4084549Seric 			message("221", "%s closing connection", HostName);
4099339Seric 			if (InChild)
4109339Seric 				ExitStat = EX_QUIT;
4114549Seric 			finis();
4124549Seric 
4138544Seric 		  case CMDVERB:		/* set verbose mode */
4148544Seric 			Verbose = TRUE;
4158544Seric 			message("200", "Verbose mode");
4168544Seric 			break;
4178544Seric 
4189314Seric 		  case CMDONEX:		/* doing one transaction only */
4199378Seric 			OneXact = TRUE;
4209314Seric 			message("200", "Only one transaction");
4219314Seric 			break;
4229314Seric 
4235003Seric # ifdef DEBUG
4249339Seric 		  case CMDDBGQSHOW:	/* show queues */
4256907Seric 			printf("Send Queue=");
4266907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
4275003Seric 			break;
4287275Seric 
4297275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
4307676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
4317676Seric 			tTflag(p);
4327676Seric 			message("200", "Debug set");
4337275Seric 			break;
43424945Seric # endif DEBUG
4357275Seric 
43624945Seric # ifdef WIZ
4377282Seric 		  case CMDDBGKILL:	/* kill the parent */
4388544Seric 			if (!iswiz())
4398544Seric 				break;
4407282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
4417282Seric 				message("200", "Mother is dead");
4427282Seric 			else
4437282Seric 				message("500", "Can't kill Mom");
4447282Seric 			break;
4458544Seric 
4468544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4478544Seric 			if (WizWord != NULL)
4488544Seric 			{
4498544Seric 				char seed[3];
4508544Seric 				extern char *crypt();
4518544Seric 
45223106Seric 				(void) strncpy(seed, WizWord, 2);
45315596Seric 				if (strcmp(WizWord, crypt(p, seed)) == 0)
4548544Seric 				{
45515596Seric 					IsWiz = TRUE;
45615596Seric 					message("200", "Please pass, oh mighty wizard");
4578544Seric 					break;
4588544Seric 				}
4598544Seric 			}
46015596Seric 			message("500", "You are no wizard!");
4618544Seric 			break;
4625003Seric 
46324945Seric # else WIZ
46424945Seric 		  case CMDDBGWIZ:	/* try to become a wizard */
46524945Seric 			message("500", "You wascal wabbit!  Wandering wizards won't win!");
46624945Seric 			break;
46724945Seric # endif WIZ
46824945Seric 
4694549Seric 		  case CMDERROR:	/* unknown command */
4704549Seric 			message("500", "Command unrecognized");
4714549Seric 			break;
4724549Seric 
4734549Seric 		  default:
4744549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4754549Seric 			break;
4764549Seric 		}
4774549Seric 	}
4784549Seric }
4794549Seric /*
4804549Seric **  SKIPWORD -- skip a fixed word.
4814549Seric **
4824549Seric **	Parameters:
4834549Seric **		p -- place to start looking.
4844549Seric **		w -- word to skip.
4854549Seric **
4864549Seric **	Returns:
4874549Seric **		p following w.
4884549Seric **		NULL on error.
4894549Seric **
4904549Seric **	Side Effects:
4914549Seric **		clobbers the p data area.
4924549Seric */
4934549Seric 
4944549Seric static char *
4954549Seric skipword(p, w)
4964549Seric 	register char *p;
4974549Seric 	char *w;
4984549Seric {
4994549Seric 	register char *q;
5004549Seric 	extern bool sameword();
5014549Seric 
5024549Seric 	/* find beginning of word */
5034549Seric 	while (isspace(*p))
5044549Seric 		p++;
5054549Seric 	q = p;
5064549Seric 
5074549Seric 	/* find end of word */
5084549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
5094549Seric 		p++;
5104549Seric 	while (isspace(*p))
5114549Seric 		*p++ = '\0';
5124549Seric 	if (*p != ':')
5134549Seric 	{
5144549Seric 	  syntax:
5154549Seric 		message("501", "Syntax error");
5164549Seric 		Errors++;
5174549Seric 		return (NULL);
5184549Seric 	}
5194549Seric 	*p++ = '\0';
5204549Seric 	while (isspace(*p))
5214549Seric 		p++;
5224549Seric 
5234549Seric 	/* see if the input word matches desired word */
5244549Seric 	if (!sameword(q, w))
5254549Seric 		goto syntax;
5264549Seric 
5274549Seric 	return (p);
5284549Seric }
5294577Seric /*
5304577Seric **  HELP -- implement the HELP command.
5314577Seric **
5324577Seric **	Parameters:
5334577Seric **		topic -- the topic we want help for.
5344577Seric **
5354577Seric **	Returns:
5364577Seric **		none.
5374577Seric **
5384577Seric **	Side Effects:
5394577Seric **		outputs the help file to message output.
5404577Seric */
5414577Seric 
5424577Seric help(topic)
5434577Seric 	char *topic;
5444577Seric {
5454577Seric 	register FILE *hf;
5464577Seric 	int len;
5474577Seric 	char buf[MAXLINE];
5484577Seric 	bool noinfo;
5494577Seric 
5508269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5514577Seric 	{
5524577Seric 		/* no help */
55311931Seric 		errno = 0;
5544577Seric 		message("502", "HELP not implemented");
5554577Seric 		return;
5564577Seric 	}
5574577Seric 
5584577Seric 	len = strlen(topic);
5594577Seric 	makelower(topic);
5604577Seric 	noinfo = TRUE;
5614577Seric 
5624577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5634577Seric 	{
5644577Seric 		if (strncmp(buf, topic, len) == 0)
5654577Seric 		{
5664577Seric 			register char *p;
5674577Seric 
5684577Seric 			p = index(buf, '\t');
5694577Seric 			if (p == NULL)
5704577Seric 				p = buf;
5714577Seric 			else
5724577Seric 				p++;
5734577Seric 			fixcrlf(p, TRUE);
5744577Seric 			message("214-", p);
5754577Seric 			noinfo = FALSE;
5764577Seric 		}
5774577Seric 	}
5784577Seric 
5794577Seric 	if (noinfo)
5804577Seric 		message("504", "HELP topic unknown");
5814577Seric 	else
5824577Seric 		message("214", "End of HELP info");
5834628Seric 	(void) fclose(hf);
5844577Seric }
5858544Seric /*
5868544Seric **  ISWIZ -- tell us if we are a wizard
5878544Seric **
5888544Seric **	If not, print a nasty message.
5898544Seric **
5908544Seric **	Parameters:
5918544Seric **		none.
5928544Seric **
5938544Seric **	Returns:
5948544Seric **		TRUE if we are a wizard.
5958544Seric **		FALSE if we are not a wizard.
5968544Seric **
5978544Seric **	Side Effects:
5988544Seric **		Prints a 500 exit stat if we are not a wizard.
5998544Seric */
6005181Seric 
60124945Seric #ifdef WIZ
60219038Seric 
6038544Seric bool
6048544Seric iswiz()
6058544Seric {
6068544Seric 	if (!IsWiz)
6078544Seric 		message("500", "Mere mortals musn't mutter that mantra");
6088544Seric 	return (IsWiz);
6098544Seric }
61019038Seric 
61124945Seric #endif WIZ
6129339Seric /*
6139339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
6149339Seric **
6159339Seric **	Parameters:
6169339Seric **		label -- a string used in error messages
6179339Seric **
6189339Seric **	Returns:
6199339Seric **		zero in the child
6209339Seric **		one in the parent
6219339Seric **
6229339Seric **	Side Effects:
6239339Seric **		none.
6249339Seric */
6258544Seric 
6269339Seric runinchild(label)
6279339Seric 	char *label;
6289339Seric {
6299339Seric 	int childpid;
6309339Seric 
63116158Seric 	if (!OneXact)
6329339Seric 	{
63316158Seric 		childpid = dofork();
63416158Seric 		if (childpid < 0)
63516158Seric 		{
63616158Seric 			syserr("%s: cannot fork", label);
63716158Seric 			return (1);
63816158Seric 		}
63916158Seric 		if (childpid > 0)
64016158Seric 		{
64116158Seric 			auto int st;
6429339Seric 
64316158Seric 			/* parent -- wait for child to complete */
64416158Seric 			st = waitfor(childpid);
64516158Seric 			if (st == -1)
64616158Seric 				syserr("%s: lost child", label);
6479339Seric 
64816158Seric 			/* if we exited on a QUIT command, complete the process */
64916158Seric 			if (st == (EX_QUIT << 8))
65016158Seric 				finis();
6519339Seric 
65216158Seric 			return (1);
65316158Seric 		}
65416158Seric 		else
65516158Seric 		{
65616158Seric 			/* child */
65716158Seric 			InChild = TRUE;
65824945Seric 			clearenvelope(CurEnv);
65916158Seric 		}
6609339Seric 	}
66115256Seric 
66216158Seric 	/* open alias database */
66316158Seric 	initaliases(AliasFile, FALSE);
66416158Seric 
66516158Seric 	return (0);
6669339Seric }
6679339Seric 
6685181Seric # endif SMTP
669