122712Sdist /*
234921Sbostic  * Copyright (c) 1983 Eric P. Allman
362532Sbostic  * Copyright (c) 1988, 1993
462532Sbostic  *	The Regents of the University of California.  All rights reserved.
533731Sbostic  *
642829Sbostic  * %sccs.include.redist.c%
733731Sbostic  */
822712Sdist 
933731Sbostic # include "sendmail.h"
1022712Sdist 
1133731Sbostic #ifndef lint
1233731Sbostic #ifdef SMTP
13*68035Seric static char sccsid[] = "@(#)srvrsmtp.c	8.52 (Berkeley) 12/05/94 (with SMTP)";
1433731Sbostic #else
15*68035Seric static char sccsid[] = "@(#)srvrsmtp.c	8.52 (Berkeley) 12/05/94 (without SMTP)";
1633731Sbostic #endif
1733731Sbostic #endif /* not lint */
1833731Sbostic 
199339Seric # include <errno.h>
204549Seric 
2133731Sbostic # ifdef SMTP
224556Seric 
234549Seric /*
244549Seric **  SMTP -- run the SMTP protocol.
254549Seric **
264549Seric **	Parameters:
274549Seric **		none.
284549Seric **
294549Seric **	Returns:
304549Seric **		never.
314549Seric **
324549Seric **	Side Effects:
334549Seric **		Reads commands from the input channel and processes
344549Seric **			them.
354549Seric */
364549Seric 
374549Seric struct cmd
384549Seric {
394549Seric 	char	*cmdname;	/* command name */
404549Seric 	int	cmdcode;	/* internal code, see below */
414549Seric };
424549Seric 
434549Seric /* values for cmdcode */
444549Seric # define CMDERROR	0	/* bad command */
454549Seric # define CMDMAIL	1	/* mail -- designate sender */
464976Seric # define CMDRCPT	2	/* rcpt -- designate recipient */
474549Seric # define CMDDATA	3	/* data -- send message text */
489339Seric # define CMDRSET	4	/* rset -- reset state */
499339Seric # define CMDVRFY	5	/* vrfy -- verify address */
5058092Seric # define CMDEXPN	6	/* expn -- expand address */
519339Seric # define CMDNOOP	7	/* noop -- do nothing */
529339Seric # define CMDQUIT	8	/* quit -- close connection and die */
539339Seric # define CMDHELO	9	/* helo -- be polite */
5458092Seric # define CMDHELP	10	/* help -- give usage info */
5558323Seric # define CMDEHLO	11	/* ehlo -- extended helo (RFC 1425) */
5658092Seric /* non-standard commands */
5758092Seric # define CMDONEX	16	/* onex -- sending one transaction only */
5858092Seric # define CMDVERB	17	/* verb -- go into verbose mode */
5964685Seric /* use this to catch and log "door handle" attempts on your system */
6064685Seric # define CMDLOGBOGUS	23	/* bogus command that should be logged */
6136230Skarels /* debugging-only commands, only enabled if SMTPDEBUG is defined */
6258092Seric # define CMDDBGQSHOW	24	/* showq -- show send queue */
6358092Seric # define CMDDBGDEBUG	25	/* debug -- set debug mode */
644549Seric 
654549Seric static struct cmd	CmdTab[] =
664549Seric {
674549Seric 	"mail",		CMDMAIL,
684976Seric 	"rcpt",		CMDRCPT,
694549Seric 	"data",		CMDDATA,
704549Seric 	"rset",		CMDRSET,
714549Seric 	"vrfy",		CMDVRFY,
7258092Seric 	"expn",		CMDEXPN,
734549Seric 	"help",		CMDHELP,
744549Seric 	"noop",		CMDNOOP,
754549Seric 	"quit",		CMDQUIT,
764976Seric 	"helo",		CMDHELO,
7758323Seric 	"ehlo",		CMDEHLO,
788544Seric 	"verb",		CMDVERB,
799314Seric 	"onex",		CMDONEX,
8036230Skarels 	/*
8136230Skarels 	 * remaining commands are here only
8236230Skarels 	 * to trap and log attempts to use them
8336230Skarels 	 */
849339Seric 	"showq",	CMDDBGQSHOW,
858544Seric 	"debug",	CMDDBGDEBUG,
8664685Seric 	"wiz",		CMDLOGBOGUS,
874549Seric 	NULL,		CMDERROR,
884549Seric };
894549Seric 
909378Seric bool	OneXact = FALSE;		/* one xaction only this run */
9165017Seric char	*CurSmtpClient;			/* who's at the other end of channel */
9211146Seric 
9363937Seric static char	*skipword();
9466325Seric extern char	RealUserName[];
9563937Seric 
9666325Seric 
9766283Seric #define MAXBADCOMMANDS	25		/* maximum number of bad commands */
9866283Seric 
9955012Seric smtp(e)
10055012Seric 	register ENVELOPE *e;
1014549Seric {
1024549Seric 	register char *p;
1038544Seric 	register struct cmd *c;
1044549Seric 	char *cmd;
1055003Seric 	auto ADDRESS *vrfyqueue;
10612612Seric 	ADDRESS *a;
10758109Seric 	bool gotmail;			/* mail command received */
10858092Seric 	bool gothello;			/* helo command received */
10958092Seric 	bool vrfy;			/* set if this is a vrfy command */
11058323Seric 	char *protocol;			/* sending protocol */
11159016Seric 	char *sendinghost;		/* sending hostname */
11266772Seric 	unsigned long msize;		/* approximate maximum message size */
11366005Seric 	char *peerhostname;		/* name of SMTP peer or "localhost" */
11458333Seric 	auto char *delimptr;
11558714Seric 	char *id;
11659747Seric 	int nrcpts;			/* number of RCPT commands */
11763787Seric 	bool doublequeue;
11866283Seric 	int badcommands = 0;		/* count of bad commands */
1198544Seric 	char inp[MAXLINE];
12057232Seric 	char cmdbuf[MAXLINE];
1217124Seric 	extern char Version[];
12224943Seric 	extern ENVELOPE BlankEnvelope;
1234549Seric 
12459066Seric 	if (fileno(OutChannel) != fileno(stdout))
1257363Seric 	{
1267363Seric 		/* arrange for debugging output to go to remote host */
12759066Seric 		(void) dup2(fileno(OutChannel), fileno(stdout));
1287363Seric 	}
12955012Seric 	settime(e);
13066005Seric 	peerhostname = RealHostName;
13166005Seric 	if (peerhostname == NULL)
13266005Seric 		peerhostname = "localhost";
13366005Seric 	CurHostName = peerhostname;
13465017Seric 	CurSmtpClient = macvalue('_', e);
13565017Seric 	if (CurSmtpClient == NULL)
13666003Seric 		CurSmtpClient = CurHostName;
13765017Seric 
13865017Seric 	setproctitle("server %s startup", CurSmtpClient);
13958050Seric 	expand("\201e", inp, &inp[sizeof inp], e);
14064496Seric 	if (BrokenSmtpPeers)
14164496Seric 	{
14266762Seric 		p = strchr(inp, '\n');
14366762Seric 		if (p != NULL)
14466762Seric 			*p = '\0';
14564496Seric 		message("220 %s", inp);
14664496Seric 	}
14764496Seric 	else
14864496Seric 	{
14966745Seric 		char *q = inp;
15066745Seric 
15166745Seric 		while (q != NULL)
15266745Seric 		{
15366762Seric 			p = strchr(q, '\n');
15466762Seric 			if (p != NULL)
15566762Seric 				*p++ = '\0';
15666745Seric 			message("220-%s", q);
15766745Seric 			q = p;
15866745Seric 		}
15964496Seric 		message("220 ESMTP spoken here");
16064496Seric 	}
16158330Seric 	protocol = NULL;
16259016Seric 	sendinghost = macvalue('s', e);
16358082Seric 	gothello = FALSE;
16458330Seric 	gotmail = FALSE;
1654549Seric 	for (;;)
1664549Seric 	{
16712612Seric 		/* arrange for backout */
16865751Seric 		if (setjmp(TopFrame) > 0)
16959058Seric 		{
17065751Seric 			/* if() nesting is necessary for Cray UNICOS */
17165751Seric 			if (InChild)
17265751Seric 			{
17365751Seric 				QuickAbort = FALSE;
17465751Seric 				SuprErrs = TRUE;
17565751Seric 				finis();
17665751Seric 			}
17759058Seric 		}
17812612Seric 		QuickAbort = FALSE;
17912612Seric 		HoldErrs = FALSE;
18051951Seric 		LogUsrErrs = FALSE;
18163843Seric 		e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS);
18212612Seric 
1837356Seric 		/* setup for the read */
18455012Seric 		e->e_to = NULL;
1854577Seric 		Errors = 0;
1867275Seric 		(void) fflush(stdout);
1877356Seric 
1887356Seric 		/* read the input line */
18961093Seric 		SmtpPhase = "server cmd read";
19061093Seric 		setproctitle("server %s cmd read", CurHostName);
19161093Seric 		p = sfgets(inp, sizeof inp, InChannel, TimeOuts.to_nextcommand,
19261093Seric 				SmtpPhase);
1937356Seric 
1947685Seric 		/* handle errors */
1957356Seric 		if (p == NULL)
1967356Seric 		{
1974549Seric 			/* end of file, just die */
19866017Seric 			disconnect(1, e);
19958151Seric 			message("421 %s Lost input channel from %s",
20065017Seric 				MyHostName, CurSmtpClient);
20155464Seric #ifdef LOG
20263843Seric 			if (LogLevel > (gotmail ? 1 : 19))
20355464Seric 				syslog(LOG_NOTICE, "lost input channel from %s",
20465017Seric 					CurSmtpClient);
20555464Seric #endif
20658069Seric 			if (InChild)
20758069Seric 				ExitStat = EX_QUIT;
2084549Seric 			finis();
2094549Seric 		}
2104549Seric 
2114549Seric 		/* clean up end of line */
2124558Seric 		fixcrlf(inp, TRUE);
2134549Seric 
2144713Seric 		/* echo command to transcript */
21555012Seric 		if (e->e_xfp != NULL)
21655012Seric 			fprintf(e->e_xfp, "<<< %s\n", inp);
2174713Seric 
21859060Seric 		if (e->e_id == NULL)
21965058Seric 			setproctitle("%s: %.80s", CurSmtpClient, inp);
22059060Seric 		else
22165058Seric 			setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp);
22259060Seric 
2234549Seric 		/* break off command */
22458050Seric 		for (p = inp; isascii(*p) && isspace(*p); p++)
2254549Seric 			continue;
22657232Seric 		cmd = cmdbuf;
22758050Seric 		while (*p != '\0' &&
22858050Seric 		       !(isascii(*p) && isspace(*p)) &&
22958050Seric 		       cmd < &cmdbuf[sizeof cmdbuf - 2])
23024981Seric 			*cmd++ = *p++;
23124981Seric 		*cmd = '\0';
2324549Seric 
23325691Seric 		/* throw away leading whitespace */
23458050Seric 		while (isascii(*p) && isspace(*p))
23525691Seric 			p++;
23625691Seric 
2374549Seric 		/* decode command */
2384549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
2394549Seric 		{
24033725Sbostic 			if (!strcasecmp(c->cmdname, cmdbuf))
2414549Seric 				break;
2424549Seric 		}
2434549Seric 
24451954Seric 		/* reset errors */
24551954Seric 		errno = 0;
24651954Seric 
2474549Seric 		/* process command */
2484549Seric 		switch (c->cmdcode)
2494549Seric 		{
2504976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
25158323Seric 		  case CMDEHLO:		/* extended hello */
25258323Seric 			if (c->cmdcode == CMDEHLO)
25358323Seric 			{
25458323Seric 				protocol = "ESMTP";
25561093Seric 				SmtpPhase = "server EHLO";
25658323Seric 			}
25758323Seric 			else
25858323Seric 			{
25958323Seric 				protocol = "SMTP";
26061093Seric 				SmtpPhase = "server HELO";
26158323Seric 			}
26267445Seric 
26367445Seric 			/* check for valid domain name (re 1123 5.2.5) */
26467445Seric 			if (*p == '\0')
26567445Seric 			{
26667445Seric 				message("501 %s requires domain address",
26767445Seric 					cmdbuf);
26867445Seric 				break;
26967445Seric 			}
27067445Seric 			else
27167445Seric 			{
27267445Seric 				register char *q;
27367445Seric 
27467445Seric 				for (q = p; *q != '\0'; q++)
27567445Seric 				{
27667445Seric 					if (!isascii(*q))
27767445Seric 						break;
27867445Seric 					if (isalnum(*q))
27967445Seric 						continue;
28067445Seric 					if (strchr("[].-_#", *q) == NULL)
28167445Seric 						break;
28267445Seric 				}
28367445Seric 				if (*q != '\0')
28467445Seric 				{
28567445Seric 					message("501 Invalid domain name");
28667445Seric 					break;
28767445Seric 				}
28867445Seric 			}
28967445Seric 
29059016Seric 			sendinghost = newstr(p);
29160210Seric 			gothello = TRUE;
29260210Seric 			if (c->cmdcode != CMDEHLO)
29360239Seric 			{
29460239Seric 				/* print old message and be done with it */
29560239Seric 				message("250 %s Hello %s, pleased to meet you",
29665017Seric 					MyHostName, CurSmtpClient);
29760210Seric 				break;
29860239Seric 			}
29960239Seric 
30060239Seric 			/* print extended message and brag */
30160239Seric 			message("250-%s Hello %s, pleased to meet you",
30266760Seric 				MyHostName, CurSmtpClient);
30358323Seric 			if (!bitset(PRIV_NOEXPN, PrivacyFlags))
30458323Seric 				message("250-EXPN");
30567417Seric 			message("250-8BITMIME");
30664359Seric 			if (MaxMessageSize > 0)
30764359Seric 				message("250-SIZE %ld", MaxMessageSize);
30859271Seric 			else
30959271Seric 				message("250-SIZE");
31068028Seric #ifdef DSN
31167963Seric 			message("250-X-DSN-1");
31268028Seric #endif
31358323Seric 			message("250 HELP");
3144976Seric 			break;
3154976Seric 
3164549Seric 		  case CMDMAIL:		/* mail -- designate sender */
31761093Seric 			SmtpPhase = "server MAIL";
31824943Seric 
3199314Seric 			/* check for validity of this command */
32058789Seric 			if (!gothello)
32158082Seric 			{
32258957Seric 				/* set sending host to our known value */
32359016Seric 				if (sendinghost == NULL)
32466005Seric 					sendinghost = peerhostname;
32558957Seric 
32658789Seric 				if (bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
32758821Seric 				{
32858789Seric 					message("503 Polite people say HELO first");
32958821Seric 					break;
33058821Seric 				}
33158082Seric 			}
33258109Seric 			if (gotmail)
3334558Seric 			{
33458151Seric 				message("503 Sender already specified");
33563843Seric 				if (InChild)
33663843Seric 					finis();
3374558Seric 				break;
3384558Seric 			}
3399339Seric 			if (InChild)
3409339Seric 			{
34136230Skarels 				errno = 0;
34258151Seric 				syserr("503 Nested MAIL command: MAIL %s", p);
34358069Seric 				finis();
3449339Seric 			}
3459339Seric 
3469339Seric 			/* fork a subprocess to process this command */
34755012Seric 			if (runinchild("SMTP-MAIL", e) > 0)
3489339Seric 				break;
34963753Seric 			if (!gothello)
35063753Seric 			{
35163753Seric 				auth_warning(e,
35266005Seric 					"Host %s didn't use HELO protocol",
35366005Seric 					peerhostname);
35463753Seric 			}
35565947Seric #ifdef PICKY_HELO_CHECK
35666005Seric 			if (strcasecmp(sendinghost, peerhostname) != 0 &&
35766005Seric 			    (strcasecmp(peerhostname, "localhost") != 0 ||
35865823Seric 			     strcasecmp(sendinghost, MyHostName) != 0))
35965823Seric 			{
36065823Seric 				auth_warning(e, "Host %s claimed to be %s",
36166005Seric 					peerhostname, sendinghost);
36265823Seric 			}
36365947Seric #endif
36465823Seric 
36558323Seric 			if (protocol == NULL)
36658323Seric 				protocol = "SMTP";
36758323Seric 			define('r', protocol, e);
36859016Seric 			define('s', sendinghost, e);
36955012Seric 			initsys(e);
37059747Seric 			nrcpts = 0;
37165089Seric 			e->e_flags |= EF_LOGSENDER;
37265058Seric 			setproctitle("%s %s: %.80s", e->e_id, CurSmtpClient, inp);
3739339Seric 
3749339Seric 			/* child -- go do the processing */
3754549Seric 			p = skipword(p, "from");
3764549Seric 			if (p == NULL)
3774549Seric 				break;
37857977Seric 			if (setjmp(TopFrame) > 0)
37958147Seric 			{
38058147Seric 				/* this failed -- undo work */
38158147Seric 				if (InChild)
38259058Seric 				{
38359058Seric 					QuickAbort = FALSE;
38459058Seric 					SuprErrs = TRUE;
38563787Seric 					e->e_flags &= ~EF_FATALERRS;
38658147Seric 					finis();
38759058Seric 				}
38857977Seric 				break;
38958147Seric 			}
39057977Seric 			QuickAbort = TRUE;
39158333Seric 
39258333Seric 			/* must parse sender first */
39358333Seric 			delimptr = NULL;
39458704Seric 			setsender(p, e, &delimptr, FALSE);
39558333Seric 			p = delimptr;
39658333Seric 			if (p != NULL && *p != '\0')
39758333Seric 				*p++ = '\0';
39858333Seric 
39966325Seric 			/* check for possible spoofing */
40066325Seric 			if (RealUid != 0 && OpMode == MD_SMTP &&
40167473Seric 			    !bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) &&
40267473Seric 			    strcmp(e->e_from.q_user, RealUserName) != 0)
40366325Seric 			{
40466325Seric 				auth_warning(e, "%s owned process doing -bs",
40566325Seric 					RealUserName);
40666325Seric 			}
40766325Seric 
40858333Seric 			/* now parse ESMTP arguments */
40958333Seric 			msize = 0;
41066764Seric 			while (p != NULL && *p != '\0')
41158333Seric 			{
41258333Seric 				char *kp;
41366304Seric 				char *vp = NULL;
41458333Seric 
41558333Seric 				/* locate the beginning of the keyword */
41658333Seric 				while (isascii(*p) && isspace(*p))
41758333Seric 					p++;
41858333Seric 				if (*p == '\0')
41958333Seric 					break;
42058333Seric 				kp = p;
42158333Seric 
42258333Seric 				/* skip to the value portion */
42358333Seric 				while (isascii(*p) && isalnum(*p) || *p == '-')
42458333Seric 					p++;
42558333Seric 				if (*p == '=')
42658333Seric 				{
42758333Seric 					*p++ = '\0';
42858333Seric 					vp = p;
42958333Seric 
43058333Seric 					/* skip to the end of the value */
43158333Seric 					while (*p != '\0' && *p != ' ' &&
43258333Seric 					       !(isascii(*p) && iscntrl(*p)) &&
43358333Seric 					       *p != '=')
43458333Seric 						p++;
43558333Seric 				}
43658333Seric 
43758333Seric 				if (*p != '\0')
43858333Seric 					*p++ = '\0';
43958333Seric 
44058333Seric 				if (tTd(19, 1))
44166764Seric 					printf("MAIL: got arg %s=\"%s\"\n", kp,
44258333Seric 						vp == NULL ? "<null>" : vp);
44358333Seric 
44458333Seric 				if (strcasecmp(kp, "size") == 0)
44558333Seric 				{
44659093Seric 					if (vp == NULL)
44758333Seric 					{
44858333Seric 						usrerr("501 SIZE requires a value");
44958333Seric 						/* NOTREACHED */
45058333Seric 					}
45166772Seric # ifdef __STDC__
45266772Seric 					msize = strtoul(vp, (char **) NULL, 10);
45366772Seric # else
45466772Seric 					msize = strtol(vp, (char **) NULL, 10);
45566772Seric # endif
45658333Seric 				}
45759093Seric 				else if (strcasecmp(kp, "body") == 0)
45859093Seric 				{
45959093Seric 					if (vp == NULL)
46059093Seric 					{
46159093Seric 						usrerr("501 BODY requires a value");
46259093Seric 						/* NOTREACHED */
46359093Seric 					}
46467417Seric 					e->e_bodytype = newstr(vp);
46559093Seric 					if (strcasecmp(vp, "8bitmime") == 0)
46659093Seric 					{
46767546Seric 						SevenBitInput = FALSE;
46859093Seric 					}
46959093Seric 					else if (strcasecmp(vp, "7bit") == 0)
47059093Seric 					{
47167546Seric 						SevenBitInput = TRUE;
47259093Seric 					}
47359093Seric 					else
47459093Seric 					{
47559093Seric 						usrerr("501 Unknown BODY type %s",
47659093Seric 							vp);
47767417Seric 						/* NOTREACHED */
47859093Seric 					}
47959093Seric 				}
48067880Seric 				else if (strcasecmp(kp, "envid") == 0)
48167880Seric 				{
48267880Seric 					if (vp == NULL)
48367880Seric 					{
48467880Seric 						usrerr("501 ENVID requires a value");
48567880Seric 						/* NOTREACHED */
48667880Seric 					}
48767880Seric 					e->e_envid = newstr(vp);
48867880Seric 				}
48967963Seric 				else if (strcasecmp(kp, "omts") == 0)
49067963Seric 				{
49167963Seric 					if (vp == NULL)
49267963Seric 					{
49367963Seric 						usrerr("501 OMTS requires a value");
49467963Seric 						/* NOTREACHED */
49567963Seric 					}
49667963Seric 					e->e_omts = newstr(vp);
49767963Seric 				}
49858333Seric 				else
49958333Seric 				{
50058333Seric 					usrerr("501 %s parameter unrecognized", kp);
50158333Seric 					/* NOTREACHED */
50258333Seric 				}
50358333Seric 			}
50459284Seric 
50559284Seric 			if (MaxMessageSize > 0 && msize > MaxMessageSize)
50659284Seric 			{
50759284Seric 				usrerr("552 Message size exceeds fixed maximum message size (%ld)",
50859284Seric 					MaxMessageSize);
50959284Seric 				/* NOTREACHED */
51059284Seric 			}
51158333Seric 
51258333Seric 			if (!enoughspace(msize))
51358333Seric 			{
51458333Seric 				message("452 Insufficient disk space; try again later");
51558333Seric 				break;
51658333Seric 			}
51758151Seric 			message("250 Sender ok");
51858147Seric 			gotmail = TRUE;
5194549Seric 			break;
5204549Seric 
5214976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
52258850Seric 			if (!gotmail)
52358850Seric 			{
52458850Seric 				usrerr("503 Need MAIL before RCPT");
52558850Seric 				break;
52658850Seric 			}
52761093Seric 			SmtpPhase = "server RCPT";
52812612Seric 			if (setjmp(TopFrame) > 0)
52914785Seric 			{
53055012Seric 				e->e_flags &= ~EF_FATALERRS;
53112612Seric 				break;
53214785Seric 			}
53312612Seric 			QuickAbort = TRUE;
53451951Seric 			LogUsrErrs = TRUE;
53558093Seric 
53659699Seric 			if (e->e_sendmode != SM_DELIVER)
53759699Seric 				e->e_flags |= EF_VRFYONLY;
53858919Seric 
5394549Seric 			p = skipword(p, "to");
5404549Seric 			if (p == NULL)
5414549Seric 				break;
54267880Seric 			a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, e);
54312612Seric 			if (a == NULL)
54412612Seric 				break;
54567880Seric 			p = delimptr;
54667880Seric 
54767880Seric 			/* now parse ESMTP arguments */
54867880Seric 			while (p != NULL && *p != '\0')
54967880Seric 			{
55067880Seric 				char *kp;
55167880Seric 				char *vp = NULL;
55267880Seric 
55367880Seric 				/* locate the beginning of the keyword */
55467880Seric 				while (isascii(*p) && isspace(*p))
55567880Seric 					p++;
55667880Seric 				if (*p == '\0')
55767880Seric 					break;
55867880Seric 				kp = p;
55967880Seric 
56067880Seric 				/* skip to the value portion */
56167880Seric 				while (isascii(*p) && isalnum(*p) || *p == '-')
56267880Seric 					p++;
56367880Seric 				if (*p == '=')
56467880Seric 				{
56567880Seric 					*p++ = '\0';
56667880Seric 					vp = p;
56767880Seric 
56867880Seric 					/* skip to the end of the value */
56967880Seric 					while (*p != '\0' && *p != ' ' &&
57067880Seric 					       !(isascii(*p) && iscntrl(*p)) &&
57167880Seric 					       *p != '=')
57267880Seric 						p++;
57367880Seric 				}
57467880Seric 
57567880Seric 				if (*p != '\0')
57667880Seric 					*p++ = '\0';
57767880Seric 
57867880Seric 				if (tTd(19, 1))
57967880Seric 					printf("RCPT: got arg %s=\"%s\"\n", kp,
58067880Seric 						vp == NULL ? "<null>" : vp);
58167880Seric 
58267963Seric 				rcpt_esmtp_args(a, kp, vp, e);
58367963Seric 
58467880Seric 			}
58567980Seric 
58667980Seric 			/* save in recipient list after ESMTP mods */
58767980Seric 			a->q_flags |= QPRIMARY;
58867982Seric 			a = recipient(a, &e->e_sendqueue, 0, e);
58967980Seric 
59012612Seric 			if (Errors != 0)
59112612Seric 				break;
59212612Seric 
59312612Seric 			/* no errors during parsing, but might be a duplicate */
59455012Seric 			e->e_to = p;
59512612Seric 			if (!bitset(QBADADDR, a->q_flags))
59659747Seric 			{
59764718Seric 				message("250 Recipient ok%s",
59864718Seric 					bitset(QQUEUEUP, a->q_flags) ?
59964718Seric 						" (will queue)" : "");
60059747Seric 				nrcpts++;
60159747Seric 			}
60212612Seric 			else
6034549Seric 			{
60412612Seric 				/* punt -- should keep message in ADDRESS.... */
60558151Seric 				message("550 Addressee unknown");
6064549Seric 			}
60755012Seric 			e->e_to = NULL;
6084549Seric 			break;
6094549Seric 
6104549Seric 		  case CMDDATA:		/* data -- text of mail */
61161093Seric 			SmtpPhase = "server DATA";
61258109Seric 			if (!gotmail)
6134549Seric 			{
61458151Seric 				message("503 Need MAIL command");
6154976Seric 				break;
6164549Seric 			}
61764718Seric 			else if (nrcpts <= 0)
6184549Seric 			{
61958151Seric 				message("503 Need RCPT (recipient)");
6204976Seric 				break;
6214549Seric 			}
6224976Seric 
62358929Seric 			/* check to see if we need to re-expand aliases */
62463787Seric 			/* also reset QBADADDR on already-diagnosted addrs */
62563787Seric 			doublequeue = FALSE;
62658929Seric 			for (a = e->e_sendqueue; a != NULL; a = a->q_next)
62758929Seric 			{
62858929Seric 				if (bitset(QVERIFIED, a->q_flags))
62963787Seric 				{
63063787Seric 					/* need to re-expand aliases */
63163787Seric 					doublequeue = TRUE;
63263787Seric 				}
63363787Seric 				if (bitset(QBADADDR, a->q_flags))
63463787Seric 				{
63563787Seric 					/* make this "go away" */
63663787Seric 					a->q_flags |= QDONTSEND;
63763787Seric 					a->q_flags &= ~QBADADDR;
63863787Seric 				}
63958929Seric 			}
64058929Seric 
6414976Seric 			/* collect the text of the message */
64224943Seric 			SmtpPhase = "collect";
64367546Seric 			collect(InChannel, TRUE, doublequeue, NULL, e);
64464766Seric 			if (Errors != 0)
64564766Seric 				goto abortmessage;
64667131Seric 
64767131Seric 			/* from now on, we have to operate silently */
64863965Seric 			HoldErrs = TRUE;
64967131Seric 			e->e_errormode = EM_MAIL;
6504976Seric 
6518238Seric 			/*
6528238Seric 			**  Arrange to send to everyone.
6538238Seric 			**	If sending to multiple people, mail back
6548238Seric 			**		errors rather than reporting directly.
6558238Seric 			**	In any case, don't mail back errors for
6568238Seric 			**		anything that has happened up to
6578238Seric 			**		now (the other end will do this).
65810197Seric 			**	Truncate our transcript -- the mail has gotten
65910197Seric 			**		to us successfully, and if we have
66010197Seric 			**		to mail this back, it will be easier
66110197Seric 			**		on the reader.
6628238Seric 			**	Then send to everyone.
6638238Seric 			**	Finally give a reply code.  If an error has
6648238Seric 			**		already been given, don't mail a
6658238Seric 			**		message back.
6669339Seric 			**	We goose error returns by clearing error bit.
6678238Seric 			*/
6688238Seric 
66924943Seric 			SmtpPhase = "delivery";
67055012Seric 			e->e_xfp = freopen(queuename(e, 'x'), "w", e->e_xfp);
67158714Seric 			id = e->e_id;
6724976Seric 
67367131Seric 			if (doublequeue)
67459730Seric 			{
67567131Seric 				/* make sure it is in the queue */
67667131Seric 				queueup(e, TRUE, FALSE);
677*68035Seric 				if (e->e_sendmode == SM_QUEUE)
678*68035Seric 					e->e_flags |= EF_KEEPQUEUE;
67959730Seric 			}
6808238Seric 			else
68158919Seric 			{
68267131Seric 				/* send to all recipients */
68367131Seric 				sendall(e, SM_DEFAULT);
68467131Seric 			}
68567131Seric 			e->e_to = NULL;
68659747Seric 
68767131Seric 			/* issue success message */
68867131Seric 			message("250 %s Message accepted for delivery", id);
68964296Seric 
69067131Seric 			/* if we just queued, poke it */
69167131Seric 			if (doublequeue && e->e_sendmode != SM_QUEUE)
69267131Seric 			{
69367131Seric 				extern pid_t dowork();
69467131Seric 
69567131Seric 				unlockqueue(e);
69667131Seric 				(void) dowork(id, TRUE, TRUE, e);
69758919Seric 			}
69858883Seric 
69959747Seric   abortmessage:
7009339Seric 			/* if in a child, pop back to our parent */
7019339Seric 			if (InChild)
7029339Seric 				finis();
70324943Seric 
70424943Seric 			/* clean up a bit */
70558109Seric 			gotmail = FALSE;
70655012Seric 			dropenvelope(e);
70758179Seric 			CurEnv = e = newenvelope(e, CurEnv);
70855012Seric 			e->e_flags = BlankEnvelope.e_flags;
7094549Seric 			break;
7104549Seric 
7114549Seric 		  case CMDRSET:		/* rset -- reset state */
71258151Seric 			message("250 Reset state");
71364359Seric 			e->e_flags |= EF_CLRQUEUE;
7149339Seric 			if (InChild)
7159339Seric 				finis();
71658109Seric 
71758109Seric 			/* clean up a bit */
71858109Seric 			gotmail = FALSE;
71958109Seric 			dropenvelope(e);
72058179Seric 			CurEnv = e = newenvelope(e, CurEnv);
7219339Seric 			break;
7224549Seric 
7234549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
72458092Seric 		  case CMDEXPN:		/* expn -- expand address */
72558092Seric 			vrfy = c->cmdcode == CMDVRFY;
72658092Seric 			if (bitset(vrfy ? PRIV_NOVRFY : PRIV_NOEXPN,
72758092Seric 						PrivacyFlags))
72858082Seric 			{
72958412Seric 				if (vrfy)
73067160Seric 					message("252 Cannot VRFY user; try RCPT to attempt delivery (or try finger)");
73158412Seric 				else
73265192Seric 					message("502 Sorry, we do not allow this operation");
73365017Seric #ifdef LOG
73465017Seric 				if (LogLevel > 5)
73565017Seric 					syslog(LOG_INFO, "%s: %s [rejected]",
73665017Seric 						CurSmtpClient, inp);
73765017Seric #endif
73858082Seric 				break;
73958082Seric 			}
74058082Seric 			else if (!gothello &&
74158092Seric 				 bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO,
74258092Seric 						PrivacyFlags))
74358082Seric 			{
74458151Seric 				message("503 I demand that you introduce yourself first");
74558082Seric 				break;
74658082Seric 			}
74758092Seric 			if (runinchild(vrfy ? "SMTP-VRFY" : "SMTP-EXPN", e) > 0)
7489339Seric 				break;
74955173Seric #ifdef LOG
75058020Seric 			if (LogLevel > 5)
75165017Seric 				syslog(LOG_INFO, "%s: %s", CurSmtpClient, inp);
75255173Seric #endif
7535003Seric 			vrfyqueue = NULL;
7547762Seric 			QuickAbort = TRUE;
75558092Seric 			if (vrfy)
75658092Seric 				e->e_flags |= EF_VRFYONLY;
75762373Seric 			while (*p != '\0' && isascii(*p) && isspace(*p))
75867615Seric 				p++;
75962373Seric 			if (*p == '\0')
76062373Seric 			{
76162373Seric 				message("501 Argument required");
76262373Seric 				Errors++;
76362373Seric 			}
76462373Seric 			else
76562373Seric 			{
76667990Seric 				(void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e);
76762373Seric 			}
7687762Seric 			if (Errors != 0)
7699339Seric 			{
7709339Seric 				if (InChild)
7719339Seric 					finis();
7727762Seric 				break;
7739339Seric 			}
77462373Seric 			if (vrfyqueue == NULL)
77562373Seric 			{
77662373Seric 				message("554 Nothing to %s", vrfy ? "VRFY" : "EXPN");
77762373Seric 			}
7785003Seric 			while (vrfyqueue != NULL)
7795003Seric 			{
78063971Seric 				a = vrfyqueue;
78163971Seric 				while ((a = a->q_next) != NULL &&
78263971Seric 				       bitset(QDONTSEND|QBADADDR, a->q_flags))
78363971Seric 					continue;
7847685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
78558151Seric 					printvrfyaddr(vrfyqueue, a == NULL);
78663847Seric 				vrfyqueue = vrfyqueue->q_next;
7875003Seric 			}
7889339Seric 			if (InChild)
7899339Seric 				finis();
7904549Seric 			break;
7914549Seric 
7924549Seric 		  case CMDHELP:		/* help -- give user info */
7934577Seric 			help(p);
7944549Seric 			break;
7954549Seric 
7964549Seric 		  case CMDNOOP:		/* noop -- do nothing */
79764122Seric 			message("250 OK");
7984549Seric 			break;
7994549Seric 
8004549Seric 		  case CMDQUIT:		/* quit -- leave mail */
80158151Seric 			message("221 %s closing connection", MyHostName);
80261051Seric 
80366283Seric doquit:
80461051Seric 			/* avoid future 050 messages */
80566017Seric 			disconnect(1, e);
80661051Seric 
8079339Seric 			if (InChild)
8089339Seric 				ExitStat = EX_QUIT;
8094549Seric 			finis();
8104549Seric 
8118544Seric 		  case CMDVERB:		/* set verbose mode */
81259957Seric 			if (bitset(PRIV_NOEXPN, PrivacyFlags))
81359957Seric 			{
81459957Seric 				/* this would give out the same info */
81559957Seric 				message("502 Verbose unavailable");
81659957Seric 				break;
81759957Seric 			}
8188544Seric 			Verbose = TRUE;
81958734Seric 			e->e_sendmode = SM_DELIVER;
82059957Seric 			message("250 Verbose mode");
8218544Seric 			break;
8228544Seric 
8239314Seric 		  case CMDONEX:		/* doing one transaction only */
8249378Seric 			OneXact = TRUE;
82559957Seric 			message("250 Only one transaction");
8269314Seric 			break;
8279314Seric 
82836230Skarels # ifdef SMTPDEBUG
8299339Seric 		  case CMDDBGQSHOW:	/* show queues */
8306907Seric 			printf("Send Queue=");
83155012Seric 			printaddr(e->e_sendqueue, TRUE);
8325003Seric 			break;
8337275Seric 
8347275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
8357676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
8367676Seric 			tTflag(p);
83758151Seric 			message("200 Debug set");
8387275Seric 			break;
8397275Seric 
84036230Skarels # else /* not SMTPDEBUG */
84136230Skarels 		  case CMDDBGQSHOW:	/* show queues */
84236230Skarels 		  case CMDDBGDEBUG:	/* set debug mode */
84364685Seric # endif /* SMTPDEBUG */
84464685Seric 		  case CMDLOGBOGUS:	/* bogus command */
84536233Skarels # ifdef LOG
84658308Seric 			if (LogLevel > 0)
84764685Seric 				syslog(LOG_CRIT,
84858020Seric 				    "\"%s\" command from %s (%s)",
84966005Seric 				    c->cmdname, peerhostname,
85058755Seric 				    anynet_ntoa(&RealHostAddr));
85136233Skarels # endif
85236230Skarels 			/* FALL THROUGH */
85336230Skarels 
8544549Seric 		  case CMDERROR:	/* unknown command */
85566283Seric 			if (++badcommands > MAXBADCOMMANDS)
85666283Seric 			{
85766283Seric 				message("421 %s Too many bad commands; closing connection",
85866283Seric 					MyHostName);
85966283Seric 				goto doquit;
86066283Seric 			}
86166283Seric 
86258151Seric 			message("500 Command unrecognized");
8634549Seric 			break;
8644549Seric 
8654549Seric 		  default:
86636230Skarels 			errno = 0;
86758151Seric 			syserr("500 smtp: unknown code %d", c->cmdcode);
8684549Seric 			break;
8694549Seric 		}
8704549Seric 	}
8714549Seric }
8724549Seric /*
8734549Seric **  SKIPWORD -- skip a fixed word.
8744549Seric **
8754549Seric **	Parameters:
8764549Seric **		p -- place to start looking.
8774549Seric **		w -- word to skip.
8784549Seric **
8794549Seric **	Returns:
8804549Seric **		p following w.
8814549Seric **		NULL on error.
8824549Seric **
8834549Seric **	Side Effects:
8844549Seric **		clobbers the p data area.
8854549Seric */
8864549Seric 
8874549Seric static char *
8884549Seric skipword(p, w)
8894549Seric 	register char *p;
8904549Seric 	char *w;
8914549Seric {
8924549Seric 	register char *q;
89366005Seric 	char *firstp = p;
8944549Seric 
8954549Seric 	/* find beginning of word */
89658050Seric 	while (isascii(*p) && isspace(*p))
8974549Seric 		p++;
8984549Seric 	q = p;
8994549Seric 
9004549Seric 	/* find end of word */
90158050Seric 	while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p)))
9024549Seric 		p++;
90358050Seric 	while (isascii(*p) && isspace(*p))
9044549Seric 		*p++ = '\0';
9054549Seric 	if (*p != ':')
9064549Seric 	{
9074549Seric 	  syntax:
90866005Seric 		message("501 Syntax error in parameters scanning \"%s\"",
90966005Seric 			firstp);
9104549Seric 		Errors++;
9114549Seric 		return (NULL);
9124549Seric 	}
9134549Seric 	*p++ = '\0';
91458050Seric 	while (isascii(*p) && isspace(*p))
9154549Seric 		p++;
9164549Seric 
91762373Seric 	if (*p == '\0')
91862373Seric 		goto syntax;
91962373Seric 
9204549Seric 	/* see if the input word matches desired word */
92133725Sbostic 	if (strcasecmp(q, w))
9224549Seric 		goto syntax;
9234549Seric 
9244549Seric 	return (p);
9254549Seric }
9264577Seric /*
92767963Seric **  RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line
92867963Seric **
92967963Seric **	Parameters:
93067963Seric **		a -- the address corresponding to the To: parameter.
93167963Seric **		kp -- the parameter key.
93267963Seric **		vp -- the value of that parameter.
93367963Seric **		e -- the envelope.
93467963Seric **
93567963Seric **	Returns:
93667963Seric **		none.
93767963Seric */
93867963Seric 
93967963Seric rcpt_esmtp_args(a, kp, vp, e)
94067963Seric 	ADDRESS *a;
94167963Seric 	char *kp;
94267963Seric 	char *vp;
94367963Seric 	ENVELOPE *e;
94467963Seric {
94567963Seric 	if (strcasecmp(kp, "notify") == 0)
94667963Seric 	{
94767963Seric 		char *p;
94867963Seric 
94967963Seric 		if (vp == NULL)
95067963Seric 		{
95167963Seric 			usrerr("501 NOTIFY requires a value");
95267963Seric 			/* NOTREACHED */
95367963Seric 		}
95467963Seric 		a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY);
95567963Seric 		if (strcasecmp(vp, "never") == 0)
95667963Seric 			return;
95767963Seric 		for (p = vp; p != NULL; vp = p)
95867963Seric 		{
95967963Seric 			p = strchr(p, ',');
96067963Seric 			if (p != NULL)
96167963Seric 				*p++ = '\0';
96267963Seric 			if (strcasecmp(vp, "success") == 0)
96367963Seric 				a->q_flags |= QPINGONSUCCESS;
96467963Seric 			else if (strcasecmp(vp, "failure") == 0)
96567963Seric 				a->q_flags |= QPINGONFAILURE;
96667963Seric 			else if (strcasecmp(vp, "delay") == 0)
96767963Seric 				a->q_flags |= QPINGONDELAY;
96867963Seric 			else
96967963Seric 			{
97067963Seric 				usrerr("501 Bad argument \"%s\"  to NOTIFY",
97167963Seric 					vp);
97267963Seric 				/* NOTREACHED */
97367963Seric 			}
97467963Seric 		}
97567963Seric 	}
97667963Seric 	else if (strcasecmp(kp, "ret") == 0)
97767963Seric 	{
97867963Seric 		if (vp == NULL)
97967963Seric 		{
98067963Seric 			usrerr("501 RET requires a value");
98167963Seric 			/* NOTREACHED */
98267963Seric 		}
98367963Seric 		a->q_flags |= QHAS_RET_PARAM;
98467963Seric 		if (strcasecmp(vp, "hdrs") == 0)
98567963Seric 			a->q_flags |= QRET_HDRS;
98667963Seric 		else if (strcasecmp(vp, "full") != 0)
98767963Seric 		{
98867963Seric 			usrerr("501 Bad argument \"%s\" to RET", vp);
98967963Seric 			/* NOTREACHED */
99067963Seric 		}
99167963Seric 	}
99267963Seric 	else if (strcasecmp(kp, "orcpt") == 0)
99367963Seric 	{
99467963Seric 		if (vp == NULL)
99567963Seric 		{
99667963Seric 			usrerr("501 ORCPT requires a value");
99767963Seric 			/* NOTREACHED */
99867963Seric 		}
99967963Seric 		a->q_orcpt = newstr(vp);
100067963Seric 	}
100167963Seric 	else
100267963Seric 	{
100367963Seric 		usrerr("501 %s parameter unrecognized", kp);
100467963Seric 		/* NOTREACHED */
100567963Seric 	}
100667963Seric }
100767963Seric /*
100858151Seric **  PRINTVRFYADDR -- print an entry in the verify queue
100958151Seric **
101058151Seric **	Parameters:
101158151Seric **		a -- the address to print
101258151Seric **		last -- set if this is the last one.
101358151Seric **
101458151Seric **	Returns:
101558151Seric **		none.
101658151Seric **
101758151Seric **	Side Effects:
101858151Seric **		Prints the appropriate 250 codes.
101958151Seric */
102058151Seric 
102158151Seric printvrfyaddr(a, last)
102258151Seric 	register ADDRESS *a;
102358151Seric 	bool last;
102458151Seric {
102558151Seric 	char fmtbuf[20];
102658151Seric 
102758151Seric 	strcpy(fmtbuf, "250");
102858151Seric 	fmtbuf[3] = last ? ' ' : '-';
102958151Seric 
103059746Seric 	if (a->q_fullname == NULL)
103159746Seric 	{
103259746Seric 		if (strchr(a->q_user, '@') == NULL)
103359746Seric 			strcpy(&fmtbuf[4], "<%s@%s>");
103459746Seric 		else
103559746Seric 			strcpy(&fmtbuf[4], "<%s>");
103659746Seric 		message(fmtbuf, a->q_user, MyHostName);
103759746Seric 	}
103858151Seric 	else
103958151Seric 	{
104059746Seric 		if (strchr(a->q_user, '@') == NULL)
104159746Seric 			strcpy(&fmtbuf[4], "%s <%s@%s>");
104259746Seric 		else
104359746Seric 			strcpy(&fmtbuf[4], "%s <%s>");
104459746Seric 		message(fmtbuf, a->q_fullname, a->q_user, MyHostName);
104558151Seric 	}
104658151Seric }
104758151Seric /*
10484577Seric **  HELP -- implement the HELP command.
10494577Seric **
10504577Seric **	Parameters:
10514577Seric **		topic -- the topic we want help for.
10524577Seric **
10534577Seric **	Returns:
10544577Seric **		none.
10554577Seric **
10564577Seric **	Side Effects:
10574577Seric **		outputs the help file to message output.
10584577Seric */
10594577Seric 
10604577Seric help(topic)
10614577Seric 	char *topic;
10624577Seric {
10634577Seric 	register FILE *hf;
10644577Seric 	int len;
10654577Seric 	char buf[MAXLINE];
10664577Seric 	bool noinfo;
10674577Seric 
10688269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
10694577Seric 	{
10704577Seric 		/* no help */
107111931Seric 		errno = 0;
107258151Seric 		message("502 HELP not implemented");
10734577Seric 		return;
10744577Seric 	}
10754577Seric 
107649669Seric 	if (topic == NULL || *topic == '\0')
107749669Seric 		topic = "smtp";
107849669Seric 	else
107949669Seric 		makelower(topic);
108049669Seric 
10814577Seric 	len = strlen(topic);
10824577Seric 	noinfo = TRUE;
10834577Seric 
10844577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
10854577Seric 	{
10864577Seric 		if (strncmp(buf, topic, len) == 0)
10874577Seric 		{
10884577Seric 			register char *p;
10894577Seric 
109056795Seric 			p = strchr(buf, '\t');
10914577Seric 			if (p == NULL)
10924577Seric 				p = buf;
10934577Seric 			else
10944577Seric 				p++;
10954577Seric 			fixcrlf(p, TRUE);
109658151Seric 			message("214-%s", p);
10974577Seric 			noinfo = FALSE;
10984577Seric 		}
10994577Seric 	}
11004577Seric 
11014577Seric 	if (noinfo)
110258151Seric 		message("504 HELP topic unknown");
11034577Seric 	else
110458151Seric 		message("214 End of HELP info");
11054628Seric 	(void) fclose(hf);
11064577Seric }
11078544Seric /*
11089339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
11099339Seric **
11109339Seric **	Parameters:
11119339Seric **		label -- a string used in error messages
11129339Seric **
11139339Seric **	Returns:
11149339Seric **		zero in the child
11159339Seric **		one in the parent
11169339Seric **
11179339Seric **	Side Effects:
11189339Seric **		none.
11199339Seric */
11208544Seric 
112155012Seric runinchild(label, e)
11229339Seric 	char *label;
112355012Seric 	register ENVELOPE *e;
11249339Seric {
11259339Seric 	int childpid;
11269339Seric 
112716158Seric 	if (!OneXact)
11289339Seric 	{
112916158Seric 		childpid = dofork();
113016158Seric 		if (childpid < 0)
113116158Seric 		{
113216158Seric 			syserr("%s: cannot fork", label);
113316158Seric 			return (1);
113416158Seric 		}
113516158Seric 		if (childpid > 0)
113616158Seric 		{
113716158Seric 			auto int st;
11389339Seric 
113916158Seric 			/* parent -- wait for child to complete */
114061093Seric 			setproctitle("server %s child wait", CurHostName);
114116158Seric 			st = waitfor(childpid);
114216158Seric 			if (st == -1)
114316158Seric 				syserr("%s: lost child", label);
114464948Seric 			else if (!WIFEXITED(st))
114564948Seric 				syserr("%s: died on signal %d",
114664948Seric 					label, st & 0177);
11479339Seric 
114816158Seric 			/* if we exited on a QUIT command, complete the process */
114966017Seric 			if (WEXITSTATUS(st) == EX_QUIT)
115066017Seric 			{
115166017Seric 				disconnect(1, e);
115216158Seric 				finis();
115366017Seric 			}
11549339Seric 
115516158Seric 			return (1);
115616158Seric 		}
115716158Seric 		else
115816158Seric 		{
115916158Seric 			/* child */
116016158Seric 			InChild = TRUE;
116125050Seric 			QuickAbort = FALSE;
116255012Seric 			clearenvelope(e, FALSE);
116316158Seric 		}
11649339Seric 	}
116515256Seric 
116616158Seric 	/* open alias database */
116760537Seric 	initmaps(FALSE, e);
116816158Seric 
116916158Seric 	return (0);
11709339Seric }
11719339Seric 
117256795Seric # endif /* SMTP */
1173