[PATCH] Mail: add IMAP ID command support (RFC2971)
Filipe da Silva
fdasilvayy at gmail.com
Mon Feb 10 08:50:22 UTC 2014
# HG changeset patch
# User Filipe da Silva <fdasilvayy at gmail.com>
# Date 1392021996 -3600
# Mon Feb 10 09:46:36 2014 +0100
# Node ID dec4454e6b1327d7737ae95db9f713cc9117ab81
# Parent 887e5abf8446603d9163a8cd011f14fab57e2a3a
Mail: add IMAP ID command support (RFC2971).
Parse the ID command and its arguments( NIL or params_list)
Handle the server response to ID command.
It accepts :
tag ID NIL
tag ID ( "Key" "Value" )
tag ID ( "Key" NIL )
tag ID ()
diff -r 887e5abf8446 -r dec4454e6b13 src/mail/ngx_mail.h
--- a/src/mail/ngx_mail.h Mon Feb 10 09:46:36 2014 +0100
+++ b/src/mail/ngx_mail.h Mon Feb 10 09:46:36 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 887e5abf8446 -r dec4454e6b13 src/mail/ngx_mail_imap_handler.c
--- a/src/mail/ngx_mail_imap_handler.c Mon Feb 10 09:46:36 2014 +0100
+++ b/src/mail/ngx_mail_imap_handler.c Mon Feb 10 09:46:36 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,70 @@ 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;
+
+ arg = s->args.elts;
+ cmd.data = s->tag.data + s->tag.len;
+ cmd.len = s->arg_end - cmd.data;
+
+ /* client may send 'tag ID NIL' */
+ 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,
+ "Invalid argument supplied:\"%V\"", &cmd);
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
+ goto valid;
+ }
+
+ /*
+ * Client may send 'tag ID ( "Key" "value" )'.
+ * Only even list count is allowed.
+ */
+ if (s->args.nelts % 2 != 0) {
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
+ for (i = 0; i < s->args.nelts; i += 2) {
+
+ if ( arg[i].len == 0) {
+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "ID empty key #%ui name : \"\"", i );
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+ else 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;
+ }
+ }
+
+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 887e5abf8446 -r dec4454e6b13 src/mail/ngx_mail_parse.c
--- a/src/mail/ngx_mail_parse.c Mon Feb 10 09:46:36 2014 +0100
+++ b/src/mail/ngx_mail_parse.c Mon Feb 10 09:46:36 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')
@@ -385,6 +396,9 @@ ngx_mail_imap_parse_command(ngx_mail_ses
goto invalid;
}
+ s->cmd.data = s->cmd_start;
+ s->cmd.len = p - s->cmd_start;
+
switch (ch) {
case ' ':
state = sw_spaces_before_argument;
@@ -409,14 +423,33 @@ 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 '(':
+ if (!s->params_list && s->args.nelts == 0) {
+ s->params_list = 1;
+ break;
+ }
+ goto invalid;
+ case ')':
+ if (s->params_list && s->args.nelts % 2 == 0) {
+ s->params_list = 0;
+ 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 +463,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 +477,9 @@ ngx_mail_imap_parse_command(ngx_mail_ses
if (ch == ' ' && s->quoted) {
break;
}
+ if (ch == ')' && s->quoted) {
+ break;
+ }
switch (ch) {
case '"':
@@ -451,6 +488,7 @@ ngx_mail_imap_parse_command(ngx_mail_ses
}
s->quoted = 0;
/* fall through */
+ case ')':
case ' ':
case CR:
case LF:
@@ -462,15 +500,42 @@ ngx_mail_imap_parse_command(ngx_mail_ses
arg->data = s->arg_start;
s->arg_start = NULL;
+ /* only accepts 'nil' as keyword in arguments */
+ if ( s->command == NGX_IMAP_ID && ch != '"') {
+ c = arg->data;
+ if (arg->len != 3
+ || (c[0] != 'N' && c[0] != 'n')
+ || (c[1] != 'I' && c[1] != 'i')
+ || (c[2] != 'L' && c[2] != 'l')) {
+ goto invalid;
+ }
+ /* only accepts 'nil' as value in id_params_list */
+ if (s->params_list && s->args.nelts % 2 != 0) {
+ goto invalid;
+ }
+ }
+
switch (ch) {
+ case ')':
+ if (!s->params_list) {
+ goto invalid;
+ }
+ s->params_list = 0;
+ /* fall through */
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;
@@ -614,6 +679,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: 9778 bytes
Desc: not available
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20140210/2fe4d3fb/attachment.bin>
More information about the nginx-devel
mailing list