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*51954Seric static char sccsid[] = "@(#)srvrsmtp.c	5.33 (Berkeley) 12/15/91 (with SMTP)";
1433731Sbostic #else
15*51954Seric static char sccsid[] = "@(#)srvrsmtp.c	5.33 (Berkeley) 12/15/91 (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 
894549Seric smtp()
904549Seric {
914549Seric 	register char *p;
928544Seric 	register struct cmd *c;
934549Seric 	char *cmd;
9446928Sbostic 	static char *skipword();
954549Seric 	bool hasmail;			/* mail command received */
965003Seric 	auto ADDRESS *vrfyqueue;
9712612Seric 	ADDRESS *a;
9830448Seric 	char *sendinghost;
998544Seric 	char inp[MAXLINE];
10024981Seric 	char cmdbuf[100];
1017124Seric 	extern char Version[];
10211151Seric 	extern char *macvalue();
10312612Seric 	extern ADDRESS *recipient();
10424943Seric 	extern ENVELOPE BlankEnvelope;
10524943Seric 	extern ENVELOPE *newenvelope();
1064549Seric 
1075003Seric 	hasmail = FALSE;
1087363Seric 	if (OutChannel != stdout)
1097363Seric 	{
1107363Seric 		/* arrange for debugging output to go to remote host */
1117363Seric 		(void) close(1);
1127363Seric 		(void) dup(fileno(OutChannel));
1137363Seric 	}
11411931Seric 	settime();
11524971Seric 	if (RealHostName != NULL)
11625050Seric 	{
11725050Seric 		CurHostName = RealHostName;
11825050Seric 		setproctitle("srvrsmtp %s", CurHostName);
11925050Seric 	}
12025050Seric 	else
12125050Seric 	{
12225050Seric 		/* this must be us!! */
12325050Seric 		CurHostName = MyHostName;
12425050Seric 	}
12516153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
12610708Seric 	message("220", inp);
12724943Seric 	SmtpPhase = "startup";
12830448Seric 	sendinghost = NULL;
1294549Seric 	for (;;)
1304549Seric 	{
13112612Seric 		/* arrange for backout */
13212612Seric 		if (setjmp(TopFrame) > 0 && InChild)
13312612Seric 			finis();
13412612Seric 		QuickAbort = FALSE;
13512612Seric 		HoldErrs = FALSE;
13651951Seric 		LogUsrErrs = FALSE;
13712612Seric 
1387356Seric 		/* setup for the read */
1396907Seric 		CurEnv->e_to = NULL;
1404577Seric 		Errors = 0;
1417275Seric 		(void) fflush(stdout);
1427356Seric 
1437356Seric 		/* read the input line */
1447685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1457356Seric 
1467685Seric 		/* handle errors */
1477356Seric 		if (p == NULL)
1487356Seric 		{
1494549Seric 			/* end of file, just die */
15036230Skarels 			message("421", "%s Lost input channel from %s",
15125050Seric 				MyHostName, CurHostName);
1524549Seric 			finis();
1534549Seric 		}
1544549Seric 
1554549Seric 		/* clean up end of line */
1564558Seric 		fixcrlf(inp, TRUE);
1574549Seric 
1584713Seric 		/* echo command to transcript */
1599545Seric 		if (CurEnv->e_xfp != NULL)
1609545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1614713Seric 
1624549Seric 		/* break off command */
1634549Seric 		for (p = inp; isspace(*p); p++)
1644549Seric 			continue;
1654549Seric 		cmd = p;
16624981Seric 		for (cmd = cmdbuf; *p != '\0' && !isspace(*p); )
16724981Seric 			*cmd++ = *p++;
16824981Seric 		*cmd = '\0';
1694549Seric 
17025691Seric 		/* throw away leading whitespace */
17125691Seric 		while (isspace(*p))
17225691Seric 			p++;
17325691Seric 
1744549Seric 		/* decode command */
1754549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1764549Seric 		{
17733725Sbostic 			if (!strcasecmp(c->cmdname, cmdbuf))
1784549Seric 				break;
1794549Seric 		}
1804549Seric 
181*51954Seric 		/* reset errors */
182*51954Seric 		errno = 0;
183*51954Seric 
1844549Seric 		/* process command */
1854549Seric 		switch (c->cmdcode)
1864549Seric 		{
1874976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
18824943Seric 			SmtpPhase = "HELO";
18925050Seric 			setproctitle("%s: %s", CurHostName, inp);
19033725Sbostic 			if (!strcasecmp(p, MyHostName))
19114877Seric 			{
19236230Skarels 				/*
19336230Skarels 				 * didn't know about alias,
19436230Skarels 				 * or connected to an echo server
19536230Skarels 				 */
19647570Seric 				message("553", "%s config error: mail loops back to myself",
19747570Seric 					MyHostName);
19814877Seric 				break;
19914877Seric 			}
20033725Sbostic 			if (RealHostName != NULL && strcasecmp(p, RealHostName))
20111146Seric 			{
20224981Seric 				char hostbuf[MAXNAME];
20311146Seric 
20424981Seric 				(void) sprintf(hostbuf, "%s (%s)", p, RealHostName);
20530448Seric 				sendinghost = newstr(hostbuf);
20611146Seric 			}
20711146Seric 			else
20830448Seric 				sendinghost = newstr(p);
2094997Seric 			message("250", "%s Hello %s, pleased to meet you",
21036230Skarels 				MyHostName, sendinghost);
2114976Seric 			break;
2124976Seric 
2134549Seric 		  case CMDMAIL:		/* mail -- designate sender */
21424943Seric 			SmtpPhase = "MAIL";
21524943Seric 
21611151Seric 			/* force a sending host even if no HELO given */
21711151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
21830448Seric 				sendinghost = RealHostName;
21911151Seric 
2209314Seric 			/* check for validity of this command */
2214558Seric 			if (hasmail)
2224558Seric 			{
2234558Seric 				message("503", "Sender already specified");
2244558Seric 				break;
2254558Seric 			}
2269339Seric 			if (InChild)
2279339Seric 			{
22836230Skarels 				errno = 0;
2299339Seric 				syserr("Nested MAIL command");
2309339Seric 				exit(0);
2319339Seric 			}
2329339Seric 
2339339Seric 			/* fork a subprocess to process this command */
2349339Seric 			if (runinchild("SMTP-MAIL") > 0)
2359339Seric 				break;
23630448Seric 			define('s', sendinghost, CurEnv);
23736579Sbostic 			define('r', "SMTP", CurEnv);
2389339Seric 			initsys();
23925016Seric 			setproctitle("%s %s: %s", CurEnv->e_id,
24025050Seric 				CurHostName, inp);
2419339Seric 
2429339Seric 			/* child -- go do the processing */
2434549Seric 			p = skipword(p, "from");
2444549Seric 			if (p == NULL)
2454549Seric 				break;
2464549Seric 			setsender(p);
2474577Seric 			if (Errors == 0)
2484549Seric 			{
2494549Seric 				message("250", "Sender ok");
2504549Seric 				hasmail = TRUE;
2514549Seric 			}
2529339Seric 			else if (InChild)
2539339Seric 				finis();
2544549Seric 			break;
2554549Seric 
2564976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
25724943Seric 			SmtpPhase = "RCPT";
25825016Seric 			setproctitle("%s %s: %s", CurEnv->e_id,
25925050Seric 				CurHostName, inp);
26012612Seric 			if (setjmp(TopFrame) > 0)
26114785Seric 			{
26214785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
26312612Seric 				break;
26414785Seric 			}
26512612Seric 			QuickAbort = TRUE;
26651951Seric 			LogUsrErrs = TRUE;
2674549Seric 			p = skipword(p, "to");
2684549Seric 			if (p == NULL)
2694549Seric 				break;
27016140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
27112612Seric 			if (a == NULL)
27212612Seric 				break;
27316886Seric 			a->q_flags |= QPRIMARY;
27412612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
27512612Seric 			if (Errors != 0)
27612612Seric 				break;
27712612Seric 
27812612Seric 			/* no errors during parsing, but might be a duplicate */
27912612Seric 			CurEnv->e_to = p;
28012612Seric 			if (!bitset(QBADADDR, a->q_flags))
28112612Seric 				message("250", "Recipient ok");
28212612Seric 			else
2834549Seric 			{
28412612Seric 				/* punt -- should keep message in ADDRESS.... */
28512612Seric 				message("550", "Addressee unknown");
2864549Seric 			}
28712612Seric 			CurEnv->e_to = NULL;
2884549Seric 			break;
2894549Seric 
2904549Seric 		  case CMDDATA:		/* data -- text of mail */
29124943Seric 			SmtpPhase = "DATA";
2924976Seric 			if (!hasmail)
2934549Seric 			{
2944976Seric 				message("503", "Need MAIL command");
2954976Seric 				break;
2964549Seric 			}
29724943Seric 			else if (CurEnv->e_nrcpts <= 0)
2984549Seric 			{
2994976Seric 				message("503", "Need RCPT (recipient)");
3004976Seric 				break;
3014549Seric 			}
3024976Seric 
3034976Seric 			/* collect the text of the message */
30424943Seric 			SmtpPhase = "collect";
30525016Seric 			setproctitle("%s %s: %s", CurEnv->e_id,
30625050Seric 				CurHostName, inp);
3074976Seric 			collect(TRUE);
3084976Seric 			if (Errors != 0)
3094976Seric 				break;
3104976Seric 
3118238Seric 			/*
3128238Seric 			**  Arrange to send to everyone.
3138238Seric 			**	If sending to multiple people, mail back
3148238Seric 			**		errors rather than reporting directly.
3158238Seric 			**	In any case, don't mail back errors for
3168238Seric 			**		anything that has happened up to
3178238Seric 			**		now (the other end will do this).
31810197Seric 			**	Truncate our transcript -- the mail has gotten
31910197Seric 			**		to us successfully, and if we have
32010197Seric 			**		to mail this back, it will be easier
32110197Seric 			**		on the reader.
3228238Seric 			**	Then send to everyone.
3238238Seric 			**	Finally give a reply code.  If an error has
3248238Seric 			**		already been given, don't mail a
3258238Seric 			**		message back.
3269339Seric 			**	We goose error returns by clearing error bit.
3278238Seric 			*/
3288238Seric 
32924943Seric 			SmtpPhase = "delivery";
33024943Seric 			if (CurEnv->e_nrcpts != 1)
3319378Seric 			{
3329378Seric 				HoldErrs = TRUE;
33316886Seric 				ErrorMode = EM_MAIL;
3349378Seric 			}
3359339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
33610197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
3374976Seric 
3384976Seric 			/* send to all recipients */
33914877Seric 			sendall(CurEnv, SM_DEFAULT);
3406907Seric 			CurEnv->e_to = NULL;
3414976Seric 
34223516Seric 			/* save statistics */
34323516Seric 			markstats(CurEnv, (ADDRESS *) NULL);
34423516Seric 
3458238Seric 			/* issue success if appropriate and reset */
3468238Seric 			if (Errors == 0 || HoldErrs)
3479283Seric 				message("250", "Ok");
3488238Seric 			else
3499339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3509339Seric 
3519339Seric 			/* if in a child, pop back to our parent */
3529339Seric 			if (InChild)
3539339Seric 				finis();
35424943Seric 
35524943Seric 			/* clean up a bit */
35624943Seric 			hasmail = 0;
35724943Seric 			dropenvelope(CurEnv);
35824943Seric 			CurEnv = newenvelope(CurEnv);
35924943Seric 			CurEnv->e_flags = BlankEnvelope.e_flags;
3604549Seric 			break;
3614549Seric 
3624549Seric 		  case CMDRSET:		/* rset -- reset state */
3634549Seric 			message("250", "Reset state");
3649339Seric 			if (InChild)
3659339Seric 				finis();
3669339Seric 			break;
3674549Seric 
3684549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3699339Seric 			if (runinchild("SMTP-VRFY") > 0)
3709339Seric 				break;
37125050Seric 			setproctitle("%s: %s", CurHostName, inp);
3725003Seric 			vrfyqueue = NULL;
3737762Seric 			QuickAbort = TRUE;
3749619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3757762Seric 			if (Errors != 0)
3769339Seric 			{
3779339Seric 				if (InChild)
3789339Seric 					finis();
3797762Seric 				break;
3809339Seric 			}
3815003Seric 			while (vrfyqueue != NULL)
3825003Seric 			{
3835003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3845003Seric 				char *code;
3855003Seric 
3867685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3875003Seric 					a = a->q_next;
3885003Seric 
3897685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3905003Seric 				{
3915003Seric 					if (a != NULL)
3925003Seric 						code = "250-";
3935003Seric 					else
3945003Seric 						code = "250";
3955003Seric 					if (vrfyqueue->q_fullname == NULL)
3965003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3975003Seric 					else
3985003Seric 						message(code, "%s <%s>",
3995003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
4005003Seric 				}
4015003Seric 				else if (a == NULL)
4025003Seric 					message("554", "Self destructive alias loop");
4035003Seric 				vrfyqueue = a;
4045003Seric 			}
4059339Seric 			if (InChild)
4069339Seric 				finis();
4074549Seric 			break;
4084549Seric 
4094549Seric 		  case CMDHELP:		/* help -- give user info */
4104577Seric 			help(p);
4114549Seric 			break;
4124549Seric 
4134549Seric 		  case CMDNOOP:		/* noop -- do nothing */
4144549Seric 			message("200", "OK");
4154549Seric 			break;
4164549Seric 
4174549Seric 		  case CMDQUIT:		/* quit -- leave mail */
41825050Seric 			message("221", "%s closing connection", MyHostName);
4199339Seric 			if (InChild)
4209339Seric 				ExitStat = EX_QUIT;
4214549Seric 			finis();
4224549Seric 
4238544Seric 		  case CMDVERB:		/* set verbose mode */
4248544Seric 			Verbose = TRUE;
42525025Seric 			SendMode = SM_DELIVER;
4268544Seric 			message("200", "Verbose mode");
4278544Seric 			break;
4288544Seric 
4299314Seric 		  case CMDONEX:		/* doing one transaction only */
4309378Seric 			OneXact = TRUE;
4319314Seric 			message("200", "Only one transaction");
4329314Seric 			break;
4339314Seric 
43436230Skarels # ifdef SMTPDEBUG
4359339Seric 		  case CMDDBGQSHOW:	/* show queues */
4366907Seric 			printf("Send Queue=");
4376907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
4385003Seric 			break;
4397275Seric 
4407275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
4417676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
4427676Seric 			tTflag(p);
4437676Seric 			message("200", "Debug set");
4447275Seric 			break;
4457275Seric 
44636230Skarels # else /* not SMTPDEBUG */
44724945Seric 
44836230Skarels 		  case CMDDBGQSHOW:	/* show queues */
44936230Skarels 		  case CMDDBGDEBUG:	/* set debug mode */
45036233Skarels # ifdef LOG
45136233Skarels 			if (RealHostName != NULL && LogLevel > 0)
45236230Skarels 				syslog(LOG_NOTICE,
45336230Skarels 				    "\"%s\" command from %s (%s)\n",
45436230Skarels 				    c->cmdname, RealHostName,
45536230Skarels 				    inet_ntoa(RealHostAddr.sin_addr));
45636233Skarels # endif
45736230Skarels 			/* FALL THROUGH */
45836230Skarels # endif /* SMTPDEBUG */
45936230Skarels 
4604549Seric 		  case CMDERROR:	/* unknown command */
4614549Seric 			message("500", "Command unrecognized");
4624549Seric 			break;
4634549Seric 
4644549Seric 		  default:
46536230Skarels 			errno = 0;
4664549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4674549Seric 			break;
4684549Seric 		}
4694549Seric 	}
4704549Seric }
4714549Seric /*
4724549Seric **  SKIPWORD -- skip a fixed word.
4734549Seric **
4744549Seric **	Parameters:
4754549Seric **		p -- place to start looking.
4764549Seric **		w -- word to skip.
4774549Seric **
4784549Seric **	Returns:
4794549Seric **		p following w.
4804549Seric **		NULL on error.
4814549Seric **
4824549Seric **	Side Effects:
4834549Seric **		clobbers the p data area.
4844549Seric */
4854549Seric 
4864549Seric static char *
4874549Seric skipword(p, w)
4884549Seric 	register char *p;
4894549Seric 	char *w;
4904549Seric {
4914549Seric 	register char *q;
4924549Seric 
4934549Seric 	/* find beginning of word */
4944549Seric 	while (isspace(*p))
4954549Seric 		p++;
4964549Seric 	q = p;
4974549Seric 
4984549Seric 	/* find end of word */
4994549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
5004549Seric 		p++;
5014549Seric 	while (isspace(*p))
5024549Seric 		*p++ = '\0';
5034549Seric 	if (*p != ':')
5044549Seric 	{
5054549Seric 	  syntax:
5064549Seric 		message("501", "Syntax error");
5074549Seric 		Errors++;
5084549Seric 		return (NULL);
5094549Seric 	}
5104549Seric 	*p++ = '\0';
5114549Seric 	while (isspace(*p))
5124549Seric 		p++;
5134549Seric 
5144549Seric 	/* see if the input word matches desired word */
51533725Sbostic 	if (strcasecmp(q, w))
5164549Seric 		goto syntax;
5174549Seric 
5184549Seric 	return (p);
5194549Seric }
5204577Seric /*
5214577Seric **  HELP -- implement the HELP command.
5224577Seric **
5234577Seric **	Parameters:
5244577Seric **		topic -- the topic we want help for.
5254577Seric **
5264577Seric **	Returns:
5274577Seric **		none.
5284577Seric **
5294577Seric **	Side Effects:
5304577Seric **		outputs the help file to message output.
5314577Seric */
5324577Seric 
5334577Seric help(topic)
5344577Seric 	char *topic;
5354577Seric {
5364577Seric 	register FILE *hf;
5374577Seric 	int len;
5384577Seric 	char buf[MAXLINE];
5394577Seric 	bool noinfo;
5404577Seric 
5418269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5424577Seric 	{
5434577Seric 		/* no help */
54411931Seric 		errno = 0;
5454577Seric 		message("502", "HELP not implemented");
5464577Seric 		return;
5474577Seric 	}
5484577Seric 
54949669Seric 	if (topic == NULL || *topic == '\0')
55049669Seric 		topic = "smtp";
55149669Seric 	else
55249669Seric 		makelower(topic);
55349669Seric 
5544577Seric 	len = strlen(topic);
5554577Seric 	noinfo = TRUE;
5564577Seric 
5574577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5584577Seric 	{
5594577Seric 		if (strncmp(buf, topic, len) == 0)
5604577Seric 		{
5614577Seric 			register char *p;
5624577Seric 
5634577Seric 			p = index(buf, '\t');
5644577Seric 			if (p == NULL)
5654577Seric 				p = buf;
5664577Seric 			else
5674577Seric 				p++;
5684577Seric 			fixcrlf(p, TRUE);
5694577Seric 			message("214-", p);
5704577Seric 			noinfo = FALSE;
5714577Seric 		}
5724577Seric 	}
5734577Seric 
5744577Seric 	if (noinfo)
5754577Seric 		message("504", "HELP topic unknown");
5764577Seric 	else
5774577Seric 		message("214", "End of HELP info");
5784628Seric 	(void) fclose(hf);
5794577Seric }
5808544Seric /*
5819339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5829339Seric **
5839339Seric **	Parameters:
5849339Seric **		label -- a string used in error messages
5859339Seric **
5869339Seric **	Returns:
5879339Seric **		zero in the child
5889339Seric **		one in the parent
5899339Seric **
5909339Seric **	Side Effects:
5919339Seric **		none.
5929339Seric */
5938544Seric 
5949339Seric runinchild(label)
5959339Seric 	char *label;
5969339Seric {
5979339Seric 	int childpid;
5989339Seric 
59916158Seric 	if (!OneXact)
6009339Seric 	{
60116158Seric 		childpid = dofork();
60216158Seric 		if (childpid < 0)
60316158Seric 		{
60416158Seric 			syserr("%s: cannot fork", label);
60516158Seric 			return (1);
60616158Seric 		}
60716158Seric 		if (childpid > 0)
60816158Seric 		{
60916158Seric 			auto int st;
6109339Seric 
61116158Seric 			/* parent -- wait for child to complete */
61216158Seric 			st = waitfor(childpid);
61316158Seric 			if (st == -1)
61416158Seric 				syserr("%s: lost child", label);
6159339Seric 
61616158Seric 			/* if we exited on a QUIT command, complete the process */
61716158Seric 			if (st == (EX_QUIT << 8))
61816158Seric 				finis();
6199339Seric 
62016158Seric 			return (1);
62116158Seric 		}
62216158Seric 		else
62316158Seric 		{
62416158Seric 			/* child */
62516158Seric 			InChild = TRUE;
62625050Seric 			QuickAbort = FALSE;
62725614Seric 			clearenvelope(CurEnv, FALSE);
62816158Seric 		}
6299339Seric 	}
63015256Seric 
63116158Seric 	/* open alias database */
63216158Seric 	initaliases(AliasFile, FALSE);
63316158Seric 
63416158Seric 	return (0);
6359339Seric }
6369339Seric 
6375181Seric # endif SMTP
638