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