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 #include <stdio.h>
00028 #include <unistd.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <errno.h>
00032 #include <time.h>
00033 #include <sys/stat.h>
00034 #define AST_INCLUDE_GLOB 1
00035 #ifdef AST_INCLUDE_GLOB
00036 #if defined(__Darwin__) || defined(__CYGWIN__)
00037 #define GLOB_ABORTED GLOB_ABEND
00038 #endif
00039 # include <glob.h>
00040 #endif
00041
00042 #include "asterisk.h"
00043
00044 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 69469 $")
00045
00046 #include "asterisk/config.h"
00047 #include "asterisk/cli.h"
00048 #include "asterisk/lock.h"
00049 #include "asterisk/options.h"
00050 #include "asterisk/logger.h"
00051 #include "asterisk/utils.h"
00052 #include "asterisk/channel.h"
00053 #include "asterisk/app.h"
00054
00055 #define MAX_NESTED_COMMENTS 128
00056 #define COMMENT_START ";--"
00057 #define COMMENT_END "--;"
00058 #define COMMENT_META ';'
00059 #define COMMENT_TAG '-'
00060
00061 static char *extconfig_conf = "extconfig.conf";
00062
00063 static struct ast_config_map {
00064 struct ast_config_map *next;
00065 char *name;
00066 char *driver;
00067 char *database;
00068 char *table;
00069 char stuff[0];
00070 } *config_maps = NULL;
00071
00072 AST_MUTEX_DEFINE_STATIC(config_lock);
00073 static struct ast_config_engine *config_engine_list;
00074
00075 #define MAX_INCLUDE_LEVEL 10
00076
00077 struct ast_comment {
00078 struct ast_comment *next;
00079 char cmt[0];
00080 };
00081
00082 struct ast_category {
00083 char name[80];
00084 int ignored;
00085 struct ast_variable *root;
00086 struct ast_variable *last;
00087 struct ast_category *next;
00088 };
00089
00090 struct ast_config {
00091 struct ast_category *root;
00092 struct ast_category *last;
00093 struct ast_category *current;
00094 struct ast_category *last_browse;
00095 int include_level;
00096 int max_include_level;
00097 };
00098
00099 struct ast_variable *ast_variable_new(const char *name, const char *value)
00100 {
00101 struct ast_variable *variable;
00102
00103 int length = strlen(name) + strlen(value) + 2 + sizeof(struct ast_variable);
00104 variable = malloc(length);
00105 if (variable) {
00106 memset(variable, 0, length);
00107 variable->name = variable->stuff;
00108 variable->value = variable->stuff + strlen(name) + 1;
00109 strcpy(variable->name,name);
00110 strcpy(variable->value,value);
00111 }
00112
00113 return variable;
00114 }
00115
00116 void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
00117 {
00118 if (category->last)
00119 category->last->next = variable;
00120 else
00121 category->root = variable;
00122 category->last = variable;
00123 while (category->last->next)
00124 category->last = category->last->next;
00125 }
00126
00127 void ast_variables_destroy(struct ast_variable *v)
00128 {
00129 struct ast_variable *vn;
00130
00131 while(v) {
00132 vn = v;
00133 v = v->next;
00134 free(vn);
00135 }
00136 }
00137
00138 struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
00139 {
00140 struct ast_category *cat = NULL;
00141
00142 if (category && config->last_browse && (config->last_browse->name == category))
00143 cat = config->last_browse;
00144 else
00145 cat = ast_category_get(config, category);
00146
00147 if (cat)
00148 return cat->root;
00149 else
00150 return NULL;
00151 }
00152
00153 char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
00154 {
00155 struct ast_variable *v;
00156
00157 if (category) {
00158 for (v = ast_variable_browse(config, category); v; v = v->next) {
00159 if (!strcasecmp(variable, v->name))
00160 return v->value;
00161 }
00162 } else {
00163 struct ast_category *cat;
00164
00165 for (cat = config->root; cat; cat = cat->next)
00166 for (v = cat->root; v; v = v->next)
00167 if (!strcasecmp(variable, v->name))
00168 return v->value;
00169 }
00170
00171 return NULL;
00172 }
00173
00174 static struct ast_variable *variable_clone(const struct ast_variable *old)
00175 {
00176 struct ast_variable *new = ast_variable_new(old->name, old->value);
00177
00178 if (new) {
00179 new->lineno = old->lineno;
00180 new->object = old->object;
00181 new->blanklines = old->blanklines;
00182
00183 }
00184
00185 return new;
00186 }
00187
00188 static void move_variables(struct ast_category *old, struct ast_category *new)
00189 {
00190 struct ast_variable *var;
00191 struct ast_variable *next;
00192
00193 next = old->root;
00194 old->root = NULL;
00195 for (var = next; var; var = next) {
00196 next = var->next;
00197 var->next = NULL;
00198 ast_variable_append(new, var);
00199 }
00200 }
00201
00202 struct ast_category *ast_category_new(const char *name)
00203 {
00204 struct ast_category *category;
00205
00206 category = malloc(sizeof(struct ast_category));
00207 if (category) {
00208 memset(category, 0, sizeof(struct ast_category));
00209 ast_copy_string(category->name, name, sizeof(category->name));
00210 }
00211
00212 return category;
00213 }
00214
00215 static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
00216 {
00217 struct ast_category *cat;
00218
00219 for (cat = config->root; cat; cat = cat->next) {
00220 if (cat->name == category_name && (ignored || !cat->ignored))
00221 return cat;
00222 }
00223
00224 for (cat = config->root; cat; cat = cat->next) {
00225 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
00226 return cat;
00227 }
00228
00229 return NULL;
00230 }
00231
00232 struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
00233 {
00234 return category_get(config, category_name, 0);
00235 }
00236
00237 int ast_category_exist(const struct ast_config *config, const char *category_name)
00238 {
00239 return !!ast_category_get(config, category_name);
00240 }
00241
00242 void ast_category_append(struct ast_config *config, struct ast_category *category)
00243 {
00244 if (config->last)
00245 config->last->next = category;
00246 else
00247 config->root = category;
00248 config->last = category;
00249 config->current = category;
00250 }
00251
00252 void ast_category_destroy(struct ast_category *cat)
00253 {
00254 ast_variables_destroy(cat->root);
00255 free(cat);
00256 }
00257
00258 static struct ast_category *next_available_category(struct ast_category *cat)
00259 {
00260 for (; cat && cat->ignored; cat = cat->next);
00261
00262 return cat;
00263 }
00264
00265 char *ast_category_browse(struct ast_config *config, const char *prev)
00266 {
00267 struct ast_category *cat = NULL;
00268
00269 if (prev && config->last_browse && (config->last_browse->name == prev))
00270 cat = config->last_browse->next;
00271 else if (!prev && config->root)
00272 cat = config->root;
00273 else if (prev) {
00274 for (cat = config->root; cat; cat = cat->next) {
00275 if (cat->name == prev) {
00276 cat = cat->next;
00277 break;
00278 }
00279 }
00280 if (!cat) {
00281 for (cat = config->root; cat; cat = cat->next) {
00282 if (!strcasecmp(cat->name, prev)) {
00283 cat = cat->next;
00284 break;
00285 }
00286 }
00287 }
00288 }
00289
00290 if (cat)
00291 cat = next_available_category(cat);
00292
00293 config->last_browse = cat;
00294 if (cat)
00295 return cat->name;
00296 else
00297 return NULL;
00298 }
00299
00300 struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
00301 {
00302 struct ast_variable *v;
00303
00304 v = cat->root;
00305 cat->root = NULL;
00306 cat->last = NULL;
00307
00308 return v;
00309 }
00310
00311 void ast_category_rename(struct ast_category *cat, const char *name)
00312 {
00313 ast_copy_string(cat->name, name, sizeof(cat->name));
00314 }
00315
00316 static void inherit_category(struct ast_category *new, const struct ast_category *base)
00317 {
00318 struct ast_variable *var;
00319
00320 for (var = base->root; var; var = var->next) {
00321 struct ast_variable *v;
00322
00323 v = variable_clone(var);
00324 if (v)
00325 ast_variable_append(new, v);
00326 }
00327 }
00328
00329 struct ast_config *ast_config_new(void)
00330 {
00331 struct ast_config *config;
00332
00333 config = malloc(sizeof(*config));
00334 if (config) {
00335 memset(config, 0, sizeof(*config));
00336 config->max_include_level = MAX_INCLUDE_LEVEL;
00337 }
00338
00339 return config;
00340 }
00341
00342 void ast_config_destroy(struct ast_config *cfg)
00343 {
00344 struct ast_category *cat, *catn;
00345
00346 if (!cfg)
00347 return;
00348
00349 cat = cfg->root;
00350 while(cat) {
00351 ast_variables_destroy(cat->root);
00352 catn = cat;
00353 cat = cat->next;
00354 free(catn);
00355 }
00356 free(cfg);
00357 }
00358
00359 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
00360 {
00361 return cfg->current;
00362 }
00363
00364 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
00365 {
00366
00367 cfg->current = (struct ast_category *) cat;
00368 }
00369
00370 static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile)
00371 {
00372 char *c;
00373 char *cur = buf;
00374 struct ast_variable *v;
00375 char cmd[512], exec_file[512];
00376 int object, do_exec, do_include;
00377
00378
00379 if (cur[0] == '[') {
00380 struct ast_category *newcat = NULL;
00381 char *catname;
00382
00383
00384 c = strchr(cur, ']');
00385 if (!c) {
00386 ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
00387 return -1;
00388 }
00389 *c++ = '\0';
00390 cur++;
00391 if (*c++ != '(')
00392 c = NULL;
00393 catname = cur;
00394 *cat = newcat = ast_category_new(catname);
00395 if (!newcat) {
00396 ast_log(LOG_WARNING, "Out of memory, line %d of %s\n", lineno, configfile);
00397 return -1;
00398 }
00399
00400 if (c) {
00401 if (!(cur = strchr(c, ')'))) {
00402 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
00403 return -1;
00404 }
00405 *cur = '\0';
00406 while ((cur = strsep(&c, ","))) {
00407 if (!strcasecmp(cur, "!")) {
00408 (*cat)->ignored = 1;
00409 } else if (!strcasecmp(cur, "+")) {
00410 *cat = category_get(cfg, catname, 1);
00411 if (!*cat) {
00412 if (newcat)
00413 ast_category_destroy(newcat);
00414 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
00415 return -1;
00416 }
00417 if (newcat) {
00418 move_variables(newcat, *cat);
00419 ast_category_destroy(newcat);
00420 newcat = NULL;
00421 }
00422 } else {
00423 struct ast_category *base;
00424
00425 base = category_get(cfg, cur, 1);
00426 if (!base) {
00427 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
00428 return -1;
00429 }
00430 inherit_category(*cat, base);
00431 }
00432 }
00433 }
00434 if (newcat)
00435 ast_category_append(cfg, *cat);
00436 } else if (cur[0] == '#') {
00437
00438 cur++;
00439 c = cur;
00440 while(*c && (*c > 32)) c++;
00441 if (*c) {
00442 *c = '\0';
00443 c++;
00444
00445 while(*c && (*c < 33)) c++;
00446 if (!*c)
00447 c = NULL;
00448 } else
00449 c = NULL;
00450 do_include = !strcasecmp(cur, "include");
00451 if(!do_include)
00452 do_exec = !strcasecmp(cur, "exec");
00453 else
00454 do_exec = 0;
00455 if (do_exec && !option_exec_includes) {
00456 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
00457 do_exec = 0;
00458 }
00459 if (do_include || do_exec) {
00460 if (c) {
00461
00462 while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
00463
00464 cur = c;
00465 while (!ast_strlen_zero(cur)) {
00466 c = cur + strlen(cur) - 1;
00467 if ((*c == '>') || (*c == '<') || (*c == '\"'))
00468 *c = '\0';
00469 else
00470 break;
00471 }
00472
00473
00474 if (do_exec) {
00475 snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d.%ld", (int)time(NULL), (long)pthread_self());
00476 snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
00477 ast_safe_system(cmd);
00478 cur = exec_file;
00479 } else
00480 exec_file[0] = '\0';
00481
00482 do_include = ast_config_internal_load(cur, cfg) ? 1 : 0;
00483 if(!ast_strlen_zero(exec_file))
00484 unlink(exec_file);
00485 if(!do_include)
00486 return 0;
00487
00488 } else {
00489 ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
00490 do_exec ? "exec" : "include",
00491 do_exec ? "/path/to/executable" : "filename",
00492 lineno,
00493 configfile);
00494 }
00495 }
00496 else
00497 ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
00498 } else {
00499
00500 if (!*cat) {
00501 ast_log(LOG_WARNING,
00502 "parse error: No category context for line %d of %s\n", lineno, configfile);
00503 return -1;
00504 }
00505 c = strchr(cur, '=');
00506 if (c) {
00507 *c = 0;
00508 c++;
00509
00510 if (*c== '>') {
00511 object = 1;
00512 c++;
00513 } else
00514 object = 0;
00515 v = ast_variable_new(ast_strip(cur), ast_strip(c));
00516 if (v) {
00517 v->lineno = lineno;
00518 v->object = object;
00519
00520 v->blanklines = 0;
00521 ast_variable_append(*cat, v);
00522 } else {
00523 ast_log(LOG_WARNING, "Out of memory, line %d\n", lineno);
00524 return -1;
00525 }
00526 } else {
00527 ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
00528 }
00529
00530 }
00531 return 0;
00532 }
00533
00534 static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg)
00535 {
00536 char fn[256];
00537 char buf[8192];
00538 char *new_buf, *comment_p, *process_buf;
00539 FILE *f;
00540 int lineno=0;
00541 int comment = 0, nest[MAX_NESTED_COMMENTS];
00542 struct ast_category *cat = NULL;
00543 int count = 0;
00544 struct stat statbuf;
00545
00546 cat = ast_config_get_current_category(cfg);
00547
00548 if (filename[0] == '/') {
00549 ast_copy_string(fn, filename, sizeof(fn));
00550 } else {
00551 snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, filename);
00552 }
00553
00554 #ifdef AST_INCLUDE_GLOB
00555 {
00556 int glob_ret;
00557 glob_t globbuf;
00558 globbuf.gl_offs = 0;
00559 #ifdef SOLARIS
00560 glob_ret = glob(fn, GLOB_NOCHECK, NULL, &globbuf);
00561 #else
00562 glob_ret = glob(fn, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf);
00563 #endif
00564 if (glob_ret == GLOB_NOSPACE)
00565 ast_log(LOG_WARNING,
00566 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
00567 else if (glob_ret == GLOB_ABORTED)
00568 ast_log(LOG_WARNING,
00569 "Glob Expansion of pattern '%s' failed: Read error\n", fn);
00570 else {
00571
00572 int i;
00573 for (i=0; i<globbuf.gl_pathc; i++) {
00574 ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
00575 #endif
00576 do {
00577 if (stat(fn, &statbuf))
00578 continue;
00579
00580 if (!S_ISREG(statbuf.st_mode)) {
00581 ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
00582 continue;
00583 }
00584 if (option_verbose > 1) {
00585 ast_verbose(VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
00586 fflush(stdout);
00587 }
00588 if (!(f = fopen(fn, "r"))) {
00589 if (option_debug)
00590 ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
00591 if (option_verbose > 1)
00592 ast_verbose( "Not found (%s)\n", strerror(errno));
00593 continue;
00594 }
00595 count++;
00596 if (option_debug)
00597 ast_log(LOG_DEBUG, "Parsing %s\n", fn);
00598 if (option_verbose > 1)
00599 ast_verbose("Found\n");
00600 while(!feof(f)) {
00601 lineno++;
00602 if (fgets(buf, sizeof(buf), f)) {
00603 new_buf = buf;
00604 if (comment)
00605 process_buf = NULL;
00606 else
00607 process_buf = buf;
00608 while ((comment_p = strchr(new_buf, COMMENT_META))) {
00609 if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
00610
00611 memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
00612 new_buf = comment_p;
00613 } else if(comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
00614
00615 if (comment < MAX_NESTED_COMMENTS) {
00616 *comment_p = '\0';
00617 new_buf = comment_p + 3;
00618 comment++;
00619 nest[comment-1] = lineno;
00620 } else {
00621 ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
00622 }
00623 } else if ((comment_p >= new_buf + 2) &&
00624 (*(comment_p - 1) == COMMENT_TAG) &&
00625 (*(comment_p - 2) == COMMENT_TAG)) {
00626
00627 comment--;
00628 new_buf = comment_p + 1;
00629 if (!comment) {
00630
00631 if (process_buf) {
00632
00633 char *oldptr;
00634 oldptr = process_buf + strlen(process_buf);
00635 memmove(oldptr, new_buf, strlen(new_buf) + 1);
00636 new_buf = oldptr;
00637 } else
00638 process_buf = new_buf;
00639 }
00640 } else {
00641 if (!comment) {
00642
00643
00644 *comment_p = '\0';
00645 new_buf = comment_p;
00646 } else
00647 new_buf = comment_p + 1;
00648 }
00649 }
00650 if (process_buf) {
00651 char *buf = ast_strip(process_buf);
00652 if (!ast_strlen_zero(buf)) {
00653 if (process_text_line(cfg, &cat, buf, lineno, fn)) {
00654 cfg = NULL;
00655 break;
00656 }
00657 }
00658 }
00659 }
00660 }
00661 fclose(f);
00662 } while(0);
00663 if (comment) {
00664 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
00665 }
00666 #ifdef AST_INCLUDE_GLOB
00667 if (!cfg)
00668 break;
00669 }
00670 globfree(&globbuf);
00671 }
00672 }
00673 #endif
00674 if (count == 0)
00675 return NULL;
00676
00677 return cfg;
00678 }
00679
00680 int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
00681 {
00682 FILE *f;
00683 char fn[256];
00684 char date[256]="";
00685 time_t t;
00686 struct ast_variable *var;
00687 struct ast_category *cat;
00688 int blanklines = 0;
00689
00690 if (configfile[0] == '/') {
00691 ast_copy_string(fn, configfile, sizeof(fn));
00692 } else {
00693 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
00694 }
00695 time(&t);
00696 ast_copy_string(date, ctime(&t), sizeof(date));
00697 #ifdef __CYGWIN__
00698 if ((f = fopen(fn, "w+"))) {
00699 #else
00700 if ((f = fopen(fn, "w"))) {
00701 #endif
00702 if (option_verbose > 1)
00703 ast_verbose(VERBOSE_PREFIX_2 "Saving '%s': ", fn);
00704 fprintf(f, ";!\n");
00705 fprintf(f, ";! Automatically generated configuration file\n");
00706 if (strcmp(configfile, fn))
00707 fprintf(f, ";! Filename: %s (%s)\n", configfile, fn);
00708 else
00709 fprintf(f, ";! Filename: %s\n", configfile);
00710 fprintf(f, ";! Generator: %s\n", generator);
00711 fprintf(f, ";! Creation Date: %s", date);
00712 fprintf(f, ";!\n");
00713 cat = cfg->root;
00714 while(cat) {
00715
00716 fprintf(f, "[%s]\n", cat->name);
00717 var = cat->root;
00718 while(var) {
00719 if (var->sameline)
00720 fprintf(f, "%s %s %s ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
00721 else
00722 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
00723 if (var->blanklines) {
00724 blanklines = var->blanklines;
00725 while (blanklines--)
00726 fprintf(f, "\n");
00727 }
00728
00729 var = var->next;
00730 }
00731 #if 0
00732
00733 fprintf(f, "\n");
00734 #endif
00735 cat = cat->next;
00736 }
00737 } else {
00738 if (option_debug)
00739 ast_log(LOG_DEBUG, "Unable to open for writing: %s\n", fn);
00740 if (option_verbose > 1)
00741 ast_verbose(VERBOSE_PREFIX_2 "Unable to write (%s)", strerror(errno));
00742 return -1;
00743 }
00744 fclose(f);
00745 return 0;
00746 }
00747
00748 static void clear_config_maps(void)
00749 {
00750 struct ast_config_map *map;
00751
00752 ast_mutex_lock(&config_lock);
00753
00754 while (config_maps) {
00755 map = config_maps;
00756 config_maps = config_maps->next;
00757 free(map);
00758 }
00759
00760 ast_mutex_unlock(&config_lock);
00761 }
00762
00763 static int append_mapping(char *name, char *driver, char *database, char *table)
00764 {
00765 struct ast_config_map *map;
00766 int length;
00767
00768 length = sizeof(*map);
00769 length += strlen(name) + 1;
00770 length += strlen(driver) + 1;
00771 length += strlen(database) + 1;
00772 if (table)
00773 length += strlen(table) + 1;
00774 map = malloc(length);
00775
00776 if (!map)
00777 return -1;
00778
00779 memset(map, 0, length);
00780 map->name = map->stuff;
00781 strcpy(map->name, name);
00782 map->driver = map->name + strlen(map->name) + 1;
00783 strcpy(map->driver, driver);
00784 map->database = map->driver + strlen(map->driver) + 1;
00785 strcpy(map->database, database);
00786 if (table) {
00787 map->table = map->database + strlen(map->database) + 1;
00788 strcpy(map->table, table);
00789 }
00790 map->next = config_maps;
00791
00792 if (option_verbose > 1)
00793 ast_verbose(VERBOSE_PREFIX_2 "Binding %s to %s/%s/%s\n",
00794 map->name, map->driver, map->database, map->table ? map->table : map->name);
00795
00796 config_maps = map;
00797 return 0;
00798 }
00799
00800 void read_config_maps(void)
00801 {
00802 struct ast_config *config, *configtmp;
00803 struct ast_variable *v;
00804 char *driver, *table, *database, *stringp;
00805
00806 clear_config_maps();
00807
00808 configtmp = ast_config_new();
00809 configtmp->max_include_level = 1;
00810 config = ast_config_internal_load(extconfig_conf, configtmp);
00811 if (!config) {
00812 ast_config_destroy(configtmp);
00813 return;
00814 }
00815
00816 for (v = ast_variable_browse(config, "settings"); v; v = v->next) {
00817 stringp = v->value;
00818 driver = strsep(&stringp, ",");
00819 database = strsep(&stringp, ",");
00820 table = strsep(&stringp, ",");
00821
00822 if (!strcmp(v->name, extconfig_conf)) {
00823 ast_log(LOG_WARNING, "Cannot bind '%s'!\n", extconfig_conf);
00824 continue;
00825 }
00826
00827 if (!strcmp(v->name, "asterisk.conf")) {
00828 ast_log(LOG_WARNING, "Cannot bind 'asterisk.conf'!\n");
00829 continue;
00830 }
00831
00832 if (!strcmp(v->name, "logger.conf")) {
00833 ast_log(LOG_WARNING, "Cannot bind 'logger.conf'!\n");
00834 continue;
00835 }
00836
00837 if (!driver || !database)
00838 continue;
00839 if (!strcasecmp(v->name, "sipfriends")) {
00840 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");
00841 append_mapping("sipusers", driver, database, table ? table : "sipfriends");
00842 append_mapping("sippeers", driver, database, table ? table : "sipfriends");
00843 } else if (!strcasecmp(v->name, "iaxfriends")) {
00844 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");
00845 append_mapping("iaxusers", driver, database, table ? table : "iaxfriends");
00846 append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends");
00847 } else
00848 append_mapping(v->name, driver, database, table);
00849 }
00850
00851 ast_config_destroy(config);
00852 }
00853
00854 int ast_config_engine_register(struct ast_config_engine *new)
00855 {
00856 struct ast_config_engine *ptr;
00857
00858 ast_mutex_lock(&config_lock);
00859
00860 if (!config_engine_list) {
00861 config_engine_list = new;
00862 } else {
00863 for (ptr = config_engine_list; ptr->next; ptr=ptr->next);
00864 ptr->next = new;
00865 }
00866
00867 ast_mutex_unlock(&config_lock);
00868 ast_log(LOG_NOTICE,"Registered Config Engine %s\n", new->name);
00869
00870 return 1;
00871 }
00872
00873 int ast_config_engine_deregister(struct ast_config_engine *del)
00874 {
00875 struct ast_config_engine *ptr, *last=NULL;
00876
00877 ast_mutex_lock(&config_lock);
00878
00879 for (ptr = config_engine_list; ptr; ptr=ptr->next) {
00880 if (ptr == del) {
00881 if (last)
00882 last->next = ptr->next;
00883 else
00884 config_engine_list = ptr->next;
00885 break;
00886 }
00887 last = ptr;
00888 }
00889
00890 ast_mutex_unlock(&config_lock);
00891
00892 return 0;
00893 }
00894
00895
00896 static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
00897 {
00898 struct ast_config_engine *eng, *ret = NULL;
00899 struct ast_config_map *map;
00900
00901 ast_mutex_lock(&config_lock);
00902
00903 for (map = config_maps; map; map = map->next) {
00904 if (!strcasecmp(family, map->name)) {
00905 if (database)
00906 ast_copy_string(database, map->database, dbsiz);
00907 if (table)
00908 ast_copy_string(table, map->table ? map->table : family, tabsiz);
00909 break;
00910 }
00911 }
00912
00913
00914 if (map) {
00915 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
00916 if (!strcasecmp(eng->name, map->driver))
00917 ret = eng;
00918 }
00919 }
00920
00921 ast_mutex_unlock(&config_lock);
00922
00923
00924 if (map && !ret)
00925 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
00926
00927 return ret;
00928 }
00929
00930 static struct ast_config_engine text_file_engine = {
00931 .name = "text",
00932 .load_func = config_text_file_load,
00933 };
00934
00935 struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg)
00936 {
00937 char db[256];
00938 char table[256];
00939 struct ast_config_engine *loader = &text_file_engine;
00940 struct ast_config *result;
00941
00942 if (cfg->include_level == cfg->max_include_level) {
00943 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
00944 return NULL;
00945 }
00946
00947 cfg->include_level++;
00948
00949 if (strcmp(filename, extconfig_conf) && strcmp(filename, "asterisk.conf") && config_engine_list) {
00950 struct ast_config_engine *eng;
00951
00952 eng = find_engine(filename, db, sizeof(db), table, sizeof(table));
00953
00954
00955 if (eng && eng->load_func) {
00956 loader = eng;
00957 } else {
00958 eng = find_engine("global", db, sizeof(db), table, sizeof(table));
00959 if (eng && eng->load_func)
00960 loader = eng;
00961 }
00962 }
00963
00964 result = loader->load_func(db, table, filename, cfg);
00965
00966 if (result)
00967 result->include_level--;
00968 else
00969 cfg->include_level--;
00970
00971 return result;
00972 }
00973
00974 struct ast_config *ast_config_load(const char *filename)
00975 {
00976 struct ast_config *cfg;
00977 struct ast_config *result;
00978
00979 cfg = ast_config_new();
00980 if (!cfg)
00981 return NULL;
00982
00983 result = ast_config_internal_load(filename, cfg);
00984 if (!result)
00985 ast_config_destroy(cfg);
00986
00987 return result;
00988 }
00989
00990 struct ast_variable *ast_load_realtime(const char *family, ...)
00991 {
00992 struct ast_config_engine *eng;
00993 char db[256]="";
00994 char table[256]="";
00995 struct ast_variable *res=NULL;
00996 va_list ap;
00997
00998 va_start(ap, family);
00999 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
01000 if (eng && eng->realtime_func)