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