Mercurial > hg > nginx-quic
annotate src/mail/ngx_mail_parse.c @ 1312:13e649b813d6 release-0.6.4
nginx-0.6.4-RELEASE
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 17 Jul 2007 09:57:37 +0000 |
parents | 68f30ab68bb7 |
children | 27f2299e0d80 |
rev | line source |
---|---|
441
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
1 |
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
2 /* |
444
42d11f017717
nginx-0.1.0-2004-09-29-20:00:49 import; remove years from copyright
Igor Sysoev <igor@sysoev.ru>
parents:
441
diff
changeset
|
3 * Copyright (C) Igor Sysoev |
441
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
4 */ |
da8c5707af39
nginx-0.1.0-2004-09-28-12:34:51 import; set copyright and remove unused files
Igor Sysoev <igor@sysoev.ru>
parents:
422
diff
changeset
|
5 |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
6 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
7 #include <ngx_config.h> |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
8 #include <ngx_core.h> |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
9 #include <ngx_event.h> |
1136 | 10 #include <ngx_mail.h> |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
11 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
12 |
1136 | 13 ngx_int_t ngx_pop3_parse_command(ngx_mail_session_t *s) |
14 { | |
15 u_char ch, *p, *c, c0, c1, c2, c3; | |
16 ngx_str_t *arg; | |
17 enum { | |
18 sw_start = 0, | |
19 sw_spaces_before_argument, | |
20 sw_argument, | |
21 sw_almost_done | |
22 } state; | |
23 | |
24 state = s->state; | |
25 | |
26 for (p = s->buffer->pos; p < s->buffer->last; p++) { | |
27 ch = *p; | |
28 | |
29 switch (state) { | |
30 | |
31 /* POP3 command */ | |
32 case sw_start: | |
33 if (ch == ' ' || ch == CR || ch == LF) { | |
34 c = s->buffer->start; | |
35 | |
36 if (p - c == 4) { | |
37 | |
38 c0 = ngx_toupper(c[0]); | |
39 c1 = ngx_toupper(c[1]); | |
40 c2 = ngx_toupper(c[2]); | |
41 c3 = ngx_toupper(c[3]); | |
42 | |
43 if (c0 == 'U' && c1 == 'S' && c2 == 'E' && c3 == 'R') | |
44 { | |
45 s->command = NGX_POP3_USER; | |
46 | |
47 } else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S') | |
48 { | |
49 s->command = NGX_POP3_PASS; | |
50 | |
51 } else if (c0 == 'A' && c1 == 'P' && c2 == 'O' && c3 == 'P') | |
52 { | |
53 s->command = NGX_POP3_APOP; | |
54 | |
55 } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') | |
56 { | |
57 s->command = NGX_POP3_QUIT; | |
58 | |
59 } else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A') | |
60 { | |
61 s->command = NGX_POP3_CAPA; | |
62 | |
63 } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') | |
64 { | |
65 s->command = NGX_POP3_AUTH; | |
66 | |
67 } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') | |
68 { | |
69 s->command = NGX_POP3_NOOP; | |
70 #if (NGX_MAIL_SSL) | |
71 } else if (c0 == 'S' && c1 == 'T' && c2 == 'L' && c3 == 'S') | |
72 { | |
73 s->command = NGX_POP3_STLS; | |
74 #endif | |
75 } else { | |
76 goto invalid; | |
77 } | |
78 | |
79 } else { | |
80 goto invalid; | |
81 } | |
82 | |
83 switch (ch) { | |
84 case ' ': | |
85 state = sw_spaces_before_argument; | |
86 break; | |
87 case CR: | |
88 state = sw_almost_done; | |
89 break; | |
90 case LF: | |
91 goto done; | |
92 } | |
93 break; | |
94 } | |
95 | |
96 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { | |
97 goto invalid; | |
98 } | |
99 | |
100 break; | |
101 | |
102 case sw_spaces_before_argument: | |
103 switch (ch) { | |
104 case ' ': | |
105 break; | |
106 case CR: | |
107 state = sw_almost_done; | |
108 s->arg_end = p; | |
109 break; | |
110 case LF: | |
111 s->arg_end = p; | |
112 goto done; | |
113 default: | |
114 if (s->args.nelts <= 2) { | |
115 state = sw_argument; | |
116 s->arg_start = p; | |
117 break; | |
118 } | |
119 goto invalid; | |
120 } | |
121 break; | |
122 | |
123 case sw_argument: | |
124 switch (ch) { | |
125 | |
126 case ' ': | |
127 | |
128 /* | |
129 * the space should be considered as part of the at username | |
130 * or password, but not of argument in other commands | |
131 */ | |
132 | |
133 if (s->command == NGX_POP3_USER | |
134 || s->command == NGX_POP3_PASS) | |
135 { | |
136 break; | |
137 } | |
138 | |
139 /* fall through */ | |
140 | |
141 case CR: | |
142 case LF: | |
143 arg = ngx_array_push(&s->args); | |
144 if (arg == NULL) { | |
145 return NGX_ERROR; | |
146 } | |
147 arg->len = p - s->arg_start; | |
148 arg->data = s->arg_start; | |
149 s->arg_start = NULL; | |
150 | |
151 switch (ch) { | |
152 case ' ': | |
153 state = sw_spaces_before_argument; | |
154 break; | |
155 case CR: | |
156 state = sw_almost_done; | |
157 break; | |
158 case LF: | |
159 goto done; | |
160 } | |
161 break; | |
162 | |
163 default: | |
164 break; | |
165 } | |
166 break; | |
167 | |
168 case sw_almost_done: | |
169 switch (ch) { | |
170 case LF: | |
171 goto done; | |
172 default: | |
173 goto invalid; | |
174 } | |
175 } | |
176 } | |
177 | |
178 s->buffer->pos = p; | |
179 s->state = state; | |
180 | |
181 return NGX_AGAIN; | |
182 | |
183 done: | |
184 | |
185 s->buffer->pos = p + 1; | |
186 | |
187 if (s->arg_start) { | |
188 arg = ngx_array_push(&s->args); | |
189 if (arg == NULL) { | |
190 return NGX_ERROR; | |
191 } | |
192 arg->len = s->arg_end - s->arg_start; | |
193 arg->data = s->arg_start; | |
194 s->arg_start = NULL; | |
195 } | |
196 | |
197 s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument; | |
198 | |
199 return NGX_OK; | |
200 | |
201 invalid: | |
202 | |
203 s->state = sw_start; | |
204 s->arg_start = NULL; | |
205 | |
206 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
207 } | |
208 | |
209 | |
210 ngx_int_t ngx_imap_parse_command(ngx_mail_session_t *s) | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
211 { |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
212 u_char ch, *p, *c; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
213 ngx_str_t *arg; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
214 enum { |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
215 sw_start = 0, |
527 | 216 sw_spaces_before_command, |
217 sw_command, | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
218 sw_spaces_before_argument, |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
219 sw_argument, |
543 | 220 sw_backslash, |
527 | 221 sw_literal, |
543 | 222 sw_no_sync_literal_argument, |
527 | 223 sw_start_literal_argument, |
224 sw_literal_argument, | |
225 sw_end_literal_argument, | |
226 sw_almost_done | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
227 } state; |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
228 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
229 state = s->state; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
230 |
527 | 231 for (p = s->buffer->pos; p < s->buffer->last; p++) { |
232 ch = *p; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
233 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
234 switch (state) { |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
235 |
527 | 236 /* IMAP tag */ |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
237 case sw_start: |
527 | 238 switch (ch) { |
239 case ' ': | |
240 s->tag.len = p - s->buffer->start + 1; | |
241 s->tag.data = s->buffer->start; | |
242 state = sw_spaces_before_command; | |
243 break; | |
244 case CR: | |
245 s->state = sw_start; | |
1136 | 246 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 247 case LF: |
248 s->state = sw_start; | |
1136 | 249 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 250 } |
251 break; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
252 |
527 | 253 case sw_spaces_before_command: |
254 switch (ch) { | |
255 case ' ': | |
256 break; | |
257 case CR: | |
258 s->state = sw_start; | |
1136 | 259 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 260 case LF: |
261 s->state = sw_start; | |
1136 | 262 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 263 default: |
264 s->cmd_start = p; | |
265 state = sw_command; | |
266 break; | |
267 } | |
268 break; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
269 |
527 | 270 case sw_command: |
271 if (ch == ' ' || ch == CR || ch == LF) { | |
272 | |
273 c = s->cmd_start; | |
274 | |
275 switch (p - c) { | |
276 | |
277 case 4: | |
278 if ((c[0] == 'N' || c[0] == 'n') | |
279 && (c[1] == 'O'|| c[1] == 'o') | |
280 && (c[2] == 'O'|| c[2] == 'o') | |
281 && (c[3] == 'P'|| c[3] == 'p')) | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
282 { |
527 | 283 s->command = NGX_IMAP_NOOP; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
284 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
285 } else { |
527 | 286 goto invalid; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
287 } |
527 | 288 break; |
289 | |
290 case 5: | |
291 if ((c[0] == 'L'|| c[0] == 'l') | |
292 && (c[1] == 'O'|| c[1] == 'o') | |
293 && (c[2] == 'G'|| c[2] == 'g') | |
294 && (c[3] == 'I'|| c[3] == 'i') | |
295 && (c[4] == 'N'|| c[4] == 'n')) | |
296 { | |
297 s->command = NGX_IMAP_LOGIN; | |
298 | |
299 } else { | |
300 goto invalid; | |
301 } | |
302 break; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
303 |
527 | 304 case 6: |
305 if ((c[0] == 'L'|| c[0] == 'l') | |
306 && (c[1] == 'O'|| c[1] == 'o') | |
307 && (c[2] == 'G'|| c[2] == 'g') | |
308 && (c[3] == 'O'|| c[3] == 'o') | |
309 && (c[4] == 'U'|| c[4] == 'u') | |
310 && (c[5] == 'T'|| c[5] == 't')) | |
311 { | |
312 s->command = NGX_IMAP_LOGOUT; | |
313 | |
314 } else { | |
315 goto invalid; | |
316 } | |
317 break; | |
318 | |
1136 | 319 #if (NGX_MAIL_SSL) |
583 | 320 case 8: |
321 if ((c[0] == 'S'|| c[0] == 's') | |
322 && (c[1] == 'T'|| c[1] == 't') | |
323 && (c[2] == 'A'|| c[2] == 'a') | |
324 && (c[3] == 'R'|| c[3] == 'r') | |
325 && (c[4] == 'T'|| c[4] == 't') | |
326 && (c[5] == 'T'|| c[5] == 't') | |
327 && (c[6] == 'L'|| c[6] == 'l') | |
328 && (c[7] == 'S'|| c[7] == 's')) | |
329 { | |
330 s->command = NGX_IMAP_STARTTLS; | |
331 | |
332 } else { | |
333 goto invalid; | |
334 } | |
335 break; | |
336 #endif | |
337 | |
527 | 338 case 10: |
339 if ((c[0] == 'C'|| c[0] == 'c') | |
340 && (c[1] == 'A'|| c[1] == 'a') | |
341 && (c[2] == 'P'|| c[2] == 'p') | |
342 && (c[3] == 'A'|| c[3] == 'a') | |
343 && (c[4] == 'B'|| c[4] == 'b') | |
344 && (c[5] == 'I'|| c[5] == 'i') | |
345 && (c[6] == 'L'|| c[6] == 'l') | |
346 && (c[7] == 'I'|| c[7] == 'i') | |
347 && (c[8] == 'T'|| c[8] == 't') | |
348 && (c[9] == 'Y'|| c[9] == 'y')) | |
349 { | |
350 s->command = NGX_IMAP_CAPABILITY; | |
351 | |
352 } else { | |
353 goto invalid; | |
354 } | |
355 break; | |
356 | |
357 default: | |
358 goto invalid; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
359 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
360 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
361 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
362 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
363 state = sw_spaces_before_argument; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
364 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
365 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
366 state = sw_almost_done; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
367 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
368 case LF: |
527 | 369 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
370 } |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
371 break; |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
372 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
373 |
527 | 374 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { |
375 goto invalid; | |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
376 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
377 |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
378 break; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
379 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
380 case sw_spaces_before_argument: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
381 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
382 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
383 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
384 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
385 state = sw_almost_done; |
527 | 386 s->arg_end = p; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
387 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
388 case LF: |
527 | 389 s->arg_end = p; |
390 goto done; | |
391 case '"': | |
392 if (s->args.nelts <= 2) { | |
393 s->quoted = 1; | |
394 s->arg_start = p + 1; | |
395 state = sw_argument; | |
396 break; | |
397 } | |
398 goto invalid; | |
399 case '{': | |
400 if (s->args.nelts <= 2) { | |
401 state = sw_literal; | |
402 break; | |
403 } | |
404 goto invalid; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
405 default: |
527 | 406 if (s->args.nelts <= 2) { |
407 s->arg_start = p; | |
408 state = sw_argument; | |
409 break; | |
410 } | |
411 goto invalid; | |
412 } | |
413 break; | |
414 | |
415 case sw_argument: | |
416 switch (ch) { | |
417 case '"': | |
418 if (!s->quoted) { | |
419 break; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
420 } |
527 | 421 s->quoted = 0; |
422 /* fall through */ | |
423 case ' ': | |
424 case CR: | |
425 case LF: | |
426 arg = ngx_array_push(&s->args); | |
427 if (arg == NULL) { | |
428 return NGX_ERROR; | |
429 } | |
430 arg->len = p - s->arg_start; | |
431 arg->data = s->arg_start; | |
432 s->arg_start = NULL; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
433 |
527 | 434 switch (ch) { |
435 case '"': | |
436 case ' ': | |
437 state = sw_spaces_before_argument; | |
438 break; | |
439 case CR: | |
440 state = sw_almost_done; | |
441 break; | |
442 case LF: | |
443 goto done; | |
444 } | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
445 break; |
543 | 446 case '\\': |
447 if (s->quoted) { | |
448 s->backslash = 1; | |
449 state = sw_backslash; | |
450 } | |
451 break; | |
452 } | |
453 break; | |
454 | |
455 case sw_backslash: | |
456 switch (ch) { | |
457 case CR: | |
458 case LF: | |
459 goto invalid; | |
460 default: | |
461 state = sw_argument; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
462 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
463 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
464 |
527 | 465 case sw_literal: |
466 if (ch >= '0' && ch <= '9') { | |
467 s->literal_len = s->literal_len * 10 + (ch - '0'); | |
468 break; | |
469 } | |
470 if (ch == '}') { | |
471 state = sw_start_literal_argument; | |
472 break; | |
473 } | |
543 | 474 if (ch == '+') { |
475 state = sw_no_sync_literal_argument; | |
476 break; | |
477 } | |
478 goto invalid; | |
479 | |
480 case sw_no_sync_literal_argument: | |
481 if (ch == '}') { | |
482 s->no_sync_literal = 1; | |
483 state = sw_start_literal_argument; | |
484 break; | |
485 } | |
527 | 486 goto invalid; |
487 | |
488 case sw_start_literal_argument: | |
489 switch (ch) { | |
490 case CR: | |
491 break; | |
492 case LF: | |
493 s->buffer->pos = p + 1; | |
494 s->arg_start = p + 1; | |
543 | 495 if (s->no_sync_literal == 0) { |
496 s->state = sw_literal_argument; | |
497 return NGX_IMAP_NEXT; | |
498 } | |
499 state = sw_literal_argument; | |
500 s->no_sync_literal = 0; | |
501 break; | |
502 default: | |
503 goto invalid; | |
527 | 504 } |
543 | 505 break; |
527 | 506 |
507 case sw_literal_argument: | |
529 | 508 if (s->literal_len && --s->literal_len) { |
527 | 509 break; |
510 } | |
511 | |
512 arg = ngx_array_push(&s->args); | |
513 if (arg == NULL) { | |
514 return NGX_ERROR; | |
515 } | |
516 arg->len = p + 1 - s->arg_start; | |
517 arg->data = s->arg_start; | |
518 s->arg_start = NULL; | |
519 state = sw_end_literal_argument; | |
520 | |
521 break; | |
522 | |
523 case sw_end_literal_argument: | |
524 switch (ch) { | |
525 case '{': | |
526 if (s->args.nelts <= 2) { | |
527 state = sw_literal; | |
528 break; | |
529 } | |
530 goto invalid; | |
531 case CR: | |
532 state = sw_almost_done; | |
533 break; | |
534 case LF: | |
535 goto done; | |
536 default: | |
529 | 537 state = sw_spaces_before_argument; |
538 break; | |
527 | 539 } |
540 break; | |
541 | |
542 case sw_almost_done: | |
543 switch (ch) { | |
544 case LF: | |
545 goto done; | |
546 default: | |
547 goto invalid; | |
548 } | |
549 } | |
550 } | |
551 | |
552 s->buffer->pos = p; | |
553 s->state = state; | |
554 | |
555 return NGX_AGAIN; | |
556 | |
557 done: | |
558 | |
559 s->buffer->pos = p + 1; | |
560 | |
561 if (s->arg_start) { | |
562 arg = ngx_array_push(&s->args); | |
563 if (arg == NULL) { | |
564 return NGX_ERROR; | |
565 } | |
566 arg->len = s->arg_end - s->arg_start; | |
567 arg->data = s->arg_start; | |
543 | 568 |
527 | 569 s->arg_start = NULL; |
570 s->cmd_start = NULL; | |
571 s->quoted = 0; | |
543 | 572 s->no_sync_literal = 0; |
527 | 573 s->literal_len = 0; |
574 } | |
575 | |
576 s->state = sw_start; | |
577 | |
578 return NGX_OK; | |
579 | |
580 invalid: | |
581 | |
582 s->state = sw_start; | |
583 s->quoted = 0; | |
543 | 584 s->no_sync_literal = 0; |
527 | 585 s->literal_len = 0; |
586 | |
1136 | 587 return NGX_MAIL_PARSE_INVALID_COMMAND; |
527 | 588 } |
589 | |
590 | |
1136 | 591 ngx_int_t ngx_smtp_parse_command(ngx_mail_session_t *s) |
527 | 592 { |
593 u_char ch, *p, *c, c0, c1, c2, c3; | |
594 ngx_str_t *arg; | |
595 enum { | |
596 sw_start = 0, | |
597 sw_spaces_before_argument, | |
598 sw_argument, | |
599 sw_almost_done | |
600 } state; | |
601 | |
602 state = s->state; | |
603 | |
604 for (p = s->buffer->pos; p < s->buffer->last; p++) { | |
605 ch = *p; | |
606 | |
607 switch (state) { | |
608 | |
1136 | 609 /* SMTP command */ |
527 | 610 case sw_start: |
611 if (ch == ' ' || ch == CR || ch == LF) { | |
612 c = s->buffer->start; | |
613 | |
614 if (p - c == 4) { | |
615 | |
616 c0 = ngx_toupper(c[0]); | |
617 c1 = ngx_toupper(c[1]); | |
618 c2 = ngx_toupper(c[2]); | |
619 c3 = ngx_toupper(c[3]); | |
620 | |
1136 | 621 if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'O') |
527 | 622 { |
1136 | 623 s->command = NGX_SMTP_HELO; |
527 | 624 |
1136 | 625 } else if (c0 == 'E' && c1 == 'H' && c2 == 'L' && c3 == 'O') |
800 | 626 { |
1136 | 627 s->command = NGX_SMTP_EHLO; |
800 | 628 |
527 | 629 } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') |
630 { | |
1136 | 631 s->command = NGX_SMTP_QUIT; |
527 | 632 |
809 | 633 } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') |
634 { | |
1136 | 635 s->command = NGX_SMTP_AUTH; |
809 | 636 |
527 | 637 } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') |
638 { | |
1136 | 639 s->command = NGX_SMTP_NOOP; |
640 | |
641 } else if (c0 == 'M' && c1 == 'A' && c2 == 'I' && c3 == 'L') | |
583 | 642 { |
1136 | 643 s->command = NGX_SMTP_MAIL; |
644 | |
645 } else if (c0 == 'R' && c1 == 'S' && c2 == 'E' && c3 == 'T') | |
646 { | |
647 s->command = NGX_SMTP_RSET; | |
648 | |
527 | 649 } else { |
650 goto invalid; | |
651 } | |
652 | |
653 } else { | |
654 goto invalid; | |
655 } | |
656 | |
657 switch (ch) { | |
658 case ' ': | |
659 state = sw_spaces_before_argument; | |
660 break; | |
661 case CR: | |
662 state = sw_almost_done; | |
663 break; | |
664 case LF: | |
665 goto done; | |
666 } | |
667 break; | |
668 } | |
669 | |
670 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { | |
671 goto invalid; | |
672 } | |
673 | |
674 break; | |
675 | |
676 case sw_spaces_before_argument: | |
677 switch (ch) { | |
678 case ' ': | |
679 break; | |
680 case CR: | |
681 state = sw_almost_done; | |
682 s->arg_end = p; | |
683 break; | |
684 case LF: | |
685 s->arg_end = p; | |
686 goto done; | |
687 default: | |
688 if (s->args.nelts <= 2) { | |
689 state = sw_argument; | |
690 s->arg_start = p; | |
691 break; | |
692 } | |
693 goto invalid; | |
694 } | |
695 break; | |
696 | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
697 case sw_argument: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
698 switch (ch) { |
800 | 699 case ' ': |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
700 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
701 case LF: |
501 | 702 arg = ngx_array_push(&s->args); |
703 if (arg == NULL) { | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
704 return NGX_ERROR; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
705 } |
527 | 706 arg->len = p - s->arg_start; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
707 arg->data = s->arg_start; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
708 s->arg_start = NULL; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
709 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
710 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
711 case ' ': |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
712 state = sw_spaces_before_argument; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
713 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
714 case CR: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
715 state = sw_almost_done; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
716 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
717 case LF: |
527 | 718 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
719 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
720 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
721 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
722 default: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
723 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
724 } |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
725 break; |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
726 |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
727 case sw_almost_done: |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
728 switch (ch) { |
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
729 case LF: |
527 | 730 goto done; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
731 default: |
527 | 732 goto invalid; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
733 } |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
734 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
735 } |
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
736 |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
737 s->buffer->pos = p; |
527 | 738 s->state = state; |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
739 |
527 | 740 return NGX_AGAIN; |
741 | |
742 done: | |
743 | |
744 s->buffer->pos = p + 1; | |
745 | |
746 if (s->arg_start) { | |
747 arg = ngx_array_push(&s->args); | |
748 if (arg == NULL) { | |
749 return NGX_ERROR; | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
750 } |
527 | 751 arg->len = s->arg_end - s->arg_start; |
752 arg->data = s->arg_start; | |
753 s->arg_start = NULL; | |
754 } | |
419
47709bff4468
nginx-0.0.10-2004-09-09-19:40:48 import
Igor Sysoev <igor@sysoev.ru>
parents:
417
diff
changeset
|
755 |
1136 | 756 s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; |
757 | |
527 | 758 return NGX_OK; |
759 | |
760 invalid: | |
761 | |
762 s->state = sw_start; | |
810 | 763 s->arg_start = NULL; |
527 | 764 |
1136 | 765 return NGX_MAIL_PARSE_INVALID_COMMAND; |
417
0526206251f6
nginx-0.0.10-2004-09-07-19:29:22 import
Igor Sysoev <igor@sysoev.ru>
parents:
diff
changeset
|
766 } |