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: 78180 $")
00032
00033 #include <stdio.h>
00034 #include <unistd.h>
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include <errno.h>
00038 #include <time.h>
00039 #include <sys/stat.h>
00040 #define AST_INCLUDE_GLOB 1
00041 #ifdef AST_INCLUDE_GLOB
00042 #if defined(__Darwin__) || defined(__CYGWIN__)
00043 #define GLOB_ABORTED GLOB_ABEND
00044 #endif
00045 # include <glob.h>
00046 #endif
00047
00048 #include "asterisk/config.h"
00049 #include "asterisk/cli.h"
00050 #include "asterisk/lock.h"
00051 #include "asterisk/options.h"
00052 #include "asterisk/logger.h"
00053 #include "asterisk/utils.h"
00054 #include "asterisk/channel.h"
00055 #include "asterisk/app.h"
00056
00057 #define MAX_NESTED_COMMENTS 128
00058 #define COMMENT_START ";--"
00059 #define COMMENT_END "--;"
00060 #define COMMENT_META ';'
00061 #define COMMENT_TAG '-'
00062
00063 static char *extconfig_conf = "extconfig.conf";
00064
00065
00066
00067 struct ast_comment {
00068 struct ast_comment *next;
00069 char cmt[0];
00070 };
00071
00072 #define CB_INCR 250
00073
00074 static void CB_INIT(char **comment_buffer, int *comment_buffer_size, char **lline_buffer, int *lline_buffer_size)
00075 {
00076 if (!(*comment_buffer)) {
00077 *comment_buffer = ast_malloc(CB_INCR);
00078 if (!(*comment_buffer))
00079 return;
00080 (*comment_buffer)[0] = 0;
00081 *comment_buffer_size = CB_INCR;
00082 *lline_buffer = ast_malloc(CB_INCR);
00083 if (!(*lline_buffer))
00084 return;
00085 (*lline_buffer)[0] = 0;
00086 *lline_buffer_size = CB_INCR;
00087 } else {
00088 (*comment_buffer)[0] = 0;
00089 (*lline_buffer)[0] = 0;
00090 }
00091 }
00092
00093 static void CB_ADD(char **comment_buffer, int *comment_buffer_size, char *str)
00094 {
00095 int rem = *comment_buffer_size - strlen(*comment_buffer) - 1;
00096 int siz = strlen(str);
00097 if (rem < siz+1) {
00098 *comment_buffer = ast_realloc(*comment_buffer, *comment_buffer_size + CB_INCR + siz + 1);
00099 if (!(*comment_buffer))
00100 return;
00101 *comment_buffer_size += CB_INCR+siz+1;
00102 }
00103 strcat(*comment_buffer,str);
00104 }
00105
00106 static void CB_ADD_LEN(char **comment_buffer, int *comment_buffer_size, char *str, int len)
00107 {
00108 int cbl = strlen(*comment_buffer) + 1;
00109 int rem = *comment_buffer_size - cbl;
00110 if (rem < len+1) {
00111 *comment_buffer = ast_realloc(*comment_buffer, *comment_buffer_size + CB_INCR + len + 1);
00112 if (!(*comment_buffer))
00113 return;
00114 *comment_buffer_size += CB_INCR+len+1;
00115 }
00116 strncat(*comment_buffer,str,len);
00117 (*comment_buffer)[cbl+len-1] = 0;
00118 }
00119
00120 static void LLB_ADD(char **lline_buffer, int *lline_buffer_size, char *str)
00121 {
00122 int rem = *lline_buffer_size - strlen(*lline_buffer) - 1;
00123 int siz = strlen(str);
00124 if (rem < siz+1) {
00125 *lline_buffer = ast_realloc(*lline_buffer, *lline_buffer_size + CB_INCR + siz + 1);
00126 if (!(*lline_buffer))
00127 return;
00128 *lline_buffer_size += CB_INCR + siz + 1;
00129 }
00130 strcat(*lline_buffer,str);
00131 }
00132
00133 static void CB_RESET(char **comment_buffer, char **lline_buffer)
00134 {
00135 (*comment_buffer)[0] = 0;
00136 (*lline_buffer)[0] = 0;
00137 }
00138
00139
00140 static struct ast_comment *ALLOC_COMMENT(const char *buffer)
00141 {
00142 struct ast_comment *x = ast_calloc(1,sizeof(struct ast_comment)+strlen(buffer)+1);
00143 strcpy(x->cmt, buffer);
00144 return x;
00145 }
00146
00147
00148 static struct ast_config_map {
00149 struct ast_config_map *next;
00150 char *name;
00151 char *driver;
00152 char *database;
00153 char *table;
00154 char stuff[0];
00155 } *config_maps = NULL;
00156
00157 AST_MUTEX_DEFINE_STATIC(config_lock);
00158 static struct ast_config_engine *config_engine_list;
00159
00160 #define MAX_INCLUDE_LEVEL 10
00161
00162 struct ast_category {
00163 char name[80];
00164 int ignored;
00165 int include_level;
00166 struct ast_comment *precomments;
00167 struct ast_comment *sameline;
00168 struct ast_variable *root;
00169 struct ast_variable *last;
00170 struct ast_category *next;
00171 };
00172
00173 struct ast_config {
00174 struct ast_category *root;
00175 struct ast_category *last;
00176 struct ast_category *current;
00177 struct ast_category *last_browse;
00178 int include_level;
00179 int max_include_level;
00180 };
00181
00182 struct ast_variable *ast_variable_new(const char *name, const char *value)
00183 {
00184 struct ast_variable *variable;
00185 int name_len = strlen(name) + 1;
00186
00187 if ((variable = ast_calloc(1, name_len + strlen(value) + 1 + sizeof(*variable)))) {
00188 variable->name = variable->stuff;
00189 variable->value = variable->stuff + name_len;
00190 strcpy(variable->name,name);
00191 strcpy(variable->value,value);
00192 }
00193
00194 return variable;
00195 }
00196
00197 void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
00198 {
00199 if (!variable)
00200 return;
00201 if (category->last)
00202 category->last->next = variable;
00203 else
00204 category->root = variable;
00205 category->last = variable;
00206 while (category->last->next)
00207 category->last = category->last->next;
00208 }
00209
00210 void ast_variables_destroy(struct ast_variable *v)
00211 {
00212 struct ast_variable *vn;
00213
00214 while(v) {
00215 vn = v;
00216 v = v->next;
00217 free(vn);
00218 }
00219 }
00220
00221 struct ast_variable *ast_variable_browse(const struct ast_config *config, const char *category)
00222 {
00223 struct ast_category *cat = NULL;
00224
00225 if (category && config->last_browse && (config->last_browse->name == category))
00226 cat = config->last_browse;
00227 else
00228 cat = ast_category_get(config, category);
00229
00230 return (cat) ? cat->root : NULL;
00231 }
00232
00233 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
00234 {
00235 const char *tmp;
00236 tmp = ast_variable_retrieve(cfg, cat, var);
00237 if (!tmp)
00238 tmp = ast_variable_retrieve(cfg, "general", var);
00239 return tmp;
00240 }
00241
00242
00243 const char *ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
00244 {
00245 struct ast_variable *v;
00246
00247 if (category) {
00248 for (v = ast_variable_browse(config, category); v; v = v->next) {
00249 if (!strcasecmp(variable, v->name))
00250 return v->value;
00251 }
00252 } else {
00253 struct ast_category *cat;
00254
00255 for (cat = config->root; cat; cat = cat->next)
00256 for (v = cat->root; v; v = v->next)
00257 if (!strcasecmp(variable, v->name))
00258 return v->value;
00259 }
00260
00261 return NULL;
00262 }
00263
00264 static struct ast_variable *variable_clone(const struct ast_variable *old)
00265 {
00266 struct ast_variable *new = ast_variable_new(old->name, old->value);
00267
00268 if (new) {
00269 new->lineno = old->lineno;
00270 new->object = old->object;
00271 new->blanklines = old->blanklines;
00272
00273 }
00274
00275 return new;
00276 }
00277
00278 static void move_variables(struct ast_category *old, struct ast_category *new)
00279 {
00280 struct ast_variable *var = old->root;
00281 old->root = NULL;
00282 #if 1
00283
00284 ast_variable_append(new, var);
00285 #else
00286 while (var) {
00287 struct ast_variable *next = var->next;
00288 var->next = NULL;
00289 ast_variable_append(new, var);
00290 var = next;
00291 }
00292 #endif
00293 }
00294
00295 struct ast_category *ast_category_new(const char *name)
00296 {
00297 struct ast_category *category;
00298
00299 if ((category = ast_calloc(1, sizeof(*category))))
00300 ast_copy_string(category->name, name, sizeof(category->name));
00301 return category;
00302 }
00303
00304 static struct ast_category *category_get(const struct ast_config *config, const char *category_name, int ignored)
00305 {
00306 struct ast_category *cat;
00307
00308
00309 for (cat = config->root; cat; cat = cat->next) {
00310 if (cat->name == category_name && (ignored || !cat->ignored))
00311 return cat;
00312 }
00313
00314 for (cat = config->root; cat; cat = cat->next) {
00315 if (!strcasecmp(cat->name, category_name) && (ignored || !cat->ignored))
00316 return cat;
00317 }
00318
00319 return NULL;
00320 }
00321
00322 struct ast_category *ast_category_get(const struct ast_config *config, const char *category_name)
00323 {
00324 return category_get(config, category_name, 0);
00325 }
00326
00327 int ast_category_exist(const struct ast_config *config, const char *category_name)
00328 {
00329 return !!ast_category_get(config, category_name);
00330 }
00331
00332 void ast_category_append(struct ast_config *config, struct ast_category *category)
00333 {
00334 if (config->last)
00335 config->last->next = category;
00336 else
00337 config->root = category;
00338 category->include_level = config->include_level;
00339 config->last = category;
00340 config->current = category;
00341 }
00342
00343 void ast_category_destroy(struct ast_category *cat)
00344 {
00345 ast_variables_destroy(cat->root);
00346 free(cat);
00347 }
00348
00349 static struct ast_category *next_available_category(struct ast_category *cat)
00350 {
00351 for (; cat && cat->ignored; cat = cat->next);
00352
00353 return cat;
00354 }
00355
00356 struct ast_variable *ast_category_root(struct ast_config *config, char *cat)
00357 {
00358 struct ast_category *category = ast_category_get(config, cat);
00359 if (category)
00360 return category->root;
00361 return NULL;
00362 }
00363
00364 char *ast_category_browse(struct ast_config *config, const char *prev)
00365 {
00366 struct ast_category *cat = NULL;
00367
00368 if (prev && config->last_browse && (config->last_browse->name == prev))
00369 cat = config->last_browse->next;
00370 else if (!prev && config->root)
00371 cat = config->root;
00372 else if (prev) {
00373 for (cat = config->root; cat; cat = cat->next) {
00374 if (cat->name == prev) {
00375 cat = cat->next;
00376 break;
00377 }
00378 }
00379 if (!cat) {
00380 for (cat = config->root; cat; cat = cat->next) {
00381 if (!strcasecmp(cat->name, prev)) {
00382 cat = cat->next;
00383 break;
00384 }
00385 }
00386 }
00387 }
00388
00389 if (cat)
00390 cat = next_available_category(cat);
00391
00392 config->last_browse = cat;
00393 return (cat) ? cat->name : NULL;
00394 }
00395
00396 struct ast_variable *ast_category_detach_variables(struct ast_category *cat)
00397 {
00398 struct ast_variable *v;
00399
00400 v = cat->root;
00401 cat->root = NULL;
00402 cat->last = NULL;
00403
00404 return v;
00405 }
00406
00407 void ast_category_rename(struct ast_category *cat, const char *name)
00408 {
00409 ast_copy_string(cat->name, name, sizeof(cat->name));
00410 }
00411
00412 static void inherit_category(struct ast_category *new, const struct ast_category *base)
00413 {
00414 struct ast_variable *var;
00415
00416 for (var = base->root; var; var = var->next)
00417 ast_variable_append(new, variable_clone(var));
00418 }
00419
00420 struct ast_config *ast_config_new(void)
00421 {
00422 struct ast_config *config;
00423
00424 if ((config = ast_calloc(1, sizeof(*config))))
00425 config->max_include_level = MAX_INCLUDE_LEVEL;
00426 return config;
00427 }
00428
00429 int ast_variable_delete(struct ast_category *category, char *variable, char *match)
00430 {
00431 struct ast_variable *cur, *prev=NULL, *curn;
00432 int res = -1;
00433 cur = category->root;
00434 while (cur) {
00435 if (cur->name == variable) {
00436 if (prev) {
00437 prev->next = cur->next;
00438 if (cur == category->last)
00439 category->last = prev;
00440 } else {
00441 category->root = cur->next;
00442 if (cur == category->last)
00443 category->last = NULL;
00444 }
00445 cur->next = NULL;
00446 ast_variables_destroy(cur);
00447 return 0;
00448 }
00449 prev = cur;
00450 cur = cur->next;
00451 }
00452
00453 prev = NULL;
00454 cur = category->root;
00455 while (cur) {
00456 curn = cur->next;
00457 if (!strcasecmp(cur->name, variable) && (ast_strlen_zero(match) || !strcasecmp(cur->value, match))) {
00458 if (prev) {
00459 prev->next = cur->next;
00460 if (cur == category->last)
00461 category->last = prev;
00462 } else {
00463 category->root = cur->next;
00464 if (cur == category->last)
00465 category->last = NULL;
00466 }
00467 cur->next = NULL;
00468 ast_variables_destroy(cur);
00469 res = 0;
00470 } else
00471 prev = cur;
00472
00473 cur = curn;
00474 }
00475 return res;
00476 }
00477
00478 int ast_variable_update(struct ast_category *category, const char *variable,
00479 const char *value, const char *match, unsigned int object)
00480 {
00481 struct ast_variable *cur, *prev=NULL, *newer;
00482
00483 if (!(newer = ast_variable_new(variable, value)))
00484 return -1;
00485
00486 newer->object = object;
00487
00488 for (cur = category->root; cur; prev = cur, cur = cur->next) {
00489 if (strcasecmp(cur->name, variable) ||
00490 (!ast_strlen_zero(match) && strcasecmp(cur->value, match)))
00491 continue;
00492
00493 newer->next = cur->next;
00494 newer->object = cur->object || object;
00495 if (prev)
00496 prev->next = newer;
00497 else
00498 category->root = newer;
00499 if (category->last == cur)
00500 category->last = newer;
00501
00502 cur->next = NULL;
00503 ast_variables_destroy(cur);
00504
00505 return 0;
00506 }
00507
00508 if (prev)
00509 prev->next = newer;
00510 else
00511 category->root = newer;
00512
00513 return 0;
00514 }
00515
00516 int ast_category_delete(struct ast_config *cfg, char *category)
00517 {
00518 struct ast_category *prev=NULL, *cat;
00519 cat = cfg->root;
00520 while(cat) {
00521 if (cat->name == category) {
00522 ast_variables_destroy(cat->root);
00523 if (prev) {
00524 prev->next = cat->next;
00525 if (cat == cfg->last)
00526 cfg->last = prev;
00527 } else {
00528 cfg->root = cat->next;
00529 if (cat == cfg->last)
00530 cfg->last = NULL;
00531 }
00532 free(cat);
00533 return 0;
00534 }
00535 prev = cat;
00536 cat = cat->next;
00537 }
00538
00539 prev = NULL;
00540 cat = cfg->root;
00541 while(cat) {
00542 if (!strcasecmp(cat->name, category)) {
00543 ast_variables_destroy(cat->root);
00544 if (prev) {
00545 prev->next = cat->next;
00546 if (cat == cfg->last)
00547 cfg->last = prev;
00548 } else {
00549 cfg->root = cat->next;
00550 if (cat == cfg->last)
00551 cfg->last = NULL;
00552 }
00553 free(cat);
00554 return 0;
00555 }
00556 prev = cat;
00557 cat = cat->next;
00558 }
00559 return -1;
00560 }
00561
00562 void ast_config_destroy(struct ast_config *cfg)
00563 {
00564 struct ast_category *cat, *catn;
00565
00566 if (!cfg)
00567 return;
00568
00569 cat = cfg->root;
00570 while(cat) {
00571 ast_variables_destroy(cat->root);
00572 catn = cat;
00573 cat = cat->next;
00574 free(catn);
00575 }
00576 free(cfg);
00577 }
00578
00579 struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
00580 {
00581 return cfg->current;
00582 }
00583
00584 void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
00585 {
00586
00587 cfg->current = (struct ast_category *) cat;
00588 }
00589
00590 static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile, int withcomments,
00591 char **comment_buffer, int *comment_buffer_size, char **lline_buffer, int *lline_buffer_size)
00592 {
00593 char *c;
00594 char *cur = buf;
00595 struct ast_variable *v;
00596 char cmd[512], exec_file[512];
00597 int object, do_exec, do_include;
00598
00599
00600 if (cur[0] == '[') {
00601 struct ast_category *newcat = NULL;
00602 char *catname;
00603
00604
00605 c = strchr(cur, ']');
00606 if (!c) {
00607 ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
00608 return -1;
00609 }
00610 *c++ = '\0';
00611 cur++;
00612 if (*c++ != '(')
00613 c = NULL;
00614 catname = cur;
00615 if (!(*cat = newcat = ast_category_new(catname))) {
00616 return -1;
00617 }
00618
00619 if (withcomments && *comment_buffer && (*comment_buffer)[0] ) {
00620 newcat->precomments = ALLOC_COMMENT(*comment_buffer);
00621 }
00622 if (withcomments && *lline_buffer && (*lline_buffer)[0] ) {
00623 newcat->sameline = ALLOC_COMMENT(*lline_buffer);
00624 }
00625 if( withcomments )
00626 CB_RESET(comment_buffer, lline_buffer);
00627
00628
00629 if (c) {
00630 if (!(cur = strchr(c, ')'))) {
00631 ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
00632 return -1;
00633 }
00634 *cur = '\0';
00635 while ((cur = strsep(&c, ","))) {
00636 if (!strcasecmp(cur, "!")) {
00637 (*cat)->ignored = 1;
00638 } else if (!strcasecmp(cur, "+")) {
00639 *cat = category_get(cfg, catname, 1);
00640 if (!(*cat)) {
00641 if (newcat)
00642 ast_category_destroy(newcat);
00643 ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
00644 return -1;
00645 }
00646 if (newcat) {
00647 move_variables(newcat, *cat);
00648 ast_category_destroy(newcat);
00649 newcat = NULL;
00650 }
00651 } else {
00652 struct ast_category *base;
00653
00654 base = category_get(cfg, cur, 1);
00655 if (!base) {
00656 ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
00657 return -1;
00658 }
00659 inherit_category(*cat, base);
00660 }
00661 }
00662 }
00663 if (newcat)
00664 ast_category_append(cfg, *cat);
00665 } else if (cur[0] == '#') {
00666
00667 cur++;
00668 c = cur;
00669 while(*c && (*c > 32)) c++;
00670 if (*c) {
00671 *c = '\0';
00672
00673 c = ast_skip_blanks(c + 1);
00674 if (!(*c))
00675 c = NULL;
00676 } else
00677 c = NULL;
00678 do_include = !strcasecmp(cur, "include");
00679 if(!do_include)
00680 do_exec = !strcasecmp(cur, "exec");
00681 else
00682 do_exec = 0;
00683 if (do_exec && !ast_opt_exec_includes) {
00684 ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
00685 do_exec = 0;
00686 }
00687 if (do_include || do_exec) {
00688 if (c) {
00689
00690 while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
00691
00692 cur = c;
00693 while (!ast_strlen_zero(cur)) {
00694 c = cur + strlen(cur) - 1;
00695 if ((*c == '>') || (*c == '<') || (*c == '\"'))
00696 *c = '\0';
00697 else
00698 break;
00699 }
00700
00701
00702 if (do_exec) {
00703 snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d.%ld", (int)time(NULL), (long)pthread_self());
00704 snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
00705 ast_safe_system(cmd);
00706 cur = exec_file;
00707 } else
00708 exec_file[0] = '\0';
00709
00710 do_include = ast_config_internal_load(cur, cfg, withcomments) ? 1 : 0;
00711 if(!ast_strlen_zero(exec_file))
00712 unlink(exec_file);
00713 if(!do_include)
00714 return 0;
00715
00716 } else {
00717 ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
00718 do_exec ? "exec" : "include",
00719 do_exec ? "/path/to/executable" : "filename",
00720 lineno,
00721 configfile);
00722 }
00723 }
00724 else
00725 ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
00726 } else {
00727
00728 if (!(*cat)) {
00729 ast_log(LOG_WARNING,
00730 "parse error: No category context for line %d of %s\n", lineno, configfile);
00731 return -1;
00732 }
00733 c = strchr(cur, '=');
00734 if (c) {
00735 *c = 0;
00736 c++;
00737
00738 if (*c== '>') {
00739 object = 1;
00740 c++;
00741 } else
00742 object = 0;
00743 if ((v = ast_variable_new(ast_strip(cur), ast_strip(c)))) {
00744 v->lineno = lineno;
00745 v->object = object;
00746
00747 v->blanklines = 0;
00748 ast_variable_append(*cat, v);
00749
00750 if (withcomments && *comment_buffer && (*comment_buffer)[0] ) {
00751 v->precomments = ALLOC_COMMENT(*comment_buffer);
00752 }
00753 if (withcomments && *lline_buffer && (*lline_buffer)[0] ) {
00754 v->sameline = ALLOC_COMMENT(*lline_buffer);
00755 }
00756 if( withcomments )
00757 CB_RESET(comment_buffer, lline_buffer);
00758
00759 } else {
00760 return -1;
00761 }
00762 } else {
00763 ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile);
00764 }
00765 }
00766 return 0;
00767 }
00768
00769 static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments)
00770 {
00771 char fn[256];
00772 char buf[8192];
00773 char *new_buf, *comment_p, *process_buf;
00774 FILE *f;
00775 int lineno=0;
00776 int comment = 0, nest[MAX_NESTED_COMMENTS];
00777 struct ast_category *cat = NULL;
00778 int count = 0;
00779 struct stat statbuf;
00780
00781 char *comment_buffer=0;
00782 int comment_buffer_size=0;
00783
00784 char *lline_buffer=0;
00785 int lline_buffer_size=0;
00786
00787
00788 cat = ast_config_get_current_category(cfg);
00789
00790 if (filename[0] == '/') {
00791 ast_copy_string(fn, filename, sizeof(fn));
00792 } else {
00793 snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_CONFIG_DIR, filename);
00794 }
00795
00796 if (withcomments) {
00797 CB_INIT(&comment_buffer, &comment_buffer_size, &lline_buffer, &lline_buffer_size);
00798 if (!lline_buffer || !comment_buffer) {
00799 ast_log(LOG_ERROR, "Failed to initialize the comment buffer!\n");
00800 return NULL;
00801 }
00802 }
00803 #ifdef AST_INCLUDE_GLOB
00804 {
00805 int glob_ret;
00806 glob_t globbuf;
00807 globbuf.gl_offs = 0;
00808 #ifdef SOLARIS
00809 glob_ret = glob(fn, GLOB_NOCHECK, NULL, &globbuf);
00810 #else
00811 glob_ret = glob(fn, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf);
00812 #endif
00813 if (glob_ret == GLOB_NOSPACE)
00814 ast_log(LOG_WARNING,
00815 "Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
00816 else if (glob_ret == GLOB_ABORTED)
00817 ast_log(LOG_WARNING,
00818 "Glob Expansion of pattern '%s' failed: Read error\n", fn);
00819 else {
00820
00821 int i;
00822 for (i=0; i<globbuf.gl_pathc; i++) {
00823 ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
00824 #endif
00825 do {
00826 if (stat(fn, &statbuf))
00827 continue;
00828
00829 if (!S_ISREG(statbuf.st_mode)) {
00830 ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
00831 continue;
00832 }
00833 if (option_verbose > 1) {
00834 ast_verbose(VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
00835 fflush(stdout);
00836 }
00837 if (!(f = fopen(fn, "r"))) {
00838 if (option_debug)
00839 ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
00840 if (option_verbose > 1)
00841 ast_verbose( "Not found (%s)\n", strerror(errno));
00842 continue;
00843 }
00844 count++;
00845 if (option_debug)
00846 ast_log(LOG_DEBUG, "Parsing %s\n", fn);
00847 if (option_verbose > 1)
00848 ast_verbose("Found\n");
00849 while(!feof(f)) {
00850 lineno++;
00851 if (fgets(buf, sizeof(buf), f)) {
00852 if ( withcomments ) {
00853 CB_ADD(&comment_buffer, &comment_buffer_size, lline_buffer);
00854 lline_buffer[0] = 0;
00855 }
00856
00857 new_buf = buf;
00858 if (comment)
00859 process_buf = NULL;
00860 else
00861 process_buf = buf;
00862
00863 while ((comment_p = strchr(new_buf, COMMENT_META))) {
00864 if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
00865
00866 new_buf = comment_p + 1;
00867 } else if(comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
00868
00869 if (comment < MAX_NESTED_COMMENTS) {
00870 *comment_p = '\0';
00871 new_buf = comment_p + 3;
00872 comment++;
00873 nest[comment-1] = lineno;
00874 } else {
00875 ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
00876 }
00877 } else if ((comment_p >= new_buf + 2) &&
00878 (*(comment_p - 1) == COMMENT_TAG) &&
00879 (*(comment_p - 2) == COMMENT_TAG)) {
00880
00881 comment--;
00882 new_buf = comment_p + 1;
00883 if (!comment) {
00884
00885 if (process_buf) {
00886
00887 char *oldptr;
00888 oldptr = process_buf + strlen(process_buf);
00889 if ( withcomments ) {
00890 CB_ADD(&comment_buffer, &comment_buffer_size, ";");
00891 CB_ADD_LEN(&comment_buffer, &comment_buffer_size, oldptr+1, new_buf-oldptr-1);
00892 }
00893
00894 memmove(oldptr, new_buf, strlen(new_buf) + 1);
00895 new_buf = oldptr;
00896 } else
00897 process_buf = new_buf;
00898 }
00899 } else {
00900 if (!comment) {
00901
00902
00903 if ( withcomments ) {
00904 LLB_ADD(&lline_buffer, &lline_buffer_size, comment_p);
00905 }
00906 *comment_p = '\0';
00907 new_buf = comment_p;
00908 } else
00909 new_buf = comment_p + 1;
00910 }
00911 }
00912 if( withcomments && comment && !process_buf )
00913 {
00914 CB_ADD(&comment_buffer, &comment_buffer_size, buf);
00915 }
00916
00917 if (process_buf) {
00918 char *buf = ast_strip(process_buf);
00919 if (!ast_strlen_zero(buf)) {
00920 if (process_text_line(cfg, &cat, buf, lineno, fn, withcomments, &comment_buffer, &comment_buffer_size, &lline_buffer, &lline_buffer_size)) {
00921 cfg = NULL;
00922 break;
00923 }
00924 }
00925 }
00926 }
00927 }
00928 fclose(f);
00929 } while(0);
00930 if (comment) {
00931 ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment - 1]);
00932 }
00933 #ifdef AST_INCLUDE_GLOB
00934 if (!cfg)
00935 break;
00936 }
00937 globfree(&globbuf);
00938 }
00939 }
00940 #endif
00941
00942 if (cfg && cfg->include_level == 1 && withcomments && comment_buffer) {
00943 free(comment_buffer);
00944 free(lline_buffer);
00945 comment_buffer = NULL;
00946 lline_buffer = NULL;
00947 comment_buffer_size = 0;
00948 lline_buffer_size = 0;
00949 }
00950
00951 if (count == 0)
00952 return NULL;
00953
00954 return cfg;
00955 }
00956
00957 int config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
00958 {
00959 FILE *f;
00960 char fn[256];
00961 char date[256]="";
00962 time_t t;
00963 struct ast_variable *var;
00964 struct ast_category *cat;
00965 struct ast_comment *cmt;
00966 int blanklines = 0;
00967
00968 if (configfile[0] == '/') {
00969 ast_copy_string(fn, configfile, sizeof(fn));
00970 } else {
00971 snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
00972 }
00973 time(&t);
00974 ast_copy_string(date, ctime(&t), sizeof(date));
00975 #ifdef __CYGWIN__
00976 if ((f = fopen(fn, "w+"))) {
00977 #else
00978 if ((f = fopen(fn, "w"))) {
00979 #endif
00980 if (option_verbose > 1)
00981 ast_verbose(VERBOSE_PREFIX_2 "Saving '%s': ", fn);
00982 fprintf(f, ";!\n");
00983 fprintf(f, ";! Automatically generated configuration file\n");
00984 if (strcmp(configfile, fn))
00985 fprintf(f, ";! Filename: %s (%s)\n", configfile, fn);
00986 else
00987 fprintf(f, ";! Filename: %s\n", configfile);
00988 fprintf(f, ";! Generator: %s\n", generator);
00989 fprintf(f, ";! Creation Date: %s", date);
00990 fprintf(f, ";!\n");
00991 cat = cfg->root;
00992 while(cat) {
00993
00994 for (cmt = cat->precomments; cmt; cmt=cmt->next)
00995 {
00996 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
00997 fprintf(f,"%s", cmt->cmt);
00998 }
00999 if (!cat->precomments)
01000 fprintf(f,"\n");
01001 fprintf(f, "[%s]", cat->name);
01002 for(cmt = cat->sameline; cmt; cmt=cmt->next)
01003 {
01004 fprintf(f,"%s", cmt->cmt);
01005 }
01006 if (!cat->sameline)
01007 fprintf(f,"\n");
01008 var = cat->root;
01009 while(var) {
01010 for (cmt = var->precomments; cmt; cmt=cmt->next)
01011 {
01012 if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
01013 fprintf(f,"%s", cmt->cmt);
01014 }
01015 if (var->sameline)
01016 fprintf(f, "%s %s %s %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
01017 else
01018 fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
01019 if (var->blanklines) {
01020 blanklines = var->blanklines;
01021 while (blanklines--)
01022 fprintf(f, "\n");
01023 }
01024
01025 var = var->next;
01026 }
01027 #if 0
01028
01029 fprintf(f, "\n");
01030 #endif
01031 cat = cat->next;
01032 }
01033 if ((option_verbose > 1) && !option_debug)
01034 ast_verbose("Saved\n");
01035 } else {
01036 if (option_debug)
01037 ast_log(LOG_DEBUG, "Unable to open for writing: %s\n", fn);
01038 if (option_verbose > 1)
01039 ast_verbose(VERBOSE_PREFIX_2 "Unable to write (%s)", strerror(errno));
01040 return -1;
01041 }
01042 fclose(f);
01043 return 0;
01044 }
01045
01046 static void clear_config_maps(void)
01047 {
01048 struct ast_config_map *map;
01049
01050 ast_mutex_lock(&config_lock);
01051
01052 while (config_maps) {
01053 map = config_maps;
01054 config_maps = config_maps->next;
01055 free(map);
01056 }
01057
01058 ast_mutex_unlock(&config_lock);
01059 }
01060
01061 static int append_mapping(char *name, char *driver, char *database, char *table)
01062 {
01063 struct ast_config_map *map;
01064 int length;
01065
01066 length = sizeof(*map);
01067 length += strlen(name) + 1;
01068 length += strlen(driver) + 1;
01069 length += strlen(database) + 1;
01070 if (table)
01071 length += strlen(table) + 1;
01072
01073 if (!(map = ast_calloc(1, length)))
01074 return -1;
01075
01076 map->name = map->stuff;
01077 strcpy(map->name, name);
01078 map->driver = map->name + strlen(map->name) + 1;
01079 strcpy(map->driver, driver);
01080 map->database = map->driver + strlen(map->driver) + 1;
01081 strcpy(map->database, database);
01082 if (table) {
01083 map->table = map->database + strlen(map->database) + 1;
01084 strcpy(map->table, table);
01085 }
01086 map->next = config_maps;
01087
01088 if (option_verbose > 1)
01089 ast_verbose(VERBOSE_PREFIX_2 "Binding %s to %s/%s/%s\n",
01090 map->name, map->driver, map->database, map->table ? map->table : map->name);
01091
01092 config_maps = map;
01093 return 0;
01094 }
01095
01096 int read_config_maps(void)
01097 {
01098 struct ast_config *config, *configtmp;
01099 struct ast_variable *v;
01100 char *driver, *table, *database, *stringp, *tmp;
01101
01102 clear_config_maps();
01103
01104 configtmp = ast_config_new();
01105 configtmp->max_include_level = 1;
01106 config = ast_config_internal_load(extconfig_conf, configtmp, 0);
01107 if (!config) {
01108 ast_config_destroy(configtmp);
01109 return 0;
01110 }
01111
01112 for (v = ast_variable_browse(config, "settings"); v; v = v->next) {
01113 stringp = v->value;
01114 driver = strsep(&stringp, ",");
01115
01116 if ((tmp = strchr(stringp, '\"')))
01117 stringp = tmp;
01118
01119
01120 if (*stringp == '"') {
01121 stringp++;
01122 database = strsep(&stringp, "\"");
01123 strsep(&stringp, ",");
01124 } else {
01125
01126 database = strsep(&stringp, ",");
01127 }
01128
01129 table = strsep(&stringp, ",");
01130
01131 if (!strcmp(v->name, extconfig_conf)) {
01132 ast_log(LOG_WARNING, "Cannot bind '%s'!\n", extconfig_conf);
01133 continue;
01134 }
01135
01136 if (!strcmp(v->name, "asterisk.conf")) {
01137 ast_log(LOG_WARNING, "Cannot bind 'asterisk.conf'!\n");
01138 continue;
01139 }
01140
01141 if (!strcmp(v->name, "logger.conf")) {
01142 ast_log(LOG_WARNING, "Cannot bind 'logger.conf'!\n");
01143 continue;
01144 }
01145
01146 if (!driver || !database)
01147 continue;
01148 if (!strcasecmp(v->name, "sipfriends")) {
01149 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");
01150 append_mapping("sipusers", driver, database, table ? table : "sipfriends");
01151 append_mapping("sippeers", driver, database, table ? table : "sipfriends");
01152 } else if (!strcasecmp(v->name, "iaxfriends")) {
01153 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");
01154 append_mapping("iaxusers", driver, database, table ? table : "iaxfriends");
01155 append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends");
01156 } else
01157 append_mapping(v->name, driver, database, table);
01158 }
01159
01160 ast_config_destroy(config);
01161 return 0;
01162 }
01163
01164 int ast_config_engine_register(struct ast_config_engine *new)
01165 {
01166 struct ast_config_engine *ptr;
01167
01168 ast_mutex_lock(&config_lock);
01169
01170 if (!config_engine_list) {
01171 config_engine_list = new;
01172 } else {
01173 for (ptr = config_engine_list; ptr->next; ptr=ptr->next);
01174 ptr->next = new;
01175 }
01176
01177 ast_mutex_unlock(&config_lock);
01178 ast_log(LOG_NOTICE,"Registered Config Engine %s\n", new->name);
01179
01180 return 1;
01181 }
01182
01183 int ast_config_engine_deregister(struct ast_config_engine *del)
01184 {
01185 struct ast_config_engine *ptr, *last=NULL;
01186
01187 ast_mutex_lock(&config_lock);
01188
01189 for (ptr = config_engine_list; ptr; ptr=ptr->next) {
01190 if (ptr == del) {
01191 if (last)
01192 last->next = ptr->next;
01193 else
01194 config_engine_list = ptr->next;
01195 break;
01196 }
01197 last = ptr;
01198 }
01199
01200 ast_mutex_unlock(&config_lock);
01201
01202 return 0;
01203 }
01204
01205
01206 static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
01207 {
01208 struct ast_config_engine *eng, *ret = NULL;
01209 struct ast_config_map *map;
01210
01211 ast_mutex_lock(&config_lock);
01212
01213 for (map = config_maps; map; map = map->next) {
01214 if (!strcasecmp(family, map->name)) {
01215 if (database)
01216 ast_copy_string(database, map->database, dbsiz);
01217 if (table)
01218 ast_copy_string(table, map->table ? map->table : family, tabsiz);
01219 break;
01220 }
01221 }
01222
01223
01224 if (map) {
01225 for (eng = config_engine_list; !ret && eng; eng = eng->next) {
01226 if (!strcasecmp(eng->name, map->driver))
01227 ret = eng;
01228 }
01229 }
01230
01231 ast_mutex_unlock(&config_lock);
01232
01233
01234 if (map && !ret)
01235 ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
01236
01237 return ret;
01238 }
01239
01240 static struct ast_config_engine text_file_engine = {
01241 .name = "text",
01242 .load_func = config_text_file_load,
01243 };
01244
01245 struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments)
01246 {
01247 char db[256];
01248 char table[256];
01249 struct ast_config_engine *loader = &text_file_engine;
01250 struct ast_config *result;
01251
01252 if (cfg->include_level == cfg->max_include_level) {
01253 ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
01254 return NULL;
01255 }
01256
01257 cfg->include_level++;
01258
01259 if (strcmp(filename, extconfig_conf) && strcmp(filename, "asterisk.conf") && config_engine_list) {
01260 struct ast_config_engine *eng;
01261
01262 eng = find_engine(filename, db, sizeof(db), table, sizeof(table));
01263
01264
01265 if (eng && eng->load_func) {
01266 loader = eng;
01267 } else {
01268 eng = find_engine("global", db, sizeof(db), table, sizeof(table));
01269 if (eng && eng->load_func)
01270 loader = eng;
01271 }
01272 }
01273
01274 result = loader->load_func(db, table, filename, cfg, withcomments);
01275
01276 if (result)
01277 result->include_level--;
01278 else
01279 cfg->include_level--;
01280
01281 return result;
01282 }
01283
01284 struct ast_config *ast_config_load(const char *filename)
01285 {
01286 struct ast_config *cfg;
01287 struct ast_config *result;
01288
01289 cfg = ast_config_new();
01290 if (!cfg)
01291 return NULL;
01292
01293 result = ast_config_internal_load(filename, cfg, 0);
01294 if (!result)
01295 ast_config_destroy(cfg);
01296
01297 return result;
01298 }
01299
01300 struct ast_config *ast_config_load_with_comments(const char *filename)
01301 {
01302 struct ast_config *cfg;
01303 struct ast_config *result;
01304
01305 cfg = ast_config_new();
01306 if (!cfg)
01307 return NULL;
01308
01309 result = ast_config_internal_load(filename, cfg, 1);
01310 if (!result)
01311 ast_config_destroy(cfg);
01312
01313 return result;
01314 }
01315
01316 struct ast_variable *ast_load_realtime(const char *family, ...)
01317 {
01318 struct ast_config_engine *eng;
01319 char db[256]="";
01320 char table[256]="";
01321 struct ast_variable *res=NULL;
01322 va_list ap;
01323
01324 va_start(ap, family);
01325 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
01326 if (eng && eng->realtime_func)
01327 res = eng->realtime_func(db, table, ap);
01328 va_end(ap);
01329
01330 return res;
01331 }
01332
01333
01334 int ast_check_realtime(const char *family)
01335 {
01336 struct ast_config_engine *eng;
01337
01338 eng = find_engine(family, NULL, 0, NULL, 0);
01339 if (eng)
01340 return 1;
01341 return 0;
01342
01343 }
01344
01345 struct ast_config *ast_load_realtime_multientry(const char *family, ...)
01346 {
01347 struct ast_config_engine *eng;
01348 char db[256]="";
01349 char table[256]="";
01350 struct ast_config *res=NULL;
01351 va_list ap;
01352
01353 va_start(ap, family);
01354 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
01355 if (eng && eng->realtime_multi_func)
01356 res = eng->realtime_multi_func(db, table, ap);
01357 va_end(ap);
01358
01359 return res;
01360 }
01361
01362 int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
01363 {
01364 struct ast_config_engine *eng;
01365 int res = -1;
01366 char db[256]="";
01367 char table[256]="";
01368 va_list ap;
01369
01370 va_start(ap, lookup);
01371 eng = find_engine(family, db, sizeof(db), table, sizeof(table));
01372 if (eng && eng->update_func)
01373 res = eng->update_func(db, table, keyfield, lookup, ap);
01374 va_end(ap);
01375
01376 return res;
01377 }
01378
01379 static int config_command(int fd, int argc, char **argv)
01380 {
01381 struct ast_config_engine *eng;
01382 struct ast_config_map *map;
01383
01384 ast_mutex_lock(&config_lock);
01385
01386 ast_cli(fd, "\n\n");
01387 for (eng = config_engine_list; eng; eng = eng->next) {
01388 ast_cli(fd, "\nConfig Engine: %s\n", eng->name);
01389 for (map = config_maps; map; map = map->next)
01390 if (!strcasecmp(map->driver, eng->name)) {
01391 ast_cli(fd, "===> %s (db=%s, table=%s)\n", map->name, map->database,
01392 map->table ? map->table : map->name);
01393 }
01394 }
01395 ast_cli(fd,"\n\n");
01396
01397 ast_mutex_unlock(&config_lock);
01398
01399 return 0;
01400 }
01401
01402 static char show_config_help[] =
01403 "Usage: core show config mappings\n"
01404 " Shows the filenames to config engines.\n";
01405
01406 static struct ast_cli_entry cli_show_config_mappings_deprecated = {
01407 { "show", "config", "mappings", NULL },
01408 config_command, NULL,
01409 NULL };
01410
01411 static struct ast_cli_entry cli_config[] = {
01412 { { "core", "show", "config", "mappings", NULL },
01413 config_command, "Display config mappings (file names to config engines)",
01414 show_config_help, NULL, &cli_show_config_mappings_deprecated },
01415 };
01416
01417 int register_config_cli()
01418 {
01419 ast_cli_register_multiple(cli_config, sizeof(cli_config) / sizeof(struct ast_cli_entry));
01420 return 0;
01421 }