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