Index: src/mail/ngx_mail_smtp_handler.c
===================================================================
--- src/mail/ngx_mail_smtp_handler.c	(.../original-0.5.34)	(revision 48)
+++ src/mail/ngx_mail_smtp_handler.c	(.../nginx-0.5.35_MX_PROXY_2)	(revision 48)
@@ -21,7 +21,7 @@
 static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s,
     ngx_connection_t *c);
 
-static ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s,
+ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s,
     ngx_connection_t *c, char *err);
 static void ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s,
     ngx_connection_t *c, char *err);
@@ -482,7 +482,7 @@
 }
 
 
-static ngx_int_t
+ngx_int_t
 ngx_mail_smtp_discard_command(ngx_mail_session_t *s, ngx_connection_t *c,
     char *err)
 {
Index: src/mail/ngx_mail_mx_handler.c
===================================================================
--- src/mail/ngx_mail_mx_handler.c	(.../original-0.5.34)	(revision 0)
+++ src/mail/ngx_mail_mx_handler.c	(.../nginx-0.5.35_MX_PROXY_2)	(revision 48)
@@ -0,0 +1,806 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ * Copypaste (M-w, C-y) NomadRain@rambler.ru
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_mail.h>
+#include <ngx_mail_smtp_module.h>
+#include <ngx_mail_mx_module.h>
+
+
+static void ngx_mail_mx_invalid_pipelining(ngx_event_t *rev);
+static ngx_int_t ngx_mail_mx_create_buffer(ngx_mail_session_t *s,
+    ngx_connection_t *c);
+
+static ngx_int_t ngx_mail_mx_helo(ngx_mail_session_t *s, ngx_connection_t *c);
+static ngx_int_t ngx_mail_mx_auth(ngx_mail_session_t *s, ngx_connection_t *c);
+static ngx_int_t ngx_mail_mx_mail(ngx_mail_session_t *s, ngx_connection_t *c);
+static ngx_int_t ngx_mail_mx_rcpt(ngx_mail_session_t *s, ngx_connection_t *c);
+static ngx_int_t ngx_mail_smtp_starttls(ngx_mail_session_t *s,
+    ngx_connection_t *c);
+
+extern ngx_int_t ngx_mail_smtp_discard_command(ngx_mail_session_t *s,
+    ngx_connection_t *c, char *err);
+
+static u_char  smtp_ok[] = "250 2.0.0 OK" CRLF;
+static u_char  smtp_bye[] = "221 2.0.0 Bye" CRLF;
+static u_char  smtp_next[] = "334 " CRLF;
+static u_char  smtp_username[] = "334 VXNlcm5hbWU6" CRLF;
+static u_char  smtp_password[] = "334 UGFzc3dvcmQ6" CRLF;
+static u_char  smtp_invalid_command[] = "500 5.5.1 Invalid command" CRLF;
+static u_char  smtp_invalid_pipelining[] =
+   "503 5.5.0 Improper use of SMTP command pipelining" CRLF;
+static u_char  smtp_invalid_argument[] = "501 5.5.4 Invalid argument" CRLF;
+static u_char  smtp_auth_required[] = "530 5.7.1 Authentication required" CRLF;
+static u_char  smtp_helo_required[] = "550 HELO/EHLO required by SMTP RFC [#1001]." CRLF;
+
+
+void
+ngx_mail_mx_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
+{
+    ngx_mail_mx_module_ctx_t   *context;
+    ngx_msec_t                 timeout;
+    ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_smtp_srv_conf_t  *sscf;
+
+    context = ngx_pcalloc(c->pool, sizeof(ngx_mail_mx_module_ctx_t));
+    if(context == NULL) {
+      ngx_mail_close_connection(c);
+      return;
+    }
+
+    ngx_mail_set_ctx(s, context, ngx_mail_mx_module);
+
+    cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+    sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_mx_module);
+
+    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 (sscf->greeting_delay) {
+         c->read->handler = ngx_mail_mx_invalid_pipelining;
+         return;
+    }
+
+    c->read->handler = ngx_mail_mx_init_protocol;
+
+    s->out = sscf->greeting;
+
+    ngx_mail_send(c->write);
+}
+
+
+static void
+ngx_mail_mx_invalid_pipelining(ngx_event_t *rev)
+{
+    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;
+
+    c->log->action = "in delay pipelining state";
+
+    if (rev->timedout) {
+
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "delay greeting");
+
+        rev->timedout = 0;
+
+        cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+        c->read->handler = ngx_mail_mx_init_protocol;
+
+        ngx_add_timer(c->read, cscf->timeout);
+
+        if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
+            ngx_mail_close_connection(c);
+            return;
+        }
+
+        sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_mx_module);
+
+        s->out = sscf->greeting;
+
+    } else {
+
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "invalid pipelining");
+
+        if (s->buffer == NULL) {
+            if (ngx_mail_mx_create_buffer(s, c) != NGX_OK) {
+                return;
+            }
+        }
+
+        if (ngx_mail_smtp_discard_command(s, c,
+                                "client was rejected before greeting: \"%V\"")
+            != NGX_OK)
+        {
+            return;
+        }
+
+        s->out.len = sizeof(smtp_invalid_pipelining) - 1;
+        s->out.data = smtp_invalid_pipelining;
+    }
+
+    ngx_mail_send(c->write);
+}
+
+
+void
+ngx_mail_mx_init_protocol(ngx_event_t *rev)
+{
+    ngx_connection_t    *c;
+    ngx_mail_session_t  *s;
+
+    c = rev->data;
+
+    c->log->action = "in auth state";
+
+    if (rev->timedout) {
+        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
+        c->timedout = 1;
+        ngx_mail_close_connection(c);
+        return;
+    }
+
+    s = c->data;
+
+    if (s->buffer == NULL) {
+        if (ngx_mail_mx_create_buffer(s, c) != NGX_OK) {
+            return;
+        }
+    }
+
+    s->mail_state = ngx_mx_start;
+    c->read->handler = ngx_mail_mx_auth_state;
+
+    ngx_mail_mx_auth_state(rev);
+}
+
+
+static ngx_int_t
+ngx_mail_mx_create_buffer(ngx_mail_session_t *s, ngx_connection_t *c)
+{
+    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;
+    }
+
+    sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_mx_module);
+
+    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;
+    }
+
+    return NGX_OK;
+}
+
+
+void
+ngx_mail_mx_auth_state(ngx_event_t *rev)
+{
+    ngx_int_t            rc;
+    ngx_connection_t    *c;
+    ngx_mail_session_t  *s;
+
+    c = rev->data;
+    s = c->data;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp auth state");
+
+    if (rev->timedout) {
+        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
+        c->timedout = 1;
+        ngx_mail_close_connection(c);
+        return;
+    }
+
+    if (s->out.len) {
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, c->log, 0, "smtp send handler busy");
+        s->blocked = 1;
+        return;
+    }
+
+    s->blocked = 0;
+
+    rc = ngx_mail_read_command(s, c);
+
+    if (rc == NGX_AGAIN || rc == NGX_ERROR) {
+        return;
+    }
+
+    s->out.len = sizeof(smtp_ok) - 1;
+    s->out.data = smtp_ok;
+
+    if (rc == NGX_OK) {
+      switch (s->command) {
+	  
+      case NGX_SMTP_HELO:
+      case NGX_SMTP_EHLO:
+	rc = ngx_mail_mx_helo(s, c);
+	break;
+	  
+      case NGX_SMTP_QUIT:
+	s->quit = 1;
+	s->out.len = sizeof(smtp_bye) - 1;
+	s->out.data = smtp_bye;
+	break;
+	  
+      case NGX_SMTP_MAIL:
+	rc = ngx_mail_mx_mail(s, c);
+	break;
+	  
+      case NGX_SMTP_RCPT:
+	rc = ngx_mail_mx_rcpt(s, c);
+	break;
+	  
+      case NGX_SMTP_NOOP:
+      case NGX_SMTP_RSET:
+	break;
+	  
+      case NGX_SMTP_STARTTLS:
+	rc = ngx_mail_smtp_starttls(s, c);
+	break;
+	  
+      default:
+	rc = NGX_MAIL_PARSE_INVALID_COMMAND;
+	break;
+      }
+      if (s->mail_state == ngx_mx_helo_mail_rcpt) rc = NGX_DONE;
+    }
+
+    switch (rc) {
+
+    case NGX_DONE:
+        ngx_mail_auth(s, c);
+        return;
+
+    case NGX_ERROR:
+        ngx_mail_session_internal_server_error(s);
+        return;
+
+    case NGX_MAIL_PARSE_INVALID_COMMAND:
+        s->mail_state = ngx_mx_start;
+        s->state = 0;
+
+        s->out.len = sizeof(smtp_invalid_command) - 1;
+        s->out.data = smtp_invalid_command;
+
+        /* fall through */
+
+    case NGX_OK:
+        s->args.nelts = 0;
+        s->buffer->pos = s->buffer->start;
+        s->buffer->last = s->buffer->start;
+
+        if (s->state) {
+            s->arg_start = s->buffer->start;
+        }
+
+        ngx_mail_send(c->write);
+    }
+}
+
+
+static ngx_int_t
+ngx_mail_mx_helo(ngx_mail_session_t *s, ngx_connection_t *c)
+{
+    ngx_str_t                 *arg;
+    ngx_mail_smtp_srv_conf_t  *sscf;
+#if (NGX_MAIL_SSL)
+    ngx_mail_ssl_conf_t       *sslcf;
+#endif
+    ngx_mail_mx_module_ctx_t  *mx_ctx;
+    ngx_str_t                 *what_free = NULL;
+
+    mx_ctx = ngx_mail_get_module_ctx(s, ngx_mail_mx_module);
+
+    if (s->args.nelts != 1) {
+        s->out.len = sizeof(smtp_invalid_argument) - 1;
+        s->out.data = smtp_invalid_argument;
+        s->state = 0;
+        return NGX_OK;
+    }
+
+    switch(s->mail_state) {
+    case ngx_mx_start: s->mail_state = ngx_mx_helo;
+      break;
+    case ngx_mx_helo_mail:
+    case ngx_mx_helo_rcpt:
+      what_free = (s->mail_state == ngx_mx_helo_mail) ? &mx_ctx->smtp_mail : &mx_ctx->smtp_rcpt;
+      ngx_pfree(c->pool, what_free->data);
+      what_free->len = 0; /*Pass through...*/
+    case ngx_mx_helo:
+      ngx_pfree(c->pool, mx_ctx->smtp_helo.data);
+      mx_ctx->smtp_helo.len = 0;
+      s->mail_state = ngx_mx_helo;
+      break;
+    default:
+      s->mail_state = ngx_mx_helo;
+      /*
+       * TODO: RFC2881: An EHLO command MAY be issued by a client later in the session.  If
+       * it is issued after the session begins, the SMTP server MUST clear all
+       * buffers and reset the state exactly as if a RSET command had been
+       * issued.
+       */
+    }
+
+    arg = s->args.elts;
+
+    mx_ctx->smtp_helo.len = arg[0].len;
+
+    mx_ctx->smtp_helo.data = ngx_palloc(c->pool, arg[0].len);
+    if (mx_ctx->smtp_helo.data == NULL) {
+        return NGX_ERROR;
+    }
+
+    ngx_memcpy(mx_ctx->smtp_helo.data, arg[0].data, arg[0].len);
+
+    sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_mx_module);
+
+    if (s->command == NGX_SMTP_HELO) {
+        s->out = sscf->server_name;
+
+    } else {
+        s->esmtp = 1;
+
+#if (NGX_MAIL_SSL)
+
+        if (c->ssl == NULL) {
+            sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
+
+            if (sslcf->starttls == NGX_MAIL_STARTTLS_ON) {
+                s->out = sscf->starttls_capability;
+                return NGX_OK;
+            }
+
+            if (sslcf->starttls == NGX_MAIL_STARTTLS_ONLY) {
+                s->out = sscf->starttls_only_capability;
+                return NGX_OK;
+            }
+        }
+#endif
+
+        s->out = sscf->capability;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_mail_mx_mail(ngx_mail_session_t *s, ngx_connection_t *c)
+{
+    ngx_str_t                *arg;
+    ngx_mail_mx_module_ctx_t *mx_ctx;
+
+    mx_ctx = ngx_mail_get_module_ctx(s, ngx_mail_mx_module);
+
+    if (s->args.nelts != 2) {
+        s->out.len = sizeof(smtp_invalid_command) - 1;
+        s->out.data = smtp_invalid_command;
+        s->state = 0;
+        return NGX_OK;
+    }
+
+    arg = s->args.elts;
+
+    if(arg[0].len == 5 &&
+       ngx_toupper(arg[0].data[0]) == 'F' &&
+       ngx_toupper(arg[0].data[1]) == 'R' &&
+       ngx_toupper(arg[0].data[2]) == 'O' &&
+       ngx_toupper(arg[0].data[3]) == 'M' &&
+       ngx_toupper(arg[0].data[4]) == ':') {
+     
+      switch(s->mail_state) {
+      case ngx_mx_helo: s->mail_state = ngx_mx_helo_mail;
+	break;
+      case ngx_mx_helo_rcpt: s->mail_state = ngx_mx_helo_mail_rcpt;
+	break;
+      case ngx_mx_helo_mail:
+	ngx_pfree(c->pool, mx_ctx->smtp_mail.data);
+	mx_ctx->smtp_mail.len = 0;
+	break;
+      default:
+	s->out.len = sizeof(smtp_helo_required) - 1;
+	s->out.data = smtp_helo_required;
+	s->state = 0;
+	return NGX_OK;
+      }
+ 
+      mx_ctx->smtp_mail.len = arg[1].len;
+      
+      mx_ctx->smtp_mail.data = ngx_palloc(c->pool, arg[1].len);
+      if (mx_ctx->smtp_mail.data == NULL) {
+        return NGX_ERROR;
+      }
+      
+      ngx_memcpy(mx_ctx->smtp_mail.data, arg[1].data, arg[1].len);
+
+    } else {
+      s->out.len = sizeof(smtp_invalid_command);
+      s->out.data = smtp_invalid_command;
+      s->state = 0;
+    }
+
+    return NGX_OK;
+}
+
+static ngx_int_t
+ngx_mail_mx_rcpt(ngx_mail_session_t *s, ngx_connection_t *c)
+{
+    ngx_str_t                *arg;
+    ngx_mail_mx_module_ctx_t *mx_ctx;
+
+    mx_ctx = ngx_mail_get_module_ctx(s, ngx_mail_mx_module);
+
+    if (s->args.nelts != 2) {
+        s->out.len = sizeof(smtp_invalid_command) - 1;
+        s->out.data = smtp_invalid_command;
+        s->state = 0;
+        return NGX_OK;
+    }
+
+    arg = s->args.elts;
+
+    if(arg[0].len == 3 &&
+       ngx_toupper(arg[0].data[0]) == 'T' &&
+       ngx_toupper(arg[0].data[1]) == 'O' &&
+       ngx_toupper(arg[0].data[2]) == ':') {
+
+      switch(s->mail_state) {
+      case ngx_mx_helo: s->mail_state = ngx_mx_helo_rcpt;
+	break;
+      case ngx_mx_helo_mail: s->mail_state = ngx_mx_helo_mail_rcpt;
+	break;
+      case ngx_mx_helo_rcpt:
+	ngx_pfree(c->pool, mx_ctx->smtp_rcpt.data);
+	mx_ctx->smtp_rcpt.len = 0;
+	break;
+      default:
+	s->out.len = sizeof(smtp_helo_required) - 1;
+	s->out.data = smtp_helo_required;
+	s->state = 0;
+	return NGX_OK;
+      }
+      
+      mx_ctx->smtp_rcpt.len = arg[1].len;
+      
+      mx_ctx->smtp_rcpt.data = ngx_palloc(c->pool, arg[1].len);
+      if (mx_ctx->smtp_rcpt.data == NULL) {
+        return NGX_ERROR;
+      }
+      
+      ngx_memcpy(mx_ctx->smtp_rcpt.data, arg[1].data, arg[1].len);
+      
+    } else {
+      s->out.len = sizeof(smtp_invalid_command);
+      s->out.data = smtp_invalid_command;
+      s->state = 0;
+    }
+
+    return NGX_OK;
+}
+
+static ngx_int_t
+ngx_mail_smtp_starttls(ngx_mail_session_t *s, ngx_connection_t *c)
+{
+#if (NGX_MAIL_SSL)
+    ngx_mail_ssl_conf_t  *sslcf;
+
+    if (c->ssl == NULL) {
+        sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module);
+        if (sslcf->starttls) {
+
+            /*
+             * RFC3207 requires us to discard any knowledge
+             * obtained from client before STARTTLS.
+             */
+
+            s->smtp_helo.len = 0;
+            s->smtp_helo.data = NULL;
+
+            c->read->handler = ngx_mail_starttls_handler;
+            return NGX_OK;
+        }
+    }
+
+#endif
+
+    return NGX_MAIL_PARSE_INVALID_COMMAND;
+}
+
+/*
+static ngx_int_t
+ngx_mail_mx_discard_command(ngx_mail_session_t *s, ngx_connection_t *c,
+    char *err)
+{
+    ssize_t    n;
+
+    n = c->recv(c, s->buffer->last, s->buffer->end - s->buffer->last);
+
+    if (n == NGX_ERROR || n == 0) {
+        ngx_mail_close_connection(c);
+        return NGX_ERROR;
+    }
+
+    if (n > 0) {
+        s->buffer->last += n;
+    }
+
+    if (n == NGX_AGAIN) {
+        if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) {
+            ngx_mail_session_internal_server_error(s);
+            return NGX_ERROR;
+        }
+
+        return NGX_AGAIN;
+    }
+
+    ngx_mail_smtp_log_rejected_command(s, c, err);
+
+    s->buffer->pos = s->buffer->start;
+    s->buffer->last = s->buffer->start;
+
+    return NGX_OK;
+}
+
+
+static void
+ngx_mail_smtp_log_rejected_command(ngx_mail_session_t *s, ngx_connection_t *c,
+    char *err)
+{
+    u_char      ch;
+    ngx_str_t   cmd;
+    ngx_uint_t  i;
+
+    if (c->log->log_level < NGX_LOG_INFO) {
+        return;
+    }
+
+    cmd.len = s->buffer->last - s->buffer->start;
+    cmd.data = s->buffer->start;
+
+    for (i = 0; i < cmd.len; i++) {
+        ch = cmd.data[i];
+
+        if (ch != CR && ch != LF) {
+            continue;
+        }
+
+        cmd.data[i] = '_';
+    }
+
+    cmd.len = i;
+
+    ngx_log_error(NGX_LOG_INFO, c->log, 0, err, &cmd);
+}
+*/
+
+ngx_int_t
+ngx_mail_mx_parse_command(ngx_mail_session_t *s)
+{
+    u_char      ch, *p, *c, c0, c1, c2, c3;
+    ngx_str_t  *arg;
+    enum {
+        sw_start = 0,
+        sw_spaces_before_argument,
+        sw_argument,
+        sw_almost_done
+    } state;
+
+    state = s->state;
+
+    for (p = s->buffer->pos; p < s->buffer->last; p++) {
+        ch = *p;
+
+        switch (state) {
+
+        /* SMTP command */
+        case sw_start:
+            if (ch == ' ' || ch == CR || ch == LF) {
+                c = s->buffer->start;
+
+                if (p - c == 4) {
+
+                    c0 = ngx_toupper(c[0]);
+                    c1 = ngx_toupper(c[1]);
+                    c2 = ngx_toupper(c[2]);
+                    c3 = ngx_toupper(c[3]);
+
+                    if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'O')
+                    {
+                        s->command = NGX_SMTP_HELO;
+
+                    } else if (c0 == 'E' && c1 == 'H' && c2 == 'L' && c3 == 'O')
+                    {
+                        s->command = NGX_SMTP_EHLO;
+
+                    } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T')
+                    {
+		        s->command = NGX_SMTP_QUIT;
+		      
+		    } else if (c0 == 'A' && c1 == 'U' && c2 == 'T' && c3 == 'H')
+		    {
+		        s->command = NGX_SMTP_AUTH;
+
+                    } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P')
+                    {
+                        s->command = NGX_SMTP_NOOP;
+
+                    } else if (c0 == 'M' && c1 == 'A' && c2 == 'I' && c3 == 'L')
+                    {
+                        s->command = NGX_SMTP_MAIL;
+
+                    } else if (c0 == 'R' && c1 == 'S' && c2 == 'E' && c3 == 'T')
+                    {
+                        s->command = NGX_SMTP_RSET;
+
+                    } else if (c0 == 'R' && c1 == 'C' && c2 == 'P' && c3 == 'T')
+                    {
+                        s->command = NGX_SMTP_RCPT;
+
+                    } else if (c0 == 'V' && c1 == 'R' && c2 == 'F' && c3 == 'Y')
+                    {
+                        s->command = NGX_SMTP_VRFY;
+
+                    } else if (c0 == 'E' && c1 == 'X' && c2 == 'P' && c3 == 'N')
+                    {
+                        s->command = NGX_SMTP_EXPN;
+
+                    } else if (c0 == 'H' && c1 == 'E' && c2 == 'L' && c3 == 'P')
+                    {
+                        s->command = NGX_SMTP_HELP;
+
+                    } else {
+                        goto invalid;
+                    }
+#if (NGX_MAIL_SSL)
+                } else if (p - c == 8) {
+
+                    if ((c[0] == 'S'|| c[0] == 's')
+                        && (c[1] == 'T'|| c[1] == 't')
+                        && (c[2] == 'A'|| c[2] == 'a')
+                        && (c[3] == 'R'|| c[3] == 'r')
+                        && (c[4] == 'T'|| c[4] == 't')
+                        && (c[5] == 'T'|| c[5] == 't')
+                        && (c[6] == 'L'|| c[6] == 'l')
+                        && (c[7] == 'S'|| c[7] == 's'))
+                    {
+                        s->command = NGX_SMTP_STARTTLS;
+
+                    } else {
+                        goto invalid;
+                    }
+#endif
+                } else {
+                    goto invalid;
+                }
+
+                switch (ch) {
+                case ' ':
+                    state = sw_spaces_before_argument;
+                    break;
+                case CR:
+                    state = sw_almost_done;
+                    break;
+                case LF:
+                    goto done;
+                }
+                break;
+            }
+
+            if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
+                goto invalid;
+            }
+
+            break;
+
+        case sw_spaces_before_argument:
+            switch (ch) {
+            case ' ':
+                break;
+            case CR:
+                state = sw_almost_done;
+                s->arg_end = p;
+                break;
+            case LF:
+                s->arg_end = p;
+                goto done;
+            default:
+                if (s->args.nelts <= 2) {
+                    state = sw_argument;
+                    s->arg_start = p;
+                    break;
+                }
+                goto invalid;
+            }
+            break;
+
+        case sw_argument:
+            switch (ch) {
+            case ' ':
+            case CR:
+            case LF:
+                arg = ngx_array_push(&s->args);
+                if (arg == NULL) {
+                    return NGX_ERROR;
+                }
+                arg->len = p - s->arg_start;
+                arg->data = s->arg_start;
+                s->arg_start = NULL;
+
+                switch (ch) {
+                case ' ':
+                    state = sw_spaces_before_argument;
+                    break;
+                case CR:
+                    state = sw_almost_done;
+                    break;
+                case LF:
+                    goto done;
+                }
+                break;
+
+            default:
+                break;
+            }
+            break;
+
+        case sw_almost_done:
+            switch (ch) {
+            case LF:
+                goto done;
+            default:
+                goto invalid;
+            }
+        }
+    }
+
+    s->buffer->pos = p;
+    s->state = state;
+
+    return NGX_AGAIN;
+
+done:
+
+    s->buffer->pos = p + 1;
+
+    if (s->arg_start) {
+        arg = ngx_array_push(&s->args);
+        if (arg == NULL) {
+            return NGX_ERROR;
+        }
+        arg->len = s->arg_end - s->arg_start;
+        arg->data = s->arg_start;
+        s->arg_start = NULL;
+    }
+
+    /*    s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument; */
+    s->state = sw_start;
+
+    return NGX_OK;
+
+invalid:
+
+    s->state = sw_start;
+    s->arg_start = NULL;
+
+    return NGX_MAIL_PARSE_INVALID_COMMAND;
+}
Index: src/mail/ngx_mail.h
===================================================================
--- src/mail/ngx_mail.h	(.../original-0.5.34)	(revision 48)
+++ src/mail/ngx_mail.h	(.../nginx-0.5.35_MX_PROXY_2)	(revision 48)
@@ -72,6 +72,7 @@
 #define NGX_MAIL_POP3_PROTOCOL  0
 #define NGX_MAIL_IMAP_PROTOCOL  1
 #define NGX_MAIL_SMTP_PROTOCOL  2
+#define NGX_MAIL_MX_PROTOCOL    3
 
 
 typedef struct ngx_mail_protocol_s  ngx_mail_protocol_t;
Index: src/mail/ngx_mail_proxy_module.c
===================================================================
--- src/mail/ngx_mail_proxy_module.c	(.../original-0.5.34)	(revision 48)
+++ src/mail/ngx_mail_proxy_module.c	(.../nginx-0.5.35_MX_PROXY_2)	(revision 48)
@@ -9,6 +9,7 @@
 #include <ngx_event.h>
 #include <ngx_event_connect.h>
 #include <ngx_mail.h>
+#include <ngx_mail_mx_module.h>
 
 
 typedef struct {
@@ -17,6 +18,7 @@
     ngx_flag_t  xclient;
     size_t      buffer_size;
     ngx_msec_t  timeout;
+    ngx_peer_addr_t *peer;
 } ngx_mail_proxy_conf_t;
 
 
@@ -24,6 +26,7 @@
 static void ngx_mail_proxy_pop3_handler(ngx_event_t *rev);
 static void ngx_mail_proxy_imap_handler(ngx_event_t *rev);
 static void ngx_mail_proxy_smtp_handler(ngx_event_t *rev);
+static void ngx_mail_proxy_mx_handler(ngx_event_t *rev);
 static void ngx_mail_proxy_dummy_handler(ngx_event_t *ev);
 static ngx_int_t ngx_mail_proxy_read_response(ngx_mail_session_t *s,
     ngx_uint_t state);
@@ -34,6 +37,8 @@
 static void *ngx_mail_proxy_create_conf(ngx_conf_t *cf);
 static char *ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent,
     void *child);
+static char *
+ngx_mail_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
 
 
 static ngx_command_t  ngx_mail_proxy_commands[] = {
@@ -73,6 +78,13 @@
       offsetof(ngx_mail_proxy_conf_t, xclient),
       NULL },
 
+    { ngx_string("proxy_pass"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_mail_proxy_pass,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      0,
+      NULL },
+
       ngx_null_command
 };
 
@@ -119,7 +131,16 @@
     s->connection->log->action = "connecting to upstream";
 
     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
 
+    if(!peer) peer = pcf->peer;
+    if(!peer) {
+      ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
+		    "no \"proxy_pass\" defined for server and no one in http auth response");
+      ngx_mail_session_internal_server_error(s);
+      return;
+    }
+
     if (cscf->so_keepalive) {
         keepalive = 1;
 
@@ -162,8 +183,6 @@
     s->connection->read->handler = ngx_mail_proxy_block_read;
     p->upstream.connection->write->handler = ngx_mail_proxy_dummy_handler;
 
-    pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
-
     s->proxy->buffer = ngx_create_temp_buf(s->connection->pool,
                                            pcf->buffer_size);
     if (s->proxy->buffer == NULL) {
@@ -183,6 +202,11 @@
         s->mail_state = ngx_imap_start;
         break;
 
+    case NGX_MAIL_MX_PROTOCOL:
+        p->upstream.connection->read->handler = ngx_mail_proxy_mx_handler;
+        s->mail_state = ngx_mx_start;
+        break;
+
     default: /* NGX_MAIL_SMTP_PROTOCOL */
         p->upstream.connection->read->handler = ngx_mail_proxy_smtp_handler;
         s->mail_state = ngx_smtp_start;
@@ -604,6 +628,161 @@
 
 
 static void
+ngx_mail_proxy_mx_handler(ngx_event_t *rev)
+{
+    u_char                    *p;
+    ngx_int_t                  rc;
+    ngx_str_t                  line;
+    ngx_connection_t          *c;
+    ngx_mail_session_t        *s;
+    ngx_mail_proxy_conf_t     *pcf;
+    ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_mx_module_ctx_t  *mx_ctx;
+
+    ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
+                   "mail proxy mx handler");
+
+    c = rev->data;
+    s = c->data;
+
+    if (rev->timedout) {
+        ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
+                      "upstream timed out");
+        c->timedout = 1;
+        ngx_mail_proxy_internal_server_error(s);
+        return;
+    }
+
+    rc = ngx_mail_proxy_read_response(s, s->mail_state);
+
+    if (rc == NGX_AGAIN) {
+        return;
+    }
+
+    if (rc == NGX_ERROR) {
+        ngx_mail_proxy_upstream_error(s);
+        return;
+    }
+
+    mx_ctx = ngx_mail_get_module_ctx(s, ngx_mail_mx_module);
+
+    switch (s->mail_state) {
+
+    case ngx_mx_start:
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send ehlo");
+
+        s->connection->log->action = "sending HELO/EHLO to upstream";
+
+	line.len = sizeof("HELO " CRLF) - 1 + mx_ctx->smtp_helo.len;
+	if (mx_ctx->smtp_helo_addition.len) line.len += mx_ctx->smtp_helo_addition.len + sizeof(" ") - 1;
+
+	line.data = ngx_palloc(c->pool, line.len);
+	if (line.data == NULL) {
+	  ngx_mail_proxy_internal_server_error(s);
+	  return;
+	}
+
+        pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
+
+        p = ngx_cpymem(line.data,
+                       ((s->esmtp) ? "EHLO " : "HELO "),
+                       sizeof("HELO ") - 1);
+
+        p = ngx_cpymem(p, mx_ctx->smtp_helo.data, mx_ctx->smtp_helo.len);
+
+	if (mx_ctx->smtp_helo_addition.len) {
+	  *p++ = ' ';
+	  p = ngx_cpymem(p, mx_ctx->smtp_helo_addition.data, mx_ctx->smtp_helo_addition.len);
+	}
+
+        *p++ = CR; *p = LF;
+
+	s->mail_state = ngx_mx_helo;
+        break;
+
+    case ngx_mx_helo:
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send mail from:");
+
+        s->connection->log->action = "sending MAIL FROM: to upstream";
+
+	line.len = sizeof("MAIL FROM: " CRLF) - 1 + mx_ctx->smtp_mail.len;
+	line.data = ngx_palloc(c->pool, line.len);
+	if (line.data == NULL) {
+	  ngx_mail_proxy_internal_server_error(s);
+	  return;
+	}
+
+        p = ngx_cpymem(line.data, "MAIL FROM: ", sizeof("MAIL FROM: ") - 1);
+        p = ngx_cpymem(p, mx_ctx->smtp_mail.data, mx_ctx->smtp_mail.len);
+        *p++ = CR; *p = LF;
+
+	s->mail_state = ngx_mx_helo_mail;
+        break;
+
+    case ngx_mx_helo_mail:
+        ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send rcpt to:");
+
+        s->connection->log->action = "sending RCPT TO: to upstream";
+
+	line.len = sizeof("RCPT TO: " CRLF) - 1 + mx_ctx->smtp_rcpt.len;
+	line.data = ngx_palloc(c->pool, line.len);
+	if (line.data == NULL) {
+	  ngx_mail_proxy_internal_server_error(s);
+	  return;
+	}
+
+        p = ngx_cpymem(line.data, "RCPT TO: ", sizeof("RCPT TO: ") - 1);
+        p = ngx_cpymem(p, mx_ctx->smtp_rcpt.data, mx_ctx->smtp_rcpt.len);
+        *p++ = CR; *p = LF;
+
+	s->mail_state = ngx_mx_helo_mail_rcpt;
+        break;
+
+    case ngx_mx_helo_mail_rcpt:
+
+        ngx_memcpy(s->proxy->buffer->start, smtp_ok, sizeof(smtp_ok) - 1);
+
+        s->proxy->buffer->pos = s->proxy->buffer->start;
+        s->proxy->buffer->last = s->proxy->buffer->start + sizeof(smtp_ok) - 1;
+
+        s->connection->read->handler = ngx_mail_proxy_handler;
+        s->connection->write->handler = ngx_mail_proxy_handler;
+        rev->handler = ngx_mail_proxy_handler;
+        c->write->handler = ngx_mail_proxy_handler;
+
+        pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
+        ngx_add_timer(s->connection->read, pcf->timeout);
+        ngx_del_timer(c->read);
+
+        c->log->action = NULL;
+
+        ngx_mail_proxy_handler(s->connection->write);
+	/*TODO: ngx_mail_delete_ctx(s, ngx_mail_mx_module);*/
+        return;
+
+    default:
+#if (NGX_SUPPRESS_WARN)
+        line.len = 0;
+        line.data = NULL;
+#endif
+        break;
+    }
+
+    if (c->send(c, line.data, line.len) < (ssize_t) line.len) {
+        /*
+         * we treat the incomplete sending as NGX_ERROR
+         * because it is very strange here
+         */
+        ngx_mail_proxy_internal_server_error(s);
+        return;
+    }
+
+    s->proxy->buffer->pos = s->proxy->buffer->start;
+    s->proxy->buffer->last = s->proxy->buffer->start;
+}
+
+
+static void
 ngx_mail_proxy_dummy_handler(ngx_event_t *wev)
 {
     ngx_connection_t    *c;
@@ -699,6 +878,29 @@
 
         break;
 
+    case NGX_MAIL_MX_PROTOCOL:
+      switch (state) {
+
+      case ngx_mx_helo:
+      case ngx_mx_noxclient:
+      case ngx_mx_helo_mail:
+      case ngx_mx_helo_rcpt:
+      case ngx_mx_helo_mail_rcpt:
+	if (p[0] == '2' && p[1] == '5' && p[2] == '0') {
+	  return NGX_OK;
+	}
+	break;
+
+      case ngx_mx_start:
+      case ngx_mx_xclient:
+	if (p[0] == '2' && p[1] == '2' && p[2] == '0') {
+	  return NGX_OK;
+	}
+	break;
+      }
+
+      break;
+
     default: /* NGX_MAIL_SMTP_PROTOCOL */
         switch (state) {
 
@@ -993,6 +1195,58 @@
     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
                               (size_t) ngx_pagesize);
     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000);
+    if (conf->peer == NULL) {
+      conf->peer = prev->peer;
+    }
 
     return NGX_CONF_OK;
 }
+
+
+static char *
+ngx_mail_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_mail_proxy_conf_t *pcf = conf;
+
+    ngx_str_t  *value;
+    ngx_url_t   u;
+
+    value = cf->args->elts;
+
+    ngx_memzero(&u, sizeof(ngx_url_t));
+
+    u.url = value[1];
+    u.default_port = 25;
+    u.uri_part = 1;
+    u.one_addr = 1;
+
+    /*
+    if (ngx_strncmp(u.url.data, "http://", 7) == 0) {
+        u.url.len -= 7;
+        u.url.data += 7;
+    }
+
+    */
+    if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
+        if (u.err) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "%s in proxy_pass \"%V\"", u.err, &u.url);
+        }
+
+        return NGX_CONF_ERROR;
+    }
+
+    pcf->peer = u.addrs;
+
+    /*
+    pcf->host_header = u.host;
+    pcf->uri = u.uri;
+
+    if (ahcf->uri.len == 0) {
+        ahcf->uri.len = sizeof("/") - 1;
+        ahcf->uri.data = (u_char *) "/";
+    }
+    */
+
+    return NGX_CONF_OK;
+}
Index: src/mail/ngx_mail_mx_module.c
===================================================================
--- src/mail/ngx_mail_mx_module.c	(.../original-0.5.34)	(revision 0)
+++ src/mail/ngx_mail_mx_module.c	(.../nginx-0.5.35_MX_PROXY_2)	(revision 48)
@@ -0,0 +1,263 @@
+
+/*
+ * Copyright (C) Igor Sysoev,
+ * Copypaste (M-w, C-y) NomadRain@rambler.ru
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+#include <ngx_mail.h>
+#include <ngx_mail_smtp_module.h>
+#include <ngx_mail_mx_module.h>
+
+
+static void *ngx_mail_mx_create_srv_conf(ngx_conf_t *cf);
+static char *ngx_mail_mx_merge_srv_conf(ngx_conf_t *cf, void *parent,
+    void *child);
+
+static ngx_mail_protocol_t  ngx_mail_mx_protocol = {
+    ngx_string("mx"),
+    { 25, 465, 587, 0 },
+    NGX_MAIL_MX_PROTOCOL,
+
+    ngx_mail_mx_init_session,
+    ngx_mail_mx_init_protocol,
+    ngx_mail_mx_parse_command,
+    ngx_mail_mx_auth_state,
+
+    ngx_string("451 4.3.2 Internal server error" CRLF)
+};
+
+
+static ngx_command_t  ngx_mail_mx_commands[] = {
+
+    { ngx_string("mx_client_buffer"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_size_slot,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_smtp_srv_conf_t, client_buffer_size),
+      NULL },
+
+    { ngx_string("mx_greeting_delay"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+      ngx_conf_set_msec_slot,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_smtp_srv_conf_t, greeting_delay),
+      NULL },
+
+    { ngx_string("mx_capabilities"),
+      NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
+      ngx_mail_capabilities,
+      NGX_MAIL_SRV_CONF_OFFSET,
+      offsetof(ngx_mail_smtp_srv_conf_t, capabilities),
+      NULL },
+
+      ngx_null_command
+};
+
+
+static ngx_mail_module_t  ngx_mail_mx_module_ctx = {
+    &ngx_mail_mx_protocol,               /* protocol */
+
+    NULL,                                  /* create main configuration */
+    NULL,                                  /* init main configuration */
+
+    ngx_mail_mx_create_srv_conf,         /* create server configuration */
+    ngx_mail_mx_merge_srv_conf           /* merge server configuration */
+};
+
+
+ngx_module_t  ngx_mail_mx_module = {
+    NGX_MODULE_V1,
+    &ngx_mail_mx_module_ctx,             /* module context */
+    ngx_mail_mx_commands,                /* module directives */
+    NGX_MAIL_MODULE,                       /* module type */
+    NULL,                                  /* init master */
+    NULL,                                  /* init module */
+    NULL,                                  /* init process */
+    NULL,                                  /* init thread */
+    NULL,                                  /* exit thread */
+    NULL,                                  /* exit process */
+    NULL,                                  /* exit master */
+    NGX_MODULE_V1_PADDING
+};
+
+
+static void *
+ngx_mail_mx_create_srv_conf(ngx_conf_t *cf)
+{
+    ngx_mail_smtp_srv_conf_t  *sscf;
+
+    sscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_smtp_srv_conf_t));
+    if (sscf == NULL) {
+        return NULL;
+    }
+
+    sscf->client_buffer_size = NGX_CONF_UNSET_SIZE;
+    sscf->greeting_delay = NGX_CONF_UNSET_MSEC;
+
+    if (ngx_array_init(&sscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
+        != NGX_OK)
+    {
+        return NULL;
+    }
+
+    return sscf;
+}
+
+
+static char *
+ngx_mail_mx_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_mail_smtp_srv_conf_t *prev = parent;
+    ngx_mail_smtp_srv_conf_t *conf = child;
+
+    u_char                    *p, *auth;
+    size_t                     size;
+    ngx_str_t                 *c;
+    ngx_uint_t                 i, m;
+    ngx_mail_core_srv_conf_t  *cscf;
+
+    ngx_conf_merge_size_value(conf->client_buffer_size,
+                              prev->client_buffer_size,
+                              (size_t) ngx_pagesize);
+
+    ngx_conf_merge_msec_value(conf->greeting_delay,
+                              prev->greeting_delay, 0);
+
+    ngx_conf_merge_bitmask_value(conf->auth_methods,
+                              prev->auth_methods,
+                              (NGX_CONF_BITMASK_SET
+                               |NGX_MAIL_AUTH_PLAIN_ENABLED
+                               |NGX_MAIL_AUTH_LOGIN_ENABLED));
+
+
+    cscf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_core_module);
+
+    size = sizeof("220  ESMTP ready" CRLF) - 1 + cscf->server_name.len;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->greeting.len = size;
+    conf->greeting.data = p;
+
+    *p++ = '2'; *p++ = '2'; *p++ = '0'; *p++ = ' ';
+    p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
+    ngx_memcpy(p, " ESMTP ready" CRLF, sizeof(" ESMTP ready" CRLF) - 1);
+
+
+    size = sizeof("250 " CRLF) - 1 + cscf->server_name.len;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->server_name.len = size;
+    conf->server_name.data = p;
+
+    *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
+    p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
+    *p++ = CR; *p = LF;
+
+
+    if (conf->capabilities.nelts == 0) {
+        conf->capabilities = prev->capabilities;
+    }
+
+    size = sizeof("250-") - 1 + cscf->server_name.len + sizeof(CRLF) - 1
+           + sizeof("250 AUTH") - 1 + sizeof(CRLF) - 1;
+
+    c = conf->capabilities.elts;
+    for (i = 0; i < conf->capabilities.nelts; i++) {
+        size += sizeof("250 ") - 1 + c[i].len + sizeof(CRLF) - 1;
+    }
+
+    /*    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+	  m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
+	  m <<= 1, i++)
+	  {
+	  if (m & conf->auth_methods) {
+	  size += 1 + ngx_mail_smtp_auth_methods_names[i].len;
+	  }
+	  } */
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->capability.len = size;
+    conf->capability.data = p;
+
+    *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
+    p = ngx_cpymem(p, cscf->server_name.data, cscf->server_name.len);
+    *p++ = CR; *p++ = LF;
+
+    for (i = 0; i < conf->capabilities.nelts; i++) {
+        *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = '-';
+        p = ngx_cpymem(p, c[i].data, c[i].len);
+        *p++ = CR; *p++ = LF;
+    }
+
+    auth = p;
+
+    *p++ = '2'; *p++ = '5'; *p++ = '0'; *p++ = ' ';
+    *p++ = 'A'; *p++ = 'U'; *p++ = 'T'; *p++ = 'H';
+
+    /*    for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+	  m <= NGX_MAIL_AUTH_CRAM_MD5_ENABLED;
+	  m <<= 1, i++)
+	  {
+	  if (m & conf->auth_methods) {
+	  *p++ = ' ';
+	  p = ngx_cpymem(p, ngx_mail_smtp_auth_methods_names[i].data,
+	  ngx_mail_smtp_auth_methods_names[i].len);
+	  }
+	  } */
+
+    *p++ = CR; *p = LF;
+
+    size += sizeof("250 STARTTLS" CRLF) - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->starttls_capability.len = size;
+    conf->starttls_capability.data = p;
+
+    p = ngx_cpymem(p, conf->capability.data,
+                   conf->capability.len);
+
+    p = ngx_cpymem(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
+    *p++ = CR; *p = LF;
+
+    p = conf->starttls_capability.data
+        + (auth - conf->capability.data) + 3;
+    *p = '-';
+
+    size = (auth - conf->capability.data)
+            + sizeof("250 STARTTLS" CRLF) - 1;
+
+    p = ngx_palloc(cf->pool, size);
+    if (p == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    conf->starttls_only_capability.len = size;
+    conf->starttls_only_capability.data = p;
+
+    p = ngx_cpymem(p, conf->capability.data,
+                   auth - conf->capability.data);
+
+    ngx_memcpy(p, "250 STARTTLS" CRLF, sizeof("250 STARTTLS" CRLF) - 1);
+
+    return NGX_CONF_OK;
+}
Index: src/mail/ngx_mail_mx_module.h
===================================================================
--- src/mail/ngx_mail_mx_module.h	(.../original-0.5.34)	(revision 0)
+++ src/mail/ngx_mail_mx_module.h	(.../nginx-0.5.35_MX_PROXY_2)	(revision 48)
@@ -0,0 +1,42 @@
+
+/*
+ * Copyright (C) Igor Sysoev,
+ * Copypaste (M-w, C-y) NomadRain@rambler.ru
+ */
+
+
+#ifndef _NGX_MAIL_MX_MODULE_H_INCLUDED_
+#define _NGX_MAIL_MX_MODULE_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_mail.h>
+
+
+void ngx_mail_mx_init_session(ngx_mail_session_t *s, ngx_connection_t *c);
+void ngx_mail_mx_init_protocol(ngx_event_t *rev);
+void ngx_mail_mx_auth_state(ngx_event_t *rev);
+ngx_int_t ngx_mail_mx_parse_command(ngx_mail_session_t *s);
+
+typedef enum {
+    ngx_mx_start = 0,
+    ngx_mx_helo,
+    ngx_mx_helo_mail,
+    ngx_mx_helo_rcpt,
+    ngx_mx_helo_mail_rcpt,
+    ngx_mx_noxclient,
+    ngx_mx_xclient
+} ngx_mx_state_e;
+
+typedef struct {
+  ngx_str_t smtp_helo;
+  ngx_str_t smtp_mail;
+  ngx_str_t smtp_rcpt;
+  ngx_str_t smtp_helo_addition;
+} ngx_mail_mx_module_ctx_t;
+
+extern ngx_module_t  ngx_mail_mx_module;
+
+
+#endif /* _NGX_MAIL_MX_MODULE_H_INCLUDED_ */
Index: src/mail/ngx_mail_auth_http_module.c
===================================================================
--- src/mail/ngx_mail_auth_http_module.c	(.../original-0.5.34)	(revision 48)
+++ src/mail/ngx_mail_auth_http_module.c	(.../nginx-0.5.35_MX_PROXY_2)	(revision 48)
@@ -9,6 +9,7 @@
 #include <ngx_event.h>
 #include <ngx_event_connect.h>
 #include <ngx_mail.h>
+#include <ngx_mail_mx_module.h>
 
 
 typedef struct {
@@ -458,6 +459,7 @@
     ngx_int_t            rc, port, n;
     ngx_peer_addr_t     *peer;
     struct sockaddr_in  *sin;
+    ngx_mail_mx_module_ctx_t *mx_ctx;
 
     ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
                    "mail auth http process headers");
@@ -523,7 +525,7 @@
                            + sizeof(CRLF) - 1;
                     break;
 
-                default: /* NGX_MAIL_SMTP_PROTOCOL */
+                default: /* NGX_MAIL_SMTP_PROTOCOL || NGX_MAIL_MX_PROTOCOL*/
                     ctx->err = ctx->errmsg;
                     continue;
                 }
@@ -549,7 +551,7 @@
                     *p++ = 'N'; *p++ = 'O'; *p++ = ' ';
                     break;
 
-                default: /* NGX_MAIL_SMTP_PROTOCOL */
+                default: /* NGX_MAIL_SMTP_PROTOCOL || NGX_MAIL_MX_PROTOCOL*/
                     break;
                 }
 
@@ -666,6 +668,30 @@
                 continue;
             }
 
+
+            if (len == sizeof("Auth-Helo-Addition") - 1
+                && ngx_strncasecmp(ctx->header_name_start,
+                                   (u_char *) "Auth-Helo-Addition",
+                                   sizeof("Auth-Helo-Addition") - 1)
+                   == 0)
+	      {
+		mx_ctx = ngx_mail_get_module_ctx(s, ngx_mail_mx_module);
+		mx_ctx->smtp_helo_addition.len = ctx->header_end - ctx->header_start;
+		mx_ctx->smtp_helo_addition.data = ngx_palloc(s->connection->pool,
+							     mx_ctx->smtp_helo_addition.len);
+                if (mx_ctx->smtp_helo_addition.data == NULL) {
+                    ngx_close_connection(ctx->peer.connection);
+                    ngx_destroy_pool(ctx->pool);
+                    ngx_mail_session_internal_server_error(s);
+                    return;
+                }
+
+                ngx_memcpy(mx_ctx->smtp_helo_addition.data, ctx->header_start,
+                           mx_ctx->smtp_helo_addition.len);
+
+                continue;
+	      }
+
             /* ignore other headers */
 
             continue;
@@ -682,7 +708,7 @@
                 ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
                               "client login failed: \"%V\"", &ctx->errmsg);
 
-                if (s->protocol == NGX_MAIL_SMTP_PROTOCOL) {
+                if (s->protocol == NGX_MAIL_SMTP_PROTOCOL || NGX_MAIL_MX_PROTOCOL) {
 
                     if (ctx->errcode.len == 0) {
                         ctx->errcode = ngx_mail_smtp_errcode;
@@ -742,44 +768,52 @@
                 return;
             }
 
-            if (ctx->addr.len == 0 || ctx->port.len == 0) {
+/* 
+ * TODO: If a backend is not sended in headers - we pass NULL to proxy module.
+ * It will indicate that backend must be taken from config.
+ */
+	    
+	     /* if (ctx->addr.len == 0 || ctx->port.len == 0) {
                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                               "auth http server %V did not send server or port",
                               ctx->peer.name);
                 ngx_destroy_pool(ctx->pool);
                 ngx_mail_session_internal_server_error(s);
                 return;
-            }
+		}*/
+	      
+	    if (s->passwd.data == NULL
+		&& s->protocol != NGX_MAIL_SMTP_PROTOCOL
+		&& s->protocol != NGX_MAIL_MX_PROTOCOL)
+	      {
+		ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
+			      "auth http server %V did not send password",
+			      ctx->peer.name);
+		ngx_destroy_pool(ctx->pool);
+		ngx_mail_session_internal_server_error(s);
+		return;
+	      }
 
-            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",
-                              ctx->peer.name);
-                ngx_destroy_pool(ctx->pool);
-                ngx_mail_session_internal_server_error(s);
-                return;
-            }
+	    if (ctx->addr.len != 0 && ctx->port.len != 0) {
 
-            peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t));
-            if (peer == NULL) {
+	      peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t));
+	      if (peer == NULL) {
                 ngx_destroy_pool(ctx->pool);
                 ngx_mail_session_internal_server_error(s);
                 return;
-            }
-
-            sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in));
-            if (sin == NULL) {
+	      }
+	      
+	      sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in));
+	      if (sin == NULL) {
                 ngx_destroy_pool(ctx->pool);
                 ngx_mail_session_internal_server_error(s);
                 return;
-            }
-
-            sin->sin_family = AF_INET;
-
-            port = ngx_atoi(ctx->port.data, ctx->port.len);
-            if (port == NGX_ERROR || port < 1 || port > 65536) {
+	      }
+	      
+	      sin->sin_family = AF_INET;
+	      
+	      port = ngx_atoi(ctx->port.data, ctx->port.len);
+	      if (port == NGX_ERROR || port < 1 || port > 65536) {
                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                               "auth http server %V sent invalid server "
                               "port:\"%V\"",
@@ -787,13 +821,13 @@
                 ngx_destroy_pool(ctx->pool);
                 ngx_mail_session_internal_server_error(s);
                 return;
-            }
-
-            sin->sin_port = htons((in_port_t) port);
-
-            ctx->addr.data[ctx->addr.len] = '\0';
-            sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data);
-            if (sin->sin_addr.s_addr == INADDR_NONE) {
+	      }
+	      
+	      sin->sin_port = htons((in_port_t) port);
+	      
+	      ctx->addr.data[ctx->addr.len] = '\0';
+	      sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data);
+	      if (sin->sin_addr.s_addr == INADDR_NONE) {
                 ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                               "auth http server %V sent invalid server "
                               "address:\"%V\"",
@@ -801,49 +835,55 @@
                 ngx_destroy_pool(ctx->pool);
                 ngx_mail_session_internal_server_error(s);
                 return;
-            }
-
-            peer->sockaddr = (struct sockaddr *) sin;
-            peer->socklen = sizeof(struct sockaddr_in);
-
-            len = ctx->addr.len + 1 + ctx->port.len;
-
-            peer->name.len = len;
-
-            peer->name.data = ngx_palloc(s->connection->pool, len);
-            if (peer->name.data == NULL) {
+	      }
+	      
+	      peer->sockaddr = (struct sockaddr *) sin;
+	      peer->socklen = sizeof(struct sockaddr_in);
+	      
+	      len = ctx->addr.len + 1 + ctx->port.len;
+	      
+	      peer->name.len = len;
+	      
+	      peer->name.data = ngx_palloc(s->connection->pool, len);
+	      if (peer->name.data == NULL) {
                 ngx_destroy_pool(ctx->pool);
                 ngx_mail_session_internal_server_error(s);
                 return;
-            }
+	      }
+	      
+	      len = ctx->addr.len;
+	      
+	      ngx_memcpy(peer->name.data, ctx->addr.data, len);
+	      
+	      peer->name.data[len++] = ':';
+	      
+	      ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len);
+	      
+	      ngx_destroy_pool(ctx->pool);
 
-            len = ctx->addr.len;
+	    } else {
+	      peer = NULL;
+	      ngx_destroy_pool(ctx->pool);
+	    }
 
-            ngx_memcpy(peer->name.data, ctx->addr.data, len);
-
-            peer->name.data[len++] = ':';
-
-            ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len);
-
-            ngx_destroy_pool(ctx->pool);
             ngx_mail_proxy_init(s, peer);
-
+	    
             return;
         }
-
+	
         if (rc == NGX_AGAIN ) {
-            return;
+	  return;
         }
-
+	
         /* rc == NGX_ERROR */
-
+	
         ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
                       "auth http server %V sent invalid header in response",
                       ctx->peer.name);
         ngx_close_connection(ctx->peer.connection);
         ngx_destroy_pool(ctx->pool);
         ngx_mail_session_internal_server_error(s);
-
+	
         return;
     }
 }
@@ -1139,34 +1179,43 @@
     ngx_buf_t                 *b;
     ngx_str_t                  login, passwd;
     ngx_mail_core_srv_conf_t  *cscf;
+    ngx_mail_mx_module_ctx_t  *mx_ctx;
 
-    if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
-        return NULL;
-    }
+    if(s->protocol != NGX_MAIL_MX_PROTOCOL) {
+        if (ngx_mail_auth_http_escape(pool, &s->login, &login) != NGX_OK) {
+            return NULL;
+        }
 
-    if (ngx_mail_auth_http_escape(pool, &s->passwd, &passwd) != NGX_OK) {
-        return NULL;
+        if (ngx_mail_auth_http_escape(pool, &s->passwd, &passwd) != NGX_OK) {
+            return NULL;
+        }
+    } else {
+	mx_ctx = ngx_mail_get_module_ctx(s, ngx_mail_mx_module);
     }
 
     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
-                + ngx_mail_auth_http_method[s->auth_method].len
-                + sizeof(CRLF) - 1
+          + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1;
+
+    if(s->protocol != NGX_MAIL_MX_PROTOCOL) {
+      len += sizeof("Auth-Method: ") - 1
+          + ngx_mail_auth_http_method[s->auth_method].len + sizeof(CRLF) - 1
           + 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: ") - 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
-                + sizeof(CRLF) - 1
-          + ahcf->header.len
-          + sizeof(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;
+    } else {
+      len += sizeof("Client-Helo: ") - 1 + mx_ctx->smtp_helo.len + sizeof(CRLF) - 1
+          + sizeof("Client-Mail: ") - 1 + mx_ctx->smtp_mail.len + sizeof(CRLF) - 1
+          + sizeof("Client-Rcpt: ") - 1 + mx_ctx->smtp_rcpt.len + sizeof(CRLF) - 1;
+    }
 
+    len += sizeof("Client-IP: ") - 1 + s->connection->addr_text.len + sizeof(CRLF) - 1
+        + ahcf->header.len
+        + sizeof(CRLF) - 1;
+
     b = ngx_create_temp_buf(pool, len);
     if (b == NULL) {
         return NULL;
@@ -1182,36 +1231,49 @@
                          ahcf->host_header.len);
     *b->last++ = CR; *b->last++ = LF;
 
-    b->last = ngx_cpymem(b->last, "Auth-Method: ",
-                         sizeof("Auth-Method: ") - 1);
-    b->last = ngx_cpymem(b->last,
-                         ngx_mail_auth_http_method[s->auth_method].data,
-                         ngx_mail_auth_http_method[s->auth_method].len);
-    *b->last++ = CR; *b->last++ = LF;
+    if(s->protocol != NGX_MAIL_MX_PROTOCOL) {
+        b->last = ngx_cpymem(b->last, "Auth-Method: ",
+                             sizeof("Auth-Method: ") - 1);
+        b->last = ngx_cpymem(b->last,
+                             ngx_mail_auth_http_method[s->auth_method].data,
+                             ngx_mail_auth_http_method[s->auth_method].len);
+        *b->last++ = CR; *b->last++ = LF;
 
-    b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1);
-    b->last = ngx_copy(b->last, login.data, login.len);
-    *b->last++ = CR; *b->last++ = LF;
+        b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1);
+        b->last = ngx_copy(b->last, login.data, login.len);
+        *b->last++ = CR; *b->last++ = LF;
 
-    b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1);
-    b->last = ngx_copy(b->last, passwd.data, passwd.len);
-    *b->last++ = CR; *b->last++ = LF;
+        b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1);
+        b->last = ngx_copy(b->last, passwd.data, passwd.len);
+        *b->last++ = CR; *b->last++ = LF;
 
-    if (s->auth_method != NGX_MAIL_AUTH_PLAIN && s->salt.len) {
-        b->last = ngx_cpymem(b->last, "Auth-Salt: ", sizeof("Auth-Salt: ") - 1);
-        b->last = ngx_copy(b->last, s->salt.data, s->salt.len);
+        if (s->auth_method != NGX_MAIL_AUTH_PLAIN && s->salt.len) {
+            b->last = ngx_cpymem(b->last, "Auth-Salt: ", sizeof("Auth-Salt: ") - 1);
+            b->last = ngx_copy(b->last, s->salt.data, s->salt.len);
 
-        s->passwd.data = NULL;
-    }
+            s->passwd.data = NULL;
+        }
 
-    b->last = ngx_cpymem(b->last, "Auth-Protocol: ",
-                         sizeof("Auth-Protocol: ") - 1);
-    b->last = ngx_cpymem(b->last, cscf->protocol->name.data,
-                         cscf->protocol->name.len);
-    *b->last++ = CR; *b->last++ = LF;
+        b->last = ngx_cpymem(b->last, "Auth-Protocol: ",
+                             sizeof("Auth-Protocol: ") - 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,
-                          s->login_attempt);
+        b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %ui" CRLF,
+                              s->login_attempt);
+    } else {
+        b->last = ngx_cpymem(b->last, "Client-Helo: ", sizeof("Client-Helo: ") - 1);
+        b->last = ngx_copy(b->last, mx_ctx->smtp_helo.data, mx_ctx->smtp_helo.len);
+	*b->last++ = CR; *b->last++ = LF;
+        b->last = ngx_cpymem(b->last, "Client-Mail: ", sizeof("Client-Mail: ") - 1);
+        b->last = ngx_copy(b->last, mx_ctx->smtp_mail.data, mx_ctx->smtp_mail.len);
+	*b->last++ = CR; *b->last++ = LF;
+        b->last = ngx_cpymem(b->last, "Client-Rcpt: ", sizeof("Client-Rcpt: ") - 1);
+        b->last = ngx_copy(b->last, mx_ctx->smtp_rcpt.data, mx_ctx->smtp_rcpt.len);
+	*b->last++ = CR; *b->last++ = LF;
+        /*What more???*/
+    }
 
     b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1);
     b->last = ngx_copy(b->last, s->connection->addr_text.data,
Index: auto/sources
===================================================================
--- auto/sources	(.../original-0.5.34)	(revision 48)
+++ auto/sources	(.../nginx-0.5.35_MX_PROXY_2)	(revision 48)
@@ -440,6 +440,11 @@
 MAIL_SMTP_SRCS="src/mail/ngx_mail_smtp_module.c \
                 src/mail/ngx_mail_smtp_handler.c"
 
+MAIL_MX_MODULE="ngx_mail_mx_module"
+MAIL_MX_DEPS="src/mail/ngx_mail_mx_module.h"
+MAIL_MX_SRCS="src/mail/ngx_mail_mx_module.c \
+                src/mail/ngx_mail_mx_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"
Index: auto/options
===================================================================
--- auto/options	(.../original-0.5.34)	(revision 48)
+++ auto/options	(.../nginx-0.5.35_MX_PROXY_2)	(revision 48)
@@ -85,6 +85,7 @@
 MAIL_POP3=YES
 MAIL_IMAP=YES
 MAIL_SMTP=YES
+MAIL_MX=YES
 
 NGX_ADDONS=
 
@@ -197,6 +198,7 @@
         --without-mail_pop3_module)      MAIL_POP3=NO               ;;
         --without-mail_imap_module)      MAIL_IMAP=NO               ;;
         --without-mail_smtp_module)      MAIL_SMTP=NO               ;;
+        --without-mail_mx_module)        MAIL_MX=NO               ;;
 
         --add-module=*)                  NGX_ADDONS="$NGX_ADDONS $value" ;;
 
@@ -312,6 +314,7 @@
   --without-mail_pop3_module         disable ngx_mail_pop3_module
   --without-mail_imap_module         disable ngx_mail_imap_module
   --without-mail_smtp_module         disable ngx_mail_smtp_module
+  --without-mail_mx_module         disable ngx_mail_mx_module
 
   --add-module=PATH                  enable an external module
 
Index: auto/modules
===================================================================
--- auto/modules	(.../original-0.5.34)	(revision 48)
+++ auto/modules	(.../nginx-0.5.35_MX_PROXY_2)	(revision 48)
@@ -361,6 +361,12 @@
         MAIL_SRCS="$MAIL_SRCS $MAIL_SMTP_SRCS"
     fi
 
+    if [ $MAIL_MX = YES ]; then
+        modules="$modules $MAIL_MX_MODULE"
+        MAIL_DEPS="$MAIL_DEPS $MAIL_MX_DEPS"
+        MAIL_SRCS="$MAIL_SRCS $MAIL_MX_SRCS"
+    fi
+
     modules="$modules $MAIL_AUTH_HTTP_MODULE"
     MAIL_SRCS="$MAIL_SRCS $MAIL_AUTH_HTTP_SRCS"
 
