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