Convert app_confbridge to use the config options framework
[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/config.h"
35 #include "asterisk/config_options.h"
36 #include "asterisk/stringfields.h"
37 #include "asterisk/acl.h"
38 #include "asterisk/frame.h"
39
40 #ifdef LOW_MEMORY
41 #define CONFIG_OPT_BUCKETS 5
42 #else
43 #define CONFIG_OPT_BUCKETS 53
44 #endif /* LOW_MEMORY */
45
46 /*! \brief Bits of aco_info that shouldn't be assigned outside this file
47  * \internal
48  */
49 struct aco_info_internal {
50         void *pending;              /*!< The user-defined config object awaiting application */
51 };
52
53 struct aco_type_internal {
54         regex_t *regex;
55         struct ao2_container *opts; /*!< The container of options registered to the aco_info */
56 };
57
58 struct aco_option {
59         const char *name;
60         const char *aliased_to;
61         const char *default_val;
62         enum aco_matchtype match_type;
63         regex_t *name_regex;
64         struct aco_type **obj;
65         enum aco_option_type type;
66         aco_option_handler handler;
67         unsigned int flags;
68         unsigned char deprecated:1;
69         size_t argc;
70         intptr_t args[0];
71 };
72
73 void *aco_pending_config(struct aco_info *info)
74 {
75         if (!(info && info->internal)) {
76                 ast_log(LOG_ERROR, "This may not be called without an initialized aco_info!\n");
77                 return NULL;
78         }
79         return info->internal->pending;
80 }
81
82 static void config_option_destroy(void *obj)
83 {
84         struct aco_option *opt = obj;
85         if (opt->match_type == ACO_REGEX && opt->name_regex) {
86                 regfree(opt->name_regex);
87                 ast_free(opt->name_regex);
88         }
89 }
90
91 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
92 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
93 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
94 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
95 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
96 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
97 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
98 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
99 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
100 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
101 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
102
103 static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
104 {
105         switch(type) {
106         case OPT_ACL_T: return acl_handler_fn;
107         case OPT_BOOL_T: return bool_handler_fn;
108         case OPT_BOOLFLAG_T: return boolflag_handler_fn;
109         case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
110         case OPT_CODEC_T: return codec_handler_fn;
111         case OPT_DOUBLE_T: return double_handler_fn;
112         case OPT_INT_T: return int_handler_fn;
113         case OPT_NOOP_T: return noop_handler_fn;
114         case OPT_SOCKADDR_T: return sockaddr_handler_fn;
115         case OPT_STRINGFIELD_T: return stringfield_handler_fn;
116         case OPT_UINT_T: return uint_handler_fn;
117
118         case OPT_CUSTOM_T: return NULL;
119         }
120
121         return NULL;
122 }
123
124 static regex_t *build_regex(const char *text)
125 {
126         int res;
127         regex_t *regex;
128
129         if (!(regex = ast_malloc(sizeof(*regex)))) {
130                 return NULL;
131         }
132
133         if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
134                 size_t len = regerror(res, regex, NULL, 0);
135                 char buf[len];
136                 regerror(res, regex, buf, len);
137                 ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
138                 ast_free(regex);
139                 return NULL;
140         }
141
142         return regex;
143 }
144
145 static int link_option_to_types(struct aco_type **types, struct aco_option *opt)
146 {
147         size_t idx = 0;
148         struct aco_type *type;
149
150         while ((type = types[idx++])) {
151                 if (!ao2_link(type->internal->opts, opt)) {
152                         while (--idx) {
153                                 ao2_unlink(types[idx]->internal->opts, opt);
154                         }
155                         return -1;
156                 }
157         }
158         return 0;
159 }
160
161 int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
162 {
163         struct aco_option *opt;
164
165         if (!info || ast_strlen_zero(name) || ast_strlen_zero(aliased_to)) {
166                 return -1;
167         }
168
169         if (!(opt = ao2_alloc(sizeof(*opt), config_option_destroy))) {
170                 return -1;
171         }
172
173         opt->name = name;
174         opt->aliased_to = aliased_to;
175         opt->deprecated = 1;
176         opt->match_type = ACO_EXACT;
177
178         if (link_option_to_types(types, opt)) {
179                 ao2_ref(opt, -1);
180                 return -1;
181         }
182
183         return 0;
184 }
185
186 int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types,
187         const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags, size_t argc, ...)
188 {
189         struct aco_option *opt;
190         va_list ap;
191         int tmp;
192
193         /* Custom option types require a handler */
194         if (!handler && kind == OPT_CUSTOM_T) {
195                 return -1;
196         }
197
198         if (!(types && types[0])) {
199                 return -1;
200         }
201
202         if (!(opt = ao2_alloc(sizeof(*opt) + argc * sizeof(opt->args[0]), config_option_destroy))) {
203                 return -1;
204         }
205
206         if (matchtype == ACO_REGEX && !(opt->name_regex = build_regex(name))) {
207                 ao2_ref(opt, -1);
208                 return -1;
209         }
210
211         va_start(ap, argc);
212         for (tmp = 0; tmp < argc; tmp++) {
213                 opt->args[tmp] = va_arg(ap, size_t);
214         }
215         va_end(ap);
216
217         opt->name = name;
218         opt->match_type = matchtype;
219         opt->default_val = default_val;
220         opt->type = kind;
221         opt->handler = handler;
222         opt->flags = flags;
223         opt->argc = argc;
224
225         if (!opt->handler && !(opt->handler = ast_config_option_default_handler(opt->type))) {
226                 /* This should never happen */
227                 ast_log(LOG_ERROR, "No handler provided, and no default handler exists for type %d\n", opt->type);
228                 ao2_ref(opt, -1);
229                 return -1;
230         };
231
232         if (link_option_to_types(types, opt)) {
233                 ao2_ref(opt, -1);
234                 return -1;
235         }
236
237         return 0;
238 }
239
240 static int config_opt_hash(const void *obj, const int flags)
241 {
242         const struct aco_option *opt = obj;
243         const char *name = (flags & OBJ_KEY) ? obj : opt->name;
244         return ast_str_case_hash(name);
245 }
246
247 static int config_opt_cmp(void *obj, void *arg, int flags)
248 {
249         struct aco_option *opt1 = obj, *opt2 = arg;
250         const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
251         return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
252 }
253
254 static int find_option_cb(void *obj, void *arg, int flags)
255 {
256         struct aco_option *match = obj;
257         const char *name = arg;
258
259         switch (match->match_type) {
260         case ACO_EXACT:
261                 return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
262         case ACO_REGEX:
263                 return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
264         }
265         ast_log(LOG_ERROR, "Unknown match type. This should not be possible.\n");
266         return CMP_STOP;
267 }
268
269 static struct aco_option *aco_option_find(struct aco_type *type, const char *name)
270 {
271         struct aco_option *opt;
272         /* Try an exact match with OBJ_KEY for the common/fast case, then iterate through
273          * all options for the regex cases */
274         if (!(opt = ao2_callback(type->internal->opts, OBJ_KEY, find_option_cb, (void *) name))) {
275                 opt = ao2_callback(type->internal->opts, 0, find_option_cb, (void *) name);
276         }
277         return opt;
278 }
279
280 struct ao2_container *aco_option_container_alloc(void)
281 {
282         return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
283 }
284
285 static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
286 {
287         size_t x;
288         struct aco_type *match;
289         const char *val;
290
291         for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
292                 /* First make sure we are an object that can service this category */
293                 if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) {
294                         continue;
295                 }
296
297                 /* Then, see if we need to match a particular field */
298                 if (!ast_strlen_zero(match->matchfield) && (!ast_strlen_zero(match->matchvalue) || match->matchfunc)) {
299                         if (!(val = ast_variable_retrieve(cfg, category, match->matchfield))) {
300                                 ast_log(LOG_ERROR, "Required match field '%s' not found\n", match->matchfield);
301                                 return NULL;
302                         }
303                         if (match->matchfunc) {
304                                 if (!match->matchfunc(val)) {
305                                         continue;
306                                 }
307                         } else if (strcasecmp(val, match->matchvalue)) {
308                                 continue;
309                         }
310                 }
311                 /* If we get this far, we're a match */
312                 break;
313         }
314
315         return match;
316 }
317
318 static int is_preload(struct aco_file *file, const char *cat)
319 {
320         int i;
321
322         if (!file->preload) {
323                 return 0;
324         }
325
326         for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
327                 if (!strcasecmp(cat, file->preload[i])) {
328                         return 1;
329                 }
330         }
331         return 0;
332 }
333
334 static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload) {
335         RAII_VAR(void *, new_item, NULL, ao2_cleanup);
336         struct aco_type *type;
337         /* For global types, field is the global option struct. For non-global, it is the container for items.
338          * We do not grab a reference to these objects, as the info already holds references to them. This
339          * pointer is just a convenience. Do not actually store it somewhere. */
340         void **field;
341
342         /* Skip preloaded categories if we aren't preloading */
343         if (!preload && is_preload(file, cat)) {
344                 return 0;
345         }
346
347         /* Find aco_type by category, if not found it is an error */
348         if (!(type = internal_aco_type_find(file, cfg, cat))) {
349                 ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
350                 return -1;
351         }
352
353         field = info->internal->pending + type->item_offset;
354         if (!*field) {
355                 ast_log(LOG_ERROR, "No object to update!\n");
356                 return -1;
357         }
358
359         if (type->type == ACO_GLOBAL && *field) {
360                 if (aco_set_defaults(type, cat, *field)) {
361                         ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
362                         return -1;
363                 }
364                 if (aco_process_category_options(type, cfg, cat, *field)) {
365                         ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
366                         return -1;
367                 }
368         } else if (type->type == ACO_ITEM) {
369                 int new = 0;
370                 /* If we have multiple definitions of a category in a file, or can set the values from multiple
371                  * files, look up the entry if we've already added it so we can merge the values together.
372                  * Otherwise, alloc a new item. */
373                 if (*field) {
374                         if (!(new_item = type->item_find(*field, cat))) {
375                                 if (!(new_item = type->item_alloc(cat))) {
376                                         ast_log(LOG_ERROR, "In %s: Could not create item for %s\n", file->filename, cat);
377                                         return -1;
378                                 }
379                                 if (aco_set_defaults(type, cat, new_item)) {
380                                         ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
381                                         return -1;
382                                 }
383                                 new = 1;
384                         }
385                 }
386
387                 if (type->item_pre_process && type->item_pre_process(new_item)) {
388                         ast_log(LOG_ERROR, "In %s: Preprocess callback for %s failed\n", file->filename, cat);
389                         return -1;
390                 }
391
392                 if (aco_process_category_options(type, cfg, cat, new_item)) {
393                         ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
394                         return -1;
395                 }
396
397                 if (type->item_prelink && type->item_prelink(new_item)) {
398                         ast_log(LOG_ERROR, "In %s: Pre-link callback for %s failed\n", file->filename, cat);
399                         return -1;
400                 }
401
402                 if (new && !ao2_link(*field, new_item)) {
403                         ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", file->filename, cat);
404                         return -1;
405                 }
406         }
407         return 0;
408 }
409
410 static int apply_config(struct aco_info *info)
411 {
412         ao2_global_obj_replace_unref(*info->global_obj, info->internal->pending);
413
414         return 0;
415 }
416
417 static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
418 {
419         const char *cat = NULL;
420
421         if (file->preload) {
422                 int i;
423                 for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
424                         if (process_category(cfg, info, file, file->preload[i], 1)) {
425                                 return ACO_PROCESS_ERROR;
426                         }
427                 }
428         }
429
430         while ((cat = ast_category_browse(cfg, cat))) {
431                 if (process_category(cfg, info, file, cat, 0)) {
432                         return ACO_PROCESS_ERROR;
433                 }
434         }
435         return ACO_PROCESS_OK;
436 }
437
438 enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
439 {
440         if (!(info->internal->pending = info->snapshot_alloc())) {
441                 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", file->filename);
442                 goto error;
443         }
444
445         if (internal_process_ast_config(info, file, cfg)) {
446                 goto error;
447         }
448
449         if (info->pre_apply_config && info->pre_apply_config()) {
450                 goto error;
451         }
452
453         if (apply_config(info)) {
454                 goto error;
455         };
456
457         ao2_cleanup(info->internal->pending);
458         return ACO_PROCESS_OK;
459
460 error:
461         ao2_cleanup(info->internal->pending);
462         return ACO_PROCESS_ERROR;
463 }
464
465 enum aco_process_status aco_process_config(struct aco_info *info, int reload)
466 {
467         struct ast_config *cfg;
468         struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
469         int res = ACO_PROCESS_OK, x = 0;
470         struct aco_file *file;
471
472         if (!(info->files[0])) {
473                 ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
474                 return ACO_PROCESS_ERROR;
475         }
476
477         if (!(info->internal->pending = info->snapshot_alloc())) {
478                 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->module);
479                 return ACO_PROCESS_ERROR;
480         }
481
482         while (res != ACO_PROCESS_ERROR && (file = info->files[x++])) {
483                 const char *filename = file->filename;
484 try_alias:
485                 if (!(cfg = ast_config_load(filename, cfg_flags))) {
486                         if (file->alias && strcmp(file->alias, filename)) {
487                                 filename = file->alias;
488                                 goto try_alias;
489                         }
490                         ast_log(LOG_ERROR, "Unable to load config file '%s'\n", file->filename);
491                         res = ACO_PROCESS_ERROR;
492                         break;
493                 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
494                         ast_debug(1, "%s was unchanged\n", file->filename);
495                         res = ACO_PROCESS_UNCHANGED;
496                         continue;
497                 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
498                         ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", file->filename);
499                         res = ACO_PROCESS_ERROR;
500                         break;
501                 } else if (cfg == CONFIG_STATUS_FILEMISSING) {
502                         if (file->alias && strcmp(file->alias, filename)) {
503                                 filename = file->alias;
504                                 goto try_alias;
505                         }
506                         ast_log(LOG_ERROR, "%s is missing! Cannot load %s\n", file->filename, info->module);
507                         res = ACO_PROCESS_ERROR;
508                         break;
509                 }
510
511                 res = internal_process_ast_config(info, file, cfg);
512                 ast_config_destroy(cfg);
513         }
514
515         if (res != ACO_PROCESS_OK) {
516            goto end;
517         }
518
519         if (info->pre_apply_config && (info->pre_apply_config()))  {
520                 res = ACO_PROCESS_ERROR;
521                 goto end;
522         }
523
524         if (apply_config(info)) {
525                 res = ACO_PROCESS_ERROR;
526                 goto end;
527         }
528
529         if (info->post_apply_config) {
530                 info->post_apply_config();
531         }
532
533 end:
534         ao2_cleanup(info->internal->pending);
535         return res;
536 }
537 int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
538 {
539         RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup);
540         if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) {
541                 const char *alias = ast_strdupa(opt->aliased_to);
542                 ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias);
543                 ao2_ref(opt, -1);
544                 opt = aco_option_find(type, alias);
545         }
546
547         if (!opt) {
548                 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);
549                 return -1;
550         }
551
552         if (!opt->handler) {
553                 /* It should be impossible for an option to not have a handler */
554                 ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name);
555                 return -1;
556         }
557         if (opt->handler(opt, var, obj)) {
558                 ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file);
559                 return -1;
560         }
561
562         return 0;
563 }
564
565 int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
566 {
567         struct ast_variable *var;
568
569         for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
570                 if (aco_process_var(type, cat, var, obj)) {
571                         return -1;
572                 }
573         }
574
575         return 0;
576 }
577
578 static void internal_type_destroy(struct aco_type *type)
579 {
580         if (type->internal->regex) {
581                 regfree(type->internal->regex);
582                 ast_free(type->internal->regex);
583         }
584         ao2_cleanup(type->internal->opts);
585         type->internal->opts = NULL;
586         ast_free(type->internal);
587         type->internal = NULL;
588 }
589
590 static void internal_file_types_destroy(struct aco_file *file)
591 {
592         size_t x;
593         struct aco_type *t;
594
595         for (x = 0, t = file->types[x]; t; t = file->types[++x]) {
596                 internal_type_destroy(t);
597                 t = NULL;
598         }
599 }
600
601 static int internal_type_init(struct aco_type *type)
602 {
603         if (!(type->internal = ast_calloc(1, sizeof(*type->internal)))) {
604                 return -1;
605         }
606
607         if (!(type->internal->regex = build_regex(type->category))) {
608                 internal_type_destroy(type);
609         }
610
611         if (!(type->internal->opts = aco_option_container_alloc())) {
612                 internal_type_destroy(type);
613         }
614
615         return 0;
616 }
617
618 int aco_info_init(struct aco_info *info)
619 {
620         size_t x, y;
621
622         if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
623                 return -1;
624         }
625
626         for (x = 0; info->files[x]; x++) {
627                 for (y = 0; info->files[x]->types[y]; y++) {
628                         if (internal_type_init(info->files[x]->types[y])) {
629                                 goto error;
630                         }
631                 }
632         }
633
634         return 0;
635 error:
636         aco_info_destroy(info);
637         return -1;
638 }
639
640 void aco_info_destroy(struct aco_info *info)
641 {
642         int x;
643         /* It shouldn't be possible for internal->pending to be in use when this is called because
644          * of the locks in loader.c around reloads and unloads and the fact that internal->pending
645          * only exists while those locks are held */
646         ast_free(info->internal);
647         info->internal = NULL;
648
649         for (x = 0; info->files[x]; x++) {
650                 internal_file_types_destroy(info->files[x]);
651         }
652 }
653
654 int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
655 {
656         struct aco_option *opt;
657         struct ao2_iterator iter;
658
659         iter = ao2_iterator_init(type->internal->opts, 0);
660
661         while ((opt = ao2_iterator_next(&iter))) {
662                 RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy);
663
664                 if (ast_strlen_zero(opt->default_val)) {
665                         ao2_ref(opt, -1);
666                         continue;
667                 }
668                 if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
669                         ao2_ref(opt, -1);
670                         ao2_iterator_destroy(&iter);
671                         return -1;
672                 }
673                 if (opt->handler(opt, var, obj)) {
674                         ast_log(LOG_ERROR, "Unable to set default for %s, %s=%s\n", category, var->name, var->value);
675                         ao2_ref(opt, -1);
676                         ao2_iterator_destroy(&iter);
677                         return -1;
678                 }
679                 ao2_ref(opt, -1);
680         }
681         ao2_iterator_destroy(&iter);
682
683         return 0;
684 }
685
686 /* Default config option handlers */
687
688 /*! \brief Default option handler for signed integers
689  * \note For a description of the opt->flags and opt->args values, see the documentation for
690  * enum aco_option_type in config_options.h
691  */
692 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
693         int *field = (int *)(obj + opt->args[0]);
694         unsigned int flags = PARSE_INT32 | opt->flags;
695         int res = 0;
696         if (opt->flags & PARSE_IN_RANGE) {
697                 res = opt->flags & PARSE_DEFAULT ?
698                         ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
699                         ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
700                 if (res) {
701                         if (opt->flags & PARSE_RANGE_DEFAULTS) {
702                                 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]);
703                                 res = 0;
704                         } else if (opt->flags & PARSE_DEFAULT) {
705                                 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
706                                 res = 0;
707                         }
708                 }
709         } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
710                 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
711         } else {
712                 res = ast_parse_arg(var->value, flags, field);
713         }
714
715         return res;
716 }
717
718 /*! \brief Default option handler for unsigned integers
719  * \note For a description of the opt->flags and opt->args values, see the documentation for
720  * enum aco_option_type in config_options.h
721  */
722 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
723         unsigned int *field = (unsigned int *)(obj + opt->args[0]);
724         unsigned int flags = PARSE_INT32 | opt->flags;
725         int res = 0;
726         if (opt->flags & PARSE_IN_RANGE) {
727                 res = opt->flags & PARSE_DEFAULT ?
728                         ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
729                         ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
730                 if (res) {
731                         if (opt->flags & PARSE_RANGE_DEFAULTS) {
732                                 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]);
733                                 res = 0;
734                         } else if (opt->flags & PARSE_DEFAULT) {
735                                 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
736                                 res = 0;
737                         }
738                 }
739         } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
740                 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
741         } else {
742                 res = ast_parse_arg(var->value, flags, field);
743         }
744
745         return res;
746 }
747
748 /*! \brief Default option handler for doubles
749  * \note For a description of the opt->flags and opt->args values, see the documentation for
750  * enum aco_option_type in config_options.h
751  */
752 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
753         double *field = (double *)(obj + opt->args[0]);
754         return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
755 }
756
757 /*! \brief Default handler for ACLs
758  * \note For a description of the opt->flags and opt->args values, see the documentation for
759  * enum aco_option_type in config_options.h
760  */
761 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
762         struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
763         int error = 0;
764         *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
765         return error;
766 }
767
768 /*! \brief Default option handler for codec preferences/capabilities
769  * \note For a description of the opt->flags and opt->args values, see the documentation for
770  * enum aco_option_type in config_options.h
771  */
772 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
773         struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + opt->args[0]);
774         struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[1]);
775         return ast_parse_allow_disallow(pref, *cap, var->value, opt->flags);
776 }
777
778 /*! \brief Default option handler for stringfields
779  * \note For a description of the opt->flags and opt->args values, see the documentation for
780  * enum aco_option_type in config_options.h
781  */
782 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
783 {
784         ast_string_field *field = (const char **)(obj + opt->args[0]);
785         struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
786         struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
787         ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
788         return 0;
789 }
790
791 /*! \brief Default option handler for bools (ast_true/ast_false)
792  * \note For a description of the opt->flags and opt->args values, see the documentation for
793  * enum aco_option_type in config_options.h
794  */
795 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
796 {
797         unsigned int *field = (unsigned int *)(obj + opt->args[0]);
798         *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
799         return 0;
800 }
801
802 /*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
803  * \note For a description of the opt->flags and opt->args values, see the documentation for
804  * enum aco_option_type in config_options.h
805  */
806 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
807 {
808         unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
809         unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
810         unsigned int flag = opt->args[1];
811         if (val) {
812                 *flags_field |= flag;
813         } else {
814                 *flags_field &= ~flag;
815         }
816         return 0;
817 }
818
819 /*! \brief Default handler for ast_sockaddrs
820  * \note For a description of the opt->flags and opt->args values, see the documentation for
821  * enum aco_option_type in config_options.h
822  */
823 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
824 {
825         struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
826         return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
827 }
828
829 /*! \brief Default handler for doing noithing
830  */
831 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
832 {
833         return 0;
834 }
835
836 /*! \brief Default handler for character arrays
837  * \note For a description of the opt->flags and opt->args values, see the documentation for
838  * enum aco_option_type in config_options.h
839  */
840 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
841 {
842         char *field = (char *)(obj + opt->args[0]);
843         size_t len = opt->args[1];
844
845         ast_copy_string(field, var->value, len);
846         return 0;
847 }