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