122712Sdist /*
234921Sbostic  * Copyright (c) 1983 Eric P. Allman
333731Sbostic  * Copyright (c) 1988 Regents of the University of California.
433731Sbostic  * All rights reserved.
533731Sbostic  *
642829Sbostic  * %sccs.include.redist.c%
733731Sbostic  */
822712Sdist 
933731Sbostic # include "sendmail.h"
1022712Sdist 
1133731Sbostic #ifndef lint
1233731Sbostic #ifdef SMTP
13*55360Seric static char sccsid[] = "@(#)srvrsmtp.c	5.37 (Berkeley) 07/19/92 (with SMTP)";
1433731Sbostic #else
15*55360Seric static char sccsid[] = "@(#)srvrsmtp.c	5.37 (Berkeley) 07/19/92 (without SMTP)";
1633731Sbostic #endif
1733731Sbostic #endif /* not lint */
1833731Sbostic 
199339Seric # include <errno.h>
2011728Seric # include <signal.h>
214549Seric 
2233731Sbostic # ifdef SMTP
234556Seric 
244549Seric /*
254549Seric **  SMTP -- run the SMTP protocol.
264549Seric **
274549Seric **	Parameters:
284549Seric **		none.
294549Seric **
304549Seric **	Returns:
314549Seric **		never.
324549Seric **
334549Seric **	Side Effects:
344549Seric **		Reads commands from the input channel and processes
354549Seric **			them.
364549Seric */
374549Seric 
384549Seric struct cmd
394549Seric {
404549Seric 	char	*cmdname;	/* command name */
414549Seric 	int	cmdcode;	/* internal code, see below */
424549Seric };
434549Seric 
444549Seric /* values for cmdcode */
454549Seric # define CMDERROR	0	/* bad command */
464549Seric # define CMDMAIL	1	/* mail -- designate sender */
474976Seric # define CMDRCPT	2	/* rcpt -- designate recipient */
484549Seric # define CMDDATA	3	/* data -- send message text */
499339Seric # define CMDRSET	4	/* rset -- reset state */
509339Seric # define CMDVRFY	5	/* vrfy -- verify address */
519339Seric # define CMDHELP	6	/* help -- give usage info */
529339Seric # define CMDNOOP	7	/* noop -- do nothing */
539339Seric # define CMDQUIT	8	/* quit -- close connection and die */
549339Seric # define CMDHELO	9	/* helo -- be polite */
5536230Skarels # define CMDONEX	10	/* onex -- sending one transaction only */
5636230Skarels # define CMDVERB	11	/* verb -- go into verbose mode */
5736230Skarels /* debugging-only commands, only enabled if SMTPDEBUG is defined */
5836230Skarels # define CMDDBGQSHOW	12	/* showq -- show send queue */
5936230Skarels # define CMDDBGDEBUG	13	/* debug -- set debug mode */
604549Seric 
614549Seric static struct cmd	CmdTab[] =
624549Seric {
634549Seric 	"mail",		CMDMAIL,
644976Seric 	"rcpt",		CMDRCPT,
654549Seric 	"data",		CMDDATA,
664549Seric 	"rset",		CMDRSET,
674549Seric 	"vrfy",		CMDVRFY,
687762Seric 	"expn",		CMDVRFY,
694549Seric 	"help",		CMDHELP,
704549Seric 	"noop",		CMDNOOP,
714549Seric 	"quit",		CMDQUIT,
724976Seric 	"helo",		CMDHELO,
738544Seric 	"verb",		CMDVERB,
749314Seric 	"onex",		CMDONEX,
7536230Skarels 	/*
7636230Skarels 	 * remaining commands are here only
7736230Skarels 	 * to trap and log attempts to use them
7836230Skarels 	 */
799339Seric 	"showq",	CMDDBGQSHOW,
808544Seric 	"debug",	CMDDBGDEBUG,
814549Seric 	NULL,		CMDERROR,
824549Seric };
834549Seric 
849339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
859378Seric bool	OneXact = FALSE;		/* one xaction only this run */
8611146Seric 
879339Seric #define EX_QUIT		22		/* special code for QUIT command */
888544Seric 
8955012Seric smtp(e)
9055012Seric 	register ENVELOPE *e;
914549Seric {
924549Seric 	register char *p;
938544Seric 	register struct cmd *c;
944549Seric 	char *cmd;
9546928Sbostic 	static char *skipword();
964549Seric 	bool hasmail;			/* mail command received */
975003Seric 	auto ADDRESS *vrfyqueue;
9812612Seric 	ADDRESS *a;
9930448Seric 	char *sendinghost;
1008544Seric 	char inp[MAXLINE];
10124981Seric 	char cmdbuf[100];
1027124Seric 	extern char Version[];
10311151Seric 	extern char *macvalue();
10412612Seric 	extern ADDRESS *recipient();
10524943Seric 	extern ENVELOPE BlankEnvelope;
10624943Seric 	extern ENVELOPE *newenvelope();
1074549Seric 
1085003Seric 	hasmail = FALSE;
1097363Seric 	if (OutChannel != stdout)
1107363Seric 	{
1117363Seric 		/* arrange for debugging output to go to remote host */
1127363Seric 		(void) close(1);
1137363Seric 		(void) dup(fileno(OutChannel));
1147363Seric 	}
11555012Seric 	settime(e);
11624971Seric 	if (RealHostName != NULL)
11725050Seric 	{
11825050Seric 		CurHostName = RealHostName;
11925050Seric 		setproctitle("srvrsmtp %s", CurHostName);
12025050Seric 	}
12125050Seric 	else
12225050Seric 	{
12325050Seric 		/* this must be us!! */
12425050Seric 		CurHostName = MyHostName;
12525050Seric 	}
12655012Seric 	expand("\001e", inp, &inp[sizeof inp], e);
127*55360Seric 	message("220", "%s", inp);
12824943Seric 	SmtpPhase = "startup";
12930448Seric 	sendinghost = NULL;
1304549Seric 	for (;;)
1314549Seric 	{
13212612Seric 		/* arrange for backout */
13312612Seric 		if (setjmp(TopFrame) > 0 && InChild)
13412612Seric 			finis();
13512612Seric 		QuickAbort = FALSE;
13612612Seric 		HoldErrs = FALSE;
13751951Seric 		LogUsrErrs = FALSE;
13812612Seric 
1397356Seric 		/* setup for the read */
14055012Seric 		e->e_to = NULL;
1414577Seric 		Errors = 0;
1427275Seric 		(void) fflush(stdout);
1437356Seric 
1447356Seric 		/* read the input line */
1457685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1467356Seric 
1477685Seric 		/* handle errors */
1487356Seric 		if (p == NULL)
1497356Seric 		{
1504549Seric 			/* end of file, just die */
15136230Skarels 			message("421", "%s Lost input channel from %s",
15225050Seric 				MyHostName, CurHostName);
1534549Seric 			finis();
1544549Seric 		}
1554549Seric 
1564549Seric 		/* clean up end of line */
1574558Seric 		fixcrlf(inp, TRUE);
1584549Seric 
1594713Seric 		/* echo command to transcript */
16055012Seric 		if (e->e_xfp != NULL)
16155012Seric 			fprintf(e->e_xfp, "<<< %s\n", inp);
1624713Seric 
1634549Seric 		/* break off command */
1644549Seric 		for (p = inp; isspace(*p); p++)
1654549Seric 			continue;
1664549Seric 		cmd = p;
16724981Seric 		for (cmd = cmdbuf; *p != '\0' && !isspace(*p); )
16824981Seric 			*cmd++ = *p++;
16924981Seric 		*cmd = '\0';
1704549Seric 
17125691Seric 		/* throw away leading whitespace */
17225691Seric 		while (isspace(*p))
17325691Seric 			p++;
17425691Seric 
1754549Seric 		/* decode command */
1764549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1774549Seric 		{
17833725Sbostic 			if (!strcasecmp(c->cmdname, cmdbuf))
1794549Seric 				break;
1804549Seric 		}
1814549Seric 
18251954Seric 		/* reset errors */
18351954Seric 		errno = 0;
18451954Seric 
1854549Seric 		/* process command */
1864549Seric 		switch (c->cmdcode)
1874549Seric 		{
1884976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
18924943Seric 			SmtpPhase = "HELO";
19025050Seric 			setproctitle("%s: %s", CurHostName, inp);
19133725Sbostic 			if (!strcasecmp(p, MyHostName))
19214877Seric 			{
19336230Skarels 				/*
19436230Skarels 				 * didn't know about alias,
19536230Skarels 				 * or connected to an echo server
19636230Skarels 				 */
19747570Seric 				message("553", "%s config error: mail loops back to myself",
19847570Seric 					MyHostName);
19914877Seric 				break;
20014877Seric 			}
20133725Sbostic 			if (RealHostName != NULL && strcasecmp(p, RealHostName))
20211146Seric 			{
20324981Seric 				char hostbuf[MAXNAME];
20411146Seric 
20524981Seric 				(void) sprintf(hostbuf, "%s (%s)", p, RealHostName);
20630448Seric 				sendinghost = newstr(hostbuf);
20711146Seric 			}
20811146Seric 			else
20930448Seric 				sendinghost = newstr(p);
2104997Seric 			message("250", "%s Hello %s, pleased to meet you",
21136230Skarels 				MyHostName, sendinghost);
2124976Seric 			break;
2134976Seric 
2144549Seric 		  case CMDMAIL:		/* mail -- designate sender */
21524943Seric 			SmtpPhase = "MAIL";
21624943Seric 
21711151Seric 			/* force a sending host even if no HELO given */
21855012Seric 			if (RealHostName != NULL && macvalue('s', e) == NULL)
21930448Seric 				sendinghost = RealHostName;
22011151Seric 
2219314Seric 			/* check for validity of this command */
2224558Seric 			if (hasmail)
2234558Seric 			{
2244558Seric 				message("503", "Sender already specified");
2254558Seric 				break;
2264558Seric 			}
2279339Seric 			if (InChild)
2289339Seric 			{
22936230Skarels 				errno = 0;
2309339Seric 				syserr("Nested MAIL command");
2319339Seric 				exit(0);
2329339Seric 			}
2339339Seric 
2349339Seric 			/* fork a subprocess to process this command */
23555012Seric 			if (runinchild("SMTP-MAIL", e) > 0)
2369339Seric 				break;
23755012Seric 			define('s', sendinghost, e);
23855012Seric 			define('r', "SMTP", e);
23955012Seric 			initsys(e);
24055012Seric 			setproctitle("%s %s: %s", e->e_id,
24125050Seric 				CurHostName, inp);
2429339Seric 
2439339Seric 			/* child -- go do the processing */
2444549Seric 			p = skipword(p, "from");
2454549Seric 			if (p == NULL)
2464549Seric 				break;
24755012Seric 			setsender(p, e);
2484577Seric 			if (Errors == 0)
2494549Seric 			{
2504549Seric 				message("250", "Sender ok");
2514549Seric 				hasmail = TRUE;
2524549Seric 			}
2539339Seric 			else if (InChild)
2549339Seric 				finis();
2554549Seric 			break;
2564549Seric 
2574976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
25824943Seric 			SmtpPhase = "RCPT";
25955012Seric 			setproctitle("%s %s: %s", e->e_id,
26025050Seric 				CurHostName, inp);
26112612Seric 			if (setjmp(TopFrame) > 0)
26214785Seric 			{
26355012Seric 				e->e_flags &= ~EF_FATALERRS;
26412612Seric 				break;
26514785Seric 			}
26612612Seric 			QuickAbort = TRUE;
26751951Seric 			LogUsrErrs = TRUE;
2684549Seric 			p = skipword(p, "to");
2694549Seric 			if (p == NULL)
2704549Seric 				break;
27155012Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0', e);
27212612Seric 			if (a == NULL)
27312612Seric 				break;
27416886Seric 			a->q_flags |= QPRIMARY;
27555012Seric 			a = recipient(a, &e->e_sendqueue, e);
27612612Seric 			if (Errors != 0)
27712612Seric 				break;
27812612Seric 
27912612Seric 			/* no errors during parsing, but might be a duplicate */
28055012Seric 			e->e_to = p;
28112612Seric 			if (!bitset(QBADADDR, a->q_flags))
28212612Seric 				message("250", "Recipient ok");
28312612Seric 			else
2844549Seric 			{
28512612Seric 				/* punt -- should keep message in ADDRESS.... */
28612612Seric 				message("550", "Addressee unknown");
2874549Seric 			}
28855012Seric 			e->e_to = NULL;
2894549Seric 			break;
2904549Seric 
2914549Seric 		  case CMDDATA:		/* data -- text of mail */
29224943Seric 			SmtpPhase = "DATA";
2934976Seric 			if (!hasmail)
2944549Seric 			{
2954976Seric 				message("503", "Need MAIL command");
2964976Seric 				break;
2974549Seric 			}
29855012Seric 			else if (e->e_nrcpts <= 0)
2994549Seric 			{
3004976Seric 				message("503", "Need RCPT (recipient)");
3014976Seric 				break;
3024549Seric 			}
3034976Seric 
3044976Seric 			/* collect the text of the message */
30524943Seric 			SmtpPhase = "collect";
30655012Seric 			setproctitle("%s %s: %s", e->e_id,
30725050Seric 				CurHostName, inp);
30855012Seric 			collect(TRUE, e);
3094976Seric 			if (Errors != 0)
3104976Seric 				break;
3114976Seric 
3128238Seric 			/*
3138238Seric 			**  Arrange to send to everyone.
3148238Seric 			**	If sending to multiple people, mail back
3158238Seric 			**		errors rather than reporting directly.
3168238Seric 			**	In any case, don't mail back errors for
3178238Seric 			**		anything that has happened up to
3188238Seric 			**		now (the other end will do this).
31910197Seric 			**	Truncate our transcript -- the mail has gotten
32010197Seric 			**		to us successfully, and if we have
32110197Seric 			**		to mail this back, it will be easier
32210197Seric 			**		on the reader.
3238238Seric 			**	Then send to everyone.
3248238Seric 			**	Finally give a reply code.  If an error has
3258238Seric 			**		already been given, don't mail a
3268238Seric 			**		message back.
3279339Seric 			**	We goose error returns by clearing error bit.
3288238Seric 			*/
3298238Seric 
33024943Seric 			SmtpPhase = "delivery";
33155012Seric 			if (e->e_nrcpts != 1)
3329378Seric 			{
3339378Seric 				HoldErrs = TRUE;
33416886Seric 				ErrorMode = EM_MAIL;
3359378Seric 			}
33655012Seric 			e->e_flags &= ~EF_FATALERRS;
33755012Seric 			e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp);
3384976Seric 
3394976Seric 			/* send to all recipients */
34055012Seric 			sendall(e, SM_DEFAULT);
34155012Seric 			e->e_to = NULL;
3424976Seric 
34323516Seric 			/* save statistics */
34455012Seric 			markstats(e, (ADDRESS *) NULL);
34523516Seric 
3468238Seric 			/* issue success if appropriate and reset */
3478238Seric 			if (Errors == 0 || HoldErrs)
3489283Seric 				message("250", "Ok");
3498238Seric 			else
35055012Seric 				e->e_flags &= ~EF_FATALERRS;
3519339Seric 
3529339Seric 			/* if in a child, pop back to our parent */
3539339Seric 			if (InChild)
3549339Seric 				finis();
35524943Seric 
35624943Seric 			/* clean up a bit */
35724943Seric 			hasmail = 0;
35855012Seric 			dropenvelope(e);
35955012Seric 			CurEnv = e = newenvelope(e);
36055012Seric 			e->e_flags = BlankEnvelope.e_flags;
3614549Seric 			break;
3624549Seric 
3634549Seric 		  case CMDRSET:		/* rset -- reset state */
3644549Seric 			message("250", "Reset state");
3659339Seric 			if (InChild)
3669339Seric 				finis();
3679339Seric 			break;
3684549Seric 
3694549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
37055012Seric 			if (runinchild("SMTP-VRFY", e) > 0)
3719339Seric 				break;
37225050Seric 			setproctitle("%s: %s", CurHostName, inp);
37355173Seric #ifdef LOG
37455173Seric 			if (LogLevel >= 9)
37555173Seric 				syslog(LOG_INFO, "%s: %s", CurHostName, inp);
37655173Seric #endif
3775003Seric 			vrfyqueue = NULL;
3787762Seric 			QuickAbort = TRUE;
37955012Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue, e);
3807762Seric 			if (Errors != 0)
3819339Seric 			{
3829339Seric 				if (InChild)
3839339Seric 					finis();
3847762Seric 				break;
3859339Seric 			}
3865003Seric 			while (vrfyqueue != NULL)
3875003Seric 			{
3885003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3895003Seric 				char *code;
3905003Seric 
3917685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3925003Seric 					a = a->q_next;
3935003Seric 
3947685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3955003Seric 				{
3965003Seric 					if (a != NULL)
3975003Seric 						code = "250-";
3985003Seric 					else
3995003Seric 						code = "250";
4005003Seric 					if (vrfyqueue->q_fullname == NULL)
4015003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
4025003Seric 					else
4035003Seric 						message(code, "%s <%s>",
4045003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
4055003Seric 				}
4065003Seric 				else if (a == NULL)
4075003Seric 					message("554", "Self destructive alias loop");
4085003Seric 				vrfyqueue = a;
4095003Seric 			}
4109339Seric 			if (InChild)
4119339Seric 				finis();
4124549Seric 			break;
4134549Seric 
4144549Seric 		  case CMDHELP:		/* help -- give user info */
4154577Seric 			help(p);
4164549Seric 			break;
4174549Seric 
4184549Seric 		  case CMDNOOP:		/* noop -- do nothing */
4194549Seric 			message("200", "OK");
4204549Seric 			break;
4214549Seric 
4224549Seric 		  case CMDQUIT:		/* quit -- leave mail */
42325050Seric 			message("221", "%s closing connection", MyHostName);
4249339Seric 			if (InChild)
4259339Seric 				ExitStat = EX_QUIT;
4264549Seric 			finis();
4274549Seric 
4288544Seric 		  case CMDVERB:		/* set verbose mode */
4298544Seric 			Verbose = TRUE;
43025025Seric 			SendMode = SM_DELIVER;
4318544Seric 			message("200", "Verbose mode");
4328544Seric 			break;
4338544Seric 
4349314Seric 		  case CMDONEX:		/* doing one transaction only */
4359378Seric 			OneXact = TRUE;
4369314Seric 			message("200", "Only one transaction");
4379314Seric 			break;
4389314Seric 
43936230Skarels # ifdef SMTPDEBUG
4409339Seric 		  case CMDDBGQSHOW:	/* show queues */
4416907Seric 			printf("Send Queue=");
44255012Seric 			printaddr(e->e_sendqueue, TRUE);
4435003Seric 			break;
4447275Seric 
4457275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
4467676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
4477676Seric 			tTflag(p);
4487676Seric 			message("200", "Debug set");
4497275Seric 			break;
4507275Seric 
45136230Skarels # else /* not SMTPDEBUG */
45224945Seric 
45336230Skarels 		  case CMDDBGQSHOW:	/* show queues */
45436230Skarels 		  case CMDDBGDEBUG:	/* set debug mode */
45536233Skarels # ifdef LOG
45636233Skarels 			if (RealHostName != NULL && LogLevel > 0)
45736230Skarels 				syslog(LOG_NOTICE,
45836230Skarels 				    "\"%s\" command from %s (%s)\n",
45936230Skarels 				    c->cmdname, RealHostName,
46036230Skarels 				    inet_ntoa(RealHostAddr.sin_addr));
46136233Skarels # endif
46236230Skarels 			/* FALL THROUGH */
46336230Skarels # endif /* SMTPDEBUG */
46436230Skarels 
4654549Seric 		  case CMDERROR:	/* unknown command */
4664549Seric 			message("500", "Command unrecognized");
4674549Seric 			break;
4684549Seric 
4694549Seric 		  default:
47036230Skarels 			errno = 0;
4714549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4724549Seric 			break;
4734549Seric 		}
4744549Seric 	}
4754549Seric }
4764549Seric /*
4774549Seric **  SKIPWORD -- skip a fixed word.
4784549Seric **
4794549Seric **	Parameters:
4804549Seric **		p -- place to start looking.
4814549Seric **		w -- word to skip.
4824549Seric **
4834549Seric **	Returns:
4844549Seric **		p following w.
4854549Seric **		NULL on error.
4864549Seric **
4874549Seric **	Side Effects:
4884549Seric **		clobbers the p data area.
4894549Seric */
4904549Seric 
4914549Seric static char *
4924549Seric skipword(p, w)
4934549Seric 	register char *p;
4944549Seric 	char *w;
4954549Seric {
4964549Seric 	register char *q;
4974549Seric 
4984549Seric 	/* find beginning of word */
4994549Seric 	while (isspace(*p))
5004549Seric 		p++;
5014549Seric 	q = p;
5024549Seric 
5034549Seric 	/* find end of word */
5044549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
5054549Seric 		p++;
5064549Seric 	while (isspace(*p))
5074549Seric 		*p++ = '\0';
5084549Seric 	if (*p != ':')
5094549Seric 	{
5104549Seric 	  syntax:
5114549Seric 		message("501", "Syntax error");
5124549Seric 		Errors++;
5134549Seric 		return (NULL);
5144549Seric 	}
5154549Seric 	*p++ = '\0';
5164549Seric 	while (isspace(*p))
5174549Seric 		p++;
5184549Seric 
5194549Seric 	/* see if the input word matches desired word */
52033725Sbostic 	if (strcasecmp(q, w))
5214549Seric 		goto syntax;
5224549Seric 
5234549Seric 	return (p);
5244549Seric }
5254577Seric /*
5264577Seric **  HELP -- implement the HELP command.
5274577Seric **
5284577Seric **	Parameters:
5294577Seric **		topic -- the topic we want help for.
5304577Seric **
5314577Seric **	Returns:
5324577Seric **		none.
5334577Seric **
5344577Seric **	Side Effects:
5354577Seric **		outputs the help file to message output.
5364577Seric */
5374577Seric 
5384577Seric help(topic)
5394577Seric 	char *topic;
5404577Seric {
5414577Seric 	register FILE *hf;
5424577Seric 	int len;
5434577Seric 	char buf[MAXLINE];
5444577Seric 	bool noinfo;
5454577Seric 
5468269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5474577Seric 	{
5484577Seric 		/* no help */
54911931Seric 		errno = 0;
5504577Seric 		message("502", "HELP not implemented");
5514577Seric 		return;
5524577Seric 	}
5534577Seric 
55449669Seric 	if (topic == NULL || *topic == '\0')
55549669Seric 		topic = "smtp";
55649669Seric 	else
55749669Seric 		makelower(topic);
55849669Seric 
5594577Seric 	len = strlen(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 /*
5869339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5879339Seric **
5889339Seric **	Parameters:
5899339Seric **		label -- a string used in error messages
5909339Seric **
5919339Seric **	Returns:
5929339Seric **		zero in the child
5939339Seric **		one in the parent
5949339Seric **
5959339Seric **	Side Effects:
5969339Seric **		none.
5979339Seric */
5988544Seric 
59955012Seric runinchild(label, e)
6009339Seric 	char *label;
60155012Seric 	register ENVELOPE *e;
6029339Seric {
6039339Seric 	int childpid;
6049339Seric 
60516158Seric 	if (!OneXact)
6069339Seric 	{
60716158Seric 		childpid = dofork();
60816158Seric 		if (childpid < 0)
60916158Seric 		{
61016158Seric 			syserr("%s: cannot fork", label);
61116158Seric 			return (1);
61216158Seric 		}
61316158Seric 		if (childpid > 0)
61416158Seric 		{
61516158Seric 			auto int st;
6169339Seric 
61716158Seric 			/* parent -- wait for child to complete */
61816158Seric 			st = waitfor(childpid);
61916158Seric 			if (st == -1)
62016158Seric 				syserr("%s: lost child", label);
6219339Seric 
62216158Seric 			/* if we exited on a QUIT command, complete the process */
62316158Seric 			if (st == (EX_QUIT << 8))
62416158Seric 				finis();
6259339Seric 
62616158Seric 			return (1);
62716158Seric 		}
62816158Seric 		else
62916158Seric 		{
63016158Seric 			/* child */
63116158Seric 			InChild = TRUE;
63225050Seric 			QuickAbort = FALSE;
63355012Seric 			clearenvelope(e, FALSE);
63416158Seric 		}
6359339Seric 	}
63615256Seric 
63716158Seric 	/* open alias database */
63855012Seric 	initaliases(AliasFile, FALSE, e);
63916158Seric 
64016158Seric 	return (0);
6419339Seric }
6429339Seric 
6435181Seric # endif SMTP
644