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