Fix the config_options_test
[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                         ast_free(regex_skip);
461                         return 0;
462                 }
463                 ast_free(regex_skip);
464         }
465
466         /* Find aco_type by category, if not found it is an error */
467         if (!(type = internal_aco_type_find(file, cfg, cat))) {
468                 ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
469                 return -1;
470         }
471
472         field = info->internal->pending + type->item_offset;
473         if (!*field) {
474                 ast_log(LOG_ERROR, "No object to update!\n");
475                 return -1;
476         }
477
478         if (type->type == ACO_GLOBAL && *field) {
479                 if (aco_set_defaults(type, cat, *field)) {
480                         ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
481                         return -1;
482                 }
483                 if (aco_process_category_options(type, cfg, cat, *field)) {
484                         ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
485                         return -1;
486                 }
487         } else if (type->type == ACO_ITEM) {
488                 int new = 0;
489                 /* If we have multiple definitions of a category in a file, or can set the values from multiple
490                  * files, look up the entry if we've already added it so we can merge the values together.
491                  * Otherwise, alloc a new item. */
492                 if (*field) {
493                         if (!(new_item = type->item_find(*field, cat))) {
494                                 if (!(new_item = type->item_alloc(cat))) {
495                                         ast_log(LOG_ERROR, "In %s: Could not create item for %s\n", file->filename, cat);
496                                         return -1;
497                                 }
498                                 if (aco_set_defaults(type, cat, new_item)) {
499                                         ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
500                                         return -1;
501                                 }
502                                 new = 1;
503                         }
504                 }
505
506                 if (type->item_pre_process && type->item_pre_process(new_item)) {
507                         ast_log(LOG_ERROR, "In %s: Preprocess callback for %s failed\n", file->filename, cat);
508                         return -1;
509                 }
510
511                 if (aco_process_category_options(type, cfg, cat, new_item)) {
512                         ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
513                         return -1;
514                 }
515
516                 if (type->item_prelink && type->item_prelink(new_item)) {
517                         ast_log(LOG_ERROR, "In %s: Pre-link callback for %s failed\n", file->filename, cat);
518                         return -1;
519                 }
520
521                 if (new && !ao2_link(*field, new_item)) {
522                         ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", file->filename, cat);
523                         return -1;
524                 }
525         }
526         return 0;
527 }
528
529 static int apply_config(struct aco_info *info)
530 {
531         ao2_global_obj_replace_unref(*info->global_obj, info->internal->pending);
532
533         return 0;
534 }
535
536 static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
537 {
538         const char *cat = NULL;
539
540         if (file->preload) {
541                 int i;
542                 for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
543                         if (process_category(cfg, info, file, file->preload[i], 1)) {
544                                 return ACO_PROCESS_ERROR;
545                         }
546                 }
547         }
548
549         while ((cat = ast_category_browse(cfg, cat))) {
550                 if (process_category(cfg, info, file, cat, 0)) {
551                         return ACO_PROCESS_ERROR;
552                 }
553         }
554         return ACO_PROCESS_OK;
555 }
556
557 enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
558 {
559         if (!info->internal) {
560                 ast_log(LOG_ERROR, "Attempt to process %s with uninitialized aco_info\n", file->filename);
561                 goto error;
562         }
563
564         if (!(info->internal->pending = info->snapshot_alloc())) {
565                 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", file->filename);
566                 goto error;
567         }
568
569         if (internal_process_ast_config(info, file, cfg)) {
570                 goto error;
571         }
572
573         if (info->pre_apply_config && info->pre_apply_config()) {
574                 goto error;
575         }
576
577         if (apply_config(info)) {
578                 goto error;
579         };
580
581         ao2_cleanup(info->internal->pending);
582         return ACO_PROCESS_OK;
583
584 error:
585         ao2_cleanup(info->internal->pending);
586         return ACO_PROCESS_ERROR;
587 }
588
589 enum aco_process_status aco_process_config(struct aco_info *info, int reload)
590 {
591         struct ast_config *cfg;
592         struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
593         int res = ACO_PROCESS_OK, x = 0;
594         struct aco_file *file;
595
596         if (!(info->files[0])) {
597                 ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
598                 return ACO_PROCESS_ERROR;
599         }
600
601         if (!info->internal) {
602                 ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
603                 return ACO_PROCESS_ERROR;
604         }
605
606         if (!(info->internal->pending = info->snapshot_alloc())) {
607                 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->module);
608                 return ACO_PROCESS_ERROR;
609         }
610
611 /*
612  * XXX ASTERISK-22009 must fix config framework loading of multiple files.
613  *
614  * A reload with multiple files must reload all files if any
615  * file has been touched.
616  */
617         while (res != ACO_PROCESS_ERROR && (file = info->files[x++])) {
618                 const char *filename = file->filename;
619 try_alias:
620                 if (!(cfg = ast_config_load(filename, cfg_flags))) {
621                         if (file->alias && strcmp(file->alias, filename)) {
622                                 filename = file->alias;
623                                 goto try_alias;
624                         }
625                         ast_log(LOG_ERROR, "Unable to load config file '%s'\n", file->filename);
626                         res = ACO_PROCESS_ERROR;
627                         break;
628                 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
629                         ast_debug(1, "%s was unchanged\n", file->filename);
630                         res = ACO_PROCESS_UNCHANGED;
631                         continue;
632                 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
633                         ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", file->filename);
634                         res = ACO_PROCESS_ERROR;
635                         break;
636                 } else if (cfg == CONFIG_STATUS_FILEMISSING) {
637                         if (file->alias && strcmp(file->alias, filename)) {
638                                 filename = file->alias;
639                                 goto try_alias;
640                         }
641                         ast_log(LOG_ERROR, "%s is missing! Cannot load %s\n", file->filename, info->module);
642                         res = ACO_PROCESS_ERROR;
643                         break;
644                 }
645
646                 res = internal_process_ast_config(info, file, cfg);
647                 ast_config_destroy(cfg);
648         }
649
650         if (res != ACO_PROCESS_OK) {
651                 goto end;
652         }
653
654         if (info->pre_apply_config && (info->pre_apply_config())) {
655                 res = ACO_PROCESS_ERROR;
656                 goto end;
657         }
658
659         if (apply_config(info)) {
660                 res = ACO_PROCESS_ERROR;
661                 goto end;
662         }
663
664         if (info->post_apply_config) {
665                 info->post_apply_config();
666         }
667
668 end:
669         ao2_cleanup(info->internal->pending);
670         return res;
671 }
672 int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
673 {
674         RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup);
675         if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) {
676                 const char *alias = ast_strdupa(opt->aliased_to);
677                 ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias);
678                 ao2_ref(opt, -1);
679                 opt = aco_option_find(type, alias);
680         }
681
682         if (!opt) {
683                 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);
684                 return -1;
685         }
686
687         if (!opt->handler) {
688                 /* It should be impossible for an option to not have a handler */
689                 ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name);
690                 return -1;
691         }
692         if (opt->handler(opt, var, obj)) {
693                 ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file);
694                 return -1;
695         }
696
697         return 0;
698 }
699
700 int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
701 {
702         struct ast_variable *var;
703
704         for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
705                 if (aco_process_var(type, cat, var, obj)) {
706                         return -1;
707                 }
708         }
709
710         return 0;
711 }
712
713 static void internal_type_destroy(struct aco_type *type)
714 {
715         /* If we've already had all our internal data cleared out,
716          * then there's no need to proceed further
717          */
718         if (!type->internal) {
719                 return;
720         }
721
722         if (type->internal->regex) {
723                 regfree(type->internal->regex);
724                 ast_free(type->internal->regex);
725         }
726         ao2_cleanup(type->internal->opts);
727         type->internal->opts = NULL;
728         ast_free(type->internal);
729         type->internal = NULL;
730 }
731
732 static void internal_file_types_destroy(struct aco_file *file)
733 {
734         size_t x;
735         struct aco_type *t;
736
737         for (x = 0, t = file->types[x]; t; t = file->types[++x]) {
738                 internal_type_destroy(t);
739                 t = NULL;
740         }
741 }
742
743 static int internal_type_init(struct aco_type *type)
744 {
745         if (!(type->internal = ast_calloc(1, sizeof(*type->internal)))) {
746                 return -1;
747         }
748
749         if (!(type->internal->regex = build_regex(type->category))) {
750                 internal_type_destroy(type);
751                 return -1;
752         }
753
754         if (!(type->internal->opts = aco_option_container_alloc())) {
755                 internal_type_destroy(type);
756                 return -1;
757         }
758
759         return 0;
760 }
761
762 int aco_info_init(struct aco_info *info)
763 {
764         size_t x = 0, y = 0;
765         struct aco_file *file;
766         struct aco_type *type;
767
768         if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
769                 return -1;
770         }
771
772         while ((file = info->files[x++])) {
773                 while ((type = file->types[y++])) {
774                         if (internal_type_init(type)) {
775                                 goto error;
776                         }
777 #ifdef AST_XML_DOCS
778                         if (!info->hidden &&
779                                 !type->hidden &&
780                                 xmldoc_update_config_type(info->module, type->name, type->category, type->matchfield, type->matchvalue, type->category_match == ACO_WHITELIST)) {
781                                 goto error;
782                         }
783 #endif /* AST_XML_DOCS */
784                 }
785                 y = 0;
786         }
787
788         return 0;
789 error:
790         aco_info_destroy(info);
791         return -1;
792 }
793
794 void aco_info_destroy(struct aco_info *info)
795 {
796         int x;
797         /* It shouldn't be possible for internal->pending to be in use when this is called because
798          * of the locks in loader.c around reloads and unloads and the fact that internal->pending
799          * only exists while those locks are held */
800         ast_free(info->internal);
801         info->internal = NULL;
802
803         for (x = 0; info->files[x]; x++) {
804                 internal_file_types_destroy(info->files[x]);
805         }
806 }
807
808 int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
809 {
810         struct aco_option *opt;
811         struct ao2_iterator iter;
812
813         iter = ao2_iterator_init(type->internal->opts, 0);
814
815         while ((opt = ao2_iterator_next(&iter))) {
816                 RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy);
817
818                 if (ast_strlen_zero(opt->default_val)) {
819                         ao2_ref(opt, -1);
820                         continue;
821                 }
822                 if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
823                         ao2_ref(opt, -1);
824                         ao2_iterator_destroy(&iter);
825                         return -1;
826                 }
827                 if (opt->handler(opt, var, obj)) {
828                         ast_log(LOG_ERROR, "Unable to set default for %s, %s=%s\n", category, var->name, var->value);
829                         ao2_ref(opt, -1);
830                         ao2_iterator_destroy(&iter);
831                         return -1;
832                 }
833                 ao2_ref(opt, -1);
834         }
835         ao2_iterator_destroy(&iter);
836
837         return 0;
838 }
839
840 #ifdef AST_XML_DOCS
841
842 /*! \internal
843  * \brief Complete the name of the module the user is looking for
844  */
845 static char *complete_config_module(const char *word, int pos, int state)
846 {
847         char *c = NULL;
848         size_t wordlen = strlen(word);
849         int which = 0;
850         struct ao2_iterator i;
851         struct ast_xml_doc_item *cur;
852
853         if (pos != 3) {
854                 return NULL;
855         }
856
857         i = ao2_iterator_init(xmldocs, 0);
858         while ((cur = ao2_iterator_next(&i))) {
859                 if (!strncasecmp(word, cur->name, wordlen) && ++which > state) {
860                         c = ast_strdup(cur->name);
861                         ao2_ref(cur, -1);
862                         break;
863                 }
864                 ao2_ref(cur, -1);
865         }
866         ao2_iterator_destroy(&i);
867
868         return c;
869 }
870
871 /*! \internal
872  * \brief Complete the name of the configuration type the user is looking for
873  */
874 static char *complete_config_type(const char *module, const char *word, int pos, int state)
875 {
876         char *c = NULL;
877         size_t wordlen = strlen(word);
878         int which = 0;
879         RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
880         struct ast_xml_doc_item *cur;
881
882         if (pos != 4) {
883                 return NULL;
884         }
885
886         if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
887                 return NULL;
888         }
889
890         cur = info;
891         while ((cur = cur->next)) {
892                 if (!strcasecmp(cur->type, "configObject") && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
893                         c = ast_strdup(cur->name);
894                         break;
895                 }
896         }
897         return c;
898 }
899
900 /*! \internal
901  * \brief Complete the name of the configuration option the user is looking for
902  */
903 static char *complete_config_option(const char *module, const char *option, const char *word, int pos, int state)
904 {
905         char *c = NULL;
906         size_t wordlen = strlen(word);
907         int which = 0;
908         RAII_VAR(struct ast_xml_doc_item *, info, NULL, ao2_cleanup);
909         struct ast_xml_doc_item *cur;
910
911         if (pos != 5) {
912                 return NULL;
913         }
914
915         if (!(info = ao2_find(xmldocs, module, OBJ_KEY))) {
916                 return NULL;
917         }
918
919         cur = info;
920         while ((cur = cur->next)) {
921                 if (!strcasecmp(cur->type, "configOption") && !strcasecmp(cur->ref, option) && !strncasecmp(word, cur->name, wordlen) && ++which > state) {
922                         c = ast_strdup(cur->name);
923                         break;
924                 }
925         }
926         return c;
927 }
928
929 /* Define as 0 if we want to allow configurations to be registered without
930  * documentation
931  */
932 #define XMLDOC_STRICT 1
933
934 /*! \internal
935  * \brief Update the XML documentation for a config type based on its registration
936  */
937 static int xmldoc_update_config_type(const char *module, const char *name, const char *category, const char *matchfield, const char *matchvalue, unsigned int matches)
938 {
939         RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
940         RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
941         struct ast_xml_doc_item *config_type;
942         struct ast_xml_node *type, *syntax, *matchinfo, *tmp;
943
944         /* If we already have a syntax element, bail. This isn't an error, since we may unload a module which
945          * has updated the docs and then load it again. */
946         if ((results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/syntax", module, name))) {
947                 return 0;
948         }
949
950         if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']", module, name))) {
951                 ast_log(LOG_WARNING, "Cannot update type '%s' in module '%s' because it has no existing documentation!\n", name, module);
952                 return XMLDOC_STRICT ? -1 : 0;
953         }
954
955         if (!(type = ast_xml_xpath_get_first_result(results))) {
956                 ast_log(LOG_WARNING, "Could not retrieve documentation for type '%s' in module '%s'\n", name, module);
957                 return XMLDOC_STRICT ? -1 : 0;
958         }
959
960         if (!(syntax = ast_xml_new_child(type, "syntax"))) {
961                 ast_log(LOG_WARNING, "Could not create syntax node for type '%s' in module '%s'\n", name, module);
962                 return XMLDOC_STRICT ? -1 : 0;
963         }
964
965         if (!(matchinfo = ast_xml_new_child(syntax, "matchInfo"))) {
966                 ast_log(LOG_WARNING, "Could not create matchInfo node for type '%s' in module '%s'\n", name, module);
967                 return XMLDOC_STRICT ? -1 : 0;
968         }
969
970         if (!(tmp = ast_xml_new_child(matchinfo, "category"))) {
971                 ast_log(LOG_WARNING, "Could not create category node for type '%s' in module '%s'\n", name, module);
972                 return XMLDOC_STRICT ? -1 : 0;
973         }
974
975         ast_xml_set_text(tmp, category);
976         ast_xml_set_attribute(tmp, "match", matches ? "true" : "false");
977
978         if (!ast_strlen_zero(matchfield) && !(tmp = ast_xml_new_child(matchinfo, "field"))) {
979                 ast_log(LOG_WARNING, "Could not add %s attribute for type '%s' in module '%s'\n", matchfield, name, module);
980                 return XMLDOC_STRICT ? -1 : 0;
981         }
982
983         ast_xml_set_attribute(tmp, "name", matchfield);
984         ast_xml_set_text(tmp, matchvalue);
985
986         if (!config_info || !(config_type = find_xmldoc_type(config_info, name))) {
987                 ast_log(LOG_WARNING, "Could not obtain XML documentation item for config type %s\n", name);
988                 return XMLDOC_STRICT ? -1 : 0;
989         }
990
991         if (ast_xmldoc_regenerate_doc_item(config_type)) {
992                 ast_log(LOG_WARNING, "Could not update type '%s' with values from config type registration\n", name);
993                 return XMLDOC_STRICT ? -1 : 0;
994         }
995
996         return 0;
997 }
998
999 /*! \internal
1000  * \brief Update the XML documentation for a config option based on its registration
1001  */
1002 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)
1003 {
1004         RAII_VAR(struct ast_xml_xpath_results *, results, NULL, ast_xml_xpath_results_free);
1005         RAII_VAR(struct ast_xml_doc_item *, config_info, ao2_find(xmldocs, module, OBJ_KEY), ao2_cleanup);
1006         struct ast_xml_doc_item * config_option;
1007         struct ast_xml_node *option;
1008
1009         ast_assert(ARRAY_LEN(aco_option_type_string) > type);
1010
1011         if (!config_info || !(config_option = find_xmldoc_option(config_info, types, name))) {
1012                 ast_log(LOG_ERROR, "XML Documentation for option '%s' in modules '%s' not found!\n", name, module);
1013                 return XMLDOC_STRICT ? -1 : 0;
1014         }
1015
1016         if (!(results = ast_xmldoc_query("//configInfo[@name='%s']/*/configObject[@name='%s']/configOption[@name='%s']", module, object_name, name))) {
1017                 ast_log(LOG_WARNING, "Could not find option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1018                 return XMLDOC_STRICT ? -1 : 0;
1019         }
1020
1021         if (!(option = ast_xml_xpath_get_first_result(results))) {
1022                 ast_log(LOG_WARNING, "Could obtain results for option '%s' with type '%s' in module '%s'\n", name, object_name, module);
1023                 return XMLDOC_STRICT ? -1 : 0;
1024         }
1025         ast_xml_set_attribute(option, "regex", regex ? "true" : "false");
1026         ast_xml_set_attribute(option, "default", default_value);
1027         ast_xml_set_attribute(option, "type", aco_option_type_string[type]);
1028
1029         if (ast_xmldoc_regenerate_doc_item(config_option)) {
1030                 ast_log(LOG_WARNING, "Could not update option '%s' with values from config option registration\n", name);
1031                 return XMLDOC_STRICT ? -1 : 0;
1032         }
1033
1034         return 0;
1035 }
1036
1037 /*! \internal
1038  * \brief Show the modules with configuration information
1039  */
1040 static void cli_show_modules(struct ast_cli_args *a)
1041 {
1042         struct ast_xml_doc_item *item;
1043         struct ao2_iterator it_items;
1044
1045         ast_assert(a->argc == 3);
1046
1047         if (ao2_container_count(xmldocs) == 0) {
1048                 ast_cli(a->fd, "No modules found.\n");
1049                 return;
1050         }
1051
1052         it_items = ao2_iterator_init(xmldocs, 0);
1053         ast_cli(a->fd, "The following modules have configuration information:\n");
1054         while ((item = ao2_iterator_next(&it_items))) {
1055                 ast_cli(a->fd, "\t%s\n", item->name);
1056                 ao2_ref(item, -1);
1057         }
1058         ao2_iterator_destroy(&it_items);
1059 }
1060
1061 /*! \internal
1062  * \brief Show the configuration types for a module
1063  */
1064 static void cli_show_module_types(struct ast_cli_args *a)
1065 {
1066         RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
1067         struct ast_xml_doc_item *tmp;
1068
1069         ast_assert(a->argc == 4);
1070
1071         if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1072                 ast_cli(a->fd, "Module %s not found.\n", a->argv[3]);
1073                 return;
1074         }
1075
1076         if (ast_str_strlen(item->synopsis)) {
1077                 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->synopsis), 1));
1078         }
1079         if (ast_str_strlen(item->description)) {
1080                 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(item->description), 1));
1081         }
1082
1083         tmp = item;
1084         ast_cli(a->fd, "Configuration option types for %s:\n", tmp->name);
1085         while ((tmp = tmp->next)) {
1086                 if (!strcasecmp(tmp->type, "configObject")) {
1087                         ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1088                                 ast_str_buffer(tmp->synopsis));
1089                 }
1090         }
1091 }
1092
1093 /*! \internal
1094  * \brief Show the information for a configuration type
1095  */
1096 static void cli_show_module_type(struct ast_cli_args *a)
1097 {
1098         RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
1099         struct ast_xml_doc_item *tmp;
1100         char option_type[64];
1101         int match = 0;
1102
1103         ast_assert(a->argc == 5);
1104
1105         if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1106                 ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1107                 return;
1108         }
1109
1110         tmp = item;
1111         while ((tmp = tmp->next)) {
1112                 if (!strcasecmp(tmp->type, "configObject") && !strcasecmp(tmp->name, a->argv[4])) {
1113                         match = 1;
1114                         term_color(option_type, tmp->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_type));
1115                         ast_cli(a->fd, "%s", option_type);
1116                         if (ast_str_strlen(tmp->syntax)) {
1117                                 ast_cli(a->fd, ": [%s]\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1118                         } else {
1119                                 ast_cli(a->fd, "\n\n");
1120                         }
1121                         if (ast_str_strlen(tmp->synopsis)) {
1122                                 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->synopsis), 1));
1123                         }
1124                         if (ast_str_strlen(tmp->description)) {
1125                                 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1126                         }
1127                 }
1128         }
1129
1130         if (!match) {
1131                 ast_cli(a->fd, "Unknown configuration type %s\n", a->argv[4]);
1132                 return;
1133         }
1134
1135         /* Now iterate over the options for the type */
1136         tmp = item;
1137         while ((tmp = tmp->next)) {
1138                 if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4])) {
1139                         ast_cli(a->fd, "%-25s -- %-65.65s\n", tmp->name,
1140                                         ast_str_buffer(tmp->synopsis));
1141                 }
1142         }
1143 }
1144
1145 /*! \internal
1146  * \brief Show detailed information for an option
1147  */
1148 static void cli_show_module_options(struct ast_cli_args *a)
1149 {
1150         RAII_VAR(struct ast_xml_doc_item *, item, NULL, ao2_cleanup);
1151         struct ast_xml_doc_item *tmp;
1152         char option_name[64];
1153         int match = 0;
1154
1155         ast_assert(a->argc == 6);
1156
1157         if (!(item = ao2_find(xmldocs, a->argv[3], OBJ_KEY))) {
1158                 ast_cli(a->fd, "Unknown module %s\n", a->argv[3]);
1159                 return;
1160         }
1161         tmp = item;
1162         while ((tmp = tmp->next)) {
1163                 if (!strcasecmp(tmp->type, "configOption") && !strcasecmp(tmp->ref, a->argv[4]) && !strcasecmp(tmp->name, a->argv[5])) {
1164                         if (match) {
1165                                 ast_cli(a->fd, "\n");
1166                         }
1167                         term_color(option_name, tmp->ref, COLOR_MAGENTA, COLOR_BLACK, sizeof(option_name));
1168                         ast_cli(a->fd, "[%s%s]\n", option_name, term_end());
1169                         if (ast_str_strlen(tmp->syntax)) {
1170                                 ast_cli(a->fd, "%s\n", ast_xmldoc_printable(ast_str_buffer(tmp->syntax), 1));
1171                         }
1172                         ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(AS_OR(tmp->synopsis, "No information available"), 1));
1173                         if (ast_str_strlen(tmp->description)) {
1174                                 ast_cli(a->fd, "%s\n\n", ast_xmldoc_printable(ast_str_buffer(tmp->description), 1));
1175                         }
1176
1177                         match = 1;
1178                 }
1179         }
1180
1181         if (!match) {
1182                 ast_cli(a->fd, "No option %s found for %s:%s\n", a->argv[5], a->argv[3], a->argv[4]);
1183         }
1184 }
1185
1186 static char *cli_show_help(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1187 {
1188         switch (cmd) {
1189         case CLI_INIT:
1190                 e->command = "config show help";
1191                 e->usage =
1192                         "Usage: config show help [<module> [<type> [<option>]]]\n"
1193                         "   Display detailed information about module configuration.\n"
1194                         "     * If nothing is specified, the modules that have\n"
1195                         "       configuration information are listed.\n"
1196                         "     * If <module> is specified, the configuration types\n"
1197                         "       for that module will be listed, along with brief\n"
1198                         "       information about that type.\n"
1199                         "     * If <module> and <type> are specified, detailed\n"
1200                         "       information about the type is displayed, as well\n"
1201                         "       as the available options.\n"
1202                         "     * If <module>, <type>, and <option> are specified,\n"
1203                         "       detailed information will be displayed about that\n"
1204                         "       option.\n"
1205                         "   NOTE: the help documentation is partially generated at run\n"
1206                         "     time when a module is loaded. If a module is not loaded,\n"
1207                         "     configuration help for that module may be incomplete.\n";
1208                 return NULL;
1209         case CLI_GENERATE:
1210                 switch(a->pos) {
1211                 case 3: return complete_config_module(a->word, a->pos, a->n);
1212                 case 4: return complete_config_type(a->argv[3], a->word, a->pos, a->n);
1213                 case 5: return complete_config_option(a->argv[3], a->argv[4], a->word, a->pos, a->n);
1214                 default: return NULL;
1215                 }
1216         }
1217
1218         switch (a->argc) {
1219         case 3:
1220                 cli_show_modules(a);
1221                 break;
1222         case 4:
1223                 cli_show_module_types(a);
1224                 break;
1225         case 5:
1226                 cli_show_module_type(a);
1227                 break;
1228         case 6:
1229                 cli_show_module_options(a);
1230                 break;
1231         default:
1232                 return CLI_SHOWUSAGE;
1233         }
1234
1235         return CLI_SUCCESS;
1236 }
1237
1238 static struct ast_cli_entry cli_aco[] = {
1239         AST_CLI_DEFINE(cli_show_help, "Show configuration help for a module"),
1240 };
1241
1242 static void aco_deinit(void)
1243 {
1244         ast_cli_unregister(cli_aco);
1245         ao2_cleanup(xmldocs);
1246 }
1247 #endif /* AST_XML_DOCS */
1248
1249 int aco_init(void)
1250 {
1251 #ifdef AST_XML_DOCS
1252         ast_register_atexit(aco_deinit);
1253         if (!(xmldocs = ast_xmldoc_build_documentation("configInfo"))) {
1254                 ast_log(LOG_ERROR, "Couldn't build config documentation\n");
1255                 return -1;
1256         }
1257         ast_cli_register_multiple(cli_aco, ARRAY_LEN(cli_aco));
1258 #endif /* AST_XML_DOCS */
1259         return 0;
1260 }
1261
1262 /* Default config option handlers */
1263
1264 /*! \brief Default option handler for signed integers
1265  * \note For a description of the opt->flags and opt->args values, see the documentation for
1266  * enum aco_option_type in config_options.h
1267  */
1268 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1269         int *field = (int *)(obj + opt->args[0]);
1270         unsigned int flags = PARSE_INT32 | opt->flags;
1271         int res = 0;
1272         if (opt->flags & PARSE_IN_RANGE) {
1273                 res = opt->flags & PARSE_DEFAULT ?
1274                         ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
1275                         ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
1276                 if (res) {
1277                         if (opt->flags & PARSE_RANGE_DEFAULTS) {
1278                                 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]);
1279                                 res = 0;
1280                         } else if (opt->flags & PARSE_DEFAULT) {
1281                                 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1282                                 res = 0;
1283                         }
1284                 }
1285         } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
1286                 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
1287         } else {
1288                 res = ast_parse_arg(var->value, flags, field);
1289         }
1290
1291         return res;
1292 }
1293
1294 /*! \brief Default option handler for unsigned integers
1295  * \note For a description of the opt->flags and opt->args values, see the documentation for
1296  * enum aco_option_type in config_options.h
1297  */
1298 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1299         unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1300         unsigned int flags = PARSE_INT32 | opt->flags;
1301         int res = 0;
1302         if (opt->flags & PARSE_IN_RANGE) {
1303                 res = opt->flags & PARSE_DEFAULT ?
1304                         ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
1305                         ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
1306                 if (res) {
1307                         if (opt->flags & PARSE_RANGE_DEFAULTS) {
1308                                 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]);
1309                                 res = 0;
1310                         } else if (opt->flags & PARSE_DEFAULT) {
1311                                 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
1312                                 res = 0;
1313                         }
1314                 }
1315         } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
1316                 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
1317         } else {
1318                 res = ast_parse_arg(var->value, flags, field);
1319         }
1320
1321         return res;
1322 }
1323
1324 /*! \brief Default option handler for doubles
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 double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1329         double *field = (double *)(obj + opt->args[0]);
1330         return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
1331 }
1332
1333 /*! \brief Default handler for ACLs
1334  * \note For a description of the opt->flags and opt->args values, see the documentation for
1335  * enum aco_option_type in config_options.h
1336  */
1337 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1338         struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
1339         int error = 0;
1340         *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
1341         return error;
1342 }
1343
1344 /*! \brief Default option handler for codec preferences/capabilities
1345  * \note For a description of the opt->flags and opt->args values, see the documentation for
1346  * enum aco_option_type in config_options.h
1347  */
1348 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
1349         struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + opt->args[0]);
1350         struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[1]);
1351         return ast_parse_allow_disallow(pref, *cap, var->value, opt->flags);
1352 }
1353
1354 /*! \brief Default option handler for stringfields
1355  * \note For a description of the opt->flags and opt->args values, see the documentation for
1356  * enum aco_option_type in config_options.h
1357  */
1358 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1359 {
1360         ast_string_field *field = (const char **)(obj + opt->args[0]);
1361         struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
1362         struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
1363
1364         if (opt->flags && ast_strlen_zero(var->value)) {
1365                 return -1;
1366         }
1367         ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
1368         return 0;
1369 }
1370
1371 /*! \brief Default option handler for bools (ast_true/ast_false)
1372  * \note For a description of the opt->flags and opt->args values, see the documentation for
1373  * enum aco_option_type in config_options.h
1374  */
1375 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1376 {
1377         unsigned int *field = (unsigned int *)(obj + opt->args[0]);
1378         *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
1379         return 0;
1380 }
1381
1382 /*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
1383  * \note For a description of the opt->flags and opt->args values, see the documentation for
1384  * enum aco_option_type in config_options.h
1385  */
1386 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1387 {
1388         unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
1389         unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
1390         unsigned int flag = opt->args[1];
1391         if (val) {
1392                 *flags_field |= flag;
1393         } else {
1394                 *flags_field &= ~flag;
1395         }
1396         return 0;
1397 }
1398
1399 /*! \brief Default handler for ast_sockaddrs
1400  * \note For a description of the opt->flags and opt->args values, see the documentation for
1401  * enum aco_option_type in config_options.h
1402  */
1403 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1404 {
1405         struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
1406         return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
1407 }
1408
1409 /*! \brief Default handler for doing nothing
1410  */
1411 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1412 {
1413         return 0;
1414 }
1415
1416 /*! \brief Default handler for character arrays
1417  * \note For a description of the opt->flags and opt->args values, see the documentation for
1418  * enum aco_option_type in config_options.h
1419  */
1420 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
1421 {
1422         char *field = (char *)(obj + opt->args[0]);
1423         size_t len = opt->args[1];
1424
1425         if (opt->flags && ast_strlen_zero(var->value)) {
1426                 return -1;
1427         }
1428         ast_copy_string(field, var->value, len);
1429         return 0;
1430 }