19339Seric # include <errno.h>
24549Seric # include "sendmail.h"
311728Seric # include <signal.h>
44549Seric 
55181Seric # ifndef SMTP
6*19038Seric SCCSID(@(#)srvrsmtp.c	4.11		04/28/85	(no SMTP));
75181Seric # else SMTP
84556Seric 
9*19038Seric SCCSID(@(#)srvrsmtp.c	4.11		04/28/85);
105181Seric 
114549Seric /*
124549Seric **  SMTP -- run the SMTP protocol.
134549Seric **
144549Seric **	Parameters:
154549Seric **		none.
164549Seric **
174549Seric **	Returns:
184549Seric **		never.
194549Seric **
204549Seric **	Side Effects:
214549Seric **		Reads commands from the input channel and processes
224549Seric **			them.
234549Seric */
244549Seric 
254549Seric struct cmd
264549Seric {
274549Seric 	char	*cmdname;	/* command name */
284549Seric 	int	cmdcode;	/* internal code, see below */
294549Seric };
304549Seric 
314549Seric /* values for cmdcode */
324549Seric # define CMDERROR	0	/* bad command */
334549Seric # define CMDMAIL	1	/* mail -- designate sender */
344976Seric # define CMDRCPT	2	/* rcpt -- designate recipient */
354549Seric # define CMDDATA	3	/* data -- send message text */
369339Seric # define CMDRSET	4	/* rset -- reset state */
379339Seric # define CMDVRFY	5	/* vrfy -- verify address */
389339Seric # define CMDHELP	6	/* help -- give usage info */
399339Seric # define CMDNOOP	7	/* noop -- do nothing */
409339Seric # define CMDQUIT	8	/* quit -- close connection and die */
419339Seric # define CMDHELO	9	/* helo -- be polite */
429339Seric # define CMDDBGQSHOW	10	/* showq -- show send queue (DEBUG) */
439339Seric # define CMDDBGDEBUG	11	/* debug -- set debug mode */
449339Seric # define CMDVERB	12	/* verb -- go into verbose mode */
459339Seric # define CMDDBGKILL	13	/* kill -- kill sendmail */
469339Seric # define CMDDBGWIZ	14	/* wiz -- become a wizard */
479339Seric # define CMDONEX	15	/* onex -- sending one transaction only */
484549Seric 
494549Seric static struct cmd	CmdTab[] =
504549Seric {
514549Seric 	"mail",		CMDMAIL,
524976Seric 	"rcpt",		CMDRCPT,
534549Seric 	"data",		CMDDATA,
544549Seric 	"rset",		CMDRSET,
554549Seric 	"vrfy",		CMDVRFY,
567762Seric 	"expn",		CMDVRFY,
574549Seric 	"help",		CMDHELP,
584549Seric 	"noop",		CMDNOOP,
594549Seric 	"quit",		CMDQUIT,
604976Seric 	"helo",		CMDHELO,
618544Seric 	"verb",		CMDVERB,
629314Seric 	"onex",		CMDONEX,
635003Seric # ifdef DEBUG
649339Seric 	"showq",	CMDDBGQSHOW,
658544Seric 	"debug",	CMDDBGDEBUG,
668544Seric 	"kill",		CMDDBGKILL,
678544Seric 	"wiz",		CMDDBGWIZ,
685003Seric # endif DEBUG
694549Seric 	NULL,		CMDERROR,
704549Seric };
714549Seric 
728544Seric bool	IsWiz = FALSE;			/* set if we are a wizard */
7315596Seric char	*WizWord;			/* the wizard word to compare against */
749339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
759378Seric bool	OneXact = FALSE;		/* one xaction only this run */
7611146Seric char	*RealHostName = NULL;		/* verified hostname, set in daemon.c */
7711146Seric 
789339Seric #define EX_QUIT		22		/* special code for QUIT command */
798544Seric 
804549Seric smtp()
814549Seric {
824549Seric 	register char *p;
838544Seric 	register struct cmd *c;
844549Seric 	char *cmd;
854549Seric 	extern char *skipword();
864549Seric 	extern bool sameword();
874549Seric 	bool hasmail;			/* mail command received */
884713Seric 	int rcps;			/* number of recipients */
895003Seric 	auto ADDRESS *vrfyqueue;
9012612Seric 	ADDRESS *a;
918544Seric 	char inp[MAXLINE];
927124Seric 	extern char Version[];
937356Seric 	extern tick();
948544Seric 	extern bool iswiz();
959349Seric 	extern char *arpadate();
9611151Seric 	extern char *macvalue();
9712612Seric 	extern ADDRESS *recipient();
984549Seric 
995003Seric 	hasmail = FALSE;
1004713Seric 	rcps = 0;
1017363Seric 	if (OutChannel != stdout)
1027363Seric 	{
1037363Seric 		/* arrange for debugging output to go to remote host */
1047363Seric 		(void) close(1);
1057363Seric 		(void) dup(fileno(OutChannel));
1067363Seric 	}
10711931Seric 	settime();
10816153Seric 	expand("\001e", inp, &inp[sizeof inp], CurEnv);
10910708Seric 	message("220", inp);
1104549Seric 	for (;;)
1114549Seric 	{
11212612Seric 		/* arrange for backout */
11312612Seric 		if (setjmp(TopFrame) > 0 && InChild)
11412612Seric 			finis();
11512612Seric 		QuickAbort = FALSE;
11612612Seric 		HoldErrs = FALSE;
11712612Seric 
1187356Seric 		/* setup for the read */
1196907Seric 		CurEnv->e_to = NULL;
1204577Seric 		Errors = 0;
1217275Seric 		(void) fflush(stdout);
1227356Seric 
1237356Seric 		/* read the input line */
1247685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1257356Seric 
1267685Seric 		/* handle errors */
1277356Seric 		if (p == NULL)
1287356Seric 		{
1294549Seric 			/* end of file, just die */
1304558Seric 			message("421", "%s Lost input channel", HostName);
1314549Seric 			finis();
1324549Seric 		}
1334549Seric 
1344549Seric 		/* clean up end of line */
1354558Seric 		fixcrlf(inp, TRUE);
1364549Seric 
1374713Seric 		/* echo command to transcript */
1389545Seric 		if (CurEnv->e_xfp != NULL)
1399545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1404713Seric 
1414549Seric 		/* break off command */
1424549Seric 		for (p = inp; isspace(*p); p++)
1434549Seric 			continue;
1444549Seric 		cmd = p;
1454549Seric 		while (*++p != '\0' && !isspace(*p))
1464549Seric 			continue;
1474549Seric 		if (*p != '\0')
1484549Seric 			*p++ = '\0';
1494549Seric 
1504549Seric 		/* decode command */
1514549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1524549Seric 		{
1534549Seric 			if (sameword(c->cmdname, cmd))
1544549Seric 				break;
1554549Seric 		}
1564549Seric 
1574549Seric 		/* process command */
1584549Seric 		switch (c->cmdcode)
1594549Seric 		{
1604976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
16114877Seric 			if (sameword(p, HostName))
16214877Seric 			{
16314877Seric 				/* connected to an echo server */
16414877Seric 				message("553", "%s I refuse to talk to myself",
16514877Seric 					HostName);
16614877Seric 				break;
16714877Seric 			}
16811146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
16911146Seric 			{
17011146Seric 				char buf[MAXNAME];
17111146Seric 
17211146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
17311146Seric 				define('s', newstr(buf), CurEnv);
17411146Seric 			}
17511146Seric 			else
17611146Seric 				define('s', newstr(p), CurEnv);
1774997Seric 			message("250", "%s Hello %s, pleased to meet you",
1784997Seric 				HostName, p);
1794976Seric 			break;
1804976Seric 
1814549Seric 		  case CMDMAIL:		/* mail -- designate sender */
18211151Seric 			/* force a sending host even if no HELO given */
18311151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
18411151Seric 				define('s', RealHostName, CurEnv);
18511151Seric 
1869314Seric 			/* check for validity of this command */
1874558Seric 			if (hasmail)
1884558Seric 			{
1894558Seric 				message("503", "Sender already specified");
1904558Seric 				break;
1914558Seric 			}
1929339Seric 			if (InChild)
1939339Seric 			{
1949339Seric 				syserr("Nested MAIL command");
1959339Seric 				exit(0);
1969339Seric 			}
1979339Seric 
1989339Seric 			/* fork a subprocess to process this command */
1999339Seric 			if (runinchild("SMTP-MAIL") > 0)
2009339Seric 				break;
2019339Seric 			initsys();
2029339Seric 
2039339Seric 			/* child -- go do the processing */
2044549Seric 			p = skipword(p, "from");
2054549Seric 			if (p == NULL)
2064549Seric 				break;
2074549Seric 			setsender(p);
2084577Seric 			if (Errors == 0)
2094549Seric 			{
2104549Seric 				message("250", "Sender ok");
2114549Seric 				hasmail = TRUE;
2124549Seric 			}
2139339Seric 			else if (InChild)
2149339Seric 				finis();
2154549Seric 			break;
2164549Seric 
2174976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
21812612Seric 			if (setjmp(TopFrame) > 0)
21914785Seric 			{
22014785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
22112612Seric 				break;
22214785Seric 			}
22312612Seric 			QuickAbort = TRUE;
2244549Seric 			p = skipword(p, "to");
2254549Seric 			if (p == NULL)
2264549Seric 				break;
22716140Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
22812612Seric 			if (a == NULL)
22912612Seric 				break;
23016886Seric 			a->q_flags |= QPRIMARY;
23112612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
23212612Seric 			if (Errors != 0)
23312612Seric 				break;
23412612Seric 
23512612Seric 			/* no errors during parsing, but might be a duplicate */
23612612Seric 			CurEnv->e_to = p;
23712612Seric 			if (!bitset(QBADADDR, a->q_flags))
23812612Seric 				message("250", "Recipient ok");
23912612Seric 			else
2404549Seric 			{
24112612Seric 				/* punt -- should keep message in ADDRESS.... */
24212612Seric 				message("550", "Addressee unknown");
2434549Seric 			}
24412612Seric 			CurEnv->e_to = NULL;
24512612Seric 			rcps++;
2464549Seric 			break;
2474549Seric 
2484549Seric 		  case CMDDATA:		/* data -- text of mail */
2494976Seric 			if (!hasmail)
2504549Seric 			{
2514976Seric 				message("503", "Need MAIL command");
2524976Seric 				break;
2534549Seric 			}
2544713Seric 			else if (rcps <= 0)
2554549Seric 			{
2564976Seric 				message("503", "Need RCPT (recipient)");
2574976Seric 				break;
2584549Seric 			}
2594976Seric 
2604976Seric 			/* collect the text of the message */
2614976Seric 			collect(TRUE);
2624976Seric 			if (Errors != 0)
2634976Seric 				break;
2644976Seric 
2658238Seric 			/*
2668238Seric 			**  Arrange to send to everyone.
2678238Seric 			**	If sending to multiple people, mail back
2688238Seric 			**		errors rather than reporting directly.
2698238Seric 			**	In any case, don't mail back errors for
2708238Seric 			**		anything that has happened up to
2718238Seric 			**		now (the other end will do this).
27210197Seric 			**	Truncate our transcript -- the mail has gotten
27310197Seric 			**		to us successfully, and if we have
27410197Seric 			**		to mail this back, it will be easier
27510197Seric 			**		on the reader.
2768238Seric 			**	Then send to everyone.
2778238Seric 			**	Finally give a reply code.  If an error has
2788238Seric 			**		already been given, don't mail a
2798238Seric 			**		message back.
2809339Seric 			**	We goose error returns by clearing error bit.
2818238Seric 			*/
2828238Seric 
2834976Seric 			if (rcps != 1)
2849378Seric 			{
2859378Seric 				HoldErrs = TRUE;
28616886Seric 				ErrorMode = EM_MAIL;
2879378Seric 			}
2889339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
28910197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
2904976Seric 
2914976Seric 			/* send to all recipients */
29214877Seric 			sendall(CurEnv, SM_DEFAULT);
2936907Seric 			CurEnv->e_to = NULL;
2944976Seric 
2958238Seric 			/* issue success if appropriate and reset */
2968238Seric 			if (Errors == 0 || HoldErrs)
2979283Seric 				message("250", "Ok");
2988238Seric 			else
2999339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
3009339Seric 
3019339Seric 			/* if in a child, pop back to our parent */
3029339Seric 			if (InChild)
3039339Seric 				finis();
3044549Seric 			break;
3054549Seric 
3064549Seric 		  case CMDRSET:		/* rset -- reset state */
3074549Seric 			message("250", "Reset state");
3089339Seric 			if (InChild)
3099339Seric 				finis();
3109339Seric 			break;
3114549Seric 
3124549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3139339Seric 			if (runinchild("SMTP-VRFY") > 0)
3149339Seric 				break;
3155003Seric 			vrfyqueue = NULL;
3167762Seric 			QuickAbort = TRUE;
3179619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3187762Seric 			if (Errors != 0)
3199339Seric 			{
3209339Seric 				if (InChild)
3219339Seric 					finis();
3227762Seric 				break;
3239339Seric 			}
3245003Seric 			while (vrfyqueue != NULL)
3255003Seric 			{
3265003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3275003Seric 				char *code;
3285003Seric 
3297685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3305003Seric 					a = a->q_next;
3315003Seric 
3327685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3335003Seric 				{
3345003Seric 					if (a != NULL)
3355003Seric 						code = "250-";
3365003Seric 					else
3375003Seric 						code = "250";
3385003Seric 					if (vrfyqueue->q_fullname == NULL)
3395003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3405003Seric 					else
3415003Seric 						message(code, "%s <%s>",
3425003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3435003Seric 				}
3445003Seric 				else if (a == NULL)
3455003Seric 					message("554", "Self destructive alias loop");
3465003Seric 				vrfyqueue = a;
3475003Seric 			}
3489339Seric 			if (InChild)
3499339Seric 				finis();
3504549Seric 			break;
3514549Seric 
3524549Seric 		  case CMDHELP:		/* help -- give user info */
3534577Seric 			if (*p == '\0')
3544577Seric 				p = "SMTP";
3554577Seric 			help(p);
3564549Seric 			break;
3574549Seric 
3584549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3594549Seric 			message("200", "OK");
3604549Seric 			break;
3614549Seric 
3624549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3634549Seric 			message("221", "%s closing connection", HostName);
3649339Seric 			if (InChild)
3659339Seric 				ExitStat = EX_QUIT;
3664549Seric 			finis();
3674549Seric 
3688544Seric 		  case CMDVERB:		/* set verbose mode */
3698544Seric 			Verbose = TRUE;
3708544Seric 			message("200", "Verbose mode");
3718544Seric 			break;
3728544Seric 
3739314Seric 		  case CMDONEX:		/* doing one transaction only */
3749378Seric 			OneXact = TRUE;
3759314Seric 			message("200", "Only one transaction");
3769314Seric 			break;
3779314Seric 
3785003Seric # ifdef DEBUG
3799339Seric 		  case CMDDBGQSHOW:	/* show queues */
3806907Seric 			printf("Send Queue=");
3816907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
3825003Seric 			break;
3837275Seric 
3847275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
3857676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
3867676Seric 			tTflag(p);
3877676Seric 			message("200", "Debug set");
3887275Seric 			break;
3897275Seric 
3907282Seric 		  case CMDDBGKILL:	/* kill the parent */
3918544Seric 			if (!iswiz())
3928544Seric 				break;
3937282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
3947282Seric 				message("200", "Mother is dead");
3957282Seric 			else
3967282Seric 				message("500", "Can't kill Mom");
3977282Seric 			break;
3988544Seric 
3998544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4008544Seric 			if (WizWord != NULL)
4018544Seric 			{
4028544Seric 				char seed[3];
4038544Seric 				extern char *crypt();
4048544Seric 
4058544Seric 				strncpy(seed, WizWord, 2);
40615596Seric 				if (strcmp(WizWord, crypt(p, seed)) == 0)
4078544Seric 				{
40815596Seric 					IsWiz = TRUE;
40915596Seric 					message("200", "Please pass, oh mighty wizard");
4108544Seric 					break;
4118544Seric 				}
4128544Seric 			}
41315596Seric 			message("500", "You are no wizard!");
4148544Seric 			break;
4155003Seric # endif DEBUG
4165003Seric 
4174549Seric 		  case CMDERROR:	/* unknown command */
4184549Seric 			message("500", "Command unrecognized");
4194549Seric 			break;
4204549Seric 
4214549Seric 		  default:
4224549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4234549Seric 			break;
4244549Seric 		}
4254549Seric 	}
4264549Seric }
4274549Seric /*
4284549Seric **  SKIPWORD -- skip a fixed word.
4294549Seric **
4304549Seric **	Parameters:
4314549Seric **		p -- place to start looking.
4324549Seric **		w -- word to skip.
4334549Seric **
4344549Seric **	Returns:
4354549Seric **		p following w.
4364549Seric **		NULL on error.
4374549Seric **
4384549Seric **	Side Effects:
4394549Seric **		clobbers the p data area.
4404549Seric */
4414549Seric 
4424549Seric static char *
4434549Seric skipword(p, w)
4444549Seric 	register char *p;
4454549Seric 	char *w;
4464549Seric {
4474549Seric 	register char *q;
4484549Seric 	extern bool sameword();
4494549Seric 
4504549Seric 	/* find beginning of word */
4514549Seric 	while (isspace(*p))
4524549Seric 		p++;
4534549Seric 	q = p;
4544549Seric 
4554549Seric 	/* find end of word */
4564549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4574549Seric 		p++;
4584549Seric 	while (isspace(*p))
4594549Seric 		*p++ = '\0';
4604549Seric 	if (*p != ':')
4614549Seric 	{
4624549Seric 	  syntax:
4634549Seric 		message("501", "Syntax error");
4644549Seric 		Errors++;
4654549Seric 		return (NULL);
4664549Seric 	}
4674549Seric 	*p++ = '\0';
4684549Seric 	while (isspace(*p))
4694549Seric 		p++;
4704549Seric 
4714549Seric 	/* see if the input word matches desired word */
4724549Seric 	if (!sameword(q, w))
4734549Seric 		goto syntax;
4744549Seric 
4754549Seric 	return (p);
4764549Seric }
4774577Seric /*
4784577Seric **  HELP -- implement the HELP command.
4794577Seric **
4804577Seric **	Parameters:
4814577Seric **		topic -- the topic we want help for.
4824577Seric **
4834577Seric **	Returns:
4844577Seric **		none.
4854577Seric **
4864577Seric **	Side Effects:
4874577Seric **		outputs the help file to message output.
4884577Seric */
4894577Seric 
4904577Seric help(topic)
4914577Seric 	char *topic;
4924577Seric {
4934577Seric 	register FILE *hf;
4944577Seric 	int len;
4954577Seric 	char buf[MAXLINE];
4964577Seric 	bool noinfo;
4974577Seric 
4988269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
4994577Seric 	{
5004577Seric 		/* no help */
50111931Seric 		errno = 0;
5024577Seric 		message("502", "HELP not implemented");
5034577Seric 		return;
5044577Seric 	}
5054577Seric 
5064577Seric 	len = strlen(topic);
5074577Seric 	makelower(topic);
5084577Seric 	noinfo = TRUE;
5094577Seric 
5104577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5114577Seric 	{
5124577Seric 		if (strncmp(buf, topic, len) == 0)
5134577Seric 		{
5144577Seric 			register char *p;
5154577Seric 
5164577Seric 			p = index(buf, '\t');
5174577Seric 			if (p == NULL)
5184577Seric 				p = buf;
5194577Seric 			else
5204577Seric 				p++;
5214577Seric 			fixcrlf(p, TRUE);
5224577Seric 			message("214-", p);
5234577Seric 			noinfo = FALSE;
5244577Seric 		}
5254577Seric 	}
5264577Seric 
5274577Seric 	if (noinfo)
5284577Seric 		message("504", "HELP topic unknown");
5294577Seric 	else
5304577Seric 		message("214", "End of HELP info");
5314628Seric 	(void) fclose(hf);
5324577Seric }
5338544Seric /*
5348544Seric **  ISWIZ -- tell us if we are a wizard
5358544Seric **
5368544Seric **	If not, print a nasty message.
5378544Seric **
5388544Seric **	Parameters:
5398544Seric **		none.
5408544Seric **
5418544Seric **	Returns:
5428544Seric **		TRUE if we are a wizard.
5438544Seric **		FALSE if we are not a wizard.
5448544Seric **
5458544Seric **	Side Effects:
5468544Seric **		Prints a 500 exit stat if we are not a wizard.
5478544Seric */
5485181Seric 
549*19038Seric #ifdef DEBUG
550*19038Seric 
5518544Seric bool
5528544Seric iswiz()
5538544Seric {
5548544Seric 	if (!IsWiz)
5558544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5568544Seric 	return (IsWiz);
5578544Seric }
558*19038Seric 
559*19038Seric #endif DEBUG
5609339Seric /*
5619339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5629339Seric **
5639339Seric **	Parameters:
5649339Seric **		label -- a string used in error messages
5659339Seric **
5669339Seric **	Returns:
5679339Seric **		zero in the child
5689339Seric **		one in the parent
5699339Seric **
5709339Seric **	Side Effects:
5719339Seric **		none.
5729339Seric */
5738544Seric 
5749339Seric runinchild(label)
5759339Seric 	char *label;
5769339Seric {
5779339Seric 	int childpid;
5789339Seric 
57916158Seric 	if (!OneXact)
5809339Seric 	{
58116158Seric 		childpid = dofork();
58216158Seric 		if (childpid < 0)
58316158Seric 		{
58416158Seric 			syserr("%s: cannot fork", label);
58516158Seric 			return (1);
58616158Seric 		}
58716158Seric 		if (childpid > 0)
58816158Seric 		{
58916158Seric 			auto int st;
5909339Seric 
59116158Seric 			/* parent -- wait for child to complete */
59216158Seric 			st = waitfor(childpid);
59316158Seric 			if (st == -1)
59416158Seric 				syserr("%s: lost child", label);
5959339Seric 
59616158Seric 			/* if we exited on a QUIT command, complete the process */
59716158Seric 			if (st == (EX_QUIT << 8))
59816158Seric 				finis();
5999339Seric 
60016158Seric 			return (1);
60116158Seric 		}
60216158Seric 		else
60316158Seric 		{
60416158Seric 			/* child */
60516158Seric 			InChild = TRUE;
60616158Seric 		}
6079339Seric 	}
60815256Seric 
60916158Seric 	/* child (or ONEX command specified) */
61016158Seric 	clearenvelope(CurEnv);
61115256Seric 
61216158Seric 	/* open alias database */
61316158Seric 	initaliases(AliasFile, FALSE);
61416158Seric 
61516158Seric 	return (0);
6169339Seric }
6179339Seric 
6185181Seric # endif SMTP
619