14549Seric # include "sendmail.h"
24549Seric 
3*4582Seric static char	SccsId[] =	"@(#)srvrsmtp.c	3.5	10/22/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 */
624549Seric 	bool hasmrcp;			/* has a recipient */
634549Seric 	bool hasdata;			/* has mail data */
644549Seric 
654549Seric 	hasmail = hasmrcp = hasdata = FALSE;
664549Seric 	message("220", "%s Sendmail at your service", HostName);
674549Seric 	for (;;)
684549Seric 	{
694549Seric 		To = NULL;
704577Seric 		Errors = 0;
714549Seric 		if (fgets(inp, sizeof inp, InChannel) == NULL)
724549Seric 		{
734549Seric 			/* end of file, just die */
744558Seric 			message("421", "%s Lost input channel", HostName);
754549Seric 			finis();
764549Seric 		}
774549Seric 
784549Seric 		/* clean up end of line */
794558Seric 		fixcrlf(inp, TRUE);
804549Seric 
814549Seric 		/* break off command */
824549Seric 		for (p = inp; isspace(*p); p++)
834549Seric 			continue;
844549Seric 		cmd = p;
854549Seric 		while (*++p != '\0' && !isspace(*p))
864549Seric 			continue;
874549Seric 		if (*p != '\0')
884549Seric 			*p++ = '\0';
894549Seric 
904549Seric 		/* decode command */
914549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
924549Seric 		{
934549Seric 			if (sameword(c->cmdname, cmd))
944549Seric 				break;
954549Seric 		}
964549Seric 
974549Seric 		/* process command */
984549Seric 		switch (c->cmdcode)
994549Seric 		{
1004549Seric 		  case CMDMAIL:		/* mail -- designate sender */
1014558Seric 			if (hasmail)
1024558Seric 			{
1034558Seric 				message("503", "Sender already specified");
1044558Seric 				break;
1054558Seric 			}
1064549Seric 			p = skipword(p, "from");
1074549Seric 			if (p == NULL)
1084549Seric 				break;
1094549Seric 			if (index(p, ',') != NULL)
1104549Seric 			{
1114549Seric 				message("501", "Source routing not implemented");
1124549Seric 				Errors++;
1134549Seric 				break;
1144549Seric 			}
1154549Seric 			setsender(p);
1164577Seric 			if (Errors == 0)
1174549Seric 			{
1184549Seric 				message("250", "Sender ok");
1194549Seric 				hasmail = TRUE;
1204549Seric 			}
1214549Seric 			break;
1224549Seric 
1234549Seric 		  case CMDMRCP:		/* mrcp -- designate recipient */
1244549Seric 			p = skipword(p, "to");
1254549Seric 			if (p == NULL)
1264549Seric 				break;
1274549Seric 			if (index(p, ',') != NULL)
1284549Seric 			{
1294549Seric 				message("501", "Source routing not implemented");
1304549Seric 				Errors++;
1314549Seric 				break;
1324549Seric 			}
1334549Seric 			sendto(p, 1, NULL);
1344577Seric 			if (Errors == 0)
1354549Seric 			{
1364549Seric 				message("250", "Recipient ok");
1374549Seric 				hasmrcp = TRUE;
1384549Seric 			}
1394549Seric 			break;
1404549Seric 
1414549Seric 		  case CMDDATA:		/* data -- text of mail */
1424549Seric 			message("354", "Enter mail, end with dot");
1434549Seric 			collect();
1444577Seric 			if (Errors == 0)
1454549Seric 			{
1464549Seric 				message("250", "Message stored");
1474549Seric 				hasdata = TRUE;
1484549Seric 			}
1494549Seric 			break;
1504549Seric 
1514549Seric 		  case CMDDOIT:		/* doit -- actually send everything */
1524549Seric 			if (!hasmail)
1534549Seric 				message("503", "Need MAIL command");
1544549Seric 			else if (!hasmrcp)
1554549Seric 				message("503", "Need MRCP (recipient)");
1564549Seric 			else if (!hasdata)
1574549Seric 				message("503", "No message, use DATA");
1584549Seric 			else
1594549Seric 			{
1604549Seric 				sendall(FALSE);
1614577Seric 				if (Errors == 0)
1624549Seric 					message("250", "Sent");
1634549Seric 			}
1644549Seric 			break;
1654549Seric 
1664549Seric 		  case CMDRSET:		/* rset -- reset state */
1674549Seric 			message("250", "Reset state");
1684549Seric 			finis();
1694549Seric 
1704549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
1714549Seric 			sendto(p, 1, NULL);
1724577Seric 			if (Errors == 0)
1734549Seric 				message("250", "user ok");
1744549Seric 			break;
1754549Seric 
1764549Seric 		  case CMDHELP:		/* help -- give user info */
1774577Seric 			if (*p == '\0')
1784577Seric 				p = "SMTP";
1794577Seric 			help(p);
1804549Seric 			break;
1814549Seric 
1824549Seric 		  case CMDNOOP:		/* noop -- do nothing */
1834549Seric 			message("200", "OK");
1844549Seric 			break;
1854549Seric 
1864549Seric 		  case CMDQUIT:		/* quit -- leave mail */
1874549Seric 			message("221", "%s closing connection", HostName);
1884549Seric 			finis();
1894549Seric 
1904577Seric 		  case CMDMRSQ:		/* mrsq -- negotiate protocol */
1914577Seric 			if (*p == 'R' || *p == 'T')
1924577Seric 			{
1934577Seric 				/* recipients first or text first */
1944577Seric 				message("200", "%c ok, please continue", *p);
1954577Seric 			}
1964577Seric 			else if (*p == '?')
1974577Seric 			{
1984577Seric 				/* what do I prefer?  anything, anytime */
1994577Seric 				message("215", "R Recipients first is my choice");
2004577Seric 			}
2014577Seric 			else if (*p == '\0')
2024577Seric 			{
2034577Seric 				/* no meaningful scheme */
2044577Seric 				message("200", "okey dokie boobie");
2054577Seric 			}
2064577Seric 			else
2074577Seric 			{
2084577Seric 				/* bad argument */
2094577Seric 				message("504", "Scheme unknown");
2104577Seric 			}
2114577Seric 			break;
2124577Seric 
2134549Seric 		  case CMDERROR:	/* unknown command */
2144549Seric 			message("500", "Command unrecognized");
2154549Seric 			break;
2164549Seric 
2174549Seric 		  default:
2184549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
2194549Seric 			break;
2204549Seric 		}
2214549Seric 	}
2224549Seric }
2234549Seric /*
2244549Seric **  SKIPWORD -- skip a fixed word.
2254549Seric **
2264549Seric **	Parameters:
2274549Seric **		p -- place to start looking.
2284549Seric **		w -- word to skip.
2294549Seric **
2304549Seric **	Returns:
2314549Seric **		p following w.
2324549Seric **		NULL on error.
2334549Seric **
2344549Seric **	Side Effects:
2354549Seric **		clobbers the p data area.
2364549Seric */
2374549Seric 
2384549Seric static char *
2394549Seric skipword(p, w)
2404549Seric 	register char *p;
2414549Seric 	char *w;
2424549Seric {
2434549Seric 	register char *q;
2444549Seric 	extern bool sameword();
2454549Seric 
2464549Seric 	/* find beginning of word */
2474549Seric 	while (isspace(*p))
2484549Seric 		p++;
2494549Seric 	q = p;
2504549Seric 
2514549Seric 	/* find end of word */
2524549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
2534549Seric 		p++;
2544549Seric 	while (isspace(*p))
2554549Seric 		*p++ = '\0';
2564549Seric 	if (*p != ':')
2574549Seric 	{
2584549Seric 	  syntax:
2594549Seric 		message("501", "Syntax error");
2604549Seric 		Errors++;
2614549Seric 		return (NULL);
2624549Seric 	}
2634549Seric 	*p++ = '\0';
2644549Seric 	while (isspace(*p))
2654549Seric 		p++;
2664549Seric 
2674549Seric 	/* see if the input word matches desired word */
2684549Seric 	if (!sameword(q, w))
2694549Seric 		goto syntax;
2704549Seric 
2714549Seric 	return (p);
2724549Seric }
2734577Seric /*
2744577Seric **  HELP -- implement the HELP command.
2754577Seric **
2764577Seric **	Parameters:
2774577Seric **		topic -- the topic we want help for.
2784577Seric **
2794577Seric **	Returns:
2804577Seric **		none.
2814577Seric **
2824577Seric **	Side Effects:
2834577Seric **		outputs the help file to message output.
2844577Seric */
2854577Seric 
2864577Seric help(topic)
2874577Seric 	char *topic;
2884577Seric {
2894577Seric 	register FILE *hf;
2904577Seric 	int len;
2914577Seric 	char buf[MAXLINE];
2924577Seric 	bool noinfo;
293*4582Seric 	extern char *HelpFile;
2944577Seric 
295*4582Seric 	hf = fopen(HelpFile, "r");
2964577Seric 	if (hf == NULL)
2974577Seric 	{
2984577Seric 		/* no help */
2994577Seric 		message("502", "HELP not implemented");
3004577Seric 		return;
3014577Seric 	}
3024577Seric 
3034577Seric 	len = strlen(topic);
3044577Seric 	makelower(topic);
3054577Seric 	noinfo = TRUE;
3064577Seric 
3074577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
3084577Seric 	{
3094577Seric 		if (strncmp(buf, topic, len) == 0)
3104577Seric 		{
3114577Seric 			register char *p;
3124577Seric 
3134577Seric 			p = index(buf, '\t');
3144577Seric 			if (p == NULL)
3154577Seric 				p = buf;
3164577Seric 			else
3174577Seric 				p++;
3184577Seric 			fixcrlf(p, TRUE);
3194577Seric 			message("214-", p);
3204577Seric 			noinfo = FALSE;
3214577Seric 		}
3224577Seric 	}
3234577Seric 
3244577Seric 	if (noinfo)
3254577Seric 		message("504", "HELP topic unknown");
3264577Seric 	else
3274577Seric 		message("214", "End of HELP info");
3284577Seric 	fclose(hf);
3294577Seric }
330