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