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