Newer
Older
for (eng = config_engine_list; !ret && eng; eng = eng->next) {
if (!strcasecmp(eng->name, map->driver))
ret = eng;
}
}
/* if we found a mapping, but the engine is not available, then issue a warning */
if (map && !ret)
ast_log(LOG_WARNING, "Realtime mapping for '%s' found to engine '%s', but the engine is not available\n", map->name, map->driver);
return ret;
}
struct ast_category *ast_config_get_current_category(const struct ast_config *cfg);
struct ast_category *ast_config_get_current_category(const struct ast_config *cfg)
{
return cfg->current;
}
Steve Murphy
committed
static struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno);
Steve Murphy
committed
static struct ast_category *ast_category_new(const char *name, const char *in_file, int lineno)
{
struct ast_category *category;
if ((category = ast_calloc(1, sizeof(*category))))
ast_copy_string(category->name, name, sizeof(category->name));
Steve Murphy
committed
category->file = strdup(in_file);
category->lineno = lineno; /* if you don't know the lineno, set it to 999999 or something real big */
return category;
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
}
struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name);
struct ast_category *localized_category_get(const struct ast_config *config, const char *category_name)
{
return category_get(config, category_name, 0);
}
static void move_variables(struct ast_category *old, struct ast_category *new)
{
struct ast_variable *var = old->root;
old->root = NULL;
#if 1
/* we can just move the entire list in a single op */
ast_variable_append(new, var);
#else
while (var) {
struct ast_variable *next = var->next;
var->next = NULL;
ast_variable_append(new, var);
var = next;
}
#endif
}
static void inherit_category(struct ast_category *new, const struct ast_category *base)
{
struct ast_variable *var;
for (var = base->root; var; var = var->next)
ast_variable_append(new, variable_clone(var));
}
static void ast_category_append(struct ast_config *config, struct ast_category *category);
static void ast_category_append(struct ast_config *config, struct ast_category *category)
{
if (config->last)
config->last->next = category;
else
config->root = category;
config->last = category;
config->current = category;
}
static void ast_category_destroy(struct ast_category *cat);
static void ast_category_destroy(struct ast_category *cat)
{
ast_variables_destroy(cat->root);
Steve Murphy
committed
if (cat->file)
free(cat->file);
free(cat);
}
static struct ast_config_engine text_file_engine = {
.name = "text",
.load_func = config_text_file_load,
};
Steve Murphy
committed
static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file);
Steve Murphy
committed
static struct ast_config *ast_config_internal_load(const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_incl_file)
{
char db[256];
char table[256];
struct ast_config_engine *loader = &text_file_engine;
struct ast_config *result;
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
if (cfg->include_level == cfg->max_include_level) {
ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", cfg->max_include_level);
return NULL;
}
cfg->include_level++;
/* silence is golden!
ast_log(LOG_WARNING, "internal loading file %s level=%d\n", filename, cfg->include_level);
*/
if (strcmp(filename, extconfig_conf) && strcmp(filename, "asterisk.conf") && config_engine_list) {
struct ast_config_engine *eng;
eng = find_engine(filename, db, sizeof(db), table, sizeof(table));
if (eng && eng->load_func) {
loader = eng;
} else {
eng = find_engine("global", db, sizeof(db), table, sizeof(table));
if (eng && eng->load_func)
loader = eng;
}
}
Steve Murphy
committed
result = loader->load_func(db, table, filename, cfg, withcomments, suggested_incl_file);
ast_log(LOG_WARNING, "finished internal loading file %s level=%d\n", filename, cfg->include_level);
*/
if (result)
result->include_level--;
return result;
}
Steve Murphy
committed
static int process_text_line(struct ast_config *cfg, struct ast_category **cat, char *buf, int lineno, const char *configfile, int withcomments, const char *suggested_include_file)
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
{
char *c;
char *cur = buf;
struct ast_variable *v;
char cmd[512], exec_file[512];
int object, do_exec, do_include;
/* Actually parse the entry */
if (cur[0] == '[') {
struct ast_category *newcat = NULL;
char *catname;
/* A category header */
c = strchr(cur, ']');
if (!c) {
ast_log(LOG_WARNING, "parse error: no closing ']', line %d of %s\n", lineno, configfile);
return -1;
}
*c++ = '\0';
cur++;
if (*c++ != '(')
c = NULL;
catname = cur;
Steve Murphy
committed
if (!(*cat = newcat = ast_category_new(catname, ast_strlen_zero(suggested_include_file)?configfile:suggested_include_file, lineno))) {
return -1;
}
Steve Murphy
committed
(*cat)->lineno = lineno;
/* add comments */
if (withcomments && comment_buffer && comment_buffer[0] ) {
newcat->precomments = ALLOC_COMMENT(comment_buffer);
}
if (withcomments && lline_buffer && lline_buffer[0] ) {
newcat->sameline = ALLOC_COMMENT(lline_buffer);
}
if( withcomments )
CB_RESET();
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
/* If there are options or categories to inherit from, process them now */
if (c) {
if (!(cur = strchr(c, ')'))) {
ast_log(LOG_WARNING, "parse error: no closing ')', line %d of %s\n", lineno, configfile);
return -1;
}
*cur = '\0';
while ((cur = strsep(&c, ","))) {
if (!strcasecmp(cur, "!")) {
(*cat)->ignored = 1;
} else if (!strcasecmp(cur, "+")) {
*cat = category_get(cfg, catname, 1);
if (!*cat) {
ast_config_destroy(cfg);
if (newcat)
ast_category_destroy(newcat);
ast_log(LOG_WARNING, "Category addition requested, but category '%s' does not exist, line %d of %s\n", catname, lineno, configfile);
return -1;
}
if (newcat) {
move_variables(newcat, *cat);
ast_category_destroy(newcat);
newcat = NULL;
}
} else {
struct ast_category *base;
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
base = category_get(cfg, cur, 1);
if (!base) {
ast_log(LOG_WARNING, "Inheritance requested, but category '%s' does not exist, line %d of %s\n", cur, lineno, configfile);
return -1;
}
inherit_category(*cat, base);
}
}
}
if (newcat)
ast_category_append(cfg, *cat);
} else if (cur[0] == '#') {
/* A directive */
cur++;
c = cur;
while(*c && (*c > 32)) c++;
if (*c) {
*c = '\0';
/* Find real argument */
c = ast_skip_blanks(c + 1);
if (!*c)
c = NULL;
c = NULL;
do_include = !strcasecmp(cur, "include");
if(!do_include)
do_exec = !strcasecmp(cur, "exec");
else
do_exec = 0;
if (do_exec && !ast_opt_exec_includes) {
ast_log(LOG_WARNING, "Cannot perform #exec unless execincludes option is enabled in asterisk.conf (options section)!\n");
do_exec = 0;
}
if (do_include || do_exec) {
if (c) {
Steve Murphy
committed
char *cur2;
char real_inclusion_name[256];
/* Strip off leading and trailing "'s and <>'s */
while((*c == '<') || (*c == '>') || (*c == '\"')) c++;
/* Get rid of leading mess */
cur = c;
Steve Murphy
committed
cur2 = cur;
while (!ast_strlen_zero(cur)) {
c = cur + strlen(cur) - 1;
if ((*c == '>') || (*c == '<') || (*c == '\"'))
*c = '\0';
else
break;
}
/* #exec </path/to/executable>
We create a tmp file, then we #include it, then we delete it. */
snprintf(exec_file, sizeof(exec_file), "/var/tmp/exec.%d.%ld", (int)time(NULL), (long)pthread_self());
snprintf(cmd, sizeof(cmd), "%s > %s 2>&1", cur, exec_file);
ast_safe_system(cmd);
cur = exec_file;
} else
exec_file[0] = '\0';
/* A #include */
/* ast_log(LOG_WARNING, "Reading in included file %s withcomments=%d\n", cur, withcomments); */
Steve Murphy
committed
/* record this inclusion */
ast_include_new(cfg, configfile, cur, do_exec, cur2, lineno, real_inclusion_name, sizeof(real_inclusion_name));
Steve Murphy
committed
do_include = ast_config_internal_load(cur, cfg, withcomments, real_inclusion_name) ? 1 : 0;
if(!ast_strlen_zero(exec_file))
unlink(exec_file);
if(!do_include)
return 0;
/* ast_log(LOG_WARNING, "Done reading in included file %s withcomments=%d\n", cur, withcomments); */
} else {
ast_log(LOG_WARNING, "Directive '#%s' needs an argument (%s) at line %d of %s\n",
do_exec ? "exec" : "include",
do_exec ? "/path/to/executable" : "filename",
lineno,
configfile);
}
}
ast_log(LOG_WARNING, "Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
} else {
/* Just a line (variable = value) */
if (!*cat) {
ast_log(LOG_WARNING,
"parse error: No category context for line %d of %s\n", lineno, configfile);
return -1;
}
c = strchr(cur, '=');
if (c) {
*c = 0;
c++;
/* Ignore > in => */
if (*c== '>') {
object = 1;
c++;
} else
object = 0;
Steve Murphy
committed
if ((v = ast_variable_new(ast_strip(cur), ast_strip(c), configfile))) {
v->lineno = lineno;
v->object = object;
/* Put and reset comments */
v->blanklines = 0;
ast_variable_append(*cat, v);
/* add comments */
if (withcomments && comment_buffer && comment_buffer[0] ) {
v->precomments = ALLOC_COMMENT(comment_buffer);
}
if (withcomments && lline_buffer && lline_buffer[0] ) {
v->sameline = ALLOC_COMMENT(lline_buffer);
}
if( withcomments )
CB_RESET();
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
} else {
return -1;
}
} else {
ast_log(LOG_WARNING, "EXTENSIONS.CONF: No '=' (equal sign) in line %d of %s\n", lineno, configfile);
}
}
return 0;
}
static int use_local_dir = 1;
void localized_use_local_dir(void);
void localized_use_conf_dir(void);
void localized_use_local_dir(void)
{
use_local_dir = 1;
}
void localized_use_conf_dir(void)
{
use_local_dir = 0;
}
Steve Murphy
committed
static struct ast_config *config_text_file_load(const char *database, const char *table, const char *filename, struct ast_config *cfg, int withcomments, const char *suggested_include_file)
{
char fn[256];
char buf[8192];
char *new_buf, *comment_p, *process_buf;
FILE *f;
int lineno=0;
int comment = 0, nest[MAX_NESTED_COMMENTS];
struct ast_category *cat = NULL;
int count = 0;
struct stat statbuf;
cat = ast_config_get_current_category(cfg);
if (filename[0] == '/') {
ast_copy_string(fn, filename, sizeof(fn));
} else {
if (use_local_dir)
snprintf(fn, sizeof(fn), "./%s", filename);
else
snprintf(fn, sizeof(fn), "%s/%s", ast_config_AST_CONFIG_DIR, filename);
}
if (withcomments && cfg && cfg->include_level < 2 ) {
CB_INIT();
}
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
#ifdef AST_INCLUDE_GLOB
{
int glob_ret;
glob_t globbuf;
globbuf.gl_offs = 0; /* initialize it to silence gcc */
#ifdef SOLARIS
glob_ret = glob(fn, GLOB_NOCHECK, NULL, &globbuf);
#else
glob_ret = glob(fn, GLOB_NOMAGIC|GLOB_BRACE, NULL, &globbuf);
#endif
if (glob_ret == GLOB_NOSPACE)
ast_log(LOG_WARNING,
"Glob Expansion of pattern '%s' failed: Not enough memory\n", fn);
else if (glob_ret == GLOB_ABORTED)
ast_log(LOG_WARNING,
"Glob Expansion of pattern '%s' failed: Read error\n", fn);
else {
/* loop over expanded files */
int i;
for (i=0; i<globbuf.gl_pathc; i++) {
ast_copy_string(fn, globbuf.gl_pathv[i], sizeof(fn));
#endif
do {
if (stat(fn, &statbuf))
continue;
if (!S_ISREG(statbuf.st_mode)) {
ast_log(LOG_WARNING, "'%s' is not a regular file, ignoring\n", fn);
continue;
}
if (option_verbose > 1) {
ast_verbose(VERBOSE_PREFIX_2 "Parsing '%s': ", fn);
fflush(stdout);
}
if (!(f = fopen(fn, "r"))) {
if (option_debug)
ast_log(LOG_DEBUG, "No file to parse: %s\n", fn);
if (option_verbose > 1)
ast_verbose( "Not found (%s)\n", strerror(errno));
continue;
}
count++;
if (option_debug)
ast_log(LOG_DEBUG, "Parsing %s\n", fn);
if (option_verbose > 1)
ast_verbose("Found\n");
while(!feof(f)) {
lineno++;
if (fgets(buf, sizeof(buf), f)) {
CB_ADD(lline_buffer); /* add the current lline buffer to the comment buffer */
lline_buffer[0] = 0; /* erase the lline buffer */
}
new_buf = buf;
process_buf = NULL;
else
process_buf = buf;
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
while ((comment_p = strchr(new_buf, COMMENT_META))) {
if ((comment_p > new_buf) && (*(comment_p-1) == '\\')) {
/* Yuck, gotta memmove */
memmove(comment_p - 1, comment_p, strlen(comment_p) + 1);
new_buf = comment_p;
} else if(comment_p[1] == COMMENT_TAG && comment_p[2] == COMMENT_TAG && (comment_p[3] != '-')) {
/* Meta-Comment start detected ";--" */
if (comment < MAX_NESTED_COMMENTS) {
*comment_p = '\0';
new_buf = comment_p + 3;
comment++;
nest[comment-1] = lineno;
} else {
ast_log(LOG_ERROR, "Maximum nest limit of %d reached.\n", MAX_NESTED_COMMENTS);
}
} else if ((comment_p >= new_buf + 2) &&
(*(comment_p - 1) == COMMENT_TAG) &&
(*(comment_p - 2) == COMMENT_TAG)) {
/* Meta-Comment end detected */
comment--;
new_buf = comment_p + 1;
if (!comment) {
/* Back to non-comment now */
if (process_buf) {
/* Actually have to move what's left over the top, then continue */
char *oldptr;
oldptr = process_buf + strlen(process_buf);
if ( withcomments ) {
CB_ADD(";");
CB_ADD_LEN(oldptr+1,new_buf-oldptr-1);
}
memmove(oldptr, new_buf, strlen(new_buf) + 1);
new_buf = oldptr;
} else
process_buf = new_buf;
}
} else {
if (!comment) {
/* If ; is found, and we are not nested in a comment,
we immediately stop all comment processing */
if ( withcomments ) {
LLB_ADD(comment_p);
}
new_buf = comment_p;
} else
new_buf = comment_p + 1;
}
}
if( withcomments && comment && !process_buf )
{
CB_ADD(buf); /* the whole line is a comment, store it */
}
if (process_buf) {
char *stripped_process_buf = ast_strip(process_buf);
if (!ast_strlen_zero(stripped_process_buf)) {
if (process_text_line(cfg, &cat, stripped_process_buf, lineno, filename, withcomments, suggested_include_file)) {
cfg = NULL;
break;
}
}
}
}
}
} while(0);
if (comment) {
ast_log(LOG_WARNING,"Unterminated comment detected beginning on line %d\n", nest[comment]);
}
#ifdef AST_INCLUDE_GLOB
if (!cfg)
break;
}
globfree(&globbuf);
}
}
#endif
if (cfg && cfg->include_level == 1 && withcomments && comment_buffer) {
free(comment_buffer);
free(lline_buffer);
comment_buffer=0;
lline_buffer=0;
comment_buffer_size=0;
lline_buffer_size=0;
}
}
if (count == 0)
return NULL;
return cfg;
}
static struct ast_config *ast_config_new(void) ;
static struct ast_config *ast_config_new(void)
{
struct ast_config *config;
if ((config = ast_calloc(1, sizeof(*config))))
config->max_include_level = MAX_INCLUDE_LEVEL;
return config;
}
struct ast_config *localized_config_load(const char *filename);
struct ast_config *localized_config_load(const char *filename)
{
struct ast_config *cfg;
struct ast_config *result;
cfg = ast_config_new();
if (!cfg)
return NULL;
Steve Murphy
committed
result = ast_config_internal_load(filename, cfg, 0, "");
if (!result)
ast_config_destroy(cfg);
return result;
}
struct ast_config *localized_config_load_with_comments(const char *filename);
struct ast_config *localized_config_load_with_comments(const char *filename)
{
struct ast_config *cfg;
struct ast_config *result;
cfg = ast_config_new();
if (!cfg)
return NULL;
Steve Murphy
committed
result = ast_config_internal_load(filename, cfg, 1, "");
if (!result)
ast_config_destroy(cfg);
return result;
}
static struct ast_category *next_available_category(struct ast_category *cat)
{
for (; cat && cat->ignored; cat = cat->next);
return cat;
}
static char *ast_category_browse(struct ast_config *config, const char *prev)
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
struct ast_category *cat = NULL;
if (prev && config->last_browse && (config->last_browse->name == prev))
cat = config->last_browse->next;
else if (!prev && config->root)
cat = config->root;
else if (prev) {
for (cat = config->root; cat; cat = cat->next) {
if (cat->name == prev) {
cat = cat->next;
break;
}
}
if (!cat) {
for (cat = config->root; cat; cat = cat->next) {
if (!strcasecmp(cat->name, prev)) {
cat = cat->next;
break;
}
}
}
}
if (cat)
cat = next_available_category(cat);
config->last_browse = cat;
return (cat) ? cat->name : NULL;
}
void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat);
void ast_config_set_current_category(struct ast_config *cfg, const struct ast_category *cat)
{
/* cast below is just to silence compiler warning about dropping "const" */
cfg->current = (struct ast_category *) cat;
}
Steve Murphy
committed
/* NOTE: categories and variables each have a file and lineno attribute. On a save operation, these are used to determine
which file and line number to write out to. Thus, an entire hierarchy of config files (via #include statements) can be
recreated. BUT, care must be taken to make sure that every cat and var has the proper file name stored, or you may
be shocked and mystified as to why things are not showing up in the files!
Steve Murphy
committed
Also, All #include/#exec statements are recorded in the "includes" LL in the ast_config structure. The file name
and line number are stored for each include, plus the name of the file included, so that these statements may be
included in the output files on a file_save operation.
Steve Murphy
committed
The lineno's are really just for relative placement in the file. There is no attempt to make sure that blank lines
are included to keep the lineno's the same between input and output. The lineno fields are used mainly to determine
the position of the #include and #exec directives. So, blank lines tend to disappear from a read/rewrite operation,
and a header gets added.
Steve Murphy
committed
vars and category heads are output in the order they are stored in the config file. So, if the software
shuffles these at all, then the placement of #include directives might get a little mixed up, because the
file/lineno data probably won't get changed.
Steve Murphy
committed
*/
static void gen_header(FILE *f1, const char *configfile, const char *fn, const char *generator)
{
char date[256]="";
time_t t;
time(&t);
ast_copy_string(date, ctime(&t), sizeof(date));
Steve Murphy
committed
fprintf(f1, ";!\n");
fprintf(f1, ";! Automatically generated configuration file\n");
if (strcmp(configfile, fn))
fprintf(f1, ";! Filename: %s (%s)\n", configfile, fn);
else
fprintf(f1, ";! Filename: %s\n", configfile);
fprintf(f1, ";! Generator: %s\n", generator);
fprintf(f1, ";! Creation Date: %s", date);
fprintf(f1, ";!\n");
}
static void set_fn(char *fn, int fn_size, const char *file, const char *configfile)
{
if (!file || file[0] == 0) {
if (configfile[0] == '/')
ast_copy_string(fn, configfile, fn_size);
else
snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, configfile);
} else if (file[0] == '/')
Steve Murphy
committed
ast_copy_string(fn, file, fn_size);
else
snprintf(fn, fn_size, "%s/%s", ast_config_AST_CONFIG_DIR, file);
}
int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator);
int localized_config_text_file_save(const char *configfile, const struct ast_config *cfg, const char *generator)
{
FILE *f;
char fn[256];
struct ast_variable *var;
struct ast_category *cat;
struct ast_comment *cmt;
Steve Murphy
committed
struct ast_config_include *incl;
int blanklines = 0;
Steve Murphy
committed
/* reset all the output flags, in case this isn't our first time saving this data */
Steve Murphy
committed
for (incl=cfg->includes; incl; incl = incl->next)
incl->output = 0;
Steve Murphy
committed
/* go thru all the inclusions and make sure all the files involved (configfile plus all its inclusions)
are all truncated to zero bytes and have that nice header*/
Steve Murphy
committed
for (incl=cfg->includes; incl; incl = incl->next)
{
if (!incl->exec) { /* leave the execs alone -- we'll write out the #exec directives, but won't zero out the include files or exec files*/
FILE *f1;
Steve Murphy
committed
set_fn(fn, sizeof(fn), incl->included_file, configfile); /* normally, fn is just set to incl->included_file, prepended with config dir if relative */
f1 = fopen(fn,"w");
if (f1) {
gen_header(f1, configfile, fn, generator);
fclose(f1); /* this should zero out the file */
} else {
ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
}
}
}
Steve Murphy
committed
set_fn(fn, sizeof(fn), 0, configfile); /* just set fn to absolute ver of configfile */
if ((f = fopen(fn, "w+"))) {
#else
if ((f = fopen(fn, "w"))) {
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Saving '%s': ", fn);
Steve Murphy
committed
gen_header(f, configfile, fn, generator);
cat = cfg->root;
Steve Murphy
committed
fclose(f);
Steve Murphy
committed
/* from here out, we open each involved file and concat the stuff we need to add to the end and immediately close... */
/* since each var, cat, and associated comments can come from any file, we have to be
Steve Murphy
committed
mobile, and open each file, print, and close it on an entry-by-entry basis */
while(cat) {
Steve Murphy
committed
set_fn(fn, sizeof(fn), cat->file, configfile);
f = fopen(fn, "a");
if (!f)
{
Steve Murphy
committed
ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
return -1;
}
Steve Murphy
committed
/* dump any includes that happen before this category header */
for (incl=cfg->includes; incl; incl = incl->next) {
if (strcmp(incl->include_location_file, cat->file) == 0){
if (cat->lineno > incl->include_location_lineno && !incl->output) {
if (incl->exec)
fprintf(f,"#exec \"%s\"\n", incl->exec_file);
else
fprintf(f,"#include \"%s\"\n", incl->included_file);
incl->output = 1;
}
}
}
Steve Murphy
committed
/* Dump section with any appropriate comment */
for (cmt = cat->precomments; cmt; cmt=cmt->next) {
if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
fprintf(f,"%s", cmt->cmt);
}
if (!cat->precomments)
fprintf(f,"\n");
fprintf(f, "[%s]", cat->name);
Steve Murphy
committed
for(cmt = cat->sameline; cmt; cmt=cmt->next) {
fprintf(f,"%s", cmt->cmt);
}
if (!cat->sameline)
fprintf(f,"\n");
Steve Murphy
committed
fclose(f);
var = cat->root;
while(var) {
Steve Murphy
committed
set_fn(fn, sizeof(fn), var->file, configfile);
f = fopen(fn, "a");
if (!f)
{
Steve Murphy
committed
ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
return -1;
}
Steve Murphy
committed
/* dump any includes that happen before this category header */
for (incl=cfg->includes; incl; incl = incl->next) {
if (strcmp(incl->include_location_file, var->file) == 0){
if (var->lineno > incl->include_location_lineno && !incl->output) {
if (incl->exec)
fprintf(f,"#exec \"%s\"\n", incl->exec_file);
else
fprintf(f,"#include \"%s\"\n", incl->included_file);
incl->output = 1;
}
}
}
Steve Murphy
committed
for (cmt = var->precomments; cmt; cmt=cmt->next) {
if (cmt->cmt[0] != ';' || cmt->cmt[1] != '!')
fprintf(f,"%s", cmt->cmt);
}
fprintf(f, "%s %s %s %s", var->name, (var->object ? "=>" : "="), var->value, var->sameline->cmt);
fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value);
if (var->blanklines) {
blanklines = var->blanklines;
while (blanklines--)
fprintf(f, "\n");
}
Steve Murphy
committed
fclose(f);
var = var->next;
}
cat = cat->next;
}
if ((option_verbose > 1) && !option_debug)
ast_verbose("Saved\n");
} else {
if (option_debug)
ast_log(LOG_DEBUG, "Unable to open for writing: %s\n", fn);
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Unable to write (%s)", strerror(errno));
return -1;
}
Steve Murphy
committed
/* Now, for files with trailing #include/#exec statements,
we have to make sure every entry is output */
Steve Murphy
committed
for (incl=cfg->includes; incl; incl = incl->next) {
if (!incl->output) {
/* open the respective file */
set_fn(fn, sizeof(fn), incl->include_location_file, configfile);
f = fopen(fn, "a");
if (!f)
{
ast_verbose(VERBOSE_PREFIX_2 "Unable to write %s (%s)", fn, strerror(errno));
return -1;
}
Steve Murphy
committed
/* output the respective include */
if (incl->exec)
fprintf(f,"#exec \"%s\"\n", incl->exec_file);
else
fprintf(f,"#include \"%s\"\n", incl->included_file);
fclose(f);
incl->output = 1;
}
}
3848
3849
3850
3851
3852
3853
3854
3855
3856
3857
3858
3859
3860
3861
3862
3863
3864
3865
3866
3867
3868
3869
3870
3871
3872
3873
3874
3875
3876
3877
3878
3879
3880
3881
3882
3883
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
return 0;
}
/* ================ the Line ========================================
above this line, you have what you need to load a config file,
and below it, you have what you need to process the extensions.conf
file into the context/exten/prio stuff. They are both in one file
to make things simpler */
static struct ast_context *local_contexts = NULL;
static struct ast_context *contexts = NULL;
struct ast_context;
struct ast_app;
#ifdef LOW_MEMORY
#define EXT_DATA_SIZE 256
#else
#define EXT_DATA_SIZE 8192
#endif
#ifdef NOT_ANYMORE
static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
#endif
#define SWITCH_DATA_LENGTH 256
static const char *ast_get_extension_app(struct ast_exten *e)
{
return e ? e->app : NULL;
}
static const char *ast_get_extension_name(struct ast_exten *exten)
{
return exten ? exten->exten : NULL;
}
static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
/*! \brief ast_change_hint: Change hint for an extension */
static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
{
struct ast_hint *hint;
int res = -1;
AST_RWLIST_TRAVERSE(&hints, hint, list) {
if (hint->exten == oe) {
hint->exten = ne;
res = 0;
break;
}
}
return res;
}
/*! \brief ast_add_hint: Add hint to hint list, check initial extension state */
static int ast_add_hint(struct ast_exten *e)
{
struct ast_hint *hint;
if (!e)
return -1;
/* Search if hint exists, do nothing */
AST_RWLIST_TRAVERSE(&hints, hint, list) {
if (hint->exten == e) {
if (option_debug > 1)
ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
return -1;
}
}
if (option_debug > 1)
ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
3922
3923
3924
3925
3926
3927
3928
3929
3930
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
3956
3957
3958
3959
3960
3961
3962
3963
3964
3965
3966
3967
3968
3969
3970
3971
3972
3973
3974
3975
3976
3977
3978
3979
3980
3981
3982
3983
3984
3985
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
if (!(hint = ast_calloc(1, sizeof(*hint)))) {
return -1;
}
/* Initialize and insert new item at the top */
hint->exten = e;
AST_RWLIST_INSERT_HEAD(&hints, hint, list);
return 0;
}
/*! \brief add the extension in the priority chain.
* returns 0 on success, -1 on failure
*/
static int add_pri(struct ast_context *con, struct ast_exten *tmp,
struct ast_exten *el, struct ast_exten *e, int replace)
{
struct ast_exten *ep;
for (ep = NULL; e ; ep = e, e = e->peer) {
if (e->priority >= tmp->priority)
break;
}
if (!e) { /* go at the end, and ep is surely set because the list is not empty */
ep->peer = tmp;
return 0; /* success */
}
if (e->priority == tmp->priority) {
/* Can't have something exactly the same. Is this a
replacement? If so, replace, otherwise, bonk. */
if (!replace) {
ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
tmp->datad(tmp->data);
free(tmp);
return -1;
}
/* we are replacing e, so copy the link fields and then update
* whoever pointed to e to point to us
*/
tmp->next = e->next; /* not meaningful if we are not first in the peer list */
tmp->peer = e->peer; /* always meaningful */
if (ep) /* We're in the peer list, just insert ourselves */
ep->peer = tmp;
else if (el) /* We're the first extension. Take over e's functions */
el->next = tmp;
else /* We're the very first extension. */
con->root = tmp;
if (tmp->priority == PRIORITY_HINT)
ast_change_hint(e,tmp);
/* Destroy the old one */
e->datad(e->data);
free(e);
} else { /* Slip ourselves in just before e */
tmp->peer = e;
tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
if (ep) /* Easy enough, we're just in the peer list */
ep->peer = tmp;
else { /* we are the first in some peer list, so link in the ext list */
if (el)
el->next = tmp; /* in the middle... */
else
con->root = tmp; /* ... or at the head */
e->next = NULL; /* e is no more at the head, so e->next must be reset */
}
/* And immediately return success. */
if (tmp->priority == PRIORITY_HINT)
ast_add_hint(tmp);
}
return 0;
}
/*! \brief ast_remove_hint: Remove hint from extension */
static int ast_remove_hint(struct ast_exten *e)
{
/* Cleanup the Notifys if hint is removed */
struct ast_hint *hint;
struct ast_state_cb *cblist, *cbprev;
int res = -1;