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