00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 399564 $")
00031
00032 #include <regex.h>
00033
00034 #include "asterisk/config.h"
00035 #include "asterisk/config_options.h"
00036 #include "asterisk/stringfields.h"
00037 #include "asterisk/acl.h"
00038 #include "asterisk/frame.h"
00039
00040 #ifdef LOW_MEMORY
00041 #define CONFIG_OPT_BUCKETS 5
00042 #else
00043 #define CONFIG_OPT_BUCKETS 53
00044 #endif
00045
00046
00047
00048
00049 struct aco_info_internal {
00050 void *pending;
00051 };
00052
00053 struct aco_type_internal {
00054 regex_t *regex;
00055 struct ao2_container *opts;
00056 };
00057
00058 struct aco_option {
00059 const char *name;
00060 const char *aliased_to;
00061 const char *default_val;
00062 enum aco_matchtype match_type;
00063 regex_t *name_regex;
00064 struct aco_type **obj;
00065 enum aco_option_type type;
00066 aco_option_handler handler;
00067 unsigned int flags;
00068 unsigned char deprecated:1;
00069 size_t argc;
00070 intptr_t args[0];
00071 };
00072
00073 void *aco_pending_config(struct aco_info *info)
00074 {
00075 if (!(info && info->internal)) {
00076 ast_log(LOG_ERROR, "This may not be called without an initialized aco_info!\n");
00077 return NULL;
00078 }
00079 return info->internal->pending;
00080 }
00081
00082 static void config_option_destroy(void *obj)
00083 {
00084 struct aco_option *opt = obj;
00085 if (opt->match_type == ACO_REGEX && opt->name_regex) {
00086 regfree(opt->name_regex);
00087 ast_free(opt->name_regex);
00088 }
00089 }
00090
00091 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00092 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00093 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00094 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00095 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00096 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00097 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00098 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00099 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00100 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00101 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00102
00103 static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
00104 {
00105 switch(type) {
00106 case OPT_ACL_T: return acl_handler_fn;
00107 case OPT_BOOL_T: return bool_handler_fn;
00108 case OPT_BOOLFLAG_T: return boolflag_handler_fn;
00109 case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
00110 case OPT_CODEC_T: return codec_handler_fn;
00111 case OPT_DOUBLE_T: return double_handler_fn;
00112 case OPT_INT_T: return int_handler_fn;
00113 case OPT_NOOP_T: return noop_handler_fn;
00114 case OPT_SOCKADDR_T: return sockaddr_handler_fn;
00115 case OPT_STRINGFIELD_T: return stringfield_handler_fn;
00116 case OPT_UINT_T: return uint_handler_fn;
00117
00118 case OPT_CUSTOM_T: return NULL;
00119 }
00120
00121 return NULL;
00122 }
00123
00124 static regex_t *build_regex(const char *text)
00125 {
00126 int res;
00127 regex_t *regex;
00128
00129 if (!(regex = ast_malloc(sizeof(*regex)))) {
00130 return NULL;
00131 }
00132
00133 if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
00134 size_t len = regerror(res, regex, NULL, 0);
00135 char buf[len];
00136 regerror(res, regex, buf, len);
00137 ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
00138 ast_free(regex);
00139 return NULL;
00140 }
00141
00142 return regex;
00143 }
00144
00145 static int link_option_to_types(struct aco_type **types, struct aco_option *opt)
00146 {
00147 size_t idx = 0;
00148 struct aco_type *type;
00149
00150 while ((type = types[idx++])) {
00151 if (!type->internal) {
00152 ast_log(LOG_ERROR, "Attempting to register option using uninitialized type\n");
00153 return -1;
00154 }
00155 if (!ao2_link(type->internal->opts, opt)) {
00156 do {
00157 ao2_unlink(types[idx]->internal->opts, opt);
00158 } while (--idx);
00159 return -1;
00160 }
00161 }
00162
00163 ao2_ref(opt, -1);
00164
00165 return 0;
00166 }
00167
00168 int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
00169 {
00170 struct aco_option *opt;
00171
00172 if (!info || ast_strlen_zero(name) || ast_strlen_zero(aliased_to)) {
00173 return -1;
00174 }
00175
00176 if (!(opt = ao2_alloc(sizeof(*opt), config_option_destroy))) {
00177 return -1;
00178 }
00179
00180 opt->name = name;
00181 opt->aliased_to = aliased_to;
00182 opt->deprecated = 1;
00183 opt->match_type = ACO_EXACT;
00184
00185 if (link_option_to_types(types, opt)) {
00186 ao2_ref(opt, -1);
00187 return -1;
00188 }
00189
00190 return 0;
00191 }
00192
00193 int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types,
00194 const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags, size_t argc, ...)
00195 {
00196 struct aco_option *opt;
00197 va_list ap;
00198 int tmp;
00199
00200
00201 if (!handler && kind == OPT_CUSTOM_T) {
00202 return -1;
00203 }
00204
00205 if (!(types && types[0])) {
00206 return -1;
00207 }
00208
00209 if (!(opt = ao2_alloc(sizeof(*opt) + argc * sizeof(opt->args[0]), config_option_destroy))) {
00210 return -1;
00211 }
00212
00213 if (matchtype == ACO_REGEX && !(opt->name_regex = build_regex(name))) {
00214 ao2_ref(opt, -1);
00215 return -1;
00216 }
00217
00218 va_start(ap, argc);
00219 for (tmp = 0; tmp < argc; tmp++) {
00220 opt->args[tmp] = va_arg(ap, size_t);
00221 }
00222 va_end(ap);
00223
00224 opt->name = name;
00225 opt->match_type = matchtype;
00226 opt->default_val = default_val;
00227 opt->type = kind;
00228 opt->handler = handler;
00229 opt->flags = flags;
00230 opt->argc = argc;
00231
00232 if (!opt->handler && !(opt->handler = ast_config_option_default_handler(opt->type))) {
00233
00234 ast_log(LOG_ERROR, "No handler provided, and no default handler exists for type %d\n", opt->type);
00235 ao2_ref(opt, -1);
00236 return -1;
00237 };
00238
00239 if (link_option_to_types(types, opt)) {
00240 ao2_ref(opt, -1);
00241 return -1;
00242 }
00243
00244 return 0;
00245 }
00246
00247 static int config_opt_hash(const void *obj, const int flags)
00248 {
00249 const struct aco_option *opt = obj;
00250 const char *name = (flags & OBJ_KEY) ? obj : opt->name;
00251 return ast_str_case_hash(name);
00252 }
00253
00254 static int config_opt_cmp(void *obj, void *arg, int flags)
00255 {
00256 struct aco_option *opt1 = obj, *opt2 = arg;
00257 const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
00258 return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
00259 }
00260
00261 static int find_option_cb(void *obj, void *arg, int flags)
00262 {
00263 struct aco_option *match = obj;
00264 const char *name = arg;
00265
00266 switch (match->match_type) {
00267 case ACO_EXACT:
00268 return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
00269 case ACO_REGEX:
00270 return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
00271 }
00272 ast_log(LOG_ERROR, "Unknown match type. This should not be possible.\n");
00273 return CMP_STOP;
00274 }
00275
00276 static struct aco_option *aco_option_find(struct aco_type *type, const char *name)
00277 {
00278 struct aco_option *opt;
00279
00280 if (!type || !type->internal || !type->internal->opts) {
00281 ast_log(LOG_NOTICE, "Attempting to use NULL or unitialized config type\n");
00282 return NULL;
00283 }
00284
00285
00286
00287 if (!(opt = ao2_callback(type->internal->opts, OBJ_KEY, find_option_cb, (void *) name))) {
00288 opt = ao2_callback(type->internal->opts, 0, find_option_cb, (void *) name);
00289 }
00290 return opt;
00291 }
00292
00293 struct ao2_container *aco_option_container_alloc(void)
00294 {
00295 return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
00296 }
00297
00298 static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
00299 {
00300 size_t x;
00301 struct aco_type *match;
00302 const char *val;
00303
00304 for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
00305
00306 if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) {
00307 continue;
00308 }
00309
00310
00311 if (!ast_strlen_zero(match->matchfield) && (!ast_strlen_zero(match->matchvalue) || match->matchfunc)) {
00312 if (!(val = ast_variable_retrieve(cfg, category, match->matchfield))) {
00313 ast_log(LOG_ERROR, "Required match field '%s' not found\n", match->matchfield);
00314 return NULL;
00315 }
00316 if (match->matchfunc) {
00317 if (!match->matchfunc(val)) {
00318 continue;
00319 }
00320 } else if (strcasecmp(val, match->matchvalue)) {
00321 continue;
00322 }
00323 }
00324
00325 break;
00326 }
00327
00328 return match;
00329 }
00330
00331 static int is_preload(struct aco_file *file, const char *cat)
00332 {
00333 int i;
00334
00335 if (!file->preload) {
00336 return 0;
00337 }
00338
00339 for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
00340 if (!strcasecmp(cat, file->preload[i])) {
00341 return 1;
00342 }
00343 }
00344 return 0;
00345 }
00346
00347 static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload) {
00348 RAII_VAR(void *, new_item, NULL, ao2_cleanup);
00349 struct aco_type *type;
00350
00351
00352
00353 void **field;
00354
00355
00356 if (!preload && is_preload(file, cat)) {
00357 return 0;
00358 }
00359
00360
00361 if (!(type = internal_aco_type_find(file, cfg, cat))) {
00362 ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
00363 return -1;
00364 }
00365
00366 field = info->internal->pending + type->item_offset;
00367 if (!*field) {
00368 ast_log(LOG_ERROR, "No object to update!\n");
00369 return -1;
00370 }
00371
00372 if (type->type == ACO_GLOBAL && *field) {
00373 if (aco_process_category_options(type, cfg, cat, *field)) {
00374 ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
00375 return -1;
00376 }
00377 } else if (type->type == ACO_ITEM) {
00378 int new = 0;
00379
00380
00381
00382 if (*field) {
00383 if (!(new_item = type->item_find(*field, cat))) {
00384 if (!(new_item = type->item_alloc(cat))) {
00385 ast_log(LOG_ERROR, "In %s: Could not create item for %s\n", file->filename, cat);
00386 return -1;
00387 }
00388 if (aco_set_defaults(type, cat, new_item)) {
00389 ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
00390 return -1;
00391 }
00392 new = 1;
00393 }
00394 }
00395
00396 if (type->item_pre_process && type->item_pre_process(new_item)) {
00397 ast_log(LOG_ERROR, "In %s: Preprocess callback for %s failed\n", file->filename, cat);
00398 return -1;
00399 }
00400
00401 if (aco_process_category_options(type, cfg, cat, new_item)) {
00402 ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
00403 return -1;
00404 }
00405
00406 if (type->item_prelink && type->item_prelink(new_item)) {
00407 ast_log(LOG_ERROR, "In %s: Pre-link callback for %s failed\n", file->filename, cat);
00408 return -1;
00409 }
00410
00411 if (new && !ao2_link(*field, new_item)) {
00412 ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", file->filename, cat);
00413 return -1;
00414 }
00415 }
00416 return 0;
00417 }
00418
00419 static int apply_config(struct aco_info *info)
00420 {
00421 ao2_global_obj_replace_unref(*info->global_obj, info->internal->pending);
00422
00423 return 0;
00424 }
00425
00426 static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
00427 {
00428 const char *cat = NULL;
00429
00430 if (file->preload) {
00431 int i;
00432 for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
00433 if (process_category(cfg, info, file, file->preload[i], 1)) {
00434 return ACO_PROCESS_ERROR;
00435 }
00436 }
00437 }
00438
00439 while ((cat = ast_category_browse(cfg, cat))) {
00440 if (process_category(cfg, info, file, cat, 0)) {
00441 return ACO_PROCESS_ERROR;
00442 }
00443 }
00444 return ACO_PROCESS_OK;
00445 }
00446
00447 enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
00448 {
00449 if (!info->internal) {
00450 ast_log(LOG_ERROR, "Attempt to process %s with uninitialized aco_info\n", file->filename);
00451 goto error;
00452 }
00453
00454 if (!(info->internal->pending = info->snapshot_alloc())) {
00455 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", file->filename);
00456 goto error;
00457 }
00458
00459 if (internal_process_ast_config(info, file, cfg)) {
00460 goto error;
00461 }
00462
00463 if (info->pre_apply_config && info->pre_apply_config()) {
00464 goto error;
00465 }
00466
00467 if (apply_config(info)) {
00468 goto error;
00469 };
00470
00471 ao2_cleanup(info->internal->pending);
00472 return ACO_PROCESS_OK;
00473
00474 error:
00475 ao2_cleanup(info->internal->pending);
00476 return ACO_PROCESS_ERROR;
00477 }
00478
00479 enum aco_process_status aco_process_config(struct aco_info *info, int reload)
00480 {
00481 struct ast_config *cfg;
00482 struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
00483 int res = ACO_PROCESS_OK, x = 0;
00484 struct aco_file *file;
00485
00486 if (!(info->files[0])) {
00487 ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
00488 return ACO_PROCESS_ERROR;
00489 }
00490
00491 if (!info->internal) {
00492 ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
00493 return ACO_PROCESS_ERROR;
00494 }
00495
00496 if (!(info->internal->pending = info->snapshot_alloc())) {
00497 ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->module);
00498 return ACO_PROCESS_ERROR;
00499 }
00500
00501 while (res != ACO_PROCESS_ERROR && (file = info->files[x++])) {
00502 const char *filename = file->filename;
00503 struct aco_type *match;
00504 int i;
00505
00506
00507 for (i = 0, match = file->types[i]; match; match = file->types[++i]) {
00508 void **field = info->internal->pending + match->item_offset;
00509
00510 if (match->type != ACO_GLOBAL || !*field) {
00511 continue;
00512 }
00513
00514 if (aco_set_defaults(match, match->category, *field)) {
00515 ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, match->category);
00516 res = ACO_PROCESS_ERROR;
00517 break;
00518 }
00519 }
00520
00521 if (res == ACO_PROCESS_ERROR) {
00522 break;
00523 }
00524
00525 try_alias:
00526 if (!(cfg = ast_config_load(filename, cfg_flags))) {
00527 if (file->alias && strcmp(file->alias, filename)) {
00528 filename = file->alias;
00529 goto try_alias;
00530 }
00531 ast_log(LOG_ERROR, "Unable to load config file '%s'\n", file->filename);
00532 res = ACO_PROCESS_ERROR;
00533 break;
00534 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00535 ast_debug(1, "%s was unchanged\n", file->filename);
00536 res = ACO_PROCESS_UNCHANGED;
00537 continue;
00538 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00539 ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", file->filename);
00540 res = ACO_PROCESS_ERROR;
00541 break;
00542 } else if (cfg == CONFIG_STATUS_FILEMISSING) {
00543 if (file->alias && strcmp(file->alias, filename)) {
00544 filename = file->alias;
00545 goto try_alias;
00546 }
00547 ast_log(LOG_ERROR, "%s is missing! Cannot load %s\n", file->filename, info->module);
00548 res = ACO_PROCESS_ERROR;
00549 break;
00550 }
00551
00552 res = internal_process_ast_config(info, file, cfg);
00553 ast_config_destroy(cfg);
00554 }
00555
00556 if (res != ACO_PROCESS_OK) {
00557 goto end;
00558 }
00559
00560 if (info->pre_apply_config && (info->pre_apply_config())) {
00561 res = ACO_PROCESS_ERROR;
00562 goto end;
00563 }
00564
00565 if (apply_config(info)) {
00566 res = ACO_PROCESS_ERROR;
00567 goto end;
00568 }
00569
00570 if (info->post_apply_config) {
00571 info->post_apply_config();
00572 }
00573
00574 end:
00575 ao2_cleanup(info->internal->pending);
00576 return res;
00577 }
00578 int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
00579 {
00580 RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup);
00581 if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) {
00582 const char *alias = ast_strdupa(opt->aliased_to);
00583 ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias);
00584 ao2_ref(opt, -1);
00585 opt = aco_option_find(type, alias);
00586 }
00587
00588 if (!opt) {
00589 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);
00590 return -1;
00591 }
00592
00593 if (!opt->handler) {
00594
00595 ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name);
00596 return -1;
00597 }
00598 if (opt->handler(opt, var, obj)) {
00599 ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file);
00600 return -1;
00601 }
00602
00603 return 0;
00604 }
00605
00606 int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
00607 {
00608 struct ast_variable *var;
00609
00610 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
00611 if (aco_process_var(type, cat, var, obj)) {
00612 return -1;
00613 }
00614 }
00615
00616 return 0;
00617 }
00618
00619 static void internal_type_destroy(struct aco_type *type)
00620 {
00621
00622
00623
00624 if (!type->internal) {
00625 return;
00626 }
00627
00628 if (type->internal->regex) {
00629 regfree(type->internal->regex);
00630 ast_free(type->internal->regex);
00631 }
00632 ao2_cleanup(type->internal->opts);
00633 type->internal->opts = NULL;
00634 ast_free(type->internal);
00635 type->internal = NULL;
00636 }
00637
00638 static void internal_file_types_destroy(struct aco_file *file)
00639 {
00640 size_t x;
00641 struct aco_type *t;
00642
00643 for (x = 0, t = file->types[x]; t; t = file->types[++x]) {
00644 internal_type_destroy(t);
00645 t = NULL;
00646 }
00647 }
00648
00649 static int internal_type_init(struct aco_type *type)
00650 {
00651 if (!(type->internal = ast_calloc(1, sizeof(*type->internal)))) {
00652 return -1;
00653 }
00654
00655 if (!(type->internal->regex = build_regex(type->category))) {
00656 internal_type_destroy(type);
00657 return -1;
00658 }
00659
00660 if (!(type->internal->opts = aco_option_container_alloc())) {
00661 internal_type_destroy(type);
00662 return -1;
00663 }
00664
00665 return 0;
00666 }
00667
00668 int aco_info_init(struct aco_info *info)
00669 {
00670 size_t x, y;
00671
00672 if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
00673 return -1;
00674 }
00675
00676 for (x = 0; info->files[x]; x++) {
00677 for (y = 0; info->files[x]->types[y]; y++) {
00678 if (internal_type_init(info->files[x]->types[y])) {
00679 goto error;
00680 }
00681 }
00682 }
00683
00684 return 0;
00685 error:
00686 aco_info_destroy(info);
00687 return -1;
00688 }
00689
00690 void aco_info_destroy(struct aco_info *info)
00691 {
00692 int x;
00693
00694
00695
00696 ast_free(info->internal);
00697 info->internal = NULL;
00698
00699 for (x = 0; info->files[x]; x++) {
00700 internal_file_types_destroy(info->files[x]);
00701 }
00702 }
00703
00704 int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
00705 {
00706 struct aco_option *opt;
00707 struct ao2_iterator iter;
00708
00709 iter = ao2_iterator_init(type->internal->opts, 0);
00710
00711 while ((opt = ao2_iterator_next(&iter))) {
00712 RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy);
00713
00714 if (ast_strlen_zero(opt->default_val)) {
00715 ao2_ref(opt, -1);
00716 continue;
00717 }
00718 if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
00719 ao2_ref(opt, -1);
00720 ao2_iterator_destroy(&iter);
00721 return -1;
00722 }
00723 if (opt->handler(opt, var, obj)) {
00724 ast_log(LOG_ERROR, "Unable to set default for %s, %s=%s\n", category, var->name, var->value);
00725 ao2_ref(opt, -1);
00726 ao2_iterator_destroy(&iter);
00727 return -1;
00728 }
00729 ao2_ref(opt, -1);
00730 }
00731 ao2_iterator_destroy(&iter);
00732
00733 return 0;
00734 }
00735
00736
00737
00738
00739
00740
00741
00742 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
00743 int *field = (int *)(obj + opt->args[0]);
00744 unsigned int flags = PARSE_INT32 | opt->flags;
00745 int res = 0;
00746 if (opt->flags & PARSE_IN_RANGE) {
00747 res = opt->flags & PARSE_DEFAULT ?
00748 ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
00749 ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
00750 if (res) {
00751 if (opt->flags & PARSE_RANGE_DEFAULTS) {
00752 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]);
00753 res = 0;
00754 } else if (opt->flags & PARSE_DEFAULT) {
00755 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
00756 res = 0;
00757 }
00758 }
00759 } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
00760 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
00761 } else {
00762 res = ast_parse_arg(var->value, flags, field);
00763 }
00764
00765 return res;
00766 }
00767
00768
00769
00770
00771
00772 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
00773 unsigned int *field = (unsigned int *)(obj + opt->args[0]);
00774 unsigned int flags = PARSE_INT32 | opt->flags;
00775 int res = 0;
00776 if (opt->flags & PARSE_IN_RANGE) {
00777 res = opt->flags & PARSE_DEFAULT ?
00778 ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
00779 ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
00780 if (res) {
00781 if (opt->flags & PARSE_RANGE_DEFAULTS) {
00782 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]);
00783 res = 0;
00784 } else if (opt->flags & PARSE_DEFAULT) {
00785 ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
00786 res = 0;
00787 }
00788 }
00789 } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
00790 ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
00791 } else {
00792 res = ast_parse_arg(var->value, flags, field);
00793 }
00794
00795 return res;
00796 }
00797
00798
00799
00800
00801
00802 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
00803 double *field = (double *)(obj + opt->args[0]);
00804 return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
00805 }
00806
00807
00808
00809
00810
00811 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
00812 struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
00813 int error = 0;
00814 *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
00815 return error;
00816 }
00817
00818
00819
00820
00821
00822 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
00823 struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + opt->args[0]);
00824 struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[1]);
00825 return ast_parse_allow_disallow(pref, *cap, var->value, opt->flags);
00826 }
00827
00828
00829
00830
00831
00832 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00833 {
00834 ast_string_field *field = (const char **)(obj + opt->args[0]);
00835 struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
00836 struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
00837 ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
00838 return 0;
00839 }
00840
00841
00842
00843
00844
00845 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00846 {
00847 unsigned int *field = (unsigned int *)(obj + opt->args[0]);
00848 *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
00849 return 0;
00850 }
00851
00852
00853
00854
00855
00856 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00857 {
00858 unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
00859 unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
00860 unsigned int flag = opt->args[1];
00861 if (val) {
00862 *flags_field |= flag;
00863 } else {
00864 *flags_field &= ~flag;
00865 }
00866 return 0;
00867 }
00868
00869
00870
00871
00872
00873 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00874 {
00875 struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
00876 return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
00877 }
00878
00879
00880
00881 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00882 {
00883 return 0;
00884 }
00885
00886
00887
00888
00889
00890 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00891 {
00892 char *field = (char *)(obj + opt->args[0]);
00893 size_t len = opt->args[1];
00894
00895 ast_copy_string(field, var->value, len);
00896 return 0;
00897 }