[PATCH 1 of 3] Mail: add IMAP ID command support (RFC2971)
Filipe da Silva
fdasilvayy at gmail.com
Sun Jan 19 11:10:55 UTC 2014
# HG changeset patch
# User Filipe da Silva <fdasilvayy at gmail.com>
# Date 1390129333 -3600
# Sun Jan 19 12:02:13 2014 +0100
# Node ID 3ad4498760c6fcd2ba24ae84f6d924b3a1a35a31
# Parent bb3dc21c89efa8cfd1b9f661fcfd2f155687b99a
Mail: add IMAP ID command support (RFC2971).
Parse the ID command and its arguments.
Handle the server response to ID command.
diff -r bb3dc21c89ef -r 3ad4498760c6 src/mail/ngx_mail.h
--- a/src/mail/ngx_mail.h Fri Jan 17 22:06:04 2014 +0400
+++ b/src/mail/ngx_mail.h Sun Jan 19 12:02:13 2014 +0100
@@ -215,6 +215,7 @@ typedef struct {
unsigned quoted:1;
unsigned backslash:1;
unsigned no_sync_literal:1;
+ unsigned params_list:1;
unsigned starttls:1;
unsigned esmtp:1;
unsigned auth_method:3;
@@ -233,6 +234,7 @@ typedef struct {
ngx_str_t smtp_helo;
ngx_str_t smtp_from;
ngx_str_t smtp_to;
+ ngx_str_t imap_id;
ngx_str_t cmd;
@@ -279,10 +281,10 @@ typedef struct {
#define NGX_IMAP_CAPABILITY 3
#define NGX_IMAP_NOOP 4
#define NGX_IMAP_STARTTLS 5
+#define NGX_IMAP_AUTHENTICATE 6
+#define NGX_IMAP_ID 7
-#define NGX_IMAP_NEXT 6
-
-#define NGX_IMAP_AUTHENTICATE 7
+#define NGX_IMAP_NEXT 8
#define NGX_SMTP_HELO 1
diff -r bb3dc21c89ef -r 3ad4498760c6 src/mail/ngx_mail_imap_handler.c
--- a/src/mail/ngx_mail_imap_handler.c Fri Jan 17 22:06:04 2014 +0400
+++ b/src/mail/ngx_mail_imap_handler.c Sun Jan 19 12:02:13 2014 +0100
@@ -18,6 +18,8 @@ static ngx_int_t ngx_mail_imap_authentic
ngx_connection_t *c);
static ngx_int_t ngx_mail_imap_capability(ngx_mail_session_t *s,
ngx_connection_t *c);
+static ngx_int_t ngx_mail_imap_id(ngx_mail_session_t *s,
+ ngx_connection_t *c);
static ngx_int_t ngx_mail_imap_starttls(ngx_mail_session_t *s,
ngx_connection_t *c);
@@ -31,6 +33,7 @@ static u_char imap_username[] = "+ VXNl
static u_char imap_password[] = "+ UGFzc3dvcmQ6" CRLF;
static u_char imap_bye[] = "* BYE" CRLF;
static u_char imap_invalid_command[] = "BAD invalid command" CRLF;
+static u_char imap_server_id_nil[] = "* ID NIL" CRLF;
void
@@ -183,6 +186,10 @@ ngx_mail_imap_auth_state(ngx_event_t *re
rc = ngx_mail_imap_capability(s, c);
break;
+ case NGX_IMAP_ID:
+ rc = ngx_mail_imap_id(s, c);
+ break;
+
case NGX_IMAP_LOGOUT:
s->quit = 1;
ngx_str_set(&s->text, imap_bye);
@@ -438,6 +445,86 @@ ngx_mail_imap_capability(ngx_mail_sessio
static ngx_int_t
+ngx_mail_imap_id(ngx_mail_session_t *s, ngx_connection_t *c)
+{
+ ngx_uint_t i;
+ ngx_str_t *arg, cmd;
+
+ if (s->args.nelts == 0) {
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
+ arg = s->args.elts;
+ cmd.data = s->tag.data + s->tag.len;
+ cmd.len = s->arg_end - cmd.data;
+
+ /* Client may send ID NIL or ID ( "key" "value" ... ) */
+ if (s->args.nelts == 1) {
+ if (cmd.len != 6
+ || ngx_strncasecmp(cmd.data, (u_char *) "ID NIL", 6) != 0) {
+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "ID invalid argument:\"%V\"",
+ &cmd);
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
+ goto valid;
+ }
+
+ /* more than one and not an even item count */
+ if (s->args.nelts % 2 != 0) {
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
+ for (i = 0; i < s->args.nelts; i += 2) {
+
+ switch (arg[i].len) {
+
+ case 0:
+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "ID empty key #%ui name : \"\"", i );
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+
+ case 3:
+ if (ngx_strncasecmp(arg[i].data, (u_char *) "NIL", 3) == 0) {
+ ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "ID NIL Key #%ui name \"%V\"", i,
+ &arg[i]);
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+ break;
+
+ default:
+ if (arg[i].len > 30) {
+ ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "ID Key #%ui name \"%V\" is too long",
+ i, &arg[i]);
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+ break;
+ }
+ }
+
+valid:
+ s->imap_id.len = cmd.len;
+ s->imap_id.data = ngx_pnalloc(c->pool, cmd.len);
+ if (s->imap_id.data == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(s->imap_id.data, cmd.data, cmd.len);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "imap client ID:\"%V%V\"", &s->tag, &s->imap_id);
+
+ /* Prepare server response to ID command */
+ ngx_str_set(&s->text, imap_server_id_nil);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_mail_imap_starttls(ngx_mail_session_t *s, ngx_connection_t *c)
{
#if (NGX_MAIL_SSL)
diff -r bb3dc21c89ef -r 3ad4498760c6 src/mail/ngx_mail_parse.c
--- a/src/mail/ngx_mail_parse.c Fri Jan 17 22:06:04 2014 +0400
+++ b/src/mail/ngx_mail_parse.c Sun Jan 19 12:02:13 2014 +0100
@@ -280,6 +280,17 @@ ngx_mail_imap_parse_command(ngx_mail_ses
switch (p - c) {
+ case 2:
+ if ((c[0] == 'I' || c[0] == 'i')
+ && (c[1] == 'D'|| c[1] == 'd'))
+ {
+ s->command = NGX_IMAP_ID;
+
+ } else {
+ goto invalid;
+ }
+ break;
+
case 4:
if ((c[0] == 'N' || c[0] == 'n')
&& (c[1] == 'O'|| c[1] == 'o')
@@ -409,14 +420,32 @@ ngx_mail_imap_parse_command(ngx_mail_ses
case ' ':
break;
case CR:
+ if (s->params_list)
+ goto invalid;
state = sw_almost_done;
s->arg_end = p;
break;
case LF:
+ if (s->params_list)
+ goto invalid;
s->arg_end = p;
goto done;
+ case '(': // params list begin
+ if (!s->params_list && s->args.nelts == 0) {
+ s->params_list = 1;
+ break;
+ }
+ goto invalid;
+ case ')': // params list closing
+ if (s->params_list && s->args.nelts > 0) {
+ s->params_list = 0;
+ state = sw_spaces_before_argument;
+ break;
+ }
+ goto invalid;
case '"':
- if (s->args.nelts <= 2) {
+ if (s->args.nelts <= 2
+ || (s->params_list && s->args.nelts < 60)) {
s->quoted = 1;
s->arg_start = p + 1;
state = sw_argument;
@@ -430,7 +459,8 @@ ngx_mail_imap_parse_command(ngx_mail_ses
}
goto invalid;
default:
- if (s->args.nelts <= 2) {
+ if (s->args.nelts <= 2
+ || (s->params_list && s->args.nelts < 60)) {
s->arg_start = p;
state = sw_argument;
break;
@@ -443,6 +473,9 @@ ngx_mail_imap_parse_command(ngx_mail_ses
if (ch == ' ' && s->quoted) {
break;
}
+ if (ch == ')' && s->quoted) {
+ break;
+ }
switch (ch) {
case '"':
@@ -451,6 +484,7 @@ ngx_mail_imap_parse_command(ngx_mail_ses
}
s->quoted = 0;
/* fall through */
+ case ')':
case ' ':
case CR:
case LF:
@@ -463,14 +497,25 @@ ngx_mail_imap_parse_command(ngx_mail_ses
s->arg_start = NULL;
switch (ch) {
+ case ')':
+ if (!s->params_list) {
+ goto invalid;
+ }
+ s->params_list = 0;
case '"':
case ' ':
state = sw_spaces_before_argument;
break;
case CR:
+ if (s->params_list)
+ goto invalid;
state = sw_almost_done;
+ s->arg_end = p;
break;
case LF:
+ if (s->params_list)
+ goto invalid;
+ s->arg_end = p;
goto done;
}
break;
@@ -602,6 +647,7 @@ done:
s->quoted = 0;
s->no_sync_literal = 0;
s->literal_len = 0;
+ s->params_list = 0;
}
s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument;
@@ -614,6 +660,7 @@ invalid:
s->quoted = 0;
s->no_sync_literal = 0;
s->literal_len = 0;
+ s->params_list = 0;
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 000-ImapID_CommandSupport.diff
Type: text/x-patch
Size: 9414 bytes
Desc: not available
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20140119/b36f78b1/attachment.bin>
More information about the nginx-devel
mailing list