19339Seric # include <errno.h>
24549Seric # include "sendmail.h"
311728Seric # include <signal.h>
44549Seric 
55181Seric # ifndef SMTP
6*12612Seric SCCSID(@(#)srvrsmtp.c	3.50		05/20/83	(no SMTP));
75181Seric # else SMTP
84556Seric 
9*12612Seric SCCSID(@(#)srvrsmtp.c	3.50		05/20/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;
94*12612Seric 	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();
101*12612Seric 	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 	{
116*12612Seric 		/* arrange for backout */
117*12612Seric 		if (setjmp(TopFrame) > 0 && InChild)
118*12612Seric 			finis();
119*12612Seric 		QuickAbort = FALSE;
120*12612Seric 		HoldErrs = FALSE;
121*12612Seric 
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 */
215*12612Seric 			if (setjmp(TopFrame) > 0)
216*12612Seric 				break;
217*12612Seric 			QuickAbort = TRUE;
2184549Seric 			p = skipword(p, "to");
2194549Seric 			if (p == NULL)
2204549Seric 				break;
221*12612Seric 			a = parseaddr(p, (ADDRESS *) NULL, 1);
222*12612Seric 			if (a == NULL)
223*12612Seric 				break;
224*12612Seric 			a = recipient(a, &CurEnv->e_sendqueue);
2259390Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
226*12612Seric 			if (Errors != 0)
227*12612Seric 				break;
228*12612Seric 
229*12612Seric 			/* no errors during parsing, but might be a duplicate */
230*12612Seric 			CurEnv->e_to = p;
231*12612Seric 			if (!bitset(QBADADDR, a->q_flags))
232*12612Seric 				message("250", "Recipient ok");
233*12612Seric 			else
2344549Seric 			{
235*12612Seric 				/* punt -- should keep message in ADDRESS.... */
236*12612Seric 				message("550", "Addressee unknown");
2374549Seric 			}
238*12612Seric 			CurEnv->e_to = NULL;
239*12612Seric 			rcps++;
2404549Seric 			break;
2414549Seric 
2424549Seric 		  case CMDDATA:		/* data -- text of mail */
2434976Seric 			if (!hasmail)
2444549Seric 			{
2454976Seric 				message("503", "Need MAIL command");
2464976Seric 				break;
2474549Seric 			}
2484713Seric 			else if (rcps <= 0)
2494549Seric 			{
2504976Seric 				message("503", "Need RCPT (recipient)");
2514976Seric 				break;
2524549Seric 			}
2534976Seric 
2544976Seric 			/* collect the text of the message */
2554976Seric 			collect(TRUE);
2564976Seric 			if (Errors != 0)
2574976Seric 				break;
2584976Seric 
2598238Seric 			/*
2608238Seric 			**  Arrange to send to everyone.
2618238Seric 			**	If sending to multiple people, mail back
2628238Seric 			**		errors rather than reporting directly.
2638238Seric 			**	In any case, don't mail back errors for
2648238Seric 			**		anything that has happened up to
2658238Seric 			**		now (the other end will do this).
26610197Seric 			**	Truncate our transcript -- the mail has gotten
26710197Seric 			**		to us successfully, and if we have
26810197Seric 			**		to mail this back, it will be easier
26910197Seric 			**		on the reader.
2708238Seric 			**	Then send to everyone.
2718238Seric 			**	Finally give a reply code.  If an error has
2728238Seric 			**		already been given, don't mail a
2738238Seric 			**		message back.
2749339Seric 			**	We goose error returns by clearing error bit.
2758238Seric 			*/
2768238Seric 
2774976Seric 			if (rcps != 1)
2789378Seric 			{
2799378Seric 				HoldErrs = TRUE;
2809378Seric 				ErrorMode == EM_MAIL;
2819378Seric 			}
2829339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
28310197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
2844976Seric 
2854976Seric 			/* send to all recipients */
2869283Seric 			sendall(CurEnv, SendMode);
2876907Seric 			CurEnv->e_to = NULL;
2884976Seric 
2898238Seric 			/* issue success if appropriate and reset */
2908238Seric 			if (Errors == 0 || HoldErrs)
2919283Seric 				message("250", "Ok");
2928238Seric 			else
2939339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
2949339Seric 
2959339Seric 			/* if in a child, pop back to our parent */
2969339Seric 			if (InChild)
2979339Seric 				finis();
2984549Seric 			break;
2994549Seric 
3004549Seric 		  case CMDRSET:		/* rset -- reset state */
3014549Seric 			message("250", "Reset state");
3029339Seric 			if (InChild)
3039339Seric 				finis();
3049339Seric 			break;
3054549Seric 
3064549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
3079339Seric 			if (runinchild("SMTP-VRFY") > 0)
3089339Seric 				break;
3095003Seric 			vrfyqueue = NULL;
3107762Seric 			QuickAbort = TRUE;
3119619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
3127762Seric 			if (Errors != 0)
3139339Seric 			{
3149339Seric 				if (InChild)
3159339Seric 					finis();
3167762Seric 				break;
3179339Seric 			}
3185003Seric 			while (vrfyqueue != NULL)
3195003Seric 			{
3205003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3215003Seric 				char *code;
3225003Seric 
3237685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3245003Seric 					a = a->q_next;
3255003Seric 
3267685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3275003Seric 				{
3285003Seric 					if (a != NULL)
3295003Seric 						code = "250-";
3305003Seric 					else
3315003Seric 						code = "250";
3325003Seric 					if (vrfyqueue->q_fullname == NULL)
3335003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3345003Seric 					else
3355003Seric 						message(code, "%s <%s>",
3365003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3375003Seric 				}
3385003Seric 				else if (a == NULL)
3395003Seric 					message("554", "Self destructive alias loop");
3405003Seric 				vrfyqueue = a;
3415003Seric 			}
3429339Seric 			if (InChild)
3439339Seric 				finis();
3444549Seric 			break;
3454549Seric 
3464549Seric 		  case CMDHELP:		/* help -- give user info */
3474577Seric 			if (*p == '\0')
3484577Seric 				p = "SMTP";
3494577Seric 			help(p);
3504549Seric 			break;
3514549Seric 
3524549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3534549Seric 			message("200", "OK");
3544549Seric 			break;
3554549Seric 
3564549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3574549Seric 			message("221", "%s closing connection", HostName);
3589339Seric 			if (InChild)
3599339Seric 				ExitStat = EX_QUIT;
3604549Seric 			finis();
3614549Seric 
3628544Seric 		  case CMDVERB:		/* set verbose mode */
3638544Seric 			Verbose = TRUE;
3648544Seric 			message("200", "Verbose mode");
3658544Seric 			break;
3668544Seric 
3679314Seric 		  case CMDONEX:		/* doing one transaction only */
3689378Seric 			OneXact = TRUE;
3699314Seric 			message("200", "Only one transaction");
3709314Seric 			break;
3719314Seric 
3725003Seric # ifdef DEBUG
3739339Seric 		  case CMDDBGQSHOW:	/* show queues */
3746907Seric 			printf("Send Queue=");
3756907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
3765003Seric 			break;
3777275Seric 
3787275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
3797676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
3807676Seric 			tTflag(p);
3817676Seric 			message("200", "Debug set");
3827275Seric 			break;
3837275Seric 
3847282Seric 		  case CMDDBGKILL:	/* kill the parent */
3858544Seric 			if (!iswiz())
3868544Seric 				break;
3877282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
3887282Seric 				message("200", "Mother is dead");
3897282Seric 			else
3907282Seric 				message("500", "Can't kill Mom");
3917282Seric 			break;
3928544Seric 
3939339Seric 		  case CMDDBGSHELL:	/* give us an interactive shell */
3949339Seric 			if (!iswiz())
3959339Seric 				break;
3969378Seric 			if (fileno(InChannel) != 0)
3979378Seric 			{
3989378Seric 				(void) close(0);
3999378Seric 				(void) dup(fileno(InChannel));
40010346Seric 				if (fileno(InChannel) != fileno(OutChannel))
40110346Seric 					(void) fclose(InChannel);
4029378Seric 				InChannel = stdin;
4039378Seric 			}
4049378Seric 			if (fileno(OutChannel) != 1)
4059378Seric 			{
4069378Seric 				(void) close(1);
4079378Seric 				(void) dup(fileno(OutChannel));
4089378Seric 				(void) fclose(OutChannel);
4099378Seric 				OutChannel = stdout;
4109378Seric 			}
41110346Seric 			(void) close(2);
41210346Seric 			(void) dup(1);
4139339Seric 			execl("/bin/csh", "sendmail", 0);
4149339Seric 			execl("/bin/sh", "sendmail", 0);
4159339Seric 			message("500", "Can't");
4169378Seric 			exit(EX_UNAVAILABLE);
4179339Seric 
4188544Seric 		  case CMDDBGWIZ:	/* become a wizard */
4198544Seric 			if (WizWord != NULL)
4208544Seric 			{
4218544Seric 				char seed[3];
4228544Seric 				extern char *crypt();
4238544Seric 
4248544Seric 				strncpy(seed, WizWord, 2);
4258544Seric 				if (strcmp(WizWord, crypt(p, seed)) != 0)
4268544Seric 				{
4278544Seric 					message("500", "You are no wizard!");
4288544Seric 					break;
4298544Seric 				}
4308544Seric 			}
4318544Seric 			IsWiz = TRUE;
4328544Seric 			message("200", "Please pass, oh mighty wizard");
4338544Seric 			break;
4345003Seric # endif DEBUG
4355003Seric 
4364549Seric 		  case CMDERROR:	/* unknown command */
4374549Seric 			message("500", "Command unrecognized");
4384549Seric 			break;
4394549Seric 
4404549Seric 		  default:
4414549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4424549Seric 			break;
4434549Seric 		}
4444549Seric 	}
4454549Seric }
4464549Seric /*
4474549Seric **  SKIPWORD -- skip a fixed word.
4484549Seric **
4494549Seric **	Parameters:
4504549Seric **		p -- place to start looking.
4514549Seric **		w -- word to skip.
4524549Seric **
4534549Seric **	Returns:
4544549Seric **		p following w.
4554549Seric **		NULL on error.
4564549Seric **
4574549Seric **	Side Effects:
4584549Seric **		clobbers the p data area.
4594549Seric */
4604549Seric 
4614549Seric static char *
4624549Seric skipword(p, w)
4634549Seric 	register char *p;
4644549Seric 	char *w;
4654549Seric {
4664549Seric 	register char *q;
4674549Seric 	extern bool sameword();
4684549Seric 
4694549Seric 	/* find beginning of word */
4704549Seric 	while (isspace(*p))
4714549Seric 		p++;
4724549Seric 	q = p;
4734549Seric 
4744549Seric 	/* find end of word */
4754549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4764549Seric 		p++;
4774549Seric 	while (isspace(*p))
4784549Seric 		*p++ = '\0';
4794549Seric 	if (*p != ':')
4804549Seric 	{
4814549Seric 	  syntax:
4824549Seric 		message("501", "Syntax error");
4834549Seric 		Errors++;
4844549Seric 		return (NULL);
4854549Seric 	}
4864549Seric 	*p++ = '\0';
4874549Seric 	while (isspace(*p))
4884549Seric 		p++;
4894549Seric 
4904549Seric 	/* see if the input word matches desired word */
4914549Seric 	if (!sameword(q, w))
4924549Seric 		goto syntax;
4934549Seric 
4944549Seric 	return (p);
4954549Seric }
4964577Seric /*
4974577Seric **  HELP -- implement the HELP command.
4984577Seric **
4994577Seric **	Parameters:
5004577Seric **		topic -- the topic we want help for.
5014577Seric **
5024577Seric **	Returns:
5034577Seric **		none.
5044577Seric **
5054577Seric **	Side Effects:
5064577Seric **		outputs the help file to message output.
5074577Seric */
5084577Seric 
5094577Seric help(topic)
5104577Seric 	char *topic;
5114577Seric {
5124577Seric 	register FILE *hf;
5134577Seric 	int len;
5144577Seric 	char buf[MAXLINE];
5154577Seric 	bool noinfo;
5164577Seric 
5178269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
5184577Seric 	{
5194577Seric 		/* no help */
52011931Seric 		errno = 0;
5214577Seric 		message("502", "HELP not implemented");
5224577Seric 		return;
5234577Seric 	}
5244577Seric 
5254577Seric 	len = strlen(topic);
5264577Seric 	makelower(topic);
5274577Seric 	noinfo = TRUE;
5284577Seric 
5294577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5304577Seric 	{
5314577Seric 		if (strncmp(buf, topic, len) == 0)
5324577Seric 		{
5334577Seric 			register char *p;
5344577Seric 
5354577Seric 			p = index(buf, '\t');
5364577Seric 			if (p == NULL)
5374577Seric 				p = buf;
5384577Seric 			else
5394577Seric 				p++;
5404577Seric 			fixcrlf(p, TRUE);
5414577Seric 			message("214-", p);
5424577Seric 			noinfo = FALSE;
5434577Seric 		}
5444577Seric 	}
5454577Seric 
5464577Seric 	if (noinfo)
5474577Seric 		message("504", "HELP topic unknown");
5484577Seric 	else
5494577Seric 		message("214", "End of HELP info");
5504628Seric 	(void) fclose(hf);
5514577Seric }
5528544Seric /*
5538544Seric **  ISWIZ -- tell us if we are a wizard
5548544Seric **
5558544Seric **	If not, print a nasty message.
5568544Seric **
5578544Seric **	Parameters:
5588544Seric **		none.
5598544Seric **
5608544Seric **	Returns:
5618544Seric **		TRUE if we are a wizard.
5628544Seric **		FALSE if we are not a wizard.
5638544Seric **
5648544Seric **	Side Effects:
5658544Seric **		Prints a 500 exit stat if we are not a wizard.
5668544Seric */
5675181Seric 
5688544Seric bool
5698544Seric iswiz()
5708544Seric {
5718544Seric 	if (!IsWiz)
5728544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5738544Seric 	return (IsWiz);
5748544Seric }
5759339Seric /*
5769339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5779339Seric **
5789339Seric **	Parameters:
5799339Seric **		label -- a string used in error messages
5809339Seric **
5819339Seric **	Returns:
5829339Seric **		zero in the child
5839339Seric **		one in the parent
5849339Seric **
5859339Seric **	Side Effects:
5869339Seric **		none.
5879339Seric */
5888544Seric 
5899339Seric runinchild(label)
5909339Seric 	char *label;
5919339Seric {
5929339Seric 	int childpid;
5939339Seric 
5949378Seric 	if (OneXact)
5959378Seric 		return (0);
5969378Seric 
5979339Seric 	childpid = dofork();
5989339Seric 	if (childpid < 0)
5999339Seric 	{
6009339Seric 		syserr("%s: cannot fork", label);
6019339Seric 		return (1);
6029339Seric 	}
6039339Seric 	if (childpid > 0)
6049339Seric 	{
6059339Seric 		auto int st;
6069339Seric 
6079378Seric 		/* parent -- wait for child to complete */
6089378Seric 		st = waitfor(childpid);
6099378Seric 		if (st == -1)
6109339Seric 			syserr("%s: lost child", label);
6119339Seric 
6129339Seric 		/* if we exited on a QUIT command, complete the process */
6139339Seric 		if (st == (EX_QUIT << 8))
6149339Seric 			finis();
6159339Seric 
6169339Seric 		return (1);
6179339Seric 	}
6189339Seric 	else
6199339Seric 	{
6209339Seric 		/* child */
6219339Seric 		InChild = TRUE;
6229545Seric 		clearenvelope(CurEnv);
6239339Seric 		return (0);
6249339Seric 	}
6259339Seric }
6269339Seric 
6275181Seric # endif SMTP
628