1 # include "sendmail.h"
2 
3 static char	SccsId[] =	"@(#)srvrsmtp.c	3.2	10/20/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 
37 static struct cmd	CmdTab[] =
38 {
39 	"mail",		CMDMAIL,
40 	"mrcp",		CMDMRCP,
41 	"data",		CMDDATA,
42 	"doit",		CMDDOIT,
43 	"rset",		CMDRSET,
44 	"vrfy",		CMDVRFY,
45 	"help",		CMDHELP,
46 	"noop",		CMDNOOP,
47 	"quit",		CMDQUIT,
48 	NULL,		CMDERROR,
49 };
50 
51 smtp()
52 {
53 	char inp[MAXLINE];
54 	register char *p;
55 	struct cmd *c;
56 	char *cmd;
57 	extern char *skipword();
58 	extern bool sameword();
59 	bool hasmail;			/* mail command received */
60 	bool hasmrcp;			/* has a recipient */
61 	bool hasdata;			/* has mail data */
62 
63 	/*%%%*/	HostName = "XYZZY";
64 	hasmail = hasmrcp = hasdata = FALSE;
65 	message("220", "%s Sendmail at your service", HostName);
66 	for (;;)
67 	{
68 		To = NULL;
69 		Errors = 0;
70 		if (fgets(inp, sizeof inp, InChannel) == NULL)
71 		{
72 			/* end of file, just die */
73 			message("421", "Lost input channel");
74 			finis();
75 		}
76 
77 		/* clean up end of line */
78 		p = index(inp, '\n');
79 		if (p != NULL)
80 			*p = '\0';
81 		p = index(inp, '\r');
82 		if (p != NULL)
83 			*p = '\0';
84 
85 		/* break off command */
86 		for (p = inp; isspace(*p); p++)
87 			continue;
88 		cmd = p;
89 		while (*++p != '\0' && !isspace(*p))
90 			continue;
91 		if (*p != '\0')
92 			*p++ = '\0';
93 
94 		/* decode command */
95 		for (c = CmdTab; c->cmdname != NULL; c++)
96 		{
97 			if (sameword(c->cmdname, cmd))
98 				break;
99 		}
100 
101 		/* process command */
102 		switch (c->cmdcode)
103 		{
104 		  case CMDMAIL:		/* mail -- designate sender */
105 			p = skipword(p, "from");
106 			if (p == NULL)
107 				break;
108 			if (index(p, ',') != NULL)
109 			{
110 				message("501", "Source routing not implemented");
111 				Errors++;
112 				break;
113 			}
114 			setsender(p);
115 			if (Errors == 0)
116 			{
117 				message("250", "Sender ok");
118 				hasmail = TRUE;
119 			}
120 			break;
121 
122 		  case CMDMRCP:		/* mrcp -- designate recipient */
123 			p = skipword(p, "to");
124 			if (p == NULL)
125 				break;
126 			if (index(p, ',') != NULL)
127 			{
128 				message("501", "Source routing not implemented");
129 				Errors++;
130 				break;
131 			}
132 			sendto(p, 1, NULL);
133 			if (Errors == 0)
134 			{
135 				message("250", "Recipient ok");
136 				hasmrcp = TRUE;
137 			}
138 			break;
139 
140 		  case CMDDATA:		/* data -- text of mail */
141 			message("354", "Enter mail, end with dot");
142 			collect();
143 			if (Errors == 0)
144 			{
145 				message("250", "Message stored");
146 				hasdata = TRUE;
147 			}
148 			break;
149 
150 		  case CMDDOIT:		/* doit -- actually send everything */
151 			if (!hasmail)
152 				message("503", "Need MAIL command");
153 			else if (!hasmrcp)
154 				message("503", "Need MRCP (recipient)");
155 			else if (!hasdata)
156 				message("503", "No message, use DATA");
157 			else
158 			{
159 				sendall(FALSE);
160 				if (Errors == 0)
161 					message("250", "Sent");
162 			}
163 			break;
164 
165 		  case CMDRSET:		/* rset -- reset state */
166 			message("250", "Reset state");
167 			finis();
168 
169 		  case CMDVRFY:		/* vrfy -- verify address */
170 			sendto(p, 1, NULL);
171 			if (Errors == 0)
172 				message("250", "user ok");
173 			break;
174 
175 		  case CMDHELP:		/* help -- give user info */
176 			message("502", "HELP not implemented");
177 			break;
178 
179 		  case CMDNOOP:		/* noop -- do nothing */
180 			message("200", "OK");
181 			break;
182 
183 		  case CMDQUIT:		/* quit -- leave mail */
184 			message("221", "%s closing connection", HostName);
185 			finis();
186 
187 		  case CMDERROR:	/* unknown command */
188 			message("500", "Command unrecognized");
189 			break;
190 
191 		  default:
192 			syserr("smtp: unknown code %d", c->cmdcode);
193 			break;
194 		}
195 	}
196 }
197 /*
198 **  SKIPWORD -- skip a fixed word.
199 **
200 **	Parameters:
201 **		p -- place to start looking.
202 **		w -- word to skip.
203 **
204 **	Returns:
205 **		p following w.
206 **		NULL on error.
207 **
208 **	Side Effects:
209 **		clobbers the p data area.
210 */
211 
212 static char *
213 skipword(p, w)
214 	register char *p;
215 	char *w;
216 {
217 	register char *q;
218 	extern bool sameword();
219 
220 	/* find beginning of word */
221 	while (isspace(*p))
222 		p++;
223 	q = p;
224 
225 	/* find end of word */
226 	while (*p != '\0' && *p != ':' && !isspace(*p))
227 		p++;
228 	while (isspace(*p))
229 		*p++ = '\0';
230 	if (*p != ':')
231 	{
232 	  syntax:
233 		message("501", "Syntax error");
234 		Errors++;
235 		return (NULL);
236 	}
237 	*p++ = '\0';
238 	while (isspace(*p))
239 		p++;
240 
241 	/* see if the input word matches desired word */
242 	if (!sameword(q, w))
243 		goto syntax;
244 
245 	return (p);
246 }
247