aboutsummaryrefslogtreecommitdiff
path: root/src/imap/ngx_imap_parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/imap/ngx_imap_parse.c')
-rw-r--r--src/imap/ngx_imap_parse.c447
1 files changed, 379 insertions, 68 deletions
diff --git a/src/imap/ngx_imap_parse.c b/src/imap/ngx_imap_parse.c
index 6c1c3e95a..e3923e892 100644
--- a/src/imap/ngx_imap_parse.c
+++ b/src/imap/ngx_imap_parse.c
@@ -10,64 +10,383 @@
#include <ngx_imap.h>
-ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
+ngx_int_t ngx_imap_parse_command(ngx_imap_session_t *s)
{
u_char ch, *p, *c;
ngx_str_t *arg;
enum {
sw_start = 0,
+ sw_spaces_before_command,
+ sw_command,
sw_spaces_before_argument,
sw_argument,
- sw_almost_done,
- sw_done
+ sw_literal,
+ sw_start_literal_argument,
+ sw_literal_argument,
+ sw_end_literal_argument,
+ sw_almost_done
} state;
state = s->state;
- p = s->buffer->pos;
- while (p < s->buffer->last && state < sw_done) {
- ch = *p++;
+ for (p = s->buffer->pos; p < s->buffer->last; p++) {
+ ch = *p;
switch (state) {
- /* POP3 command */
+ /* IMAP tag */
+ case sw_start:
+ switch (ch) {
+ case ' ':
+ s->tag.len = p - s->buffer->start + 1;
+ s->tag.data = s->buffer->start;
+ state = sw_spaces_before_command;
+ break;
+ case CR:
+ s->state = sw_start;
+ return NGX_IMAP_PARSE_INVALID_COMMAND;
+ case LF:
+ s->state = sw_start;
+ return NGX_IMAP_PARSE_INVALID_COMMAND;
+ }
+ break;
+
+ case sw_spaces_before_command:
+ switch (ch) {
+ case ' ':
+ break;
+ case CR:
+ s->state = sw_start;
+ return NGX_IMAP_PARSE_INVALID_COMMAND;
+ case LF:
+ s->state = sw_start;
+ return NGX_IMAP_PARSE_INVALID_COMMAND;
+ default:
+ s->cmd_start = p;
+ state = sw_command;
+ break;
+ }
+ break;
+
+ case sw_command:
+ if (ch == ' ' || ch == CR || ch == LF) {
+
+ c = s->cmd_start;
+
+ switch (p - c) {
+
+ case 4:
+ if ((c[0] == 'N' || c[0] == 'n')
+ && (c[1] == 'O'|| c[1] == 'o')
+ && (c[2] == 'O'|| c[2] == 'o')
+ && (c[3] == 'P'|| c[3] == 'p'))
+ {
+ s->command = NGX_IMAP_NOOP;
+
+ } else {
+ goto invalid;
+ }
+ break;
+
+ case 5:
+ if ((c[0] == 'L'|| c[0] == 'l')
+ && (c[1] == 'O'|| c[1] == 'o')
+ && (c[2] == 'G'|| c[2] == 'g')
+ && (c[3] == 'I'|| c[3] == 'i')
+ && (c[4] == 'N'|| c[4] == 'n'))
+ {
+ s->command = NGX_IMAP_LOGIN;
+
+ } else {
+ goto invalid;
+ }
+ break;
+
+ case 6:
+ if ((c[0] == 'L'|| c[0] == 'l')
+ && (c[1] == 'O'|| c[1] == 'o')
+ && (c[2] == 'G'|| c[2] == 'g')
+ && (c[3] == 'O'|| c[3] == 'o')
+ && (c[4] == 'U'|| c[4] == 'u')
+ && (c[5] == 'T'|| c[5] == 't'))
+ {
+ s->command = NGX_IMAP_LOGOUT;
+
+ } else {
+ goto invalid;
+ }
+ break;
+
+ case 10:
+ if ((c[0] == 'C'|| c[0] == 'c')
+ && (c[1] == 'A'|| c[1] == 'a')
+ && (c[2] == 'P'|| c[2] == 'p')
+ && (c[3] == 'A'|| c[3] == 'a')
+ && (c[4] == 'B'|| c[4] == 'b')
+ && (c[5] == 'I'|| c[5] == 'i')
+ && (c[6] == 'L'|| c[6] == 'l')
+ && (c[7] == 'I'|| c[7] == 'i')
+ && (c[8] == 'T'|| c[8] == 't')
+ && (c[9] == 'Y'|| c[9] == 'y'))
+ {
+ s->command = NGX_IMAP_CAPABILITY;
+
+ } else {
+ goto invalid;
+ }
+ break;
+
+ default:
+ goto invalid;
+ }
+
+ switch (ch) {
+ case ' ':
+ state = sw_spaces_before_argument;
+ break;
+ case CR:
+ state = sw_almost_done;
+ break;
+ case LF:
+ goto done;
+ }
+ break;
+ }
+
+ if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
+ goto invalid;
+ }
+
+ break;
+
+ case sw_spaces_before_argument:
+ switch (ch) {
+ case ' ':
+ break;
+ case CR:
+ state = sw_almost_done;
+ s->arg_end = p;
+ break;
+ case LF:
+ s->arg_end = p;
+ goto done;
+ case '"':
+ if (s->args.nelts <= 2) {
+ s->quoted = 1;
+ s->arg_start = p + 1;
+ state = sw_argument;
+ break;
+ }
+ goto invalid;
+ case '{':
+ if (s->args.nelts <= 2) {
+ state = sw_literal;
+ break;
+ }
+ goto invalid;
+ default:
+ if (s->args.nelts <= 2) {
+ s->arg_start = p;
+ state = sw_argument;
+ break;
+ }
+ goto invalid;
+ }
+ break;
+
+ case sw_argument:
+ switch (ch) {
+ case '"':
+ if (!s->quoted) {
+ break;
+ }
+ s->quoted = 0;
+ /* fall through */
+ case ' ':
+ case CR:
+ case LF:
+ arg = ngx_array_push(&s->args);
+ if (arg == NULL) {
+ return NGX_ERROR;
+ }
+ arg->len = p - s->arg_start;
+ arg->data = s->arg_start;
+ s->arg_start = NULL;
+
+ switch (ch) {
+ case '"':
+ case ' ':
+ state = sw_spaces_before_argument;
+ break;
+ case CR:
+ state = sw_almost_done;
+ break;
+ case LF:
+ goto done;
+ }
+ break;
+ }
+ break;
+
+ case sw_literal:
+ if (ch >= '0' && ch <= '9') {
+ s->literal_len = s->literal_len * 10 + (ch - '0');
+ break;
+ }
+ if (ch == '}') {
+ state = sw_start_literal_argument;
+ break;
+ }
+ goto invalid;
+
+ case sw_start_literal_argument:
+ switch (ch) {
+ case CR:
+ break;
+ case LF:
+ s->buffer->pos = p + 1;
+ s->arg_start = p + 1;
+ s->state = sw_literal_argument;
+ return NGX_IMAP_NEXT;
+ }
+ goto invalid;
+
+ case sw_literal_argument:
+ if (--s->literal_len) {
+ break;
+ }
+
+ arg = ngx_array_push(&s->args);
+ if (arg == NULL) {
+ return NGX_ERROR;
+ }
+ arg->len = p + 1 - s->arg_start;
+ arg->data = s->arg_start;
+ s->arg_start = NULL;
+ state = sw_end_literal_argument;
+
+ break;
+
+ case sw_end_literal_argument:
+ switch (ch) {
+ case '{':
+ if (s->args.nelts <= 2) {
+ state = sw_literal;
+ break;
+ }
+ goto invalid;
+ case CR:
+ state = sw_almost_done;
+ break;
+ case LF:
+ goto done;
+ default:
+ goto invalid;
+ }
+ break;
+ case sw_almost_done:
+ switch (ch) {
+ case LF:
+ goto done;
+ default:
+ goto invalid;
+ }
+ }
+ }
+
+ s->buffer->pos = p;
+ s->state = state;
+
+ return NGX_AGAIN;
+
+done:
+
+ s->buffer->pos = p + 1;
+
+ if (s->arg_start) {
+ arg = ngx_array_push(&s->args);
+ if (arg == NULL) {
+ return NGX_ERROR;
+ }
+ arg->len = s->arg_end - s->arg_start;
+ arg->data = s->arg_start;
+ s->arg_start = NULL;
+ s->cmd_start = NULL;
+ s->quoted = 0;
+ s->literal_len = 0;
+ }
+
+ s->state = sw_start;
+
+ return NGX_OK;
+
+invalid:
+
+ s->state = sw_start;
+ s->quoted = 0;
+ s->literal_len = 0;
+
+ return NGX_IMAP_PARSE_INVALID_COMMAND;
+}
+
+
+ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
+{
+ u_char ch, *p, *c, c0, c1, c2, c3;
+ ngx_str_t *arg;
+ enum {
+ sw_start = 0,
+ sw_spaces_before_argument,
+ sw_argument,
+ sw_almost_done
+ } state;
+
+ state = s->state;
+
+ for (p = s->buffer->pos; p < s->buffer->last; p++) {
+ ch = *p;
+
+ switch (state) {
+
+ /* POP3 command */
case sw_start:
if (ch == ' ' || ch == CR || ch == LF) {
c = s->buffer->start;
- if (p - 1 - c == 4) {
+ if (p - c == 4) {
+
+ c0 = ngx_toupper(c[0]);
+ c1 = ngx_toupper(c[1]);
+ c2 = ngx_toupper(c[2]);
+ c3 = ngx_toupper(c[3]);
- if (c[0] == 'U' && c[1] == 'S'
- && c[2] == 'E' && c[3] == 'R')
+ if (c0 == 'U' && c1 == 'S' && c2 == 'E' && c3 == 'R')
{
s->command = NGX_POP3_USER;
- } else if (c[0] == 'P' && c[1] == 'A'
- && c[2] == 'S' && c[3] == 'S')
+ } else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S')
{
s->command = NGX_POP3_PASS;
- } else if (c[0] == 'Q' && c[1] == 'U'
- && c[2] == 'I' && c[3] == 'T')
+ } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T')
{
s->command = NGX_POP3_QUIT;
-#if 0
- } else if (c[0] == 'N' && c[1] == 'O'
- && c[2] == 'O' && c[3] == 'P')
+ } else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A')
+ {
+ s->command = NGX_POP3_CAPA;
+
+ } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P')
{
s->command = NGX_POP3_NOOP;
-#endif
} else {
- s->state = sw_start;
- return NGX_IMAP_PARSE_INVALID_COMMAND;
+ goto invalid;
}
} else {
- s->state = sw_start;
- return NGX_IMAP_PARSE_INVALID_COMMAND;
+ goto invalid;
}
switch (ch) {
@@ -78,45 +397,38 @@ ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
state = sw_almost_done;
break;
case LF:
- state = sw_done;
- break;
+ goto done;
}
break;
}
- if (ch < 'A' || ch > 'Z') {
- s->state = sw_start;
- return NGX_IMAP_PARSE_INVALID_COMMAND;
+ if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
+ goto invalid;
}
break;
- /* the spaces before the argument */
case sw_spaces_before_argument:
switch (ch) {
case ' ':
break;
case CR:
state = sw_almost_done;
- s->arg_end = p - 1;
+ s->arg_end = p;
break;
case LF:
- state = sw_done;
- s->arg_end = p - 1;
- break;
+ s->arg_end = p;
+ goto done;
default:
- if (s->args.nelts > 2) {
- s->state = sw_start;
- return NGX_IMAP_PARSE_INVALID_COMMAND;
+ if (s->args.nelts <= 2) {
+ state = sw_argument;
+ s->arg_start = p;
+ break;
}
-
- state = sw_argument;
- s->arg_start = p - 1;
- break;
+ goto invalid;
}
break;
- /* the argument */
case sw_argument:
switch (ch) {
case ' ':
@@ -126,7 +438,7 @@ ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
if (arg == NULL) {
return NGX_ERROR;
}
- arg->len = p - 1 - s->arg_start;
+ arg->len = p - s->arg_start;
arg->data = s->arg_start;
s->arg_start = NULL;
@@ -138,8 +450,7 @@ ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
state = sw_almost_done;
break;
case LF:
- state = sw_done;
- break;
+ goto done;
}
break;
@@ -148,42 +459,42 @@ ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
}
break;
- /* end of request line */
case sw_almost_done:
switch (ch) {
case LF:
- state = sw_done;
- break;
+ goto done;
default:
- s->state = sw_start;
- return NGX_IMAP_PARSE_INVALID_COMMAND;
+ goto invalid;
}
- break;
-
- /* suppress warning */
- case sw_done:
- break;
}
}
s->buffer->pos = p;
+ s->state = state;
- if (state == sw_done) {
- if (s->arg_start) {
- arg = ngx_array_push(&s->args);
- if (arg == NULL) {
- return NGX_ERROR;
- }
- arg->len = s->arg_end - s->arg_start;
- arg->data = s->arg_start;
- s->arg_start = NULL;
- }
+ return NGX_AGAIN;
+
+done:
- s->state = sw_start;
- return NGX_OK;
+ s->buffer->pos = p + 1;
- } else {
- s->state = state;
- return NGX_AGAIN;
+ if (s->arg_start) {
+ arg = ngx_array_push(&s->args);
+ if (arg == NULL) {
+ return NGX_ERROR;
+ }
+ arg->len = s->arg_end - s->arg_start;
+ arg->data = s->arg_start;
+ s->arg_start = NULL;
}
+
+ s->state = sw_start;
+
+ return NGX_OK;
+
+invalid:
+
+ s->state = sw_start;
+
+ return NGX_IMAP_PARSE_INVALID_COMMAND;
}