00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
#include <stdio.h>
00015
#include <unistd.h>
00016
#include <stdlib.h>
00017
#include <string.h>
00018
#include <errno.h>
00019
#include <time.h>
00020
#include <asterisk/config.h>
00021
#include <asterisk/options.h>
00022
#include <asterisk/logger.h>
00023
#include <asterisk/utils.h>
00024
#include "asterisk.h"
00025
#include "astconf.h"
00026
00027 #define MAX_INCLUDE_LEVEL 10
00028
00029 struct ast_category {
00030 char name[80];
00031 struct ast_variable *
root;
00032 struct ast_category *
next;
00033
#ifdef PRESERVE_COMMENTS
00034
struct ast_comment *precomments;
00035
struct ast_comment *sameline;
00036
#endif
00037
};
00038
00039 struct ast_config {
00040
00041
00042 struct ast_category *
root;
00043 struct ast_category *
prev;
00044
#ifdef PRESERVE_COMMENTS
00045
struct ast_comment *trailingcomments;
00046
#endif
00047
};
00048
00049
#ifdef PRESERVE_COMMENTS
00050
struct ast_comment_struct
00051 {
00052
struct ast_comment *root;
00053
struct ast_comment *prev;
00054 };
00055
#endif
00056
00057
static char *strip(
char *buf)
00058 {
00059
char *start;
00060
00061
while(!ast_strlen_zero(buf) && (buf[strlen(buf)-1]<33))
00062 buf[strlen(buf)-1] =
'\0';
00063 start = buf;
00064
00065
while(*start && (*start < 33))
00066 *start++ =
'\0';
00067
return start;
00068 }
00069
00070
#ifdef PRESERVE_COMMENTS
00071
static void free_comments(
struct ast_comment *com)
00072 {
00073
struct ast_comment *l;
00074
while (com) {
00075 l = com;
00076 com = com->
next;
00077
free(l);
00078 }
00079 }
00080
#endif
00081
00082 void ast_destroy(
struct ast_config *ast)
00083 {
00084
struct ast_category *cat, *catn;
00085
struct ast_variable *v, *vn;
00086
00087
if (!ast)
00088
return;
00089
00090 cat = ast->
root;
00091
while(cat) {
00092 v = cat->
root;
00093
while(v) {
00094 vn = v;
00095
free(v->name);
00096
free(v->value);
00097
#ifdef PRESERVE_COMMENTS
00098
free_comments(v->precomments);
00099 free_comments(v->sameline);
00100
#endif
00101
v = v->next;
00102
free(vn);
00103 }
00104 catn = cat;
00105
#ifdef PRESERVE_COMMENTS
00106
free_comments(cat->precomments);
00107 free_comments(cat->sameline);
00108
#endif
00109
cat = cat->next;
00110
free(catn);
00111 }
00112
#ifdef PRESERVE_COMMENTS
00113
free_comments(ast->trailingcomments);
00114
#endif
00115
free(ast);
00116 }
00117
00118 int ast_true(
char *s)
00119 {
00120
if (!
s)
00121
return 0;
00122
00123
if (!strcasecmp(
s,
"yes") ||
00124 !strcasecmp(
s,
"true") ||
00125 !strcasecmp(
s,
"y") ||
00126 !strcasecmp(
s,
"t") ||
00127 !strcasecmp(
s,
"1"))
00128
return -1;
00129
return 0;
00130 }
00131
00132 int ast_false(
char *s)
00133 {
00134
if (!
s)
00135
return 0;
00136
00137
if (!strcasecmp(
s,
"no") ||
00138 !strcasecmp(
s,
"false") ||
00139 !strcasecmp(
s,
"n") ||
00140 !strcasecmp(
s,
"f") ||
00141 !strcasecmp(
s,
"0"))
00142
return -1;
00143
return 0;
00144 }
00145
00146 struct ast_variable *
ast_variable_browse(
struct ast_config *config,
char *category)
00147 {
00148
struct ast_category *cat;
00149 cat = config->
root;
00150
while(cat) {
00151
if (cat->name == category)
00152
return cat->
root;
00153 cat = cat->
next;
00154 }
00155 cat = config->
root;
00156
while(cat) {
00157
if (!strcasecmp(cat->name, category))
00158
return cat->
root;
00159 cat = cat->
next;
00160 }
00161
return NULL;
00162 }
00163
00164 char *
ast_variable_retrieve(
struct ast_config *config,
char *category,
char *value)
00165 {
00166
struct ast_variable *v;
00167
if (category) {
00168 v =
ast_variable_browse(config, category);
00169
while (v) {
00170
if (value == v->name)
00171
return v->value;
00172 v=v->next;
00173 }
00174 v =
ast_variable_browse(config, category);
00175
while (v) {
00176
if (!strcasecmp(value, v->name))
00177
return v->value;
00178 v=v->next;
00179 }
00180 }
else {
00181
struct ast_category *cat;
00182 cat = config->
root;
00183
while(cat) {
00184 v = cat->
root;
00185
while (v) {
00186
if (!strcasecmp(value, v->name))
00187
return v->
value;
00188 v=v->next;
00189 }
00190 cat = cat->next;
00191 }
00192 }
00193
return NULL;
00194 }
00195
00196
#ifdef PRESERVE_COMMENTS
00197
int ast_variable_delete(
struct ast_config *cfg,
char *category,
char *variable,
char *value)
00198 {
00199
struct ast_variable *v, *pv, *bv, *bpv;
00200
struct ast_category *cat;
00201 cat = cfg->
root;
00202
while(cat) {
00203
if (cat->name == category) {
00204
break;
00205 }
00206 cat = cat->
next;
00207 }
00208
if (!cat) {
00209 cat = cfg->
root;
00210
while(cat) {
00211
if (!strcasecmp(cat->name, category)) {
00212
break;
00213 }
00214 cat = cat->
next;
00215 }
00216 }
00217
if (!cat)
00218
return -1;
00219 v = cat->
root;
00220 pv = NULL;
00221
while (v) {
00222
if ((variable == v->name) && (!value || !strcmp(v->value, value)))
00223
break;
00224 pv = v;
00225 v=v->
next;
00226 }
00227
if (!v) {
00228
00229 bv = NULL;
00230 bpv = NULL;
00231 v = cat->root;
00232 pv = NULL;
00233
while (v) {
00234
if (!strcasecmp(variable, v->name) && (!value || !strcmp(v->value, value))) {
00235 bv = v;
00236 bpv = pv;
00237 }
00238 pv = v;
00239 v=v->
next;
00240 }
00241 v = bv;
00242 }
00243
00244
if (v) {
00245
00246
if (pv)
00247 pv->
next = v->
next;
00248
else
00249 cat->root = v->
next;
00250 v->
next = NULL;
00251
free(v->name);
00252
if (v->value)
00253
free(v->value);
00254 free_comments(v->sameline);
00255 free_comments(v->precomments);
00256
return 0;
00257 }
00258
return -1;
00259 }
00260
00261
int ast_category_delete(
struct ast_config *cfg,
char *category)
00262 {
00263
struct ast_variable *v, *pv;
00264
struct ast_category *cat, *cprev;
00265 cat = cfg->
root;
00266 cprev = NULL;
00267
while(cat) {
00268
if (cat->name == category) {
00269
break;
00270 }
00271 cprev = cat;
00272 cat = cat->
next;
00273 }
00274
if (!cat) {
00275 cat = cfg->
root;
00276 cprev = NULL;
00277
while(cat) {
00278
if (!strcasecmp(cat->name, category)) {
00279
break;
00280 }
00281 cprev = cat;
00282 cat = cat->
next;
00283 }
00284 }
00285
if (!cat)
00286
return -1;
00287
00288
if (cprev)
00289 cprev->
next = cat->
next;
00290
else
00291 cfg->
root = cat->
next;
00292 v = cat->
root;
00293
while (v) {
00294 pv = v;
00295 v=v->
next;
00296
if (pv->value)
00297
free(pv->value);
00298
if (pv->name)
00299
free(pv->name);
00300 free_comments(pv->sameline);
00301 free_comments(pv->precomments);
00302
free(pv);
00303 }
00304 free_comments(cat->sameline);
00305 free_comments(cat->precomments);
00306
free(cat);
00307
return 0;
00308 }
00309
00310
struct ast_variable *
ast_variable_append_modify(
struct ast_config *config,
char *category,
char *variable,
char *value,
int newcat,
int newvar,
int move)
00311 {
00312
struct ast_variable *v, *pv=NULL, *bv, *bpv;
00313
struct ast_category *cat, *pcat;
00314 cat = config->
root;
00315
if (!newcat) {
00316
while(cat) {
00317
if (cat->name == category) {
00318
break;
00319 }
00320 cat = cat->
next;
00321 }
00322
if (!cat) {
00323 cat = config->
root;
00324
while(cat) {
00325
if (!strcasecmp(cat->name, category)) {
00326
break;
00327 }
00328 cat = cat->
next;
00329 }
00330 }
00331 }
00332
if (!cat) {
00333 cat =
malloc(
sizeof(
struct ast_category));
00334
if (!cat)
00335
return NULL;
00336 memset(cat, 0,
sizeof(
struct ast_category));
00337 strncpy(cat->name, category,
sizeof(cat->name));
00338
if (config->
root) {
00339
00340 pcat = config->
root;
00341
while(pcat->next)
00342 pcat = pcat->
next;
00343 pcat->
next = cat;
00344 }
else {
00345
00346 config->
root = cat;
00347 }
00348
00349 }
00350
if (!newvar) {
00351 v = cat->
root;
00352 pv = NULL;
00353
while (v) {
00354
if (variable == v->name)
00355
break;
00356 pv = v;
00357 v=v->
next;
00358 }
00359
if (!v) {
00360
00361 bv = NULL;
00362 bpv = NULL;
00363 v = cat->root;
00364 pv = NULL;
00365
while (v) {
00366
if (!strcasecmp(variable, v->name)) {
00367 bv = v;
00368 bpv = pv;
00369 }
00370 pv = v;
00371 v=v->
next;
00372 }
00373 v = bv;
00374 }
00375 }
else v = NULL;
00376
if (v && move) {
00377
00378
if (pv)
00379 pv->
next = v->
next;
00380
else
00381 cat->root = v->
next;
00382 v->
next = NULL;
00383 }
00384
if (!v) {
00385 v =
malloc(
sizeof(
struct ast_variable));
00386
if (!v)
00387
return NULL;
00388 memset(v, 0,
sizeof(
struct ast_variable));
00389 v->name =
strdup(variable);
00390 move = 1;
00391 }
00392
if (v->value)
00393
free(v->value);
00394
if (value)
00395 v->value =
strdup(value);
00396
else
00397 v->value =
strdup(
"");
00398
if (move) {
00399
if (cat->root) {
00400 pv = cat->root;
00401
while (pv->next)
00402 pv = pv->next;
00403 pv->next = v;
00404 }
else {
00405 cat->root = v;
00406 }
00407 }
00408
return v;
00409 }
00410
#endif
00411
00412 int ast_category_exist(
struct ast_config *config,
char *category_name)
00413 {
00414
struct ast_category *category = NULL;
00415
00416 category = config->
root;
00417
00418
while(category) {
00419
if (!strcasecmp(category->name,category_name))
00420
return 1;
00421 category = category->
next;
00422 }
00423
00424
return 0;
00425 }
00426
00427
#ifdef PRESERVE_COMMENTS
00428
static struct ast_comment *build_comment(
char *cmt)
00429 {
00430
struct ast_comment *c;
00431
int len = strlen(cmt) + 1;
00432 c =
malloc(
sizeof(
struct ast_comment) + len);
00433
if (c) {
00434
00435 memset(c, 0,
sizeof(
struct ast_comment));
00436
00437 strcpy(c->cmt, cmt);
00438 }
00439
return c;
00440 }
00441
#endif
00442
00443
static struct ast_config *__ast_load(
char *configfile,
struct ast_config *tmp,
struct ast_category **_tmpc,
struct ast_variable **_last,
int includelevel
00444 #ifdef PRESERVE_COMMENTS
00445 ,
struct ast_comment_struct *acs
00446 #endif
00447 );
00448
00449
static int cfg_process(
struct ast_config *tmp,
struct ast_category **_tmpc,
struct ast_variable **_last,
char *buf,
int lineno,
char *configfile,
int includelevel
00450 #ifdef PRESERVE_COMMENTS
00451 ,
struct ast_comment_struct *acs
00452 #endif
00453 )
00454 {
00455
char *c;
00456
char *cur;
00457
struct ast_variable *v;
00458
#ifdef PRESERVE_COMMENTS
00459
struct ast_comment *com = NULL;
00460
#endif
00461
int object;
00462
00463 c = strchr(buf,
';');
00464
if (c) {
00465 *c =
'\0';
00466
#ifdef PRESERVE_COMMENTS
00467
c++;
00468
if (*c !=
'!')
00469 com = build_comment(c);
00470
#endif
00471
}
00472 cur = strip(buf);
00473
if (!ast_strlen_zero(cur)) {
00474
00475
if (cur[0] ==
'[') {
00476
00477 c = strchr(cur,
']');
00478
if (c) {
00479 *c = 0;
00480 *_tmpc =
malloc(
sizeof(
struct ast_category));
00481
if (!*_tmpc) {
00482
ast_destroy(tmp);
00483
ast_log(LOG_WARNING,
00484
"Out of memory, line %d\n", lineno);
00485
return -1;
00486 }
00487 memset(*_tmpc, 0,
sizeof(
struct ast_category));
00488 strncpy((*_tmpc)->name, cur+1,
sizeof((*_tmpc)->name) - 1);
00489 (*_tmpc)->root = NULL;
00490
#ifdef PRESERVE_COMMENTS
00491
(*_tmpc)->precomments = acs->root;
00492 (*_tmpc)->sameline = com;
00493
#endif
00494
if (!tmp->
prev)
00495 tmp->
root = *_tmpc;
00496
else
00497 tmp->
prev->
next = *_tmpc;
00498
00499 tmp->
prev = *_tmpc;
00500
#ifdef PRESERVE_COMMENTS
00501
acs->
root = NULL;
00502 acs->prev = NULL;
00503
#endif
00504
*_last = NULL;
00505 }
else {
00506
ast_log(LOG_WARNING,
00507
"parse error: no closing ']', line %d of %s\n", lineno, configfile);
00508 }
00509 }
else if (cur[0] ==
'#') {
00510
00511 cur++;
00512 c = cur;
00513
while(*c && (*c > 32)) c++;
00514
if (*c) {
00515 *c =
'\0';
00516 c++;
00517
00518
while(*c && (*c < 33)) c++;
00519
if (!*c)
00520 c = NULL;
00521 }
else
00522 c = NULL;
00523
if (!strcasecmp(cur,
"include")) {
00524
00525
if (c) {
00526
while((*c ==
'<') || (*c ==
'>') || (*c ==
'\"')) c++;
00527
00528 cur = c;
00529
while(!ast_strlen_zero(cur)) {
00530 c = cur + strlen(cur) - 1;
00531
if ((*c ==
'>') || (*c ==
'<') || (*c ==
'\"'))
00532 *c =
'\0';
00533
else
00534
break;
00535 }
00536
if (includelevel <
MAX_INCLUDE_LEVEL) {
00537 __ast_load(cur, tmp, _tmpc, _last, includelevel + 1
00538 #ifdef PRESERVE_COMMENTS
00539 ,acs
00540 #endif
00541 );
00542 }
else
00543
ast_log(LOG_WARNING,
"Maximum Include level (%d) exceeded\n", includelevel);
00544 }
else
00545
ast_log(LOG_WARNING,
"Directive '#include' needs an argument (filename) at line %d of %s\n", lineno, configfile);
00546
00547 }
else
00548
ast_log(LOG_WARNING,
"Unknown directive '%s' at line %d of %s\n", cur, lineno, configfile);
00549 }
else {
00550
00551
if (!*_tmpc) {
00552
ast_log(LOG_WARNING,
00553
"parse error: No category context for line %d of %s\n", lineno, configfile);
00554
ast_destroy(tmp);
00555
return -1;
00556 }
00557 c = strchr(cur,
'=');
00558
if (c) {
00559 *c = 0;
00560 c++;
00561
00562
if (*c==
'>') {
00563 object = 1;
00564 c++;
00565 }
else
00566 object = 0;
00567 v =
malloc(
sizeof(
struct ast_variable));
00568
if (v) {
00569 memset(v, 0,
sizeof(
struct ast_variable));
00570 v->next = NULL;
00571 v->name =
strdup(strip(cur));
00572 v->value =
strdup(strip(c));
00573 v->lineno = lineno;
00574 v->object = object;
00575
00576
#ifdef PRESERVE_COMMENTS
00577
v->precomments = acs->root;
00578 v->sameline = com;
00579 acs->prev = NULL;
00580 acs->root = NULL;
00581
#endif
00582
v->blanklines = 0;
00583
if (*_last)
00584 (*_last)->next = v;
00585
else
00586 (*_tmpc)->root = v;
00587 *_last = v;
00588 }
else {
00589
ast_destroy(tmp);
00590
ast_log(LOG_WARNING,
"Out of memory, line %d\n", lineno);
00591
return -1;
00592 }
00593 }
else {
00594
ast_log(LOG_WARNING,
"No '=' (equal sign) in line %d of %s\n", lineno, configfile);
00595 }
00596
00597 }
00598 }
else {
00599
00600
#ifdef PRESERVE_COMMENTS
00601
if (com) {
00602
if (acs->prev)
00603 acs->prev->next = com;
00604
else
00605 acs->root = com;
00606 acs->prev = com;
00607 }
else {
00608
if (*_last)
00609 (*_last)->blanklines++;
00610
00611 }
00612
#endif
00613
}
00614
return 0;
00615 }
00616
00617
#ifdef PRESERVE_COMMENTS
00618
static void dump_comments(FILE *f,
struct ast_comment *comment)
00619 {
00620
while (comment) {
00621 fprintf(f,
";%s", comment->
cmt);
00622 comment = comment->
next;
00623 }
00624 }
00625
#endif
00626
00627 int ast_save(
char *configfile,
struct ast_config *cfg,
char *generator)
00628 {
00629 FILE *f;
00630
char fn[256];
00631
char date[256];
00632 time_t t;
00633
struct ast_variable *var;
00634
struct ast_category *cat;
00635
int blanklines = 0;
00636
if (configfile[0] ==
'/') {
00637 strncpy(fn, configfile,
sizeof(fn)-1);
00638 }
else {
00639 snprintf(fn,
sizeof(fn),
"%s/%s",
AST_CONFIG_DIR, configfile);
00640 }
00641 time(&t);
00642 strncpy(date, ctime(&t),
sizeof(date));
00643
if ((f = fopen(fn,
"w"))) {
00644
if ((
option_verbose > 1) && !
option_debug)
00645
ast_verbose(
VERBOSE_PREFIX_2 "Saving '%s': ", fn);
00646 fprintf(f,
";!\n");
00647 fprintf(f,
";! Automatically generated configuration file\n");
00648 fprintf(f,
";! Filename: %s (%s)\n", configfile, fn);
00649 fprintf(f,
";! Generator: %s\n", generator);
00650 fprintf(f,
";! Creation Date: %s", date);
00651 fprintf(f,
";!\n");
00652 cat = cfg->
root;
00653
while(cat) {
00654
#ifdef PRESERVE_COMMENTS
00655
00656 dump_comments(f, cat->precomments);
00657
#endif
00658
00659
#ifdef PRESERVE_COMMENTS
00660
if (cat->sameline)
00661 fprintf(f,
"[%s] ; %s\n", cat->name, cat->sameline->cmt);
00662
else
00663
#endif
00664
fprintf(f,
"[%s]\n", cat->name);
00665 var = cat->root;
00666
while(var) {
00667
#ifdef PRESERVE_COMMENTS
00668
dump_comments(f, var->precomments);
00669
#endif
00670
if (var->sameline)
00671 fprintf(f,
"%s %s %s ; %s\n", var->name, (var->object ?
"=>" :
"="), var->value, var->sameline->cmt);
00672
else
00673 fprintf(f,
"%s %s %s\n", var->name, (var->object ?
"=>" :
"="), var->value);
00674
if (var->blanklines) {
00675 blanklines = var->blanklines;
00676
while (blanklines) {
00677 fprintf(f,
"\n");
00678 blanklines--;
00679 }
00680 }
00681
00682 var = var->next;
00683 }
00684
#if 0
00685
00686 fprintf(f,
"\n");
00687
#endif
00688
cat = cat->next;
00689 }
00690
#ifdef PRESERVE_COMMENTS
00691
dump_comments(f, cfg->trailingcomments);
00692
#endif
00693
}
else {
00694
if (
option_debug)
00695 printf(
"Unable to open for writing: %s\n", fn);
00696
else if (
option_verbose > 1)
00697 printf(
"Unable to write (%s)", strerror(errno));
00698
return -1;
00699 }
00700 fclose(f);
00701
return 0;
00702 }
00703
00704
static struct ast_config *__ast_load(
char *configfile,
struct ast_config *tmp,
struct ast_category **_tmpc,
struct ast_variable **_last,
int includelevel
00705 #ifdef PRESERVE_COMMENTS
00706 ,
struct ast_comment_struct *acs
00707 #endif
00708 )
00709 {
00710
char fn[256];
00711
char buf[512];
00712 FILE *f;
00713
int lineno=0;
00714
int master=0;
00715
00716
if (configfile[0] ==
'/') {
00717 strncpy(fn, configfile,
sizeof(fn)-1);
00718 }
else {
00719 snprintf(fn,
sizeof(fn),
"%s/%s", (
char *)ast_config_AST_CONFIG_DIR, configfile);
00720 }
00721
if ((
option_verbose > 1) && !
option_debug) {
00722
ast_verbose( VERBOSE_PREFIX_2
"Parsing '%s': ", fn);
00723 fflush(stdout);
00724 }
00725
if ((f = fopen(fn,
"r"))) {
00726
if (
option_debug)
00727
ast_log(LOG_DEBUG,
"Parsing %s\n", fn);
00728
else if (
option_verbose > 1)
00729
ast_verbose(
"Found\n");
00730
if (!tmp) {
00731 tmp =
malloc(
sizeof(
struct ast_config));
00732
if (tmp)
00733 memset(tmp, 0,
sizeof(
struct ast_config));
00734
00735 master = 1;
00736 }
00737
if (!tmp) {
00738
ast_log(LOG_WARNING,
"Out of memory\n");
00739 fclose(f);
00740
return NULL;
00741 }
00742
while(!feof(f)) {
00743 lineno++;
00744
if (fgets(buf,
sizeof(buf), f)) {
00745
if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel
00746 #ifdef PRESERVE_COMMENTS
00747 , acs
00748 #endif
00749 )) {
00750 fclose(f);
00751
return NULL;
00752 }
00753 }
00754 }
00755 fclose(f);
00756 }
else {
00757
if (
option_debug)
00758
ast_log(LOG_DEBUG,
"No file to parse: %s\n", fn);
00759
else if (
option_verbose > 1)
00760
ast_verbose(
"Not found (%s)\n", strerror(errno));
00761 }
00762
#ifdef PRESERVE_COMMENTS
00763
if (master) {
00764
00765 tmp->trailingcomments = acs->
root;
00766 acs->
root = NULL;
00767 acs->prev = NULL;
00768 }
00769
#endif
00770
return tmp;
00771 }
00772
00773 struct ast_config *
ast_load(
char *configfile)
00774 {
00775
struct ast_category *tmpc=NULL;
00776
struct ast_variable *last = NULL;
00777
#ifdef PRESERVE_COMMENTS
00778
struct ast_comment_struct acs = { NULL, NULL };
00779
#endif
00780
return __ast_load(configfile, NULL, &tmpc, &last, 0
00781 #ifdef PRESERVE_COMMENTS
00782 ,&acs
00783 #endif
00784 );
00785 }
00786
00787 char *
ast_category_browse(
struct ast_config *config,
char *prev)
00788 {
00789
struct ast_category *cat;
00790
if (!prev) {
00791
if (config->
root)
00792
return config->
root->
name;
00793
else
00794
return NULL;
00795 }
00796 cat = config->
root;
00797
while(cat) {
00798
if (cat->name == prev) {
00799
if (cat->next)
00800
return cat->
next->
name;
00801
else
00802
return NULL;
00803 }
00804 cat = cat->next;
00805 }
00806 cat = config->
root;
00807
while(cat) {
00808
if (!strcasecmp(cat->name, prev)) {
00809
if (cat->next)
00810
return cat->
next->
name;
00811
else
00812
return NULL;
00813 }
00814 cat = cat->next;
00815 }
00816
return NULL;
00817 }