Newer
Older
/* Go through the time and enable each appropriate bit */
for (x = minute_start; x != minute_end; x = (x + 1) % (24 * 60)) {
i->minmask[x / 30] |= (1 << (x % 30));
}
/* Do the last one */
i->minmask[x / 30] |= (1 << (x % 30));
}
/* All done */
return;
}
static void null_datad(void *foo)
{
}
/*! \brief Find realtime engine for realtime family */
static struct ast_config_engine *find_engine(const char *family, char *database, int dbsiz, char *table, int tabsiz)
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
{
struct ast_config_engine *eng, *ret = NULL;
struct ast_config_map *map;
for (map = config_maps; map; map = map->next) {
if (!strcasecmp(family, map->name)) {
if (database)
ast_copy_string(database, map->database, dbsiz);
if (table)
ast_copy_string(table, map->table ? map->table : family, tabsiz);
break;
}
}
/* Check if the required driver (engine) exist */
if (map) {
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;
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
}
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;
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
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)
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
{
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();
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
/* 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;
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
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();
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
} 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();
}
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
#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;
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
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)
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
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;
}
}
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
3914
3915
3916
3917
3918
3919
3920
3921
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
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));
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;