src/mail/ngx_mail_core_module.c - nginx

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, "multipath") == 0) {
  345. #ifdef IPPROTO_MPTCP
  346.             ls->protocol = IPPROTO_MPTCP;
  347.             ls->bind = 1;
  348. #else
  349.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  350.                                "multipath is not supported "
  351.                                "on this platform, ignored");
  352. #endif
  353.             continue;
  354.         }

  355.         if (ngx_strcmp(value[i].data, "ssl") == 0) {
  356. #if (NGX_MAIL_SSL)
  357.             ngx_mail_ssl_conf_t  *sslcf;

  358.             sslcf = ngx_mail_conf_get_module_srv_conf(cf, ngx_mail_ssl_module);

  359.             sslcf->listen = 1;
  360.             sslcf->file = cf->conf_file->file.name.data;
  361.             sslcf->line = cf->conf_file->line;

  362.             ls->ssl = 1;

  363.             continue;
  364. #else
  365.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  366.                                "the \"ssl\" parameter requires "
  367.                                "ngx_mail_ssl_module");
  368.             return NGX_CONF_ERROR;
  369. #endif
  370.         }

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

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

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

  376.             } else {

  377. #if (NGX_HAVE_KEEPALIVE_TUNABLE)
  378.                 u_char     *p, *end;
  379.                 ngx_str_t   s;

  380.                 end = value[i].data + value[i].len;
  381.                 s.data = value[i].data + 13;

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

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

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

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

  394.                 p = ngx_strlchr(s.data, end, ':');
  395.                 if (p == NULL) {
  396.                     p = end;
  397.                 }

  398.                 if (p > s.data) {
  399.                     s.len = p - s.data;

  400.                     ls->tcp_keepintvl = ngx_parse_time(&s, 1);
  401.                     if (ls->tcp_keepintvl == (time_t) NGX_ERROR) {
  402.                         goto invalid_so_keepalive;
  403.                     }
  404.                 }

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

  406.                 if (s.data < end) {
  407.                     s.len = end - s.data;

  408.                     ls->tcp_keepcnt = ngx_atoi(s.data, s.len);
  409.                     if (ls->tcp_keepcnt == NGX_ERROR) {
  410.                         goto invalid_so_keepalive;
  411.                     }
  412.                 }

  413.                 if (ls->tcp_keepidle == 0 && ls->tcp_keepintvl == 0
  414.                     && ls->tcp_keepcnt == 0)
  415.                 {
  416.                     goto invalid_so_keepalive;
  417.                 }

  418.                 ls->so_keepalive = 1;

  419. #else

  420.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  421.                                    "the \"so_keepalive\" parameter accepts "
  422.                                    "only \"on\" or \"off\" on this platform");
  423.                 return NGX_CONF_ERROR;

  424. #endif
  425.             }

  426.             ls->bind = 1;

  427.             continue;

  428. #if (NGX_HAVE_KEEPALIVE_TUNABLE)
  429.         invalid_so_keepalive:

  430.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  431.                                "invalid so_keepalive value: \"%s\"",
  432.                                &value[i].data[13]);
  433.             return NGX_CONF_ERROR;
  434. #endif
  435.         }

  436.         if (ngx_strcmp(value[i].data, "proxy_protocol") == 0) {
  437.             ls->proxy_protocol = 1;
  438.             continue;
  439.         }

  440.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  441.                            "invalid parameter \"%V\"", &value[i]);
  442.         return NGX_CONF_ERROR;
  443.     }

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

  445.         for (i = 0; i < n; i++) {
  446.             if (ngx_cmp_sockaddr(u.addrs[n].sockaddr, u.addrs[n].socklen,
  447.                                  u.addrs[i].sockaddr, u.addrs[i].socklen, 1)
  448.                 == NGX_OK)
  449.             {
  450.                 goto next;
  451.             }
  452.         }

  453.         if (n != 0) {
  454.             nls = ngx_array_push(&cmcf->listen);
  455.             if (nls == NULL) {
  456.                 return NGX_CONF_ERROR;
  457.             }

  458.             *nls = *ls;

  459.         } else {
  460.             nls = ls;
  461.         }

  462.         nls->sockaddr = u.addrs[n].sockaddr;
  463.         nls->socklen = u.addrs[n].socklen;
  464.         nls->addr_text = u.addrs[n].name;
  465.         nls->wildcard = ngx_inet_wildcard(nls->sockaddr);

  466.         als = cmcf->listen.elts;

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

  468.             if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen,
  469.                                  nls->sockaddr, nls->socklen, 1)
  470.                 != NGX_OK)
  471.             {
  472.                 continue;
  473.             }

  474.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  475.                                "duplicate \"%V\" address and port pair",
  476.                                &nls->addr_text);
  477.             return NGX_CONF_ERROR;
  478.         }

  479.     next:
  480.         continue;
  481.     }

  482.     return NGX_CONF_OK;
  483. }


  484. static char *
  485. ngx_mail_core_protocol(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  486. {
  487.     ngx_mail_core_srv_conf_t  *cscf = conf;

  488.     ngx_str_t          *value;
  489.     ngx_uint_t          m;
  490.     ngx_mail_module_t  *module;

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

  492.     for (m = 0; cf->cycle->modules[m]; m++) {
  493.         if (cf->cycle->modules[m]->type != NGX_MAIL_MODULE) {
  494.             continue;
  495.         }

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

  497.         if (module->protocol
  498.             && ngx_strcmp(module->protocol->name.data, value[1].data) == 0)
  499.         {
  500.             cscf->protocol = module->protocol;

  501.             return NGX_CONF_OK;
  502.         }
  503.     }

  504.     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  505.                        "unknown protocol \"%V\"", &value[1]);
  506.     return NGX_CONF_ERROR;
  507. }


  508. static char *
  509. ngx_mail_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  510. {
  511.     ngx_mail_core_srv_conf_t  *cscf = conf;

  512.     return ngx_log_set_log(cf, &cscf->error_log);
  513. }


  514. static char *
  515. ngx_mail_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  516. {
  517.     ngx_mail_core_srv_conf_t  *cscf = conf;

  518.     ngx_str_t  *value;

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

  520.     if (cscf->resolver != NGX_CONF_UNSET_PTR) {
  521.         return "is duplicate";
  522.     }

  523.     if (ngx_strcmp(value[1].data, "off") == 0) {
  524.         cscf->resolver = NULL;
  525.         return NGX_CONF_OK;
  526.     }

  527.     cscf->resolver = ngx_resolver_create(cf, &value[1], cf->args->nelts - 1);
  528.     if (cscf->resolver == NULL) {
  529.         return NGX_CONF_ERROR;
  530.     }

  531.     return NGX_CONF_OK;
  532. }


  533. char *
  534. ngx_mail_capabilities(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
  535. {
  536.     char  *p = conf;

  537.     ngx_str_t    *c, *value;
  538.     ngx_uint_t    i;
  539.     ngx_array_t  *a;

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

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

  542.     for (i = 1; i < cf->args->nelts; i++) {
  543.         c = ngx_array_push(a);
  544.         if (c == NULL) {
  545.             return NGX_CONF_ERROR;
  546.         }

  547.         *c = value[i];
  548.     }

  549.     return NGX_CONF_OK;
  550. }