1 # include "sendmail.h"
2 
3 static char	SccsId[] =	"@(#)srvrsmtp.c	3.6	10/26/81";
4 
5 /*
6 **  SMTP -- run the SMTP protocol.
7 **
8 **	Parameters:
9 **		none.
10 **
11 **	Returns:
12 **		never.
13 **
14 **	Side Effects:
15 **		Reads commands from the input channel and processes
16 **			them.
17 */
18 
19 struct cmd
20 {
21 	char	*cmdname;	/* command name */
22 	int	cmdcode;	/* internal code, see below */
23 };
24 
25 /* values for cmdcode */
26 # define CMDERROR	0	/* bad command */
27 # define CMDMAIL	1	/* mail -- designate sender */
28 # define CMDMRCP	2	/* mrcp -- designate recipient */
29 # define CMDDATA	3	/* data -- send message text */
30 # define CMDDOIT	4	/* doit -- actually do delivery */
31 # define CMDRSET	5	/* rset -- reset state */
32 # define CMDVRFY	6	/* vrfy -- verify address */
33 # define CMDHELP	7	/* help -- give usage info */
34 # define CMDNOOP	8	/* noop -- do nothing */
35 # define CMDQUIT	9	/* quit -- close connection and die */
36 # define CMDMRSQ	10	/* mrsq -- for old mtp compat only */
37 
38 static struct cmd	CmdTab[] =
39 {
40 	"mail",		CMDMAIL,
41 	"mrcp",		CMDMRCP,
42 	"data",		CMDDATA,
43 	"doit",		CMDDOIT,
44 	"rset",		CMDRSET,
45 	"vrfy",		CMDVRFY,
46 	"help",		CMDHELP,
47 	"noop",		CMDNOOP,
48 	"quit",		CMDQUIT,
49 	"mrsq",		CMDMRSQ,
50 	NULL,		CMDERROR,
51 };
52 
53 smtp()
54 {
55 	char inp[MAXLINE];
56 	register char *p;
57 	struct cmd *c;
58 	char *cmd;
59 	extern char *skipword();
60 	extern bool sameword();
61 	bool hasmail;			/* mail command received */
62 	bool hasmrcp;			/* has a recipient */
63 	bool hasdata;			/* has mail data */
64 
65 	hasmail = hasmrcp = hasdata = FALSE;
66 	message("220", "%s Sendmail at your service", HostName);
67 	for (;;)
68 	{
69 		To = NULL;
70 		Errors = 0;
71 		if (fgets(inp, sizeof inp, InChannel) == NULL)
72 		{
73 			/* end of file, just die */
74 			message("421", "%s Lost input channel", HostName);
75 			finis();
76 		}
77 
78 		/* clean up end of line */
79 		fixcrlf(inp, TRUE);
80 
81 		/* break off command */
82 		for (p = inp; isspace(*p); p++)
83 			continue;
84 		cmd = p;
85 		while (*++p != '\0' && !isspace(*p))
86 			continue;
87 		if (*p != '\0')
88 			*p++ = '\0';
89 
90 		/* decode command */
91 		for (c = CmdTab; c->cmdname != NULL; c++)
92 		{
93 			if (sameword(c->cmdname, cmd))
94 				break;
95 		}
96 
97 		/* process command */
98 		switch (c->cmdcode)
99 		{
100 		  case CMDMAIL:		/* mail -- designate sender */
101 			if (hasmail)
102 			{
103 				message("503", "Sender already specified");
104 				break;
105 			}
106 			p = skipword(p, "from");
107 			if (p == NULL)
108 				break;
109 			if (index(p, ',') != NULL)
110 			{
111 				message("501", "Source routing not implemented");
112 				Errors++;
113 				break;
114 			}
115 			setsender(p);
116 			if (Errors == 0)
117 			{
118 				message("250", "Sender ok");
119 				hasmail = TRUE;
120 			}
121 			break;
122 
123 		  case CMDMRCP:		/* mrcp -- designate recipient */
124 			p = skipword(p, "to");
125 			if (p == NULL)
126 				break;
127 			if (index(p, ',') != NULL)
128 			{
129 				message("501", "Source routing not implemented");
130 				Errors++;
131 				break;
132 			}
133 			sendto(p, 1, (ADDRESS *) NULL);
134 			if (Errors == 0)
135 			{
136 				message("250", "Recipient ok");
137 				hasmrcp = TRUE;
138 			}
139 			break;
140 
141 		  case CMDDATA:		/* data -- text of mail */
142 			message("354", "Enter mail, end with dot");
143 			collect();
144 			if (Errors == 0)
145 			{
146 				message("250", "Message stored");
147 				hasdata = TRUE;
148 			}
149 			break;
150 
151 		  case CMDDOIT:		/* doit -- actually send everything */
152 			if (!hasmail)
153 				message("503", "Need MAIL command");
154 			else if (!hasmrcp)
155 				message("503", "Need MRCP (recipient)");
156 			else if (!hasdata)
157 				message("503", "No message, use DATA");
158 			else
159 			{
160 				sendall(FALSE);
161 				if (Errors == 0)
162 					message("250", "Sent");
163 			}
164 			break;
165 
166 		  case CMDRSET:		/* rset -- reset state */
167 			message("250", "Reset state");
168 			finis();
169 
170 		  case CMDVRFY:		/* vrfy -- verify address */
171 			sendto(p, 1, (ADDRESS *) NULL);
172 			if (Errors == 0)
173 				message("250", "user ok");
174 			break;
175 
176 		  case CMDHELP:		/* help -- give user info */
177 			if (*p == '\0')
178 				p = "SMTP";
179 			help(p);
180 			break;
181 
182 		  case CMDNOOP:		/* noop -- do nothing */
183 			message("200", "OK");
184 			break;
185 
186 		  case CMDQUIT:		/* quit -- leave mail */
187 			message("221", "%s closing connection", HostName);
188 			finis();
189 
190 		  case CMDMRSQ:		/* mrsq -- negotiate protocol */
191 			if (*p == 'R' || *p == 'T')
192 			{
193 				/* recipients first or text first */
194 				message("200", "%c ok, please continue", *p);
195 			}
196 			else if (*p == '?')
197 			{
198 				/* what do I prefer?  anything, anytime */
199 				message("215", "R Recipients first is my choice");
200 			}
201 			else if (*p == '\0')
202 			{
203 				/* no meaningful scheme */
204 				message("200", "okey dokie boobie");
205 			}
206 			else
207 			{
208 				/* bad argument */
209 				message("504", "Scheme unknown");
210 			}
211 			break;
212 
213 		  case CMDERROR:	/* unknown command */
214 			message("500", "Command unrecognized");
215 			break;
216 
217 		  default:
218 			syserr("smtp: unknown code %d", c->cmdcode);
219 			break;
220 		}
221 	}
222 }
223 /*
224 **  SKIPWORD -- skip a fixed word.
225 **
226 **	Parameters:
227 **		p -- place to start looking.
228 **		w -- word to skip.
229 **
230 **	Returns:
231 **		p following w.
232 **		NULL on error.
233 **
234 **	Side Effects:
235 **		clobbers the p data area.
236 */
237 
238 static char *
239 skipword(p, w)
240 	register char *p;
241 	char *w;
242 {
243 	register char *q;
244 	extern bool sameword();
245 
246 	/* find beginning of word */
247 	while (isspace(*p))
248 		p++;
249 	q = p;
250 
251 	/* find end of word */
252 	while (*p != '\0' && *p != ':' && !isspace(*p))
253 		p++;
254 	while (isspace(*p))
255 		*p++ = '\0';
256 	if (*p != ':')
257 	{
258 	  syntax:
259 		message("501", "Syntax error");
260 		Errors++;
261 		return (NULL);
262 	}
263 	*p++ = '\0';
264 	while (isspace(*p))
265 		p++;
266 
267 	/* see if the input word matches desired word */
268 	if (!sameword(q, w))
269 		goto syntax;
270 
271 	return (p);
272 }
273 /*
274 **  HELP -- implement the HELP command.
275 **
276 **	Parameters:
277 **		topic -- the topic we want help for.
278 **
279 **	Returns:
280 **		none.
281 **
282 **	Side Effects:
283 **		outputs the help file to message output.
284 */
285 
286 help(topic)
287 	char *topic;
288 {
289 	register FILE *hf;
290 	int len;
291 	char buf[MAXLINE];
292 	bool noinfo;
293 	extern char *HelpFile;
294 
295 	hf = fopen(HelpFile, "r");
296 	if (hf == NULL)
297 	{
298 		/* no help */
299 		message("502", "HELP not implemented");
300 		return;
301 	}
302 
303 	len = strlen(topic);
304 	makelower(topic);
305 	noinfo = TRUE;
306 
307 	while (fgets(buf, sizeof buf, hf) != NULL)
308 	{
309 		if (strncmp(buf, topic, len) == 0)
310 		{
311 			register char *p;
312 
313 			p = index(buf, '\t');
314 			if (p == NULL)
315 				p = buf;
316 			else
317 				p++;
318 			fixcrlf(p, TRUE);
319 			message("214-", p);
320 			noinfo = FALSE;
321 		}
322 	}
323 
324 	if (noinfo)
325 		message("504", "HELP topic unknown");
326 	else
327 		message("214", "End of HELP info");
328 	(void) fclose(hf);
329 }
330