[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