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, 624 insertions(+), 2811 deletions(-) [+]
line wrap: on
line diff
--- a/auto/modules
+++ b/auto/modules
@@ -308,8 +308,6 @@ fi
 
 
 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 = YES ]; then
 
     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
+++ b/auto/options
@@ -81,6 +81,9 @@ HTTP_STUB_STATUS=NO
 
 MAIL=NO
 MAIL_SSL=NO
+MAIL_POP3=YES
+MAIL_IMAP=YES
+MAIL_SMTP=YES
 
 NGX_ADDONS=
 
@@ -190,6 +193,9 @@ do
         # 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
+++ b/auto/sources
@@ -423,11 +423,23 @@ MAIL_MODULES="ngx_mail_module ngx_mail_c
 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
+++ b/src/mail/ngx_mail.c
@@ -185,6 +185,8 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma
 
         /* 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 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma
 
             /* 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 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma
         }
     }
 
-    /* mail{}'s cf->ctx was needed while the configuration merging */
-
     *cf = pcf;
 
 
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -73,57 +73,27 @@ typedef struct {
 #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 @@ typedef struct {
 
     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 @@ typedef struct {
 
     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 @@ typedef struct {
 #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 @@ typedef struct {
 #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 @@ ngx_int_t ngx_mail_starttls_only(ngx_mai
 
 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_login_password(n
 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 @@ void ngx_mail_session_internal_server_er
 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
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -111,6 +111,8 @@ static ngx_command_t  ngx_mail_auth_http
 
 
 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 @@ ngx_module_t  ngx_mail_auth_http_module 
 };
 
 
-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_auth_http_me
 
 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 @@ ngx_mail_auth_http_process_headers(ngx_m
                 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 @@ ngx_mail_auth_sleep_handler(ngx_event_t 
             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 @@ ngx_mail_auth_sleep_handler(ngx_event_t 
             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 @@ static ngx_buf_t *
 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 @@ ngx_mail_auth_http_create_request(ngx_ma
         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 @@ ngx_mail_auth_http_create_request(ngx_ma
           + 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 @@ ngx_mail_auth_http_create_request(ngx_ma
 
     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
+++ b/src/mail/ngx_mail_core_module.c
@@ -18,90 +18,10 @@ static char *ngx_mail_core_server(ngx_co
     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 @@ static ngx_command_t  ngx_mail_core_comm
     { 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 @@ static ngx_command_t  ngx_mail_core_comm
       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 @@ static ngx_command_t  ngx_mail_core_comm
       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 @@ ngx_mail_core_create_srv_conf(ngx_conf_t
         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_merge_srv_conf(ngx_conf_t 
     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 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         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_server(ngx_conf_t *cf, ngx
     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 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx
     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 @@ ngx_mail_core_server(ngx_conf_t *cf, ngx
 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 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx
     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 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx
 
 
 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
+++ b/src/mail/ngx_mail_handler.c
@@ -18,34 +18,6 @@ static void ngx_mail_ssl_handshake_handl
 #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 @@ ngx_mail_ssl_init_connection(ngx_ssl_t *
 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 @@ ngx_mail_init_session(ngx_connection_t *
 
     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 @@ ngx_mail_init_session(ngx_connection_t *
 
     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_mail_send(ngx_event_t *wev)
 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 @@ ngx_mail_read_command(ngx_mail_session_t
         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 @@ ngx_mail_auth(ngx_mail_session_t *s, ngx
 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
+++ b/src/mail/ngx_mail_imap_handler.c
@@ -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_mail_imap_init_protocol(ngx_event_t 
 {
     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 @@ ngx_mail_imap_init_protocol(ngx_event_t 
             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_mail_imap_authenticate(ngx_mail_sess
 {
     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 @@ ngx_mail_imap_authenticate(ngx_mail_sess
 
     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 @@ ngx_mail_imap_authenticate(ngx_mail_sess
 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 @@ ngx_mail_imap_capability(ngx_mail_sessio
         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;
 }
copy from src/mail/ngx_mail_core_module.c
copy to src/mail/ngx_mail_imap_module.c
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_imap_module.c
@@ -8,37 +8,15 @@
 #include <ngx_core.h>
 #include <ngx_event.h>
 #include <ngx_mail.h>
-
-
-static void *ngx_mail_core_create_main_conf(ngx_conf_t *cf);
-static void *ngx_mail_core_create_srv_conf(ngx_conf_t *cf);
-static char *ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
-    void *child);
-static char *ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
-    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,
-    void *conf);
+#include <ngx_mail_imap_module.h>
 
 
-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 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_pop3_default_capabilities[] = {
-    ngx_string("TOP"),
-    ngx_string("USER"),
-    ngx_string("UIDL"),
-    ngx_null_string
-};
-
-
-static ngx_str_t  ngx_imap_default_capabilities[] = {
+static ngx_str_t  ngx_mail_imap_default_capabilities[] = {
     ngx_string("IMAP4"),
     ngx_string("IMAP4rev1"),
     ngx_string("UIDPLUS"),
@@ -46,15 +24,7 @@ static ngx_str_t  ngx_imap_default_capab
 };
 
 
-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[] = {
+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 },
@@ -62,15 +32,7 @@ static ngx_conf_bitmask_t  ngx_imap_auth
 };
 
 
-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[] = {
+static ngx_str_t  ngx_mail_imap_auth_methods_names[] = {
     ngx_string("AUTH=PLAIN"),
     ngx_string("AUTH=LOGIN"),
     ngx_null_string,  /* APOP */
@@ -78,161 +40,62 @@ static ngx_str_t  ngx_imap_auth_methods_
 };
 
 
-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_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_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"),
-      NGX_MAIL_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
-      ngx_mail_core_server,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("listen"),
-      NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
-      ngx_mail_core_listen,
-      0,
-      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 },
+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_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),
-      NULL },
-
-    { ngx_string("so_keepalive"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, so_keepalive),
-      NULL },
-
-    { ngx_string("timeout"),
-      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, 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),
+      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_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,
+      ngx_mail_capabilities,
       NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, server_name),
+      offsetof(ngx_mail_imap_srv_conf_t, capabilities),
       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 },
+      offsetof(ngx_mail_imap_srv_conf_t, auth_methods),
+      &ngx_mail_imap_auth_methods },
 
       ngx_null_command
 };
 
 
-static ngx_mail_module_t  ngx_mail_core_module_ctx = {
-    ngx_mail_core_create_main_conf,        /* create main configuration */
+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_core_create_srv_conf,         /* create server configuration */
-    ngx_mail_core_merge_srv_conf           /* merge server configuration */
+    ngx_mail_imap_create_srv_conf,         /* create server configuration */
+    ngx_mail_imap_merge_srv_conf           /* merge server configuration */
 };
 
 
-ngx_module_t  ngx_mail_core_module = {
+ngx_module_t  ngx_mail_imap_module = {
     NGX_MODULE_V1,
-    &ngx_mail_core_module_ctx,             /* module context */
-    ngx_mail_core_commands,                /* module directives */
+    &ngx_mail_imap_module_ctx,             /* module context */
+    ngx_mail_imap_commands,                /* module directives */
     NGX_MAIL_MODULE,                       /* module type */
     NULL,                                  /* init master */
     NULL,                                  /* init module */
@@ -246,258 +109,56 @@ ngx_module_t  ngx_mail_core_module = {
 
 
 static void *
-ngx_mail_core_create_main_conf(ngx_conf_t *cf)
+ngx_mail_imap_create_srv_conf(ngx_conf_t *cf)
 {
-    ngx_mail_core_main_conf_t  *cmcf;
-
-    cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t));
-    if (cmcf == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    if (ngx_array_init(&cmcf->servers, cf->pool, 4,
-                       sizeof(ngx_mail_core_srv_conf_t *))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
+    ngx_mail_imap_srv_conf_t  *iscf;
 
-    if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-    return cmcf;
-}
-
-
-static void *
-ngx_mail_core_create_srv_conf(ngx_conf_t *cf)
-{
-    ngx_mail_core_srv_conf_t  *cscf;
-
-    cscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_srv_conf_t));
-    if (cscf == NULL) {
+    iscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_imap_srv_conf_t));
+    if (iscf == NULL) {
         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;
+    iscf->client_buffer_size = NGX_CONF_UNSET_SIZE;
 
-    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))
+    if (ngx_array_init(&iscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
         != NGX_OK)
     {
         return NULL;
     }
 
-    return cscf;
+    return iscf;
 }
 
 
 static char *
-ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
+ngx_mail_imap_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
 {
-    ngx_mail_core_srv_conf_t *prev = parent;
-    ngx_mail_core_srv_conf_t *conf = child;
+    ngx_mail_imap_srv_conf_t *prev = parent;
+    ngx_mail_imap_srv_conf_t *conf = child;
 
     u_char      *p, *auth;
-    size_t       size, stls_only_size;
+    size_t       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,
+    ngx_conf_merge_size_value(conf->client_buffer_size,
+                              prev->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_merge_bitmask_value(conf->auth_methods,
+                              prev->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, "");
-
-    if (conf->server_name.len == 0) {
-        conf->server_name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN);
-        if (conf->server_name.data == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN)
-            == -1)
-        {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 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;
+    if (conf->capabilities.nelts == 0) {
+        conf->capabilities = prev->capabilities;
     }
 
-    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->capabilities.nelts == 0) {
 
-    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);
+        for (d = ngx_mail_imap_default_capabilities; d->len; d++) {
+            c = ngx_array_push(&conf->capabilities);
             if (c == NULL) {
                 return NGX_CONF_ERROR;
             }
@@ -508,8 +169,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
 
     size = sizeof("* CAPABILITY" CRLF) - 1;
 
-    c = conf->imap_capabilities.elts;
-    for (i = 0; i < conf->imap_capabilities.nelts; i++) {
+    c = conf->capabilities.elts;
+    for (i = 0; i < conf->capabilities.nelts; i++) {
         size += 1 + c[i].len;
     }
 
@@ -517,8 +178,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
          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;
+        if (m & conf->auth_methods) {
+            size += 1 + ngx_mail_imap_auth_methods_names[i].len;
         }
     }
 
@@ -527,12 +188,12 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
-    conf->imap_capability.len = size;
-    conf->imap_capability.data = p;
+    conf->capability.len = size;
+    conf->capability.data = p;
 
     p = ngx_cpymem(p, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
 
-    for (i = 0; i < conf->imap_capabilities.nelts; i++) {
+    for (i = 0; i < conf->capabilities.nelts; i++) {
         *p++ = ' ';
         p = ngx_cpymem(p, c[i].data, c[i].len);
     }
@@ -543,10 +204,10 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
          m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
          m <<= 1, i++)
     {
-        if (m & conf->imap_auth_methods) {
+        if (m & conf->auth_methods) {
             *p++ = ' ';
-            p = ngx_cpymem(p, ngx_imap_auth_methods_names[i].data,
-                           ngx_imap_auth_methods_names[i].len);
+            p = ngx_cpymem(p, ngx_mail_imap_auth_methods_names[i].data,
+                           ngx_mail_imap_auth_methods_names[i].len);
         }
     }
 
@@ -560,16 +221,16 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
-    conf->imap_starttls_capability.len = size;
-    conf->imap_starttls_capability.data = p;
+    conf->starttls_capability.len = size;
+    conf->starttls_capability.data = p;
 
-    p = ngx_cpymem(p, conf->imap_capability.data,
-                   conf->imap_capability.len - (sizeof(CRLF) - 1));
+    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->imap_capability.data) + sizeof(CRLF) - 1
+    size = (auth - conf->capability.data) + sizeof(CRLF) - 1
             + sizeof(" STARTTLS LOGINDISABLED") - 1;
 
     p = ngx_palloc(cf->pool, size);
@@ -577,308 +238,14 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
-    conf->imap_starttls_only_capability.len = size;
-    conf->imap_starttls_only_capability.data = p;
+    conf->starttls_only_capability.len = size;
+    conf->starttls_only_capability.data = p;
 
-    p = ngx_cpymem(p, conf->imap_capability.data,
-                   auth - conf->imap_capability.data);
+    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;
 
-
-    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;
 }
-
-
-static char *
-ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    char                       *rv;
-    void                       *mconf;
-    ngx_uint_t                  m;
-    ngx_conf_t                  pcf;
-    ngx_mail_module_t          *module;
-    ngx_mail_conf_ctx_t        *ctx, *mail_ctx;
-    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;
-    }
-
-    mail_ctx = cf->ctx;
-    ctx->main_conf = mail_ctx->main_conf;
-
-    /* the server{}'s srv_conf */
-
-    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
-    if (ctx->srv_conf == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    for (m = 0; ngx_modules[m]; m++) {
-        if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
-            continue;
-        }
-
-        module = ngx_modules[m]->ctx;
-
-        if (module->create_srv_conf) {
-            mconf = module->create_srv_conf(cf);
-            if (mconf == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
-        }
-    }
-
-    /* the server configuration context */
-
-    cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
-    cscf->ctx = ctx;
-
-    cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
-
-    cscfp = ngx_array_push(&cmcf->servers);
-    if (cscfp == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    *cscfp = cscf;
-
-
-    /* parse inside server{} */
-
-    pcf = *cf;
-    cf->ctx = ctx;
-    cf->cmd_type = NGX_MAIL_SRV_CONF;
-
-    rv = ngx_conf_parse(cf, NULL);
-
-    *cf = pcf;
-
-    return rv;
-}
-
-
-/* AF_INET only */
-
-static char *
-ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_str_t                  *value;
-    ngx_url_t                   u;
-    ngx_uint_t                  i;
-    ngx_mail_listen_t          *imls;
-    ngx_mail_core_main_conf_t  *cmcf;
-
-    value = cf->args->elts;
-
-    ngx_memzero(&u, sizeof(ngx_url_t));
-
-    u.url = value[1];
-    u.listen = 1;
-
-    if (ngx_parse_url(cf, &u) != NGX_OK) {
-        if (u.err) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "%s in \"%V\" of the \"listen\" directive",
-                               u.err, &u.url);
-        }
-
-        return NGX_CONF_ERROR;
-    }
-
-    cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);
-
-    imls = cmcf->listen.elts;
-
-    for (i = 0; i < cmcf->listen.nelts; i++) {
-
-        if (imls[i].addr != u.addr.in_addr || imls[i].port != u.port) {
-            continue;
-        }
-
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "duplicate \"%V\" address and port pair", &u.url);
-        return NGX_CONF_ERROR;
-    }
-
-    imls = ngx_array_push(&cmcf->listen);
-    if (imls == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    ngx_memzero(imls, sizeof(ngx_mail_listen_t));
-
-    imls->addr = u.addr.in_addr;
-    imls->port = u.port;
-    imls->family = AF_INET;
-    imls->ctx = cf->ctx;
-
-    if (cf->args->nelts == 2) {
-        return NGX_CONF_OK;
-    }
-
-    if (ngx_strcmp(value[2].data, "bind") == 0) {
-        imls->bind = 1;
-        return NGX_CONF_OK;
-    }
-
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "the invalid \"%V\" parameter", &value[2]);
-    return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_mail_core_capability(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    char  *p = conf;
-
-    ngx_str_t    *c, *value;
-    ngx_uint_t    i;
-    ngx_array_t  *a;
-
-    a = (ngx_array_t *) (p + cmd->offset);
-
-    value = cf->args->elts;
-
-    for (i = 1; i < cf->args->nelts; i++) {
-        c = ngx_array_push(a);
-        if (c == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        *c = value[i];
-    }
-
-    return NGX_CONF_OK;
-}
new file mode 100644
--- /dev/null
+++ b/src/mail/ngx_mail_imap_module.h
@@ -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
+++ b/src/mail/ngx_mail_pop3_handler.c
@@ -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 @@ ngx_mail_pop3_init_session(ngx_mail_sess
 {
     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 @@ ngx_mail_pop3_pass(ngx_mail_session_t *s
 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 @@ ngx_mail_pop3_capa(ngx_mail_session_t *s
         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 @@ static ngx_int_t
 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 @@ ngx_mail_pop3_apop(ngx_mail_session_t *s
         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 @@ static ngx_int_t
 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 @@ ngx_mail_pop3_auth(ngx_mail_session_t *s
     }
 #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 @@ ngx_mail_pop3_auth(ngx_mail_session_t *s
 
     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;
         }
 
copy from src/mail/ngx_mail_core_module.c
copy to src/mail/ngx_mail_pop3_module.c
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_pop3_module.c
@@ -8,29 +8,15 @@
 #include <ngx_core.h>
 #include <ngx_event.h>
 #include <ngx_mail.h>
+#include <ngx_mail_pop3_module.h>
 
 
-static void *ngx_mail_core_create_main_conf(ngx_conf_t *cf);
-static void *ngx_mail_core_create_srv_conf(ngx_conf_t *cf);
-static char *ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
+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 char *ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
-    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,
-    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[] = {
+static ngx_str_t  ngx_mail_pop3_default_capabilities[] = {
     ngx_string("TOP"),
     ngx_string("USER"),
     ngx_string("UIDL"),
@@ -38,15 +24,7 @@ static ngx_str_t  ngx_pop3_default_capab
 };
 
 
-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[] = {
+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 },
@@ -54,46 +32,14 @@ static ngx_conf_bitmask_t  ngx_pop3_auth
 };
 
 
-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 =
+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_pop3_auth_cram_md5_capability =
+static ngx_str_t  ngx_mail_pop3_auth_cram_md5_capability =
     ngx_string("+OK methods supported:" CRLF
                "LOGIN" CRLF
                "PLAIN" CRLF
@@ -101,138 +47,55 @@ static ngx_str_t  ngx_pop3_auth_cram_md5
                "." CRLF);
 
 
-
-static ngx_command_t  ngx_mail_core_commands[] = {
-
-    { ngx_string("server"),
-      NGX_MAIL_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
-      ngx_mail_core_server,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("listen"),
-      NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
-      ngx_mail_core_listen,
-      0,
-      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 },
+static ngx_mail_protocol_t  ngx_mail_pop3_protocol = {
+    ngx_string("pop3"),
+    { 110, 995, 0, 0 },
+    NGX_MAIL_POP3_PROTOCOL,
 
-    { 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_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_mail_pop3_init_session,
+    ngx_mail_pop3_init_protocol,
+    ngx_mail_pop3_parse_command,
+    ngx_mail_pop3_auth_state,
 
-    { 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),
-      NULL },
+    ngx_string("-ERR internal server error" CRLF)
+};
 
-    { ngx_string("so_keepalive"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, so_keepalive),
-      NULL },
 
-    { ngx_string("timeout"),
-      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, timeout),
-      NULL },
+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_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_capabilities,
       NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, smtp_capabilities),
+      offsetof(ngx_mail_pop3_srv_conf_t, capabilities),
       NULL },
 
-    { ngx_string("server_name"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
-      ngx_conf_set_str_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      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 },
+      offsetof(ngx_mail_pop3_srv_conf_t, auth_methods),
+      &ngx_mail_pop3_auth_methods },
 
       ngx_null_command
 };
 
 
-static ngx_mail_module_t  ngx_mail_core_module_ctx = {
-    ngx_mail_core_create_main_conf,        /* create main configuration */
+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_core_create_srv_conf,         /* create server configuration */
-    ngx_mail_core_merge_srv_conf           /* merge server configuration */
+    ngx_mail_pop3_create_srv_conf,         /* create server configuration */
+    ngx_mail_pop3_merge_srv_conf           /* merge server configuration */
 };
 
 
-ngx_module_t  ngx_mail_core_module = {
+ngx_module_t  ngx_mail_pop3_module = {
     NGX_MODULE_V1,
-    &ngx_mail_core_module_ctx,             /* module context */
-    ngx_mail_core_commands,                /* module directives */
+    &ngx_mail_pop3_module_ctx,             /* module context */
+    ngx_mail_pop3_commands,                /* module directives */
     NGX_MAIL_MODULE,                       /* module type */
     NULL,                                  /* init master */
     NULL,                                  /* init module */
@@ -246,142 +109,49 @@ ngx_module_t  ngx_mail_core_module = {
 
 
 static void *
-ngx_mail_core_create_main_conf(ngx_conf_t *cf)
+ngx_mail_pop3_create_srv_conf(ngx_conf_t *cf)
 {
-    ngx_mail_core_main_conf_t  *cmcf;
-
-    cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t));
-    if (cmcf == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    if (ngx_array_init(&cmcf->servers, cf->pool, 4,
-                       sizeof(ngx_mail_core_srv_conf_t *))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
+    ngx_mail_pop3_srv_conf_t  *pscf;
 
-    if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-    return cmcf;
-}
-
-
-static void *
-ngx_mail_core_create_srv_conf(ngx_conf_t *cf)
-{
-    ngx_mail_core_srv_conf_t  *cscf;
-
-    cscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_srv_conf_t));
-    if (cscf == NULL) {
+    pscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_pop3_srv_conf_t));
+    if (pscf == NULL) {
         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;
-
-    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))
+    if (ngx_array_init(&pscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
         != NGX_OK)
     {
         return NULL;
     }
 
-    return cscf;
+    return pscf;
 }
 
 
 static char *
-ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
+ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
 {
-    ngx_mail_core_srv_conf_t *prev = parent;
-    ngx_mail_core_srv_conf_t *conf = child;
+    ngx_mail_pop3_srv_conf_t *prev = parent;
+    ngx_mail_pop3_srv_conf_t *conf = child;
 
-    u_char      *p, *auth;
+    u_char      *p;
     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_uint_t   i;
 
-    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, "");
+    ngx_conf_merge_bitmask_value(conf->auth_methods,
+                                 prev->auth_methods,
+                                 (NGX_CONF_BITMASK_SET
+                                  |NGX_MAIL_AUTH_PLAIN_ENABLED));
 
-    if (conf->server_name.len == 0) {
-        conf->server_name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN);
-        if (conf->server_name.data == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN)
-            == -1)
-        {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
-                               "gethostname() failed");
-            return NGX_CONF_ERROR;
-        }
-
-        conf->server_name.len = ngx_strlen(conf->server_name.data);
+    if (conf->capabilities.nelts == 0) {
+        conf->capabilities = prev->capabilities;
     }
 
-
-    if (conf->pop3_capabilities.nelts == 0) {
-        conf->pop3_capabilities = prev->pop3_capabilities;
-    }
+    if (conf->capabilities.nelts == 0) {
 
-    if (conf->pop3_capabilities.nelts == 0) {
-
-        for (d = ngx_pop3_default_capabilities; d->len; d++) {
-            c = ngx_array_push(&conf->pop3_capabilities);
+        for (d = ngx_mail_pop3_default_capabilities; d->len; d++) {
+            c = ngx_array_push(&conf->capabilities);
             if (c == NULL) {
                 return NGX_CONF_ERROR;
             }
@@ -395,8 +165,8 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
 
     stls_only_size = size + sizeof("STLS" CRLF) - 1;
 
-    c = conf->pop3_capabilities.elts;
-    for (i = 0; i < conf->pop3_capabilities.nelts; i++) {
+    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) {
@@ -406,7 +176,7 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         stls_only_size += c[i].len + sizeof(CRLF) - 1;
     }
 
-    if (conf->pop3_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
+    if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
         size += sizeof("SASL LOGIN PLAIN CRAM-MD5" CRLF) - 1;
 
     } else {
@@ -418,18 +188,18 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
-    conf->pop3_capability.len = size;
-    conf->pop3_capability.data = p;
+    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->pop3_capabilities.nelts; i++) {
+    for (i = 0; i < conf->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) {
+    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);
 
@@ -448,21 +218,21 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
-    conf->pop3_starttls_capability.len = size;
-    conf->pop3_starttls_capability.data = p;
+    conf->starttls_capability.len = size;
+    conf->starttls_capability.data = p;
 
-    p = ngx_cpymem(p, conf->pop3_capability.data,
-                   conf->pop3_capability.len - (sizeof("." CRLF) - 1));
+    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->pop3_auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
-        conf->pop3_auth_capability = ngx_pop3_auth_cram_md5_capability;
+    if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
+        conf->auth_capability = ngx_mail_pop3_auth_cram_md5_capability;
 
     } else {
-        conf->pop3_auth_capability = ngx_pop3_auth_plain_capability;
+        conf->auth_capability = ngx_mail_pop3_auth_plain_capability;
     }
 
 
@@ -471,13 +241,13 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
-    conf->pop3_starttls_only_capability.len = stls_only_size;
-    conf->pop3_starttls_only_capability.data = p;
+    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->pop3_capabilities.nelts; i++) {
+    for (i = 0; i < conf->capabilities.nelts; i++) {
         if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
             continue;
         }
@@ -489,396 +259,5 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
     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) {
-        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;
 }
-
-
-static char *
-ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    char                       *rv;
-    void                       *mconf;
-    ngx_uint_t                  m;
-    ngx_conf_t                  pcf;
-    ngx_mail_module_t          *module;
-    ngx_mail_conf_ctx_t        *ctx, *mail_ctx;
-    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;
-    }
-
-    mail_ctx = cf->ctx;
-    ctx->main_conf = mail_ctx->main_conf;
-
-    /* the server{}'s srv_conf */
-
-    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
-    if (ctx->srv_conf == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    for (m = 0; ngx_modules[m]; m++) {
-        if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
-            continue;
-        }
-
-        module = ngx_modules[m]->ctx;
-
-        if (module->create_srv_conf) {
-            mconf = module->create_srv_conf(cf);
-            if (mconf == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
-        }
-    }
-
-    /* the server configuration context */
-
-    cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
-    cscf->ctx = ctx;
-
-    cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
-
-    cscfp = ngx_array_push(&cmcf->servers);
-    if (cscfp == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    *cscfp = cscf;
-
-
-    /* parse inside server{} */
-
-    pcf = *cf;
-    cf->ctx = ctx;
-    cf->cmd_type = NGX_MAIL_SRV_CONF;
-
-    rv = ngx_conf_parse(cf, NULL);
-
-    *cf = pcf;
-
-    return rv;
-}
-
-
-/* AF_INET only */
-
-static char *
-ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_str_t                  *value;
-    ngx_url_t                   u;
-    ngx_uint_t                  i;
-    ngx_mail_listen_t          *imls;
-    ngx_mail_core_main_conf_t  *cmcf;
-
-    value = cf->args->elts;
-
-    ngx_memzero(&u, sizeof(ngx_url_t));
-
-    u.url = value[1];
-    u.listen = 1;
-
-    if (ngx_parse_url(cf, &u) != NGX_OK) {
-        if (u.err) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "%s in \"%V\" of the \"listen\" directive",
-                               u.err, &u.url);
-        }
-
-        return NGX_CONF_ERROR;
-    }
-
-    cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);
-
-    imls = cmcf->listen.elts;
-
-    for (i = 0; i < cmcf->listen.nelts; i++) {
-
-        if (imls[i].addr != u.addr.in_addr || imls[i].port != u.port) {
-            continue;
-        }
-
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "duplicate \"%V\" address and port pair", &u.url);
-        return NGX_CONF_ERROR;
-    }
-
-    imls = ngx_array_push(&cmcf->listen);
-    if (imls == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    ngx_memzero(imls, sizeof(ngx_mail_listen_t));
-
-    imls->addr = u.addr.in_addr;
-    imls->port = u.port;
-    imls->family = AF_INET;
-    imls->ctx = cf->ctx;
-
-    if (cf->args->nelts == 2) {
-        return NGX_CONF_OK;
-    }
-
-    if (ngx_strcmp(value[2].data, "bind") == 0) {
-        imls->bind = 1;
-        return NGX_CONF_OK;
-    }
-
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "the invalid \"%V\" parameter", &value[2]);
-    return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_mail_core_capability(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    char  *p = conf;
-
-    ngx_str_t    *c, *value;
-    ngx_uint_t    i;
-    ngx_array_t  *a;
-
-    a = (ngx_array_t *) (p + cmd->offset);
-
-    value = cf->args->elts;
-
-    for (i = 1; i < cf->args->nelts; i++) {
-        c = ngx_array_push(a);
-        if (c == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        *c = value[i];
-    }
-
-    return NGX_CONF_OK;
-}
new file mode 100644
--- /dev/null
+++ b/src/mail/ngx_mail_pop3_module.h
@@ -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
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -78,6 +78,8 @@ static ngx_command_t  ngx_mail_proxy_com
 
 
 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
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -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_mail_smtp_init_session(ngx_mail_sess
 {
     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_mail_smtp_invalid_pipelining(ngx_eve
     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 @@ ngx_mail_smtp_invalid_pipelining(ngx_eve
             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 @@ ngx_mail_smtp_init_protocol(ngx_event_t 
 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 @@ static ngx_int_t
 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_mail_smtp_helo(ngx_mail_session_t *s
 
     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 @@ ngx_mail_smtp_helo(ngx_mail_session_t *s
             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_mail_smtp_auth(ngx_mail_session_t *s
 {
     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 @@ ngx_mail_smtp_auth(ngx_mail_session_t *s
 
     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;
             }
copy from src/mail/ngx_mail_core_module.c
copy to src/mail/ngx_mail_smtp_module.c
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_smtp_module.c
@@ -8,53 +8,15 @@
 #include <ngx_core.h>
 #include <ngx_event.h>
 #include <ngx_mail.h>
-
-
-static void *ngx_mail_core_create_main_conf(ngx_conf_t *cf);
-static void *ngx_mail_core_create_srv_conf(ngx_conf_t *cf);
-static char *ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
-    void *child);
-static char *ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
-    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,
-    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 }
-};
+#include <ngx_mail_smtp_module.h>
 
 
-static ngx_str_t  ngx_pop3_default_capabilities[] = {
-    ngx_string("TOP"),
-    ngx_string("USER"),
-    ngx_string("UIDL"),
-    ngx_null_string
-};
+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_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[] = {
+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 },
@@ -62,23 +24,7 @@ static ngx_conf_bitmask_t  ngx_imap_auth
 };
 
 
-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[] = {
+static ngx_str_t  ngx_mail_smtp_auth_methods_names[] = {
     ngx_string("PLAIN"),
     ngx_string("LOGIN"),
     ngx_null_string,  /* APOP */
@@ -86,153 +32,69 @@ static ngx_str_t  ngx_smtp_auth_methods_
 };
 
 
-static ngx_str_t  ngx_pop3_auth_plain_capability =
-    ngx_string("+OK methods supported:" CRLF
-               "LOGIN" CRLF
-               "PLAIN" CRLF
-               "." CRLF);
-
+static ngx_mail_protocol_t  ngx_mail_smtp_protocol = {
+    ngx_string("smtp"),
+    { 25, 465, 587, 0 },
+    NGX_MAIL_SMTP_PROTOCOL,
 
-static ngx_str_t  ngx_pop3_auth_cram_md5_capability =
-    ngx_string("+OK methods supported:" CRLF
-               "LOGIN" CRLF
-               "PLAIN" CRLF
-               "CRAM-MD5" CRLF
-               "." CRLF);
+    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_core_commands[] = {
-
-    { ngx_string("server"),
-      NGX_MAIL_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
-      ngx_mail_core_server,
-      0,
-      0,
-      NULL },
-
-    { ngx_string("listen"),
-      NGX_MAIL_SRV_CONF|NGX_CONF_TAKE12,
-      ngx_mail_core_listen,
-      0,
-      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_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, imap_client_buffer_size),
-      NULL },
+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_core_srv_conf_t, smtp_client_buffer_size),
+      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_core_srv_conf_t, smtp_greeting_delay),
-      NULL },
-
-    { ngx_string("so_keepalive"),
-      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
-      ngx_conf_set_flag_slot,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      offsetof(ngx_mail_core_srv_conf_t, so_keepalive),
-      NULL },
-
-    { ngx_string("timeout"),
-      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, 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),
+      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_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,
-      NGX_MAIL_SRV_CONF_OFFSET,
-      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_capabilities,
       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 },
+      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_core_srv_conf_t, smtp_auth_methods),
-      &ngx_smtp_auth_methods },
+      offsetof(ngx_mail_smtp_srv_conf_t, auth_methods),
+      &ngx_mail_smtp_auth_methods },
 
       ngx_null_command
 };
 
 
-static ngx_mail_module_t  ngx_mail_core_module_ctx = {
-    ngx_mail_core_create_main_conf,        /* create main configuration */
+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_core_create_srv_conf,         /* create server configuration */
-    ngx_mail_core_merge_srv_conf           /* merge server configuration */
+    ngx_mail_smtp_create_srv_conf,         /* create server configuration */
+    ngx_mail_smtp_merge_srv_conf           /* merge server configuration */
 };
 
 
-ngx_module_t  ngx_mail_core_module = {
+ngx_module_t  ngx_mail_smtp_module = {
     NGX_MODULE_V1,
-    &ngx_mail_core_module_ctx,             /* module context */
-    ngx_mail_core_commands,                /* module directives */
+    &ngx_mail_smtp_module_ctx,             /* module context */
+    ngx_mail_smtp_commands,                /* module directives */
     NGX_MAIL_MODULE,                       /* module type */
     NULL,                                  /* init master */
     NULL,                                  /* init module */
@@ -246,279 +108,104 @@ ngx_module_t  ngx_mail_core_module = {
 
 
 static void *
-ngx_mail_core_create_main_conf(ngx_conf_t *cf)
+ngx_mail_smtp_create_srv_conf(ngx_conf_t *cf)
 {
-    ngx_mail_core_main_conf_t  *cmcf;
-
-    cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t));
-    if (cmcf == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    if (ngx_array_init(&cmcf->servers, cf->pool, 4,
-                       sizeof(ngx_mail_core_srv_conf_t *))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
+    ngx_mail_smtp_srv_conf_t  *sscf;
 
-    if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t))
-        != NGX_OK)
-    {
-        return NGX_CONF_ERROR;
-    }
-
-    return cmcf;
-}
-
-
-static void *
-ngx_mail_core_create_srv_conf(ngx_conf_t *cf)
-{
-    ngx_mail_core_srv_conf_t  *cscf;
-
-    cscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_srv_conf_t));
-    if (cscf == NULL) {
+    sscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_smtp_srv_conf_t));
+    if (sscf == NULL) {
         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;
+    sscf->client_buffer_size = NGX_CONF_UNSET_SIZE;
+    sscf->greeting_delay = NGX_CONF_UNSET_MSEC;
 
-    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))
+    if (ngx_array_init(&sscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
         != NGX_OK)
     {
         return NULL;
     }
 
-    return cscf;
+    return sscf;
 }
 
 
 static char *
-ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
+ngx_mail_smtp_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
 {
-    ngx_mail_core_srv_conf_t *prev = parent;
-    ngx_mail_core_srv_conf_t *conf = child;
+    ngx_mail_smtp_srv_conf_t *prev = parent;
+    ngx_mail_smtp_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;
+    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->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,
+    ngx_conf_merge_size_value(conf->client_buffer_size,
+                              prev->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_msec_value(conf->greeting_delay,
+                              prev->greeting_delay, 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_merge_bitmask_value(conf->auth_methods,
+                              prev->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, "");
-
-    if (conf->server_name.len == 0) {
-        conf->server_name.data = ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN);
-        if (conf->server_name.data == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        if (gethostname((char *) conf->server_name.data, NGX_MAXHOSTNAMELEN)
-            == -1)
-        {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 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) {
+    cscf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_core_module);
 
-        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;
-    }
+    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->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;
-    }
+    conf->greeting.len = size;
+    conf->greeting.data = p;
 
-    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;
+    *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("STLS" 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->pop3_starttls_capability.len = size;
-    conf->pop3_starttls_capability.data = p;
+    conf->server_name.len = size;
+    conf->server_name.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;
+    *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->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;
+    if (conf->capabilities.nelts == 0) {
+        conf->capabilities = prev->capabilities;
     }
 
-    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;
-
+    size = sizeof("250-") - 1 + cscf->server_name.len + sizeof(CRLF) - 1
+           + sizeof("250 AUTH") - 1 + sizeof(CRLF) - 1;
 
-    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;
+    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->imap_auth_methods) {
-            size += 1 + ngx_imap_auth_methods_names[i].len;
+        if (m & conf->auth_methods) {
+            size += 1 + ngx_mail_smtp_auth_methods_names[i].len;
         }
     }
 
@@ -527,130 +214,14 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         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;
+    conf->capability.len = size;
+    conf->capability.data = p;
 
     *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
-    p = ngx_cpymem(p, conf->server_name.data, conf->server_name.len);
+    p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
     *p++ = CR; *p++ = LF;
 
-    for (i = 0; i < conf->smtp_capabilities.nelts; i++) {
+    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;
@@ -665,10 +236,10 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
          m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
          m <<= 1, i++)
     {
-        if (m & conf->smtp_auth_methods) {
+        if (m & conf->auth_methods) {
             *p++ = ' ';
-            p = ngx_cpymem(p, ngx_smtp_auth_methods_names[i].data,
-                           ngx_smtp_auth_methods_names[i].len);
+            p = ngx_cpymem(p, ngx_mail_smtp_auth_methods_names[i].data,
+                           ngx_mail_smtp_auth_methods_names[i].len);
         }
     }
 
@@ -681,20 +252,20 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
-    conf->smtp_starttls_capability.len = size;
-    conf->smtp_starttls_capability.data = p;
+    conf->starttls_capability.len = size;
+    conf->starttls_capability.data = p;
 
-    p = ngx_cpymem(p, conf->smtp_capability.data,
-                   conf->smtp_capability.len);
+    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->smtp_starttls_capability.data
-        + (auth - conf->smtp_capability.data) + 3;
+    p = conf->starttls_capability.data
+        + (auth - conf->capability.data) + 3;
     *p = '-';
 
-    size = (auth - conf->smtp_capability.data)
+    size = (auth - conf->capability.data)
             + sizeof("250 STARTTLS" CRLF) - 1;
 
     p = ngx_palloc(cf->pool, size);
@@ -702,183 +273,13 @@ ngx_mail_core_merge_srv_conf(ngx_conf_t 
         return NGX_CONF_ERROR;
     }
 
-    conf->smtp_starttls_only_capability.len = size;
-    conf->smtp_starttls_only_capability.data = p;
+    conf->starttls_only_capability.len = size;
+    conf->starttls_only_capability.data = p;
 
-    p = ngx_cpymem(p, conf->smtp_capability.data,
-                   auth - conf->smtp_capability.data);
+    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;
 }
-
-
-static char *
-ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    char                       *rv;
-    void                       *mconf;
-    ngx_uint_t                  m;
-    ngx_conf_t                  pcf;
-    ngx_mail_module_t          *module;
-    ngx_mail_conf_ctx_t        *ctx, *mail_ctx;
-    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;
-    }
-
-    mail_ctx = cf->ctx;
-    ctx->main_conf = mail_ctx->main_conf;
-
-    /* the server{}'s srv_conf */
-
-    ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
-    if (ctx->srv_conf == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    for (m = 0; ngx_modules[m]; m++) {
-        if (ngx_modules[m]->type != NGX_MAIL_MODULE) {
-            continue;
-        }
-
-        module = ngx_modules[m]->ctx;
-
-        if (module->create_srv_conf) {
-            mconf = module->create_srv_conf(cf);
-            if (mconf == NULL) {
-                return NGX_CONF_ERROR;
-            }
-
-            ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf;
-        }
-    }
-
-    /* the server configuration context */
-
-    cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
-    cscf->ctx = ctx;
-
-    cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];
-
-    cscfp = ngx_array_push(&cmcf->servers);
-    if (cscfp == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    *cscfp = cscf;
-
-
-    /* parse inside server{} */
-
-    pcf = *cf;
-    cf->ctx = ctx;
-    cf->cmd_type = NGX_MAIL_SRV_CONF;
-
-    rv = ngx_conf_parse(cf, NULL);
-
-    *cf = pcf;
-
-    return rv;
-}
-
-
-/* AF_INET only */
-
-static char *
-ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    ngx_str_t                  *value;
-    ngx_url_t                   u;
-    ngx_uint_t                  i;
-    ngx_mail_listen_t          *imls;
-    ngx_mail_core_main_conf_t  *cmcf;
-
-    value = cf->args->elts;
-
-    ngx_memzero(&u, sizeof(ngx_url_t));
-
-    u.url = value[1];
-    u.listen = 1;
-
-    if (ngx_parse_url(cf, &u) != NGX_OK) {
-        if (u.err) {
-            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "%s in \"%V\" of the \"listen\" directive",
-                               u.err, &u.url);
-        }
-
-        return NGX_CONF_ERROR;
-    }
-
-    cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);
-
-    imls = cmcf->listen.elts;
-
-    for (i = 0; i < cmcf->listen.nelts; i++) {
-
-        if (imls[i].addr != u.addr.in_addr || imls[i].port != u.port) {
-            continue;
-        }
-
-        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                           "duplicate \"%V\" address and port pair", &u.url);
-        return NGX_CONF_ERROR;
-    }
-
-    imls = ngx_array_push(&cmcf->listen);
-    if (imls == NULL) {
-        return NGX_CONF_ERROR;
-    }
-
-    ngx_memzero(imls, sizeof(ngx_mail_listen_t));
-
-    imls->addr = u.addr.in_addr;
-    imls->port = u.port;
-    imls->family = AF_INET;
-    imls->ctx = cf->ctx;
-
-    if (cf->args->nelts == 2) {
-        return NGX_CONF_OK;
-    }
-
-    if (ngx_strcmp(value[2].data, "bind") == 0) {
-        imls->bind = 1;
-        return NGX_CONF_OK;
-    }
-
-    ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                       "the invalid \"%V\" parameter", &value[2]);
-    return NGX_CONF_ERROR;
-}
-
-
-static char *
-ngx_mail_core_capability(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
-    char  *p = conf;
-
-    ngx_str_t    *c, *value;
-    ngx_uint_t    i;
-    ngx_array_t  *a;
-
-    a = (ngx_array_t *) (p + cmd->offset);
-
-    value = cf->args->elts;
-
-    for (i = 1; i < cf->args->nelts; i++) {
-        c = ngx_array_push(a);
-        if (c == NULL) {
-            return NGX_CONF_ERROR;
-        }
-
-        *c = value[i];
-    }
-
-    return NGX_CONF_OK;
-}
new file mode 100644
--- /dev/null
+++ b/src/mail/ngx_mail_smtp_module.h
@@ -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
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -120,6 +120,8 @@ static ngx_command_t  ngx_mail_ssl_comma
 
 
 static ngx_mail_module_t  ngx_mail_ssl_module_ctx = {
+    NULL,                                  /* protocol */
+
     NULL,                                  /* create main configuration */
     NULL,                                  /* init main configuration */