14549Seric # include "sendmail.h"
24549Seric 
3*4976Seric static char	SccsId[] =	"@(#)srvrsmtp.c	3.8	11/21/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 */
28*4976Seric # define CMDRCPT	2	/* rcpt -- designate recipient */
294549Seric # define CMDDATA	3	/* data -- send message text */
304549Seric # define CMDRSET	5	/* rset -- reset state */
314549Seric # define CMDVRFY	6	/* vrfy -- verify address */
324549Seric # define CMDHELP	7	/* help -- give usage info */
334549Seric # define CMDNOOP	8	/* noop -- do nothing */
344549Seric # define CMDQUIT	9	/* quit -- close connection and die */
354577Seric # define CMDMRSQ	10	/* mrsq -- for old mtp compat only */
36*4976Seric # define CMDHELO	11	/* helo -- be polite */
374549Seric 
384549Seric static struct cmd	CmdTab[] =
394549Seric {
404549Seric 	"mail",		CMDMAIL,
41*4976Seric 	"rcpt",		CMDRCPT,
42*4976Seric 	"mrcp",		CMDRCPT,	/* for old MTP compatability */
434549Seric 	"data",		CMDDATA,
444549Seric 	"rset",		CMDRSET,
454549Seric 	"vrfy",		CMDVRFY,
464549Seric 	"help",		CMDHELP,
474549Seric 	"noop",		CMDNOOP,
484549Seric 	"quit",		CMDQUIT,
494577Seric 	"mrsq",		CMDMRSQ,
50*4976Seric 	"helo",		CMDHELO,
514549Seric 	NULL,		CMDERROR,
524549Seric };
534549Seric 
544549Seric smtp()
554549Seric {
564549Seric 	char inp[MAXLINE];
574549Seric 	register char *p;
584549Seric 	struct cmd *c;
594549Seric 	char *cmd;
604549Seric 	extern char *skipword();
614549Seric 	extern bool sameword();
624549Seric 	bool hasmail;			/* mail command received */
634713Seric 	int rcps;			/* number of recipients */
644549Seric 	bool hasdata;			/* has mail data */
654549Seric 
664713Seric 	hasmail = hasdata = FALSE;
674713Seric 	rcps = 0;
684549Seric 	message("220", "%s Sendmail at your service", HostName);
694549Seric 	for (;;)
704549Seric 	{
714549Seric 		To = NULL;
724577Seric 		Errors = 0;
734549Seric 		if (fgets(inp, sizeof inp, InChannel) == NULL)
744549Seric 		{
754549Seric 			/* end of file, just die */
764558Seric 			message("421", "%s Lost input channel", HostName);
774549Seric 			finis();
784549Seric 		}
794549Seric 
804549Seric 		/* clean up end of line */
814558Seric 		fixcrlf(inp, TRUE);
824549Seric 
834713Seric 		/* echo command to transcript */
844713Seric 		fprintf(Xscript, "*** %s\n", inp);
854713Seric 
864549Seric 		/* break off command */
874549Seric 		for (p = inp; isspace(*p); p++)
884549Seric 			continue;
894549Seric 		cmd = p;
904549Seric 		while (*++p != '\0' && !isspace(*p))
914549Seric 			continue;
924549Seric 		if (*p != '\0')
934549Seric 			*p++ = '\0';
944549Seric 
954549Seric 		/* decode command */
964549Seric 		for (c = CmdTab; c->cmdname != NULL; c++)
974549Seric 		{
984549Seric 			if (sameword(c->cmdname, cmd))
994549Seric 				break;
1004549Seric 		}
1014549Seric 
1024549Seric 		/* process command */
1034549Seric 		switch (c->cmdcode)
1044549Seric 		{
105*4976Seric 		  case CMDHELO:		/* hello -- introduce yourself */
106*4976Seric 			message("250", "%s Pleased to meet you", HostName);
107*4976Seric 			break;
108*4976Seric 
1094549Seric 		  case CMDMAIL:		/* mail -- designate sender */
1104558Seric 			if (hasmail)
1114558Seric 			{
1124558Seric 				message("503", "Sender already specified");
1134558Seric 				break;
1144558Seric 			}
1154549Seric 			p = skipword(p, "from");
1164549Seric 			if (p == NULL)
1174549Seric 				break;
1184549Seric 			if (index(p, ',') != NULL)
1194549Seric 			{
1204549Seric 				message("501", "Source routing not implemented");
1214549Seric 				Errors++;
1224549Seric 				break;
1234549Seric 			}
1244549Seric 			setsender(p);
1254577Seric 			if (Errors == 0)
1264549Seric 			{
1274549Seric 				message("250", "Sender ok");
1284549Seric 				hasmail = TRUE;
1294549Seric 			}
1304549Seric 			break;
1314549Seric 
132*4976Seric 		  case CMDRCPT:		/* rcpt -- designate recipient */
1334549Seric 			p = skipword(p, "to");
1344549Seric 			if (p == NULL)
1354549Seric 				break;
1364549Seric 			if (index(p, ',') != NULL)
1374549Seric 			{
1384549Seric 				message("501", "Source routing not implemented");
1394549Seric 				Errors++;
1404549Seric 				break;
1414549Seric 			}
1424628Seric 			sendto(p, 1, (ADDRESS *) NULL);
1434577Seric 			if (Errors == 0)
1444549Seric 			{
1454549Seric 				message("250", "Recipient ok");
1464713Seric 				rcps++;
1474549Seric 			}
1484549Seric 			break;
1494549Seric 
1504549Seric 		  case CMDDATA:		/* data -- text of mail */
151*4976Seric 			if (!hasmail)
1524549Seric 			{
153*4976Seric 				message("503", "Need MAIL command");
154*4976Seric 				break;
1554549Seric 			}
1564713Seric 			else if (rcps <= 0)
1574549Seric 			{
158*4976Seric 				message("503", "Need RCPT (recipient)");
159*4976Seric 				break;
1604549Seric 			}
161*4976Seric 
162*4976Seric 			/* collect the text of the message */
163*4976Seric 			collect(TRUE);
164*4976Seric 			if (Errors != 0)
165*4976Seric 				break;
166*4976Seric 
167*4976Seric 			/* if sending to multiple people, mail back errors */
168*4976Seric 			if (rcps != 1)
169*4976Seric 				HoldErrs = MailBack = TRUE;
170*4976Seric 
171*4976Seric 			/* send to all recipients */
172*4976Seric 			sendall(FALSE);
173*4976Seric 
174*4976Seric 			/* reset strange modes */
175*4976Seric 			HoldErrs = FALSE;
176*4976Seric 			To = NULL;
177*4976Seric 
178*4976Seric 			/* issue success if appropriate */
179*4976Seric 			if (Errors == 0 || rcps != 1)
180*4976Seric 				message("250", "Sent");
1814549Seric 			break;
1824549Seric 
1834549Seric 		  case CMDRSET:		/* rset -- reset state */
1844549Seric 			message("250", "Reset state");
1854549Seric 			finis();
1864549Seric 
1874549Seric 		  case CMDVRFY:		/* vrfy -- verify address */
1884628Seric 			sendto(p, 1, (ADDRESS *) NULL);
1894577Seric 			if (Errors == 0)
1904549Seric 				message("250", "user ok");
1914549Seric 			break;
1924549Seric 
1934549Seric 		  case CMDHELP:		/* help -- give user info */
1944577Seric 			if (*p == '\0')
1954577Seric 				p = "SMTP";
1964577Seric 			help(p);
1974549Seric 			break;
1984549Seric 
1994549Seric 		  case CMDNOOP:		/* noop -- do nothing */
2004549Seric 			message("200", "OK");
2014549Seric 			break;
2024549Seric 
2034549Seric 		  case CMDQUIT:		/* quit -- leave mail */
2044549Seric 			message("221", "%s closing connection", HostName);
2054549Seric 			finis();
2064549Seric 
2074577Seric 		  case CMDMRSQ:		/* mrsq -- negotiate protocol */
2084577Seric 			if (*p == 'R' || *p == 'T')
2094577Seric 			{
2104577Seric 				/* recipients first or text first */
2114577Seric 				message("200", "%c ok, please continue", *p);
2124577Seric 			}
2134577Seric 			else if (*p == '?')
2144577Seric 			{
2154577Seric 				/* what do I prefer?  anything, anytime */
2164577Seric 				message("215", "R Recipients first is my choice");
2174577Seric 			}
2184577Seric 			else if (*p == '\0')
2194577Seric 			{
2204577Seric 				/* no meaningful scheme */
2214577Seric 				message("200", "okey dokie boobie");
2224577Seric 			}
2234577Seric 			else
2244577Seric 			{
2254577Seric 				/* bad argument */
2264577Seric 				message("504", "Scheme unknown");
2274577Seric 			}
2284577Seric 			break;
2294577Seric 
2304549Seric 		  case CMDERROR:	/* unknown command */
2314549Seric 			message("500", "Command unrecognized");
2324549Seric 			break;
2334549Seric 
2344549Seric 		  default:
2354549Seric 			syserr("smtp: unknown code %d", c->cmdcode);
2364549Seric 			break;
2374549Seric 		}
2384549Seric 	}
2394549Seric }
2404549Seric /*
2414549Seric **  SKIPWORD -- skip a fixed word.
2424549Seric **
2434549Seric **	Parameters:
2444549Seric **		p -- place to start looking.
2454549Seric **		w -- word to skip.
2464549Seric **
2474549Seric **	Returns:
2484549Seric **		p following w.
2494549Seric **		NULL on error.
2504549Seric **
2514549Seric **	Side Effects:
2524549Seric **		clobbers the p data area.
2534549Seric */
2544549Seric 
2554549Seric static char *
2564549Seric skipword(p, w)
2574549Seric 	register char *p;
2584549Seric 	char *w;
2594549Seric {
2604549Seric 	register char *q;
2614549Seric 	extern bool sameword();
2624549Seric 
2634549Seric 	/* find beginning of word */
2644549Seric 	while (isspace(*p))
2654549Seric 		p++;
2664549Seric 	q = p;
2674549Seric 
2684549Seric 	/* find end of word */
2694549Seric 	while (*p != '\0' && *p != ':' && !isspace(*p))
2704549Seric 		p++;
2714549Seric 	while (isspace(*p))
2724549Seric 		*p++ = '\0';
2734549Seric 	if (*p != ':')
2744549Seric 	{
2754549Seric 	  syntax:
2764549Seric 		message("501", "Syntax error");
2774549Seric 		Errors++;
2784549Seric 		return (NULL);
2794549Seric 	}
2804549Seric 	*p++ = '\0';
2814549Seric 	while (isspace(*p))
2824549Seric 		p++;
2834549Seric 
2844549Seric 	/* see if the input word matches desired word */
2854549Seric 	if (!sameword(q, w))
2864549Seric 		goto syntax;
2874549Seric 
2884549Seric 	return (p);
2894549Seric }
2904577Seric /*
2914577Seric **  HELP -- implement the HELP command.
2924577Seric **
2934577Seric **	Parameters:
2944577Seric **		topic -- the topic we want help for.
2954577Seric **
2964577Seric **	Returns:
2974577Seric **		none.
2984577Seric **
2994577Seric **	Side Effects:
3004577Seric **		outputs the help file to message output.
3014577Seric */
3024577Seric 
3034577Seric help(topic)
3044577Seric 	char *topic;
3054577Seric {
3064577Seric 	register FILE *hf;
3074577Seric 	int len;
3084577Seric 	char buf[MAXLINE];
3094577Seric 	bool noinfo;
3104582Seric 	extern char *HelpFile;
3114577Seric 
3124582Seric 	hf = fopen(HelpFile, "r");
3134577Seric 	if (hf == NULL)
3144577Seric 	{
3154577Seric 		/* no help */
3164577Seric 		message("502", "HELP not implemented");
3174577Seric 		return;
3184577Seric 	}
3194577Seric 
3204577Seric 	len = strlen(topic);
3214577Seric 	makelower(topic);
3224577Seric 	noinfo = TRUE;
3234577Seric 
3244577Seric 	while (fgets(buf, sizeof buf, hf) != NULL)
3254577Seric 	{
3264577Seric 		if (strncmp(buf, topic, len) == 0)
3274577Seric 		{
3284577Seric 			register char *p;
3294577Seric 
3304577Seric 			p = index(buf, '\t');
3314577Seric 			if (p == NULL)
3324577Seric 				p = buf;
3334577Seric 			else
3344577Seric 				p++;
3354577Seric 			fixcrlf(p, TRUE);
3364577Seric 			message("214-", p);
3374577Seric 			noinfo = FALSE;
3384577Seric 		}
3394577Seric 	}
3404577Seric 
3414577Seric 	if (noinfo)
3424577Seric 		message("504", "HELP topic unknown");
3434577Seric 	else
3444577Seric 		message("214", "End of HELP info");
3454628Seric 	(void) fclose(hf);
3464577Seric }
347