Mercurial > hg > nginx-mail
annotate src/mail/ngx_mail_parse.c @ 401:98c752b41cbc PATCH_NGINX_MAIL_0_3
Mail: raise number of arguments parsed in smtp.
MAIL FROM / RCPT TO commands may have arbitrary number of parameters
defined by various extensions. I'm aware of at least following used in
wild: SIZE=, AUTH=, RET=, ENVID= (DSN), BODY= (8BITMIME). Additionally,
rfc2821 address may contain spaces - so it will be parsed as several
arguments too.
Suppose 11 arguments is enough (3 was definitely not enough).
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 23 Jul 2007 00:09:59 +0000 |
parents | f9e6413396d4 |
children | d4cac61d8e95 |
rev | line source |
---|---|
290 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_event.h> | |
10 #include <ngx_mail.h> | |
11 | |
12 | |
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) | |
211 { | |
212 u_char ch, *p, *c; | |
213 ngx_str_t *arg; | |
214 enum { | |
215 sw_start = 0, | |
216 sw_spaces_before_command, | |
217 sw_command, | |
218 sw_spaces_before_argument, | |
219 sw_argument, | |
220 sw_backslash, | |
221 sw_literal, | |
222 sw_no_sync_literal_argument, | |
223 sw_start_literal_argument, | |
224 sw_literal_argument, | |
225 sw_end_literal_argument, | |
226 sw_almost_done | |
227 } state; | |
228 | |
229 state = s->state; | |
230 | |
231 for (p = s->buffer->pos; p < s->buffer->last; p++) { | |
232 ch = *p; | |
233 | |
234 switch (state) { | |
235 | |
236 /* IMAP tag */ | |
237 case sw_start: | |
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; | |
246 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
247 case LF: | |
248 s->state = sw_start; | |
249 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
250 } | |
251 break; | |
252 | |
253 case sw_spaces_before_command: | |
254 switch (ch) { | |
255 case ' ': | |
256 break; | |
257 case CR: | |
258 s->state = sw_start; | |
259 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
260 case LF: | |
261 s->state = sw_start; | |
262 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
263 default: | |
264 s->cmd_start = p; | |
265 state = sw_command; | |
266 break; | |
267 } | |
268 break; | |
269 | |
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')) | |
282 { | |
283 s->command = NGX_IMAP_NOOP; | |
284 | |
285 } else { | |
286 goto invalid; | |
287 } | |
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; | |
303 | |
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 | |
319 #if (NGX_MAIL_SSL) | |
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 | |
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 | |
398
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
357 case 12: |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
358 if ((c[0] == 'A'|| c[0] == 'a') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
359 && (c[1] == 'U'|| c[1] == 'u') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
360 && (c[2] == 'T'|| c[2] == 't') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
361 && (c[3] == 'H'|| c[3] == 'h') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
362 && (c[4] == 'E'|| c[4] == 'e') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
363 && (c[5] == 'N'|| c[5] == 'n') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
364 && (c[6] == 'T'|| c[6] == 't') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
365 && (c[7] == 'I'|| c[7] == 'i') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
366 && (c[8] == 'C'|| c[8] == 'c') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
367 && (c[9] == 'A'|| c[9] == 'a') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
368 && (c[10] == 'T'|| c[10] == 't') |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
369 && (c[11] == 'E'|| c[11] == 'e')) |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
370 { |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
371 s->command = NGX_IMAP_AUTHENTICATE; |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
372 |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
373 } else { |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
374 goto invalid; |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
375 } |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
376 break; |
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
377 |
290 | 378 default: |
379 goto invalid; | |
380 } | |
381 | |
382 switch (ch) { | |
383 case ' ': | |
384 state = sw_spaces_before_argument; | |
385 break; | |
386 case CR: | |
387 state = sw_almost_done; | |
388 break; | |
389 case LF: | |
390 goto done; | |
391 } | |
392 break; | |
393 } | |
394 | |
395 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { | |
396 goto invalid; | |
397 } | |
398 | |
399 break; | |
400 | |
401 case sw_spaces_before_argument: | |
402 switch (ch) { | |
403 case ' ': | |
404 break; | |
405 case CR: | |
406 state = sw_almost_done; | |
407 s->arg_end = p; | |
408 break; | |
409 case LF: | |
410 s->arg_end = p; | |
411 goto done; | |
412 case '"': | |
413 if (s->args.nelts <= 2) { | |
414 s->quoted = 1; | |
415 s->arg_start = p + 1; | |
416 state = sw_argument; | |
417 break; | |
418 } | |
419 goto invalid; | |
420 case '{': | |
421 if (s->args.nelts <= 2) { | |
422 state = sw_literal; | |
423 break; | |
424 } | |
425 goto invalid; | |
426 default: | |
427 if (s->args.nelts <= 2) { | |
428 s->arg_start = p; | |
429 state = sw_argument; | |
430 break; | |
431 } | |
432 goto invalid; | |
433 } | |
434 break; | |
435 | |
436 case sw_argument: | |
437 switch (ch) { | |
438 case '"': | |
439 if (!s->quoted) { | |
440 break; | |
441 } | |
442 s->quoted = 0; | |
443 /* fall through */ | |
444 case ' ': | |
445 case CR: | |
446 case LF: | |
447 arg = ngx_array_push(&s->args); | |
448 if (arg == NULL) { | |
449 return NGX_ERROR; | |
450 } | |
451 arg->len = p - s->arg_start; | |
452 arg->data = s->arg_start; | |
453 s->arg_start = NULL; | |
454 | |
455 switch (ch) { | |
456 case '"': | |
457 case ' ': | |
458 state = sw_spaces_before_argument; | |
459 break; | |
460 case CR: | |
461 state = sw_almost_done; | |
462 break; | |
463 case LF: | |
464 goto done; | |
465 } | |
466 break; | |
467 case '\\': | |
468 if (s->quoted) { | |
469 s->backslash = 1; | |
470 state = sw_backslash; | |
471 } | |
472 break; | |
473 } | |
474 break; | |
475 | |
476 case sw_backslash: | |
477 switch (ch) { | |
478 case CR: | |
479 case LF: | |
480 goto invalid; | |
481 default: | |
482 state = sw_argument; | |
483 } | |
484 break; | |
485 | |
486 case sw_literal: | |
487 if (ch >= '0' && ch <= '9') { | |
488 s->literal_len = s->literal_len * 10 + (ch - '0'); | |
489 break; | |
490 } | |
491 if (ch == '}') { | |
492 state = sw_start_literal_argument; | |
493 break; | |
494 } | |
495 if (ch == '+') { | |
496 state = sw_no_sync_literal_argument; | |
497 break; | |
498 } | |
499 goto invalid; | |
500 | |
501 case sw_no_sync_literal_argument: | |
502 if (ch == '}') { | |
503 s->no_sync_literal = 1; | |
504 state = sw_start_literal_argument; | |
505 break; | |
506 } | |
507 goto invalid; | |
508 | |
509 case sw_start_literal_argument: | |
510 switch (ch) { | |
511 case CR: | |
512 break; | |
513 case LF: | |
514 s->buffer->pos = p + 1; | |
515 s->arg_start = p + 1; | |
516 if (s->no_sync_literal == 0) { | |
517 s->state = sw_literal_argument; | |
518 return NGX_IMAP_NEXT; | |
519 } | |
520 state = sw_literal_argument; | |
521 s->no_sync_literal = 0; | |
522 break; | |
523 default: | |
524 goto invalid; | |
525 } | |
526 break; | |
527 | |
528 case sw_literal_argument: | |
529 if (s->literal_len && --s->literal_len) { | |
530 break; | |
531 } | |
532 | |
533 arg = ngx_array_push(&s->args); | |
534 if (arg == NULL) { | |
535 return NGX_ERROR; | |
536 } | |
537 arg->len = p + 1 - s->arg_start; | |
538 arg->data = s->arg_start; | |
539 s->arg_start = NULL; | |
540 state = sw_end_literal_argument; | |
541 | |
542 break; | |
543 | |
544 case sw_end_literal_argument: | |
545 switch (ch) { | |
546 case '{': | |
547 if (s->args.nelts <= 2) { | |
548 state = sw_literal; | |
549 break; | |
550 } | |
551 goto invalid; | |
552 case CR: | |
553 state = sw_almost_done; | |
554 break; | |
555 case LF: | |
556 goto done; | |
557 default: | |
558 state = sw_spaces_before_argument; | |
559 break; | |
560 } | |
561 break; | |
562 | |
563 case sw_almost_done: | |
564 switch (ch) { | |
565 case LF: | |
566 goto done; | |
567 default: | |
568 goto invalid; | |
569 } | |
570 } | |
571 } | |
572 | |
573 s->buffer->pos = p; | |
574 s->state = state; | |
575 | |
576 return NGX_AGAIN; | |
577 | |
578 done: | |
579 | |
580 s->buffer->pos = p + 1; | |
581 | |
582 if (s->arg_start) { | |
583 arg = ngx_array_push(&s->args); | |
584 if (arg == NULL) { | |
585 return NGX_ERROR; | |
586 } | |
587 arg->len = s->arg_end - s->arg_start; | |
588 arg->data = s->arg_start; | |
589 | |
590 s->arg_start = NULL; | |
591 s->cmd_start = NULL; | |
592 s->quoted = 0; | |
593 s->no_sync_literal = 0; | |
594 s->literal_len = 0; | |
595 } | |
596 | |
398
f9e6413396d4
Mail: IMAP AUTHENTICATE command support.
Maxim Dounin <mdounin@mdounin.ru>
parents:
394
diff
changeset
|
597 s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument; |
290 | 598 |
599 return NGX_OK; | |
600 | |
601 invalid: | |
602 | |
603 s->state = sw_start; | |
604 s->quoted = 0; | |
605 s->no_sync_literal = 0; | |
606 s->literal_len = 0; | |
607 | |
608 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
609 } | |
610 | |
611 | |
612 ngx_int_t ngx_smtp_parse_command(ngx_mail_session_t *s) | |
613 { | |
614 u_char ch, *p, *c, c0, c1, c2, c3; | |
615 ngx_str_t *arg; | |
616 enum { | |
617 sw_start = 0, | |
618 sw_spaces_before_argument, | |
619 sw_argument, | |
620 sw_almost_done | |
621 } state; | |
622 | |
623 state = s->state; | |
624 | |
625 for (p = s->buffer->pos; p < s->buffer->last; p++) { | |
626 ch = *p; | |
627 | |
628 switch (state) { | |
629 | |
630 /* SMTP command */ | |
631 case sw_start: | |
632 if (ch == ' ' || ch == CR || ch == LF) { | |
633 c = s->buffer->start; | |
634 | |
635 if (p - c == 4) { | |
636 | |
637 c0 = ngx_toupper(c[0]); | |
638 c1 = ngx_toupper(c[1]); | |
639 c2 = ngx_toupper(c[2]); | |
640 c3 = ngx_toupper(c[3]); | |
641 | |
642 if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'O') | |
643 { | |
644 s->command = NGX_SMTP_HELO; | |
645 | |
646 } else if (c0 == 'E' && c1 == 'H' && c2 == 'L' && c3 == 'O') | |
647 { | |
648 s->command = NGX_SMTP_EHLO; | |
649 | |
650 } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T') | |
651 { | |
652 s->command = NGX_SMTP_QUIT; | |
653 | |
654 } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H') | |
655 { | |
656 s->command = NGX_SMTP_AUTH; | |
657 | |
658 } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P') | |
659 { | |
660 s->command = NGX_SMTP_NOOP; | |
661 | |
662 } else if (c0 == 'M' && c1 == 'A' && c2 == 'I' && c3 == 'L') | |
663 { | |
664 s->command = NGX_SMTP_MAIL; | |
665 | |
666 } else if (c0 == 'R' && c1 == 'S' && c2 == 'E' && c3 == 'T') | |
667 { | |
668 s->command = NGX_SMTP_RSET; | |
669 | |
394 | 670 } else if (c0 == 'R' && c1 == 'C' && c2 == 'P' && c3 == 'T') |
671 { | |
672 s->command = NGX_SMTP_RCPT; | |
673 | |
674 } else if (c0 == 'V' && c1 == 'R' && c2 == 'F' && c3 == 'Y') | |
675 { | |
676 s->command = NGX_SMTP_VRFY; | |
677 | |
678 } else if (c0 == 'E' && c1 == 'X' && c2 == 'P' && c3 == 'N') | |
679 { | |
680 s->command = NGX_SMTP_EXPN; | |
681 | |
682 } else if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'P') | |
683 { | |
684 s->command = NGX_SMTP_HELP; | |
685 | |
290 | 686 } else { |
687 goto invalid; | |
688 } | |
689 | |
394 | 690 #if (NGX_MAIL_SSL) |
691 } else if (p - c == 8) { | |
692 | |
693 if ((c[0] == 'S'|| c[0] == 's') | |
694 && (c[1] == 'T'|| c[1] == 't') | |
695 && (c[2] == 'A'|| c[2] == 'a') | |
696 && (c[3] == 'R'|| c[3] == 'r') | |
697 && (c[4] == 'T'|| c[4] == 't') | |
698 && (c[5] == 'T'|| c[5] == 't') | |
699 && (c[6] == 'L'|| c[6] == 'l') | |
700 && (c[7] == 'S'|| c[7] == 's')) | |
701 { | |
702 s->command = NGX_SMTP_STARTTLS; | |
703 | |
704 } else { | |
705 goto invalid; | |
706 } | |
707 #endif | |
708 | |
290 | 709 } else { |
710 goto invalid; | |
711 } | |
712 | |
713 switch (ch) { | |
714 case ' ': | |
715 state = sw_spaces_before_argument; | |
716 break; | |
717 case CR: | |
718 state = sw_almost_done; | |
719 break; | |
720 case LF: | |
721 goto done; | |
722 } | |
723 break; | |
724 } | |
725 | |
726 if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) { | |
727 goto invalid; | |
728 } | |
729 | |
730 break; | |
731 | |
732 case sw_spaces_before_argument: | |
733 switch (ch) { | |
734 case ' ': | |
735 break; | |
736 case CR: | |
737 state = sw_almost_done; | |
738 s->arg_end = p; | |
739 break; | |
740 case LF: | |
741 s->arg_end = p; | |
742 goto done; | |
743 default: | |
401
98c752b41cbc
Mail: raise number of arguments parsed in smtp.
Maxim Dounin <mdounin@mdounin.ru>
parents:
398
diff
changeset
|
744 if (s->args.nelts <= 10) { |
290 | 745 state = sw_argument; |
746 s->arg_start = p; | |
747 break; | |
748 } | |
749 goto invalid; | |
750 } | |
751 break; | |
752 | |
753 case sw_argument: | |
754 switch (ch) { | |
755 case ' ': | |
756 case CR: | |
757 case LF: | |
758 arg = ngx_array_push(&s->args); | |
759 if (arg == NULL) { | |
760 return NGX_ERROR; | |
761 } | |
762 arg->len = p - s->arg_start; | |
763 arg->data = s->arg_start; | |
764 s->arg_start = NULL; | |
765 | |
766 switch (ch) { | |
767 case ' ': | |
768 state = sw_spaces_before_argument; | |
769 break; | |
770 case CR: | |
771 state = sw_almost_done; | |
772 break; | |
773 case LF: | |
774 goto done; | |
775 } | |
776 break; | |
777 | |
778 default: | |
779 break; | |
780 } | |
781 break; | |
782 | |
783 case sw_almost_done: | |
784 switch (ch) { | |
785 case LF: | |
786 goto done; | |
787 default: | |
788 goto invalid; | |
789 } | |
790 } | |
791 } | |
792 | |
793 s->buffer->pos = p; | |
794 s->state = state; | |
795 | |
796 return NGX_AGAIN; | |
797 | |
798 done: | |
799 | |
800 s->buffer->pos = p + 1; | |
801 | |
802 if (s->arg_start) { | |
803 arg = ngx_array_push(&s->args); | |
804 if (arg == NULL) { | |
805 return NGX_ERROR; | |
806 } | |
807 arg->len = s->arg_end - s->arg_start; | |
808 arg->data = s->arg_start; | |
809 s->arg_start = NULL; | |
810 } | |
811 | |
812 s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; | |
813 | |
814 return NGX_OK; | |
815 | |
816 invalid: | |
817 | |
818 s->state = sw_start; | |
819 s->arg_start = NULL; | |
820 | |
821 return NGX_MAIL_PARSE_INVALID_COMMAND; | |
822 } |