changeset 1487:f69493e8faab

ngx_mail_pop3_module, ngx_mail_imap_module, and ngx_mail_smtp_module
author Igor Sysoev <igor@sysoev.ru>
date Sat, 15 Sep 2007 16:51:16 +0000
parents 0e7074ef7303
children 0e66eabd18b5
files auto/modules auto/options auto/sources src/mail/ngx_mail.c src/mail/ngx_mail.h src/mail/ngx_mail_auth_http_module.c src/mail/ngx_mail_core_module.c src/mail/ngx_mail_handler.c src/mail/ngx_mail_imap_handler.c src/mail/ngx_mail_imap_module.c src/mail/ngx_mail_imap_module.h src/mail/ngx_mail_pop3_handler.c src/mail/ngx_mail_pop3_module.c src/mail/ngx_mail_pop3_module.h src/mail/ngx_mail_proxy_module.c src/mail/ngx_mail_smtp_handler.c src/mail/ngx_mail_smtp_module.c src/mail/ngx_mail_smtp_module.h src/mail/ngx_mail_ssl_module.c
diffstat 19 files changed, 1188 insertions(+), 723 deletions(-) [+]
line wrap: on
line diff
--- a/auto/modules	Fri Sep 14 15:04:45 2007 +0000
+++ b/auto/modules	Sat Sep 15 16:51:16 2007 +0000
@@ -308,8 +308,6 @@
 
 
 if [ $MAIL_SSL = YES ]; then
-    MAIL_DEPS="$MAIL_DEPS $MAIL_SSL_DEPS"
-    MAIL_SRCS="$MAIL_SRCS $MAIL_SSL_SRCS"
     have=NGX_MAIL_SSL . auto/have
     USE_OPENSSL=YES
 fi
@@ -341,6 +339,26 @@
 
     if [ $MAIL_SSL = YES ]; then
         modules="$modules $MAIL_SSL_MODULE"
+        MAIL_DEPS="$MAIL_DEPS $MAIL_SSL_DEPS"
+        MAIL_SRCS="$MAIL_SRCS $MAIL_SSL_SRCS"
+    fi
+
+    if [ $MAIL_POP3 = YES ]; then
+        modules="$modules $MAIL_POP3_MODULE"
+        MAIL_DEPS="$MAIL_DEPS $MAIL_POP3_DEPS"
+        MAIL_SRCS="$MAIL_SRCS $MAIL_POP3_SRCS"
+    fi
+
+    if [ $MAIL_IMAP = YES ]; then
+        modules="$modules $MAIL_IMAP_MODULE"
+        MAIL_DEPS="$MAIL_DEPS $MAIL_IMAP_DEPS"
+        MAIL_SRCS="$MAIL_SRCS $MAIL_IMAP_SRCS"
+    fi
+
+    if [ $MAIL_SMTP = YES ]; then
+        modules="$modules $MAIL_SMTP_MODULE"
+        MAIL_DEPS="$MAIL_DEPS $MAIL_SMTP_DEPS"
+        MAIL_SRCS="$MAIL_SRCS $MAIL_SMTP_SRCS"
     fi
 
     modules="$modules $MAIL_AUTH_HTTP_MODULE"
--- a/auto/options	Fri Sep 14 15:04:45 2007 +0000
+++ b/auto/options	Sat Sep 15 16:51:16 2007 +0000
@@ -81,6 +81,9 @@
 
 MAIL=NO
 MAIL_SSL=NO
+MAIL_POP3=YES
+MAIL_IMAP=YES
+MAIL_SMTP=YES
 
 NGX_ADDONS=
 
@@ -190,6 +193,9 @@
         # STUB
         --with-imap)                     MAIL=YES                   ;;
         --with-imap_ssl_module)          MAIL_SSL=YES               ;;
+        --without-mail_pop3_module)      MAIL_POP3=NO               ;;
+        --without-mail_imap_module)      MAIL_IMAP=NO               ;;
+        --without-mail_smtp_module)      MAIL_SMTP=NO               ;;
 
         --add-module=*)                  NGX_ADDONS="$NGX_ADDONS $value" ;;
 
--- a/auto/sources	Fri Sep 14 15:04:45 2007 +0000
+++ b/auto/sources	Sat Sep 15 16:51:16 2007 +0000
@@ -423,11 +423,23 @@
 MAIL_SRCS="src/mail/ngx_mail.c \
            src/mail/ngx_mail_core_module.c \
            src/mail/ngx_mail_handler.c \
-           src/mail/ngx_mail_pop3_handler.c \
-           src/mail/ngx_mail_imap_handler.c \
-           src/mail/ngx_mail_smtp_handler.c \
            src/mail/ngx_mail_parse.c"
 
+MAIL_POP3_MODULE="ngx_mail_pop3_module"
+MAIL_POP3_DEPS="src/mail/ngx_mail_pop3_module.h"
+MAIL_POP3_SRCS="src/mail/ngx_mail_pop3_module.c \
+                src/mail/ngx_mail_pop3_handler.c"
+
+MAIL_IMAP_MODULE="ngx_mail_imap_module"
+MAIL_IMAP_DEPS="src/mail/ngx_mail_imap_module.h"
+MAIL_IMAP_SRCS="src/mail/ngx_mail_imap_module.c \
+                src/mail/ngx_mail_imap_handler.c"
+
+MAIL_SMTP_MODULE="ngx_mail_smtp_module"
+MAIL_SMTP_DEPS="src/mail/ngx_mail_smtp_module.h"
+MAIL_SMTP_SRCS="src/mail/ngx_mail_smtp_module.c \
+                src/mail/ngx_mail_smtp_handler.c"
+
 MAIL_SSL_MODULE="ngx_mail_ssl_module"
 MAIL_SSL_DEPS="src/mail/ngx_mail_ssl_module.h"
 MAIL_SSL_SRCS="src/mail/ngx_mail_ssl_module.c"
--- a/src/mail/ngx_mail.c	Fri Sep 14 15:04:45 2007 +0000
+++ b/src/mail/ngx_mail.c	Sat Sep 15 16:51:16 2007 +0000
@@ -185,6 +185,8 @@
 
         /* init mail{} main_conf's */
 
+        cf->ctx = ctx;
+
         if (module->init_main_conf) {
             rv = module->init_main_conf(cf, ctx->main_conf[mi]);
             if (rv != NGX_CONF_OK) {
@@ -197,6 +199,8 @@
 
             /* merge the server{}s' srv_conf's */
 
+            cf->ctx = cscfp[s]->ctx;
+
             if (module->merge_srv_conf) {
                 rv = module->merge_srv_conf(cf,
                                             ctx->srv_conf[mi],
@@ -209,8 +213,6 @@
         }
     }
 
-    /* mail{}'s cf->ctx was needed while the configuration merging */
-
     *cf = pcf;
 
 
--- a/src/mail/ngx_mail.h	Fri Sep 14 15:04:45 2007 +0000
+++ b/src/mail/ngx_mail.h	Sat Sep 15 16:51:16 2007 +0000
@@ -73,57 +73,27 @@
 #define NGX_MAIL_IMAP_PROTOCOL  1
 #define NGX_MAIL_SMTP_PROTOCOL  2
 
-typedef struct {
-    ngx_msec_t              timeout;
-    ngx_msec_t              smtp_greeting_delay;
+
+typedef struct ngx_mail_protocol_s  ngx_mail_protocol_t;
+
 
-    size_t                  imap_client_buffer_size;
-    size_t                  smtp_client_buffer_size;
+typedef struct {
+    ngx_mail_protocol_t    *protocol;
 
-    ngx_uint_t              protocol;
+    ngx_msec_t              timeout;
 
     ngx_flag_t              so_keepalive;
 
-    ngx_str_t               pop3_capability;
-    ngx_str_t               pop3_starttls_capability;
-    ngx_str_t               pop3_starttls_only_capability;
-    ngx_str_t               pop3_auth_capability;
-
-    ngx_str_t               imap_capability;
-    ngx_str_t               imap_starttls_capability;
-    ngx_str_t               imap_starttls_only_capability;
+    ngx_str_t               server_name;
 
-    ngx_str_t               smtp_capability;
-    ngx_str_t               smtp_starttls_capability;
-    ngx_str_t               smtp_starttls_only_capability;
-
-    ngx_str_t               server_name;
-    ngx_str_t               smtp_server_name;
-    ngx_str_t               smtp_greeting;
-
-    ngx_uint_t              pop3_auth_methods;
-    ngx_uint_t              imap_auth_methods;
-    ngx_uint_t              smtp_auth_methods;
-
-    ngx_array_t             pop3_capabilities;
-    ngx_array_t             imap_capabilities;
-    ngx_array_t             smtp_capabilities;
+    u_char                 *file_name;
+    ngx_int_t               line;
 
     /* server ctx */
     ngx_mail_conf_ctx_t    *ctx;
 } ngx_mail_core_srv_conf_t;
 
 
-typedef struct {
-    void                 *(*create_main_conf)(ngx_conf_t *cf);
-    char                 *(*init_main_conf)(ngx_conf_t *cf, void *conf);
-
-    void                 *(*create_srv_conf)(ngx_conf_t *cf);
-    char                 *(*merge_srv_conf)(ngx_conf_t *cf, void *prev,
-                                void *conf);
-} ngx_mail_module_t;
-
-
 typedef enum {
     ngx_pop3_start = 0,
     ngx_pop3_user,
@@ -181,9 +151,9 @@
 
     ngx_uint_t              mail_state;
 
+    unsigned                protocol:3;
     unsigned                blocked:1;
     unsigned                quit:1;
-    unsigned                protocol:2;
     unsigned                quoted:1;
     unsigned                backslash:1;
     unsigned                no_sync_literal:1;
@@ -208,7 +178,7 @@
 
     ngx_uint_t              login_attempt;
 
-    /* used to parse IMAP/POP3/SMTP command */
+    /* used to parse POP3/IMAP/SMTP command */
 
     ngx_uint_t              state;
     u_char                 *cmd_start;
@@ -282,10 +252,43 @@
 #define NGX_MAIL_PARSE_INVALID_COMMAND  20
 
 
-#define NGX_MAIL_MODULE      0x4C49414D     /* "MAIL" */
+typedef void (*ngx_mail_init_session_pt)(ngx_mail_session_t *s,
+    ngx_connection_t *c);
+typedef void (*ngx_mail_init_protocol_pt)(ngx_event_t *rev);
+typedef void (*ngx_mail_auth_state_pt)(ngx_event_t *rev);
+typedef ngx_int_t (*ngx_mail_parse_command_pt)(ngx_mail_session_t *s);
+
+
+struct ngx_mail_protocol_s {
+    ngx_str_t                   name;
+    in_port_t                   port[4];
+    ngx_uint_t                  type;
+
+    ngx_mail_init_session_pt    init_session;
+    ngx_mail_init_protocol_pt   init_protocol;
+    ngx_mail_parse_command_pt   parse_command;
+    ngx_mail_auth_state_pt      auth_state;
 
-#define NGX_MAIL_MAIN_CONF   0x02000000
-#define NGX_MAIL_SRV_CONF    0x04000000
+    ngx_str_t                   internal_server_error;
+};
+
+
+typedef struct {
+    ngx_mail_protocol_t        *protocol;
+
+    void                       *(*create_main_conf)(ngx_conf_t *cf);
+    char                       *(*init_main_conf)(ngx_conf_t *cf, void *conf);
+
+    void                       *(*create_srv_conf)(ngx_conf_t *cf);
+    char                       *(*merge_srv_conf)(ngx_conf_t *cf, void *prev,
+                                      void *conf);
+} ngx_mail_module_t;
+
+
+#define NGX_MAIL_MODULE         0x4C49414D     /* "MAIL" */
+
+#define NGX_MAIL_MAIN_CONF      0x02000000
+#define NGX_MAIL_SRV_CONF       0x04000000
 
 
 #define NGX_MAIL_MAIN_CONF_OFFSET  offsetof(ngx_mail_conf_ctx_t, main_conf)
@@ -306,12 +309,6 @@
 #define ngx_mail_conf_get_module_srv_conf(cf, module)                        \
     ((ngx_mail_conf_ctx_t *) cf->ctx)->srv_conf[module.ctx_index]
 
-typedef void (*ngx_mail_init_session_pt)(ngx_mail_session_t *s,
-    ngx_connection_t *c);
-typedef void (*ngx_mail_init_protocol_pt)(ngx_event_t *rev);
-typedef void (*ngx_mail_auth_state_pt)(ngx_event_t *rev);
-typedef ngx_int_t (*ngx_mail_parse_command_pt)(ngx_mail_session_t *s);
-
 
 #if (NGX_MAIL_SSL)
 void ngx_mail_starttls_handler(ngx_event_t *rev);
@@ -321,10 +318,6 @@
 
 void ngx_mail_init_connection(ngx_connection_t *c);
 
-void ngx_mail_pop3_auth_state(ngx_event_t *rev);
-void ngx_mail_imap_auth_state(ngx_event_t *rev);
-void ngx_mail_smtp_auth_state(ngx_event_t *rev);
-
 ngx_int_t ngx_mail_salt(ngx_mail_session_t *s, ngx_connection_t *c,
     ngx_mail_core_srv_conf_t *cscf);
 ngx_int_t ngx_mail_auth_plain(ngx_mail_session_t *s, ngx_connection_t *c,
@@ -336,6 +329,7 @@
 ngx_int_t ngx_mail_auth_cram_md5_salt(ngx_mail_session_t *s,
     ngx_connection_t *c, char *prefix, size_t len);
 ngx_int_t ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c);
+ngx_int_t ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c);
 
 void ngx_mail_send(ngx_event_t *wev);
 ngx_int_t ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c);
@@ -345,18 +339,7 @@
 u_char *ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len);
 
 
-void ngx_mail_pop3_init_session(ngx_mail_session_t *s, ngx_connection_t *c);
-void ngx_mail_imap_init_session(ngx_mail_session_t *s, ngx_connection_t *c);
-void ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c);
-
-void ngx_mail_pop3_init_protocol(ngx_event_t *rev);
-void ngx_mail_imap_init_protocol(ngx_event_t *rev);
-void ngx_mail_smtp_init_protocol(ngx_event_t *rev);
-
-ngx_int_t ngx_mail_pop3_parse_command(ngx_mail_session_t *s);
-ngx_int_t ngx_mail_imap_parse_command(ngx_mail_session_t *s);
-ngx_int_t ngx_mail_smtp_parse_command(ngx_mail_session_t *s);
-ngx_int_t ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c);
+char *ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
 /* STUB */
--- a/src/mail/ngx_mail_auth_http_module.c	Fri Sep 14 15:04:45 2007 +0000
+++ b/src/mail/ngx_mail_auth_http_module.c	Sat Sep 15 16:51:16 2007 +0000
@@ -111,6 +111,8 @@
 
 
 static ngx_mail_module_t  ngx_mail_auth_http_module_ctx = {
+    NULL,                                  /* protocol */
+
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
 
@@ -135,7 +137,6 @@
 };
 
 
-static char       *ngx_mail_auth_http_protocol[] = { "pop3", "imap", "smtp" };
 static ngx_str_t   ngx_mail_auth_http_method[] = {
     ngx_string("plain"),
     ngx_string("plain"),
@@ -145,18 +146,6 @@
 
 static ngx_str_t   ngx_mail_smtp_errcode = ngx_string("535 5.7.0");
 
-static ngx_uint_t  ngx_mail_start_states[] = {
-   ngx_pop3_start,
-   ngx_imap_start,
-   ngx_smtp_start
-};
-
-static ngx_mail_auth_state_pt  ngx_mail_auth_states[] = {
-   ngx_mail_pop3_auth_state,
-   ngx_mail_imap_auth_state,
-   ngx_mail_smtp_auth_state
-};
-
 
 void
 ngx_mail_auth_http_init(ngx_mail_session_t *s)
@@ -762,7 +751,8 @@
                 return;
             }
 
-            if (s->passwd.data == NULL && s->protocol != NGX_MAIL_SMTP_PROTOCOL)
+            if (s->passwd.data == NULL
+                && s->protocol != NGX_MAIL_SMTP_PROTOCOL)
             {
                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                               "auth http server %V did not send password",
@@ -881,9 +871,11 @@
             return;
         }
 
-        s->mail_state = ngx_mail_start_states[s->protocol];
-        rev->handler = ngx_mail_auth_states[s->protocol];
+        cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
 
+        rev->handler = cscf->protocol->auth_state;
+
+        s->mail_state = 0;
         s->auth_method = NGX_MAIL_AUTH_PLAIN;
 
         c->log->action = "in auth state";
@@ -894,8 +886,6 @@
             return;
         }
 
-        cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
-
         ngx_add_timer(rev, cscf->timeout);
 
         if (rev->ready) {
@@ -1145,9 +1135,10 @@
 ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
     ngx_mail_auth_http_conf_t *ahcf)
 {
-    size_t      len;
-    ngx_buf_t  *b;
-    ngx_str_t   login, passwd;
+    size_t                     len;
+    ngx_buf_t                 *b;
+    ngx_str_t                  login, passwd;
+    ngx_mail_core_srv_conf_t  *cscf;
 
     if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
         return NULL;
@@ -1157,6 +1148,8 @@
         return NULL;
     }
 
+    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
     len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
           + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1
           + sizeof("Auth-Method: ") - 1
@@ -1165,7 +1158,8 @@
           + sizeof("Auth-User: ") - 1 + login.len + sizeof(CRLF) - 1
           + sizeof("Auth-Pass: ") - 1 + passwd.len + sizeof(CRLF) - 1
           + sizeof("Auth-Salt: ") - 1 + s->salt.len
-          + sizeof("Auth-Protocol: imap" CRLF) - 1
+          + sizeof("Auth-Protocol: ") - 1 + cscf->protocol->name.len
+                + sizeof(CRLF) - 1
           + sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN
                 + sizeof(CRLF) - 1
           + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
@@ -1212,8 +1206,8 @@
 
     b->last = ngx_cpymem(b->last, "Auth-Protocol: ",
                          sizeof("Auth-Protocol: ") - 1);
-    b->last = ngx_cpymem(b->last, ngx_mail_auth_http_protocol[s->protocol],
-                         sizeof("imap") - 1);
+    b->last = ngx_cpymem(b->last, cscf->protocol->name.data,
+                         cscf->protocol->name.len);
     *b->last++ = CR; *b->last++ = LF;
 
     b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF,
--- a/src/mail/ngx_mail_core_module.c	Fri Sep 14 15:04:45 2007 +0000
+++ b/src/mail/ngx_mail_core_module.c	Sat Sep 15 16:51:16 2007 +0000
@@ -18,90 +18,10 @@
     void *conf);
 static char *ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
-static char *ngx_mail_core_capability(ngx_conf_t *cf, ngx_command_t *cmd,
+static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
 
 
-static ngx_conf_enum_t  ngx_mail_core_procotol[] = {
-    { ngx_string("pop3"), NGX_MAIL_POP3_PROTOCOL },
-    { ngx_string("imap"), NGX_MAIL_IMAP_PROTOCOL },
-    { ngx_string("smtp"), NGX_MAIL_SMTP_PROTOCOL },
-    { ngx_null_string, 0 }
-};
-
-
-static ngx_str_t  ngx_pop3_default_capabilities[] = {
-    ngx_string("TOP"),
-    ngx_string("USER"),
-    ngx_string("UIDL"),
-    ngx_null_string
-};
-
-
-static ngx_str_t  ngx_imap_default_capabilities[] = {
-    ngx_string("IMAP4"),
-    ngx_string("IMAP4rev1"),
-    ngx_string("UIDPLUS"),
-    ngx_null_string
-};
-
-
-static ngx_conf_bitmask_t  ngx_pop3_auth_methods[] = {
-    { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
-    { ngx_string("apop"), NGX_MAIL_AUTH_APOP_ENABLED },
-    { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
-    { ngx_null_string, 0 }
-};
-
-
-static ngx_conf_bitmask_t  ngx_imap_auth_methods[] = {
-    { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
-    { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
-    { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
-    { ngx_null_string, 0 }
-};
-
-
-static ngx_conf_bitmask_t  ngx_smtp_auth_methods[] = {
-    { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
-    { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
-    { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
-    { ngx_null_string, 0 }
-};
-
-
-static ngx_str_t  ngx_imap_auth_methods_names[] = {
-    ngx_string("AUTH=PLAIN"),
-    ngx_string("AUTH=LOGIN"),
-    ngx_null_string,  /* APOP */
-    ngx_string("AUTH=CRAM-MD5")
-};
-
-
-static ngx_str_t  ngx_smtp_auth_methods_names[] = {
-    ngx_string("PLAIN"),
-    ngx_string("LOGIN"),
-    ngx_null_string,  /* APOP */
-    ngx_string("CRAM-MD5")
-};
-
-
-static ngx_str_t  ngx_pop3_auth_plain_capability =
-    ngx_string("+OK methods supported:" CRLF
-               "LOGIN" CRLF
-               "PLAIN" CRLF
-               "." CRLF);
-
-
-static ngx_str_t  ngx_pop3_auth_cram_md5_capability =
-    ngx_string("+OK methods supported:" CRLF
-               "LOGIN" CRLF
-               "PLAIN" CRLF
-               "CRAM-MD5" CRLF
-               "." CRLF);
-
-
-
 static ngx_command_t  ngx_mail_core_commands[] = {
 
     { ngx_string("server"),
@@ -114,36 +34,15 @@
     { ngx_string("listen"),
       NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
       ngx_mail_core_listen,
-      0,
+      NGX_MAIL_SRV_CONF_OFFSET,
       0,
       NULL },
 
     { ngx_string("protocol"),
       NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_enum_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, protocol),
-      &ngx_mail_core_procotol },
-
-    { ngx_string("imap_client_buffer"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
+      ngx_mail_core_protocol,
       NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, imap_client_buffer_size),
-      NULL },
-
-    { ngx_string("smtp_client_buffer"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_size_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, smtp_client_buffer_size),
-      NULL },
-
-    { ngx_string("smtp_greeting_delay"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_msec_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, smtp_greeting_delay),
+      0,
       NULL },
 
     { ngx_string("so_keepalive"),
@@ -160,27 +59,6 @@
       offsetof(ngx_mail_core_srv_conf_t, timeout),
       NULL },
 
-    { ngx_string("pop3_capabilities"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
-      ngx_mail_core_capability,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, pop3_capabilities),
-      NULL },
-
-    { ngx_string("imap_capabilities"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
-      ngx_mail_core_capability,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, imap_capabilities),
-      NULL },
-
-    { ngx_string("smtp_capabilities"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
-      ngx_mail_core_capability,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, smtp_capabilities),
-      NULL },
-
     { ngx_string("server_name"),
       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_str_slot,
@@ -188,39 +66,13 @@
       offsetof(ngx_mail_core_srv_conf_t, server_name),
       NULL },
 
-    { ngx_string("auth"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
-      ngx_conf_set_bitmask_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, pop3_auth_methods),
-      &ngx_pop3_auth_methods },
-
-    { ngx_string("pop3_auth"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
-      ngx_conf_set_bitmask_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, pop3_auth_methods),
-      &ngx_pop3_auth_methods },
-
-    { ngx_string("imap_auth"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
-      ngx_conf_set_bitmask_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, imap_auth_methods),
-      &ngx_imap_auth_methods },
-
-    { ngx_string("smtp_auth"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
-      ngx_conf_set_bitmask_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, smtp_auth_methods),
-      &ngx_smtp_auth_methods },
-
       ngx_null_command
 };
 
 
 static ngx_mail_module_t  ngx_mail_core_module_ctx = {
+    NULL,                                  /* protocol */
+
     ngx_mail_core_create_main_conf,        /* create main configuration */
     NULL,                                  /* init main configuration */
 
@@ -282,30 +134,14 @@
         return NULL;
     }
 
-    cscf->imap_client_buffer_size = NGX_CONF_UNSET_SIZE;
-    cscf->smtp_client_buffer_size = NGX_CONF_UNSET_SIZE;
-    cscf->protocol = NGX_CONF_UNSET_UINT;
-    cscf->timeout = NGX_CONF_UNSET_MSEC;
-    cscf->smtp_greeting_delay = NGX_CONF_UNSET_MSEC;
-    cscf->so_keepalive = NGX_CONF_UNSET;
+    /*
+     * set by ngx_pcalloc():
+     *
+     *     cscf->protocol = NULL;
+     */
 
-    if (ngx_array_init(&cscf->pop3_capabilities, cf->pool, 4, sizeof(ngx_str_t))
-        != NGX_OK)
-    {
-        return NULL;
-    }
-
-    if (ngx_array_init(&cscf->imap_capabilities, cf->pool, 4, sizeof(ngx_str_t))
-        != NGX_OK)
-    {
-        return NULL;
-    }
-
-    if (ngx_array_init(&cscf->smtp_capabilities, cf->pool, 4, sizeof(ngx_str_t))
-        != NGX_OK)
-    {
-        return NULL;
-    }
+    cscf->timeout = NGX_CONF_UNSET_MSEC;
+    cscf->so_keepalive = NGX_CONF_UNSET;
 
     return cscf;
 }
@@ -317,42 +153,10 @@
     ngx_mail_core_srv_conf_t *prev = parent;
     ngx_mail_core_srv_conf_t *conf = child;
 
-    u_char      *p, *auth;
-    size_t       size, stls_only_size;
-    ngx_str_t   *c, *d;
-    ngx_uint_t   i, m;
-
-    ngx_conf_merge_size_value(conf->imap_client_buffer_size,
-                              prev->imap_client_buffer_size,
-                              (size_t) ngx_pagesize);
-    ngx_conf_merge_size_value(conf->smtp_client_buffer_size,
-                              prev->smtp_client_buffer_size,
-                              (size_t) ngx_pagesize);
-
     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
-    ngx_conf_merge_msec_value(conf->smtp_greeting_delay,
-                              prev->smtp_greeting_delay, 0);
 
-    ngx_conf_merge_uint_value(conf->protocol, prev->protocol,
-                              NGX_MAIL_IMAP_PROTOCOL);
     ngx_conf_merge_value(conf->so_keepalive, prev->so_keepalive, 0);
 
-    ngx_conf_merge_bitmask_value(conf->pop3_auth_methods,
-                              prev->pop3_auth_methods,
-                              (NGX_CONF_BITMASK_SET
-                               |NGX_MAIL_AUTH_PLAIN_ENABLED));
-
-    ngx_conf_merge_bitmask_value(conf->imap_auth_methods,
-                              prev->imap_auth_methods,
-                              (NGX_CONF_BITMASK_SET
-                               |NGX_MAIL_AUTH_PLAIN_ENABLED));
-
-    ngx_conf_merge_bitmask_value(conf->smtp_auth_methods,
-                              prev->smtp_auth_methods,
-                              (NGX_CONF_BITMASK_SET
-                               |NGX_MAIL_AUTH_PLAIN_ENABLED
-                               |NGX_MAIL_AUTH_LOGIN_ENABLED));
-
 
     ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");
 
@@ -365,351 +169,21 @@
         if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN)
             == -1)
         {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
-                               "gethostname() failed");
+            ngx_log_error(NGX_LOG_EMERG, cf->log, ngx_errno,
+                          "gethostname() failed");
             return NGX_CONF_ERROR;
         }
 
         conf->server_name.len = ngx_strlen(conf->server_name.data);
     }
 
-
-    if (conf->pop3_capabilities.nelts == 0) {
-        conf->pop3_capabilities = prev->pop3_capabilities;
-    }
-
-    if (conf->pop3_capabilities.nelts == 0) {
-
-        for (d = ngx_pop3_default_capabilities; d->len; d++) {
-            c = ngx_array_push(&conf->pop3_capabilities);
-            if (c == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            *c = *d;
-        }
-    }
-
-    size = sizeof("+OK Capability list follows" CRLF) - 1
-           + sizeof("." CRLF) - 1;
-
-    stls_only_size = size + sizeof("STLS" CRLF) - 1;
-
-    c = conf->pop3_capabilities.elts;
-    for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
-        size += c[i].len + sizeof(CRLF) - 1;
-
-        if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
-            continue;
-        }
-
-        stls_only_size += c[i].len + sizeof(CRLF) - 1;
-    }
-
-    if (conf->pop3_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
-        size += sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1;
-
-    } else {
-        size += sizeof("SASL LOGIN PLAIN" CRLF) - 1;
-    }
-
-    p = ngx_palloc(cf->pool, size);
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->pop3_capability.len = size;
-    conf->pop3_capability.data = p;
-
-    p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
-                   sizeof("+OK Capability list follows" CRLF) - 1);
-
-    for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
-        p = ngx_cpymem(p, c[i].data, c[i].len);
-        *p++ = CR; *p++ = LF;
-    }
-
-    if (conf->pop3_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
-        p = ngx_cpymem(p, "SASL LOGIN PLAIN CRAM-MD5" CRLF,
-                       sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1);
-
-    } else {
-        p = ngx_cpymem(p, "SASL LOGIN PLAIN" CRLF,
-                       sizeof("SASL LOGIN PLAIN" CRLF) - 1);
-    }
-
-    *p++ = '.'; *p++ = CR; *p = LF;
-
-
-    size += sizeof("STLS" CRLF) - 1;
-
-    p = ngx_palloc(cf->pool, size);
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->pop3_starttls_capability.len = size;
-    conf->pop3_starttls_capability.data = p;
-
-    p = ngx_cpymem(p, conf->pop3_capability.data,
-                   conf->pop3_capability.len - (sizeof("." CRLF) - 1));
-
-    p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
-    *p++ = '.'; *p++ = CR; *p = LF;
-
-
-    if (conf->pop3_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
-        conf->pop3_auth_capability = ngx_pop3_auth_cram_md5_capability;
-
-    } else {
-        conf->pop3_auth_capability = ngx_pop3_auth_plain_capability;
-    }
-
-
-    p = ngx_palloc(cf->pool, stls_only_size);
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->pop3_starttls_only_capability.len = stls_only_size;
-    conf->pop3_starttls_only_capability.data = p;
-
-    p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
-                   sizeof("+OK Capability list follows" CRLF) - 1);
-
-    for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
-        if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
-            continue;
-        }
-
-        p = ngx_cpymem(p, c[i].data, c[i].len);
-        *p++ = CR; *p++ = LF;
-    }
-
-    p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
-    *p++ = '.'; *p++ = CR; *p = LF;
-
-
-    if (conf->imap_capabilities.nelts == 0) {
-        conf->imap_capabilities = prev->imap_capabilities;
-    }
-
-    if (conf->imap_capabilities.nelts == 0) {
-
-        for (d = ngx_imap_default_capabilities; d->len; d++) {
-            c = ngx_array_push(&conf->imap_capabilities);
-            if (c == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            *c = *d;
-        }
-    }
-
-    size = sizeof("* CAPABILITY" CRLF) - 1;
-
-    c = conf->imap_capabilities.elts;
-    for (i = 0; i < conf->imap_capabilities.nelts; i++) {
-        size += 1 + c[i].len;
-    }
-
-    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
-         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
-         m <<= 1, i++)
-    {
-        if (m & conf->imap_auth_methods) {
-            size += 1 + ngx_imap_auth_methods_names[i].len;
-        }
-    }
-
-    p = ngx_palloc(cf->pool, size);
-    if (p == NULL) {
+    if (conf->protocol == NULL) {
+        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                      "unknown mail protocol for server in %s:%ui",
+                      conf->file_name, conf->line);
         return NGX_CONF_ERROR;
     }
 
-    conf->imap_capability.len = size;
-    conf->imap_capability.data = p;
-
-    p = ngx_cpymem(p, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
-
-    for (i = 0; i < conf->imap_capabilities.nelts; i++) {
-        *p++ = ' ';
-        p = ngx_cpymem(p, c[i].data, c[i].len);
-    }
-
-    auth = p;
-
-    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
-         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
-         m <<= 1, i++)
-    {
-        if (m & conf->imap_auth_methods) {
-            *p++ = ' ';
-            p = ngx_cpymem(p, ngx_imap_auth_methods_names[i].data,
-                           ngx_imap_auth_methods_names[i].len);
-        }
-    }
-
-    *p++ = CR; *p = LF;
-
-
-    size += sizeof(" STARTTLS") - 1;
-
-    p = ngx_palloc(cf->pool, size);
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->imap_starttls_capability.len = size;
-    conf->imap_starttls_capability.data = p;
-
-    p = ngx_cpymem(p, conf->imap_capability.data,
-                   conf->imap_capability.len - (sizeof(CRLF) - 1));
-    p = ngx_cpymem(p, " STARTTLS", sizeof(" STARTTLS") - 1);
-    *p++ = CR; *p = LF;
-
-
-    size = (auth - conf->imap_capability.data) + sizeof(CRLF) - 1
-            + sizeof(" STARTTLS LOGINDISABLED") - 1;
-
-    p = ngx_palloc(cf->pool, size);
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->imap_starttls_only_capability.len = size;
-    conf->imap_starttls_only_capability.data = p;
-
-    p = ngx_cpymem(p, conf->imap_capability.data,
-                   auth - conf->imap_capability.data);
-    p = ngx_cpymem(p, " STARTTLS LOGINDISABLED",
-                   sizeof(" STARTTLS LOGINDISABLED") - 1);
-    *p++ = CR; *p = LF;
-
-
-    size = sizeof("220  ESMTP ready" CRLF) - 1 + conf->server_name.len;
-
-    p = ngx_palloc(cf->pool, size);
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->smtp_greeting.len = size;
-    conf->smtp_greeting.data = p;
-
-    *p++ = '2'; *p++ = '2'; *p++ = '0'; *p++ = ' ';
-    p = ngx_cpymem(p, conf->server_name.data, conf->server_name.len);
-    ngx_memcpy(p, " ESMTP ready" CRLF, sizeof(" ESMTP ready" CRLF) - 1);
-
-
-    size = sizeof("250 " CRLF) - 1 + conf->server_name.len;
-
-    p = ngx_palloc(cf->pool, size);
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->smtp_server_name.len = size;
-    conf->smtp_server_name.data = p;
-
-    *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
-    p = ngx_cpymem(p, conf->server_name.data, conf->server_name.len);
-    *p++ = CR; *p = LF;
-
-
-    if (conf->smtp_capabilities.nelts == 0) {
-        conf->smtp_capabilities = prev->smtp_capabilities;
-    }
-
-    size = sizeof("250-") - 1 + conf->server_name.len + sizeof(CRLF) - 1
-           + sizeof("250 AUTH") - 1 + sizeof(CRLF) - 1;
-
-    c = conf->smtp_capabilities.elts;
-    for (i = 0; i < conf->smtp_capabilities.nelts; i++) {
-        size += sizeof("250 ") - 1 + c[i].len + sizeof(CRLF) - 1;
-    }
-
-    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
-         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
-         m <<= 1, i++)
-    {
-        if (m & conf->smtp_auth_methods) {
-            size += 1 + ngx_smtp_auth_methods_names[i].len;
-        }
-    }
-
-    p = ngx_palloc(cf->pool, size);
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->smtp_capability.len = size;
-    conf->smtp_capability.data = p;
-
-    *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
-    p = ngx_cpymem(p, conf->server_name.data, conf->server_name.len);
-    *p++ = CR; *p++ = LF;
-
-    for (i = 0; i < conf->smtp_capabilities.nelts; i++) {
-        *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
-        p = ngx_cpymem(p, c[i].data, c[i].len);
-        *p++ = CR; *p++ = LF;
-    }
-
-    auth = p;
-
-    *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
-    *p++ = 'A'; *p++ = 'U'; *p++ = 'T'; *p++ = 'H';
-
-    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
-         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
-         m <<= 1, i++)
-    {
-        if (m & conf->smtp_auth_methods) {
-            *p++ = ' ';
-            p = ngx_cpymem(p, ngx_smtp_auth_methods_names[i].data,
-                           ngx_smtp_auth_methods_names[i].len);
-        }
-    }
-
-    *p++ = CR; *p = LF;
-
-    size += sizeof("250 STARTTLS" CRLF) - 1;
-
-    p = ngx_palloc(cf->pool, size);
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->smtp_starttls_capability.len = size;
-    conf->smtp_starttls_capability.data = p;
-
-    p = ngx_cpymem(p, conf->smtp_capability.data,
-                   conf->smtp_capability.len);
-
-    p = ngx_cpymem(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
-    *p++ = CR; *p = LF;
-
-    p = conf->smtp_starttls_capability.data
-        + (auth - conf->smtp_capability.data) + 3;
-    *p = '-';
-
-    size = (auth - conf->smtp_capability.data)
-            + sizeof("250 STARTTLS" CRLF) - 1;
-
-    p = ngx_palloc(cf->pool, size);
-    if (p == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    conf->smtp_starttls_only_capability.len = size;
-    conf->smtp_starttls_only_capability.data = p;
-
-    p = ngx_cpymem(p, conf->smtp_capability.data,
-                   auth - conf->smtp_capability.data);
-
-    ngx_memcpy(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
-
     return NGX_CONF_OK;
 }
 
@@ -726,7 +200,6 @@
     ngx_mail_core_srv_conf_t   *cscf, **cscfp;
     ngx_mail_core_main_conf_t  *cmcf;
 
-
     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
     if (ctx == NULL) {
         return NGX_CONF_ERROR;
@@ -764,6 +237,9 @@
     cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
     cscf->ctx = ctx;
 
+    cscf->file_name = cf->conf_file->file.name.data;
+    cscf->line = cf->conf_file->line;
+
     cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
 
     cscfp = ngx_array_push(&cmcf->servers);
@@ -793,10 +269,13 @@
 static char *
 ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
+    ngx_mail_core_srv_conf_t  *cscf = conf;
+
     ngx_str_t                  *value;
     ngx_url_t                   u;
-    ngx_uint_t                  i;
+    ngx_uint_t                  i, m;
     ngx_mail_listen_t          *imls;
+    ngx_mail_module_t          *module;
     ngx_mail_core_main_conf_t  *cmcf;
 
     value = cf->args->elts;
@@ -843,6 +322,25 @@
     imls->family = AF_INET;
     imls->ctx = cf->ctx;
 
+    for (m = 0; ngx_modules[m]; m++) {
+        if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
+            continue;
+        }
+
+        module = ngx_modules[m]->ctx;
+
+        if (module->protocol == NULL) {
+            continue;
+        }
+
+        for (i = 0; module->protocol->port[i]; i++) {
+            if (module->protocol->port[i] == u.port) {
+                cscf->protocol = module->protocol;
+                break;
+            }
+        }
+    }
+
     if (cf->args->nelts == 2) {
         return NGX_CONF_OK;
     }
@@ -859,7 +357,40 @@
 
 
 static char *
-ngx_mail_core_capability(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_mail_core_srv_conf_t  *cscf = conf;
+
+    ngx_str_t          *value;
+    ngx_uint_t          m;
+    ngx_mail_module_t  *module;
+
+    value = cf->args->elts;
+
+    for (m = 0; ngx_modules[m]; m++) {
+        if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
+            continue;
+        }
+
+        module = ngx_modules[m]->ctx;
+
+        if (module->protocol
+            && ngx_strcmp(module->protocol->name.data, value[1].data) == 0)
+        {
+            cscf->protocol = module->protocol;
+
+            return NGX_CONF_OK;
+        }
+    }
+
+    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                       "unknown protocol \"%V\"", &value[1]);
+    return NGX_CONF_ERROR;
+}
+
+
+char *
+ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
 {
     char  *p = conf;
 
--- a/src/mail/ngx_mail_handler.c	Fri Sep 14 15:04:45 2007 +0000
+++ b/src/mail/ngx_mail_handler.c	Sat Sep 15 16:51:16 2007 +0000
@@ -18,34 +18,6 @@
 #endif
 
 
-static ngx_mail_init_session_pt  ngx_mail_init_sessions[] = {
-   ngx_mail_pop3_init_session,
-   ngx_mail_imap_init_session,
-   ngx_mail_smtp_init_session
-};
-
-
-static ngx_mail_init_protocol_pt  ngx_mail_init_protocols[] = {
-   ngx_mail_pop3_init_protocol,
-   ngx_mail_imap_init_protocol,
-   ngx_mail_smtp_init_protocol
-};
-
-
-static ngx_mail_parse_command_pt  ngx_mail_parse_commands[] = {
-   ngx_mail_pop3_parse_command,
-   ngx_mail_imap_parse_command,
-   ngx_mail_smtp_parse_command
-};
-
-
-static ngx_str_t  internal_server_errors[] = {
-   ngx_string("-ERR internal server error" CRLF),
-   ngx_string("* BAD internal server error" CRLF),
-   ngx_string("451 4.3.2 Internal server error" CRLF),
-};
-
-
 void
 ngx_mail_init_connection(ngx_connection_t *c)
 {
@@ -210,17 +182,20 @@
 static void
 ngx_mail_ssl_handshake_handler(ngx_connection_t *c)
 {
-    ngx_mail_session_t  *s;
+    ngx_mail_session_t        *s;
+    ngx_mail_core_srv_conf_t  *cscf;
 
     if (c->ssl->handshaked) {
 
         s = c->data;
 
         if (s->starttls) {
-            c->read->handler = ngx_mail_init_protocols[s->protocol];
+            cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+            c->read->handler = cscf->protocol->init_protocol;
             c->write->handler = ngx_mail_send;
 
-            ngx_mail_init_protocols[s->protocol](c->read);
+            cscf->protocol->init_protocol(c->read);
 
             return;
         }
@@ -245,7 +220,7 @@
 
     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
 
-    s->protocol = cscf->protocol;
+    s->protocol = cscf->protocol->type;
 
     s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module);
     if (s->ctx == NULL) {
@@ -255,7 +230,7 @@
 
     c->write->handler = ngx_mail_send;
 
-    ngx_mail_init_sessions[s->protocol](s, c);
+    cscf->protocol->init_session(s, c);
 }
 
 
@@ -567,9 +542,10 @@
 ngx_int_t
 ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c)
 {
-    ssize_t    n;
-    ngx_int_t  rc;
-    ngx_str_t  l;
+    ssize_t                    n;
+    ngx_int_t                  rc;
+    ngx_str_t                  l;
+    ngx_mail_core_srv_conf_t  *cscf;
 
     n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
 
@@ -591,7 +567,9 @@
         return NGX_AGAIN;
     }
 
-    rc = ngx_mail_parse_commands[s->protocol](s);
+    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+    rc = cscf->protocol->parse_command(s);
 
     if (rc == NGX_AGAIN) {
 
@@ -644,7 +622,11 @@
 void
 ngx_mail_session_internal_server_error(ngx_mail_session_t *s)
 {
-    s->out = internal_server_errors[s->protocol];
+    ngx_mail_core_srv_conf_t  *cscf;
+
+    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+    s->out = cscf->protocol->internal_server_error;
     s->quit = 1;
 
     ngx_mail_send(s->connection->write);
--- a/src/mail/ngx_mail_imap_handler.c	Fri Sep 14 15:04:45 2007 +0000
+++ b/src/mail/ngx_mail_imap_handler.c	Sat Sep 15 16:51:16 2007 +0000
@@ -8,6 +8,7 @@
 #include <ngx_core.h>
 #include <ngx_event.h>
 #include <ngx_mail.h>
+#include <ngx_mail_imap_module.h>
 
 
 static ngx_int_t ngx_mail_imap_login(ngx_mail_session_t *s,
@@ -58,7 +59,7 @@
 {
     ngx_connection_t          *c;
     ngx_mail_session_t        *s;
-    ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_imap_srv_conf_t  *iscf;
 
     c = rev->data;
 
@@ -81,9 +82,9 @@
             return;
         }
 
-        cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+        iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
 
-        s->buffer = ngx_create_temp_buf(c->pool, cscf->imap_client_buffer_size);
+        s->buffer = ngx_create_temp_buf(c->pool, iscf->client_buffer_size);
         if (s->buffer == NULL) {
             ngx_mail_session_internal_server_error(s);
             return;
@@ -349,6 +350,7 @@
 {
     ngx_int_t                  rc;
     ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_imap_srv_conf_t  *iscf;
 
 #if (NGX_MAIL_SSL)
     if (ngx_mail_starttls_only(s, c)) {
@@ -378,13 +380,15 @@
 
     case NGX_MAIL_AUTH_CRAM_MD5:
 
-        cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+        iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
 
-        if (!(cscf->imap_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
+        if (!(iscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
             return NGX_MAIL_PARSE_INVALID_COMMAND;
         }
 
         if (s->salt.data == NULL) {
+            cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
             if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
                 return NGX_ERROR;
             }
@@ -405,12 +409,12 @@
 static ngx_int_t
 ngx_mail_imap_capability(ngx_mail_session_t *s, ngx_connection_t *c)
 {
-    ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_imap_srv_conf_t  *iscf;
 #if (NGX_MAIL_SSL)
     ngx_mail_ssl_conf_t       *sslcf;
 #endif
 
-    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+    iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
 
 #if (NGX_MAIL_SSL)
 
@@ -418,18 +422,18 @@
         sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
 
         if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
-            s->text = cscf->imap_starttls_capability;
+            s->text = iscf->starttls_capability;
             return NGX_OK;
         }
 
         if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
-            s->text = cscf->imap_starttls_only_capability;
+            s->text = iscf->starttls_only_capability;
             return NGX_OK;
         }
     }
 #endif
 
-    s->text = cscf->imap_capability;
+    s->text = iscf->capability;
 
     return NGX_OK;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mail/ngx_mail_imap_module.c	Sat Sep 15 16:51:16 2007 +0000
@@ -0,0 +1,251 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_mail.h>
+#include <ngx_mail_imap_module.h>
+
+
+static void *ngx_mail_imap_create_srv_conf(ngx_conf_t *cf);
+static char *ngx_mail_imap_merge_srv_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+
+
+static ngx_str_t  ngx_mail_imap_default_capabilities[] = {
+    ngx_string("IMAP4"),
+    ngx_string("IMAP4rev1"),
+    ngx_string("UIDPLUS"),
+    ngx_null_string
+};
+
+
+static ngx_conf_bitmask_t  ngx_mail_imap_auth_methods[] = {
+    { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
+    { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
+    { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_str_t  ngx_mail_imap_auth_methods_names[] = {
+    ngx_string("AUTH=PLAIN"),
+    ngx_string("AUTH=LOGIN"),
+    ngx_null_string,  /* APOP */
+    ngx_string("AUTH=CRAM-MD5")
+};
+
+
+static ngx_mail_protocol_t  ngx_mail_imap_protocol = {
+    ngx_string("imap"),
+    { 143, 993, 0, 0 },
+    NGX_MAIL_IMAP_PROTOCOL,
+
+    ngx_mail_imap_init_session,
+    ngx_mail_imap_init_protocol,
+    ngx_mail_imap_parse_command,
+    ngx_mail_imap_auth_state,
+
+    ngx_string("* BAD internal server error" CRLF)
+};
+
+
+static ngx_command_t  ngx_mail_imap_commands[] = {
+
+    { ngx_string("imap_client_buffer"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_imap_srv_conf_t, client_buffer_size),
+      NULL },
+
+    { ngx_string("imap_capabilities"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
+      ngx_mail_capabilities,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_imap_srv_conf_t, capabilities),
+      NULL },
+
+    { ngx_string("imap_auth"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
+      ngx_conf_set_bitmask_slot,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_imap_srv_conf_t, auth_methods),
+      &ngx_mail_imap_auth_methods },
+
+      ngx_null_command
+};
+
+
+static ngx_mail_module_t  ngx_mail_imap_module_ctx = {
+    &ngx_mail_imap_protocol,               /* protocol */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    ngx_mail_imap_create_srv_conf,         /* create server configuration */
+    ngx_mail_imap_merge_srv_conf           /* merge server configuration */
+};
+
+
+ngx_module_t  ngx_mail_imap_module = {
+    NGX_MODULE_V1,
+    &ngx_mail_imap_module_ctx,             /* module context */
+    ngx_mail_imap_commands,                /* module directives */
+    NGX_MAIL_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static void *
+ngx_mail_imap_create_srv_conf(ngx_conf_t *cf)
+{
+    ngx_mail_imap_srv_conf_t  *iscf;
+
+    iscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_imap_srv_conf_t));
+    if (iscf == NULL) {
+        return NULL;
+    }
+
+    iscf->client_buffer_size = NGX_CONF_UNSET_SIZE;
+
+    if (ngx_array_init(&iscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
+        != NGX_OK)
+    {
+        return NULL;
+    }
+
+    return iscf;
+}
+
+
+static char *
+ngx_mail_imap_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_mail_imap_srv_conf_t *prev = parent;
+    ngx_mail_imap_srv_conf_t *conf = child;
+
+    u_char      *p, *auth;
+    size_t       size;
+    ngx_str_t   *c, *d;
+    ngx_uint_t   i, m;
+
+    ngx_conf_merge_size_value(conf->client_buffer_size,
+                              prev->client_buffer_size,
+                              (size_t) ngx_pagesize);
+
+    ngx_conf_merge_bitmask_value(conf->auth_methods,
+                              prev->auth_methods,
+                              (NGX_CONF_BITMASK_SET
+                               |NGX_MAIL_AUTH_PLAIN_ENABLED));
+
+
+    if (conf->capabilities.nelts == 0) {
+        conf->capabilities = prev->capabilities;
+    }
+
+    if (conf->capabilities.nelts == 0) {
+
+        for (d = ngx_mail_imap_default_capabilities; d->len; d++) {
+            c = ngx_array_push(&conf->capabilities);
+            if (c == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            *c = *d;
+        }
+    }
+
+    size = sizeof("* CAPABILITY" CRLF) - 1;
+
+    c = conf->capabilities.elts;
+    for (i = 0; i < conf->capabilities.nelts; i++) {
+        size += 1 + c[i].len;
+    }
+
+    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
+         m <<= 1, i++)
+    {
+        if (m & conf->auth_methods) {
+            size += 1 + ngx_mail_imap_auth_methods_names[i].len;
+        }
+    }
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->capability.len = size;
+    conf->capability.data = p;
+
+    p = ngx_cpymem(p, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
+
+    for (i = 0; i < conf->capabilities.nelts; i++) {
+        *p++ = ' ';
+        p = ngx_cpymem(p, c[i].data, c[i].len);
+    }
+
+    auth = p;
+
+    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
+         m <<= 1, i++)
+    {
+        if (m & conf->auth_methods) {
+            *p++ = ' ';
+            p = ngx_cpymem(p, ngx_mail_imap_auth_methods_names[i].data,
+                           ngx_mail_imap_auth_methods_names[i].len);
+        }
+    }
+
+    *p++ = CR; *p = LF;
+
+
+    size += sizeof(" STARTTLS") - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->starttls_capability.len = size;
+    conf->starttls_capability.data = p;
+
+    p = ngx_cpymem(p, conf->capability.data,
+                   conf->capability.len - (sizeof(CRLF) - 1));
+    p = ngx_cpymem(p, " STARTTLS", sizeof(" STARTTLS") - 1);
+    *p++ = CR; *p = LF;
+
+
+    size = (auth - conf->capability.data) + sizeof(CRLF) - 1
+            + sizeof(" STARTTLS LOGINDISABLED") - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->starttls_only_capability.len = size;
+    conf->starttls_only_capability.data = p;
+
+    p = ngx_cpymem(p, conf->capability.data,
+                   auth - conf->capability.data);
+    p = ngx_cpymem(p, " STARTTLS LOGINDISABLED",
+                   sizeof(" STARTTLS LOGINDISABLED") - 1);
+    *p++ = CR; *p = LF;
+
+    return NGX_CONF_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mail/ngx_mail_imap_module.h	Sat Sep 15 16:51:16 2007 +0000
@@ -0,0 +1,38 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_MAIL_IMAP_MODULE_H_INCLUDED_
+#define _NGX_MAIL_IMAP_MODULE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_mail.h>
+
+
+typedef struct {
+    size_t       client_buffer_size;
+
+    ngx_str_t    capability;
+    ngx_str_t    starttls_capability;
+    ngx_str_t    starttls_only_capability;
+
+    ngx_uint_t   auth_methods;
+
+    ngx_array_t  capabilities;
+} ngx_mail_imap_srv_conf_t;
+
+
+void ngx_mail_imap_init_session(ngx_mail_session_t *s, ngx_connection_t *c);
+void ngx_mail_imap_init_protocol(ngx_event_t *rev);
+void ngx_mail_imap_auth_state(ngx_event_t *rev);
+ngx_int_t ngx_mail_imap_parse_command(ngx_mail_session_t *s);
+
+
+extern ngx_module_t  ngx_mail_imap_module;
+
+
+#endif /* _NGX_MAIL_IMAP_MODULE_H_INCLUDED_ */
--- a/src/mail/ngx_mail_pop3_handler.c	Fri Sep 14 15:04:45 2007 +0000
+++ b/src/mail/ngx_mail_pop3_handler.c	Sat Sep 15 16:51:16 2007 +0000
@@ -8,6 +8,7 @@
 #include <ngx_core.h>
 #include <ngx_event.h>
 #include <ngx_mail.h>
+#include <ngx_mail_pop3_module.h>
 
 
 static ngx_int_t ngx_mail_pop3_user(ngx_mail_session_t *s, ngx_connection_t *c);
@@ -32,10 +33,12 @@
 {
     u_char                    *p;
     ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_pop3_srv_conf_t  *pscf;
 
+    pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
 
-    if (cscf->pop3_auth_methods
+    if (pscf->auth_methods
         & (NGX_MAIL_AUTH_APOP_ENABLED|NGX_MAIL_AUTH_CRAM_MD5_ENABLED))
     {
         if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
@@ -340,12 +343,12 @@
 static ngx_int_t
 ngx_mail_pop3_capa(ngx_mail_session_t *s, ngx_connection_t *c, ngx_int_t stls)
 {
-    ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_pop3_srv_conf_t  *pscf;
 #if (NGX_MAIL_SSL)
     ngx_mail_ssl_conf_t       *sslcf;
 #endif
 
-    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+    pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
 
 #if (NGX_MAIL_SSL)
 
@@ -353,19 +356,19 @@
         sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
 
         if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
-            s->out = cscf->pop3_starttls_capability;
+            s->out = pscf->starttls_capability;
             return NGX_OK;
         }
 
         if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
-            s->out = cscf->pop3_starttls_only_capability;
+            s->out = pscf->starttls_only_capability;
             return NGX_OK;
         }
     }
 
 #endif
 
-    s->out = cscf->pop3_capability;
+    s->out = pscf->capability;
     return NGX_OK;
 }
 
@@ -394,7 +397,7 @@
 ngx_mail_pop3_apop(ngx_mail_session_t *s, ngx_connection_t *c)
 {
     ngx_str_t                 *arg;
-    ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_pop3_srv_conf_t  *pscf;
 
 #if (NGX_MAIL_SSL)
     if (ngx_mail_starttls_only(s, c)) {
@@ -406,9 +409,9 @@
         return NGX_MAIL_PARSE_INVALID_COMMAND;
     }
 
-    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+    pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
 
-    if (!(cscf->pop3_auth_methods & NGX_MAIL_AUTH_APOP_ENABLED)) {
+    if (!(pscf->auth_methods & NGX_MAIL_AUTH_APOP_ENABLED)) {
         return NGX_MAIL_PARSE_INVALID_COMMAND;
     }
 
@@ -443,7 +446,7 @@
 ngx_mail_pop3_auth(ngx_mail_session_t *s, ngx_connection_t *c)
 {
     ngx_int_t                  rc;
-    ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_pop3_srv_conf_t  *pscf;
 
 #if (NGX_MAIL_SSL)
     if (ngx_mail_starttls_only(s, c)) {
@@ -451,10 +454,10 @@
     }
 #endif
 
-    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+    pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
 
     if (s->args.nelts == 0) {
-        s->out = cscf->pop3_auth_capability;
+        s->out = pscf->auth_capability;
         s->state = 0;
 
         return NGX_OK;
@@ -482,7 +485,7 @@
 
     case NGX_MAIL_AUTH_CRAM_MD5:
 
-        if (!(cscf->pop3_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
+        if (!(pscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
             return NGX_MAIL_PARSE_INVALID_COMMAND;
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mail/ngx_mail_pop3_module.c	Sat Sep 15 16:51:16 2007 +0000
@@ -0,0 +1,263 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_mail.h>
+#include <ngx_mail_pop3_module.h>
+
+
+static void *ngx_mail_pop3_create_srv_conf(ngx_conf_t *cf);
+static char *ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+
+
+static ngx_str_t  ngx_mail_pop3_default_capabilities[] = {
+    ngx_string("TOP"),
+    ngx_string("USER"),
+    ngx_string("UIDL"),
+    ngx_null_string
+};
+
+
+static ngx_conf_bitmask_t  ngx_mail_pop3_auth_methods[] = {
+    { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
+    { ngx_string("apop"), NGX_MAIL_AUTH_APOP_ENABLED },
+    { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_str_t  ngx_mail_pop3_auth_plain_capability =
+    ngx_string("+OK methods supported:" CRLF
+               "LOGIN" CRLF
+               "PLAIN" CRLF
+               "." CRLF);
+
+
+static ngx_str_t  ngx_mail_pop3_auth_cram_md5_capability =
+    ngx_string("+OK methods supported:" CRLF
+               "LOGIN" CRLF
+               "PLAIN" CRLF
+               "CRAM-MD5" CRLF
+               "." CRLF);
+
+
+static ngx_mail_protocol_t  ngx_mail_pop3_protocol = {
+    ngx_string("pop3"),
+    { 110, 995, 0, 0 },
+    NGX_MAIL_POP3_PROTOCOL,
+
+    ngx_mail_pop3_init_session,
+    ngx_mail_pop3_init_protocol,
+    ngx_mail_pop3_parse_command,
+    ngx_mail_pop3_auth_state,
+
+    ngx_string("-ERR internal server error" CRLF)
+};
+
+
+static ngx_command_t  ngx_mail_pop3_commands[] = {
+
+    { ngx_string("pop3_capabilities"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
+      ngx_mail_capabilities,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_pop3_srv_conf_t, capabilities),
+      NULL },
+
+    { ngx_string("pop3_auth"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
+      ngx_conf_set_bitmask_slot,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_pop3_srv_conf_t, auth_methods),
+      &ngx_mail_pop3_auth_methods },
+
+      ngx_null_command
+};
+
+
+static ngx_mail_module_t  ngx_mail_pop3_module_ctx = {
+    &ngx_mail_pop3_protocol,               /* protocol */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    ngx_mail_pop3_create_srv_conf,         /* create server configuration */
+    ngx_mail_pop3_merge_srv_conf           /* merge server configuration */
+};
+
+
+ngx_module_t  ngx_mail_pop3_module = {
+    NGX_MODULE_V1,
+    &ngx_mail_pop3_module_ctx,             /* module context */
+    ngx_mail_pop3_commands,                /* module directives */
+    NGX_MAIL_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static void *
+ngx_mail_pop3_create_srv_conf(ngx_conf_t *cf)
+{
+    ngx_mail_pop3_srv_conf_t  *pscf;
+
+    pscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_pop3_srv_conf_t));
+    if (pscf == NULL) {
+        return NULL;
+    }
+
+    if (ngx_array_init(&pscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
+        != NGX_OK)
+    {
+        return NULL;
+    }
+
+    return pscf;
+}
+
+
+static char *
+ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_mail_pop3_srv_conf_t *prev = parent;
+    ngx_mail_pop3_srv_conf_t *conf = child;
+
+    u_char      *p;
+    size_t       size, stls_only_size;
+    ngx_str_t   *c, *d;
+    ngx_uint_t   i;
+
+    ngx_conf_merge_bitmask_value(conf->auth_methods,
+                                 prev->auth_methods,
+                                 (NGX_CONF_BITMASK_SET
+                                  |NGX_MAIL_AUTH_PLAIN_ENABLED));
+
+    if (conf->capabilities.nelts == 0) {
+        conf->capabilities = prev->capabilities;
+    }
+
+    if (conf->capabilities.nelts == 0) {
+
+        for (d = ngx_mail_pop3_default_capabilities; d->len; d++) {
+            c = ngx_array_push(&conf->capabilities);
+            if (c == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            *c = *d;
+        }
+    }
+
+    size = sizeof("+OK Capability list follows" CRLF) - 1
+           + sizeof("." CRLF) - 1;
+
+    stls_only_size = size + sizeof("STLS" CRLF) - 1;
+
+    c = conf->capabilities.elts;
+    for (i = 0; i < conf->capabilities.nelts; i++) {
+        size += c[i].len + sizeof(CRLF) - 1;
+
+        if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
+            continue;
+        }
+
+        stls_only_size += c[i].len + sizeof(CRLF) - 1;
+    }
+
+    if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
+        size += sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1;
+
+    } else {
+        size += sizeof("SASL LOGIN PLAIN" CRLF) - 1;
+    }
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->capability.len = size;
+    conf->capability.data = p;
+
+    p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
+                   sizeof("+OK Capability list follows" CRLF) - 1);
+
+    for (i = 0; i < conf->capabilities.nelts; i++) {
+        p = ngx_cpymem(p, c[i].data, c[i].len);
+        *p++ = CR; *p++ = LF;
+    }
+
+    if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
+        p = ngx_cpymem(p, "SASL LOGIN PLAIN CRAM-MD5" CRLF,
+                       sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1);
+
+    } else {
+        p = ngx_cpymem(p, "SASL LOGIN PLAIN" CRLF,
+                       sizeof("SASL LOGIN PLAIN" CRLF) - 1);
+    }
+
+    *p++ = '.'; *p++ = CR; *p = LF;
+
+
+    size += sizeof("STLS" CRLF) - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->starttls_capability.len = size;
+    conf->starttls_capability.data = p;
+
+    p = ngx_cpymem(p, conf->capability.data,
+                   conf->capability.len - (sizeof("." CRLF) - 1));
+
+    p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
+    *p++ = '.'; *p++ = CR; *p = LF;
+
+
+    if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
+        conf->auth_capability = ngx_mail_pop3_auth_cram_md5_capability;
+
+    } else {
+        conf->auth_capability = ngx_mail_pop3_auth_plain_capability;
+    }
+
+
+    p = ngx_palloc(cf->pool, stls_only_size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->starttls_only_capability.len = stls_only_size;
+    conf->starttls_only_capability.data = p;
+
+    p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
+                   sizeof("+OK Capability list follows" CRLF) - 1);
+
+    for (i = 0; i < conf->capabilities.nelts; i++) {
+        if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
+            continue;
+        }
+
+        p = ngx_cpymem(p, c[i].data, c[i].len);
+        *p++ = CR; *p++ = LF;
+    }
+
+    p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
+    *p++ = '.'; *p++ = CR; *p = LF;
+
+    return NGX_CONF_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mail/ngx_mail_pop3_module.h	Sat Sep 15 16:51:16 2007 +0000
@@ -0,0 +1,37 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_MAIL_POP3_MODULE_H_INCLUDED_
+#define _NGX_MAIL_POP3_MODULE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_mail.h>
+
+
+typedef struct {
+    ngx_str_t    capability;
+    ngx_str_t    starttls_capability;
+    ngx_str_t    starttls_only_capability;
+    ngx_str_t    auth_capability;
+
+    ngx_uint_t   auth_methods;
+
+    ngx_array_t  capabilities;
+} ngx_mail_pop3_srv_conf_t;
+
+
+void ngx_mail_pop3_init_session(ngx_mail_session_t *s, ngx_connection_t *c);
+void ngx_mail_pop3_init_protocol(ngx_event_t *rev);
+void ngx_mail_pop3_auth_state(ngx_event_t *rev);
+ngx_int_t ngx_mail_pop3_parse_command(ngx_mail_session_t *s);
+
+
+extern ngx_module_t  ngx_mail_pop3_module;
+
+
+#endif /* _NGX_MAIL_POP3_MODULE_H_INCLUDED_ */
--- a/src/mail/ngx_mail_proxy_module.c	Fri Sep 14 15:04:45 2007 +0000
+++ b/src/mail/ngx_mail_proxy_module.c	Sat Sep 15 16:51:16 2007 +0000
@@ -78,6 +78,8 @@
 
 
 static ngx_mail_module_t  ngx_mail_proxy_module_ctx = {
+    NULL,                                  /* protocol */
+
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */
 
--- a/src/mail/ngx_mail_smtp_handler.c	Fri Sep 14 15:04:45 2007 +0000
+++ b/src/mail/ngx_mail_smtp_handler.c	Sat Sep 15 16:51:16 2007 +0000
@@ -8,6 +8,7 @@
 #include <ngx_core.h>
 #include <ngx_event.h>
 #include <ngx_mail.h>
+#include <ngx_mail_smtp_module.h>
 
 
 static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
@@ -43,25 +44,26 @@
 {
     ngx_msec_t                 timeout;
     ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_smtp_srv_conf_t  *sscf;
 
     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+    sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
 
-    timeout = cscf->smtp_greeting_delay ? cscf->smtp_greeting_delay:
-                                          cscf->timeout;
+    timeout = sscf->greeting_delay ? sscf->greeting_delay : cscf->timeout;
     ngx_add_timer(c->read, timeout);
 
     if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
         ngx_mail_close_connection(c);
     }
 
-    if (cscf->smtp_greeting_delay) {
+    if (sscf->greeting_delay) {
          c->read->handler = ngx_mail_smtp_invalid_pipelining;
          return;
     }
 
     c->read->handler = ngx_mail_smtp_init_protocol;
 
-    s->out = cscf->smtp_greeting;
+    s->out = sscf->greeting;
 
     ngx_mail_send(c->write);
 }
@@ -73,6 +75,7 @@
     ngx_connection_t          *c;
     ngx_mail_session_t        *s;
     ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_smtp_srv_conf_t  *sscf;
 
     c = rev->data;
     s = c->data;
@@ -96,7 +99,9 @@
             return;
         }
 
-        s->out = cscf->smtp_greeting;
+        sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
+
+        s->out = sscf->greeting;
 
     } else {
 
@@ -158,16 +163,16 @@
 static ngx_int_t
 ngx_mail_smtp_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c)
 {
-    ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_smtp_srv_conf_t  *sscf;
 
     if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) {
         ngx_mail_session_internal_server_error(s);
         return NGX_ERROR;
     }
 
-    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+    sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
 
-    s->buffer = ngx_create_temp_buf(c->pool, cscf->smtp_client_buffer_size);
+    s->buffer = ngx_create_temp_buf(c->pool, sscf->client_buffer_size);
     if (s->buffer == NULL) {
         ngx_mail_session_internal_server_error(s);
         return NGX_ERROR;
@@ -313,13 +318,11 @@
 ngx_mail_smtp_helo(ngx_mail_session_t *s, ngx_connection_t *c)
 {
     ngx_str_t                 *arg;
-    ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_smtp_srv_conf_t  *sscf;
 #if (NGX_MAIL_SSL)
     ngx_mail_ssl_conf_t       *sslcf;
 #endif
 
-    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
-
     if (s->args.nelts != 1) {
         s->out.len = sizeof(smtp_invalid_argument) - 1;
         s->out.data = smtp_invalid_argument;
@@ -338,8 +341,10 @@
 
     ngx_memcpy(s->smtp_helo.data, arg[0].data, arg[0].len);
 
+    sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
+
     if (s->command == NGX_SMTP_HELO) {
-        s->out = cscf->smtp_server_name;
+        s->out = sscf->server_name;
 
     } else {
         s->esmtp = 1;
@@ -350,18 +355,18 @@
             sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
 
             if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
-                s->out = cscf->smtp_starttls_capability;
+                s->out = sscf->starttls_capability;
                 return NGX_OK;
             }
 
             if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
-                s->out = cscf->smtp_starttls_only_capability;
+                s->out = sscf->starttls_only_capability;
                 return NGX_OK;
             }
         }
 #endif
 
-        s->out = cscf->smtp_capability;
+        s->out = sscf->capability;
     }
 
     return NGX_OK;
@@ -373,6 +378,7 @@
 {
     ngx_int_t                  rc;
     ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_smtp_srv_conf_t  *sscf;
 
 #if (NGX_MAIL_SSL)
     if (ngx_mail_starttls_only(s, c)) {
@@ -409,13 +415,15 @@
 
     case NGX_MAIL_AUTH_CRAM_MD5:
 
-        cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+        sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
 
-        if (!(cscf->smtp_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
+        if (!(sscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
             return NGX_MAIL_PARSE_INVALID_COMMAND;
         }
 
         if (s->salt.data == NULL) {
+            cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
             if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
                 return NGX_ERROR;
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mail/ngx_mail_smtp_module.c	Sat Sep 15 16:51:16 2007 +0000
@@ -0,0 +1,285 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_mail.h>
+#include <ngx_mail_smtp_module.h>
+
+
+static void *ngx_mail_smtp_create_srv_conf(ngx_conf_t *cf);
+static char *ngx_mail_smtp_merge_srv_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+
+
+static ngx_conf_bitmask_t  ngx_mail_smtp_auth_methods[] = {
+    { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
+    { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
+    { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
+    { ngx_null_string, 0 }
+};
+
+
+static ngx_str_t  ngx_mail_smtp_auth_methods_names[] = {
+    ngx_string("PLAIN"),
+    ngx_string("LOGIN"),
+    ngx_null_string,  /* APOP */
+    ngx_string("CRAM-MD5")
+};
+
+
+static ngx_mail_protocol_t  ngx_mail_smtp_protocol = {
+    ngx_string("smtp"),
+    { 25, 465, 587, 0 },
+    NGX_MAIL_SMTP_PROTOCOL,
+
+    ngx_mail_smtp_init_session,
+    ngx_mail_smtp_init_protocol,
+    ngx_mail_smtp_parse_command,
+    ngx_mail_smtp_auth_state,
+
+    ngx_string("451 4.3.2 Internal server error" CRLF)
+};
+
+
+static ngx_command_t  ngx_mail_smtp_commands[] = {
+
+    { ngx_string("smtp_client_buffer"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_smtp_srv_conf_t, client_buffer_size),
+      NULL },
+
+    { ngx_string("smtp_greeting_delay"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_smtp_srv_conf_t, greeting_delay),
+      NULL },
+
+    { ngx_string("smtp_capabilities"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
+      ngx_mail_capabilities,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_smtp_srv_conf_t, capabilities),
+      NULL },
+
+    { ngx_string("smtp_auth"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
+      ngx_conf_set_bitmask_slot,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_smtp_srv_conf_t, auth_methods),
+      &ngx_mail_smtp_auth_methods },
+
+      ngx_null_command
+};
+
+
+static ngx_mail_module_t  ngx_mail_smtp_module_ctx = {
+    &ngx_mail_smtp_protocol,               /* protocol */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    ngx_mail_smtp_create_srv_conf,         /* create server configuration */
+    ngx_mail_smtp_merge_srv_conf           /* merge server configuration */
+};
+
+
+ngx_module_t  ngx_mail_smtp_module = {
+    NGX_MODULE_V1,
+    &ngx_mail_smtp_module_ctx,             /* module context */
+    ngx_mail_smtp_commands,                /* module directives */
+    NGX_MAIL_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static void *
+ngx_mail_smtp_create_srv_conf(ngx_conf_t *cf)
+{
+    ngx_mail_smtp_srv_conf_t  *sscf;
+
+    sscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_smtp_srv_conf_t));
+    if (sscf == NULL) {
+        return NULL;
+    }
+
+    sscf->client_buffer_size = NGX_CONF_UNSET_SIZE;
+    sscf->greeting_delay = NGX_CONF_UNSET_MSEC;
+
+    if (ngx_array_init(&sscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
+        != NGX_OK)
+    {
+        return NULL;
+    }
+
+    return sscf;
+}
+
+
+static char *
+ngx_mail_smtp_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_mail_smtp_srv_conf_t *prev = parent;
+    ngx_mail_smtp_srv_conf_t *conf = child;
+
+    u_char                    *p, *auth;
+    size_t                     size;
+    ngx_str_t                 *c;
+    ngx_uint_t                 i, m;
+    ngx_mail_core_srv_conf_t  *cscf;
+
+    ngx_conf_merge_size_value(conf->client_buffer_size,
+                              prev->client_buffer_size,
+                              (size_t) ngx_pagesize);
+
+    ngx_conf_merge_msec_value(conf->greeting_delay,
+                              prev->greeting_delay, 0);
+
+    ngx_conf_merge_bitmask_value(conf->auth_methods,
+                              prev->auth_methods,
+                              (NGX_CONF_BITMASK_SET
+                               |NGX_MAIL_AUTH_PLAIN_ENABLED
+                               |NGX_MAIL_AUTH_LOGIN_ENABLED));
+
+
+    cscf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_core_module);
+
+    size = sizeof("220  ESMTP ready" CRLF) - 1 + cscf->server_name.len;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->greeting.len = size;
+    conf->greeting.data = p;
+
+    *p++ = '2'; *p++ = '2'; *p++ = '0'; *p++ = ' ';
+    p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
+    ngx_memcpy(p, " ESMTP ready" CRLF, sizeof(" ESMTP ready" CRLF) - 1);
+
+
+    size = sizeof("250 " CRLF) - 1 + cscf->server_name.len;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->server_name.len = size;
+    conf->server_name.data = p;
+
+    *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
+    p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
+    *p++ = CR; *p = LF;
+
+
+    if (conf->capabilities.nelts == 0) {
+        conf->capabilities = prev->capabilities;
+    }
+
+    size = sizeof("250-") - 1 + cscf->server_name.len + sizeof(CRLF) - 1
+           + sizeof("250 AUTH") - 1 + sizeof(CRLF) - 1;
+
+    c = conf->capabilities.elts;
+    for (i = 0; i < conf->capabilities.nelts; i++) {
+        size += sizeof("250 ") - 1 + c[i].len + sizeof(CRLF) - 1;
+    }
+
+    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
+         m <<= 1, i++)
+    {
+        if (m & conf->auth_methods) {
+            size += 1 + ngx_mail_smtp_auth_methods_names[i].len;
+        }
+    }
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->capability.len = size;
+    conf->capability.data = p;
+
+    *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
+    p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
+    *p++ = CR; *p++ = LF;
+
+    for (i = 0; i < conf->capabilities.nelts; i++) {
+        *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
+        p = ngx_cpymem(p, c[i].data, c[i].len);
+        *p++ = CR; *p++ = LF;
+    }
+
+    auth = p;
+
+    *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
+    *p++ = 'A'; *p++ = 'U'; *p++ = 'T'; *p++ = 'H';
+
+    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+         m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
+         m <<= 1, i++)
+    {
+        if (m & conf->auth_methods) {
+            *p++ = ' ';
+            p = ngx_cpymem(p, ngx_mail_smtp_auth_methods_names[i].data,
+                           ngx_mail_smtp_auth_methods_names[i].len);
+        }
+    }
+
+    *p++ = CR; *p = LF;
+
+    size += sizeof("250 STARTTLS" CRLF) - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->starttls_capability.len = size;
+    conf->starttls_capability.data = p;
+
+    p = ngx_cpymem(p, conf->capability.data,
+                   conf->capability.len);
+
+    p = ngx_cpymem(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
+    *p++ = CR; *p = LF;
+
+    p = conf->starttls_capability.data
+        + (auth - conf->capability.data) + 3;
+    *p = '-';
+
+    size = (auth - conf->capability.data)
+            + sizeof("250 STARTTLS" CRLF) - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->starttls_only_capability.len = size;
+    conf->starttls_only_capability.data = p;
+
+    p = ngx_cpymem(p, conf->capability.data,
+                   auth - conf->capability.data);
+
+    ngx_memcpy(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
+
+    return NGX_CONF_OK;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mail/ngx_mail_smtp_module.h	Sat Sep 15 16:51:16 2007 +0000
@@ -0,0 +1,44 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_MAIL_SMTP_MODULE_H_INCLUDED_
+#define _NGX_MAIL_SMTP_MODULE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_mail.h>
+#include <ngx_mail_smtp_module.h>
+
+
+typedef struct {
+    ngx_msec_t   greeting_delay;
+
+    size_t       client_buffer_size;
+
+    ngx_str_t    capability;
+    ngx_str_t    starttls_capability;
+    ngx_str_t    starttls_only_capability;
+
+    ngx_str_t    server_name;
+    ngx_str_t    greeting;
+
+    ngx_uint_t   auth_methods;
+
+    ngx_array_t  capabilities;
+} ngx_mail_smtp_srv_conf_t;
+
+
+void ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c);
+void ngx_mail_smtp_init_protocol(ngx_event_t *rev);
+void ngx_mail_smtp_auth_state(ngx_event_t *rev);
+ngx_int_t ngx_mail_smtp_parse_command(ngx_mail_session_t *s);
+
+
+extern ngx_module_t  ngx_mail_smtp_module;
+
+
+#endif /* _NGX_MAIL_SMTP_MODULE_H_INCLUDED_ */
--- a/src/mail/ngx_mail_ssl_module.c	Fri Sep 14 15:04:45 2007 +0000
+++ b/src/mail/ngx_mail_ssl_module.c	Sat Sep 15 16:51:16 2007 +0000
@@ -120,6 +120,8 @@
 
 
 static ngx_mail_module_t  ngx_mail_ssl_module_ctx = {
+    NULL,                                  /* protocol */
+
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */