19339Seric # include <errno.h>
24549Seric # include "sendmail.h"
34549Seric 
45181Seric # ifndef SMTP
5*11151Seric SCCSID(@(#)srvrsmtp.c	3.47		02/18/83	(no SMTP));
65181Seric # else SMTP
74556Seric 
8*11151Seric SCCSID(@(#)srvrsmtp.c	3.47		02/18/83);
95181Seric 
104549Seric /*
114549Seric **  SMTP -- run the SMTP protocol.
124549Seric **
134549Seric **	Parameters:
144549Seric **		none.
154549Seric **
164549Seric **	Returns:
174549Seric **		never.
184549Seric **
194549Seric **	Side Effects:
204549Seric **		Reads commands from the input channel and processes
214549Seric **			them.
224549Seric */
234549Seric 
244549Seric struct cmd
254549Seric {
264549Seric 	char	*cmdname;	/* command name */
274549Seric 	int	cmdcode;	/* internal code, see below */
284549Seric };
294549Seric 
304549Seric /* values for cmdcode */
314549Seric # define CMDERROR	0	/* bad command */
324549Seric # define CMDMAIL	1	/* mail -- designate sender */
334976Seric # define CMDRCPT	2	/* rcpt -- designate recipient */
344549Seric # define CMDDATA	3	/* data -- send message text */
359339Seric # define CMDRSET	4	/* rset -- reset state */
369339Seric # define CMDVRFY	5	/* vrfy -- verify address */
379339Seric # define CMDHELP	6	/* help -- give usage info */
389339Seric # define CMDNOOP	7	/* noop -- do nothing */
399339Seric # define CMDQUIT	8	/* quit -- close connection and die */
409339Seric # define CMDHELO	9	/* helo -- be polite */
419339Seric # define CMDDBGQSHOW	10	/* showq -- show send queue (DEBUG) */
429339Seric # define CMDDBGDEBUG	11	/* debug -- set debug mode */
439339Seric # define CMDVERB	12	/* verb -- go into verbose mode */
449339Seric # define CMDDBGKILL	13	/* kill -- kill sendmail */
459339Seric # define CMDDBGWIZ	14	/* wiz -- become a wizard */
469339Seric # define CMDONEX	15	/* onex -- sending one transaction only */
479339Seric # define CMDDBGSHELL	16	/* shell -- give us a shell */
484549Seric 
494549Seric static struct cmd	CmdTab[] =
504549Seric {
514549Seric 	"mail",		CMDMAIL,
524976Seric 	"rcpt",		CMDRCPT,
534549Seric 	"data",		CMDDATA,
544549Seric 	"rset",		CMDRSET,
554549Seric 	"vrfy",		CMDVRFY,
567762Seric 	"expn",		CMDVRFY,
574549Seric 	"help",		CMDHELP,
584549Seric 	"noop",		CMDNOOP,
594549Seric 	"quit",		CMDQUIT,
604976Seric 	"helo",		CMDHELO,
618544Seric 	"verb",		CMDVERB,
629314Seric 	"onex",		CMDONEX,
635003Seric # ifdef DEBUG
649339Seric 	"showq",	CMDDBGQSHOW,
658544Seric 	"debug",	CMDDBGDEBUG,
668544Seric 	"kill",		CMDDBGKILL,
678544Seric 	"wiz",		CMDDBGWIZ,
689339Seric 	"shell",	CMDDBGSHELL,
695003Seric # endif DEBUG
704549Seric 	NULL,		CMDERROR,
714549Seric };
724549Seric 
738544Seric # ifdef DEBUG
748544Seric bool	IsWiz = FALSE;			/* set if we are a wizard */
758544Seric char	*WizWord = NULL;		/* the wizard word to compare against */
768544Seric # endif DEBUG
779339Seric bool	InChild = FALSE;		/* true if running in a subprocess */
789378Seric bool	OneXact = FALSE;		/* one xaction only this run */
7911146Seric char	*RealHostName = NULL;		/* verified hostname, set in daemon.c */
8011146Seric 
819339Seric #define EX_QUIT		22		/* special code for QUIT command */
828544Seric 
834549Seric smtp()
844549Seric {
854549Seric 	register char *p;
868544Seric 	register struct cmd *c;
874549Seric 	char *cmd;
884549Seric 	extern char *skipword();
894549Seric 	extern bool sameword();
904549Seric 	bool hasmail;			/* mail command received */
914713Seric 	int rcps;			/* number of recipients */
925003Seric 	auto ADDRESS *vrfyqueue;
938544Seric 	char inp[MAXLINE];
947124Seric 	extern char Version[];
957356Seric 	extern tick();
968544Seric 	extern bool iswiz();
979349Seric 	extern char *arpadate();
98*11151Seric 	extern char *macvalue();
994549Seric 
1005003Seric 	hasmail = FALSE;
1014713Seric 	rcps = 0;
1027363Seric 	if (OutChannel != stdout)
1037363Seric 	{
1047363Seric 		/* arrange for debugging output to go to remote host */
1057363Seric 		(void) close(1);
1067363Seric 		(void) dup(fileno(OutChannel));
1077363Seric 	}
10810708Seric 	expand("$e", inp, &inp[sizeof inp], CurEnv);
10910708Seric 	message("220", inp);
1107762Seric 	(void) setjmp(TopFrame);
1117762Seric 	QuickAbort = FALSE;
1129390Seric 	HoldErrs = FALSE;
1134549Seric 	for (;;)
1144549Seric 	{
1157356Seric 		/* setup for the read */
1166907Seric 		CurEnv->e_to = NULL;
1174577Seric 		Errors = 0;
1187275Seric 		(void) fflush(stdout);
1197356Seric 
1207356Seric 		/* read the input line */
1217685Seric 		p = sfgets(inp, sizeof inp, InChannel);
1227356Seric 
1237685Seric 		/* handle errors */
1247356Seric 		if (p == NULL)
1257356Seric 		{
1264549Seric 			/* end of file, just die */
1274558Seric 			message("421", "%s Lost input channel", HostName);
1284549Seric 			finis();
1294549Seric 		}
1304549Seric 
1314549Seric 		/* clean up end of line */
1324558Seric 		fixcrlf(inp, TRUE);
1334549Seric 
1344713Seric 		/* echo command to transcript */
1359545Seric 		if (CurEnv->e_xfp != NULL)
1369545Seric 			fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
1374713Seric 
1384549Seric 		/* break off command */
1394549Seric 		for (p = inp; isspace(*p); p++)
1404549Seric 			continue;
1414549Seric 		cmd = p;
1424549Seric 		while (*++p != '\0' && !isspace(*p))
1434549Seric 			continue;
1444549Seric 		if (*p != '\0')
1454549Seric 			*p++ = '\0';
1464549Seric 
1474549Seric 		/* decode command */
1484549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
1494549Seric 		{
1504549Seric 			if (sameword(c->cmdname, cmd))
1514549Seric 				break;
1524549Seric 		}
1534549Seric 
1544549Seric 		/* process command */
1554549Seric 		switch (c->cmdcode)
1564549Seric 		{
1574976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
15811146Seric 			if (RealHostName != NULL && !sameword(p, RealHostName))
15911146Seric 			{
16011146Seric 				char buf[MAXNAME];
16111146Seric 
16211146Seric 				(void) sprintf(buf, "%s (%s)", p, RealHostName);
16311146Seric 				define('s', newstr(buf), CurEnv);
16411146Seric 			}
16511146Seric 			else
16611146Seric 				define('s', newstr(p), CurEnv);
1674997Seric 			message("250", "%s Hello %s, pleased to meet you",
1684997Seric 				HostName, p);
1694976Seric 			break;
1704976Seric 
1714549Seric 		  case CMDMAIL:		/* mail -- designate sender */
172*11151Seric 			/* force a sending host even if no HELO given */
173*11151Seric 			if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
174*11151Seric 				define('s', RealHostName, CurEnv);
175*11151Seric 
1769314Seric 			/* check for validity of this command */
1774558Seric 			if (hasmail)
1784558Seric 			{
1794558Seric 				message("503", "Sender already specified");
1804558Seric 				break;
1814558Seric 			}
1829339Seric 			if (InChild)
1839339Seric 			{
1849339Seric 				syserr("Nested MAIL command");
1859339Seric 				exit(0);
1869339Seric 			}
1879339Seric 
1889339Seric 			/* fork a subprocess to process this command */
1899339Seric 			if (runinchild("SMTP-MAIL") > 0)
1909339Seric 				break;
1919339Seric 			initsys();
1929339Seric 
1939339Seric 			/* child -- go do the processing */
1944549Seric 			p = skipword(p, "from");
1954549Seric 			if (p == NULL)
1964549Seric 				break;
1974549Seric 			setsender(p);
1984577Seric 			if (Errors == 0)
1994549Seric 			{
2004549Seric 				message("250", "Sender ok");
2014549Seric 				hasmail = TRUE;
2024549Seric 			}
2039339Seric 			else if (InChild)
2049339Seric 				finis();
2054549Seric 			break;
2064549Seric 
2074976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
2084549Seric 			p = skipword(p, "to");
2094549Seric 			if (p == NULL)
2104549Seric 				break;
2119619Seric 			sendtolist(p, (ADDRESS *) NULL, &CurEnv->e_sendqueue);
2129390Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
2134577Seric 			if (Errors == 0)
2144549Seric 			{
2156057Seric 				message("250", "%s... Recipient ok", p);
2164713Seric 				rcps++;
2174549Seric 			}
2184549Seric 			break;
2194549Seric 
2204549Seric 		  case CMDDATA:		/* data -- text of mail */
2214976Seric 			if (!hasmail)
2224549Seric 			{
2234976Seric 				message("503", "Need MAIL command");
2244976Seric 				break;
2254549Seric 			}
2264713Seric 			else if (rcps <= 0)
2274549Seric 			{
2284976Seric 				message("503", "Need RCPT (recipient)");
2294976Seric 				break;
2304549Seric 			}
2314976Seric 
2324976Seric 			/* collect the text of the message */
2334976Seric 			collect(TRUE);
2344976Seric 			if (Errors != 0)
2354976Seric 				break;
2364976Seric 
2378238Seric 			/*
2388238Seric 			**  Arrange to send to everyone.
2398238Seric 			**	If sending to multiple people, mail back
2408238Seric 			**		errors rather than reporting directly.
2418238Seric 			**	In any case, don't mail back errors for
2428238Seric 			**		anything that has happened up to
2438238Seric 			**		now (the other end will do this).
24410197Seric 			**	Truncate our transcript -- the mail has gotten
24510197Seric 			**		to us successfully, and if we have
24610197Seric 			**		to mail this back, it will be easier
24710197Seric 			**		on the reader.
2488238Seric 			**	Then send to everyone.
2498238Seric 			**	Finally give a reply code.  If an error has
2508238Seric 			**		already been given, don't mail a
2518238Seric 			**		message back.
2529339Seric 			**	We goose error returns by clearing error bit.
2538238Seric 			*/
2548238Seric 
2554976Seric 			if (rcps != 1)
2569378Seric 			{
2579378Seric 				HoldErrs = TRUE;
2589378Seric 				ErrorMode == EM_MAIL;
2599378Seric 			}
2609339Seric 			CurEnv->e_flags &= ~EF_FATALERRS;
26110197Seric 			CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
2624976Seric 
2634976Seric 			/* send to all recipients */
2649283Seric 			sendall(CurEnv, SendMode);
2656907Seric 			CurEnv->e_to = NULL;
2664976Seric 
2678238Seric 			/* issue success if appropriate and reset */
2688238Seric 			if (Errors == 0 || HoldErrs)
2699283Seric 				message("250", "Ok");
2708238Seric 			else
2719339Seric 				CurEnv->e_flags &= ~EF_FATALERRS;
2729339Seric 
2739339Seric 			/* if in a child, pop back to our parent */
2749339Seric 			if (InChild)
2759339Seric 				finis();
2764549Seric 			break;
2774549Seric 
2784549Seric 		  case CMDRSET:		/* rset -- reset state */
2794549Seric 			message("250", "Reset state");
2809339Seric 			if (InChild)
2819339Seric 				finis();
2829339Seric 			break;
2834549Seric 
2844549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
2859339Seric 			if (runinchild("SMTP-VRFY") > 0)
2869339Seric 				break;
2875003Seric 			vrfyqueue = NULL;
2887762Seric 			QuickAbort = TRUE;
2899619Seric 			sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
2907762Seric 			if (Errors != 0)
2919339Seric 			{
2929339Seric 				if (InChild)
2939339Seric 					finis();
2947762Seric 				break;
2959339Seric 			}
2965003Seric 			while (vrfyqueue != NULL)
2975003Seric 			{
2985003Seric 				register ADDRESS *a = vrfyqueue->q_next;
2995003Seric 				char *code;
3005003Seric 
3017685Seric 				while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
3025003Seric 					a = a->q_next;
3035003Seric 
3047685Seric 				if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
3055003Seric 				{
3065003Seric 					if (a != NULL)
3075003Seric 						code = "250-";
3085003Seric 					else
3095003Seric 						code = "250";
3105003Seric 					if (vrfyqueue->q_fullname == NULL)
3115003Seric 						message(code, "<%s>", vrfyqueue->q_paddr);
3125003Seric 					else
3135003Seric 						message(code, "%s <%s>",
3145003Seric 						    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
3155003Seric 				}
3165003Seric 				else if (a == NULL)
3175003Seric 					message("554", "Self destructive alias loop");
3185003Seric 				vrfyqueue = a;
3195003Seric 			}
3209339Seric 			if (InChild)
3219339Seric 				finis();
3224549Seric 			break;
3234549Seric 
3244549Seric 		  case CMDHELP:		/* help -- give user info */
3254577Seric 			if (*p == '\0')
3264577Seric 				p = "SMTP";
3274577Seric 			help(p);
3284549Seric 			break;
3294549Seric 
3304549Seric 		  case CMDNOOP:		/* noop -- do nothing */
3314549Seric 			message("200", "OK");
3324549Seric 			break;
3334549Seric 
3344549Seric 		  case CMDQUIT:		/* quit -- leave mail */
3354549Seric 			message("221", "%s closing connection", HostName);
3369339Seric 			if (InChild)
3379339Seric 				ExitStat = EX_QUIT;
3384549Seric 			finis();
3394549Seric 
3408544Seric 		  case CMDVERB:		/* set verbose mode */
3418544Seric 			Verbose = TRUE;
3428544Seric 			message("200", "Verbose mode");
3438544Seric 			break;
3448544Seric 
3459314Seric 		  case CMDONEX:		/* doing one transaction only */
3469378Seric 			OneXact = TRUE;
3479314Seric 			message("200", "Only one transaction");
3489314Seric 			break;
3499314Seric 
3505003Seric # ifdef DEBUG
3519339Seric 		  case CMDDBGQSHOW:	/* show queues */
3526907Seric 			printf("Send Queue=");
3536907Seric 			printaddr(CurEnv->e_sendqueue, TRUE);
3545003Seric 			break;
3557275Seric 
3567275Seric 		  case CMDDBGDEBUG:	/* set debug mode */
3577676Seric 			tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
3587676Seric 			tTflag(p);
3597676Seric 			message("200", "Debug set");
3607275Seric 			break;
3617275Seric 
3627282Seric 		  case CMDDBGKILL:	/* kill the parent */
3638544Seric 			if (!iswiz())
3648544Seric 				break;
3657282Seric 			if (kill(MotherPid, SIGTERM) >= 0)
3667282Seric 				message("200", "Mother is dead");
3677282Seric 			else
3687282Seric 				message("500", "Can't kill Mom");
3697282Seric 			break;
3708544Seric 
3719339Seric 		  case CMDDBGSHELL:	/* give us an interactive shell */
3729339Seric 			if (!iswiz())
3739339Seric 				break;
3749378Seric 			if (fileno(InChannel) != 0)
3759378Seric 			{
3769378Seric 				(void) close(0);
3779378Seric 				(void) dup(fileno(InChannel));
37810346Seric 				if (fileno(InChannel) != fileno(OutChannel))
37910346Seric 					(void) fclose(InChannel);
3809378Seric 				InChannel = stdin;
3819378Seric 			}
3829378Seric 			if (fileno(OutChannel) != 1)
3839378Seric 			{
3849378Seric 				(void) close(1);
3859378Seric 				(void) dup(fileno(OutChannel));
3869378Seric 				(void) fclose(OutChannel);
3879378Seric 				OutChannel = stdout;
3889378Seric 			}
38910346Seric 			(void) close(2);
39010346Seric 			(void) dup(1);
3919339Seric 			execl("/bin/csh", "sendmail", 0);
3929339Seric 			execl("/bin/sh", "sendmail", 0);
3939339Seric 			message("500", "Can't");
3949378Seric 			exit(EX_UNAVAILABLE);
3959339Seric 
3968544Seric 		  case CMDDBGWIZ:	/* become a wizard */
3978544Seric 			if (WizWord != NULL)
3988544Seric 			{
3998544Seric 				char seed[3];
4008544Seric 				extern char *crypt();
4018544Seric 
4028544Seric 				strncpy(seed, WizWord, 2);
4038544Seric 				if (strcmp(WizWord, crypt(p, seed)) != 0)
4048544Seric 				{
4058544Seric 					message("500", "You are no wizard!");
4068544Seric 					break;
4078544Seric 				}
4088544Seric 			}
4098544Seric 			IsWiz = TRUE;
4108544Seric 			message("200", "Please pass, oh mighty wizard");
4118544Seric 			break;
4125003Seric # endif DEBUG
4135003Seric 
4144549Seric 		  case CMDERROR:	/* unknown command */
4154549Seric 			message("500", "Command unrecognized");
4164549Seric 			break;
4174549Seric 
4184549Seric 		  default:
4194549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
4204549Seric 			break;
4214549Seric 		}
4224549Seric 	}
4234549Seric }
4244549Seric /*
4254549Seric **  SKIPWORD -- skip a fixed word.
4264549Seric **
4274549Seric **	Parameters:
4284549Seric **		p -- place to start looking.
4294549Seric **		w -- word to skip.
4304549Seric **
4314549Seric **	Returns:
4324549Seric **		p following w.
4334549Seric **		NULL on error.
4344549Seric **
4354549Seric **	Side Effects:
4364549Seric **		clobbers the p data area.
4374549Seric */
4384549Seric 
4394549Seric static char *
4404549Seric skipword(p, w)
4414549Seric 	register char *p;
4424549Seric 	char *w;
4434549Seric {
4444549Seric 	register char *q;
4454549Seric 	extern bool sameword();
4464549Seric 
4474549Seric 	/* find beginning of word */
4484549Seric 	while (isspace(*p))
4494549Seric 		p++;
4504549Seric 	q = p;
4514549Seric 
4524549Seric 	/* find end of word */
4534549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
4544549Seric 		p++;
4554549Seric 	while (isspace(*p))
4564549Seric 		*p++ = '\0';
4574549Seric 	if (*p != ':')
4584549Seric 	{
4594549Seric 	  syntax:
4604549Seric 		message("501", "Syntax error");
4614549Seric 		Errors++;
4624549Seric 		return (NULL);
4634549Seric 	}
4644549Seric 	*p++ = '\0';
4654549Seric 	while (isspace(*p))
4664549Seric 		p++;
4674549Seric 
4684549Seric 	/* see if the input word matches desired word */
4694549Seric 	if (!sameword(q, w))
4704549Seric 		goto syntax;
4714549Seric 
4724549Seric 	return (p);
4734549Seric }
4744577Seric /*
4754577Seric **  HELP -- implement the HELP command.
4764577Seric **
4774577Seric **	Parameters:
4784577Seric **		topic -- the topic we want help for.
4794577Seric **
4804577Seric **	Returns:
4814577Seric **		none.
4824577Seric **
4834577Seric **	Side Effects:
4844577Seric **		outputs the help file to message output.
4854577Seric */
4864577Seric 
4874577Seric help(topic)
4884577Seric 	char *topic;
4894577Seric {
4904577Seric 	register FILE *hf;
4914577Seric 	int len;
4924577Seric 	char buf[MAXLINE];
4934577Seric 	bool noinfo;
4944577Seric 
4958269Seric 	if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
4964577Seric 	{
4974577Seric 		/* no help */
4984577Seric 		message("502", "HELP not implemented");
4994577Seric 		return;
5004577Seric 	}
5014577Seric 
5024577Seric 	len = strlen(topic);
5034577Seric 	makelower(topic);
5044577Seric 	noinfo = TRUE;
5054577Seric 
5064577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
5074577Seric 	{
5084577Seric 		if (strncmp(buf, topic, len) == 0)
5094577Seric 		{
5104577Seric 			register char *p;
5114577Seric 
5124577Seric 			p = index(buf, '\t');
5134577Seric 			if (p == NULL)
5144577Seric 				p = buf;
5154577Seric 			else
5164577Seric 				p++;
5174577Seric 			fixcrlf(p, TRUE);
5184577Seric 			message("214-", p);
5194577Seric 			noinfo = FALSE;
5204577Seric 		}
5214577Seric 	}
5224577Seric 
5234577Seric 	if (noinfo)
5244577Seric 		message("504", "HELP topic unknown");
5254577Seric 	else
5264577Seric 		message("214", "End of HELP info");
5274628Seric 	(void) fclose(hf);
5284577Seric }
5298544Seric /*
5308544Seric **  ISWIZ -- tell us if we are a wizard
5318544Seric **
5328544Seric **	If not, print a nasty message.
5338544Seric **
5348544Seric **	Parameters:
5358544Seric **		none.
5368544Seric **
5378544Seric **	Returns:
5388544Seric **		TRUE if we are a wizard.
5398544Seric **		FALSE if we are not a wizard.
5408544Seric **
5418544Seric **	Side Effects:
5428544Seric **		Prints a 500 exit stat if we are not a wizard.
5438544Seric */
5445181Seric 
5458544Seric bool
5468544Seric iswiz()
5478544Seric {
5488544Seric 	if (!IsWiz)
5498544Seric 		message("500", "Mere mortals musn't mutter that mantra");
5508544Seric 	return (IsWiz);
5518544Seric }
5529339Seric /*
5539339Seric **  RUNINCHILD -- return twice -- once in the child, then in the parent again
5549339Seric **
5559339Seric **	Parameters:
5569339Seric **		label -- a string used in error messages
5579339Seric **
5589339Seric **	Returns:
5599339Seric **		zero in the child
5609339Seric **		one in the parent
5619339Seric **
5629339Seric **	Side Effects:
5639339Seric **		none.
5649339Seric */
5658544Seric 
5669339Seric runinchild(label)
5679339Seric 	char *label;
5689339Seric {
5699339Seric 	int childpid;
5709339Seric 
5719378Seric 	if (OneXact)
5729378Seric 		return (0);
5739378Seric 
5749339Seric 	childpid = dofork();
5759339Seric 	if (childpid < 0)
5769339Seric 	{
5779339Seric 		syserr("%s: cannot fork", label);
5789339Seric 		return (1);
5799339Seric 	}
5809339Seric 	if (childpid > 0)
5819339Seric 	{
5829339Seric 		auto int st;
5839339Seric 
5849378Seric 		/* parent -- wait for child to complete */
5859378Seric 		st = waitfor(childpid);
5869378Seric 		if (st == -1)
5879339Seric 			syserr("%s: lost child", label);
5889339Seric 
5899339Seric 		/* if we exited on a QUIT command, complete the process */
5909339Seric 		if (st == (EX_QUIT << 8))
5919339Seric 			finis();
5929339Seric 
5939339Seric 		return (1);
5949339Seric 	}
5959339Seric 	else
5969339Seric 	{
5979339Seric 		/* child */
5989339Seric 		InChild = TRUE;
5999545Seric 		clearenvelope(CurEnv);
6009339Seric 		return (0);
6019339Seric 	}
6029339Seric }
6039339Seric 
6045181Seric # endif SMTP
605