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