19339Seric # include <errno.h>
24549Seric # include "sendmail.h"
3*11728Seric # include <signal.h>
44549Seric 
55181Seric # ifndef SMTP
6*11728Seric SCCSID(@(#)srvrsmtp.c	3.48		03/26/83	(no SMTP));
75181Seric # else SMTP
84556Seric 
9*11728Seric SCCSID(@(#)srvrsmtp.c	3.48		03/26/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 	}
10910708Seric 	expand("$e", inp, &inp[sizeof inp], CurEnv);
11010708Seric 	message("220", inp);
1117762Seric 	(void) setjmp(TopFrame);
1127762Seric 	QuickAbort = FALSE;
1139390Seric 	HoldErrs = FALSE;
1144549Seric 	for (;;)
1154549Seric 	{
1167356Seric 		/* setup for the read */
1176907Seric 		CurEnv->e_to = NULL;
1184577Seric 		Errors = 0;
1197275Seric 		(void) fflush(stdout);
1207356Seric 
1217356Seric 		/* read the input line */
1227685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1237356Seric 
1247685Seric 		/* handle errors */
1257356Seric 		if (p == NULL)
1267356Seric 		{
1274549Seric 			/* end of file, just die */
1284558Seric 			message("421", "%s Lost input channel", HostName);
1294549Seric 			finis();
1304549Seric 		}
1314549Seric 
1324549Seric 		/* clean up end of line */
1334558Seric 		fixcrlf(inp, TRUE);
1344549Seric 
1354713Seric 		/* echo command to transcript */
1369545Seric 		if (CurEnv->e_xfp != NULL)
1379545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1384713Seric 
1394549Seric 		/* break off command */
1404549Seric 		for (p = inp; isspace(*p); p++)
1414549Seric 			continue;
1424549Seric 		cmd = p;
1434549Seric 		while (*++p != '\0' && !isspace(*p))
1444549Seric 			continue;
1454549Seric 		if (*p != '\0')
1464549Seric 			*p++ = '\0';
1474549Seric 
1484549Seric 		/* decode command */
1494549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1504549Seric 		{
1514549Seric 			if (sameword(c->cmdname, cmd))
1524549Seric 				break;
1534549Seric 		}
1544549Seric 
1554549Seric 		/* process command */
1564549Seric 		switch (c->cmdcode)
1574549Seric 		{
1584976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
15911146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
16011146Seric 			{
16111146Seric 				char buf[MAXNAME];
16211146Seric 
16311146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
16411146Seric 				define('s', newstr(buf), CurEnv);
16511146Seric 			}
16611146Seric 			else
16711146Seric 				define('s', newstr(p), CurEnv);
1684997Seric 			message("250", "%s Hello %s, pleased to meet you",
1694997Seric 				HostName, p);
1704976Seric 			break;
1714976Seric 
1724549Seric 		  case CMDMAIL:		/* mail -- designate sender */
17311151Seric 			/* force a sending host even if no HELO given */
17411151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
17511151Seric 				define('s', RealHostName, CurEnv);
17611151Seric 
1779314Seric 			/* check for validity of this command */
1784558Seric 			if (hasmail)
1794558Seric 			{
1804558Seric 				message("503", "Sender already specified");
1814558Seric 				break;
1824558Seric 			}
1839339Seric 			if (InChild)
1849339Seric 			{
1859339Seric 				syserr("Nested MAIL command");
1869339Seric 				exit(0);
1879339Seric 			}
1889339Seric 
1899339Seric 			/* fork a subprocess to process this command */
1909339Seric 			if (runinchild("SMTP-MAIL") > 0)
1919339Seric 				break;
1929339Seric 			initsys();
1939339Seric 
1949339Seric 			/* child -- go do the processing */
1954549Seric 			p = skipword(p, "from");
1964549Seric 			if (p == NULL)
1974549Seric 				break;
1984549Seric 			setsender(p);
1994577Seric 			if (Errors == 0)
2004549Seric 			{
2014549Seric 				message("250", "Sender ok");
2024549Seric 				hasmail = TRUE;
2034549Seric 			}
2049339Seric 			else if (InChild)
2059339Seric 				finis();
2064549Seric 			break;
2074549Seric 
2084976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
2094549Seric 			p = skipword(p, "to");
2104549Seric 			if (p == NULL)
2114549Seric 				break;
2129619Seric 			sendtolist(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
2139390Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
2144577Seric 			if (Errors == 0)
2154549Seric 			{
2166057Seric 				message("250", "%s... Recipient ok", p);
2174713Seric 				rcps++;
2184549Seric 			}
2194549Seric 			break;
2204549Seric 
2214549Seric 		  case CMDDATA:		/* data -- text of mail */
2224976Seric 			if (!hasmail)
2234549Seric 			{
2244976Seric 				message("503", "Need MAIL command");
2254976Seric 				break;
2264549Seric 			}
2274713Seric 			else if (rcps <= 0)
2284549Seric 			{
2294976Seric 				message("503", "Need RCPT (recipient)");
2304976Seric 				break;
2314549Seric 			}
2324976Seric 
2334976Seric 			/* collect the text of the message */
2344976Seric 			collect(TRUE);
2354976Seric 			if (Errors != 0)
2364976Seric 				break;
2374976Seric 
2388238Seric 			/*
2398238Seric 			**  Arrange to send to everyone.
2408238Seric 			**	If sending to multiple people, mail back
2418238Seric 			**		errors rather than reporting directly.
2428238Seric 			**	In any case, don't mail back errors for
2438238Seric 			**		anything that has happened up to
2448238Seric 			**		now (the other end will do this).
24510197Seric 			**	Truncate our transcript -- the mail has gotten
24610197Seric 			**		to us successfully, and if we have
24710197Seric 			**		to mail this back, it will be easier
24810197Seric 			**		on the reader.
2498238Seric 			**	Then send to everyone.
2508238Seric 			**	Finally give a reply code.  If an error has
2518238Seric 			**		already been given, don't mail a
2528238Seric 			**		message back.
2539339Seric 			**	We goose error returns by clearing error bit.
2548238Seric 			*/
2558238Seric 
2564976Seric 			if (rcps != 1)
2579378Seric 			{
2589378Seric 				HoldErrs = TRUE;
2599378Seric 				ErrorMode == EM_MAIL;
2609378Seric 			}
2619339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
26210197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
2634976Seric 
2644976Seric 			/* send to all recipients */
2659283Seric 			sendall(CurEnv, SendMode);
2666907Seric 			CurEnv->e_to = NULL;
2674976Seric 
2688238Seric 			/* issue success if appropriate and reset */
2698238Seric 			if (Errors == 0 || HoldErrs)
2709283Seric 				message("250", "Ok");
2718238Seric 			else
2729339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
2739339Seric 
2749339Seric 			/* if in a child, pop back to our parent */
2759339Seric 			if (InChild)
2769339Seric 				finis();
2774549Seric 			break;
2784549Seric 
2794549Seric 		  case CMDRSET:		/* rset -- reset state */
2804549Seric 			message("250", "Reset state");
2819339Seric 			if (InChild)
2829339Seric 				finis();
2839339Seric 			break;
2844549Seric 
2854549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
2869339Seric 			if (runinchild("SMTP-VRFY") > 0)
2879339Seric 				break;
2885003Seric 			vrfyqueue = NULL;
2897762Seric 			QuickAbort = TRUE;
2909619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
2917762Seric 			if (Errors != 0)
2929339Seric 			{
2939339Seric 				if (InChild)
2949339Seric 					finis();
2957762Seric 				break;
2969339Seric 			}
2975003Seric 			while (vrfyqueue != NULL)
2985003Seric 			{
2995003Seric 				register ADDRESS *a = vrfyqueue->q_next;
3005003Seric 				char *code;
3015003Seric 
3027685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3035003Seric 					a = a->q_next;
3045003Seric 
3057685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3065003Seric 				{
3075003Seric 					if (a != NULL)
3085003Seric 						code = "250-";
3095003Seric 					else
3105003Seric 						code = "250";
3115003Seric 					if (vrfyqueue->q_fullname == NULL)
3125003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3135003Seric 					else
3145003Seric 						message(code, "%s <%s>",
3155003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3165003Seric 				}
3175003Seric 				else if (a == NULL)
3185003Seric 					message("554", "Self destructive alias loop");
3195003Seric 				vrfyqueue = a;
3205003Seric 			}
3219339Seric 			if (InChild)
3229339Seric 				finis();
3234549Seric 			break;
3244549Seric 
3254549Seric 		  case CMDHELP:		/* help -- give user info */
3264577Seric 			if (*p == '\0')
3274577Seric 				p = "SMTP";
3284577Seric 			help(p);
3294549Seric 			break;
3304549Seric 
3314549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3324549Seric 			message("200", "OK");
3334549Seric 			break;
3344549Seric 
3354549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3364549Seric 			message("221", "%s closing connection", HostName);
3379339Seric 			if (InChild)
3389339Seric 				ExitStat = EX_QUIT;
3394549Seric 			finis();
3404549Seric 
3418544Seric 		  case CMDVERB:		/* set verbose mode */
3428544Seric 			Verbose = TRUE;
3438544Seric 			message("200", "Verbose mode");
3448544Seric 			break;
3458544Seric 
3469314Seric 		  case CMDONEX:		/* doing one transaction only */
3479378Seric 			OneXact = TRUE;
3489314Seric 			message("200", "Only one transaction");
3499314Seric 			break;
3509314Seric 
3515003Seric # ifdef DEBUG
3529339Seric 		  case CMDDBGQSHOW:	/* show queues */
3536907Seric 			printf("Send Queue=");
3546907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
3555003Seric 			break;
3567275Seric 
3577275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
3587676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
3597676Seric 			tTflag(p);
3607676Seric 			message("200", "Debug set");
3617275Seric 			break;
3627275Seric 
3637282Seric 		  case CMDDBGKILL:	/* kill the parent */
3648544Seric 			if (!iswiz())
3658544Seric 				break;
3667282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
3677282Seric 				message("200", "Mother is dead");
3687282Seric 			else
3697282Seric 				message("500", "Can't kill Mom");
3707282Seric 			break;
3718544Seric 
3729339Seric 		  case CMDDBGSHELL:	/* give us an interactive shell */
3739339Seric 			if (!iswiz())
3749339Seric 				break;
3759378Seric 			if (fileno(InChannel) != 0)
3769378Seric 			{
3779378Seric 				(void) close(0);
3789378Seric 				(void) dup(fileno(InChannel));
37910346Seric 				if (fileno(InChannel) != fileno(OutChannel))
38010346Seric 					(void) fclose(InChannel);
3819378Seric 				InChannel = stdin;
3829378Seric 			}
3839378Seric 			if (fileno(OutChannel) != 1)
3849378Seric 			{
3859378Seric 				(void) close(1);
3869378Seric 				(void) dup(fileno(OutChannel));
3879378Seric 				(void) fclose(OutChannel);
3889378Seric 				OutChannel = stdout;
3899378Seric 			}
39010346Seric 			(void) close(2);
39110346Seric 			(void) dup(1);
3929339Seric 			execl("/bin/csh", "sendmail", 0);
3939339Seric 			execl("/bin/sh", "sendmail", 0);
3949339Seric 			message("500", "Can't");
3959378Seric 			exit(EX_UNAVAILABLE);
3969339Seric 
3978544Seric 		  case CMDDBGWIZ:	/* become a wizard */
3988544Seric 			if (WizWord != NULL)
3998544Seric 			{
4008544Seric 				char seed[3];
4018544Seric 				extern char *crypt();
4028544Seric 
4038544Seric 				strncpy(seed, WizWord, 2);
4048544Seric 				if (strcmp(WizWord, crypt(p, seed)) != 0)
4058544Seric 				{
4068544Seric 					message("500", "You are no wizard!");
4078544Seric 					break;
4088544Seric 				}
4098544Seric 			}
4108544Seric 			IsWiz = TRUE;
4118544Seric 			message("200", "Please pass, oh mighty wizard");
4128544Seric 			break;
4135003Seric # endif DEBUG
4145003Seric 
4154549Seric 		  case CMDERROR:	/* unknown command */
4164549Seric 			message("500", "Command unrecognized");
4174549Seric 			break;
4184549Seric 
4194549Seric 		  default:
4204549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4214549Seric 			break;
4224549Seric 		}
4234549Seric 	}
4244549Seric }
4254549Seric /*
4264549Seric **  SKIPWORD -- skip a fixed word.
4274549Seric **
4284549Seric **	Parameters:
4294549Seric **		p -- place to start looking.
4304549Seric **		w -- word to skip.
4314549Seric **
4324549Seric **	Returns:
4334549Seric **		p following w.
4344549Seric **		NULL on error.
4354549Seric **
4364549Seric **	Side Effects:
4374549Seric **		clobbers the p data area.
4384549Seric */
4394549Seric 
4404549Seric static char *
4414549Seric skipword(p, w)
4424549Seric 	register char *p;
4434549Seric 	char *w;
4444549Seric {
4454549Seric 	register char *q;
4464549Seric 	extern bool sameword();
4474549Seric 
4484549Seric 	/* find beginning of word */
4494549Seric 	while (isspace(*p))
4504549Seric 		p++;
4514549Seric 	q = p;
4524549Seric 
4534549Seric 	/* find end of word */
4544549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4554549Seric 		p++;
4564549Seric 	while (isspace(*p))
4574549Seric 		*p++ = '\0';
4584549Seric 	if (*p != ':')
4594549Seric 	{
4604549Seric 	  syntax:
4614549Seric 		message("501", "Syntax error");
4624549Seric 		Errors++;
4634549Seric 		return (NULL);
4644549Seric 	}
4654549Seric 	*p++ = '\0';
4664549Seric 	while (isspace(*p))
4674549Seric 		p++;
4684549Seric 
4694549Seric 	/* see if the input word matches desired word */
4704549Seric 	if (!sameword(q, w))
4714549Seric 		goto syntax;
4724549Seric 
4734549Seric 	return (p);
4744549Seric }
4754577Seric /*
4764577Seric **  HELP -- implement the HELP command.
4774577Seric **
4784577Seric **	Parameters:
4794577Seric **		topic -- the topic we want help for.
4804577Seric **
4814577Seric **	Returns:
4824577Seric **		none.
4834577Seric **
4844577Seric **	Side Effects:
4854577Seric **		outputs the help file to message output.
4864577Seric */
4874577Seric 
4884577Seric help(topic)
4894577Seric 	char *topic;
4904577Seric {
4914577Seric 	register FILE *hf;
4924577Seric 	int len;
4934577Seric 	char buf[MAXLINE];
4944577Seric 	bool noinfo;
4954577Seric 
4968269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
4974577Seric 	{
4984577Seric 		/* no help */
4994577Seric 		message("502", "HELP not implemented");
5004577Seric 		return;
5014577Seric 	}
5024577Seric 
5034577Seric 	len = strlen(topic);
5044577Seric 	makelower(topic);
5054577Seric 	noinfo = TRUE;
5064577Seric 
5074577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5084577Seric 	{
5094577Seric 		if (strncmp(buf, topic, len) == 0)
5104577Seric 		{
5114577Seric 			register char *p;
5124577Seric 
5134577Seric 			p = index(buf, '\t');
5144577Seric 			if (p == NULL)
5154577Seric 				p = buf;
5164577Seric 			else
5174577Seric 				p++;
5184577Seric 			fixcrlf(p, TRUE);
5194577Seric 			message("214-", p);
5204577Seric 			noinfo = FALSE;
5214577Seric 		}
5224577Seric 	}
5234577Seric 
5244577Seric 	if (noinfo)
5254577Seric 		message("504", "HELP topic unknown");
5264577Seric 	else
5274577Seric 		message("214", "End of HELP info");
5284628Seric 	(void) fclose(hf);
5294577Seric }
5308544Seric /*
5318544Seric **  ISWIZ -- tell us if we are a wizard
5328544Seric **
5338544Seric **	If not, print a nasty message.
5348544Seric **
5358544Seric **	Parameters:
5368544Seric **		none.
5378544Seric **
5388544Seric **	Returns:
5398544Seric **		TRUE if we are a wizard.
5408544Seric **		FALSE if we are not a wizard.
5418544Seric **
5428544Seric **	Side Effects:
5438544Seric **		Prints a 500 exit stat if we are not a wizard.
5448544Seric */
5455181Seric 
5468544Seric bool
5478544Seric iswiz()
5488544Seric {
5498544Seric 	if (!IsWiz)
5508544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5518544Seric 	return (IsWiz);
5528544Seric }
5539339Seric /*
5549339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5559339Seric **
5569339Seric **	Parameters:
5579339Seric **		label -- a string used in error messages
5589339Seric **
5599339Seric **	Returns:
5609339Seric **		zero in the child
5619339Seric **		one in the parent
5629339Seric **
5639339Seric **	Side Effects:
5649339Seric **		none.
5659339Seric */
5668544Seric 
5679339Seric runinchild(label)
5689339Seric 	char *label;
5699339Seric {
5709339Seric 	int childpid;
5719339Seric 
5729378Seric 	if (OneXact)
5739378Seric 		return (0);
5749378Seric 
5759339Seric 	childpid = dofork();
5769339Seric 	if (childpid < 0)
5779339Seric 	{
5789339Seric 		syserr("%s: cannot fork", label);
5799339Seric 		return (1);
5809339Seric 	}
5819339Seric 	if (childpid > 0)
5829339Seric 	{
5839339Seric 		auto int st;
5849339Seric 
5859378Seric 		/* parent -- wait for child to complete */
5869378Seric 		st = waitfor(childpid);
5879378Seric 		if (st == -1)
5889339Seric 			syserr("%s: lost child", label);
5899339Seric 
5909339Seric 		/* if we exited on a QUIT command, complete the process */
5919339Seric 		if (st == (EX_QUIT << 8))
5929339Seric 			finis();
5939339Seric 
5949339Seric 		return (1);
5959339Seric 	}
5969339Seric 	else
5979339Seric 	{
5989339Seric 		/* child */
5999339Seric 		InChild = TRUE;
6009545Seric 		clearenvelope(CurEnv);
6019339Seric 		return (0);
6029339Seric 	}
6039339Seric }
6049339Seric 
6055181Seric # endif SMTP
606