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