19339Seric # include <errno.h>
24549Seric # include "sendmail.h"
311728Seric # include <signal.h>
44549Seric 
55181Seric # ifndef SMTP
6*11931Seric SCCSID(@(#)srvrsmtp.c	3.49		04/17/83	(no SMTP));
75181Seric # else SMTP
84556Seric 
9*11931Seric SCCSID(@(#)srvrsmtp.c	3.49		04/17/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;
948544Seric 	char inp[MAXLINE];
957124Seric 	extern char Version[];
967356Seric 	extern tick();
978544Seric 	extern bool iswiz();
989349Seric 	extern char *arpadate();
9911151Seric 	extern char *macvalue();
1004549Seric 
1015003Seric 	hasmail = FALSE;
1024713Seric 	rcps = 0;
1037363Seric 	if (OutChannel != stdout)
1047363Seric 	{
1057363Seric 		/* arrange for debugging output to go to remote host */
1067363Seric 		(void) close(1);
1077363Seric 		(void) dup(fileno(OutChannel));
1087363Seric 	}
109*11931Seric 	settime();
11010708Seric 	expand("$e", inp, &inp[sizeof inp], CurEnv);
11110708Seric 	message("220", inp);
1127762Seric 	(void) setjmp(TopFrame);
1137762Seric 	QuickAbort = FALSE;
1149390Seric 	HoldErrs = FALSE;
1154549Seric 	for (;;)
1164549Seric 	{
1177356Seric 		/* setup for the read */
1186907Seric 		CurEnv->e_to = NULL;
1194577Seric 		Errors = 0;
1207275Seric 		(void) fflush(stdout);
1217356Seric 
1227356Seric 		/* read the input line */
1237685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1247356Seric 
1257685Seric 		/* handle errors */
1267356Seric 		if (p == NULL)
1277356Seric 		{
1284549Seric 			/* end of file, just die */
1294558Seric 			message("421", "%s Lost input channel", HostName);
1304549Seric 			finis();
1314549Seric 		}
1324549Seric 
1334549Seric 		/* clean up end of line */
1344558Seric 		fixcrlf(inp, TRUE);
1354549Seric 
1364713Seric 		/* echo command to transcript */
1379545Seric 		if (CurEnv->e_xfp != NULL)
1389545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1394713Seric 
1404549Seric 		/* break off command */
1414549Seric 		for (p = inp; isspace(*p); p++)
1424549Seric 			continue;
1434549Seric 		cmd = p;
1444549Seric 		while (*++p != '\0' && !isspace(*p))
1454549Seric 			continue;
1464549Seric 		if (*p != '\0')
1474549Seric 			*p++ = '\0';
1484549Seric 
1494549Seric 		/* decode command */
1504549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1514549Seric 		{
1524549Seric 			if (sameword(c->cmdname, cmd))
1534549Seric 				break;
1544549Seric 		}
1554549Seric 
1564549Seric 		/* process command */
1574549Seric 		switch (c->cmdcode)
1584549Seric 		{
1594976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
16011146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
16111146Seric 			{
16211146Seric 				char buf[MAXNAME];
16311146Seric 
16411146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
16511146Seric 				define('s', newstr(buf), CurEnv);
16611146Seric 			}
16711146Seric 			else
16811146Seric 				define('s', newstr(p), CurEnv);
1694997Seric 			message("250", "%s Hello %s, pleased to meet you",
1704997Seric 				HostName, p);
1714976Seric 			break;
1724976Seric 
1734549Seric 		  case CMDMAIL:		/* mail -- designate sender */
17411151Seric 			/* force a sending host even if no HELO given */
17511151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
17611151Seric 				define('s', RealHostName, CurEnv);
17711151Seric 
1789314Seric 			/* check for validity of this command */
1794558Seric 			if (hasmail)
1804558Seric 			{
1814558Seric 				message("503", "Sender already specified");
1824558Seric 				break;
1834558Seric 			}
1849339Seric 			if (InChild)
1859339Seric 			{
1869339Seric 				syserr("Nested MAIL command");
1879339Seric 				exit(0);
1889339Seric 			}
1899339Seric 
1909339Seric 			/* fork a subprocess to process this command */
1919339Seric 			if (runinchild("SMTP-MAIL") > 0)
1929339Seric 				break;
1939339Seric 			initsys();
1949339Seric 
1959339Seric 			/* child -- go do the processing */
1964549Seric 			p = skipword(p, "from");
1974549Seric 			if (p == NULL)
1984549Seric 				break;
1994549Seric 			setsender(p);
2004577Seric 			if (Errors == 0)
2014549Seric 			{
2024549Seric 				message("250", "Sender ok");
2034549Seric 				hasmail = TRUE;
2044549Seric 			}
2059339Seric 			else if (InChild)
2069339Seric 				finis();
2074549Seric 			break;
2084549Seric 
2094976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
2104549Seric 			p = skipword(p, "to");
2114549Seric 			if (p == NULL)
2124549Seric 				break;
2139619Seric 			sendtolist(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
2149390Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
2154577Seric 			if (Errors == 0)
2164549Seric 			{
2176057Seric 				message("250", "%s... Recipient ok", p);
2184713Seric 				rcps++;
2194549Seric 			}
2204549Seric 			break;
2214549Seric 
2224549Seric 		  case CMDDATA:		/* data -- text of mail */
2234976Seric 			if (!hasmail)
2244549Seric 			{
2254976Seric 				message("503", "Need MAIL command");
2264976Seric 				break;
2274549Seric 			}
2284713Seric 			else if (rcps <= 0)
2294549Seric 			{
2304976Seric 				message("503", "Need RCPT (recipient)");
2314976Seric 				break;
2324549Seric 			}
2334976Seric 
2344976Seric 			/* collect the text of the message */
2354976Seric 			collect(TRUE);
2364976Seric 			if (Errors != 0)
2374976Seric 				break;
2384976Seric 
2398238Seric 			/*
2408238Seric 			**  Arrange to send to everyone.
2418238Seric 			**	If sending to multiple people, mail back
2428238Seric 			**		errors rather than reporting directly.
2438238Seric 			**	In any case, don't mail back errors for
2448238Seric 			**		anything that has happened up to
2458238Seric 			**		now (the other end will do this).
24610197Seric 			**	Truncate our transcript -- the mail has gotten
24710197Seric 			**		to us successfully, and if we have
24810197Seric 			**		to mail this back, it will be easier
24910197Seric 			**		on the reader.
2508238Seric 			**	Then send to everyone.
2518238Seric 			**	Finally give a reply code.  If an error has
2528238Seric 			**		already been given, don't mail a
2538238Seric 			**		message back.
2549339Seric 			**	We goose error returns by clearing error bit.
2558238Seric 			*/
2568238Seric 
2574976Seric 			if (rcps != 1)
2589378Seric 			{
2599378Seric 				HoldErrs = TRUE;
2609378Seric 				ErrorMode == EM_MAIL;
2619378Seric 			}
2629339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
26310197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
2644976Seric 
2654976Seric 			/* send to all recipients */
2669283Seric 			sendall(CurEnv, SendMode);
2676907Seric 			CurEnv->e_to = NULL;
2684976Seric 
2698238Seric 			/* issue success if appropriate and reset */
2708238Seric 			if (Errors == 0 || HoldErrs)
2719283Seric 				message("250", "Ok");
2728238Seric 			else
2739339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
2749339Seric 
2759339Seric 			/* if in a child, pop back to our parent */
2769339Seric 			if (InChild)
2779339Seric 				finis();
2784549Seric 			break;
2794549Seric 
2804549Seric 		  case CMDRSET:		/* rset -- reset state */
2814549Seric 			message("250", "Reset state");
2829339Seric 			if (InChild)
2839339Seric 				finis();
2849339Seric 			break;
2854549Seric 
2864549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
2879339Seric 			if (runinchild("SMTP-VRFY") > 0)
2889339Seric 				break;
2895003Seric 			vrfyqueue = NULL;
2907762Seric 			QuickAbort = TRUE;
2919619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
2927762Seric 			if (Errors != 0)
2939339Seric 			{
2949339Seric 				if (InChild)
2959339Seric 					finis();
2967762Seric 				break;
2979339Seric 			}
2985003Seric 			while (vrfyqueue != NULL)
2995003Seric 			{
3005003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3015003Seric 				char *code;
3025003Seric 
3037685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3045003Seric 					a = a->q_next;
3055003Seric 
3067685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3075003Seric 				{
3085003Seric 					if (a != NULL)
3095003Seric 						code = "250-";
3105003Seric 					else
3115003Seric 						code = "250";
3125003Seric 					if (vrfyqueue->q_fullname == NULL)
3135003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3145003Seric 					else
3155003Seric 						message(code, "%s <%s>",
3165003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3175003Seric 				}
3185003Seric 				else if (a == NULL)
3195003Seric 					message("554", "Self destructive alias loop");
3205003Seric 				vrfyqueue = a;
3215003Seric 			}
3229339Seric 			if (InChild)
3239339Seric 				finis();
3244549Seric 			break;
3254549Seric 
3264549Seric 		  case CMDHELP:		/* help -- give user info */
3274577Seric 			if (*p == '\0')
3284577Seric 				p = "SMTP";
3294577Seric 			help(p);
3304549Seric 			break;
3314549Seric 
3324549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3334549Seric 			message("200", "OK");
3344549Seric 			break;
3354549Seric 
3364549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3374549Seric 			message("221", "%s closing connection", HostName);
3389339Seric 			if (InChild)
3399339Seric 				ExitStat = EX_QUIT;
3404549Seric 			finis();
3414549Seric 
3428544Seric 		  case CMDVERB:		/* set verbose mode */
3438544Seric 			Verbose = TRUE;
3448544Seric 			message("200", "Verbose mode");
3458544Seric 			break;
3468544Seric 
3479314Seric 		  case CMDONEX:		/* doing one transaction only */
3489378Seric 			OneXact = TRUE;
3499314Seric 			message("200", "Only one transaction");
3509314Seric 			break;
3519314Seric 
3525003Seric # ifdef DEBUG
3539339Seric 		  case CMDDBGQSHOW:	/* show queues */
3546907Seric 			printf("Send Queue=");
3556907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
3565003Seric 			break;
3577275Seric 
3587275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
3597676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
3607676Seric 			tTflag(p);
3617676Seric 			message("200", "Debug set");
3627275Seric 			break;
3637275Seric 
3647282Seric 		  case CMDDBGKILL:	/* kill the parent */
3658544Seric 			if (!iswiz())
3668544Seric 				break;
3677282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
3687282Seric 				message("200", "Mother is dead");
3697282Seric 			else
3707282Seric 				message("500", "Can't kill Mom");
3717282Seric 			break;
3728544Seric 
3739339Seric 		  case CMDDBGSHELL:	/* give us an interactive shell */
3749339Seric 			if (!iswiz())
3759339Seric 				break;
3769378Seric 			if (fileno(InChannel) != 0)
3779378Seric 			{
3789378Seric 				(void) close(0);
3799378Seric 				(void) dup(fileno(InChannel));
38010346Seric 				if (fileno(InChannel) != fileno(OutChannel))
38110346Seric 					(void) fclose(InChannel);
3829378Seric 				InChannel = stdin;
3839378Seric 			}
3849378Seric 			if (fileno(OutChannel) != 1)
3859378Seric 			{
3869378Seric 				(void) close(1);
3879378Seric 				(void) dup(fileno(OutChannel));
3889378Seric 				(void) fclose(OutChannel);
3899378Seric 				OutChannel = stdout;
3909378Seric 			}
39110346Seric 			(void) close(2);
39210346Seric 			(void) dup(1);
3939339Seric 			execl("/bin/csh", "sendmail", 0);
3949339Seric 			execl("/bin/sh", "sendmail", 0);
3959339Seric 			message("500", "Can't");
3969378Seric 			exit(EX_UNAVAILABLE);
3979339Seric 
3988544Seric 		  case CMDDBGWIZ:	/* become a wizard */
3998544Seric 			if (WizWord != NULL)
4008544Seric 			{
4018544Seric 				char seed[3];
4028544Seric 				extern char *crypt();
4038544Seric 
4048544Seric 				strncpy(seed, WizWord, 2);
4058544Seric 				if (strcmp(WizWord, crypt(p, seed)) != 0)
4068544Seric 				{
4078544Seric 					message("500", "You are no wizard!");
4088544Seric 					break;
4098544Seric 				}
4108544Seric 			}
4118544Seric 			IsWiz = TRUE;
4128544Seric 			message("200", "Please pass, oh mighty wizard");
4138544Seric 			break;
4145003Seric # endif DEBUG
4155003Seric 
4164549Seric 		  case CMDERROR:	/* unknown command */
4174549Seric 			message("500", "Command unrecognized");
4184549Seric 			break;
4194549Seric 
4204549Seric 		  default:
4214549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4224549Seric 			break;
4234549Seric 		}
4244549Seric 	}
4254549Seric }
4264549Seric /*
4274549Seric **  SKIPWORD -- skip a fixed word.
4284549Seric **
4294549Seric **	Parameters:
4304549Seric **		p -- place to start looking.
4314549Seric **		w -- word to skip.
4324549Seric **
4334549Seric **	Returns:
4344549Seric **		p following w.
4354549Seric **		NULL on error.
4364549Seric **
4374549Seric **	Side Effects:
4384549Seric **		clobbers the p data area.
4394549Seric */
4404549Seric 
4414549Seric static char *
4424549Seric skipword(p, w)
4434549Seric 	register char *p;
4444549Seric 	char *w;
4454549Seric {
4464549Seric 	register char *q;
4474549Seric 	extern bool sameword();
4484549Seric 
4494549Seric 	/* find beginning of word */
4504549Seric 	while (isspace(*p))
4514549Seric 		p++;
4524549Seric 	q = p;
4534549Seric 
4544549Seric 	/* find end of word */
4554549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4564549Seric 		p++;
4574549Seric 	while (isspace(*p))
4584549Seric 		*p++ = '\0';
4594549Seric 	if (*p != ':')
4604549Seric 	{
4614549Seric 	  syntax:
4624549Seric 		message("501", "Syntax error");
4634549Seric 		Errors++;
4644549Seric 		return (NULL);
4654549Seric 	}
4664549Seric 	*p++ = '\0';
4674549Seric 	while (isspace(*p))
4684549Seric 		p++;
4694549Seric 
4704549Seric 	/* see if the input word matches desired word */
4714549Seric 	if (!sameword(q, w))
4724549Seric 		goto syntax;
4734549Seric 
4744549Seric 	return (p);
4754549Seric }
4764577Seric /*
4774577Seric **  HELP -- implement the HELP command.
4784577Seric **
4794577Seric **	Parameters:
4804577Seric **		topic -- the topic we want help for.
4814577Seric **
4824577Seric **	Returns:
4834577Seric **		none.
4844577Seric **
4854577Seric **	Side Effects:
4864577Seric **		outputs the help file to message output.
4874577Seric */
4884577Seric 
4894577Seric help(topic)
4904577Seric 	char *topic;
4914577Seric {
4924577Seric 	register FILE *hf;
4934577Seric 	int len;
4944577Seric 	char buf[MAXLINE];
4954577Seric 	bool noinfo;
4964577Seric 
4978269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
4984577Seric 	{
4994577Seric 		/* no help */
500*11931Seric 		errno = 0;
5014577Seric 		message("502", "HELP not implemented");
5024577Seric 		return;
5034577Seric 	}
5044577Seric 
5054577Seric 	len = strlen(topic);
5064577Seric 	makelower(topic);
5074577Seric 	noinfo = TRUE;
5084577Seric 
5094577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5104577Seric 	{
5114577Seric 		if (strncmp(buf, topic, len) == 0)
5124577Seric 		{
5134577Seric 			register char *p;
5144577Seric 
5154577Seric 			p = index(buf, '\t');
5164577Seric 			if (p == NULL)
5174577Seric 				p = buf;
5184577Seric 			else
5194577Seric 				p++;
5204577Seric 			fixcrlf(p, TRUE);
5214577Seric 			message("214-", p);
5224577Seric 			noinfo = FALSE;
5234577Seric 		}
5244577Seric 	}
5254577Seric 
5264577Seric 	if (noinfo)
5274577Seric 		message("504", "HELP topic unknown");
5284577Seric 	else
5294577Seric 		message("214", "End of HELP info");
5304628Seric 	(void) fclose(hf);
5314577Seric }
5328544Seric /*
5338544Seric **  ISWIZ -- tell us if we are a wizard
5348544Seric **
5358544Seric **	If not, print a nasty message.
5368544Seric **
5378544Seric **	Parameters:
5388544Seric **		none.
5398544Seric **
5408544Seric **	Returns:
5418544Seric **		TRUE if we are a wizard.
5428544Seric **		FALSE if we are not a wizard.
5438544Seric **
5448544Seric **	Side Effects:
5458544Seric **		Prints a 500 exit stat if we are not a wizard.
5468544Seric */
5475181Seric 
5488544Seric bool
5498544Seric iswiz()
5508544Seric {
5518544Seric 	if (!IsWiz)
5528544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5538544Seric 	return (IsWiz);
5548544Seric }
5559339Seric /*
5569339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5579339Seric **
5589339Seric **	Parameters:
5599339Seric **		label -- a string used in error messages
5609339Seric **
5619339Seric **	Returns:
5629339Seric **		zero in the child
5639339Seric **		one in the parent
5649339Seric **
5659339Seric **	Side Effects:
5669339Seric **		none.
5679339Seric */
5688544Seric 
5699339Seric runinchild(label)
5709339Seric 	char *label;
5719339Seric {
5729339Seric 	int childpid;
5739339Seric 
5749378Seric 	if (OneXact)
5759378Seric 		return (0);
5769378Seric 
5779339Seric 	childpid = dofork();
5789339Seric 	if (childpid < 0)
5799339Seric 	{
5809339Seric 		syserr("%s: cannot fork", label);
5819339Seric 		return (1);
5829339Seric 	}
5839339Seric 	if (childpid > 0)
5849339Seric 	{
5859339Seric 		auto int st;
5869339Seric 
5879378Seric 		/* parent -- wait for child to complete */
5889378Seric 		st = waitfor(childpid);
5899378Seric 		if (st == -1)
5909339Seric 			syserr("%s: lost child", label);
5919339Seric 
5929339Seric 		/* if we exited on a QUIT command, complete the process */
5939339Seric 		if (st == (EX_QUIT << 8))
5949339Seric 			finis();
5959339Seric 
5969339Seric 		return (1);
5979339Seric 	}
5989339Seric 	else
5999339Seric 	{
6009339Seric 		/* child */
6019339Seric 		InChild = TRUE;
6029545Seric 		clearenvelope(CurEnv);
6039339Seric 		return (0);
6049339Seric 	}
6059339Seric }
6069339Seric 
6075181Seric # endif SMTP
608