src/mail/ngx_mail_core_module.c - nginx source code

Global variables defined

Functions defined

Source code


  1. /*
  2. * Copyright (C) Igor Sysoev
  3. * Copyright (C) Nginx, Inc.
  4. */


  5. #include <ngx_config.h>
  6. #include <ngx_core.h>
  7. #include <ngx_event.h>
  8. #include <ngx_mail.h>


  9. static void *ngx_mail_core_create_main_conf(ngx_conf_t *cf);
  10. static void *ngx_mail_core_create_srv_conf(ngx_conf_t *cf);
  11. static char *ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent,
  12.     void *child);
  13. static char *ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd,
  14.     void *conf);
  15. static char *ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd,
  16.     void *conf);
  17. static char *ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd,
  18.     void *conf);
  19. static char *ngx_mail_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
  20.     void *conf);
  21. static char *ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
  22.     void *conf);


  23. static ngx_command_t  ngx_mail_core_commands[] = {

  24.     { ngx_string("server"),
  25.       NGX_MAIL_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
  26.       ngx_mail_core_server,
  27.       0,
  28.       0,
  29.       NULL },

  30.     { ngx_string("listen"),
  31.       NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
  32.       ngx_mail_core_listen,
  33.       NGX_MAIL_SRV_CONF_OFFSET,
  34.       0,
  35.       NULL },

  36.     { ngx_string("protocol"),
  37.       NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  38.       ngx_mail_core_protocol,
  39.       NGX_MAIL_SRV_CONF_OFFSET,
  40.       0,
  41.       NULL },

  42.     { ngx_string("timeout"),
  43.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  44.       ngx_conf_set_msec_slot,
  45.       NGX_MAIL_SRV_CONF_OFFSET,
  46.       offsetof(ngx_mail_core_srv_conf_t, timeout),
  47.       NULL },

  48.     { ngx_string("server_name"),
  49.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  50.       ngx_conf_set_str_slot,
  51.       NGX_MAIL_SRV_CONF_OFFSET,
  52.       offsetof(ngx_mail_core_srv_conf_t, server_name),
  53.       NULL },

  54.     { ngx_string("error_log"),
  55.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
  56.       ngx_mail_core_error_log,
  57.       NGX_MAIL_SRV_CONF_OFFSET,
  58.       0,
  59.       NULL },

  60.     { ngx_string("resolver"),
  61.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
  62.       ngx_mail_core_resolver,
  63.       NGX_MAIL_SRV_CONF_OFFSET,
  64.       0,
  65.       NULL },

  66.     { ngx_string("resolver_timeout"),
  67.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  68.       ngx_conf_set_msec_slot,
  69.       NGX_MAIL_SRV_CONF_OFFSET,
  70.       offsetof(ngx_mail_core_srv_conf_t, resolver_timeout),
  71.       NULL },

  72.     { ngx_string("max_errors"),
  73.       NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
  74.       ngx_conf_set_num_slot,
  75.       NGX_MAIL_SRV_CONF_OFFSET,
  76.       offsetof(ngx_mail_core_srv_conf_t, max_errors),
  77.       NULL },

  78.       ngx_null_command
  79. };


  80. static ngx_mail_module_t  ngx_mail_core_module_ctx = {
  81.     NULL,                                  /* protocol */

  82.     ngx_mail_core_create_main_conf,        /* create main configuration */
  83.     NULL,                                  /* init main configuration */

  84.     ngx_mail_core_create_srv_conf,         /* create server configuration */
  85.     ngx_mail_core_merge_srv_conf           /* merge server configuration */
  86. };


  87. ngx_module_t  ngx_mail_core_module = {
  88.     NGX_MODULE_V1,
  89.     &ngx_mail_core_module_ctx,             /* module context */
  90.     ngx_mail_core_commands,                /* module directives */
  91.     NGX_MAIL_MODULE,                       /* module type */
  92.     NULL,                                  /* init master */
  93.     NULL,                                  /* init module */
  94.     NULL,                                  /* init process */
  95.     NULL,                                  /* init thread */
  96.     NULL,                                  /* exit thread */
  97.     NULL,                                  /* exit process */
  98.     NULL,                                  /* exit master */
  99.     NGX_MODULE_V1_PADDING
  100. };


  101. static void *
  102. ngx_mail_core_create_main_conf(ngx_conf_t *cf)
  103. {
  104.     ngx_mail_core_main_conf_t  *cmcf;

  105.     cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_main_conf_t));
  106.     if (cmcf == NULL) {
  107.         return NULL;
  108.     }

  109.     if (ngx_array_init(&cmcf->servers, cf->pool, 4,
  110.                        sizeof(ngx_mail_core_srv_conf_t *))
  111.         != NGX_OK)
  112.     {
  113.         return NULL;
  114.     }

  115.     if (ngx_array_init(&cmcf->listen, cf->pool, 4, sizeof(ngx_mail_listen_t))
  116.         != NGX_OK)
  117.     {
  118.         return NULL;
  119.     }

  120.     return cmcf;
  121. }


  122. static void *
  123. ngx_mail_core_create_srv_conf(ngx_conf_t *cf)
  124. {
  125.     ngx_mail_core_srv_conf_t  *cscf;

  126.     cscf = ngx_pcalloc(cf->pool, sizeof(ngx_mail_core_srv_conf_t));
  127.     if (cscf == NULL) {
  128.         return NULL;
  129.     }

  130.     /*
  131.      * set by ngx_pcalloc():
  132.      *
  133.      *     cscf->protocol = NULL;
  134.      *     cscf->error_log = NULL;
  135.      */

  136.     cscf->timeout = NGX_CONF_UNSET_MSEC;
  137.     cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;

  138.     cscf->max_errors = NGX_CONF_UNSET_UINT;

  139.     cscf->resolver = NGX_CONF_UNSET_PTR;

  140.     cscf->file_name = cf->conf_file->file.name.data;
  141.     cscf->line = cf->conf_file->line;

  142.     return cscf;
  143. }


  144. static char *
  145. ngx_mail_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
  146. {
  147.     ngx_mail_core_srv_conf_t *prev = parent;
  148.     ngx_mail_core_srv_conf_t *conf = child;

  149.     ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
  150.     ngx_conf_merge_msec_value(conf->resolver_timeout, prev->resolver_timeout,
  151.                               30000);

  152.     ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5);

  153.     ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");

  154.     if (conf->server_name.len == 0) {
  155.         conf->server_name = cf->cycle->hostname;
  156.     }

  157.     if (conf->protocol == NULL) {
  158.         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  159.                       "unknown mail protocol for server in %s:%ui",
  160.                       conf->file_name, conf->line);
  161.         return NGX_CONF_ERROR;
  162.     }

  163.     if (conf->error_log == NULL) {
  164.         if (prev->error_log) {
  165.             conf->error_log = prev->error_log;
  166.         } else {
  167.             conf->error_log = &cf->cycle->new_log;
  168.         }
  169.     }

  170.     ngx_conf_merge_ptr_value(conf->resolver, prev->resolver, NULL);

  171.     return NGX_CONF_OK;
  172. }


  173. static char *
  174. ngx_mail_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  175. {
  176.     char                       *rv;
  177.     void                       *mconf;
  178.     ngx_uint_t                  m;
  179.     ngx_conf_t                  pcf;
  180.     ngx_mail_module_t          *module;
  181.     ngx_mail_conf_ctx_t        *ctx, *mail_ctx;
  182.     ngx_mail_core_srv_conf_t   *cscf, **cscfp;
  183.     ngx_mail_core_main_conf_t  *cmcf;

  184.     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_mail_conf_ctx_t));
  185.     if (ctx == NULL) {
  186.         return NGX_CONF_ERROR;
  187.     }

  188.     mail_ctx = cf->ctx;
  189.     ctx->main_conf = mail_ctx->main_conf;

  190.     /* the server{}'s srv_conf */

  191.     ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_mail_max_module);
  192.     if (ctx->srv_conf == NULL) {
  193.         return NGX_CONF_ERROR;
  194.     }

  195.     for (m = 0; cf->cycle->modules[m]; m++) {
  196.         if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
  197.             continue;
  198.         }

  199.         module = cf->cycle->modules[m]->ctx;

  200.         if (module->create_srv_conf) {
  201.             mconf = module->create_srv_conf(cf);
  202.             if (mconf == NULL) {
  203.                 return NGX_CONF_ERROR;
  204.             }

  205.             ctx->srv_conf[cf->cycle->modules[m]->ctx_index] = mconf;
  206.         }
  207.     }

  208.     /* the server configuration context */

  209.     cscf = ctx->srv_conf[ngx_mail_core_module.ctx_index];
  210.     cscf->ctx = ctx;

  211.     cmcf = ctx->main_conf[ngx_mail_core_module.ctx_index];

  212.     cscfp = ngx_array_push(&cmcf->servers);
  213.     if (cscfp == NULL) {
  214.         return NGX_CONF_ERROR;
  215.     }

  216.     *cscfp = cscf;


  217.     /* parse inside server{} */

  218.     pcf = *cf;
  219.     cf->ctx = ctx;
  220.     cf->cmd_type = NGX_MAIL_SRV_CONF;

  221.     rv = ngx_conf_parse(cf, NULL);

  222.     *cf = pcf;

  223.     if (rv == NGX_CONF_OK && !cscf->listen) {
  224.         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
  225.                       "no \"listen\" is defined for server in %s:%ui",
  226.                       cscf->file_name, cscf->line);
  227.         return NGX_CONF_ERROR;
  228.     }

  229.     return rv;
  230. }


  231. static char *
  232. ngx_mail_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  233. {
  234.     ngx_mail_core_srv_conf_t  *cscf = conf;

  235.     ngx_str_t                  *value, size;
  236.     ngx_url_t                   u;
  237.     ngx_uint_t                  i, n, m;
  238.     ngx_mail_listen_t          *ls, *als, *nls;
  239.     ngx_mail_module_t          *module;
  240.     ngx_mail_core_main_conf_t  *cmcf;

  241.     cscf->listen = 1;

  242.     value = cf->args->elts;

  243.     ngx_memzero(&u, sizeof(ngx_url_t));

  244.     u.url = value[1];
  245.     u.listen = 1;

  246.     if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
  247.         if (u.err) {
  248.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  249.                                "%s in \"%V\" of the \"listen\" directive",
  250.                                u.err, &u.url);
  251.         }

  252.         return NGX_CONF_ERROR;
  253.     }

  254.     cmcf = ngx_mail_conf_get_module_main_conf(cf, ngx_mail_core_module);

  255.     ls = ngx_array_push(&cmcf->listen);
  256.     if (ls == NULL) {
  257.         return NGX_CONF_ERROR;
  258.     }

  259.     ngx_memzero(ls, sizeof(ngx_mail_listen_t));

  260.     ls->backlog = NGX_LISTEN_BACKLOG;
  261.     ls->rcvbuf = -1;
  262.     ls->sndbuf = -1;
  263.     ls->ctx = cf->ctx;

  264. #if (NGX_HAVE_INET6)
  265.     ls->ipv6only = 1;
  266. #endif

  267.     if (cscf->protocol == NULL) {
  268.         for (m = 0; cf->cycle->modules[m]; m++) {
  269.             if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
  270.                 continue;
  271.             }

  272.             module = cf->cycle->modules[m]->ctx;

  273.             if (module->protocol == NULL) {
  274.                 continue;
  275.             }

  276.             for (i = 0; module->protocol->port[i]; i++) {
  277.                 if (module->protocol->port[i] == u.port) {
  278.                     cscf->protocol = module->protocol;
  279.                     break;
  280.                 }
  281.             }
  282.         }
  283.     }

  284.     for (i = 2; i < cf->args->nelts; i++) {

  285.         if (ngx_strcmp(value[i].data, "bind") == 0) {
  286.             ls->bind = 1;
  287.             continue;
  288.         }

  289.         if (ngx_strncmp(value[i].data, "backlog=", 8) == 0) {
  290.             ls->backlog = ngx_atoi(value[i].data + 8, value[i].len - 8);
  291.             ls->bind = 1;

  292.             if (ls->backlog == NGX_ERROR || ls->backlog == 0) {
  293.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  294.                                    "invalid backlog \"%V\"", &value[i]);
  295.                 return NGX_CONF_ERROR;
  296.             }

  297.             continue;
  298.         }

  299.         if (ngx_strncmp(value[i].data, "rcvbuf=", 7) == 0) {
  300.             size.len = value[i].len - 7;
  301.             size.data = value[i].data + 7;

  302.             ls->rcvbuf = ngx_parse_size(&size);
  303.             ls->bind = 1;

  304.             if (ls->rcvbuf == NGX_ERROR) {
  305.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  306.                                    "invalid rcvbuf \"%V\"", &value[i]);
  307.                 return NGX_CONF_ERROR;
  308.             }

  309.             continue;
  310.         }

  311.         if (ngx_strncmp(value[i].data, "sndbuf=", 7) == 0) {
  312.             size.len = value[i].len - 7;
  313.             size.data = value[i].data + 7;

  314.             ls->sndbuf = ngx_parse_size(&size);
  315.             ls->bind = 1;

  316.             if (ls->sndbuf == NGX_ERROR) {
  317.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  318.                                    "invalid sndbuf \"%V\"", &value[i]);
  319.                 return NGX_CONF_ERROR;
  320.             }

  321.             continue;
  322.         }

  323.         if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
  324. #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
  325.             if (ngx_strcmp(&value[i].data[10], "n") == 0) {
  326.                 ls->ipv6only = 1;

  327.             } else if (ngx_strcmp(&value[i].data[10], "ff") == 0) {
  328.                 ls->ipv6only = 0;

  329.             } else {
  330.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  331.                                    "invalid ipv6only flags \"%s\"",
  332.                                    &value[i].data[9]);
  333.                 return NGX_CONF_ERROR;
  334.             }

  335.             ls->bind = 1;
  336.             continue;
  337. #else
  338.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  339.                                "ipv6only is not supported "
  340.                                "on this platform");
  341.             return NGX_CONF_ERROR;
  342. #endif
  343.         }

  344.         if (ngx_strcmp(value[i].data, "ssl") == 0) {
  345. #if (NGX_MAIL_SSL)
  346.             ngx_mail_ssl_conf_t  *sslcf;

  347.             sslcf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_ssl_module);

  348.             sslcf->listen = 1;
  349.             sslcf->file = cf->conf_file->file.name.data;
  350.             sslcf->line = cf->conf_file->line;

  351.             ls->ssl = 1;

  352.             continue;
  353. #else
  354.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  355.                                "the \"ssl\" parameter requires "
  356.                                "ngx_mail_ssl_module");
  357.             return NGX_CONF_ERROR;
  358. #endif
  359.         }

  360.         if (ngx_strncmp(value[i].data, "so_keepalive=", 13) == 0) {

  361.             if (ngx_strcmp(&value[i].data[13], "on") == 0) {
  362.                 ls->so_keepalive = 1;

  363.             } else if (ngx_strcmp(&value[i].data[13], "off") == 0) {
  364.                 ls->so_keepalive = 2;

  365.             } else {

  366. #if (NGX_HAVE_KEEPALIVE_TUNABLE)
  367.                 u_char     *p, *end;
  368.                 ngx_str_t   s;

  369.                 end = value[i].data + value[i].len;
  370.                 s.data = value[i].data + 13;

  371.                 p = ngx_strlchr(s.data, end, ':');
  372.                 if (p == NULL) {
  373.                     p = end;
  374.                 }

  375.                 if (p > s.data) {
  376.                     s.len = p - s.data;

  377.                     ls->tcp_keepidle = ngx_parse_time(&s, 1);
  378.                     if (ls->tcp_keepidle == (time_t) NGX_ERROR) {
  379.                         goto invalid_so_keepalive;
  380.                     }
  381.                 }

  382.                 s.data = (p < end) ? (p + 1) : end;

  383.                 p = ngx_strlchr(s.data, end, ':');
  384.                 if (p == NULL) {
  385.                     p = end;
  386.                 }

  387.                 if (p > s.data) {
  388.                     s.len = p - s.data;

  389.                     ls->tcp_keepintvl = ngx_parse_time(&s, 1);
  390.                     if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
  391.                         goto invalid_so_keepalive;
  392.                     }
  393.                 }

  394.                 s.data = (p < end) ? (p + 1) : end;

  395.                 if (s.data < end) {
  396.                     s.len = end - s.data;

  397.                     ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
  398.                     if (ls->tcp_keepcnt == NGX_ERROR) {
  399.                         goto invalid_so_keepalive;
  400.                     }
  401.                 }

  402.                 if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
  403.                     && ls->tcp_keepcnt == 0)
  404.                 {
  405.                     goto invalid_so_keepalive;
  406.                 }

  407.                 ls->so_keepalive = 1;

  408. #else

  409.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  410.                                    "the \"so_keepalive\" parameter accepts "
  411.                                    "only \"on\" or \"off\" on this platform");
  412.                 return NGX_CONF_ERROR;

  413. #endif
  414.             }

  415.             ls->bind = 1;

  416.             continue;

  417. #if (NGX_HAVE_KEEPALIVE_TUNABLE)
  418.         invalid_so_keepalive:

  419.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  420.                                "invalid so_keepalive value: \"%s\"",
  421.                                &value[i].data[13]);
  422.             return NGX_CONF_ERROR;
  423. #endif
  424.         }

  425.         if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) {
  426.             ls->proxy_protocol = 1;
  427.             continue;
  428.         }

  429.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  430.                            "invalid parameter \"%V\"", &value[i]);
  431.         return NGX_CONF_ERROR;
  432.     }

  433.     for (n = 0; n < u.naddrs; n++) {

  434.         for (i = 0; i < n; i++) {
  435.             if (ngx_cmp_sockaddr(u.addrs[n].sockaddr, u.addrs[n].socklen,
  436.                                  u.addrs[i].sockaddr, u.addrs[i].socklen, 1)
  437.                 == NGX_OK)
  438.             {
  439.                 goto next;
  440.             }
  441.         }

  442.         if (n != 0) {
  443.             nls = ngx_array_push(&cmcf->listen);
  444.             if (nls == NULL) {
  445.                 return NGX_CONF_ERROR;
  446.             }

  447.             *nls = *ls;

  448.         } else {
  449.             nls = ls;
  450.         }

  451.         nls->sockaddr = u.addrs[n].sockaddr;
  452.         nls->socklen = u.addrs[n].socklen;
  453.         nls->addr_text = u.addrs[n].name;
  454.         nls->wildcard = ngx_inet_wildcard(nls->sockaddr);

  455.         als = cmcf->listen.elts;

  456.         for (i = 0; i < cmcf->listen.nelts - 1; i++) {

  457.             if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen,
  458.                                  nls->sockaddr, nls->socklen, 1)
  459.                 != NGX_OK)
  460.             {
  461.                 continue;
  462.             }

  463.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  464.                                "duplicate \"%V\" address and port pair",
  465.                                &nls->addr_text);
  466.             return NGX_CONF_ERROR;
  467.         }

  468.     next:
  469.         continue;
  470.     }

  471.     return NGX_CONF_OK;
  472. }


  473. static char *
  474. ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  475. {
  476.     ngx_mail_core_srv_conf_t  *cscf = conf;

  477.     ngx_str_t          *value;
  478.     ngx_uint_t          m;
  479.     ngx_mail_module_t  *module;

  480.     value = cf->args->elts;

  481.     for (m = 0; cf->cycle->modules[m]; m++) {
  482.         if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
  483.             continue;
  484.         }

  485.         module = cf->cycle->modules[m]->ctx;

  486.         if (module->protocol
  487.             && ngx_strcmp(module->protocol->name.data, value[1].data) == 0)
  488.         {
  489.             cscf->protocol = module->protocol;

  490.             return NGX_CONF_OK;
  491.         }
  492.     }

  493.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  494.                        "unknown protocol \"%V\"", &value[1]);
  495.     return NGX_CONF_ERROR;
  496. }


  497. static char *
  498. ngx_mail_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  499. {
  500.     ngx_mail_core_srv_conf_t  *cscf = conf;

  501.     return ngx_log_set_log(cf, &cscf->error_log);
  502. }


  503. static char *
  504. ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  505. {
  506.     ngx_mail_core_srv_conf_t  *cscf = conf;

  507.     ngx_str_t  *value;

  508.     value = cf->args->elts;

  509.     if (cscf->resolver != NGX_CONF_UNSET_PTR) {
  510.         return "is duplicate";
  511.     }

  512.     if (ngx_strcmp(value[1].data, "off") == 0) {
  513.         cscf->resolver = NULL;
  514.         return NGX_CONF_OK;
  515.     }

  516.     cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
  517.     if (cscf->resolver == NULL) {
  518.         return NGX_CONF_ERROR;
  519.     }

  520.     return NGX_CONF_OK;
  521. }


  522. char *
  523. ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  524. {
  525.     char  *p = conf;

  526.     ngx_str_t    *c, *value;
  527.     ngx_uint_t    i;
  528.     ngx_array_t  *a;

  529.     a = (ngx_array_t *) (p + cmd->offset);

  530.     value = cf->args->elts;

  531.     for (i = 1; i < cf->args->nelts; i++) {
  532.         c = ngx_array_push(a);
  533.         if (c == NULL) {
  534.             return NGX_CONF_ERROR;
  535.         }

  536.         *c = value[i];
  537.     }

  538.     return NGX_CONF_OK;
  539. }