14549Seric # include "sendmail.h"
24549Seric 
3*4556Seric static char	SccsId[] =	"@(#)srvrsmtp.c	3.2	10/20/81";
4*4556Seric 
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 */
364549Seric 
374549Seric static struct cmd	CmdTab[] =
384549Seric {
394549Seric 	"mail",		CMDMAIL,
404549Seric 	"mrcp",		CMDMRCP,
414549Seric 	"data",		CMDDATA,
424549Seric 	"doit",		CMDDOIT,
434549Seric 	"rset",		CMDRSET,
444549Seric 	"vrfy",		CMDVRFY,
454549Seric 	"help",		CMDHELP,
464549Seric 	"noop",		CMDNOOP,
474549Seric 	"quit",		CMDQUIT,
484549Seric 	NULL,		CMDERROR,
494549Seric };
504549Seric 
514549Seric smtp()
524549Seric {
534549Seric 	char inp[MAXLINE];
544549Seric 	register char *p;
554549Seric 	struct cmd *c;
564549Seric 	char *cmd;
574549Seric 	extern char *skipword();
584549Seric 	extern bool sameword();
594549Seric 	bool hasmail;			/* mail command received */
604549Seric 	bool hasmrcp;			/* has a recipient */
614549Seric 	bool hasdata;			/* has mail data */
624549Seric 
634549Seric 	/*%%%*/	HostName = "XYZZY";
644549Seric 	hasmail = hasmrcp = hasdata = FALSE;
654549Seric 	message("220", "%s Sendmail at your service", HostName);
664549Seric 	for (;;)
674549Seric 	{
684549Seric 		To = NULL;
694549Seric 		Errors = 0;
704549Seric 		if (fgets(inp, sizeof inp, InChannel) == NULL)
714549Seric 		{
724549Seric 			/* end of file, just die */
734549Seric 			message("421", "Lost input channel");
744549Seric 			finis();
754549Seric 		}
764549Seric 
774549Seric 		/* clean up end of line */
784549Seric 		p = index(inp, '\n');
794549Seric 		if (p != NULL)
804549Seric 			*p = '\0';
814549Seric 		p = index(inp, '\r');
824549Seric 		if (p != NULL)
834549Seric 			*p = '\0';
844549Seric 
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 */
1054549Seric 			p = skipword(p, "from");
1064549Seric 			if (p == NULL)
1074549Seric 				break;
1084549Seric 			if (index(p, ',') != NULL)
1094549Seric 			{
1104549Seric 				message("501", "Source routing not implemented");
1114549Seric 				Errors++;
1124549Seric 				break;
1134549Seric 			}
1144549Seric 			setsender(p);
1154549Seric 			if (Errors == 0)
1164549Seric 			{
1174549Seric 				message("250", "Sender ok");
1184549Seric 				hasmail = TRUE;
1194549Seric 			}
1204549Seric 			break;
1214549Seric 
1224549Seric 		  case CMDMRCP:		/* mrcp -- designate recipient */
1234549Seric 			p = skipword(p, "to");
1244549Seric 			if (p == NULL)
1254549Seric 				break;
1264549Seric 			if (index(p, ',') != NULL)
1274549Seric 			{
1284549Seric 				message("501", "Source routing not implemented");
1294549Seric 				Errors++;
1304549Seric 				break;
1314549Seric 			}
1324549Seric 			sendto(p, 1, NULL);
1334549Seric 			if (Errors == 0)
1344549Seric 			{
1354549Seric 				message("250", "Recipient ok");
1364549Seric 				hasmrcp = TRUE;
1374549Seric 			}
1384549Seric 			break;
1394549Seric 
1404549Seric 		  case CMDDATA:		/* data -- text of mail */
1414549Seric 			message("354", "Enter mail, end with dot");
1424549Seric 			collect();
1434549Seric 			if (Errors == 0)
1444549Seric 			{
1454549Seric 				message("250", "Message stored");
1464549Seric 				hasdata = TRUE;
1474549Seric 			}
1484549Seric 			break;
1494549Seric 
1504549Seric 		  case CMDDOIT:		/* doit -- actually send everything */
1514549Seric 			if (!hasmail)
1524549Seric 				message("503", "Need MAIL command");
1534549Seric 			else if (!hasmrcp)
1544549Seric 				message("503", "Need MRCP (recipient)");
1554549Seric 			else if (!hasdata)
1564549Seric 				message("503", "No message, use DATA");
1574549Seric 			else
1584549Seric 			{
1594549Seric 				sendall(FALSE);
1604549Seric 				if (Errors == 0)
1614549Seric 					message("250", "Sent");
1624549Seric 			}
1634549Seric 			break;
1644549Seric 
1654549Seric 		  case CMDRSET:		/* rset -- reset state */
1664549Seric 			message("250", "Reset state");
1674549Seric 			finis();
1684549Seric 
1694549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
1704549Seric 			sendto(p, 1, NULL);
1714549Seric 			if (Errors == 0)
1724549Seric 				message("250", "user ok");
1734549Seric 			break;
1744549Seric 
1754549Seric 		  case CMDHELP:		/* help -- give user info */
1764549Seric 			message("502", "HELP not implemented");
1774549Seric 			break;
1784549Seric 
1794549Seric 		  case CMDNOOP:		/* noop -- do nothing */
1804549Seric 			message("200", "OK");
1814549Seric 			break;
1824549Seric 
1834549Seric 		  case CMDQUIT:		/* quit -- leave mail */
1844549Seric 			message("221", "%s closing connection", HostName);
1854549Seric 			finis();
1864549Seric 
1874549Seric 		  case CMDERROR:	/* unknown command */
1884549Seric 			message("500", "Command unrecognized");
1894549Seric 			break;
1904549Seric 
1914549Seric 		  default:
1924549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
1934549Seric 			break;
1944549Seric 		}
1954549Seric 	}
1964549Seric }
1974549Seric /*
1984549Seric **  SKIPWORD -- skip a fixed word.
1994549Seric **
2004549Seric **	Parameters:
2014549Seric **		p -- place to start looking.
2024549Seric **		w -- word to skip.
2034549Seric **
2044549Seric **	Returns:
2054549Seric **		p following w.
2064549Seric **		NULL on error.
2074549Seric **
2084549Seric **	Side Effects:
2094549Seric **		clobbers the p data area.
2104549Seric */
2114549Seric 
2124549Seric static char *
2134549Seric skipword(p, w)
2144549Seric 	register char *p;
2154549Seric 	char *w;
2164549Seric {
2174549Seric 	register char *q;
2184549Seric 	extern bool sameword();
2194549Seric 
2204549Seric 	/* find beginning of word */
2214549Seric 	while (isspace(*p))
2224549Seric 		p++;
2234549Seric 	q = p;
2244549Seric 
2254549Seric 	/* find end of word */
2264549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
2274549Seric 		p++;
2284549Seric 	while (isspace(*p))
2294549Seric 		*p++ = '\0';
2304549Seric 	if (*p != ':')
2314549Seric 	{
2324549Seric 	  syntax:
2334549Seric 		message("501", "Syntax error");
2344549Seric 		Errors++;
2354549Seric 		return (NULL);
2364549Seric 	}
2374549Seric 	*p++ = '\0';
2384549Seric 	while (isspace(*p))
2394549Seric 		p++;
2404549Seric 
2414549Seric 	/* see if the input word matches desired word */
2424549Seric 	if (!sameword(q, w))
2434549Seric 		goto syntax;
2444549Seric 
2454549Seric 	return (p);
2464549Seric }
247