1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_event.h>
11e18a033bSKonstantin Ananyev#include <ngx_mail.h>
12e18a033bSKonstantin Ananyev#include <ngx_mail_pop3_module.h>
13e18a033bSKonstantin Ananyev#include <ngx_mail_imap_module.h>
14e18a033bSKonstantin Ananyev#include <ngx_mail_smtp_module.h>
15e18a033bSKonstantin Ananyev
16e18a033bSKonstantin Ananyev
17e18a033bSKonstantin Ananyevngx_int_t
18e18a033bSKonstantin Ananyevngx_mail_pop3_parse_command(ngx_mail_session_t *s)
19e18a033bSKonstantin Ananyev{
20e18a033bSKonstantin Ananyev    u_char      ch, *p, *c, c0, c1, c2, c3;
21e18a033bSKonstantin Ananyev    ngx_str_t  *arg;
22e18a033bSKonstantin Ananyev    enum {
23e18a033bSKonstantin Ananyev        sw_start = 0,
24e18a033bSKonstantin Ananyev        sw_spaces_before_argument,
25e18a033bSKonstantin Ananyev        sw_argument,
26e18a033bSKonstantin Ananyev        sw_almost_done
27e18a033bSKonstantin Ananyev    } state;
28e18a033bSKonstantin Ananyev
29e18a033bSKonstantin Ananyev    state = s->state;
30e18a033bSKonstantin Ananyev
31e18a033bSKonstantin Ananyev    for (p = s->buffer->pos; p < s->buffer->last; p++) {
32e18a033bSKonstantin Ananyev        ch = *p;
33e18a033bSKonstantin Ananyev
34e18a033bSKonstantin Ananyev        switch (state) {
35e18a033bSKonstantin Ananyev
36e18a033bSKonstantin Ananyev        /* POP3 command */
37e18a033bSKonstantin Ananyev        case sw_start:
38e18a033bSKonstantin Ananyev            if (ch == ' ' || ch == CR || ch == LF) {
39e18a033bSKonstantin Ananyev                c = s->buffer->start;
40e18a033bSKonstantin Ananyev
41e18a033bSKonstantin Ananyev                if (p - c == 4) {
42e18a033bSKonstantin Ananyev
43e18a033bSKonstantin Ananyev                    c0 = ngx_toupper(c[0]);
44e18a033bSKonstantin Ananyev                    c1 = ngx_toupper(c[1]);
45e18a033bSKonstantin Ananyev                    c2 = ngx_toupper(c[2]);
46e18a033bSKonstantin Ananyev                    c3 = ngx_toupper(c[3]);
47e18a033bSKonstantin Ananyev
48e18a033bSKonstantin Ananyev                    if (c0 == 'U' && c1 == 'S' && c2 == 'E' && c3 == 'R')
49e18a033bSKonstantin Ananyev                    {
50e18a033bSKonstantin Ananyev                        s->command = NGX_POP3_USER;
51e18a033bSKonstantin Ananyev
52e18a033bSKonstantin Ananyev                    } else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S')
53e18a033bSKonstantin Ananyev                    {
54e18a033bSKonstantin Ananyev                        s->command = NGX_POP3_PASS;
55e18a033bSKonstantin Ananyev
56e18a033bSKonstantin Ananyev                    } else if (c0 == 'A' && c1 == 'P' && c2 == 'O' && c3 == 'P')
57e18a033bSKonstantin Ananyev                    {
58e18a033bSKonstantin Ananyev                        s->command = NGX_POP3_APOP;
59e18a033bSKonstantin Ananyev
60e18a033bSKonstantin Ananyev                    } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T')
61e18a033bSKonstantin Ananyev                    {
62e18a033bSKonstantin Ananyev                        s->command = NGX_POP3_QUIT;
63e18a033bSKonstantin Ananyev
64e18a033bSKonstantin Ananyev                    } else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A')
65e18a033bSKonstantin Ananyev                    {
66e18a033bSKonstantin Ananyev                        s->command = NGX_POP3_CAPA;
67e18a033bSKonstantin Ananyev
68e18a033bSKonstantin Ananyev                    } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H')
69e18a033bSKonstantin Ananyev                    {
70e18a033bSKonstantin Ananyev                        s->command = NGX_POP3_AUTH;
71e18a033bSKonstantin Ananyev
72e18a033bSKonstantin Ananyev                    } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P')
73e18a033bSKonstantin Ananyev                    {
74e18a033bSKonstantin Ananyev                        s->command = NGX_POP3_NOOP;
75e18a033bSKonstantin Ananyev#if (NGX_MAIL_SSL)
76e18a033bSKonstantin Ananyev                    } else if (c0 == 'S' && c1 == 'T' && c2 == 'L' && c3 == 'S')
77e18a033bSKonstantin Ananyev                    {
78e18a033bSKonstantin Ananyev                        s->command = NGX_POP3_STLS;
79e18a033bSKonstantin Ananyev#endif
80e18a033bSKonstantin Ananyev                    } else {
81e18a033bSKonstantin Ananyev                        goto invalid;
82e18a033bSKonstantin Ananyev                    }
83e18a033bSKonstantin Ananyev
84e18a033bSKonstantin Ananyev                } else {
85e18a033bSKonstantin Ananyev                    goto invalid;
86e18a033bSKonstantin Ananyev                }
87e18a033bSKonstantin Ananyev
88e18a033bSKonstantin Ananyev                switch (ch) {
89e18a033bSKonstantin Ananyev                case ' ':
90e18a033bSKonstantin Ananyev                    state = sw_spaces_before_argument;
91e18a033bSKonstantin Ananyev                    break;
92e18a033bSKonstantin Ananyev                case CR:
93e18a033bSKonstantin Ananyev                    state = sw_almost_done;
94e18a033bSKonstantin Ananyev                    break;
95e18a033bSKonstantin Ananyev                case LF:
96e18a033bSKonstantin Ananyev                    goto done;
97e18a033bSKonstantin Ananyev                }
98e18a033bSKonstantin Ananyev                break;
99e18a033bSKonstantin Ananyev            }
100e18a033bSKonstantin Ananyev
101e18a033bSKonstantin Ananyev            if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
102e18a033bSKonstantin Ananyev                goto invalid;
103e18a033bSKonstantin Ananyev            }
104e18a033bSKonstantin Ananyev
105e18a033bSKonstantin Ananyev            break;
106e18a033bSKonstantin Ananyev
107e18a033bSKonstantin Ananyev        case sw_spaces_before_argument:
108e18a033bSKonstantin Ananyev            switch (ch) {
109e18a033bSKonstantin Ananyev            case ' ':
110e18a033bSKonstantin Ananyev                break;
111e18a033bSKonstantin Ananyev            case CR:
112e18a033bSKonstantin Ananyev                state = sw_almost_done;
113e18a033bSKonstantin Ananyev                s->arg_end = p;
114e18a033bSKonstantin Ananyev                break;
115e18a033bSKonstantin Ananyev            case LF:
116e18a033bSKonstantin Ananyev                s->arg_end = p;
117e18a033bSKonstantin Ananyev                goto done;
118e18a033bSKonstantin Ananyev            default:
119e18a033bSKonstantin Ananyev                if (s->args.nelts <= 2) {
120e18a033bSKonstantin Ananyev                    state = sw_argument;
121e18a033bSKonstantin Ananyev                    s->arg_start = p;
122e18a033bSKonstantin Ananyev                    break;
123e18a033bSKonstantin Ananyev                }
124e18a033bSKonstantin Ananyev                goto invalid;
125e18a033bSKonstantin Ananyev            }
126e18a033bSKonstantin Ananyev            break;
127e18a033bSKonstantin Ananyev
128e18a033bSKonstantin Ananyev        case sw_argument:
129e18a033bSKonstantin Ananyev            switch (ch) {
130e18a033bSKonstantin Ananyev
131e18a033bSKonstantin Ananyev            case ' ':
132e18a033bSKonstantin Ananyev
133e18a033bSKonstantin Ananyev                /*
134e18a033bSKonstantin Ananyev                 * the space should be considered as part of the at username
135e18a033bSKonstantin Ananyev                 * or password, but not of argument in other commands
136e18a033bSKonstantin Ananyev                 */
137e18a033bSKonstantin Ananyev
138e18a033bSKonstantin Ananyev                if (s->command == NGX_POP3_USER
139e18a033bSKonstantin Ananyev                    || s->command == NGX_POP3_PASS)
140e18a033bSKonstantin Ananyev                {
141e18a033bSKonstantin Ananyev                    break;
142e18a033bSKonstantin Ananyev                }
143e18a033bSKonstantin Ananyev
144e18a033bSKonstantin Ananyev                /* fall through */
145e18a033bSKonstantin Ananyev
146e18a033bSKonstantin Ananyev            case CR:
147e18a033bSKonstantin Ananyev            case LF:
148e18a033bSKonstantin Ananyev                arg = ngx_array_push(&s->args);
149e18a033bSKonstantin Ananyev                if (arg == NULL) {
150e18a033bSKonstantin Ananyev                    return NGX_ERROR;
151e18a033bSKonstantin Ananyev                }
152e18a033bSKonstantin Ananyev                arg->len = p - s->arg_start;
153e18a033bSKonstantin Ananyev                arg->data = s->arg_start;
154e18a033bSKonstantin Ananyev                s->arg_start = NULL;
155e18a033bSKonstantin Ananyev
156e18a033bSKonstantin Ananyev                switch (ch) {
157e18a033bSKonstantin Ananyev                case ' ':
158e18a033bSKonstantin Ananyev                    state = sw_spaces_before_argument;
159e18a033bSKonstantin Ananyev                    break;
160e18a033bSKonstantin Ananyev                case CR:
161e18a033bSKonstantin Ananyev                    state = sw_almost_done;
162e18a033bSKonstantin Ananyev                    break;
163e18a033bSKonstantin Ananyev                case LF:
164e18a033bSKonstantin Ananyev                    goto done;
165e18a033bSKonstantin Ananyev                }
166e18a033bSKonstantin Ananyev                break;
167e18a033bSKonstantin Ananyev
168e18a033bSKonstantin Ananyev            default:
169e18a033bSKonstantin Ananyev                break;
170e18a033bSKonstantin Ananyev            }
171e18a033bSKonstantin Ananyev            break;
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev        case sw_almost_done:
174e18a033bSKonstantin Ananyev            switch (ch) {
175e18a033bSKonstantin Ananyev            case LF:
176e18a033bSKonstantin Ananyev                goto done;
177e18a033bSKonstantin Ananyev            default:
178e18a033bSKonstantin Ananyev                goto invalid;
179e18a033bSKonstantin Ananyev            }
180e18a033bSKonstantin Ananyev        }
181e18a033bSKonstantin Ananyev    }
182e18a033bSKonstantin Ananyev
183e18a033bSKonstantin Ananyev    s->buffer->pos = p;
184e18a033bSKonstantin Ananyev    s->state = state;
185e18a033bSKonstantin Ananyev
186e18a033bSKonstantin Ananyev    return NGX_AGAIN;
187e18a033bSKonstantin Ananyev
188e18a033bSKonstantin Ananyevdone:
189e18a033bSKonstantin Ananyev
190e18a033bSKonstantin Ananyev    s->buffer->pos = p + 1;
191e18a033bSKonstantin Ananyev
192e18a033bSKonstantin Ananyev    if (s->arg_start) {
193e18a033bSKonstantin Ananyev        arg = ngx_array_push(&s->args);
194e18a033bSKonstantin Ananyev        if (arg == NULL) {
195e18a033bSKonstantin Ananyev            return NGX_ERROR;
196e18a033bSKonstantin Ananyev        }
197e18a033bSKonstantin Ananyev        arg->len = s->arg_end - s->arg_start;
198e18a033bSKonstantin Ananyev        arg->data = s->arg_start;
199e18a033bSKonstantin Ananyev        s->arg_start = NULL;
200e18a033bSKonstantin Ananyev    }
201e18a033bSKonstantin Ananyev
202e18a033bSKonstantin Ananyev    s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument;
203e18a033bSKonstantin Ananyev
204e18a033bSKonstantin Ananyev    return NGX_OK;
205e18a033bSKonstantin Ananyev
206e18a033bSKonstantin Ananyevinvalid:
207e18a033bSKonstantin Ananyev
208e18a033bSKonstantin Ananyev    s->state = sw_start;
209e18a033bSKonstantin Ananyev    s->arg_start = NULL;
210e18a033bSKonstantin Ananyev
211e18a033bSKonstantin Ananyev    return NGX_MAIL_PARSE_INVALID_COMMAND;
212e18a033bSKonstantin Ananyev}
213e18a033bSKonstantin Ananyev
214e18a033bSKonstantin Ananyev
215e18a033bSKonstantin Ananyevngx_int_t
216e18a033bSKonstantin Ananyevngx_mail_imap_parse_command(ngx_mail_session_t *s)
217e18a033bSKonstantin Ananyev{
218e18a033bSKonstantin Ananyev    u_char      ch, *p, *c;
219e18a033bSKonstantin Ananyev    ngx_str_t  *arg;
220e18a033bSKonstantin Ananyev    enum {
221e18a033bSKonstantin Ananyev        sw_start = 0,
222e18a033bSKonstantin Ananyev        sw_spaces_before_command,
223e18a033bSKonstantin Ananyev        sw_command,
224e18a033bSKonstantin Ananyev        sw_spaces_before_argument,
225e18a033bSKonstantin Ananyev        sw_argument,
226e18a033bSKonstantin Ananyev        sw_backslash,
227e18a033bSKonstantin Ananyev        sw_literal,
228e18a033bSKonstantin Ananyev        sw_no_sync_literal_argument,
229e18a033bSKonstantin Ananyev        sw_start_literal_argument,
230e18a033bSKonstantin Ananyev        sw_literal_argument,
231e18a033bSKonstantin Ananyev        sw_end_literal_argument,
232e18a033bSKonstantin Ananyev        sw_almost_done
233e18a033bSKonstantin Ananyev    } state;
234e18a033bSKonstantin Ananyev
235e18a033bSKonstantin Ananyev    state = s->state;
236e18a033bSKonstantin Ananyev
237e18a033bSKonstantin Ananyev    for (p = s->buffer->pos; p < s->buffer->last; p++) {
238e18a033bSKonstantin Ananyev        ch = *p;
239e18a033bSKonstantin Ananyev
240e18a033bSKonstantin Ananyev        switch (state) {
241e18a033bSKonstantin Ananyev
242e18a033bSKonstantin Ananyev        /* IMAP tag */
243e18a033bSKonstantin Ananyev        case sw_start:
244e18a033bSKonstantin Ananyev            switch (ch) {
245e18a033bSKonstantin Ananyev            case ' ':
246e18a033bSKonstantin Ananyev                s->tag.len = p - s->buffer->start + 1;
247e18a033bSKonstantin Ananyev                s->tag.data = s->buffer->start;
248e18a033bSKonstantin Ananyev                state = sw_spaces_before_command;
249e18a033bSKonstantin Ananyev                break;
250e18a033bSKonstantin Ananyev            case CR:
251e18a033bSKonstantin Ananyev                s->state = sw_start;
252e18a033bSKonstantin Ananyev                return NGX_MAIL_PARSE_INVALID_COMMAND;
253e18a033bSKonstantin Ananyev            case LF:
254e18a033bSKonstantin Ananyev                s->state = sw_start;
255e18a033bSKonstantin Ananyev                return NGX_MAIL_PARSE_INVALID_COMMAND;
256e18a033bSKonstantin Ananyev            }
257e18a033bSKonstantin Ananyev            break;
258e18a033bSKonstantin Ananyev
259e18a033bSKonstantin Ananyev        case sw_spaces_before_command:
260e18a033bSKonstantin Ananyev            switch (ch) {
261e18a033bSKonstantin Ananyev            case ' ':
262e18a033bSKonstantin Ananyev                break;
263e18a033bSKonstantin Ananyev            case CR:
264e18a033bSKonstantin Ananyev                s->state = sw_start;
265e18a033bSKonstantin Ananyev                return NGX_MAIL_PARSE_INVALID_COMMAND;
266e18a033bSKonstantin Ananyev            case LF:
267e18a033bSKonstantin Ananyev                s->state = sw_start;
268e18a033bSKonstantin Ananyev                return NGX_MAIL_PARSE_INVALID_COMMAND;
269e18a033bSKonstantin Ananyev            default:
270e18a033bSKonstantin Ananyev                s->cmd_start = p;
271e18a033bSKonstantin Ananyev                state = sw_command;
272e18a033bSKonstantin Ananyev                break;
273e18a033bSKonstantin Ananyev            }
274e18a033bSKonstantin Ananyev            break;
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev        case sw_command:
277e18a033bSKonstantin Ananyev            if (ch == ' ' || ch == CR || ch == LF) {
278e18a033bSKonstantin Ananyev
279e18a033bSKonstantin Ananyev                c = s->cmd_start;
280e18a033bSKonstantin Ananyev
281e18a033bSKonstantin Ananyev                switch (p - c) {
282e18a033bSKonstantin Ananyev
283e18a033bSKonstantin Ananyev                case 4:
284e18a033bSKonstantin Ananyev                    if ((c[0] == 'N' || c[0] == 'n')
285e18a033bSKonstantin Ananyev                        && (c[1] == 'O'|| c[1] == 'o')
286e18a033bSKonstantin Ananyev                        && (c[2] == 'O'|| c[2] == 'o')
287e18a033bSKonstantin Ananyev                        && (c[3] == 'P'|| c[3] == 'p'))
288e18a033bSKonstantin Ananyev                    {
289e18a033bSKonstantin Ananyev                        s->command = NGX_IMAP_NOOP;
290e18a033bSKonstantin Ananyev
291e18a033bSKonstantin Ananyev                    } else {
292e18a033bSKonstantin Ananyev                        goto invalid;
293e18a033bSKonstantin Ananyev                    }
294e18a033bSKonstantin Ananyev                    break;
295e18a033bSKonstantin Ananyev
296e18a033bSKonstantin Ananyev                case 5:
297e18a033bSKonstantin Ananyev                    if ((c[0] == 'L'|| c[0] == 'l')
298e18a033bSKonstantin Ananyev                        && (c[1] == 'O'|| c[1] == 'o')
299e18a033bSKonstantin Ananyev                        && (c[2] == 'G'|| c[2] == 'g')
300e18a033bSKonstantin Ananyev                        && (c[3] == 'I'|| c[3] == 'i')
301e18a033bSKonstantin Ananyev                        && (c[4] == 'N'|| c[4] == 'n'))
302e18a033bSKonstantin Ananyev                    {
303e18a033bSKonstantin Ananyev                        s->command = NGX_IMAP_LOGIN;
304e18a033bSKonstantin Ananyev
305e18a033bSKonstantin Ananyev                    } else {
306e18a033bSKonstantin Ananyev                        goto invalid;
307e18a033bSKonstantin Ananyev                    }
308e18a033bSKonstantin Ananyev                    break;
309e18a033bSKonstantin Ananyev
310e18a033bSKonstantin Ananyev                case 6:
311e18a033bSKonstantin Ananyev                    if ((c[0] == 'L'|| c[0] == 'l')
312e18a033bSKonstantin Ananyev                        && (c[1] == 'O'|| c[1] == 'o')
313e18a033bSKonstantin Ananyev                        && (c[2] == 'G'|| c[2] == 'g')
314e18a033bSKonstantin Ananyev                        && (c[3] == 'O'|| c[3] == 'o')
315e18a033bSKonstantin Ananyev                        && (c[4] == 'U'|| c[4] == 'u')
316e18a033bSKonstantin Ananyev                        && (c[5] == 'T'|| c[5] == 't'))
317e18a033bSKonstantin Ananyev                    {
318e18a033bSKonstantin Ananyev                        s->command = NGX_IMAP_LOGOUT;
319e18a033bSKonstantin Ananyev
320e18a033bSKonstantin Ananyev                    } else {
321e18a033bSKonstantin Ananyev                        goto invalid;
322e18a033bSKonstantin Ananyev                    }
323e18a033bSKonstantin Ananyev                    break;
324e18a033bSKonstantin Ananyev
325e18a033bSKonstantin Ananyev#if (NGX_MAIL_SSL)
326e18a033bSKonstantin Ananyev                case 8:
327e18a033bSKonstantin Ananyev                    if ((c[0] == 'S'|| c[0] == 's')
328e18a033bSKonstantin Ananyev                        && (c[1] == 'T'|| c[1] == 't')
329e18a033bSKonstantin Ananyev                        && (c[2] == 'A'|| c[2] == 'a')
330e18a033bSKonstantin Ananyev                        && (c[3] == 'R'|| c[3] == 'r')
331e18a033bSKonstantin Ananyev                        && (c[4] == 'T'|| c[4] == 't')
332e18a033bSKonstantin Ananyev                        && (c[5] == 'T'|| c[5] == 't')
333e18a033bSKonstantin Ananyev                        && (c[6] == 'L'|| c[6] == 'l')
334e18a033bSKonstantin Ananyev                        && (c[7] == 'S'|| c[7] == 's'))
335e18a033bSKonstantin Ananyev                    {
336e18a033bSKonstantin Ananyev                        s->command = NGX_IMAP_STARTTLS;
337e18a033bSKonstantin Ananyev
338e18a033bSKonstantin Ananyev                    } else {
339e18a033bSKonstantin Ananyev                        goto invalid;
340e18a033bSKonstantin Ananyev                    }
341e18a033bSKonstantin Ananyev                    break;
342e18a033bSKonstantin Ananyev#endif
343e18a033bSKonstantin Ananyev
344e18a033bSKonstantin Ananyev                case 10:
345e18a033bSKonstantin Ananyev                    if ((c[0] == 'C'|| c[0] == 'c')
346e18a033bSKonstantin Ananyev                        && (c[1] == 'A'|| c[1] == 'a')
347e18a033bSKonstantin Ananyev                        && (c[2] == 'P'|| c[2] == 'p')
348e18a033bSKonstantin Ananyev                        && (c[3] == 'A'|| c[3] == 'a')
349e18a033bSKonstantin Ananyev                        && (c[4] == 'B'|| c[4] == 'b')
350e18a033bSKonstantin Ananyev                        && (c[5] == 'I'|| c[5] == 'i')
351e18a033bSKonstantin Ananyev                        && (c[6] == 'L'|| c[6] == 'l')
352e18a033bSKonstantin Ananyev                        && (c[7] == 'I'|| c[7] == 'i')
353e18a033bSKonstantin Ananyev                        && (c[8] == 'T'|| c[8] == 't')
354e18a033bSKonstantin Ananyev                        && (c[9] == 'Y'|| c[9] == 'y'))
355e18a033bSKonstantin Ananyev                    {
356e18a033bSKonstantin Ananyev                        s->command = NGX_IMAP_CAPABILITY;
357e18a033bSKonstantin Ananyev
358e18a033bSKonstantin Ananyev                    } else {
359e18a033bSKonstantin Ananyev                        goto invalid;
360e18a033bSKonstantin Ananyev                    }
361e18a033bSKonstantin Ananyev                    break;
362e18a033bSKonstantin Ananyev
363e18a033bSKonstantin Ananyev                case 12:
364e18a033bSKonstantin Ananyev                    if ((c[0] == 'A'|| c[0] == 'a')
365e18a033bSKonstantin Ananyev                        && (c[1] == 'U'|| c[1] == 'u')
366e18a033bSKonstantin Ananyev                        && (c[2] == 'T'|| c[2] == 't')
367e18a033bSKonstantin Ananyev                        && (c[3] == 'H'|| c[3] == 'h')
368e18a033bSKonstantin Ananyev                        && (c[4] == 'E'|| c[4] == 'e')
369e18a033bSKonstantin Ananyev                        && (c[5] == 'N'|| c[5] == 'n')
370e18a033bSKonstantin Ananyev                        && (c[6] == 'T'|| c[6] == 't')
371e18a033bSKonstantin Ananyev                        && (c[7] == 'I'|| c[7] == 'i')
372e18a033bSKonstantin Ananyev                        && (c[8] == 'C'|| c[8] == 'c')
373e18a033bSKonstantin Ananyev                        && (c[9] == 'A'|| c[9] == 'a')
374e18a033bSKonstantin Ananyev                        && (c[10] == 'T'|| c[10] == 't')
375e18a033bSKonstantin Ananyev                        && (c[11] == 'E'|| c[11] == 'e'))
376e18a033bSKonstantin Ananyev                    {
377e18a033bSKonstantin Ananyev                        s->command = NGX_IMAP_AUTHENTICATE;
378e18a033bSKonstantin Ananyev
379e18a033bSKonstantin Ananyev                    } else {
380e18a033bSKonstantin Ananyev                        goto invalid;
381e18a033bSKonstantin Ananyev                    }
382e18a033bSKonstantin Ananyev                    break;
383e18a033bSKonstantin Ananyev
384e18a033bSKonstantin Ananyev                default:
385e18a033bSKonstantin Ananyev                    goto invalid;
386e18a033bSKonstantin Ananyev                }
387e18a033bSKonstantin Ananyev
388e18a033bSKonstantin Ananyev                switch (ch) {
389e18a033bSKonstantin Ananyev                case ' ':
390e18a033bSKonstantin Ananyev                    state = sw_spaces_before_argument;
391e18a033bSKonstantin Ananyev                    break;
392e18a033bSKonstantin Ananyev                case CR:
393e18a033bSKonstantin Ananyev                    state = sw_almost_done;
394e18a033bSKonstantin Ananyev                    break;
395e18a033bSKonstantin Ananyev                case LF:
396e18a033bSKonstantin Ananyev                    goto done;
397e18a033bSKonstantin Ananyev                }
398e18a033bSKonstantin Ananyev                break;
399e18a033bSKonstantin Ananyev            }
400e18a033bSKonstantin Ananyev
401e18a033bSKonstantin Ananyev            if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
402e18a033bSKonstantin Ananyev                goto invalid;
403e18a033bSKonstantin Ananyev            }
404e18a033bSKonstantin Ananyev
405e18a033bSKonstantin Ananyev            break;
406e18a033bSKonstantin Ananyev
407e18a033bSKonstantin Ananyev        case sw_spaces_before_argument:
408e18a033bSKonstantin Ananyev            switch (ch) {
409e18a033bSKonstantin Ananyev            case ' ':
410e18a033bSKonstantin Ananyev                break;
411e18a033bSKonstantin Ananyev            case CR:
412e18a033bSKonstantin Ananyev                state = sw_almost_done;
413e18a033bSKonstantin Ananyev                s->arg_end = p;
414e18a033bSKonstantin Ananyev                break;
415e18a033bSKonstantin Ananyev            case LF:
416e18a033bSKonstantin Ananyev                s->arg_end = p;
417e18a033bSKonstantin Ananyev                goto done;
418e18a033bSKonstantin Ananyev            case '"':
419e18a033bSKonstantin Ananyev                if (s->args.nelts <= 2) {
420e18a033bSKonstantin Ananyev                    s->quoted = 1;
421e18a033bSKonstantin Ananyev                    s->arg_start = p + 1;
422