config_options.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2012, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  * \brief Configuration Option-handling
00021  * \author Terry Wilson <twilson@digium.com>
00022  */
00023 
00024 /*** MODULEINFO
00025    <support_level>core</support_level>
00026  ***/
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 433498 $")
00031 
00032 #include <regex.h>
00033 
00034 #include "asterisk/_private.h"
00035 #include "asterisk/config.h"
00036 #include "asterisk/config_options.h"
00037 #include "asterisk/stringfields.h"
00038 #include "asterisk/acl.h"
00039 #include "asterisk/frame.h"
00040 #include "asterisk/xmldoc.h"
00041 #include "asterisk/cli.h"
00042 #include "asterisk/term.h"
00043 #include "asterisk/format_cap.h"
00044 
00045 #ifdef LOW_MEMORY
00046 #define CONFIG_OPT_BUCKETS 5
00047 #else
00048 #define CONFIG_OPT_BUCKETS 53
00049 #endif /* LOW_MEMORY */
00050 
00051 /*! \brief Bits of aco_info that shouldn't be assigned outside this file
00052  * \internal
00053  */
00054 struct aco_info_internal {
00055    void *pending;              /*!< The user-defined config object awaiting application */
00056 };
00057 
00058 struct aco_type_internal {
00059    regex_t *regex;
00060    struct ao2_container *opts; /*!< The container of options registered to the aco_info */
00061 };
00062 
00063 struct aco_option {
00064    const char *name;
00065    const char *aliased_to;
00066    const char *default_val;
00067    enum aco_matchtype match_type;
00068    regex_t *name_regex;
00069    struct aco_type **obj;
00070    enum aco_option_type type;
00071    aco_option_handler handler;
00072    unsigned int flags;
00073    unsigned int no_doc:1;
00074    unsigned char deprecated:1;
00075    size_t argc;
00076    intptr_t args[0];
00077 };
00078 
00079 #ifdef AST_XML_DOCS
00080 static struct ao2_container *xmldocs;
00081 #endif /* AST_XML_DOCS */
00082 
00083 /*! \brief Value of the aco_option_type enum as strings */
00084 static char *aco_option_type_string[] = {
00085    "ACL",            /* OPT_ACL_T, */
00086    "Boolean",        /* OPT_BOOL_T, */
00087    "Boolean",        /* OPT_BOOLFLAG_T, */
00088    "String",         /* OPT_CHAR_ARRAY_T, */
00089    "Codec",       /* OPT_CODEC_T, */
00090    "Custom",         /* OPT_CUSTOM_T, */
00091    "Double",         /* OPT_DOUBLE_T, */
00092    "Integer",        /* OPT_INT_T, */
00093    "None",           /* OPT_NOOP_T, */
00094    "IP Address",     /* OPT_SOCKADDR_T, */
00095    "String",         /* OPT_STRINGFIELD_T, */
00096    "Unsigned Integer",  /* OPT_UINT_T, */
00097 };
00098 
00099 void *aco_pending_config(struct aco_info *info)
00100 {
00101    if (!(info && info->internal)) {
00102       ast_log(LOG_ERROR, "This may not be called without an initialized aco_info!\n");
00103       return NULL;
00104    }
00105    return info->internal->pending;
00106 }
00107 
00108 static void config_option_destroy(void *obj)
00109 {
00110    struct aco_option *opt = obj;
00111    if (opt->match_type == ACO_REGEX && opt->name_regex) {
00112       regfree(opt->name_regex);
00113       ast_free(opt->name_regex);
00114    }
00115 }
00116 
00117 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00118 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00119 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00120 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00121 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00122 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00123 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00124 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00125 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00126 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00127 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00128 
00129 #ifdef AST_XML_DOCS
00130 static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches);
00131 static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type);
00132 #endif
00133 
00134 static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
00135 {
00136    switch(type) {
00137    case OPT_ACL_T: return acl_handler_fn;
00138    case OPT_BOOL_T: return bool_handler_fn;
00139    case OPT_BOOLFLAG_T: return boolflag_handler_fn;
00140    case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
00141    case OPT_CODEC_T: return codec_handler_fn;
00142    case OPT_DOUBLE_T: return double_handler_fn;
00143    case OPT_INT_T: return int_handler_fn;
00144    case OPT_NOOP_T: return noop_handler_fn;
00145    case OPT_SOCKADDR_T: return sockaddr_handler_fn;
00146    case OPT_STRINGFIELD_T: return stringfield_handler_fn;
00147    case OPT_UINT_T: return uint_handler_fn;
00148 
00149    case OPT_CUSTOM_T: return NULL;
00150    }
00151 
00152    return NULL;
00153 }
00154 
00155 static regex_t *build_regex(const char *text)
00156 {
00157    int res;
00158    regex_t *regex;
00159 
00160    if (!(regex = ast_malloc(sizeof(*regex)))) {
00161       return NULL;
00162    }
00163 
00164    if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
00165       size_t len = regerror(res, regex, NULL, 0);
00166       char buf[len];
00167       regerror(res, regex, buf, len);
00168       ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
00169       ast_free(regex);
00170       return NULL;
00171    }
00172 
00173    return regex;
00174 }
00175 
00176 static int link_option_to_types(struct aco_info *info, struct aco_type **types, struct aco_option *opt)
00177 {
00178    size_t idx = 0;
00179    struct aco_type *type;
00180 
00181    while ((type = types[idx++])) {
00182       if (!type->internal) {
00183          ast_log(LOG_ERROR, "Attempting to register option using uninitialized type\n");
00184          return -1;
00185       }
00186       if (!ao2_link(type->internal->opts, opt)
00187 #ifdef AST_XML_DOCS
00188             || (!info->hidden &&
00189                !opt->no_doc &&
00190                xmldoc_update_config_option(types, info->module, opt->name, type->name, opt->default_val, opt->match_type == ACO_REGEX, opt->type))
00191 #endif /* AST_XML_DOCS */
00192       ) {
00193          do {
00194             ao2_unlink(types[idx - 1]->internal->opts, opt);
00195          } while (--idx);
00196          return -1;
00197       }
00198    }
00199    /* The container(s) should hold the only ref to opt */
00200    ao2_ref(opt, -1);
00201 
00202    return 0;
00203 }
00204 
00205 int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
00206 {
00207    struct aco_option *opt;
00208 
00209    if (!info || ast_strlen_zero(name) || ast_strlen_zero(aliased_to)) {
00210       return -1;
00211    }
00212 
00213    if (!(opt = ao2_alloc(sizeof(*opt), config_option_destroy))) {
00214       return -1;
00215    }
00216 
00217    opt->name = name;
00218    opt->aliased_to = aliased_to;
00219    opt->deprecated = 1;
00220    opt->match_type = ACO_EXACT;
00221 
00222    if (link_option_to_types(info, types, opt)) {
00223       ao2_ref(opt, -1);
00224       return -1;
00225    }
00226 
00227    return 0;
00228 }
00229 
00230 unsigned int aco_option_get_flags(const struct aco_option *option)
00231 {
00232    return option->flags;
00233 }
00234 
00235 intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
00236 {
00237    return option->args[position];
00238 }
00239 
00240 #ifdef AST_XML_DOCS
00241 /*! \internal
00242  * \brief Find a particular ast_xml_doc_item from it's parent config_info, types, and name
00243  */
00244 static struct ast_xml_doc_item *find_xmldoc_option(struct ast_xml_doc_item *config_info, struct aco_type **types, const char *name)
00245 {
00246    struct ast_xml_doc_item *iter = config_info;
00247 
00248    if (!iter) {
00249       return NULL;
00250    }
00251    /* First is just the configInfo, we can skip it */
00252    while ((iter = AST_LIST_NEXT(iter, next))) {
00253       size_t x;
00254       if (strcasecmp(iter->name, name)) {
00255          continue;
00256       }
00257       for (x = 0; types[x]; x++) {
00258          /* All we care about is that at least one type has the option */
00259          if (!strcasecmp(types[x]->name, iter->ref)) {
00260             return iter;
00261          }
00262       }
00263    }
00264    return NULL;
00265 }
00266 
00267 /*! \internal
00268  * \brief Find a particular ast_xml_doc_item from it's parent config_info and name
00269  */
00270 static struct ast_xml_doc_item *find_xmldoc_type(struct ast_xml_doc_item *config_info, const char *name)
00271 {
00272    struct ast_xml_doc_item *iter = config_info;
00273    if (!iter) {
00274       return NULL;
00275    }
00276    /* First is just the config Info, skip it */
00277    while ((iter = AST_LIST_NEXT(iter, next))) {
00278       if (!strcasecmp(iter->type, "configObject") && !strcasecmp(iter->name, name)) {
00279          break;
00280       }
00281    }
00282    return iter;
00283 }
00284 
00285 #endif /* AST_XML_DOCS */
00286 
00287 int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types,
00288    const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags,
00289    unsigned int no_doc, size_t argc, ...)
00290 {
00291    struct aco_option *opt;
00292    va_list ap;
00293    int tmp;
00294 
00295    /* Custom option types require a handler */
00296    if (!handler && kind == OPT_CUSTOM_T) {
00297       return -1;
00298    }
00299 
00300    if (!(types && types[0])) {
00301       return -1;
00302    }
00303 
00304    if (!(opt = ao2_alloc(sizeof(*opt) + argc * sizeof(opt->args[0]), config_option_destroy))) {
00305       return -1;
00306    }
00307 
00308    if (matchtype == ACO_REGEX && !(opt->name_regex = build_regex(name))) {
00309       ao2_ref(opt, -1);
00310       return -1;
00311    }
00312 
00313    va_start(ap, argc);
00314    for (tmp = 0; tmp < argc; tmp++) {
00315       opt->args[tmp] = va_arg(ap, size_t);
00316    }
00317    va_end(ap);
00318 
00319    opt->name = name;
00320    opt->match_type = matchtype;
00321    opt->default_val = default_val;
00322    opt->type = kind;
00323    opt->handler = handler;
00324    opt->flags = flags;
00325    opt->argc = argc;
00326    opt->no_doc = no_doc;
00327 
00328    if (!opt->handler && !(opt->handler = ast_config_option_default_handler(opt->type))) {
00329       /* This should never happen */
00330       ast_log(LOG_ERROR, "No handler provided, and no default handler exists for type %u\n", opt->type);
00331       ao2_ref(opt, -1);
00332       return -1;
00333    };
00334 
00335    if (link_option_to_types(info, types, opt)) {
00336       ao2_ref(opt, -1);
00337       return -1;
00338    }
00339 
00340    return 0;
00341 }
00342 
00343 static int config_opt_hash(const void *obj, const int flags)
00344 {
00345    const struct aco_option *opt = obj;
00346    const char *name = (flags & OBJ_KEY) ? obj : opt->name;
00347    return ast_str_case_hash(name);
00348 }
00349 
00350 static int config_opt_cmp(void *obj, void *arg, int flags)
00351 {
00352    struct aco_option *opt1 = obj, *opt2 = arg;
00353    const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
00354    return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
00355 }
00356 
00357 static int find_option_cb(void *obj, void *arg, int flags)
00358 {
00359    struct aco_option *match = obj;
00360    const char *name = arg;
00361 
00362    switch (match->match_type) {
00363    case ACO_EXACT:
00364       return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
00365    case ACO_REGEX:
00366       return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
00367    }
00368    ast_log(LOG_ERROR, "Unknown match type. This should not be possible.\n");
00369    return CMP_STOP;
00370 }
00371 
00372 static struct aco_option *aco_option_find(struct aco_type *type, const char *name)
00373 {
00374    struct aco_option *opt;
00375 
00376    if (!type || !type->internal || !type->internal->opts) {
00377       ast_log(LOG_NOTICE, "Attempting to use NULL or unitialized config type\n");
00378       return NULL;
00379    }
00380 
00381    /* Try an exact match with OBJ_KEY for the common/fast case, then iterate through
00382     * all options for the regex cases */
00383    if (!(opt = ao2_callback(type->internal->opts, OBJ_KEY, find_option_cb, (void *) name))) {
00384       opt = ao2_callback(type->internal->opts, 0, find_option_cb, (void *) name);
00385    }
00386    return opt;
00387 }
00388 
00389 struct ao2_container *aco_option_container_alloc(void)
00390 {
00391    return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
00392 }
00393 
00394 static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
00395 {
00396    size_t x;
00397    struct aco_type *match;
00398    const char *val;
00399 
00400    for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
00401       /* First make sure we are an object that can service this category */
00402       if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) {
00403          continue;
00404       }
00405 
00406       /* Then, see if we need to match a particular field */
00407       if (!ast_strlen_zero(match->matchfield) && (!ast_strlen_zero(match->matchvalue) || match->matchfunc)) {
00408          if (!(val = ast_variable_retrieve(cfg, category, match->matchfield))) {
00409             ast_log(LOG_ERROR, "Required match field '%s' not found\n", match->matchfield);
00410             return NULL;
00411          }
00412          if (match->matchfunc) {
00413             if (!match->matchfunc(val)) {
00414                continue;
00415             }
00416          } else if (strcasecmp(val, match->matchvalue)) {
00417             continue;
00418          }
00419       }
00420       /* If we get this far, we're a match */
00421       break;
00422    }
00423 
00424    return match;
00425 }
00426 
00427 static int is_preload(struct aco_file *file, const char *cat)
00428 {
00429    int i;
00430 
00431    if (!file->preload) {
00432       return 0;
00433    }
00434 
00435    for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
00436       if (!strcasecmp(cat, file->preload[i])) {
00437          return 1;
00438       }
00439    }
00440    return 0;
00441 }
00442 
00443 static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload) {
00444    RAII_VAR(void *, new_item, NULL, ao2_cleanup);
00445    struct aco_type *type;
00446    /* For global types, field is the global option struct. For non-global, it is the container for items.
00447     * We do not grab a reference to these objects, as the info already holds references to them. This
00448     * pointer is just a convenience. Do not actually store it somewhere. */
00449    void **field;
00450    regex_t *regex_skip;
00451 
00452    /* Skip preloaded categories if we aren't preloading */
00453    if (!preload && is_preload(file, cat)) {
00454       return 0;
00455    }
00456 
00457    /* Skip the category if we've been told to ignore it */
00458    if (!ast_strlen_zero(file->skip_category)) {
00459       regex_skip = build_regex(file->skip_category);
00460       if (!regexec(regex_skip, cat, 0, NULL, 0)) {
00461          regfree(regex_skip);
00462          ast_free(regex_skip);
00463          return 0;
00464       }
00465       regfree(regex_skip);
00466       ast_free(regex_skip);
00467    }
00468 
00469    /* Find aco_type by category, if not found it is an error */
00470    if (!(type = internal_aco_type_find(file, cfg, cat))) {
00471       ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
00472       return -1;
00473    }
00474 
00475    field = info->internal->pending + type->item_offset;
00476    if (!*field) {
00477       ast_log(LOG_ERROR, "In %s: %s - No object to update!\n", file->filename, cat);
00478       return -1;
00479    }
00480 
00481    if (type->type == ACO_GLOBAL && *field) {
00482       if (aco_process_category_options(type, cfg, cat, *field)) {
00483          ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
00484          return -1;
00485       }
00486    } else if (type->type == ACO_ITEM) {
00487       int new = 0;
00488       /* If we have multiple definitions of a category in a file, or can set the values from multiple
00489        * files, look up the entry if we've already added it so we can merge the values together.
00490        * Otherwise, alloc a new item. */
00491       if (*field) {
00492          if (!(new_item = type->item_find(*field, cat))) {
00493             if (!(new_item = type->item_alloc(cat))) {
00494                ast_log(LOG_ERROR, "In %s: Could not create item for %s\n", file->filename, cat);
00495                return -1;
00496             }
00497             if (aco_set_defaults(type, cat, new_item)) {
00498                ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
00499                return -1;
00500             }
00501             new = 1;
00502          }
00503       }
00504 
00505       if (type->item_pre_process && type->item_pre_process(new_item)) {
00506          ast_log(LOG_ERROR, "In %s: Preprocess callback for %s failed\n", file->filename, cat);
00507          return -1;
00508       }
00509 
00510       if (aco_process_category_options(type, cfg, cat, new_item)) {
00511          ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
00512          return -1;
00513       }
00514 
00515       if (type->item_prelink && type->item_prelink(new_item)) {
00516          ast_log(LOG_ERROR, "In %s: Pre-link callback for %s failed\n", file->filename, cat);
00517          return -1;
00518       }
00519 
00520       if (new && !ao2_link(*field, new_item)) {
00521          ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", file->filename, cat);
00522          return -1;
00523       }
00524    }
00525    return 0;
00526 }
00527 
00528 static int apply_config(struct aco_info *info)
00529 {
00530    ao2_global_obj_replace_unref(*info->global_obj, info->internal->pending);
00531 
00532    return 0;
00533 }
00534 
00535 static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
00536 {
00537    const char *cat = NULL;
00538 
00539    if (file->preload) {
00540       int i;
00541       for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
00542          if (process_category(cfg, info, file, file->preload[i], 1)) {
00543             return ACO_PROCESS_ERROR;
00544          }
00545       }
00546    }
00547 
00548    while ((cat = ast_category_browse(cfg, cat))) {
00549       if (process_category(cfg, info, file, cat, 0)) {
00550          return ACO_PROCESS_ERROR;
00551       }
00552    }
00553    return ACO_PROCESS_OK;
00554 }
00555 
00556 enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
00557 {
00558    if (!info->internal) {
00559       ast_log(LOG_ERROR, "Attempt to process %s with uninitialized aco_info\n", file->filename);
00560       goto error;
00561    }
00562 
00563    if (!(info->internal->pending = info->snapshot_alloc())) {
00564       ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", file->filename);
00565       goto error;
00566    }
00567 
00568    if (internal_process_ast_config(info, file, cfg)) {
00569       goto error;
00570    }
00571 
00572    if (info->pre_apply_config && info->pre_apply_config()) {
00573       goto error;
00574    }
00575 
00576    if (apply_config(info)) {
00577       goto error;
00578    };
00579 
00580    ao2_cleanup(info->internal->pending);
00581    return ACO_PROCESS_OK;
00582 
00583 error:
00584    ao2_cleanup(info->internal->pending);
00585    return ACO_PROCESS_ERROR;
00586 }
00587 
00588 enum aco_process_status aco_process_config(struct aco_info *info, int reload)
00589 {
00590    struct ast_config *cfg;
00591    struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
00592    int res = ACO_PROCESS_OK;
00593    int file_count = 0;
00594    struct aco_file *file;
00595 
00596    if (!info->internal) {
00597       ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
00598       return ACO_PROCESS_ERROR;
00599    }
00600 
00601    if (!(info->files[0])) {
00602       ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
00603       return ACO_PROCESS_ERROR;
00604    }
00605 
00606    if (!(info->internal->pending = info->snapshot_alloc())) {
00607       ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->module);
00608       return ACO_PROCESS_ERROR;
00609    }
00610 
00611    while (res != ACO_PROCESS_ERROR && (file = info->files[file_count++])) {
00612       const char *filename = file->filename;
00613       struct aco_type *match;
00614       int i;
00615 
00616       /* set defaults for global objects */
00617       for (i = 0, match = file->types[i]; match; match = file->types[++i]) {
00618          void **field = info->internal->pending + match->item_offset;
00619 
00620          if (match->type != ACO_GLOBAL || !*field) {
00621             continue;
00622          }
00623 
00624          if (aco_set_defaults(match, match->category, *field)) {
00625             ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, match->category);
00626             res = ACO_PROCESS_ERROR;
00627             break;
00628          }
00629       }
00630 
00631       if (res == ACO_PROCESS_ERROR) {
00632          break;
00633       }
00634 
00635 try_alias:
00636       cfg = ast_config_load(filename, cfg_flags);
00637       if (!cfg || cfg == CONFIG_STATUS_FILEMISSING) {
00638          if (file->alias && strcmp(file->alias, filename)) {
00639             filename = file->alias;
00640             goto try_alias;
00641          }
00642          ast_log(LOG_ERROR, "Unable to load config file '%s'\n", file->filename);
00643          res = ACO_PROCESS_ERROR;
00644          break;
00645       } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00646          ast_debug(1, "%s was unchanged\n", file->filename);
00647          res = ACO_PROCESS_UNCHANGED;
00648          continue;
00649       } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00650          ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n",
00651             file->filename);
00652          res = ACO_PROCESS_ERROR;
00653          break;
00654       }
00655 
00656       /* A file got loaded. */
00657       if (reload) {
00658          /* Must do any subsequent file loads unconditionally. */
00659          reload = 0;
00660          ast_clear_flag(&cfg_flags, CONFIG_FLAG_FILEUNCHANGED);
00661 
00662          if (file_count != 1) {
00663             /*
00664              * Must restart loading to load all config files since a file
00665              * after the first one changed.
00666              */
00667             file_count = 0;
00668          } else {
00669             res = internal_process_ast_config(info, file, cfg);
00670          }
00671       } else {
00672          res = internal_process_ast_config(info, file, cfg);
00673       }
00674       ast_config_destroy(cfg);
00675    }
00676 
00677    if (res != ACO_PROCESS_OK) {
00678       goto end;
00679    }
00680 
00681    if (info->pre_apply_config && info->pre_apply_config()) {
00682       res = ACO_PROCESS_ERROR;
00683       goto end;
00684    }
00685 
00686    if (apply_config(info)) {
00687       res = ACO_PROCESS_ERROR;
00688       goto end;
00689    }
00690 
00691    if (info->post_apply_config) {
00692       info->post_apply_config();
00693    }
00694 
00695 end:
00696    ao2_cleanup(info->internal->pending);
00697    return res;
00698 }
00699 int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
00700 {
00701    RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup);
00702    if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) {
00703       const char *alias = ast_strdupa(opt->aliased_to);
00704       ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias);
00705       ao2_ref(opt, -1);
00706       opt = aco_option_find(type, alias);
00707    }
00708 
00709    if (!opt) {
00710       ast_log(LOG_ERROR, "Could not find option suitable for category '%s' named '%s' at line %d of %s\n", cat, var->name, var->lineno, var->file);
00711       return -1;
00712    }
00713 
00714    if (!opt->handler) {
00715       /* It should be impossible for an option to not have a handler */
00716       ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name);
00717       return -1;
00718    }
00719    if (opt->handler(opt, var, obj)) {
00720       ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file);
00721       return -1;
00722    }
00723 
00724    return 0;
00725 }
00726 
00727 int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
00728 {
00729    struct ast_variable *var;
00730 
00731    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
00732       if (aco_process_var(type, cat, var, obj)) {
00733          return -1;
00734       }
00735    }
00736 
00737    return 0;
00738 }
00739 
00740 static void internal_type_destroy(struct aco_type *type)
00741 {
00742    /* If we've already had all our internal data cleared out,
00743     * then there's no need to proceed further
00744     */
00745    if (!type->internal) {
00746       return;
00747    }
00748 
00749    if (type->internal->regex) {
00750       regfree(type->internal->regex);
00751       ast_free(type->internal->regex);
00752    }
00753    ao2_cleanup(type->internal->opts);
00754    type->internal->opts = NULL;
00755    ast_free(type->internal);
00756    type->internal = NULL;
00757 }
00758 
00759 static void internal_file_types_destroy(struct aco_file *file)
00760 {
00761    size_t x;
00762    struct aco_type *t;
00763 
00764    for (x = 0, t = file->types[x]; t; t = file->types[++x]) {
00765       internal_type_destroy(t);
00766       t = NULL;
00767    }
00768 }
00769 
00770 static int internal_type_init(struct aco_type *type)
00771 {
00772    if (!(type->internal = ast_calloc(1, sizeof(*type->internal)))) {
00773       return -1;
00774    }
00775 
00776    if (!(type->internal->regex = build_regex(type->category))) {
00777       internal_type_destroy(type);
00778       return -1;
00779    }
00780 
00781    if (!(type->internal->opts = aco_option_container_alloc())) {
00782       internal_type_destroy(type);
00783       return -1;
00784    }
00785 
00786    return 0;
00787 }
00788 
00789 int aco_info_init(struct aco_info *info)
00790 {
00791    size_t x = 0, y = 0;
00792    struct aco_file *file;
00793    struct aco_type *type;
00794 
00795    if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
00796       return -1;
00797    }
00798 
00799    while ((file = info->files[x++])) {
00800       while ((type = file->types[y++])) {
00801          if (internal_type_init(type)) {
00802             goto error;
00803          }
00804 #ifdef AST_XML_DOCS
00805          if (!info->hidden &&
00806             !type->hidden &&
00807             xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match == ACO_WHITELIST)) {
00808             goto error;
00809          }
00810 #endif /* AST_XML_DOCS */
00811       }
00812       y = 0;
00813    }
00814 
00815    return 0;
00816 error:
00817    aco_info_destroy(info);
00818    return -1;
00819 }
00820 
00821 void aco_info_destroy(struct aco_info *info)
00822 {
00823    int x;
00824    /* It shouldn't be possible for internal->pending to be in use when this is called because
00825     * of the locks in loader.c around reloads and unloads and the fact that internal->pending
00826     * only exists while those locks are held */
00827    ast_free(info->internal);
00828    info->internal = NULL;
00829 
00830    for (x = 0; info->files[x]; x++) {
00831       internal_file_types_destroy(info->files[x]);
00832    }
00833 }
00834 
00835 int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
00836 {
00837    struct aco_option *opt;
00838    struct ao2_iterator iter;
00839 
00840    iter = ao2_iterator_init(type->internal->opts, 0);
00841 
00842    while ((opt = ao2_iterator_next(&iter))) {
00843       RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy);
00844 
00845       if (ast_strlen_zero(opt->default_val)) {
00846          ao2_ref(opt, -1);
00847          continue;
00848       }
00849       if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
00850          ao2_ref(opt, -1);
00851          ao2_iterator_destroy(&iter);
00852          return -1;
00853       }
00854       if (opt->handler(opt, var, obj)) {
00855          ast_log(LOG_ERROR, "Unable to set default for %s, %s=%s\n", category, var->name, var->value);
00856          ao2_ref(opt, -1);
00857          ao2_iterator_destroy(&iter);
00858          return -1;
00859       }
00860       ao2_ref(opt, -1);
00861    }
00862    ao2_iterator_destroy(&iter);
00863 
00864    return 0;
00865 }
00866 
00867 #ifdef AST_XML_DOCS
00868 
00869 /*! \internal
00870  * \brief Complete the name of the module the user is looking for
00871  */
00872 static char *complete_config_module(const char *word, int pos, int state)
00873 {
00874    char *c = NULL;
00875    size_t wordlen = strlen(word);
00876    int which = 0;
00877    struct ao2_iterator i;
00878    struct ast_xml_doc_item *cur;
00879 
00880    if (pos != 3) {
00881       return NULL;
00882    }
00883 
00884    i = ao2_iterator_init(xmldocs, 0);
00885    while ((cur = ao2_iterator_next(&i))) {
00886       if (!strncasecmp(word, cur->name, wordlen) && ++which > state) {
00887          c = ast_strdup(cur->name);
00888          ao2_ref(cur, -1);
00889          break;
00890       }
00891       ao2_ref(cur, -1);
00892    }
00893    ao2_iterator_destroy(&i);
00894 
00895    return c;
00896 }
00897 
00898 /*! \internal
00899  * \brief Complete the name of the configuration type the user is looking for
00900  */
00901 static char *complete_config_type(const char *module, const char *word, int pos, int state)
00902 {
00903    char *c = NULL;
00904    size_t wordlen = strlen(word);
00905    int which = 0;
00906    RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
00907    struct ast_xml_doc_item *cur;
00908 
00909    if (pos != 4) {
00910       return NULL;
00911    }
00912 
00913    if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
00914       return NULL;
00915    }
00916 
00917    cur = info;
00918    while ((cur = AST_LIST_NEXT(cur, next))) {
00919       if (!strcasecmp(cur->type, "configObject") && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
00920          c = ast_strdup(cur->name);
00921          break;
00922       }
00923    }
00924    return c;
00925 }
00926 
00927 /*! \internal
00928  * \brief Complete the name of the configuration option the user is looking for
00929  */
00930 static char *complete_config_option(const char *module, const char *option, const char *word, int pos, int state)
00931 {
00932    char *c = NULL;
00933    size_t wordlen = strlen(word);
00934    int which = 0;
00935    RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
00936    struct ast_xml_doc_item *cur;
00937 
00938    if (pos != 5) {
00939       return NULL;
00940    }
00941 
00942    if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
00943       return NULL;
00944    }
00945 
00946    cur = info;
00947    while ((cur = AST_LIST_NEXT(cur, next))) {
00948       if (!strcasecmp(cur->type, "configOption") && !strcasecmp(cur->ref, option) && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
00949          c = ast_strdup(cur->name);
00950          break;
00951       }
00952    }
00953    return c;
00954 }
00955 
00956 /* Define as 0 if we want to allow configurations to be registered without
00957  * documentation
00958  */
00959 #define XMLDOC_STRICT 1
00960 
00961 /*! \internal
00962  * \brief Update the XML documentation for a config type based on its registration
00963  */
00964 static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches)
00965 {
00966    RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
00967    RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
00968    struct ast_xml_doc_item *config_type;
00969    struct ast_xml_node *type, *syntax, *matchinfo, *tmp;
00970 
00971    /* If we already have a syntax element, bail. This isn't an error, since we may unload a module which
00972     * has updated the docs and then load it again. */
00973    if ((results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/syntax", module, name))) {
00974       return 0;
00975    }
00976 
00977    if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']", module, name))) {
00978       ast_log(LOG_WARNING, "Cannot update type '%s' in module '%s' because it has no existing documentation!\n", name, module);
00979       return XMLDOC_STRICT ? -1 : 0;
00980    }
00981 
00982    if (!(type = ast_xml_xpath_get_first_result(results))) {
00983       ast_log(LOG_WARNING, "Could not retrieve documentation for type '%s' in module '%s'\n", name, module);
00984       return XMLDOC_STRICT ? -1 : 0;
00985    }
00986 
00987    if (!(syntax = ast_xml_new_child(type, "syntax"))) {
00988       ast_log(LOG_WARNING, "Could not create syntax node for type '%s' in module '%s'\n", name, module);
00989       return XMLDOC_STRICT ? -1 : 0;
00990    }
00991 
00992    if (!(matchinfo = ast_xml_new_child(syntax, "matchInfo"))) {
00993       ast_log(LOG_WARNING, "Could not create matchInfo node for type '%s' in module '%s'\n", name, module);
00994       return XMLDOC_STRICT ? -1 : 0;
00995    }
00996 
00997    if (!(tmp = ast_xml_new_child(matchinfo, "category"))) {
00998       ast_log(LOG_WARNING, "Could not create category node for type '%s' in module '%s'\n", name, module);
00999       return XMLDOC_STRICT ? -1 : 0;
01000    }
01001 
01002    ast_xml_set_text(tmp, category);
01003    ast_xml_set_attribute(tmp, "match", matches ? "true" : "false");
01004 
01005    if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) {
01006       ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
01007       return XMLDOC_STRICT ? -1 : 0;
01008    }
01009 
01010    ast_xml_set_attribute(tmp, "name", matchfield);
01011    ast_xml_set_text(tmp, matchvalue);
01012 
01013    if (!config_info || !(config_type = find_xmldoc_type(config_info, name))) {
01014       ast_log(LOG_WARNING, "Could not obtain XML documentation item for config type %s\n", name);
01015       return XMLDOC_STRICT ? -1 : 0;
01016    }
01017 
01018    if (ast_xmldoc_regenerate_doc_item(config_type)) {
01019       ast_log(LOG_WARNING, "Could not update type '%s' with values from config type registration\n", name);
01020       return XMLDOC_STRICT ? -1 : 0;
01021    }
01022 
01023    return 0;
01024 }
01025 
01026 /*! \internal
01027  * \brief Update the XML documentation for a config option based on its registration
01028  */
01029 static int xmldoc_update_config_option(struct aco_type **types, const char *module, const char *name, const char *object_name, const char *default_value, unsigned int regex, enum aco_option_type type)
01030 {
01031    RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
01032    RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
01033    struct ast_xml_doc_item * config_option;
01034    struct ast_xml_node *option;
01035 
01036    ast_assert(ARRAY_LEN(aco_option_type_string) > type);
01037 
01038    if (!config_info || !(config_option = find_xmldoc_option(config_info, types, name))) {
01039       ast_log(LOG_ERROR, "XML Documentation for option '%s' in modules '%s' not found!\n", name, module);
01040       return XMLDOC_STRICT ? -1 : 0;
01041    }
01042 
01043    if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/configOption[@name='%s']", module, object_name, name))) {
01044       ast_log(LOG_WARNING, "Could not find option '%s' with type '%s' in module '%s'\n", name, object_name, module);
01045       return XMLDOC_STRICT ? -1 : 0;
01046    }
01047 
01048    if (!(option = ast_xml_xpath_get_first_result(results))) {
01049       ast_log(LOG_WARNING, "Could obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module);
01050       return XMLDOC_STRICT ? -1 : 0;
01051    }
01052    ast_xml_set_attribute(option, "regex", regex ? "true" : "false");
01053    ast_xml_set_attribute(option, "default", default_value);
01054    ast_xml_set_attribute(option, "type", aco_option_type_string[type]);
01055 
01056    if (ast_xmldoc_regenerate_doc_item(config_option)) {
01057       ast_log(LOG_WARNING, "Could not update option '%s' with values from config option registration\n", name);
01058       return XMLDOC_STRICT ? -1 : 0;
01059    }
01060 
01061    return 0;
01062 }
01063 
01064 /*! \internal
01065  * \brief Show the modules with configuration information
01066  */
01067 static void cli_show_modules(struct ast_cli_args *a)
01068 {
01069    struct ast_xml_doc_item *item;
01070    struct ao2_iterator it_items;
01071 
01072    ast_assert(a->argc == 3);
01073 
01074    if (ao2_container_count(xmldocs) == 0) {
01075       ast_cli(a->fd, "No modules found.\n");
01076       return;
01077    }
01078 
01079    it_items = ao2_iterator_init(xmldocs, 0);
01080    ast_cli(a->fd, "The following modules have configuration information:\n");
01081    while ((item = ao2_iterator_next(&it_items))) {
01082       ast_cli(a->fd, "\t%s\n", item->name);
01083       ao2_ref(item, -1);
01084    }
01085    ao2_iterator_destroy(&it_items);
01086 }
01087 
01088 /*! \internal
01089  * \brief Show the configuration types for a module
01090  */
01091 static void cli_show_module_types(struct ast_cli_args *a)
01092 {
01093    RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
01094    struct ast_xml_doc_item *tmp;
01095 
01096    ast_assert(a->argc == 4);
01097 
01098    if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
01099       ast_cli(a->fd, "Module %s not found.\n", a->argv[3]);
01100       return;
01101    }
01102 
01103    if (ast_str_strlen(item->synopsis)) {
01104       ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->synopsis), 1));
01105    }
01106    if (ast_str_strlen(item->description)) {
01107       ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->description), 1));
01108    }
01109 
01110    tmp = item;
01111    ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
01112    while ((tmp = AST_LIST_NEXT(tmp, next))) {
01113       if (!strcasecmp(tmp->type, "configObject")) {
01114          ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
01115             ast_str_buffer(tmp->synopsis));
01116       }
01117    }
01118 }
01119 
01120 /*! \internal
01121  * \brief Show the information for a configuration type
01122  */
01123 static void cli_show_module_type(struct ast_cli_args *a)
01124 {
01125    RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
01126    struct ast_xml_doc_item *tmp;
01127    char option_type[64];
01128    int match = 0;
01129 
01130    ast_assert(a->argc == 5);
01131 
01132    if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
01133       ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
01134       return;
01135    }
01136 
01137    tmp = item;
01138    while ((tmp = AST_LIST_NEXT(tmp, next))) {
01139       if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
01140          match = 1;
01141          term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
01142          ast_cli(a->fd, "%s", option_type);
01143          if (ast_str_strlen(tmp->syntax)) {
01144             ast_cli(a->fd, ": [%s]\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
01145          } else {
01146             ast_cli(a->fd, "\n\n");
01147          }
01148          if (ast_str_strlen(tmp->synopsis)) {
01149             ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->synopsis), 1));
01150          }
01151          if (ast_str_strlen(tmp->description)) {
01152             ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
01153          }
01154       }
01155    }
01156 
01157    if (!match) {
01158       ast_cli(a->fd, "Unknown configuration type %s\n", a->argv[4]);
01159       return;
01160    }
01161 
01162    /* Now iterate over the options for the type */
01163    tmp = item;
01164    while ((tmp = AST_LIST_NEXT(tmp, next))) {
01165       if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
01166          ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
01167                ast_str_buffer(tmp->synopsis));
01168       }
01169    }
01170 }
01171 
01172 /*! \internal
01173  * \brief Show detailed information for an option
01174  */
01175 static void cli_show_module_options(struct ast_cli_args *a)
01176 {
01177    RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
01178    struct ast_xml_doc_item *tmp;
01179    char option_name[64];
01180    int match = 0;
01181 
01182    ast_assert(a->argc == 6);
01183 
01184    if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
01185       ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
01186       return;
01187    }
01188    tmp = item;
01189    while ((tmp = AST_LIST_NEXT(tmp, next))) {
01190       if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
01191          if (match) {
01192             ast_cli(a->fd, "\n");
01193          }
01194          term_color(option_name, tmp->ref, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_name));
01195          ast_cli(a->fd, "[%s%s]\n", option_name, ast_term_reset());
01196          if (ast_str_strlen(tmp->syntax)) {
01197             ast_cli(a->fd, "%s\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
01198          }
01199          ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(AS_OR(tmp->synopsis, "No information available"), 1));
01200          if (ast_str_strlen(tmp->description)) {
01201             ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
01202          }
01203 
01204          if (ast_str_strlen(tmp->seealso)) {
01205             ast_cli(a->fd, "See Also:\n");
01206             ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->seealso), 1));
01207          }
01208 
01209          match = 1;
01210       }
01211    }
01212 
01213    if (!match) {
01214       ast_cli(a->fd, "No option %s found for %s:%s\n", a->argv[5], a->argv[3], a->argv[4]);
01215    }
01216 }
01217 
01218 static char *cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01219 {
01220    switch (cmd) {
01221    case CLI_INIT:
01222       e->command = "config show help";
01223       e->usage =
01224          "Usage: config show help [<module> [<type> [<option>]]]\n"
01225          "   Display detailed information about module configuration.\n"
01226          "     * If nothing is specified, the modules that have\n"
01227          "       configuration information are listed.\n"
01228          "     * If <module> is specified, the configuration types\n"
01229          "       for that module will be listed, along with brief\n"
01230          "       information about that type.\n"
01231          "     * If <module> and <type> are specified, detailed\n"
01232          "       information about the type is displayed, as well\n"
01233          "       as the available options.\n"
01234          "     * If <module>, <type>, and <option> are specified,\n"
01235          "       detailed information will be displayed about that\n"
01236          "       option.\n"
01237          "   NOTE: the help documentation is partially generated at run\n"
01238          "     time when a module is loaded. If a module is not loaded,\n"
01239          "     configuration help for that module may be incomplete.\n";
01240       return NULL;
01241    case CLI_GENERATE:
01242       switch(a->pos) {
01243       case 3: return complete_config_module(a->word, a->pos, a->n);
01244       case 4: return complete_config_type(a->argv[3], a->word, a->pos, a->n);
01245       case 5: return complete_config_option(a->argv[3], a->argv[4], a->word, a->pos, a->n);
01246       default: return NULL;
01247       }
01248    }
01249 
01250    switch (a->argc) {
01251    case 3:
01252       cli_show_modules(a);
01253       break;
01254    case 4:
01255       cli_show_module_types(a);
01256       break;
01257    case 5:
01258       cli_show_module_type(a);
01259       break;
01260    case 6:
01261       cli_show_module_options(a);
01262       break;
01263    default:
01264       return CLI_SHOWUSAGE;
01265    }
01266 
01267    return CLI_SUCCESS;
01268 }
01269 
01270 static struct ast_cli_entry cli_aco[] = {
01271    AST_CLI_DEFINE(cli_show_help, "Show configuration help for a module"),
01272 };
01273 
01274 static void aco_deinit(void)
01275 {
01276    ast_cli_unregister(cli_aco);
01277    ao2_cleanup(xmldocs);
01278 }
01279 #endif /* AST_XML_DOCS */
01280 
01281 int aco_init(void)
01282 {
01283 #ifdef AST_XML_DOCS
01284    ast_register_cleanup(aco_deinit);
01285    if (!(xmldocs = ast_xmldoc_build_documentation("configInfo"))) {
01286       ast_log(LOG_ERROR, "Couldn't build config documentation\n");
01287       return -1;
01288    }
01289    ast_cli_register_multiple(cli_aco, ARRAY_LEN(cli_aco));
01290 #endif /* AST_XML_DOCS */
01291    return 0;
01292 }
01293 
01294 /* Default config option handlers */
01295 
01296 /*! \brief Default option handler for signed integers
01297  * \note For a description of the opt->flags and opt->args values, see the documentation for
01298  * enum aco_option_type in config_options.h
01299  */
01300 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
01301    int *field = (int *)(obj + opt->args[0]);
01302    unsigned int flags = PARSE_INT32 | opt->flags;
01303    int res = 0;
01304    if (opt->flags & PARSE_IN_RANGE) {
01305       res = opt->flags & PARSE_DEFAULT ?
01306          ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
01307          ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
01308       if (res) {
01309          if (opt->flags & PARSE_RANGE_DEFAULTS) {
01310             ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
01311             res = 0;
01312          } else if (opt->flags & PARSE_DEFAULT) {
01313             ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
01314             res = 0;
01315          }
01316       }
01317    } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
01318       ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
01319    } else {
01320       res = ast_parse_arg(var->value, flags, field);
01321    }
01322 
01323    return res;
01324 }
01325 
01326 /*! \brief Default option handler for unsigned integers
01327  * \note For a description of the opt->flags and opt->args values, see the documentation for
01328  * enum aco_option_type in config_options.h
01329  */
01330 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
01331    unsigned int *field = (unsigned int *)(obj + opt->args[0]);
01332    unsigned int flags = PARSE_INT32 | opt->flags;
01333    int res = 0;
01334    if (opt->flags & PARSE_IN_RANGE) {
01335       res = opt->flags & PARSE_DEFAULT ?
01336          ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
01337          ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
01338       if (res) {
01339          if (opt->flags & PARSE_RANGE_DEFAULTS) {
01340             ast_log(LOG_WARNING, "Failed to set %s=%s. Set to %u instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
01341             res = 0;
01342          } else if (opt->flags & PARSE_DEFAULT) {
01343             ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %u instead.\n", var->name, var->value, *field);
01344             res = 0;
01345          }
01346       }
01347    } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
01348       ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
01349    } else {
01350       res = ast_parse_arg(var->value, flags, field);
01351    }
01352 
01353    return res;
01354 }
01355 
01356 /*! \brief Default option handler for doubles
01357  * \note For a description of the opt->flags and opt->args values, see the documentation for
01358  * enum aco_option_type in config_options.h
01359  */
01360 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
01361    double *field = (double *)(obj + opt->args[0]);
01362    return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
01363 }
01364 
01365 /*! \brief Default handler for ACLs
01366  * \note For a description of the opt->flags and opt->args values, see the documentation for
01367  * enum aco_option_type in config_options.h
01368  */
01369 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
01370    struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
01371    int error = 0;
01372    *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
01373    return error;
01374 }
01375 
01376 /*! \brief Default option handler for codec preferences/capabilities
01377  * \note For a description of the opt->flags and opt->args values, see the documentation for
01378  * enum aco_option_type in config_options.h
01379  */
01380 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
01381    struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[0]);
01382    return ast_format_cap_update_by_allow_disallow(*cap, var->value, opt->flags);
01383 }
01384 
01385 /*! \brief Default option handler for stringfields
01386  * \note For a description of the opt->flags and opt->args values, see the documentation for
01387  * enum aco_option_type in config_options.h
01388  */
01389 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
01390 {
01391    ast_string_field *field = (const char **)(obj + opt->args[0]);
01392    struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
01393    struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
01394 
01395    if (opt->flags && ast_strlen_zero(var->value)) {
01396       return -1;
01397    }
01398    ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
01399    return 0;
01400 }
01401 
01402 /*! \brief Default option handler for bools (ast_true/ast_false)
01403  * \note For a description of the opt->flags and opt->args values, see the documentation for
01404  * enum aco_option_type in config_options.h
01405  */
01406 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
01407 {
01408    unsigned int *field = (unsigned int *)(obj + opt->args[0]);
01409    *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
01410    return 0;
01411 }
01412 
01413 /*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
01414  * \note For a description of the opt->flags and opt->args values, see the documentation for
01415  * enum aco_option_type in config_options.h
01416  */
01417 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
01418 {
01419    unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
01420    unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
01421    unsigned int flag = opt->args[1];
01422    if (val) {
01423       *flags_field |= flag;
01424    } else {
01425       *flags_field &= ~flag;
01426    }
01427    return 0;
01428 }
01429 
01430 /*! \brief Default handler for ast_sockaddrs
01431  * \note For a description of the opt->flags and opt->args values, see the documentation for
01432  * enum aco_option_type in config_options.h
01433  */
01434 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
01435 {
01436    struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
01437    return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
01438 }
01439 
01440 /*! \brief Default handler for doing nothing
01441  */
01442 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
01443 {
01444    return 0;
01445 }
01446 
01447 /*! \brief Default handler for character arrays
01448  * \note For a description of the opt->flags and opt->args values, see the documentation for
01449  * enum aco_option_type in config_options.h
01450  */
01451 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
01452 {
01453    char *field = (char *)(obj + opt->args[0]);
01454    size_t len = opt->args[1];
01455 
01456    if (opt->flags && ast_strlen_zero(var->value)) {
01457       return -1;
01458    }
01459    ast_copy_string(field, var->value, len);
01460    return 0;
01461 }

Generated on Thu Apr 16 06:27:31 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6