void
ngx_mail_imap_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
{
    ngx_mail_core_srv_conf_t  *cscf;
    ngx_mail_imap_srv_conf_t  *iscf;
    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->out = iscf->greeting;

    if (iscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
    	if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
			ngx_mail_session_internal_server_error(s);
			return;
		}
	}

    c->read->handler = ngx_mail_imap_init_protocol;

    /*ngx_add_timer(c->read, cscf->timeout);

    if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
        ngx_mail_close_connection(c);
    }

    ngx_mail_send(c->write);*/
}
static ngx_int_t
ngx_mail_imap_authenticate(ngx_mail_session_t *s, ngx_connection_t *c)
{
    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)) {
        return NGX_MAIL_PARSE_INVALID_COMMAND;
    }
#endif

    rc = ngx_mail_auth_parse(s, c);

    switch (rc) {

    case NGX_MAIL_AUTH_LOGIN:

        s->out.len = sizeof(imap_username) - 1;
        s->out.data = imap_username;
        s->mail_state = ngx_imap_auth_login_username;

        return NGX_OK;

    case NGX_MAIL_AUTH_PLAIN:

        s->out.len = sizeof(imap_plain_next) - 1;
        s->out.data = imap_plain_next;
        s->mail_state = ngx_imap_auth_plain;

        return NGX_OK;

    case NGX_MAIL_AUTH_CRAM_MD5:

        iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);

        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;
            }
        }

        if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
            s->mail_state = ngx_imap_auth_cram_md5;
            return NGX_OK;
        }

        return NGX_ERROR;
    }

    return rc;
}
static ngx_int_t
ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c)
{
    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))
    {
        return NGX_MAIL_PARSE_INVALID_COMMAND;
    }
#endif
    if (s->args.nelts == 0)
    {
        ngx_str_set(&s->out, smtp_invalid_argument);
        s->state = 0;
        return NGX_OK;
    }
    rc = ngx_mail_auth_parse(s, c);
    switch (rc)
    {
    case NGX_MAIL_AUTH_LOGIN:
        ngx_str_set(&s->out, smtp_username);
        s->mail_state = ngx_smtp_auth_login_username;
        return NGX_OK;
    case NGX_MAIL_AUTH_LOGIN_USERNAME:
        ngx_str_set(&s->out, smtp_password);
        s->mail_state = ngx_smtp_auth_login_password;
        return ngx_mail_auth_login_username(s, c, 1);
    case NGX_MAIL_AUTH_PLAIN:
        ngx_str_set(&s->out, smtp_next);
        s->mail_state = ngx_smtp_auth_plain;
        return NGX_OK;
    case NGX_MAIL_AUTH_CRAM_MD5:
        sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
        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;
            }
        }
        if (ngx_mail_auth_cram_md5_salt(s, c, "334 ", 4) == NGX_OK)
        {
            s->mail_state = ngx_smtp_auth_cram_md5;
            return NGX_OK;
        }
        return NGX_ERROR;
    }
    return rc;
}
void
ngx_mail_pop3_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
{
    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 (pscf->auth_methods
        & (NGX_MAIL_AUTH_APOP_ENABLED|NGX_MAIL_AUTH_CRAM_MD5_ENABLED))
    {
        if (ngx_mail_salt(s, c, cscf) != NGX_OK) {
            ngx_mail_session_internal_server_error(s);
            return;
        }

        s->out.data = ngx_pnalloc(c->pool, sizeof(pop3_greeting) + s->salt.len);
        if (s->out.data == NULL) {
            ngx_mail_session_internal_server_error(s);
            return;
        }

        p = ngx_cpymem(s->out.data, pop3_greeting, sizeof(pop3_greeting) - 3);
        *p++ = ' ';
        p = ngx_cpymem(p, s->salt.data, s->salt.len);

        s->out.len = p - s->out.data;

    } else {
        ngx_str_set(&s->out, pop3_greeting);
    }

    c->read->handler = ngx_mail_pop3_init_protocol;

    ngx_add_timer(c->read, cscf->timeout);

    if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
        ngx_mail_close_connection(c);
    }

    ngx_mail_send(c->write);
}
static ngx_int_t
ngx_mail_imap_authenticate(ngx_mail_session_t *s, ngx_connection_t *c)
{
    ngx_int_t                  rc, res;
    ngx_mail_core_srv_conf_t  *cscf;
    ngx_mail_imap_srv_conf_t  *iscf;

    rc = ngx_mail_auth_parse(s, c);
    iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);

    switch (rc) {

    case NGX_MAIL_AUTH_LOGIN:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }
        ngx_str_set(&s->out, imap_username);
        s->mail_state = ngx_imap_auth_login_username;

        return NGX_MAIL_AUTH_ARGUMENT;

    case NGX_MAIL_AUTH_LOGIN_USERNAME:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }

        res = ngx_mail_auth_login_username(s, c, 1);
        if (res == NGX_MAIL_AUTH_ARGUMENT) {
            ngx_str_set(&s->out, imap_password);
            s->mail_state = ngx_imap_auth_login_password;
            return NGX_MAIL_AUTH_ARGUMENT;
        } else {
            return res;
        }

    case NGX_MAIL_AUTH_PLAIN:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }
        ngx_str_set(&s->out, imap_plain_next);
        s->mail_state = ngx_imap_auth_plain;

        return NGX_MAIL_AUTH_ARGUMENT;

    case NGX_MAIL_AUTH_PLAIN_IR:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }
        return ngx_mail_auth_plain(s, c, 1);

    case NGX_MAIL_AUTH_GSSAPI:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }
        ngx_str_set(&s->out, imap_gssapi_next);
        s->mail_state = ngx_imap_auth_gssapi;

        return NGX_MAIL_AUTH_ARGUMENT;

    case NGX_MAIL_AUTH_GSSAPI_IR:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }
        s->mail_state = ngx_imap_auth_gssapi;
        ngx_str_t output;
        ngx_str_set(&output, "");
        res = ngx_mail_auth_gssapi(s, c, &output);
        if(res == NGX_MAIL_AUTH_ARGUMENT) {
            s->out = output;
            return NGX_MAIL_AUTH_ARGUMENT;
        } else {
            return res;
        }

    case NGX_MAIL_AUTH_CRAM_MD5:
        if (!(iscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
            return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
        }

        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;
            }
        }

        if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
            s->mail_state = ngx_imap_auth_cram_md5;
            return NGX_MAIL_AUTH_ARGUMENT;
        }

        return NGX_ERROR;
    }

    return rc;
}