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
00029 #include "asterisk.h"
00030
00031 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 202754 $")
00032
00033 #include "asterisk/paths.h"
00034 #include "asterisk/network.h"
00035 #include <time.h>
00036 #include <sys/stat.h>
00037
00038 #include <math.h>
00039
00040 #define AST_INCLUDE_GLOB 1
00041
00042 #include "asterisk/config.h"
00043 #include "asterisk/cli.h"
00044 #include "asterisk/lock.h"
00045 #include "asterisk/utils.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/app.h"
00048 #include "asterisk/astobj2.h"
00049 #include "asterisk/strings.h"
00050
00051 #define MAX_NESTED_COMMENTS 128
00052 #define COMMENT_START ";--"
00053 #define COMMENT_END "--;"
00054 #define COMMENT_META ';'
00055 #define COMMENT_TAG '-'
00056
00057 static char *extconfig_conf = "extconfig.conf";
00058
00059
00060
00061 struct ast_comment {
00062 struct ast_comment *next;
00063 char cmt[0];
00064 };
00065
00066
00067 struct cache_file_include {
00068 AST_LIST_ENTRY(cache_file_include) list;
00069 char include[0];
00070 };
00071
00072 struct cache_file_mtime {
00073 AST_LIST_ENTRY(cache_file_mtime) list;
00074 AST_LIST_HEAD(includes, cache_file_include) includes;
00075 unsigned int has_exec:1;
00076 time_t mtime;
00077 char *who_asked;
00078 char filename[0];
00079 };
00080
00081 static AST_LIST_HEAD_STATIC(cfmtime_head, cache_file_mtime);
00082
00083
00084
00085 #define CB_SIZE 250
00086
00087 static void CB_ADD(struct ast_str **cb, const char *str)
00088 {
00089 ast_str_append(cb, 0, "%s", str);
00090 }
00091
00092 static void CB_ADD_LEN(struct ast_str **cb, const char *str, int len)
00093 {
00094 char *s = alloca(len + 1);
00095 ast_copy_string(s, str, len);
00096 ast_str_append(cb, 0, "%s", str);
00097 }
00098
00099 static void CB_RESET(struct ast_str *cb, struct ast_str *llb)
00100 {
00101 if (cb)
00102 cb->used = 0;
00103 if (llb)
00104 llb->used = 0;
00105 }
00106
00107 static struct ast_comment *ALLOC_COMMENT(const struct ast_str *buffer)
00108 {
00109 struct ast_comment *x = NULL;
00110 if (buffer && buffer->used)
00111 x = ast_calloc(1, sizeof(*x) + buffer->used + 1);
00112 if (x)
00113 strcpy(x->cmt, buffer->str);
00114 return x;
00115 }
00116
00117
00118
00119
00120 struct inclfile {
00121 char *fname;
00122 int lineno;
00123 };
00124
00125 static int hash_string(const void *obj, const int flags)
00126 {
00127 char *str = ((struct inclfile*)obj)->fname;
00128 int total;
00129
00130 for (total=0; *str; str++) {
00131 unsigned int tmp = total;
00132 total <<= 1;
00133 total += tmp;
00134 total <<= 2;
00135 total += tmp;
00136
00137 total += ((unsigned int)(*str));
00138 }
00139 if (total < 0)
00140 total = -total;
00141 return total;
00142 }
00143
00144 static int hashtab_compare_strings(void *a, void *b, int flags)
00145 {
00146 const struct inclfile *ae = a, *be = b;
00147 return !strcmp(ae->fname, be->fname) ? CMP_MATCH : 0;
00148 }
00149
00150 static struct ast_config_map {
00151 struct ast_config_map *next;
00152 char *name;
00153 char *driver;
00154 char *database;
00155 char *table;
00156 char stuff[0];
00157 } *config_maps = NULL;
00158
00159 AST_MUTEX_DEFINE_STATIC(config_lock);
00160 static struct ast_config_engine *config_engine_list;
00161
00162 #define MAX_INCLUDE_LEVEL 10
00163
00164 struct ast_category_template_instance {
00165 char name[80];
00166 const struct ast_category *inst;
00167 AST_LIST_ENTRY(ast_category_template_instance) next;
00168 };
00169
00170 struct ast_category {
00171 char name[80];
00172 int ignored;
00173 int include_level;
00174 char *file;
00175 int lineno;
00176 AST_LIST_HEAD_NOLOCK(template_instance_list, ast_category_template_instance) template_instances;
00177 struct ast_comment *precomments;
00178 struct ast_comment *sameline;
00179 struct ast_comment *trailing;
00180 struct ast_variable *root;
00181 struct ast_variable *last;
00182 struct ast_category *next;
00183 };
00184
00185 struct ast_config {
00186 struct ast_category *root;
00187 struct ast_category *last;
00188 struct ast_category *current;
00189 struct ast_category *last_browse;
00190 int include_level;
00191 int max_include_level;
00192 struct ast_config_include *includes;
00193 };
00194
00195 struct ast_config_include {
00196 char *include_location_file;
00197 int include_location_lineno;
00198 int exec;
00199 char *exec_file;
00200 char *included_file;
00201 int inclusion_count;
00202
00203 int output;
00204 struct ast_config_include *next;
00205 };
00206
00207 struct ast_variable *ast_variable_new(const char *name, const char *value, const char *filename)
00208 {
00209 struct ast_variable *variable;
00210 int name_len = strlen(name) + 1;
00211 int val_len = strlen(value) + 1;
00212 int fn_len = strlen(filename) + 1;
00213
00214 if ((variable = ast_calloc(1, name_len + val_len + fn_len + sizeof(*variable)))) {
00215 char *dst = variable->stuff;
00216 variable->name = strcpy(dst, name);
00217 dst += name_len;
00218 variable->value = strcpy(dst, value);
00219 dst += val_len;
00220 variable->file = strcpy(dst, filename);
00221 }
00222 return variable;
00223 }
00224
00225 struct ast_config_include *ast_include_new(struct ast_config *conf, const char *from_file, const char *included_file, int is_exec, const char *exec_file, int from_lineno, char *real_included_file_name, int real_included_file_name_size)
00226 {
00227
00228
00229
00230
00231 struct ast_config_include *inc;
00232 struct stat statbuf;
00233
00234 inc = ast_include_find(conf, included_file);
00235 if (inc) {
00236 do {
00237 inc->inclusion_count++;
00238 snprintf(real_included_file_name, real_included_file_name_size, "%s~~%d", included_file, inc->inclusion_count);
00239 } while (stat(real_included_file_name, &statbuf) == 0);
00240 ast_log(LOG_WARNING,"'%s', line %d: Same File included more than once! This data will be saved in %s if saved back to disk.\n", from_file, from_lineno, real_included_file_name);
00241 } else
00242 *real_included_file_name = 0;
00243
00244 inc = ast_calloc(1,sizeof(struct ast_config_include));
00245 inc->include_location_file = ast_strdup(from_file);
00246 inc->include_location_lineno = from_lineno;
00247 if (!ast_strlen_zero(real_included_file_name))
00248 inc->included_file = ast_strdup(real_included_file_name);
00249 else
00250 inc->included_file = ast_strdup(included_file);
00251
00252 inc->exec = is_exec;
00253 if (is_exec)
00254 inc->exec_file = ast_strdup(exec_file);
00255
00256
00257 inc->next = conf->includes;
00258 conf->includes = inc;
00259
00260 return inc;
00261 }
00262
00263 void ast_include_rename(struct ast_config *conf, const char *from_file, const char *to_file)
00264 {
00265 struct ast_config_include *incl;
00266 struct ast_category *cat;
00267 struct ast_variable *v;
00268
00269 int from_len = strlen(from_file);
00270 int to_len = strlen(to_file);
00271
00272 if (strcmp(from_file, to_file) == 0)
00273 return;
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284 for (incl = conf->includes; incl; incl=incl->next) {
00285 if (strcmp(incl->include_location_file,from_file) == 0) {
00286 if (from_len >= to_len)
00287 strcpy(incl->include_location_file, to_file);
00288 else {
00289 free(incl->include_location_file);
00290 incl->include_location_file = strdup(to_file);
00291 }
00292 }
00293 }
00294 for (cat = conf->root; cat; cat = cat->next) {
00295 if (strcmp(cat->file,from_file) == 0) {
00296 if (from_len >= to_len)
00297 strcpy(cat->file, to_file);
00298 else {
00299 free(cat->file);
00300 cat->file = strdup(to_file);
00301 }
00302 }
00303 for (v = cat->root; v; v = v->next) {
00304 if (strcmp(v->file,from_file) == 0) {
00305 if (from_len >= to_len)
00306 strcpy(v->file, to_file);
00307 else {
00308 free(v->file);
00309 v->file = strdup(to_file);
00310 }
00311 }
00312 }
00313 }
00314 }
00315
00316 struct ast_config_include *ast_include_find(struct ast_config *conf, const char *included_file)
00317 {
00318 struct ast_config_include *x;
00319 for (x=conf->includes;x;x=x->next) {
00320 if (strcmp(x->included_file,included_file) == 0)
00321 return x;
00322 }
00323 return 0;
00324 }
00325
00326
00327 void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
00328 {
00329 if (!variable)
00330 return;
00331 if (category->last)
00332 category->last->next = variable;
00333 else
00334 category->root = variable;
00335 category->last = variable;
00336 while (category->last->next)
00337 category->last = category->last->next;
00338 }
00339
00340 void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line)
00341 {
00342 struct ast_variable *cur = category->root;
00343 int lineno;
00344 int insertline;
00345
00346 if (!variable || sscanf(line, "%d", &insertline) != 1)
00347 return;
00348 if (!insertline) {
00349 variable->next = category->root;
00350 category->root = variable;
00351 } else {
00352 for (lineno = 1; lineno < insertline; lineno++) {
00353 cur = cur->next;
00354 if (!cur->next)
00355 break;
00356 }
00357 variable->next = cur->next;
00358 cur->next = variable;
00359 }
00360 }
00361
00362 void ast_variables_destroy(struct ast_variable *v)
00363 {
00364 struct ast_variable *vn;
00365
00366 while (v) {
00367 vn = v;
00368 v = v->next;
00369 ast_free(vn);
00370 }
00371 }
00372
00373 struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
00374 {
00375 struct ast_category *cat = NULL;
00376
00377 if (category && config->last_browse && (config->last_browse->name == category))
00378 cat = config->last_browse;
00379 else
00380 cat = ast_category_get(config, category);
00381
00382 return (cat) ? cat->root : NULL;
00383 }
00384
00385 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
00386 {
00387 const char *tmp;
00388 tmp = ast_variable_retrieve(cfg, cat, var);
00389 if (!tmp)
00390 tmp = ast_variable_retrieve(cfg, "general", var);
00391 return tmp;
00392 }
00393
00394
00395 const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
00396 {
00397 struct ast_variable *v;
00398
00399 if (category) {
00400 for (v = ast_variable_browse(config, category); v; v = v->next) {
00401 if (!strcasecmp(variable, v->name))
00402 return v->value;
00403 }
00404 } else {
00405 struct ast_category *cat;
00406
00407 for (cat = config->root; cat; cat = cat->next)
00408 for (v = cat->root; v; v = v->next)
00409 if (!strcasecmp(variable, v->name))
00410 return v->value;
00411 }
00412
00413 return NULL;
00414 }
00415
00416 static struct ast_variable *variable_clone(const struct ast_variable *old)
00417 {
00418 struct ast_variable *new = ast_variable_new(old->name, old->value, old->file);
00419
00420 if (new) {
00421 new->lineno = old->lineno;
00422 new->object = old->object;
00423 new->blanklines = old->blanklines;
00424
00425 }
00426
00427 return new;
00428 }
00429
00430 static void move_variables(struct ast_category *old, struct ast_category *new)
00431 {
00432 struct ast_variable *var = old->root;
00433
00434 old->root = NULL;
00435
00436 ast_variable_append(new, var);
00437 }
00438
00439 struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
00440 {
00441 struct ast_category *category;
00442
00443 if ((category = ast_calloc(1, sizeof(*category))))
00444 ast_copy_string(category->name, name, sizeof(category->name));
00445 category->file = strdup(in_file);
00446 category->lineno = lineno;
00447 return category;
00448 }
00449
00450 static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
00451 {
00452 struct ast_category *cat;
00453
00454
00455 for (cat = config->root; cat; cat = cat->next) {
00456 if (cat->name == category_name && (ignored || !cat->ignored))
00457 return cat;
00458 }
00459
00460 for (cat = config->root; cat; cat = cat->next) {
00461 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
00462 return cat;
00463 }
00464
00465 return NULL;
00466 }
00467
00468 struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
00469 {
00470 return category_get(config, category_name, 0);
00471 }
00472
00473 int ast_category_exist(const struct ast_config *config, const char *category_name)
00474 {
00475 return !!ast_category_get(config, category_name);
00476 }
00477
00478 void ast_category_append(struct ast_config *config, struct ast_category *category)
00479 {
00480 if (config->last)
00481 config->last->next = category;
00482 else
00483 config->root = category;
00484 category->include_level = config->include_level;
00485 config->last = category;
00486 config->current = category;
00487 }
00488
00489 void ast_category_insert(struct ast_config *config, struct ast_category *cat, const char *match)
00490 {
00491 struct ast_category *cur_category;
00492
00493 if (!cat || !match)
00494 return;
00495 if (!strcasecmp(config->root->name, match)) {
00496 cat->next = config->root;
00497 config->root = cat;
00498 return;
00499 }
00500 for (cur_category = config->root; cur_category; cur_category = cur_category->next) {
00501 if (!strcasecmp(cur_category->next->name, match)) {
00502 cat->next = cur_category->next;
00503 cur_category->next = cat;
00504 break;
00505 }
00506 }
00507 }
00508
00509 static void ast_destroy_comments(struct ast_category *cat)
00510 {
00511 struct ast_comment *n, *p;
00512
00513 for (p=cat->precomments; p; p=n) {
00514 n = p->next;
00515 free(p);
00516 }
00517 for (p=cat->sameline; p; p=n) {
00518 n = p->next;
00519 free(p);
00520 }
00521 for (p=cat->trailing; p; p=n) {
00522 n = p->next;
00523 free(p);
00524 }
00525 cat->precomments = NULL;
00526 cat->sameline = NULL;
00527 cat->trailing = NULL;
00528 }
00529
00530 static void ast_destroy_template_list(struct ast_category *cat)
00531 {
00532 struct ast_category_template_instance *x;
00533
00534 while ((x = AST_LIST_REMOVE_HEAD(&cat->template_instances, next)))
00535 free(x);
00536 }
00537
00538 void ast_category_destroy(struct ast_category *cat)
00539 {
00540 ast_variables_destroy(cat->root);
00541 if (cat->file) {
00542 free(cat->file);
00543 cat->file = 0;
00544 }
00545 ast_destroy_comments(cat);
00546 ast_destroy_template_list(cat);
00547 ast_free(cat);
00548 }
00549
00550 static void ast_includes_destroy(struct ast_config_include *incls)
00551 {
00552 struct ast_config_include *incl,*inclnext;
00553
00554 for (incl=incls; incl; incl = inclnext) {
00555 inclnext = incl->next;
00556 if (incl->include_location_file)
00557 free(incl->include_location_file);
00558 if (incl->exec_file)
00559 free(incl->exec_file);
00560 if (incl->included_file)
00561 free(incl->included_file);
00562 free(incl);
00563 }
00564 }
00565
00566 static struct ast_category *next_available_category(struct ast_category *cat)
00567 {
00568 for (; cat && cat->ignored; cat = cat->next);
00569
00570 return cat;
00571 }
00572
00573
00574 struct ast_variable *ast_category_first(struct ast_category *cat)
00575 {
00576 return (cat) ? cat->root : NULL;
00577 }
00578
00579 struct ast_variable *ast_category_root(struct ast_config *config, char *cat)
00580 {
00581 struct ast_category *category = ast_category_get(config, cat);
00582
00583 if (category)
00584 return category->root;
00585 return NULL;
00586 }
00587
00588 char *ast_category_browse(struct ast_config *config, const char *prev)
00589 {
00590 struct ast_category *cat = NULL;
00591
00592 if (prev && config->last_browse && (config->last_browse->name == prev))
00593 cat = config->last_browse->next;
00594 else if (!prev && config->root)
00595 cat = config->root;
00596 else if (prev) {
00597 for (cat = config->root; cat; cat = cat->next) {
00598 if (cat->name == prev) {
00599 cat = cat->next;
00600 break;
00601 }
00602 }
00603 if (!cat) {
00604 for (cat = config->root; cat; cat = cat->next) {
00605 if (!strcasecmp(cat->name, prev)) {
00606 cat = cat->next;
00607 break;
00608 }
00609 }
00610 }
00611 }
00612
00613 if (cat)
00614 cat = next_available_category(cat);
00615
00616 config->last_browse = cat;
00617 return (cat) ? cat->name : NULL;
00618 }
00619
00620 struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
00621 {
00622 struct ast_variable *v;
00623
00624 v = cat->root;
00625 cat->root = NULL;
00626 cat->last = NULL;
00627
00628 return v;
00629 }
00630
00631 void ast_category_rename(struct ast_category *cat, const char *name)
00632 {
00633 ast_copy_string(cat->name, name, sizeof(cat->name));
00634 }
00635
00636 static void inherit_category(struct ast_category *new, const struct ast_category *base)
00637 {
00638 struct ast_variable *var;
00639 struct ast_category_template_instance *x = ast_calloc(1,sizeof(struct ast_category_template_instance));
00640
00641 strcpy(x->name, base->name);
00642 x->inst = base;
00643 AST_LIST_INSERT_TAIL(&new->template_instances, x, next);
00644 for (var = base->root; var; var = var->next)
00645 ast_variable_append(new, variable_clone(var));
00646 }
00647
00648 struct ast_config *ast_config_new(void)
00649 {
00650 struct ast_config *config;
00651
00652 if ((config = ast_calloc(1, sizeof(*config))))
00653 config->max_include_level = MAX_INCLUDE_LEVEL;
00654 return config;
00655 }
00656
00657 int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line)
00658 {
00659 struct ast_variable *cur, *prev=NULL, *curn;
00660 int res = -1;
00661 int lineno = 0;
00662
00663 cur = category->root;
00664 while (cur) {
00665 if (cur->name == variable) {
00666 if (prev) {
00667 prev->next = cur->next;
00668 if (cur == category->last)
00669 category->last = prev;
00670 } else {
00671 category->root = cur->next;
00672 if (cur == category->last)
00673 category->last = NULL;
00674 }
00675 cur->next = NULL;
00676 ast_variables_destroy(cur);
00677 return 0;
00678 }
00679 prev = cur;
00680 cur = cur->next;
00681 }
00682
00683 prev = NULL;
00684 cur = category->root;
00685 while (cur) {
00686 curn = cur->next;
00687 if ((!ast_strlen_zero(line) && lineno == atoi(line)) || (ast_strlen_zero(line) && !strcasecmp(cur->name, variable) && (ast_strlen_zero(match) || !strcasecmp(cur->value, match)))) {
00688 if (prev) {
00689 prev->next = cur->next;
00690 if (cur == category->last)
00691 category->last = prev;
00692 } else {
00693 category->root = cur->next;
00694 if (cur == category->last)
00695 category->last = NULL;
00696 }
00697 cur->next = NULL;
00698 ast_variables_destroy(cur);
00699 res = 0;
00700 } else
00701 prev = cur;
00702
00703 cur = curn;
00704 lineno++;
00705 }
00706 return res;
00707 }
00708
00709 int ast_variable_update(struct ast_category *category, const char *variable,
00710 const char *value, const char *match, unsigned int object)
00711 {
00712 struct ast_variable *cur, *prev=NULL, *newer=NULL;
00713
00714 for (cur = category->root; cur; prev = cur, cur = cur->next) {
00715 if (strcasecmp(cur->name, variable) ||
00716 (!ast_strlen_zero(match) && strcasecmp(cur->value, match)))
00717 continue;
00718
00719 if (!(newer = ast_variable_new(variable, value, cur->file)))
00720 return -1;
00721
00722 newer->next = cur->next;
00723 newer->object = cur->object || object;
00724
00725
00726 newer->lineno = cur->lineno;
00727 newer->blanklines = cur->blanklines;
00728 newer->precomments = cur->precomments; cur->precomments = NULL;
00729 newer->sameline = cur->sameline; cur->sameline = NULL;
00730 newer->trailing = cur->trailing; cur->trailing = NULL;
00731
00732 if (prev)
00733 prev->next = newer;
00734 else
00735 category->root = newer;
00736 if (category->last == cur)
00737 category->last = newer;
00738
00739 cur->next = NULL;
00740 ast_variables_destroy(cur);
00741
00742 return 0;
00743 }
00744
00745 if (prev)
00746 prev->next = newer;
00747 else
00748 category->root = newer;
00749
00750 return 0;
00751 }
00752
00753 int ast_category_delete(struct ast_config *cfg, const char *category)
00754 {
00755 struct ast_category *prev=NULL, *cat;
00756
00757 cat = cfg->root;
00758 while (cat) {
00759 if (cat->name == category) {
00760 if (prev) {
00761 prev->next = cat->next;
00762 if (cat == cfg->last)
00763 cfg->last = prev;
00764 } else {
00765 cfg->root = cat->next;
00766 if (cat == cfg->last)
00767 cfg->last = NULL;
00768 }
00769 ast_category_destroy(cat);
00770 return 0;
00771 }
00772 prev = cat;
00773 cat = cat->next;
00774 }
00775
00776 prev = NULL;
00777 cat = cfg->root;
00778 while (cat) {
00779 if (!strcasecmp(cat->name, category)) {
00780 if (prev) {
00781 prev->next = cat->next;
00782 if (cat == cfg->last)
00783 cfg->last = prev;
00784 } else {
00785 cfg->root = cat->next;
00786 if (cat == cfg->last)
00787 cfg->last = NULL;
00788 }
00789 ast_category_destroy(cat);
00790 return 0;
00791 }
00792 prev = cat;
00793 cat = cat->next;
00794 }
00795 return -1;
00796 }
00797
00798 int ast_category_empty(struct ast_config *cfg, const char *category)
00799 {
00800 struct ast_category *cat;
00801
00802 for (cat = cfg->root; cat; cat = cat->next) {
00803 if (!strcasecmp(cat->name, category))
00804 continue;
00805 ast_variables_destroy(cat->root);
00806 cat->root = NULL;
00807 cat->last = NULL;
00808 return 0;
00809 }
00810
00811 return -1;
00812 }
00813
00814 void ast_config_destroy(struct ast_config *cfg)
00815 {
00816 struct ast_category *cat, *catn;
00817
00818 if (!cfg)
00819 return;
00820
00821 ast_includes_destroy(cfg->includes);
00822
00823 cat = cfg->root;
00824 while (cat) {
00825 catn = cat;
00826 cat = cat->next;
00827 ast_category_destroy(catn);
00828 }
00829 ast_free(cfg);
00830 }
00831
00832 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
00833 {
00834 return cfg->current;
00835 }
00836
00837 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
00838 {
00839
00840 cfg->current = (struct ast_category *) cat;
00841 }
00842
00843 enum config_cache_attribute_enum {
00844 ATTRIBUTE_INCLUDE = 0,
00845 ATTRIBUTE_EXEC = 1,
00846 };
00847
00848 static void config_cache_attribute(const char *configfile, enum config_cache_attribute_enum attrtype, const char *filename, const char *who_asked)
00849 {
00850 struct cache_file_mtime *cfmtime;
00851 struct cache_file_include *cfinclude;
00852 struct stat statbuf = { 0, };
00853
00854
00855 AST_LIST_LOCK(&cfmtime_head);
00856 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
00857 if (!strcmp(cfmtime->filename, configfile) && !strcmp(cfmtime->who_asked, who_asked))
00858 break;
00859 }
00860 if (!cfmtime) {
00861 cfmtime = ast_calloc(1, sizeof(*cfmtime) + strlen(configfile) + 1 + strlen(who_asked) + 1);
00862 if (!cfmtime) {
00863 AST_LIST_UNLOCK(&cfmtime_head);
00864 return;
00865 }
00866 AST_LIST_HEAD_INIT(&cfmtime->includes);
00867 strcpy(cfmtime->filename, configfile);
00868 cfmtime->who_asked = cfmtime->filename + strlen(configfile) + 1;
00869 strcpy(cfmtime->who_asked, who_asked);
00870
00871 AST_LIST_INSERT_TAIL(&cfmtime_head, cfmtime, list);
00872 }
00873
00874 if (!stat(configfile, &statbuf))
00875 cfmtime->mtime = 0;
00876 else
00877 cfmtime->mtime = statbuf.st_mtime;
00878
00879 switch (attrtype) {
00880 case ATTRIBUTE_INCLUDE:
00881 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
00882 if (!strcmp(cfinclude->include, filename)) {
00883 AST_LIST_UNLOCK(&cfmtime_head);
00884 return;
00885 }
00886 }
00887 cfinclude = ast_calloc(1, sizeof(*cfinclude) + strlen(filename) + 1);
00888 if (!cfinclude) {
00889 AST_LIST_UNLOCK(&cfmtime_head);
00890 return;
00891 }
00892 strcpy(cfinclude->include, filename);
00893 AST_LIST_INSERT_TAIL(&cfmtime->includes, cfinclude, list);
00894 break;
00895 case ATTRIBUTE_EXEC:
00896 cfmtime->has_exec = 1;
00897 break;
00898 }
00899 AST_LIST_UNLOCK(&cfmtime_head);
00900 }
00901
00902
00903
00904
00905
00906
00907
00908
00909 static int process_text_line(struct ast_config *cfg, struct ast_category **cat,
00910 char *buf, int lineno, const char *configfile, struct ast_flags flags,
00911 struct ast_str *comment_buffer,
00912 struct ast_str *lline_buffer,
00913 const char *suggested_include_file,
00914 struct ast_category **last_cat, struct ast_variable **last_var, const char *who_asked)
00915 {
00916 char *c;
00917 char *cur = buf;
00918 struct ast_variable *v;
00919 char cmd[512], exec_file[512];
00920
00921
00922 if (cur[0] == '[') {
00923
00924
00925
00926
00927
00928
00929
00930
00931 struct ast_category *newcat = NULL;
00932 char *catname;
00933
00934 c = strchr(cur, ']');
00935 if (!c) {
00936 ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
00937 return -1;
00938 }
00939 *c++ = '\0';
00940 cur++;
00941 if (*c++ != '(')
00942 c = NULL;
00943 catname = cur;
00944 if (!(*cat = newcat = ast_category_new(catname,
00945 S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile),
00946 lineno))) {
00947 return -1;
00948 }
00949 (*cat)->lineno = lineno;
00950 *last_var = 0;
00951 *last_cat = newcat;
00952
00953
00954 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
00955 newcat->precomments = ALLOC_COMMENT(comment_buffer);
00956 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
00957 newcat->sameline = ALLOC_COMMENT(lline_buffer);
00958 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
00959 CB_RESET(comment_buffer, lline_buffer);
00960
00961
00962 if (c) {
00963 if (!(cur = strchr(c, ')'))) {
00964 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
00965 return -1;
00966 }
00967 *cur = '\0';
00968 while ((cur = strsep(&c, ","))) {
00969 if (!strcasecmp(cur, "!")) {
00970 (*cat)->ignored = 1;
00971 } else if (!strcasecmp(cur, "+")) {
00972 *cat = category_get(cfg, catname, 1);
00973 if (!(*cat)) {
00974 if (newcat)
00975 ast_category_destroy(newcat);
00976 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
00977 return -1;
00978 }
00979 if (newcat) {
00980 move_variables(newcat, *cat);
00981 ast_category_destroy(newcat);
00982 newcat = NULL;
00983 }
00984 } else {
00985 struct ast_category *base;
00986
00987 base = category_get(cfg, cur, 1);
00988 if (!base) {
00989 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
00990 return -1;
00991 }
00992 inherit_category(*cat, base);
00993 }
00994 }
00995 }
00996 if (newcat)
00997 ast_category_append(cfg, *cat);
00998 } else if (cur[0] == '#') {
00999 char *cur2;
01000 char real_inclusion_name[256];
01001 struct ast_config_include *inclu;
01002 int do_include = 0;
01003
01004 cur++;
01005 c = cur;
01006 while (*c && (*c > 32)) c++;
01007 if (*c) {
01008 *c = '\0';
01009
01010 c = ast_skip_blanks(c + 1);
01011 if (!(*c))
01012 c = NULL;
01013 } else
01014 c = NULL;
01015 if (!strcasecmp(cur, "include")) {
01016 do_include = 1;
01017 } else if (!strcasecmp(cur, "exec")) {
01018 if (!ast_opt_exec_includes) {
01019 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
01020 return 0;
01021 }
01022 } else {
01023 ast_log(LOG_WARNING, "Unknown directive '#%s' at line %d of %s\n", cur, lineno, configfile);
01024 return 0;
01025 }
01026
01027 if (c == NULL) {
01028 ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
01029 do_include ? "include" : "exec",
01030 do_include ? "filename" : "/path/to/executable",
01031 lineno,
01032 configfile);
01033 return 0;
01034 }
01035
01036
01037 while ((*c == '<') || (*c == '>') || (*c == '\"')) c++;
01038
01039 cur = c;
01040 cur2 = cur;
01041 while (!ast_strlen_zero(cur)) {
01042 c = cur + strlen(cur) - 1;
01043 if ((*c == '>') || (*c == '<') || (*c == '\"'))
01044 *c = '\0';
01045 else
01046 break;
01047 }
01048
01049
01050 if (!do_include) {
01051 struct timeval tv = ast_tvnow();
01052 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
01053 config_cache_attribute(configfile, ATTRIBUTE_EXEC, NULL, who_asked);
01054 snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d%d.%ld", (int)tv.tv_sec, (int)tv.tv_usec, (long)pthread_self());
01055 snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
01056 ast_safe_system(cmd);
01057 cur = exec_file;
01058 } else {
01059 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
01060 config_cache_attribute(configfile, ATTRIBUTE_INCLUDE, cur, who_asked);
01061 exec_file[0] = '\0';
01062 }
01063
01064
01065 inclu = ast_include_new(cfg, cfg->include_level == 1 ? "" : configfile, cur, !do_include, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
01066
01067 do_include = ast_config_internal_load(cur, cfg, flags, real_inclusion_name, who_asked) ? 1 : 0;
01068 if (!ast_strlen_zero(exec_file))
01069 unlink(exec_file);
01070 if (!do_include) {
01071 ast_log(LOG_ERROR, "The file '%s' was listed as a #include but it does not exist.\n", cur);
01072 return -1;
01073 }
01074
01075
01076 } else {
01077
01078 if (!(*cat)) {
01079 ast_log(LOG_WARNING,
01080 "parse error: No category context for line %d of %s\n", lineno, configfile);
01081 return -1;
01082 }
01083 c = strchr(cur, '=');
01084 if (c) {
01085 int object;
01086 *c = 0;
01087 c++;
01088
01089 if (*c== '>') {
01090 object = 1;
01091 c++;
01092 } else
01093 object = 0;
01094 if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), S_OR(suggested_include_file, cfg->include_level == 1 ? "" : configfile)))) {
01095 v->lineno = lineno;
01096 v->object = object;
01097 *last_cat = 0;
01098 *last_var = v;
01099
01100 v->blanklines = 0;
01101 ast_variable_append(*cat, v);
01102
01103 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
01104 v->precomments = ALLOC_COMMENT(comment_buffer);
01105 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
01106 v->sameline = ALLOC_COMMENT(lline_buffer);
01107 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
01108 CB_RESET(comment_buffer, lline_buffer);
01109
01110 } else {
01111 return -1;
01112 }
01113 } else {
01114 ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
01115 }
01116 }
01117 return 0;
01118 }
01119
01120 static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, struct ast_flags flags, const char *suggested_include_file, const char *who_asked)
01121 {
01122 char fn[256];
01123 #if defined(LOW_MEMORY)
01124 char buf[512];
01125 #else
01126 char buf[8192];
01127 #endif
01128 char *new_buf, *comment_p, *process_buf;
01129 FILE *f;
01130 int lineno=0;
01131 int comment = 0, nest[MAX_NESTED_COMMENTS];
01132 struct ast_category *cat = NULL;
01133 int count = 0;
01134 struct stat statbuf;
01135 struct cache_file_mtime *cfmtime = NULL;
01136 struct cache_file_include *cfinclude;
01137 struct ast_variable *last_var = 0;
01138 struct ast_category *last_cat = 0;
01139
01140 struct ast_str *comment_buffer = NULL;
01141 struct ast_str *lline_buffer = NULL;
01142
01143 if (cfg)
01144 cat = ast_config_get_current_category(cfg);
01145
01146 if (filename[0] == '/') {
01147 ast_copy_string(fn, filename, sizeof(fn));
01148 } else {
01149 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
01150 }
01151
01152 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
01153 comment_buffer = ast_str_create(CB_SIZE);
01154 if (comment_buffer)
01155 lline_buffer = ast_str_create(CB_SIZE);
01156 if (!lline_buffer) {
01157 if (comment_buffer)
01158 ast_free(comment_buffer);
01159 ast_log(LOG_ERROR, "Failed to initialize the comment buffer!\n");
01160 return NULL;
01161 }
01162 }
01163 #ifdef AST_INCLUDE_GLOB
01164 {
01165 int glob_ret;
01166 glob_t globbuf;
01167 globbuf.gl_offs = 0;
01168 glob_ret = glob(fn, MY_GLOB_FLAGS, NULL, &globbuf);
01169 if (glob_ret == GLOB_NOSPACE)
01170 ast_log(LOG_WARNING,
01171 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
01172 else if (glob_ret == GLOB_ABORTED)
01173 ast_log(LOG_WARNING,
01174 "Glob Expansion of pattern '%s' failed: Read error\n", fn);
01175 else {
01176
01177 int i;
01178 for (i=0; i<globbuf.gl_pathc; i++) {
01179 ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
01180 #endif
01181
01182
01183
01184
01185
01186 do {
01187 if (stat(fn, &statbuf))
01188 continue;
01189
01190 if (!S_ISREG(statbuf.st_mode)) {
01191 ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
01192 continue;
01193 }
01194
01195 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE)) {
01196
01197 AST_LIST_LOCK(&cfmtime_head);
01198 AST_LIST_TRAVERSE(&cfmtime_head, cfmtime, list) {
01199 if (!strcmp(cfmtime->filename, fn) && !strcmp(cfmtime->who_asked, who_asked))
01200 break;
01201 }
01202 if (!cfmtime) {
01203 cfmtime = ast_calloc(1, sizeof(*cfmtime) + strlen(fn) + 1 + strlen(who_asked) + 1);
01204 if (!cfmtime)
01205 continue;
01206 AST_LIST_HEAD_INIT(&cfmtime->includes);
01207 strcpy(cfmtime->filename, fn);
01208 cfmtime->who_asked = cfmtime->filename + strlen(fn) + 1;
01209 strcpy(cfmtime->who_asked, who_asked);
01210
01211 AST_LIST_INSERT_TAIL(&cfmtime_head, cfmtime, list);
01212 }
01213 }
01214
01215 if (cfmtime && (!cfmtime->has_exec) && (cfmtime->mtime == statbuf.st_mtime) && ast_test_flag(&flags, CONFIG_FLAG_FILEUNCHANGED)) {
01216
01217 int unchanged = 1;
01218 AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
01219
01220
01221 char fn2[256];
01222 #ifdef AST_INCLUDE_GLOB
01223 int glob_ret;
01224 glob_t globbuf = { .gl_offs = 0 };
01225 glob_ret = glob(cfinclude->include, MY_GLOB_FLAGS, NULL, &globbuf);
01226
01227 if (glob_ret == GLOB_NOSPACE || glob_ret == GLOB_ABORTED)
01228 unchanged = 0;
01229 else {
01230
01231 int j;
01232 for (j = 0; j < globbuf.gl_pathc; j++) {
01233 ast_copy_string(fn2, globbuf.gl_pathv[j], sizeof(fn2));
01234 #else
01235 ast_copy_string(fn2, cfinclude->include);
01236 #endif
01237 if (config_text_file_load(NULL, NULL, fn2, NULL, flags, "", who_asked) == NULL) {
01238
01239 unchanged = 0;
01240
01241 break;
01242 }
01243 #ifdef AST_INCLUDE_GLOB
01244 }
01245 }
01246 #endif
01247 }
01248
01249 if (unchanged) {
01250 AST_LIST_UNLOCK(&cfmtime_head);
01251 return CONFIG_STATUS_FILEUNCHANGED;
01252 }
01253 }
01254 if (!ast_test_flag(&flags, CONFIG_FLAG_NOCACHE))
01255 AST_LIST_UNLOCK(&cfmtime_head);
01256
01257
01258 if (cfg == NULL)
01259 return NULL;
01260
01261 if (cfmtime)
01262 cfmtime->mtime = statbuf.st_mtime;
01263
01264 ast_verb(2, "Parsing '%s': ", fn);
01265 fflush(stdout);
01266 if (!(f = fopen(fn, "r"))) {
01267 ast_debug(1, "No file to parse: %s\n", fn);
01268 ast_verb(2, "Not found (%s)\n", strerror(errno));
01269 continue;
01270 }
01271 count++;
01272
01273 ast_clear_flag(&flags, CONFIG_FLAG_FILEUNCHANGED);
01274 ast_debug(1, "Parsing %s\n", fn);
01275 ast_verb(2, "Found\n");
01276 while (!feof(f)) {
01277 lineno++;
01278 if (fgets(buf, sizeof(buf), f)) {
01279 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && lline_buffer && lline_buffer->used) {
01280 CB_ADD(&comment_buffer, lline_buffer->str);
01281 lline_buffer->used = 0;
01282 }
01283
01284 new_buf = buf;
01285 if (comment)
01286 process_buf = NULL;
01287 else
01288 process_buf = buf;
01289
01290 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used && (ast_strlen_zero(buf) || strlen(buf) == strspn(buf," \t\n\r"))) {
01291
01292 CB_ADD(&comment_buffer, "\n");
01293 continue;
01294 }
01295
01296 while ((comment_p = strchr(new_buf, COMMENT_META))) {
01297 if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
01298
01299 new_buf = comment_p + 1;
01300 } else if (comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
01301
01302 if (comment < MAX_NESTED_COMMENTS) {
01303 *comment_p = '\0';
01304 new_buf = comment_p + 3;
01305 comment++;
01306 nest[comment-1] = lineno;
01307 } else {
01308 ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
01309 }
01310 } else if ((comment_p >= new_buf + 2) &&
01311 (*(comment_p - 1) == COMMENT_TAG) &&
01312 (*(comment_p - 2) == COMMENT_TAG)) {
01313
01314 comment--;
01315 new_buf = comment_p + 1;
01316 if (!comment) {
01317
01318 if (process_buf) {
01319
01320 char *oldptr;
01321 oldptr = process_buf + strlen(process_buf);
01322 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
01323 CB_ADD(&comment_buffer, ";");
01324 CB_ADD_LEN(&comment_buffer, oldptr+1, new_buf-oldptr-1);
01325 }
01326
01327 memmove(oldptr, new_buf, strlen(new_buf) + 1);
01328 new_buf = oldptr;
01329 } else
01330 process_buf = new_buf;
01331 }
01332 } else {
01333 if (!comment) {
01334
01335
01336 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
01337 CB_ADD(&lline_buffer, comment_p);
01338 }
01339 *comment_p = '\0';
01340 new_buf = comment_p;
01341 } else
01342 new_buf = comment_p + 1;
01343 }
01344 }
01345 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment && !process_buf ) {
01346 CB_ADD(&comment_buffer, buf);
01347 }
01348
01349 if (process_buf) {
01350 char *buf = ast_strip(process_buf);
01351 if (!ast_strlen_zero(buf)) {
01352 if (process_text_line(cfg, &cat, buf, lineno, fn, flags, comment_buffer, lline_buffer, suggested_include_file, &last_cat, &last_var, who_asked)) {
01353 cfg = NULL;
01354 break;
01355 }
01356 }
01357 }
01358 }
01359 }
01360
01361 if (last_cat) {
01362 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used ) {
01363 if (lline_buffer && lline_buffer->used) {
01364 CB_ADD(&comment_buffer, lline_buffer->str);
01365 lline_buffer->used = 0;
01366 }
01367 last_cat->trailing = ALLOC_COMMENT(comment_buffer);
01368 }
01369 } else if (last_var) {
01370 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used ) {
01371 if (lline_buffer && lline_buffer->used) {
01372 CB_ADD(&comment_buffer, lline_buffer->str);
01373 lline_buffer->used = 0;
01374 }
01375 last_var->trailing = ALLOC_COMMENT(comment_buffer);
01376 }
01377 } else {
01378 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS) && comment_buffer && comment_buffer->used) {
01379 ast_debug(1, "Nothing to attach comments to, discarded: %s\n", comment_buffer->str);
01380 }
01381 }
01382 if (ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS))
01383 CB_RESET(comment_buffer, lline_buffer);
01384
01385 fclose(f);
01386 } while (0);
01387 if (comment) {
01388 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
01389 }
01390 #ifdef AST_INCLUDE_GLOB
01391 if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED)
01392 break;
01393 }
01394 globfree(&globbuf);
01395 }
01396 }
01397 #endif
01398
01399 if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg->include_level == 1 && ast_test_flag(&flags, CONFIG_FLAG_WITHCOMMENTS)) {
01400 if (comment_buffer)
01401 ast_free(comment_buffer);
01402 if (lline_buffer)
01403 ast_free(lline_buffer);
01404 comment_buffer = NULL;
01405 lline_buffer = NULL;
01406 }
01407
01408 if (count == 0)
01409 return NULL;
01410
01411 return cfg;
01412 }
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435 static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
01436 {
01437 char date[256]="";
01438 time_t t;
01439
01440 time(&t);
01441 ast_copy_string(date, ctime(&t), sizeof(date));
01442
01443 fprintf(f1, ";!\n");
01444 fprintf(f1, ";! Automatically generated configuration file\n");
01445 if (strcmp(configfile, fn))
01446 fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
01447 else
01448 fprintf(f1, ";! Filename: %s\n", configfile);
01449 fprintf(f1, ";! Generator: %s\n", generator);
01450 fprintf(f1, ";! Creation Date: %s", date);
01451 fprintf(f1, ";!\n");
01452 }
01453
01454 static void inclfile_destroy(void *obj)
01455 {
01456 const struct inclfile *o = obj;
01457
01458 if (o->fname)
01459 free(o->fname);
01460 }
01461
01462
01463 static void set_fn(char *fn, int fn_size, const char *file, const char *configfile, struct ao2_container *fileset, struct inclfile **fi)
01464 {
01465 struct inclfile lookup;
01466
01467 if (!file || file[0] == 0) {
01468 if (configfile[0] == '/')
01469 ast_copy_string(fn, configfile, fn_size);
01470 else
01471 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
01472 } else if (file[0] == '/')
01473 ast_copy_string(fn, file, fn_size);
01474 else
01475 snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
01476 lookup.fname = fn;
01477 *fi = ao2_find(fileset, &lookup, OBJ_POINTER);
01478 if (!(*fi)) {
01479
01480 struct inclfile *fx = ao2_alloc(sizeof(struct inclfile), inclfile_destroy);
01481 fx->fname = ast_strdup(fn);
01482 fx->lineno = 1;
01483 *fi = fx;
01484 ao2_link(fileset, fx);
01485 }
01486 }
01487
01488 static int count_linefeeds(char *str)
01489 {
01490 int count = 0;
01491
01492 while (*str) {
01493 if (*str =='\n')
01494 count++;
01495 str++;
01496 }
01497 return count;
01498 }
01499
01500 static int count_linefeeds_in_comments(struct ast_comment *x)
01501 {
01502 int count = 0;
01503
01504 while (x) {
01505 count += count_linefeeds(x->cmt);
01506 x = x->next;
01507 }
01508 return count;
01509 }
01510
01511 static void insert_leading_blank_lines(FILE *fp, struct inclfile *fi, struct ast_comment *precomments, int lineno)
01512 {
01513 int precomment_lines = count_linefeeds_in_comments(precomments);
01514 int i;
01515
01516
01517
01518
01519
01520 if (lineno - precomment_lines - fi->lineno < 0) {
01521 return;
01522 } else if (lineno == 0) {
01523
01524 return;
01525 } else if (lineno - precomment_lines - fi->lineno < 5) {
01526
01527
01528 for (i = fi->lineno; i < lineno - precomment_lines; i++) {
01529 fprintf(fp, "\n");
01530 }
01531 } else {
01532
01533
01534 fprintf(fp, "\n");
01535 }
01536
01537 fi->lineno = lineno + 1;
01538 }
01539
01540 int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
01541 {
01542 FILE *f;
01543 char fn[256];
01544 struct ast_variable *var;
01545 struct ast_category *cat;
01546 struct ast_comment *cmt;
01547 struct ast_config_include *incl;
01548 int blanklines = 0;
01549 struct ao2_container *fileset = ao2_container_alloc(180000, hash_string, hashtab_compare_strings);
01550 struct inclfile *fi = 0;
01551
01552
01553
01554 for (incl=cfg->includes; incl; incl = incl->next)
01555 incl->output = 0;
01556
01557
01558
01559
01560 for (incl=cfg->includes; incl; incl = incl->next)
01561 {
01562 if (!incl->exec) {
01563 FILE *f1;
01564
01565 set_fn(fn, sizeof(fn), incl->included_file, configfile, fileset, &fi);
01566 f1 = fopen(fn,"w");
01567 if (f1) {
01568 gen_header(f1, configfile, fn, generator);
01569 fclose(f1);
01570 } else {
01571 ast_debug(1, "Unable to open for writing: %s\n", fn);
01572 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
01573 }
01574 ao2_ref(fi,-1);
01575 fi = 0;
01576 }
01577 }
01578
01579 set_fn(fn, sizeof(fn), 0, configfile, fileset, &fi);
01580 #ifdef __CYGWIN__
01581 if ((f = fopen(fn, "w+"))) {
01582 #else
01583 if ((f = fopen(fn, "w"))) {
01584 #endif
01585 ast_verb(2, "Saving '%s': ", fn);
01586 gen_header(f, configfile, fn, generator);
01587 cat = cfg->root;
01588 fclose(f);
01589 ao2_ref(fi,-1);
01590
01591
01592
01593
01594
01595 while (cat) {
01596 set_fn(fn, sizeof(fn), cat->file, configfile, fileset, &fi);
01597 f = fopen(fn, "a");
01598 if (!f)
01599 {
01600 ast_debug(1, "Unable to open for writing: %s\n", fn);
01601 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
01602 ao2_ref(fileset, -1);
01603 return -1;
01604 }
01605
01606
01607 for (incl=cfg->includes; incl; incl = incl->next) {
01608 if (strcmp(incl->include_location_file, cat->file) == 0){
01609 if (cat->lineno > incl->include_location_lineno && !incl->output) {
01610 if (incl->exec)
01611 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
01612 else
01613 fprintf(f,"#include \"%s\"\n", incl->included_file);
01614 incl->output = 1;
01615 }
01616 }
01617 }
01618
01619 insert_leading_blank_lines(f, fi, cat->precomments, cat->lineno);
01620
01621 for (cmt = cat->precomments; cmt; cmt=cmt->next) {
01622 char *cmtp = cmt->cmt;
01623 while (*cmtp == ';' && *(cmtp+1) == '!') {
01624 char *cmtp2 = strchr(cmtp+1, '\n');
01625 if (cmtp2)
01626 cmtp = cmtp2+1;
01627 else cmtp = 0;
01628 }
01629 if (cmtp)
01630 fprintf(f,"%s", cmtp);
01631 }
01632 fprintf(f, "[%s]", cat->name);
01633 if (cat->ignored || !AST_LIST_EMPTY(&cat->template_instances)) {
01634 fprintf(f, "(");
01635 if (cat->ignored) {
01636 fprintf(f, "!");
01637 }
01638 if (cat->ignored && !AST_LIST_EMPTY(&cat->template_instances)) {
01639 fprintf(f, ",");
01640 }
01641 if (!AST_LIST_EMPTY(&cat->template_instances)) {
01642 struct ast_category_template_instance *x;
01643 AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
01644 fprintf(f,"%s",x->name);
01645 if (x != AST_LIST_LAST(&cat->template_instances))
01646 fprintf(f,",");
01647 }
01648 }
01649 fprintf(f, ")");
01650 }
01651 for(cmt = cat->sameline; cmt; cmt=cmt->next)
01652 {
01653 fprintf(f,"%s", cmt->cmt);
01654 }
01655 if (!cat->sameline)
01656 fprintf(f,"\n");
01657 for (cmt = cat->trailing; cmt; cmt=cmt->next) {
01658 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
01659 fprintf(f,"%s", cmt->cmt);
01660 }
01661 fclose(f);
01662 ao2_ref(fi,-1);
01663 fi = 0;
01664
01665 var = cat->root;
01666 while (var) {
01667 struct ast_category_template_instance *x;
01668 int found = 0;
01669 AST_LIST_TRAVERSE(&cat->template_instances, x, next) {
01670 struct ast_variable *v;
01671 for (v = x->inst->root; v; v = v->next) {
01672 if (!strcasecmp(var->name, v->name) && !strcmp(var->value, v->value)) {
01673 found = 1;
01674 break;
01675 }
01676 }
01677 if (found)
01678 break;
01679 }
01680 if (found) {
01681 var = var->next;
01682 continue;
01683 }
01684 set_fn(fn, sizeof(fn), var->file, configfile, fileset, &fi);
01685 f = fopen(fn, "a");
01686 if (!f)
01687 {
01688 ast_debug(1, "Unable to open for writing: %s\n", fn);
01689 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
01690 ao2_ref(fi,-1);
01691 fi = 0;
01692 ao2_ref(fileset, -1);
01693 return -1;
01694 }
01695
01696
01697 for (incl=cfg->includes; incl; incl = incl->next) {
01698 if (strcmp(incl->include_location_file, var->file) == 0){
01699 if (var->lineno > incl->include_location_lineno && !incl->output) {
01700 if (incl->exec)
01701 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
01702 else
01703 fprintf(f,"#include \"%s\"\n", incl->included_file);
01704 incl->output = 1;
01705 }
01706 }
01707 }
01708
01709 insert_leading_blank_lines(f, fi, var->precomments, var->lineno);
01710 for (cmt = var->precomments; cmt; cmt=cmt->next) {
01711 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
01712 fprintf(f,"%s", cmt->cmt);
01713 }
01714 if (var->sameline)
01715 fprintf(f, "%s %s %s %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
01716 else
01717 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
01718 for (cmt = var->trailing; cmt; cmt=cmt->next) {
01719 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
01720 fprintf(f,"%s", cmt->cmt);
01721 }
01722 if (var->blanklines) {
01723 blanklines = var->blanklines;
01724 while (blanklines--)
01725 fprintf(f, "\n");
01726 }
01727
01728 fclose(f);
01729 ao2_ref(fi,-1);
01730 fi = 0;
01731
01732 var = var->next;
01733 }
01734 cat = cat->next;
01735 }
01736 if (!option_debug)
01737 ast_verb(2, "Saved\n");
01738 } else {
01739 ast_debug(1, "Unable to open for writing: %s\n", fn);
01740 ast_verb(2, "Unable to write (%s)", strerror(errno));
01741 ao2_ref(fi,-1);
01742 ao2_ref(fileset, -1);
01743 return -1;
01744 }
01745
01746
01747
01748
01749 for (incl=cfg->includes; incl; incl = incl->next) {
01750 if (!incl->output) {
01751
01752 set_fn(fn, sizeof(fn), incl->include_location_file, configfile, fileset, &fi);
01753 f = fopen(fn, "a");
01754 if (!f)
01755 {
01756 ast_debug(1, "Unable to open for writing: %s\n", fn);
01757 ast_verb(2, "Unable to write %s (%s)", fn, strerror(errno));
01758 ao2_ref(fi,-1);
01759 fi = 0;
01760 ao2_ref(fileset, -1);
01761 return -1;
01762 }
01763
01764
01765 if (incl->exec)
01766 fprintf(f,"#exec \"%s\"\n", incl->exec_file);
01767 else
01768 fprintf(f,"#include \"%s\"\n", incl->included_file);
01769 fclose(f);
01770 incl->output = 1;
01771 ao2_ref(fi,-1);
01772 fi = 0;
01773 }
01774 }
01775 ao2_ref(fileset, -1);
01776
01777 return 0;
01778 }
01779
01780 static void clear_config_maps(void)
01781 {
01782 struct ast_config_map *map;
01783
01784 ast_mutex_lock(&config_lock);
01785
01786 while (config_maps) {
01787 map = config_maps;
01788 config_maps = config_maps->next;
01789 ast_free(map);
01790 }
01791
01792 ast_mutex_unlock(&config_lock);
01793 }
01794
01795 static int append_mapping(const char *name, const char *driver, const char *database, const char *table)
01796 {
01797 struct ast_config_map *map;
01798 int length;
01799
01800 length = sizeof(*map);
01801 length += strlen(name) + 1;
01802 length += strlen(driver) + 1;
01803 length += strlen(database) + 1;
01804 if (table)
01805 length += strlen(table) + 1;
01806
01807 if (!(map = ast_calloc(1, length)))
01808 return -1;
01809
01810 map->name = map->stuff;
01811 strcpy(map->name, name);
01812 map->driver = map->name + strlen(map->name) + 1;
01813 strcpy(map->driver, driver);
01814 map->database = map->driver + strlen(map->driver) + 1;
01815 strcpy(map->database, database);
01816 if (table) {
01817 map->table = map->database + strlen(map->database) + 1;
01818 strcpy(map->table, table);
01819 }
01820 map->next = config_maps;
01821
01822 ast_verb(2, "Binding %s to %s/%s/%s\n", map->name, map->driver, map->database, map->table ? map->table : map->name);
01823
01824 config_maps = map;
01825 return 0;
01826 }
01827
01828 int read_config_maps(void)
01829 {
01830 struct ast_config *config, *configtmp;
01831 struct ast_variable *v;
01832 char *driver, *table, *database, *stringp, *tmp;
01833 struct ast_flags flags = { 0 };
01834
01835 clear_config_maps();
01836
01837 configtmp = ast_config_new();
01838 configtmp->max_include_level = 1;
01839 config = ast_config_internal_load(extconfig_conf, configtmp, flags, "", "config.c");
01840 if (!config) {
01841 ast_config_destroy(configtmp);
01842 return 0;
01843 }
01844
01845 for (v = ast_variable_browse(config, "settings"); v; v = v->next) {
01846 char buf[512];
01847 ast_copy_string(buf, v->value, sizeof(buf));
01848 stringp = buf;
01849 driver = strsep(&stringp, ",");
01850
01851 if ((tmp = strchr(stringp, '\"')))
01852 stringp = tmp;
01853
01854
01855 if (*stringp == '"') {
01856 stringp++;
01857 database = strsep(&stringp, "\"");
01858 strsep(&stringp, ",");
01859 } else {
01860
01861 database = strsep(&stringp, ",");
01862 }
01863
01864 table = strsep(&stringp, ",");
01865
01866 if (!strcmp(v->name, extconfig_conf)) {
01867 ast_log(LOG_WARNING, "Cannot bind '%s'!\n", extconfig_conf);
01868 continue;
01869 }
01870
01871 if (!strcmp(v->name, "asterisk.conf")) {
01872 ast_log(LOG_WARNING, "Cannot bind 'asterisk.conf'!\n");
01873 continue;
01874 }
01875
01876 if (!strcmp(v->name, "logger.conf")) {
01877 ast_log(LOG_WARNING, "Cannot bind 'logger.conf'!\n");
01878 continue;
01879 }
01880
01881 if (!driver || !database)
01882 continue;
01883 if (!strcasecmp(v->name, "sipfriends")) {
01884 ast_log(LOG_WARNING, "The 'sipfriends' table is obsolete, update your config to use sipusers and sippeers, though they can point to the same table.\n");
01885 append_mapping("sipusers", driver, database, table ? table : "sipfriends");
01886 append_mapping("sippeers", driver, database, table ? table : "sipfriends");
01887 } else if (!strcasecmp(v->name, "iaxfriends")) {
01888 ast_log(LOG_WARNING, "The 'iaxfriends' table is obsolete, update your config to use iaxusers and iaxpeers, though they can point to the same table.\n");
01889 append_mapping("iaxusers", driver, database, table ? table : "iaxfriends");
01890 append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends");
01891 } else
01892 append_mapping(v->name, driver, database, table);
01893 }
01894
01895 ast_config_destroy(config);
01896 return 0;
01897 }
01898
01899 int ast_config_engine_register(struct ast_config_engine *new)
01900 {
01901 struct ast_config_engine *ptr;
01902
01903 ast_mutex_lock(&config_lock);
01904
01905 if (!config_engine_list) {
01906 config_engine_list = new;
01907 } else {
01908 for (ptr = config_engine_list; ptr->next; ptr=ptr->next);
01909 ptr->next = new;
01910 }
01911
01912 ast_mutex_unlock(&config_lock);
01913 ast_log(LOG_NOTICE,"Registered Config Engine %s\n", new->name);
01914
01915 return 1;
01916 }
01917
01918 int ast_config_engine_deregister(struct ast_config_engine *del)
01919 {
01920 struct ast_config_engine *ptr, *last=NULL;
01921
01922 ast_mutex_lock(&config_lock);
01923
01924 for (ptr = config_engine_list; ptr; ptr=ptr->next) {
01925 if (ptr == del) {
01926 if (last)
01927 last->next = ptr->next;
01928 else
01929 config_engine_list = ptr->next;
01930 break;
01931 }
01932 last = ptr;
01933 }
01934
01935 ast_mutex_unlock(&config_lock);
01936
01937 return 0;
01938 }
01939
01940
01941 static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
01942 {
01943 struct ast_config_engine *eng, *ret = NULL;
01944 struct ast_config_map *map;
01945
01946 ast_mutex_lock(&config_lock);
01947
01948 for (map = config_maps; map; map = map->next) {
01949 if (!strcasecmp(family, map->name)) {
01950 if (database)
01951 ast_copy_string(database, map->database, dbsiz);
01952 if (table)
01953 ast_copy_string(table, map->table ? map->table : family, tabsiz);
01954 break;
01955 }
01956 }
01957
01958
01959 if (map) {
01960 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
01961 if (!strcasecmp(eng->name, map->driver))
01962 ret = eng;
01963 }
01964 }
01965
01966 ast_mutex_unlock(&config_lock);
01967
01968
01969 if (map && !ret)
01970 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
01971
01972 return ret;
01973 }
01974
01975 static struct ast_config_engine text_file_engine = {
01976 .name = "text",
01977 .load_func = config_text_file_load,
01978 };
01979
01980 struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, struct ast_flags flags, const char *suggested_include_file, const char *who_asked)
01981 {
01982 char db[256];
01983 char table[256];
01984 struct ast_config_engine *loader = &text_file_engine;
01985 struct ast_config *result;
01986
01987
01988 if (cfg->max_include_level > 0 && cfg->include_level == cfg->max_include_level + 1) {
01989 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
01990 return NULL;
01991 }
01992
01993 cfg->include_level++;
01994
01995 if (strcmp(filename, extconfig_conf) && strcmp(filename, "asterisk.conf") && config_engine_list) {
01996 struct ast_config_engine *eng;
01997
01998 eng = find_engine(filename, db, sizeof(db), table, sizeof(table));
01999
02000
02001 if (eng && eng->load_func) {
02002 loader = eng;
02003 } else {
02004 eng = find_engine("global", db, sizeof(db), table, sizeof(table));
02005 if (eng && eng->load_func)
02006 loader = eng;
02007 }
02008 }
02009
02010 result = loader->load_func(db, table, filename, cfg, flags, suggested_include_file, who_asked);
02011
02012 if (result && result != CONFIG_STATUS_FILEUNCHANGED)
02013 result->include_level--;
02014 else
02015 cfg->include_level--;
02016
02017 return result;
02018 }
02019
02020 struct ast_config *ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
02021 {
02022 struct ast_config *cfg;
02023 struct ast_config *result;
02024
02025 cfg = ast_config_new();
02026 if (!cfg)
02027 return NULL;
02028
02029 result = ast_config_internal_load(filename, cfg, flags, "", who_asked);
02030 if (!result || result == CONFIG_STATUS_FILEUNCHANGED)
02031 ast_config_destroy(cfg);
02032
02033 return result;
02034 }
02035
02036 static struct ast_variable *ast_load_realtime_helper(const char *family, va_list ap)
02037 {
02038 struct ast_config_engine *eng;
02039 char db[256]="";
02040 char table[256]="";
02041 struct ast_variable *res=NULL;
02042
02043 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
02044 if (eng && eng->realtime_func)
02045 res = eng->realtime_func(db, table, ap);
02046
02047 return res;
02048 }
02049
02050 struct ast_variable *ast_load_realtime_all(const char *family, ...)
02051 {
02052 struct ast_variable *res;
02053 va_list ap;
02054
02055 va_start(ap, family);
02056 res = ast_load_realtime_helper(family, ap);
02057 va_end(ap);
02058
02059 return res;
02060 }
02061
02062 struct ast_variable *ast_load_realtime(const char *family, ...)
02063 {
02064 struct ast_variable *res, *cur, *prev = NULL, *freeme = NULL;
02065 va_list ap;
02066
02067 va_start(ap, family);
02068 res = ast_load_realtime_helper(family, ap);
02069 va_end(ap);
02070
02071
02072 for (cur = res; cur; cur = cur->next) {
02073 if (freeme) {
02074 ast_free(freeme);
02075 freeme = NULL;
02076 }
02077
02078 if (ast_strlen_zero(cur->value)) {
02079 if (prev)
02080 prev->next = cur->next;
02081 else
02082 res = cur->next;
02083 freeme = cur;
02084 } else {
02085 prev = cur;
02086 }
02087 }
02088 return res;
02089 }
02090
02091
02092 int ast_check_realtime(const char *family)
02093 {
02094 struct ast_config_engine *eng;
02095
02096 eng = find_engine(family, NULL, 0, NULL, 0);
02097 if (eng)
02098 return 1;
02099 return 0;
02100 }
02101
02102
02103 int ast_realtime_enabled()
02104 {
02105 return config_maps ? 1 : 0;
02106 }
02107
02108 struct ast_config *ast_load_realtime_multientry(const char *family, ...)
02109 {
02110 struct ast_config_engine *eng;
02111 char db[256]="";
02112 char table[256]="";
02113 struct ast_config *res=NULL;
02114 va_list ap;
02115
02116 va_start(ap, family);
02117 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
02118 if (eng && eng->realtime_multi_func)
02119 res = eng->realtime_multi_func(db, table, ap);
02120 va_end(ap);
02121
02122 return res;
02123 }
02124
02125 int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
02126 {
02127 struct ast_config_engine *eng;
02128 int res = -1;
02129 char db[256]="";
02130 char table[256]="";
02131 va_list ap;
02132
02133 va_start(ap, lookup);
02134 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
02135 if (eng && eng->update_func)
02136 res = eng->update_func(db, table, keyfield, lookup, ap);
02137 va_end(ap);
02138
02139 return res;
02140 }
02141
02142 int ast_store_realtime(const char *family, ...) {
02143 struct ast_config_engine *eng;
02144 int res = -1;
02145 char db[256]="";
02146 char table[256]="";
02147 va_list ap;
02148
02149 va_start(ap, family);
02150 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
02151 if (eng && eng->store_func)
02152 res = eng->store_func(db, table, ap);
02153 va_end(ap);
02154
02155 return res;
02156 }
02157
02158 int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...) {
02159 struct ast_config_engine *eng;
02160 int res = -1;
02161 char db[256]="";
02162 char table[256]="";
02163 va_list ap;
02164
02165 va_start(ap, lookup);
02166 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
02167 if (eng && eng->destroy_func)
02168 res = eng->destroy_func(db, table, keyfield, lookup, ap);
02169 va_end(ap);
02170
02171 return res;
02172 }
02173
02174
02175
02176
02177 int ast_parse_arg(const char *arg, enum ast_parse_flags flags,
02178 void *p_result, ...)
02179 {
02180 va_list ap;
02181 int error = 0;
02182
02183 va_start(ap, p_result);
02184 switch (flags & PARSE_TYPE) {
02185 case PARSE_INT32:
02186 {
02187 int32_t *result = p_result;
02188 int32_t x, def = result ? *result : 0,
02189 high = (int32_t)0x7fffffff,
02190 low = (int32_t)0x80000000;
02191
02192 if (flags & PARSE_DEFAULT)
02193 def = va_arg(ap, int32_t);
02194 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
02195
02196 low = va_arg(ap, int32_t);
02197 high = va_arg(ap, int32_t);
02198 }
02199 x = strtol(arg, NULL, 0);
02200 error = (x < low) || (x > high);
02201 if (flags & PARSE_OUT_RANGE)
02202 error = !error;
02203 if (result)
02204 *result = error ? def : x;
02205 ast_debug(3,
02206 "extract int from [%s] in [%d, %d] gives [%d](%d)\n",
02207 arg, low, high,
02208 result ? *result : x, error);
02209 break;
02210 }
02211
02212 case PARSE_UINT32:
02213 {
02214 uint32_t *result = p_result;
02215 uint32_t x, def = result ? *result : 0,
02216 low = 0, high = (uint32_t)~0;
02217
02218 if (flags & PARSE_DEFAULT)
02219 def = va_arg(ap, uint32_t);
02220 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
02221
02222 low = va_arg(ap, uint32_t);
02223 high = va_arg(ap, uint32_t);
02224 }
02225 x = strtoul(arg, NULL, 0);
02226 error = (x < low) || (x > high);
02227 if (flags & PARSE_OUT_RANGE)
02228 error = !error;
02229 if (result)
02230 *result = error ? def : x;
02231 ast_debug(3,
02232 "extract uint from [%s] in [%u, %u] gives [%u](%d)\n",
02233 arg, low, high,
02234 result ? *result : x, error);
02235 break;
02236 }
02237
02238 case PARSE_DOUBLE:
02239 {
02240 double *result = p_result;
02241 double x, def = result ? *result : 0,
02242 low = -HUGE_VAL, high = HUGE_VAL;
02243
02244
02245 if (flags & PARSE_DEFAULT)
02246 def = va_arg(ap, double);
02247 if (flags & (PARSE_IN_RANGE|PARSE_OUT_RANGE)) {
02248
02249 low = va_arg(ap, double);
02250 high = va_arg(ap, double);
02251 }
02252 x = strtod(arg, NULL);
02253 error = (x < low) || (x > high);
02254 if (flags & PARSE_OUT_RANGE)
02255 error = !error;
02256 if (result)
02257 *result = error ? def : x;
02258 ast_debug(3,
02259 "extract double from [%s] in [%f, %f] gives [%f](%d)\n",
02260 arg, low, high,
02261 result ? *result : x, error);
02262 break;
02263 }
02264 case PARSE_INADDR:
02265 {
02266 char *port, *buf;
02267 struct sockaddr_in _sa_buf;
02268 struct sockaddr_in *sa = p_result ?
02269 (struct sockaddr_in *)p_result : &_sa_buf;
02270
02271 struct sockaddr_in *def = (flags & PARSE_DEFAULT) ?
02272 va_arg(ap, struct sockaddr_in *) : sa;
02273 struct hostent *hp;
02274 struct ast_hostent ahp;
02275
02276 memset(&_sa_buf, '\0', sizeof(_sa_buf));
02277
02278 port = ast_strdupa(arg);
02279 buf = strsep(&port, ":");
02280 sa->sin_family = AF_INET;
02281
02282
02283
02284
02285 flags &= PARSE_PORT_MASK;
02286 if (port) {
02287 if (flags == PARSE_PORT_FORBID) {
02288 error = 1;
02289 sa->sin_port = def->sin_port;
02290 } else if (flags == PARSE_PORT_IGNORE)
02291 sa->sin_port = def->sin_port;
02292 else
02293 sa->sin_port = htons(strtol(port, NULL, 0));
02294 } else {
02295 sa->sin_port = def->sin_port;
02296 if (flags == PARSE_PORT_REQUIRE)
02297 error = 1;
02298 }
02299
02300 hp = ast_gethostbyname(buf, &ahp);
02301 if (hp)
02302 memcpy(&sa->sin_addr, hp->h_addr, sizeof(sa->sin_addr));
02303 else {
02304 error = 1;
02305 sa->sin_addr = def->sin_addr;
02306 }
02307 ast_debug(3,
02308 "extract inaddr from [%s] gives [%s:%d](%d)\n",
02309 arg, ast_inet_ntoa(sa->sin_addr),
02310 ntohs(sa->sin_port), error);
02311 break;
02312 }
02313 }
02314 va_end(ap);
02315 return error;
02316 }
02317
02318 static char *handle_cli_core_show_config_mappings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02319 {
02320 struct ast_config_engine *eng;
02321 struct ast_config_map *map;
02322
02323 switch (cmd) {
02324 case CLI_INIT:
02325 e->command = "core show config mappings";
02326 e->usage =
02327 "Usage: core show config mappings\n"
02328 " Shows the filenames to config engines.\n";
02329 return NULL;
02330 case CLI_GENERATE:
02331 return NULL;
02332 }
02333
02334 ast_mutex_lock(&config_lock);
02335
02336 if (!config_engine_list) {
02337 ast_cli(a->fd, "No config mappings found.\n");
02338 } else {
02339 ast_cli(a->fd, "\n\n");
02340 for (eng = config_engine_list; eng; eng = eng->next) {
02341 ast_cli(a->fd, "\nConfig Engine: %s\n", eng->name);
02342 for (map = config_maps; map; map = map->next) {
02343 if (!strcasecmp(map->driver, eng->name)) {
02344 ast_cli(a->fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
02345 map->table ? map->table : map->name);
02346 }
02347 }
02348 }
02349 ast_cli(a->fd,"\n\n");
02350 }
02351
02352 ast_mutex_unlock(&config_lock);
02353
02354 return CLI_SUCCESS;
02355 }
02356
02357 static struct ast_cli_entry cli_config[] = {
02358 AST_CLI_DEFINE(handle_cli_core_show_config_mappings, "Display config mappings (file names to config engines)"),
02359 };
02360
02361 int register_config_cli()
02362 {
02363 ast_cli_register_multiple(cli_config, sizeof(cli_config) / sizeof(struct ast_cli_entry));
02364 return 0;
02365 }