37c743355ee2d0ea8b623fa04cd68b0408ccf670
[asterisk/asterisk.git] / main / config_options.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2012, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  * \brief Configuration Option-handling
21  * \author Terry Wilson <twilson@digium.com>
22  */
23
24 /*** MODULEINFO
25         <support_level>core</support_level>
26  ***/
27
28 #include "asterisk.h"
29
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
31
32 #include <regex.h>
33
34 #include "asterisk/_private.h"
35 #include "asterisk/config.h"
36 #include "asterisk/config_options.h"
37 #include "asterisk/stringfields.h"
38 #include "asterisk/acl.h"
39 #include "asterisk/frame.h"
40 #include "asterisk/xmldoc.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/term.h"
43
44 #ifdef LOW_MEMORY
45 #define CONFIG_OPT_BUCKETS 5
46 #else
47 #define CONFIG_OPT_BUCKETS 53
48 #endif /* LOW_MEMORY */
49
50 /*! \brief Bits of aco_info that shouldn't be assigned outside this file
51  * \internal
52  */
53 struct aco_info_internal {
54         void *pending;              /*!< The user-defined config object awaiting application */
55 };
56
57 struct aco_type_internal {
58         regex_t *regex;
59         struct ao2_container *opts; /*!< The container of options registered to the aco_info */
60 };
61
62 struct aco_option {
63         const char *name;
64         const char *aliased_to;
65         const char *default_val;
66         enum aco_matchtype match_type;
67         regex_t *name_regex;
68         struct aco_type **obj;
69         enum aco_option_type type;
70         aco_option_handler handler;
71         unsigned int flags;
72         unsigned int no_doc:1;
73         unsigned char deprecated:1;
74         size_t argc;
75         intptr_t args[0];
76 };
77
78 #ifdef AST_XML_DOCS
79 static struct ao2_container *xmldocs;
80 #endif /* AST_XML_DOCS */
81
82 /*! \brief Value of the aco_option_type enum as strings */
83 static char *aco_option_type_string[] = {
84         "ACL",                          /* OPT_ACL_T, */
85         "Boolean",                      /* OPT_BOOL_T, */
86         "Boolean",                      /* OPT_BOOLFLAG_T, */
87         "String",                       /* OPT_CHAR_ARRAY_T, */
88         "Codec",                        /* OPT_CODEC_T, */
89         "Custom",                       /* OPT_CUSTOM_T, */
90         "Double",                       /* OPT_DOUBLE_T, */
91         "Integer",                      /* OPT_INT_T, */
92         "None",                         /* OPT_NOOP_T, */
93         "IP Address",           /* OPT_SOCKADDR_T, */
94         "String",                       /* OPT_STRINGFIELD_T, */
95         "Unsigned Integer",     /* OPT_UINT_T, */
96 };
97
98 void *aco_pending_config(struct aco_info *info)
99 {
100         if (!(info && info->internal)) {
101                 ast_log(LOG_ERROR, "This may not be called without an initialized aco_info!\n");
102                 return NULL;
103         }
104         return info->internal->pending;
105 }
106
107 static void config_option_destroy(void *obj)
108 {
109         struct aco_option *opt = obj;
110         if (opt->match_type == ACO_REGEX && opt->name_regex) {
111                 regfree(opt->name_regex);
112                 ast_free(opt->name_regex);
113         }
114 }
115
116 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
117 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
118 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
119 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
120 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
121 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
122 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
123 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
124 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
125 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
126 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
127
128 #ifdef AST_XML_DOCS
129 static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches);
130 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);
131 #endif
132
133 static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
134 {
135         switch(type) {
136         case OPT_ACL_T: return acl_handler_fn;
137         case OPT_BOOL_T: return bool_handler_fn;
138         case OPT_BOOLFLAG_T: return boolflag_handler_fn;
139         case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
140         case OPT_CODEC_T: return codec_handler_fn;
141         case OPT_DOUBLE_T: return double_handler_fn;
142         case OPT_INT_T: return int_handler_fn;
143         case OPT_NOOP_T: return noop_handler_fn;
144         case OPT_SOCKADDR_T: return sockaddr_handler_fn;
145         case OPT_STRINGFIELD_T: return stringfield_handler_fn;
146         case OPT_UINT_T: return uint_handler_fn;
147
148         case OPT_CUSTOM_T: return NULL;
149         }
150
151         return NULL;
152 }
153
154 static regex_t *build_regex(const char *text)
155 {
156         int res;
157         regex_t *regex;
158
159         if (!(regex = ast_malloc(sizeof(*regex)))) {
160                 return NULL;
161         }
162
163         if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
164                 size_t len = regerror(res, regex, NULL, 0);
165                 char buf[len];
166                 regerror(res, regex, buf, len);
167                 ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
168                 ast_free(regex);
169                 return NULL;
170         }
171
172         return regex;
173 }
174
175 static int link_option_to_types(struct aco_info *info, struct aco_type **types, struct aco_option *opt)
176 {
177         size_t idx = 0;
178         struct aco_type *type;
179
180         while ((type = types[idx++])) {
181                 if (!type->internal) {
182                         ast_log(LOG_ERROR, "Attempting to register option using uninitialized type\n");
183                         return -1;
184                 }
185                 if (!ao2_link(type->internal->opts, opt)
186 #ifdef AST_XML_DOCS
187                                 || (!opt->no_doc && xmldoc_update_config_option(types, info->module, opt->name, type->name, opt->default_val, opt->match_type == ACO_REGEX, opt->type))
188 #endif /* AST_XML_DOCS */
189                 ) {
190                         do {
191                                 ao2_unlink(types[idx - 1]->internal->opts, opt);
192                         } while (--idx);
193                         return -1;
194                 }
195         }
196         /* The container(s) should hold the only ref to opt */
197         ao2_ref(opt, -1);
198
199         return 0;
200 }
201
202 int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
203 {
204         struct aco_option *opt;
205
206         if (!info || ast_strlen_zero(name) || ast_strlen_zero(aliased_to)) {
207                 return -1;
208         }
209
210         if (!(opt = ao2_alloc(sizeof(*opt), config_option_destroy))) {
211                 return -1;
212         }
213
214         opt->name = name;
215         opt->aliased_to = aliased_to;
216         opt->deprecated = 1;
217         opt->match_type = ACO_EXACT;
218
219         if (link_option_to_types(info, types, opt)) {
220                 ao2_ref(opt, -1);
221                 return -1;
222         }
223
224         return 0;
225 }
226
227 unsigned int aco_option_get_flags(const struct aco_option *option)
228 {
229         return option->flags;
230 }
231
232 #ifdef AST_XML_DOCS
233 /*! \internal
234  * \brief Find a particular ast_xml_doc_item from it's parent config_info, types, and name
235  */
236 static struct ast_xml_doc_item *find_xmldoc_option(struct ast_xml_doc_item *config_info, struct aco_type **types, const char *name)
237 {
238         struct ast_xml_doc_item *iter = config_info;
239
240         if (!iter) {
241                 return NULL;
242         }
243         /* First is just the configInfo, we can skip it */
244         while ((iter = iter->next)) {
245                 size_t x;
246                 if (strcasecmp(iter->name, name)) {
247                         continue;
248                 }
249                 for (x = 0; types[x]; x++) {
250                         /* All we care about is that at least one type has the option */
251                         if (!strcasecmp(types[x]->name, iter->ref)) {
252                                 return iter;
253                         }
254                 }
255         }
256         return NULL;
257 }
258
259 /*! \internal
260  * \brief Find a particular ast_xml_doc_item from it's parent config_info and name
261  */
262 static struct ast_xml_doc_item *find_xmldoc_type(struct ast_xml_doc_item *config_info, const char *name)
263 {
264         struct ast_xml_doc_item *iter = config_info;
265         if (!iter) {
266                 return NULL;
267         }
268         /* First is just the config Info, skip it */
269         while ((iter = iter->next)) {
270                 if (!strcasecmp(iter->type, "configObject") && !strcasecmp(iter->name, name)) {
271                         break;
272                 }
273         }
274         return iter;
275 }
276
277 #endif /* AST_XML_DOCS */
278
279 int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types,
280         const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags,
281         unsigned int no_doc, size_t argc, ...)
282 {
283         struct aco_option *opt;
284         va_list ap;
285         int tmp;
286
287         /* Custom option types require a handler */
288         if (!handler && kind == OPT_CUSTOM_T) {
289                 return -1;
290         }
291
292         if (!(types && types[0])) {
293                 return -1;
294         }
295
296         if (!(opt = ao2_alloc(sizeof(*opt) + argc * sizeof(opt->args[0]), config_option_destroy))) {
297                 return -1;
298         }
299
300         if (matchtype == ACO_REGEX && !(opt->name_regex = build_regex(name))) {
301                 ao2_ref(opt, -1);
302                 return -1;
303         }
304
305         va_start(ap, argc);
306         for (tmp = 0; tmp < argc; tmp++) {
307                 opt->args[tmp] = va_arg(ap, size_t);
308         }
309         va_end(ap);
310
311         opt->name = name;
312         opt->match_type = matchtype;
313         opt->default_val = default_val;
314         opt->type = kind;
315         opt->handler = handler;
316         opt->flags = flags;
317         opt->argc = argc;
318         opt->no_doc = no_doc;
319
320         if (!opt->handler && !(opt->handler = ast_config_option_default_handler(opt->type))) {
321                 /* This should never happen */
322                 ast_log(LOG_ERROR, "No handler provided, and no default handler exists for type %d\n", opt->type);
323                 ao2_ref(opt, -1);
324                 return -1;
325         };
326
327         if (link_option_to_types(info, types, opt)) {
328                 ao2_ref(opt, -1);
329                 return -1;
330         }
331
332         return 0;
333 }
334
335 static int config_opt_hash(const void *obj, const int flags)
336 {
337         const struct aco_option *opt = obj;
338         const char *name = (flags & OBJ_KEY) ? obj : opt->name;
339         return ast_str_case_hash(name);
340 }
341
342 static int config_opt_cmp(void *obj, void *arg, int flags)
343 {
344         struct aco_option *opt1 = obj, *opt2 = arg;
345         const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
346         return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
347 }
348
349 static int find_option_cb(void *obj, void *arg, int flags)
350 {
351         struct aco_option *match = obj;
352         const char *name = arg;
353
354         switch (match->match_type) {
355         case ACO_EXACT:
356                 return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
357         case ACO_REGEX:
358                 return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
359         }
360         ast_log(LOG_ERROR, "Unknown match type. This should not be possible.\n");
361         return CMP_STOP;
362 }
363
364 static struct aco_option *aco_option_find(struct aco_type *type, const char *name)
365 {
366         struct aco_option *opt;
367
368         if (!type || !type->internal || !type->internal->opts) {
369                 ast_log(LOG_NOTICE, "Attempting to use NULL or unitialized config type\n");
370                 return NULL;
371         }
372
373         /* Try an exact match with OBJ_KEY for the common/fast case, then iterate through
374          * all options for the regex cases */
375         if (!(opt = ao2_callback(type->internal->opts, OBJ_KEY, find_option_cb, (void *) name))) {
376                 opt = ao2_callback(type->internal->opts, 0, find_option_cb, (void *) name);
377         }
378         return opt;
379 }
380
381 struct ao2_container *aco_option_container_alloc(void)
382 {
383         return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
384 }
385
386 static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
387 {
388         size_t x;
389         struct aco_type *match;
390         const char *val;
391
392         for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
393                 /* First make sure we are an object that can service this category */
394                 if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) {
395                         continue;
396                 }
397
398                 /* Then, see if we need to match a particular field */
399                 if (!ast_strlen_zero(match->matchfield) && (!ast_strlen_zero(match->matchvalue) || match->matchfunc)) {
400                         if (!(val = ast_variable_retrieve(cfg, category, match->matchfield))) {
401                                 ast_log(LOG_ERROR, "Required match field '%s' not found\n", match->matchfield);
402                                 return NULL;
403                         }
404                         if (match->matchfunc) {
405                                 if (!match->matchfunc(val)) {
406                                         continue;
407                                 }
408                         } else if (strcasecmp(val, match->matchvalue)) {
409                                 continue;
410                         }
411                 }
412                 /* If we get this far, we're a match */
413                 break;
414         }
415
416         return match;
417 }
418
419 static int is_preload(struct aco_file *file, const char *cat)
420 {
421         int i;
422
423         if (!file->preload) {
424                 return 0;
425         }
426
427         for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
428                 if (!strcasecmp(cat, file->preload[i])) {
429                         return 1;
430                 }
431         }
432         return 0;
433 }
434
435 static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload) {
436         RAII_VAR(void *, new_item, NULL, ao2_cleanup);
437         struct aco_type *type;
438         /* For global types, field is the global option struct. For non-global, it is the container for items.
439          * We do not grab a reference to these objects, as the info already holds references to them. This
440          * pointer is just a convenience. Do not actually store it somewhere. */
441         void **field;
442         regex_t *regex_skip;
443
444         /* Skip preloaded categories if we aren't preloading */
445         if (!preload && is_preload(file, cat)) {
446                 return 0;
447         }
448
449         /* Skip the category if we've been told to ignore it */
450         if (!ast_strlen_zero(file->skip_category)) {
451                 regex_skip = build_regex(file->skip_category);
452                 if (!regexec(regex_skip, cat, 0, NULL, 0)) {
453                         ast_free(regex_skip);
454                         return 0;
455                 }
456                 ast_free(regex_skip);
457         }
458
459         /* Find aco_type by category, if not found it is an error */
460         if (!(type = internal_aco_type_find(file, cfg, cat))) {
461                 ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
462                 return -1;
463         }
464
465         field = info->internal->pending + type->item_offset;
466         if (!*field) {
467                 ast_log(LOG_ERROR, "No object to update!\n");
468                 return -1;
469         }
470
471         if (type->type == ACO_GLOBAL && *field) {
472                 if (aco_set_defaults(type, cat, *field)) {
473                         ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
474                         return -1;
475                 }
476                 if (aco_process_category_options(type, cfg, cat, *field)) {
477                         ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
478                         return -1;
479                 }
480         } else if (type->type == ACO_ITEM) {
481                 int new = 0;
482                 /* If we have multiple definitions of a category in a file, or can set the values from multiple
483                  * files, look up the entry if we've already added it so we can merge the values together.
484                  * Otherwise, alloc a new item. */
485                 if (*field) {
486                         if (!(new_item = type->item_find(*field, cat))) {
487                                 if (!(new_item = type->item_alloc(cat))) {
488                                         ast_log(LOG_ERROR, "In %s: Could not create item for %s\n", file->filename, cat);
489                                         return -1;
490                                 }
491                                 if (aco_set_defaults(type, cat, new_item)) {
492                                         ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
493                                         return -1;
494                                 }
495                                 new = 1;
496                         }
497                 }
498
499                 if (type->item_pre_process && type->item_pre_process(new_item)) {
500                         ast_log(LOG_ERROR, "In %s: Preprocess callback for %s failed\n", file->filename, cat);
501                         return -1;
502                 }
503
504                 if (aco_process_category_options(type, cfg, cat, new_item)) {
505                         ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
506                         return -1;
507                 }
508
509                 if (type->item_prelink && type->item_prelink(new_item)) {
510                         ast_log(LOG_ERROR, "In %s: Pre-link callback for %s failed\n", file->filename, cat);
511                         return -1;
512                 }
513
514                 if (new && !ao2_link(*field, new_item)) {
515                         ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", file->filename, cat);
516                         return -1;
517                 }
518         }
519         return 0;
520 }
521
522 static int apply_config(struct aco_info *info)
523 {
524         ao2_global_obj_replace_unref(*info->global_obj, info->internal->pending);
525
526         return 0;
527 }
528
529 static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
530 {
531         const char *cat = NULL;
532
533         if (file->preload) {
534                 int i;
535                 for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
536                         if (process_category(cfg, info, file, file->preload[i], 1)) {
537                                 return ACO_PROCESS_ERROR;
538                         }
539                 }
540         }
541
542         while ((cat = ast_category_browse(cfg, cat))) {
543                 if (process_category(cfg, info, file, cat, 0)) {
544                         return ACO_PROCESS_ERROR;
545                 }
546         }
547         return ACO_PROCESS_OK;
548 }
549
550 enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
551 {
552         if (!info->internal) {
553                 ast_log(LOG_ERROR, "Attempt to process %s with uninitialized aco_info\n", file->filename);
554                 goto error;
555         }
556
557         if (!(info->internal->pending = info->snapshot_alloc())) {
558                 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", file->filename);
559                 goto error;
560         }
561
562         if (internal_process_ast_config(info, file, cfg)) {
563                 goto error;
564         }
565
566         if (info->pre_apply_config && info->pre_apply_config()) {
567                 goto error;
568         }
569
570         if (apply_config(info)) {
571                 goto error;
572         };
573
574         ao2_cleanup(info->internal->pending);
575         return ACO_PROCESS_OK;
576
577 error:
578         ao2_cleanup(info->internal->pending);
579         return ACO_PROCESS_ERROR;
580 }
581
582 enum aco_process_status aco_process_config(struct aco_info *info, int reload)
583 {
584         struct ast_config *cfg;
585         struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
586         int res = ACO_PROCESS_OK, x = 0;
587         struct aco_file *file;
588
589         if (!(info->files[0])) {
590                 ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
591                 return ACO_PROCESS_ERROR;
592         }
593
594         if (!info->internal) {
595                 ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
596                 return ACO_PROCESS_ERROR;
597         }
598
599         if (!(info->internal->pending = info->snapshot_alloc())) {
600                 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->module);
601                 return ACO_PROCESS_ERROR;
602         }
603
604 /*
605  * XXX ASTERISK-22009 must fix config framework loading of multiple files.
606  *
607  * A reload with multiple files must reload all files if any
608  * file has been touched.
609  */
610         while (res != ACO_PROCESS_ERROR && (file = info->files[x++])) {
611                 const char *filename = file->filename;
612 try_alias:
613                 if (!(cfg = ast_config_load(filename, cfg_flags))) {
614                         if (file->alias && strcmp(file->alias, filename)) {
615                                 filename = file->alias;
616                                 goto try_alias;
617                         }
618                         ast_log(LOG_ERROR, "Unable to load config file '%s'\n", file->filename);
619                         res = ACO_PROCESS_ERROR;
620                         break;
621                 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
622                         ast_debug(1, "%s was unchanged\n", file->filename);
623                         res = ACO_PROCESS_UNCHANGED;
624                         continue;
625                 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
626                         ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", file->filename);
627                         res = ACO_PROCESS_ERROR;
628                         break;
629                 } else if (cfg == CONFIG_STATUS_FILEMISSING) {
630                         if (file->alias && strcmp(file->alias, filename)) {
631                                 filename = file->alias;
632                                 goto try_alias;
633                         }
634                         ast_log(LOG_ERROR, "%s is missing! Cannot load %s\n", file->filename, info->module);
635                         res = ACO_PROCESS_ERROR;
636                         break;
637                 }
638
639                 res = internal_process_ast_config(info, file, cfg);
640                 ast_config_destroy(cfg);
641         }
642
643         if (res != ACO_PROCESS_OK) {
644                 goto end;
645         }
646
647         if (info->pre_apply_config && (info->pre_apply_config())) {
648                 res = ACO_PROCESS_ERROR;
649                 goto end;
650         }
651
652         if (apply_config(info)) {
653                 res = ACO_PROCESS_ERROR;
654                 goto end;
655         }
656
657         if (info->post_apply_config) {
658                 info->post_apply_config();
659         }
660
661 end:
662         ao2_cleanup(info->internal->pending);
663         return res;
664 }
665 int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
666 {
667         RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup);
668         if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) {
669                 const char *alias = ast_strdupa(opt->aliased_to);
670                 ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias);
671                 ao2_ref(opt, -1);
672                 opt = aco_option_find(type, alias);
673         }
674
675         if (!opt) {
676                 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);
677                 return -1;
678         }
679
680         if (!opt->handler) {
681                 /* It should be impossible for an option to not have a handler */
682                 ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name);
683                 return -1;
684         }
685         if (opt->handler(opt, var, obj)) {
686                 ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file);
687                 return -1;
688         }
689
690         return 0;
691 }
692
693 int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
694 {
695         struct ast_variable *var;
696
697         for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
698                 if (aco_process_var(type, cat, var, obj)) {
699                         return -1;
700                 }
701         }
702
703         return 0;
704 }
705
706 static void internal_type_destroy(struct aco_type *type)
707 {
708         /* If we've already had all our internal data cleared out,
709          * then there's no need to proceed further
710          */
711         if (!type->internal) {
712                 return;
713         }
714
715         if (type->internal->regex) {
716                 regfree(type->internal->regex);
717                 ast_free(type->internal->regex);
718         }
719         ao2_cleanup(type->internal->opts);
720         type->internal->opts = NULL;
721         ast_free(type->internal);
722         type->internal = NULL;
723 }
724
725 static void internal_file_types_destroy(struct aco_file *file)
726 {
727         size_t x;
728         struct aco_type *t;
729
730         for (x = 0, t = file->types[x]; t; t = file->types[++x]) {
731                 internal_type_destroy(t);
732                 t = NULL;
733         }
734 }
735
736 static int internal_type_init(struct aco_type *type)
737 {
738         if (!(type->internal = ast_calloc(1, sizeof(*type->internal)))) {
739                 return -1;
740         }
741
742         if (!(type->internal->regex = build_regex(type->category))) {
743                 internal_type_destroy(type);
744                 return -1;
745         }
746
747         if (!(type->internal->opts = aco_option_container_alloc())) {
748                 internal_type_destroy(type);
749                 return -1;
750         }
751
752         return 0;
753 }
754
755 int aco_info_init(struct aco_info *info)
756 {
757         size_t x = 0, y = 0;
758         struct aco_file *file;
759         struct aco_type *type;
760
761         if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
762                 return -1;
763         }
764
765         while ((file = info->files[x++])) {
766                 while ((type = file->types[y++])) {
767                         if (internal_type_init(type)) {
768                                 goto error;
769                         }
770 #ifdef AST_XML_DOCS
771                         if (!type->hidden && xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match == ACO_WHITELIST)) {
772                                 goto error;
773                         }
774 #endif /* AST_XML_DOCS */
775                 }
776                 y = 0;
777         }
778
779         return 0;
780 error:
781         aco_info_destroy(info);
782         return -1;
783 }
784
785 void aco_info_destroy(struct aco_info *info)
786 {
787         int x;
788         /* It shouldn't be possible for internal->pending to be in use when this is called because
789          * of the locks in loader.c around reloads and unloads and the fact that internal->pending
790          * only exists while those locks are held */
791         ast_free(info->internal);
792         info->internal = NULL;
793
794         for (x = 0; info->files[x]; x++) {
795                 internal_file_types_destroy(info->files[x]);
796         }
797 }
798
799 int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
800 {
801         struct aco_option *opt;
802         struct ao2_iterator iter;
803
804         iter = ao2_iterator_init(type->internal->opts, 0);
805
806         while ((opt = ao2_iterator_next(&iter))) {
807                 RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy);
808
809                 if (ast_strlen_zero(opt->default_val)) {
810                         ao2_ref(opt, -1);
811                         continue;
812                 }
813                 if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
814                         ao2_ref(opt, -1);
815                         ao2_iterator_destroy(&iter);
816                         return -1;
817                 }
818                 if (opt->handler(opt, var, obj)) {
819                         ast_log(LOG_ERROR, "Unable to set default for %s, %s=%s\n", category, var->name, var->value);
820                         ao2_ref(opt, -1);
821                         ao2_iterator_destroy(&iter);
822                         return -1;
823                 }
824                 ao2_ref(opt, -1);
825         }
826         ao2_iterator_destroy(&iter);
827
828         return 0;
829 }
830
831 #ifdef AST_XML_DOCS
832
833 /*! \internal
834  * \brief Complete the name of the module the user is looking for
835  */
836 static char *complete_config_module(const char *word, int pos, int state)
837 {
838         char *c = NULL;
839         size_t wordlen = strlen(word);
840         int which = 0;
841         struct ao2_iterator i;
842         struct ast_xml_doc_item *cur;
843
844         if (pos != 3) {
845                 return NULL;
846         }
847
848         i = ao2_iterator_init(xmldocs, 0);
849         while ((cur = ao2_iterator_next(&i))) {
850                 if (!strncasecmp(word, cur->name, wordlen) && ++which > state) {
851                         c = ast_strdup(cur->name);
852                         ao2_ref(cur, -1);
853                         break;
854                 }
855                 ao2_ref(cur, -1);
856         }
857         ao2_iterator_destroy(&i);
858
859         return c;
860 }
861
862 /*! \internal
863  * \brief Complete the name of the configuration type the user is looking for
864  */
865 static char *complete_config_type(const char *module, const char *word, int pos, int state)
866 {
867         char *c = NULL;
868         size_t wordlen = strlen(word);
869         int which = 0;
870         RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
871         struct ast_xml_doc_item *cur;
872
873         if (pos != 4) {
874                 return NULL;
875         }
876
877         if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
878                 return NULL;
879         }
880
881         cur = info;
882         while ((cur = cur->next)) {
883                 if (!strcasecmp(cur->type, "configObject") && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
884                         c = ast_strdup(cur->name);
885                         break;
886                 }
887         }
888         return c;
889 }
890
891 /*! \internal
892  * \brief Complete the name of the configuration option the user is looking for
893  */
894 static char *complete_config_option(const char *module, const char *option, const char *word, int pos, int state)
895 {
896         char *c = NULL;
897         size_t wordlen = strlen(word);
898         int which = 0;
899         RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
900         struct ast_xml_doc_item *cur;
901
902         if (pos != 5) {
903                 return NULL;
904         }
905
906         if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
907                 return NULL;
908         }
909
910         cur = info;
911         while ((cur = cur->next)) {
912                 if (!strcasecmp(cur->type, "configOption") && !strcasecmp(cur->ref, option) && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
913                         c = ast_strdup(cur->name);
914                         break;
915                 }
916         }
917         return c;
918 }
919
920 /* Define as 0 if we want to allow configurations to be registered without
921  * documentation
922  */
923 #define XMLDOC_STRICT 1
924
925 /*! \internal
926  * \brief Update the XML documentation for a config type based on its registration
927  */
928 static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches)
929 {
930         RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
931         RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
932         struct ast_xml_doc_item *config_type;
933         struct ast_xml_node *type, *syntax, *matchinfo, *tmp;
934
935         /* If we already have a syntax element, bail. This isn't an error, since we may unload a module which
936          * has updated the docs and then load it again. */
937         if ((results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/syntax", module, name))) {
938                 return 0;
939         }
940
941         if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']", module, name))) {
942                 ast_log(LOG_WARNING, "Cannot update type '%s' in module '%s' because it has no existing documentation!\n", name, module);
943                 return XMLDOC_STRICT ? -1 : 0;
944         }
945
946         if (!(type = ast_xml_xpath_get_first_result(results))) {
947                 ast_log(LOG_WARNING, "Could not retrieve documentation for type '%s' in module '%s'\n", name, module);
948                 return XMLDOC_STRICT ? -1 : 0;
949         }
950
951         if (!(syntax = ast_xml_new_child(type, "syntax"))) {
952                 ast_log(LOG_WARNING, "Could not create syntax node for type '%s' in module '%s'\n", name, module);
953                 return XMLDOC_STRICT ? -1 : 0;
954         }
955
956         if (!(matchinfo = ast_xml_new_child(syntax, "matchInfo"))) {
957                 ast_log(LOG_WARNING, "Could not create matchInfo node for type '%s' in module '%s'\n", name, module);
958                 return XMLDOC_STRICT ? -1 : 0;
959         }
960
961         if (!(tmp = ast_xml_new_child(matchinfo, "category"))) {
962                 ast_log(LOG_WARNING, "Could not create category node for type '%s' in module '%s'\n", name, module);
963                 return XMLDOC_STRICT ? -1 : 0;
964         }
965
966         ast_xml_set_text(tmp, category);
967         ast_xml_set_attribute(tmp, "match", matches ? "true" : "false");
968
969         if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) {
970                 ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
971                 return XMLDOC_STRICT ? -1 : 0;
972         }
973
974         ast_xml_set_attribute(tmp, "name", matchfield);
975         ast_xml_set_text(tmp, matchvalue);
976
977         if (!config_info || !(config_type = find_xmldoc_type(config_info, name))) {
978                 ast_log(LOG_WARNING, "Could not obtain XML documentation item for config type %s\n", name);
979                 return XMLDOC_STRICT ? -1 : 0;
980         }
981
982         if (ast_xmldoc_regenerate_doc_item(config_type)) {
983                 ast_log(LOG_WARNING, "Could not update type '%s' with values from config type registration\n", name);
984                 return XMLDOC_STRICT ? -1 : 0;
985         }
986
987         return 0;
988 }
989
990 /*! \internal
991  * \brief Update the XML documentation for a config option based on its registration
992  */
993 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)
994 {
995         RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
996         RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
997         struct ast_xml_doc_item * config_option;
998         struct ast_xml_node *option;
999
1000         ast_assert(ARRAY_LEN(aco_option_type_string) > type);
1001
1002         if (!config_info || !(config_option = find_xmldoc_option(config_info, types, name))) {
1003                 ast_log(LOG_ERROR, "XML Documentation for option '%s' in modules '%s' not found!\n", name, module);
1004                 return XMLDOC_STRICT ? -1 : 0;
1005         }
1006
1007         if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/configOption[@name='%s']", module, object_name, name))) {
1008                 ast_log(LOG_WARNING, "Could not find option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1009                 return XMLDOC_STRICT ? -1 : 0;
1010         }
1011
1012         if (!(option = ast_xml_xpath_get_first_result(results))) {
1013                 ast_log(LOG_WARNING, "Could obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1014                 return XMLDOC_STRICT ? -1 : 0;
1015         }
1016         ast_xml_set_attribute(option, "regex", regex ? "true" : "false");
1017         ast_xml_set_attribute(option, "default", default_value);
1018         ast_xml_set_attribute(option, "type", aco_option_type_string[type]);
1019
1020         if (ast_xmldoc_regenerate_doc_item(config_option)) {
1021                 ast_log(LOG_WARNING, "Could not update option '%s' with values from config option registration\n", name);
1022                 return XMLDOC_STRICT ? -1 : 0;
1023         }
1024
1025         return 0;
1026 }
1027
1028 /*! \internal
1029  * \brief Show the modules with configuration information
1030  */
1031 static void cli_show_modules(struct ast_cli_args *a)
1032 {
1033         struct ast_xml_doc_item *item;
1034         struct ao2_iterator it_items;
1035
1036         ast_assert(a->argc == 3);
1037
1038         if (ao2_container_count(xmldocs) == 0) {
1039                 ast_cli(a->fd, "No modules found.\n");
1040                 return;
1041         }
1042
1043         it_items = ao2_iterator_init(xmldocs, 0);
1044         ast_cli(a->fd, "The following modules have configuration information:\n");
1045         while ((item = ao2_iterator_next(&it_items))) {
1046                 ast_cli(a->fd, "\t%s\n", item->name);
1047                 ao2_ref(item, -1);
1048         }
1049         ao2_iterator_destroy(&it_items);
1050 }
1051
1052 /*! \internal
1053  * \brief Show the configuration types for a module
1054  */
1055 static void cli_show_module_types(struct ast_cli_args *a)
1056 {
1057         RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
1058         struct ast_xml_doc_item *tmp;
1059
1060         ast_assert(a->argc == 4);
1061
1062         if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1063                 ast_cli(a->fd, "Module %s not found.\n", a->argv[3]);
1064                 return;
1065         }
1066
1067         if (ast_str_strlen(item->synopsis)) {
1068                 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->synopsis), 1));
1069         }
1070         if (ast_str_strlen(item->description)) {
1071                 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->description), 1));
1072         }
1073
1074         tmp = item;
1075         ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
1076         while ((tmp = tmp->next)) {
1077                 if (!strcasecmp(tmp->type, "configObject")) {
1078                         ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1079                                 ast_str_buffer(tmp->synopsis));
1080                 }
1081         }
1082 }
1083
1084 /*! \internal
1085  * \brief Show the information for a configuration type
1086  */
1087 static void cli_show_module_type(struct ast_cli_args *a)
1088 {
1089         RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
1090         struct ast_xml_doc_item *tmp;
1091         char option_type[64];
1092         int match = 0;
1093
1094         ast_assert(a->argc == 5);
1095
1096         if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1097                 ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1098                 return;
1099         }
1100
1101         tmp = item;
1102         while ((tmp = tmp->next)) {
1103                 if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
1104                         match = 1;
1105                         term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
1106                         ast_cli(a->fd, "%s", option_type);
1107                         if (ast_str_strlen(tmp->syntax)) {
1108                                 ast_cli(a->fd, ": [%s]\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1109                         } else {
1110                                 ast_cli(a->fd, "\n\n");
1111                         }
1112                         if (ast_str_strlen(tmp->synopsis)) {
1113                                 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->synopsis), 1));
1114                         }
1115                         if (ast_str_strlen(tmp->description)) {
1116                                 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1117                         }
1118                 }
1119         }
1120
1121         if (!match) {
1122                 ast_cli(a->fd, "Unknown configuration type %s\n", a->argv[4]);
1123                 return;
1124         }
1125
1126         /* Now iterate over the options for the type */
1127         tmp = item;
1128         while ((tmp = tmp->next)) {
1129                 if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
1130                         ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1131                                         ast_str_buffer(tmp->synopsis));
1132                 }
1133         }
1134 }
1135
1136 /*! \internal
1137  * \brief Show detailed information for an option
1138  */
1139 static void cli_show_module_options(struct ast_cli_args *a)
1140 {
1141         RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
1142         struct ast_xml_doc_item *tmp;
1143         char option_name[64];
1144         int match = 0;
1145
1146         ast_assert(a->argc == 6);
1147
1148         if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1149                 ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1150                 return;
1151         }
1152         tmp = item;
1153         while ((tmp = tmp->next)) {
1154                 if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
1155                         if (match) {
1156                                 ast_cli(a->fd, "\n");
1157                         }
1158                         term_color(option_name, tmp->ref, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_name));
1159                         ast_cli(a->fd, "[%s%s]\n", option_name, term_end());
1160                         if (ast_str_strlen(tmp->syntax)) {
1161                                 ast_cli(a->fd, "%s\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1162                         }
1163                         ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(AS_OR(tmp->synopsis, "No information available"), 1));
1164                         if (ast_str_strlen(tmp->description)) {
1165                                 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1166                         }
1167
1168                         match = 1;
1169                 }
1170         }
1171
1172         if (!match) {
1173                 ast_cli(a->fd, "No option %s found for %s:%s\n", a->argv[5], a->argv[3], a->argv[4]);
1174         }
1175 }
1176
1177 static char *cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1178 {
1179         switch (cmd) {
1180         case CLI_INIT:
1181                 e->command = "config show help";
1182                 e->usage =
1183                         "Usage: config show help [<module> [<type> [<option>]]]\n"
1184                         "   Display detailed information about module configuration.\n"
1185                         "     * If nothing is specified, the modules that have\n"
1186                         "       configuration information are listed.\n"
1187                         "     * If <module> is specified, the configuration types\n"
1188                         "       for that module will be listed, along with brief\n"
1189                         "       information about that type.\n"
1190                         "     * If <module> and <type> are specified, detailed\n"
1191                         "       information about the type is displayed, as well\n"
1192                         "       as the available options.\n"
1193                         "     * If <module>, <type>, and <option> are specified,\n"
1194                         "       detailed information will be displayed about that\n"
1195                         "       option.\n"
1196                         "   NOTE: the help documentation is partially generated at run\n"
1197                         "     time when a module is loaded. If a module is not loaded,\n"
1198                         "     configuration help for that module may be incomplete.\n";
1199                 return NULL;
1200         case CLI_GENERATE:
1201                 switch(a->pos) {
1202                 case 3: return complete_config_module(a->word, a->pos, a->n);
1203                 case 4: return complete_config_type(a->argv[3], a->word, a->pos, a->n);
1204                 case 5: return complete_config_option(a->argv[3], a->argv[4], a->word, a->pos, a->n);
1205                 default: return NULL;
1206                 }
1207         }
1208
1209         switch (a->argc) {
1210         case 3:
1211                 cli_show_modules(a);
1212                 break;
1213         case 4:
1214                 cli_show_module_types(a);
1215                 break;
1216         case 5:
1217                 cli_show_module_type(a);
1218                 break;
1219         case 6:
1220                 cli_show_module_options(a);
1221                 break;
1222         default:
1223                 return CLI_SHOWUSAGE;
1224         }
1225
1226         return CLI_SUCCESS;
1227 }
1228
1229 static struct ast_cli_entry cli_aco[] = {
1230         AST_CLI_DEFINE(cli_show_help, "Show configuration help for a module"),
1231 };
1232
1233 static void aco_deinit(void)
1234 {
1235         ast_cli_unregister(cli_aco);
1236         ao2_cleanup(xmldocs);
1237 }
1238 #endif /* AST_XML_DOCS */
1239
1240 int aco_init(void)
1241 {
1242 #ifdef AST_XML_DOCS
1243         ast_register_atexit(aco_deinit);
1244         if (!(xmldocs = ast_xmldoc_build_documentation("configInfo"))) {
1245                 ast_log(LOG_ERROR, "Couldn't build config documentation\n");
1246                 return -1;
1247         }
1248         ast_cli_register_multiple(cli_aco, ARRAY_LEN(cli_aco));
1249 #endif /* AST_XML_DOCS */
1250         return 0;
1251 }
1252
1253 /* Default config option handlers */
1254
1255 /*! \brief Default option handler for signed integers
1256  * \note For a description of the opt->flags and opt->args values, see the documentation for
1257  * enum aco_option_type in config_options.h
1258  */
1259 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1260         int *field = (int *)(obj + opt->args[0]);
1261         unsigned int flags = PARSE_INT32 | opt->flags;
1262         int res = 0;
1263         if (opt->flags & PARSE_IN_RANGE) {
1264                 res = opt->flags & PARSE_DEFAULT ?
1265                         ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
1266                         ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
1267                 if (res) {
1268                         if (opt->flags & PARSE_RANGE_DEFAULTS) {
1269                                 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]);
1270                                 res = 0;
1271                         } else if (opt->flags & PARSE_DEFAULT) {
1272                                 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1273                                 res = 0;
1274                         }
1275                 }
1276         } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
1277                 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
1278         } else {
1279                 res = ast_parse_arg(var->value, flags, field);
1280         }
1281
1282         return res;
1283 }
1284
1285 /*! \brief Default option handler for unsigned integers
1286  * \note For a description of the opt->flags and opt->args values, see the documentation for
1287  * enum aco_option_type in config_options.h
1288  */
1289 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1290         unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1291         unsigned int flags = PARSE_INT32 | opt->flags;
1292         int res = 0;
1293         if (opt->flags & PARSE_IN_RANGE) {
1294                 res = opt->flags & PARSE_DEFAULT ?
1295                         ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
1296                         ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
1297                 if (res) {
1298                         if (opt->flags & PARSE_RANGE_DEFAULTS) {
1299                                 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]);
1300                                 res = 0;
1301                         } else if (opt->flags & PARSE_DEFAULT) {
1302                                 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1303                                 res = 0;
1304                         }
1305                 }
1306         } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
1307                 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
1308         } else {
1309                 res = ast_parse_arg(var->value, flags, field);
1310         }
1311
1312         return res;
1313 }
1314
1315 /*! \brief Default option handler for doubles
1316  * \note For a description of the opt->flags and opt->args values, see the documentation for
1317  * enum aco_option_type in config_options.h
1318  */
1319 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1320         double *field = (double *)(obj + opt->args[0]);
1321         return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
1322 }
1323
1324 /*! \brief Default handler for ACLs
1325  * \note For a description of the opt->flags and opt->args values, see the documentation for
1326  * enum aco_option_type in config_options.h
1327  */
1328 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1329         struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
1330         int error = 0;
1331         *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
1332         return error;
1333 }
1334
1335 /*! \brief Default option handler for codec preferences/capabilities
1336  * \note For a description of the opt->flags and opt->args values, see the documentation for
1337  * enum aco_option_type in config_options.h
1338  */
1339 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1340         struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + opt->args[0]);
1341         struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[1]);
1342         return ast_parse_allow_disallow(pref, *cap, var->value, opt->flags);
1343 }
1344
1345 /*! \brief Default option handler for stringfields
1346  * \note For a description of the opt->flags and opt->args values, see the documentation for
1347  * enum aco_option_type in config_options.h
1348  */
1349 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1350 {
1351         ast_string_field *field = (const char **)(obj + opt->args[0]);
1352         struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
1353         struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
1354
1355         if (opt->flags && ast_strlen_zero(var->value)) {
1356                 return -1;
1357         }
1358         ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
1359         return 0;
1360 }
1361
1362 /*! \brief Default option handler for bools (ast_true/ast_false)
1363  * \note For a description of the opt->flags and opt->args values, see the documentation for
1364  * enum aco_option_type in config_options.h
1365  */
1366 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1367 {
1368         unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1369         *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
1370         return 0;
1371 }
1372
1373 /*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
1374  * \note For a description of the opt->flags and opt->args values, see the documentation for
1375  * enum aco_option_type in config_options.h
1376  */
1377 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1378 {
1379         unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
1380         unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
1381         unsigned int flag = opt->args[1];
1382         if (val) {
1383                 *flags_field |= flag;
1384         } else {
1385                 *flags_field &= ~flag;
1386         }
1387         return 0;
1388 }
1389
1390 /*! \brief Default handler for ast_sockaddrs
1391  * \note For a description of the opt->flags and opt->args values, see the documentation for
1392  * enum aco_option_type in config_options.h
1393  */
1394 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1395 {
1396         struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
1397         return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
1398 }
1399
1400 /*! \brief Default handler for doing nothing
1401  */
1402 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1403 {
1404         return 0;
1405 }
1406
1407 /*! \brief Default handler for character arrays
1408  * \note For a description of the opt->flags and opt->args values, see the documentation for
1409  * enum aco_option_type in config_options.h
1410  */
1411 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1412 {
1413         char *field = (char *)(obj + opt->args[0]);
1414         size_t len = opt->args[1];
1415
1416         if (opt->flags && ast_strlen_zero(var->value)) {
1417                 return -1;
1418         }
1419         ast_copy_string(field, var->value, len);
1420         return 0;
1421 }