19339Seric # include <errno.h>
24549Seric # include "sendmail.h"
311728Seric # include <signal.h>
44549Seric 
55181Seric # ifndef SMTP
6*14785Seric SCCSID(@(#)srvrsmtp.c	4.2		08/21/83	(no SMTP));
75181Seric # else SMTP
84556Seric 
9*14785Seric SCCSID(@(#)srvrsmtp.c	4.2		08/21/83);
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 */
489339Seric # define CMDDBGSHELL	16	/* shell -- give us a shell */
494549Seric 
504549Seric static struct cmd	CmdTab[] =
514549Seric {
524549Seric 	"mail",		CMDMAIL,
534976Seric 	"rcpt",		CMDRCPT,
544549Seric 	"data",		CMDDATA,
554549Seric 	"rset",		CMDRSET,
564549Seric 	"vrfy",		CMDVRFY,
577762Seric 	"expn",		CMDVRFY,
584549Seric 	"help",		CMDHELP,
594549Seric 	"noop",		CMDNOOP,
604549Seric 	"quit",		CMDQUIT,
614976Seric 	"helo",		CMDHELO,
628544Seric 	"verb",		CMDVERB,
639314Seric 	"onex",		CMDONEX,
645003Seric # ifdef DEBUG
659339Seric 	"showq",	CMDDBGQSHOW,
668544Seric 	"debug",	CMDDBGDEBUG,
678544Seric 	"kill",		CMDDBGKILL,
688544Seric 	"wiz",		CMDDBGWIZ,
699339Seric 	"shell",	CMDDBGSHELL,
705003Seric # endif DEBUG
714549Seric 	NULL,		CMDERROR,
724549Seric };
734549Seric 
748544Seric # ifdef DEBUG
758544Seric bool	IsWiz = FALSE;			/* set if we are a wizard */
768544Seric char	*WizWord = NULL;		/* the wizard word to compare against */
778544Seric # endif DEBUG
789339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
799378Seric bool	OneXact = FALSE;		/* one xaction only this run */
8011146Seric char	*RealHostName = NULL;		/* verified hostname, set in daemon.c */
8111146Seric 
829339Seric #define EX_QUIT		22		/* special code for QUIT command */
838544Seric 
844549Seric smtp()
854549Seric {
864549Seric 	register char *p;
878544Seric 	register struct cmd *c;
884549Seric 	char *cmd;
894549Seric 	extern char *skipword();
904549Seric 	extern bool sameword();
914549Seric 	bool hasmail;			/* mail command received */
924713Seric 	int rcps;			/* number of recipients */
935003Seric 	auto ADDRESS *vrfyqueue;
9412612Seric 	ADDRESS *a;
958544Seric 	char inp[MAXLINE];
967124Seric 	extern char Version[];
977356Seric 	extern tick();
988544Seric 	extern bool iswiz();
999349Seric 	extern char *arpadate();
10011151Seric 	extern char *macvalue();
10112612Seric 	extern ADDRESS *recipient();
1024549Seric 
1035003Seric 	hasmail = FALSE;
1044713Seric 	rcps = 0;
1057363Seric 	if (OutChannel != stdout)
1067363Seric 	{
1077363Seric 		/* arrange for debugging output to go to remote host */
1087363Seric 		(void) close(1);
1097363Seric 		(void) dup(fileno(OutChannel));
1107363Seric 	}
11111931Seric 	settime();
11210708Seric 	expand("$e", inp, &inp[sizeof inp], CurEnv);
11310708Seric 	message("220", inp);
1144549Seric 	for (;;)
1154549Seric 	{
11612612Seric 		/* arrange for backout */
11712612Seric 		if (setjmp(TopFrame) > 0 && InChild)
11812612Seric 			finis();
11912612Seric 		QuickAbort = FALSE;
12012612Seric 		HoldErrs = FALSE;
12112612Seric 
1227356Seric 		/* setup for the read */
1236907Seric 		CurEnv->e_to = NULL;
1244577Seric 		Errors = 0;
1257275Seric 		(void) fflush(stdout);
1267356Seric 
1277356Seric 		/* read the input line */
1287685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1297356Seric 
1307685Seric 		/* handle errors */
1317356Seric 		if (p == NULL)
1327356Seric 		{
1334549Seric 			/* end of file, just die */
1344558Seric 			message("421", "%s Lost input channel", HostName);
1354549Seric 			finis();
1364549Seric 		}
1374549Seric 
1384549Seric 		/* clean up end of line */
1394558Seric 		fixcrlf(inp, TRUE);
1404549Seric 
1414713Seric 		/* echo command to transcript */
1429545Seric 		if (CurEnv->e_xfp != NULL)
1439545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1444713Seric 
1454549Seric 		/* break off command */
1464549Seric 		for (p = inp; isspace(*p); p++)
1474549Seric 			continue;
1484549Seric 		cmd = p;
1494549Seric 		while (*++p != '\0' && !isspace(*p))
1504549Seric 			continue;
1514549Seric 		if (*p != '\0')
1524549Seric 			*p++ = '\0';
1534549Seric 
1544549Seric 		/* decode command */
1554549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1564549Seric 		{
1574549Seric 			if (sameword(c->cmdname, cmd))
1584549Seric 				break;
1594549Seric 		}
1604549Seric 
1614549Seric 		/* process command */
1624549Seric 		switch (c->cmdcode)
1634549Seric 		{
1644976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
16511146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
16611146Seric 			{
16711146Seric 				char buf[MAXNAME];
16811146Seric 
16911146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
17011146Seric 				define('s', newstr(buf), CurEnv);
17111146Seric 			}
17211146Seric 			else
17311146Seric 				define('s', newstr(p), CurEnv);
1744997Seric 			message("250", "%s Hello %s, pleased to meet you",
1754997Seric 				HostName, p);
1764976Seric 			break;
1774976Seric 
1784549Seric 		  case CMDMAIL:		/* mail -- designate sender */
17911151Seric 			/* force a sending host even if no HELO given */
18011151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
18111151Seric 				define('s', RealHostName, CurEnv);
18211151Seric 
1839314Seric 			/* check for validity of this command */
1844558Seric 			if (hasmail)
1854558Seric 			{
1864558Seric 				message("503", "Sender already specified");
1874558Seric 				break;
1884558Seric 			}
1899339Seric 			if (InChild)
1909339Seric 			{
1919339Seric 				syserr("Nested MAIL command");
1929339Seric 				exit(0);
1939339Seric 			}
1949339Seric 
1959339Seric 			/* fork a subprocess to process this command */
1969339Seric 			if (runinchild("SMTP-MAIL") > 0)
1979339Seric 				break;
1989339Seric 			initsys();
1999339Seric 
2009339Seric 			/* child -- go do the processing */
2014549Seric 			p = skipword(p, "from");
2024549Seric 			if (p == NULL)
2034549Seric 				break;
2044549Seric 			setsender(p);
2054577Seric 			if (Errors == 0)
2064549Seric 			{
2074549Seric 				message("250", "Sender ok");
2084549Seric 				hasmail = TRUE;
2094549Seric 			}
2109339Seric 			else if (InChild)
2119339Seric 				finis();
2124549Seric 			break;
2134549Seric 
2144976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
21512612Seric 			if (setjmp(TopFrame) > 0)
216*14785Seric 			{
217*14785Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
21812612Seric 				break;
219*14785Seric 			}
22012612Seric 			QuickAbort = TRUE;
2214549Seric 			p = skipword(p, "to");
2224549Seric 			if (p == NULL)
2234549Seric 				break;
22412612Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1);
22512612Seric 			if (a == NULL)
22612612Seric 				break;
22712612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
22812612Seric 			if (Errors != 0)
22912612Seric 				break;
23012612Seric 
23112612Seric 			/* no errors during parsing, but might be a duplicate */
23212612Seric 			CurEnv->e_to = p;
23312612Seric 			if (!bitset(QBADADDR, a->q_flags))
23412612Seric 				message("250", "Recipient ok");
23512612Seric 			else
2364549Seric 			{
23712612Seric 				/* punt -- should keep message in ADDRESS.... */
23812612Seric 				message("550", "Addressee unknown");
2394549Seric 			}
24012612Seric 			CurEnv->e_to = NULL;
24112612Seric 			rcps++;
2424549Seric 			break;
2434549Seric 
2444549Seric 		  case CMDDATA:		/* data -- text of mail */
2454976Seric 			if (!hasmail)
2464549Seric 			{
2474976Seric 				message("503", "Need MAIL command");
2484976Seric 				break;
2494549Seric 			}
2504713Seric 			else if (rcps <= 0)
2514549Seric 			{
2524976Seric 				message("503", "Need RCPT (recipient)");
2534976Seric 				break;
2544549Seric 			}
2554976Seric 
2564976Seric 			/* collect the text of the message */
2574976Seric 			collect(TRUE);
2584976Seric 			if (Errors != 0)
2594976Seric 				break;
2604976Seric 
2618238Seric 			/*
2628238Seric 			**  Arrange to send to everyone.
2638238Seric 			**	If sending to multiple people, mail back
2648238Seric 			**		errors rather than reporting directly.
2658238Seric 			**	In any case, don't mail back errors for
2668238Seric 			**		anything that has happened up to
2678238Seric 			**		now (the other end will do this).
26810197Seric 			**	Truncate our transcript -- the mail has gotten
26910197Seric 			**		to us successfully, and if we have
27010197Seric 			**		to mail this back, it will be easier
27110197Seric 			**		on the reader.
2728238Seric 			**	Then send to everyone.
2738238Seric 			**	Finally give a reply code.  If an error has
2748238Seric 			**		already been given, don't mail a
2758238Seric 			**		message back.
2769339Seric 			**	We goose error returns by clearing error bit.
2778238Seric 			*/
2788238Seric 
2794976Seric 			if (rcps != 1)
2809378Seric 			{
2819378Seric 				HoldErrs = TRUE;
2829378Seric 				ErrorMode == EM_MAIL;
2839378Seric 			}
2849339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
28510197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
2864976Seric 
2874976Seric 			/* send to all recipients */
2889283Seric 			sendall(CurEnv, SendMode);
2896907Seric 			CurEnv->e_to = NULL;
2904976Seric 
2918238Seric 			/* issue success if appropriate and reset */
2928238Seric 			if (Errors == 0 || HoldErrs)
2939283Seric 				message("250", "Ok");
2948238Seric 			else
2959339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
2969339Seric 
2979339Seric 			/* if in a child, pop back to our parent */
2989339Seric 			if (InChild)
2999339Seric 				finis();
3004549Seric 			break;
3014549Seric 
3024549Seric 		  case CMDRSET:		/* rset -- reset state */
3034549Seric 			message("250", "Reset state");
3049339Seric 			if (InChild)
3059339Seric 				finis();
3069339Seric 			break;
3074549Seric 
3084549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3099339Seric 			if (runinchild("SMTP-VRFY") > 0)
3109339Seric 				break;
3115003Seric 			vrfyqueue = NULL;
3127762Seric 			QuickAbort = TRUE;
3139619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3147762Seric 			if (Errors != 0)
3159339Seric 			{
3169339Seric 				if (InChild)
3179339Seric 					finis();
3187762Seric 				break;
3199339Seric 			}
3205003Seric 			while (vrfyqueue != NULL)
3215003Seric 			{
3225003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3235003Seric 				char *code;
3245003Seric 
3257685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3265003Seric 					a = a->q_next;
3275003Seric 
3287685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3295003Seric 				{
3305003Seric 					if (a != NULL)
3315003Seric 						code = "250-";
3325003Seric 					else
3335003Seric 						code = "250";
3345003Seric 					if (vrfyqueue->q_fullname == NULL)
3355003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3365003Seric 					else
3375003Seric 						message(code, "%s <%s>",
3385003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3395003Seric 				}
3405003Seric 				else if (a == NULL)
3415003Seric 					message("554", "Self destructive alias loop");
3425003Seric 				vrfyqueue = a;
3435003Seric 			}
3449339Seric 			if (InChild)
3459339Seric 				finis();
3464549Seric 			break;
3474549Seric 
3484549Seric 		  case CMDHELP:		/* help -- give user info */
3494577Seric 			if (*p == '\0')
3504577Seric 				p = "SMTP";
3514577Seric 			help(p);
3524549Seric 			break;
3534549Seric 
3544549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3554549Seric 			message("200", "OK");
3564549Seric 			break;
3574549Seric 
3584549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3594549Seric 			message("221", "%s closing connection", HostName);
3609339Seric 			if (InChild)
3619339Seric 				ExitStat = EX_QUIT;
3624549Seric 			finis();
3634549Seric 
3648544Seric 		  case CMDVERB:		/* set verbose mode */
3658544Seric 			Verbose = TRUE;
3668544Seric 			message("200", "Verbose mode");
3678544Seric 			break;
3688544Seric 
3699314Seric 		  case CMDONEX:		/* doing one transaction only */
3709378Seric 			OneXact = TRUE;
3719314Seric 			message("200", "Only one transaction");
3729314Seric 			break;
3739314Seric 
3745003Seric # ifdef DEBUG
3759339Seric 		  case CMDDBGQSHOW:	/* show queues */
3766907Seric 			printf("Send Queue=");
3776907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
3785003Seric 			break;
3797275Seric 
3807275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
3817676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
3827676Seric 			tTflag(p);
3837676Seric 			message("200", "Debug set");
3847275Seric 			break;
3857275Seric 
3867282Seric 		  case CMDDBGKILL:	/* kill the parent */
3878544Seric 			if (!iswiz())
3888544Seric 				break;
3897282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
3907282Seric 				message("200", "Mother is dead");
3917282Seric 			else
3927282Seric 				message("500", "Can't kill Mom");
3937282Seric 			break;
3948544Seric 
3959339Seric 		  case CMDDBGSHELL:	/* give us an interactive shell */
3969339Seric 			if (!iswiz())
3979339Seric 				break;
3989378Seric 			if (fileno(InChannel) != 0)
3999378Seric 			{
4009378Seric 				(void) close(0);
4019378Seric 				(void) dup(fileno(InChannel));
40210346Seric 				if (fileno(InChannel) != fileno(OutChannel))
40310346Seric 					(void) fclose(InChannel);
4049378Seric 				InChannel = stdin;
4059378Seric 			}
4069378Seric 			if (fileno(OutChannel) != 1)
4079378Seric 			{
4089378Seric 				(void) close(1);
4099378Seric 				(void) dup(fileno(OutChannel));
4109378Seric 				(void) fclose(OutChannel);
4119378Seric 				OutChannel = stdout;
4129378Seric 			}
41310346Seric 			(void) close(2);
41410346Seric 			(void) dup(1);
4159339Seric 			execl("/bin/csh", "sendmail", 0);
4169339Seric 			execl("/bin/sh", "sendmail", 0);
4179339Seric 			message("500", "Can't");
4189378Seric 			exit(EX_UNAVAILABLE);
4199339Seric 
4208544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4218544Seric 			if (WizWord != NULL)
4228544Seric 			{
4238544Seric 				char seed[3];
4248544Seric 				extern char *crypt();
4258544Seric 
4268544Seric 				strncpy(seed, WizWord, 2);
4278544Seric 				if (strcmp(WizWord, crypt(p, seed)) != 0)
4288544Seric 				{
4298544Seric 					message("500", "You are no wizard!");
4308544Seric 					break;
4318544Seric 				}
4328544Seric 			}
4338544Seric 			IsWiz = TRUE;
4348544Seric 			message("200", "Please pass, oh mighty wizard");
4358544Seric 			break;
4365003Seric # endif DEBUG
4375003Seric 
4384549Seric 		  case CMDERROR:	/* unknown command */
4394549Seric 			message("500", "Command unrecognized");
4404549Seric 			break;
4414549Seric 
4424549Seric 		  default:
4434549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4444549Seric 			break;
4454549Seric 		}
4464549Seric 	}
4474549Seric }
4484549Seric /*
4494549Seric **  SKIPWORD -- skip a fixed word.
4504549Seric **
4514549Seric **	Parameters:
4524549Seric **		p -- place to start looking.
4534549Seric **		w -- word to skip.
4544549Seric **
4554549Seric **	Returns:
4564549Seric **		p following w.
4574549Seric **		NULL on error.
4584549Seric **
4594549Seric **	Side Effects:
4604549Seric **		clobbers the p data area.
4614549Seric */
4624549Seric 
4634549Seric static char *
4644549Seric skipword(p, w)
4654549Seric 	register char *p;
4664549Seric 	char *w;
4674549Seric {
4684549Seric 	register char *q;
4694549Seric 	extern bool sameword();
4704549Seric 
4714549Seric 	/* find beginning of word */
4724549Seric 	while (isspace(*p))
4734549Seric 		p++;
4744549Seric 	q = p;
4754549Seric 
4764549Seric 	/* find end of word */
4774549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4784549Seric 		p++;
4794549Seric 	while (isspace(*p))
4804549Seric 		*p++ = '\0';
4814549Seric 	if (*p != ':')
4824549Seric 	{
4834549Seric 	  syntax:
4844549Seric 		message("501", "Syntax error");
4854549Seric 		Errors++;
4864549Seric 		return (NULL);
4874549Seric 	}
4884549Seric 	*p++ = '\0';
4894549Seric 	while (isspace(*p))
4904549Seric 		p++;
4914549Seric 
4924549Seric 	/* see if the input word matches desired word */
4934549Seric 	if (!sameword(q, w))
4944549Seric 		goto syntax;
4954549Seric 
4964549Seric 	return (p);
4974549Seric }
4984577Seric /*
4994577Seric **  HELP -- implement the HELP command.
5004577Seric **
5014577Seric **	Parameters:
5024577Seric **		topic -- the topic we want help for.
5034577Seric **
5044577Seric **	Returns:
5054577Seric **		none.
5064577Seric **
5074577Seric **	Side Effects:
5084577Seric **		outputs the help file to message output.
5094577Seric */
5104577Seric 
5114577Seric help(topic)
5124577Seric 	char *topic;
5134577Seric {
5144577Seric 	register FILE *hf;
5154577Seric 	int len;
5164577Seric 	char buf[MAXLINE];
5174577Seric 	bool noinfo;
5184577Seric 
5198269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5204577Seric 	{
5214577Seric 		/* no help */
52211931Seric 		errno = 0;
5234577Seric 		message("502", "HELP not implemented");
5244577Seric 		return;
5254577Seric 	}
5264577Seric 
5274577Seric 	len = strlen(topic);
5284577Seric 	makelower(topic);
5294577Seric 	noinfo = TRUE;
5304577Seric 
5314577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5324577Seric 	{
5334577Seric 		if (strncmp(buf, topic, len) == 0)
5344577Seric 		{
5354577Seric 			register char *p;
5364577Seric 
5374577Seric 			p = index(buf, '\t');
5384577Seric 			if (p == NULL)
5394577Seric 				p = buf;
5404577Seric 			else
5414577Seric 				p++;
5424577Seric 			fixcrlf(p, TRUE);
5434577Seric 			message("214-", p);
5444577Seric 			noinfo = FALSE;
5454577Seric 		}
5464577Seric 	}
5474577Seric 
5484577Seric 	if (noinfo)
5494577Seric 		message("504", "HELP topic unknown");
5504577Seric 	else
5514577Seric 		message("214", "End of HELP info");
5524628Seric 	(void) fclose(hf);
5534577Seric }
5548544Seric /*
5558544Seric **  ISWIZ -- tell us if we are a wizard
5568544Seric **
5578544Seric **	If not, print a nasty message.
5588544Seric **
5598544Seric **	Parameters:
5608544Seric **		none.
5618544Seric **
5628544Seric **	Returns:
5638544Seric **		TRUE if we are a wizard.
5648544Seric **		FALSE if we are not a wizard.
5658544Seric **
5668544Seric **	Side Effects:
5678544Seric **		Prints a 500 exit stat if we are not a wizard.
5688544Seric */
5695181Seric 
5708544Seric bool
5718544Seric iswiz()
5728544Seric {
5738544Seric 	if (!IsWiz)
5748544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5758544Seric 	return (IsWiz);
5768544Seric }
5779339Seric /*
5789339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5799339Seric **
5809339Seric **	Parameters:
5819339Seric **		label -- a string used in error messages
5829339Seric **
5839339Seric **	Returns:
5849339Seric **		zero in the child
5859339Seric **		one in the parent
5869339Seric **
5879339Seric **	Side Effects:
5889339Seric **		none.
5899339Seric */
5908544Seric 
5919339Seric runinchild(label)
5929339Seric 	char *label;
5939339Seric {
5949339Seric 	int childpid;
5959339Seric 
5969378Seric 	if (OneXact)
5979378Seric 		return (0);
5989378Seric 
5999339Seric 	childpid = dofork();
6009339Seric 	if (childpid < 0)
6019339Seric 	{
6029339Seric 		syserr("%s: cannot fork", label);
6039339Seric 		return (1);
6049339Seric 	}
6059339Seric 	if (childpid > 0)
6069339Seric 	{
6079339Seric 		auto int st;
6089339Seric 
6099378Seric 		/* parent -- wait for child to complete */
6109378Seric 		st = waitfor(childpid);
6119378Seric 		if (st == -1)
6129339Seric 			syserr("%s: lost child", label);
6139339Seric 
6149339Seric 		/* if we exited on a QUIT command, complete the process */
6159339Seric 		if (st == (EX_QUIT << 8))
6169339Seric 			finis();
6179339Seric 
6189339Seric 		return (1);
6199339Seric 	}
6209339Seric 	else
6219339Seric 	{
6229339Seric 		/* child */
6239339Seric 		InChild = TRUE;
6249545Seric 		clearenvelope(CurEnv);
6259339Seric 		return (0);
6269339Seric 	}
6279339Seric }
6289339Seric 
6295181Seric # endif SMTP
630