14549Seric # include "sendmail.h"
24549Seric 
3*4713Seric static char	SccsId[] =	"@(#)srvrsmtp.c	3.7	10/31/81";
44556Seric 
54549Seric /*
64549Seric **  SMTP -- run the SMTP protocol.
74549Seric **
84549Seric **	Parameters:
94549Seric **		none.
104549Seric **
114549Seric **	Returns:
124549Seric **		never.
134549Seric **
144549Seric **	Side Effects:
154549Seric **		Reads commands from the input channel and processes
164549Seric **			them.
174549Seric */
184549Seric 
194549Seric struct cmd
204549Seric {
214549Seric 	char	*cmdname;	/* command name */
224549Seric 	int	cmdcode;	/* internal code, see below */
234549Seric };
244549Seric 
254549Seric /* values for cmdcode */
264549Seric # define CMDERROR	0	/* bad command */
274549Seric # define CMDMAIL	1	/* mail -- designate sender */
284549Seric # define CMDMRCP	2	/* mrcp -- designate recipient */
294549Seric # define CMDDATA	3	/* data -- send message text */
304549Seric # define CMDDOIT	4	/* doit -- actually do delivery */
314549Seric # define CMDRSET	5	/* rset -- reset state */
324549Seric # define CMDVRFY	6	/* vrfy -- verify address */
334549Seric # define CMDHELP	7	/* help -- give usage info */
344549Seric # define CMDNOOP	8	/* noop -- do nothing */
354549Seric # define CMDQUIT	9	/* quit -- close connection and die */
364577Seric # define CMDMRSQ	10	/* mrsq -- for old mtp compat only */
374549Seric 
384549Seric static struct cmd	CmdTab[] =
394549Seric {
404549Seric 	"mail",		CMDMAIL,
414549Seric 	"mrcp",		CMDMRCP,
424549Seric 	"data",		CMDDATA,
434549Seric 	"doit",		CMDDOIT,
444549Seric 	"rset",		CMDRSET,
454549Seric 	"vrfy",		CMDVRFY,
464549Seric 	"help",		CMDHELP,
474549Seric 	"noop",		CMDNOOP,
484549Seric 	"quit",		CMDQUIT,
494577Seric 	"mrsq",		CMDMRSQ,
504549Seric 	NULL,		CMDERROR,
514549Seric };
524549Seric 
534549Seric smtp()
544549Seric {
554549Seric 	char inp[MAXLINE];
564549Seric 	register char *p;
574549Seric 	struct cmd *c;
584549Seric 	char *cmd;
594549Seric 	extern char *skipword();
604549Seric 	extern bool sameword();
614549Seric 	bool hasmail;			/* mail command received */
62*4713Seric 	int rcps;			/* number of recipients */
634549Seric 	bool hasdata;			/* has mail data */
644549Seric 
65*4713Seric 	hasmail = hasdata = FALSE;
66*4713Seric 	rcps = 0;
674549Seric 	message("220", "%s Sendmail at your service", HostName);
684549Seric 	for (;;)
694549Seric 	{
704549Seric 		To = NULL;
714577Seric 		Errors = 0;
724549Seric 		if (fgets(inp, sizeof inp, InChannel) == NULL)
734549Seric 		{
744549Seric 			/* end of file, just die */
754558Seric 			message("421", "%s Lost input channel", HostName);
764549Seric 			finis();
774549Seric 		}
784549Seric 
794549Seric 		/* clean up end of line */
804558Seric 		fixcrlf(inp, TRUE);
814549Seric 
82*4713Seric 		/* echo command to transcript */
83*4713Seric 		fprintf(Xscript, "*** %s\n", inp);
84*4713Seric 
854549Seric 		/* break off command */
864549Seric 		for (p = inp; isspace(*p); p++)
874549Seric 			continue;
884549Seric 		cmd = p;
894549Seric 		while (*++p != '\0' && !isspace(*p))
904549Seric 			continue;
914549Seric 		if (*p != '\0')
924549Seric 			*p++ = '\0';
934549Seric 
944549Seric 		/* decode command */
954549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
964549Seric 		{
974549Seric 			if (sameword(c->cmdname, cmd))
984549Seric 				break;
994549Seric 		}
1004549Seric 
1014549Seric 		/* process command */
1024549Seric 		switch (c->cmdcode)
1034549Seric 		{
1044549Seric 		  case CMDMAIL:		/* mail -- designate sender */
1054558Seric 			if (hasmail)
1064558Seric 			{
1074558Seric 				message("503", "Sender already specified");
1084558Seric 				break;
1094558Seric 			}
1104549Seric 			p = skipword(p, "from");
1114549Seric 			if (p == NULL)
1124549Seric 				break;
1134549Seric 			if (index(p, ',') != NULL)
1144549Seric 			{
1154549Seric 				message("501", "Source routing not implemented");
1164549Seric 				Errors++;
1174549Seric 				break;
1184549Seric 			}
1194549Seric 			setsender(p);
1204577Seric 			if (Errors == 0)
1214549Seric 			{
1224549Seric 				message("250", "Sender ok");
1234549Seric 				hasmail = TRUE;
1244549Seric 			}
1254549Seric 			break;
1264549Seric 
1274549Seric 		  case CMDMRCP:		/* mrcp -- designate recipient */
1284549Seric 			p = skipword(p, "to");
1294549Seric 			if (p == NULL)
1304549Seric 				break;
1314549Seric 			if (index(p, ',') != NULL)
1324549Seric 			{
1334549Seric 				message("501", "Source routing not implemented");
1344549Seric 				Errors++;
1354549Seric 				break;
1364549Seric 			}
1374628Seric 			sendto(p, 1, (ADDRESS *) NULL);
1384577Seric 			if (Errors == 0)
1394549Seric 			{
1404549Seric 				message("250", "Recipient ok");
141*4713Seric 				rcps++;
1424549Seric 			}
1434549Seric 			break;
1444549Seric 
1454549Seric 		  case CMDDATA:		/* data -- text of mail */
146*4713Seric 			collect(TRUE);
1474577Seric 			if (Errors == 0)
1484549Seric 			{
1494549Seric 				message("250", "Message stored");
1504549Seric 				hasdata = TRUE;
1514549Seric 			}
1524549Seric 			break;
1534549Seric 
1544549Seric 		  case CMDDOIT:		/* doit -- actually send everything */
1554549Seric 			if (!hasmail)
1564549Seric 				message("503", "Need MAIL command");
157*4713Seric 			else if (rcps <= 0)
1584549Seric 				message("503", "Need MRCP (recipient)");
1594549Seric 			else if (!hasdata)
1604549Seric 				message("503", "No message, use DATA");
1614549Seric 			else
1624549Seric 			{
163*4713Seric 				if (rcps != 1)
164*4713Seric 					HoldErrs = MailBack = TRUE;
1654549Seric 				sendall(FALSE);
166*4713Seric 				HoldErrs = FALSE;
167*4713Seric 				To = NULL;
168*4713Seric 				if (Errors == 0 || rcps != 1)
1694549Seric 					message("250", "Sent");
1704549Seric 			}
1714549Seric 			break;
1724549Seric 
1734549Seric 		  case CMDRSET:		/* rset -- reset state */
1744549Seric 			message("250", "Reset state");
1754549Seric 			finis();
1764549Seric 
1774549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
1784628Seric 			sendto(p, 1, (ADDRESS *) NULL);
1794577Seric 			if (Errors == 0)
1804549Seric 				message("250", "user ok");
1814549Seric 			break;
1824549Seric 
1834549Seric 		  case CMDHELP:		/* help -- give user info */
1844577Seric 			if (*p == '\0')
1854577Seric 				p = "SMTP";
1864577Seric 			help(p);
1874549Seric 			break;
1884549Seric 
1894549Seric 		  case CMDNOOP:		/* noop -- do nothing */
1904549Seric 			message("200", "OK");
1914549Seric 			break;
1924549Seric 
1934549Seric 		  case CMDQUIT:		/* quit -- leave mail */
1944549Seric 			message("221", "%s closing connection", HostName);
1954549Seric 			finis();
1964549Seric 
1974577Seric 		  case CMDMRSQ:		/* mrsq -- negotiate protocol */
1984577Seric 			if (*p == 'R' || *p == 'T')
1994577Seric 			{
2004577Seric 				/* recipients first or text first */
2014577Seric 				message("200", "%c ok, please continue", *p);
2024577Seric 			}
2034577Seric 			else if (*p == '?')
2044577Seric 			{
2054577Seric 				/* what do I prefer?  anything, anytime */
2064577Seric 				message("215", "R Recipients first is my choice");
2074577Seric 			}
2084577Seric 			else if (*p == '\0')
2094577Seric 			{
2104577Seric 				/* no meaningful scheme */
2114577Seric 				message("200", "okey dokie boobie");
2124577Seric 			}
2134577Seric 			else
2144577Seric 			{
2154577Seric 				/* bad argument */
2164577Seric 				message("504", "Scheme unknown");
2174577Seric 			}
2184577Seric 			break;
2194577Seric 
2204549Seric 		  case CMDERROR:	/* unknown command */
2214549Seric 			message("500", "Command unrecognized");
2224549Seric 			break;
2234549Seric 
2244549Seric 		  default:
2254549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
2264549Seric 			break;
2274549Seric 		}
2284549Seric 	}
2294549Seric }
2304549Seric /*
2314549Seric **  SKIPWORD -- skip a fixed word.
2324549Seric **
2334549Seric **	Parameters:
2344549Seric **		p -- place to start looking.
2354549Seric **		w -- word to skip.
2364549Seric **
2374549Seric **	Returns:
2384549Seric **		p following w.
2394549Seric **		NULL on error.
2404549Seric **
2414549Seric **	Side Effects:
2424549Seric **		clobbers the p data area.
2434549Seric */
2444549Seric 
2454549Seric static char *
2464549Seric skipword(p, w)
2474549Seric 	register char *p;
2484549Seric 	char *w;
2494549Seric {
2504549Seric 	register char *q;
2514549Seric 	extern bool sameword();
2524549Seric 
2534549Seric 	/* find beginning of word */
2544549Seric 	while (isspace(*p))
2554549Seric 		p++;
2564549Seric 	q = p;
2574549Seric 
2584549Seric 	/* find end of word */
2594549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
2604549Seric 		p++;
2614549Seric 	while (isspace(*p))
2624549Seric 		*p++ = '\0';
2634549Seric 	if (*p != ':')
2644549Seric 	{
2654549Seric 	  syntax:
2664549Seric 		message("501", "Syntax error");
2674549Seric 		Errors++;
2684549Seric 		return (NULL);
2694549Seric 	}
2704549Seric 	*p++ = '\0';
2714549Seric 	while (isspace(*p))
2724549Seric 		p++;
2734549Seric 
2744549Seric 	/* see if the input word matches desired word */
2754549Seric 	if (!sameword(q, w))
2764549Seric 		goto syntax;
2774549Seric 
2784549Seric 	return (p);
2794549Seric }
2804577Seric /*
2814577Seric **  HELP -- implement the HELP command.
2824577Seric **
2834577Seric **	Parameters:
2844577Seric **		topic -- the topic we want help for.
2854577Seric **
2864577Seric **	Returns:
2874577Seric **		none.
2884577Seric **
2894577Seric **	Side Effects:
2904577Seric **		outputs the help file to message output.
2914577Seric */
2924577Seric 
2934577Seric help(topic)
2944577Seric 	char *topic;
2954577Seric {
2964577Seric 	register FILE *hf;
2974577Seric 	int len;
2984577Seric 	char buf[MAXLINE];
2994577Seric 	bool noinfo;
3004582Seric 	extern char *HelpFile;
3014577Seric 
3024582Seric 	hf = fopen(HelpFile, "r");
3034577Seric 	if (hf == NULL)
3044577Seric 	{
3054577Seric 		/* no help */
3064577Seric 		message("502", "HELP not implemented");
3074577Seric 		return;
3084577Seric 	}
3094577Seric 
3104577Seric 	len = strlen(topic);
3114577Seric 	makelower(topic);
3124577Seric 	noinfo = TRUE;
3134577Seric 
3144577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
3154577Seric 	{
3164577Seric 		if (strncmp(buf, topic, len) == 0)
3174577Seric 		{
3184577Seric 			register char *p;
3194577Seric 
3204577Seric 			p = index(buf, '\t');
3214577Seric 			if (p == NULL)
3224577Seric 				p = buf;
3234577Seric 			else
3244577Seric 				p++;
3254577Seric 			fixcrlf(p, TRUE);
3264577Seric 			message("214-", p);
3274577Seric 			noinfo = FALSE;
3284577Seric 		}
3294577Seric 	}
3304577Seric 
3314577Seric 	if (noinfo)
3324577Seric 		message("504", "HELP topic unknown");
3334577Seric 	else
3344577Seric 		message("214", "End of HELP info");
3354628Seric 	(void) fclose(hf);
3364577Seric }
337