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 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 201682 $")
00029
00030 #include <ctype.h>
00031
00032 #include "asterisk/paths.h"
00033 #include "asterisk/pbx.h"
00034 #include "asterisk/config.h"
00035 #include "asterisk/module.h"
00036 #include "asterisk/logger.h"
00037 #include "asterisk/cli.h"
00038 #include "asterisk/channel.h"
00039 #include "asterisk/callerid.h"
00040
00041 static char *config = "extensions.conf";
00042 static char *registrar = "pbx_config";
00043 static char userscontext[AST_MAX_EXTENSION] = "default";
00044
00045 static int static_config = 0;
00046 static int write_protect_config = 1;
00047 static int autofallthrough_config = 1;
00048 static int clearglobalvars_config = 0;
00049 static int extenpatternmatchnew_config = 0;
00050
00051 AST_MUTEX_DEFINE_STATIC(save_dialplan_lock);
00052
00053 static struct ast_context *local_contexts = NULL;
00054 static struct ast_hashtab *local_table = NULL;
00055
00056
00057
00058 static char *complete_dialplan_remove_include(struct ast_cli_args *);
00059 static char *complete_dialplan_add_include(struct ast_cli_args *);
00060 static char *complete_dialplan_remove_ignorepat(struct ast_cli_args *);
00061 static char *complete_dialplan_add_ignorepat(struct ast_cli_args *);
00062 static char *complete_dialplan_remove_extension(struct ast_cli_args *);
00063 static char *complete_dialplan_add_extension(struct ast_cli_args *);
00064
00065
00066
00067
00068
00069
00070
00071
00072 static char *handle_cli_dialplan_remove_include(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00073 {
00074 switch (cmd) {
00075 case CLI_INIT:
00076 e->command = "dialplan remove include";
00077 e->usage =
00078 "Usage: dialplan remove include <context> from <context>\n"
00079 " Remove an included context from another context.\n";
00080 return NULL;
00081 case CLI_GENERATE:
00082 return complete_dialplan_remove_include(a);
00083 }
00084
00085 if (strcmp(a->argv[4], "from"))
00086 return CLI_SHOWUSAGE;
00087
00088 if (!ast_context_remove_include(a->argv[5], a->argv[3], registrar)) {
00089 ast_cli(a->fd, "We are not including '%s' into '%s' now\n",
00090 a->argv[3], a->argv[5]);
00091 return CLI_SUCCESS;
00092 }
00093
00094 ast_cli(a->fd, "Failed to remove '%s' include from '%s' context\n",
00095 a->argv[3], a->argv[5]);
00096 return CLI_FAILURE;
00097 }
00098
00099
00100 static int lookup_ci(struct ast_context *c, const char *name)
00101 {
00102 struct ast_include *i = NULL;
00103
00104 if (ast_rdlock_context(c))
00105 return 0;
00106 while ( (i = ast_walk_context_includes(c, i)) )
00107 if (!strcmp(name, ast_get_include_name(i)))
00108 break;
00109 ast_unlock_context(c);
00110 return i ? -1 : 0;
00111 }
00112
00113
00114 static int lookup_c_ip(struct ast_context *c, const char *name)
00115 {
00116 struct ast_ignorepat *ip = NULL;
00117
00118 if (ast_rdlock_context(c))
00119 return 0;
00120 while ( (ip = ast_walk_context_ignorepats(c, ip)) )
00121 if (!strcmp(name, ast_get_ignorepat_name(ip)))
00122 break;
00123 ast_unlock_context(c);
00124 return ip ? -1 : 0;
00125 }
00126
00127
00128 static const char *skip_words(const char *p, int n)
00129 {
00130 int in_blank = 0;
00131 for (;n && *p; p++) {
00132 if (isblank(*p) && !in_blank) {
00133 n--;
00134 in_blank = 1;
00135 } else if ( in_blank) {
00136 in_blank = 0;
00137 }
00138 }
00139 return p;
00140 }
00141
00142
00143 static int partial_match(const char *s, const char *word, int len)
00144 {
00145 return (len == 0 || !strncmp(s, word, len));
00146 }
00147
00148
00149
00150
00151 static int split_ec(const char *src, char **ext, char ** const ctx, char ** const cid)
00152 {
00153 char *i, *c, *e = ast_strdup(src);
00154
00155 if (e == NULL)
00156 return -1;
00157
00158 *ext = e;
00159 c = strchr(e, '@');
00160 if (c == NULL)
00161 *ctx = "";
00162 else {
00163 *c++ = '\0';
00164 *ctx = c;
00165 if (strchr(c, '@')) {
00166 free(e);
00167 return -1;
00168 }
00169 }
00170 if (cid && (i = strchr(e, '/'))) {
00171 *i++ = '\0';
00172 *cid = i;
00173 } else if (cid) {
00174
00175 *cid = NULL;
00176 }
00177 return 0;
00178 }
00179
00180
00181 static char *complete_dialplan_remove_include(struct ast_cli_args *a)
00182 {
00183 int which = 0;
00184 char *res = NULL;
00185 int len = strlen(a->word);
00186 struct ast_context *c = NULL;
00187
00188 if (a->pos == 3) {
00189 if (ast_wrlock_contexts()) {
00190 ast_log(LOG_ERROR, "Failed to lock context list\n");
00191 return NULL;
00192 }
00193
00194 while (!res && (c = ast_walk_contexts(c))) {
00195 struct ast_include *i = NULL;
00196
00197 if (ast_rdlock_context(c))
00198 continue;
00199
00200 while ( !res && (i = ast_walk_context_includes(c, i)) ) {
00201 const char *i_name = ast_get_include_name(i);
00202 struct ast_context *nc = NULL;
00203 int already_served = 0;
00204
00205 if (!partial_match(i_name, a->word, len))
00206 continue;
00207
00208
00209
00210
00211
00212
00213 while ( (nc = ast_walk_contexts(nc)) && nc != c && !already_served)
00214 already_served = lookup_ci(nc, i_name);
00215
00216 if (!already_served && ++which > a->n)
00217 res = strdup(i_name);
00218 }
00219 ast_unlock_context(c);
00220 }
00221
00222 ast_unlock_contexts();
00223 return res;
00224 } else if (a->pos == 4) {
00225
00226
00227
00228
00229 char *context, *dupline;
00230 const char *s = skip_words(a->line, 3);
00231
00232 if (a->n > 0)
00233 return NULL;
00234 context = dupline = strdup(s);
00235 if (!dupline) {
00236 ast_log(LOG_ERROR, "Out of free memory\n");
00237 return NULL;
00238 }
00239 strsep(&dupline, " ");
00240
00241 if (ast_rdlock_contexts()) {
00242 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
00243 free(context);
00244 return NULL;
00245 }
00246
00247
00248 while (!res && (c = ast_walk_contexts(c)))
00249 if (lookup_ci(c, context))
00250 res = strdup("from");
00251 ast_unlock_contexts();
00252 if (!res)
00253 ast_log(LOG_WARNING, "%s not included anywhere\n", context);
00254 free(context);
00255 return res;
00256 } else if (a->pos == 5) {
00257
00258
00259
00260 char *context, *dupline, *from;
00261 const char *s = skip_words(a->line, 3);
00262 context = dupline = strdup(s);
00263 if (!dupline) {
00264 ast_log(LOG_ERROR, "Out of free memory\n");
00265 return NULL;
00266 }
00267
00268 strsep(&dupline, " ");
00269
00270
00271 from = strsep(&dupline, " ");
00272 if (!from || strcmp(from, "from")) {
00273 free(context);
00274 return NULL;
00275 }
00276
00277 if (ast_rdlock_contexts()) {
00278 ast_log(LOG_ERROR, "Failed to lock context list\n");
00279 free(context);
00280 return NULL;
00281 }
00282
00283
00284 c = NULL;
00285 while ( !res && (c = ast_walk_contexts(c))) {
00286 const char *c_name = ast_get_context_name(c);
00287 if (!partial_match(c_name, a->word, len))
00288 continue;
00289
00290 if (lookup_ci(c, context) && ++which > a->n)
00291 res = strdup(c_name);
00292 }
00293 ast_unlock_contexts();
00294 free(context);
00295 return res;
00296 }
00297
00298 return NULL;
00299 }
00300
00301
00302
00303
00304 static char *handle_cli_dialplan_remove_extension(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00305 {
00306 int removing_priority = 0;
00307 char *exten, *context, *cid;
00308 char *ret = CLI_FAILURE;
00309
00310 switch (cmd) {
00311 case CLI_INIT:
00312 e->command = "dialplan remove extension";
00313 e->usage =
00314 "Usage: dialplan remove extension exten[/cid]@context [priority]\n"
00315 " Remove an extension from a given context. If a priority\n"
00316 " is given, only that specific priority from the given extension\n"
00317 " will be removed.\n";
00318 return NULL;
00319 case CLI_GENERATE:
00320 return complete_dialplan_remove_extension(a);
00321 }
00322
00323 if (a->argc != 5 && a->argc != 4)
00324 return CLI_SHOWUSAGE;
00325
00326
00327
00328
00329 if (a->argc == 5) {
00330 char *c = a->argv[4];
00331
00332
00333
00334
00335
00336 if (!strcmp("hint", c))
00337 removing_priority = PRIORITY_HINT;
00338 else {
00339 while (*c && isdigit(*c))
00340 c++;
00341 if (*c) {
00342 ast_cli(a->fd, "Invalid priority '%s'\n", a->argv[4]);
00343 return CLI_FAILURE;
00344 }
00345 removing_priority = atoi(a->argv[4]);
00346 }
00347
00348 if (removing_priority == 0) {
00349 ast_cli(a->fd, "If you want to remove whole extension, please " \
00350 "omit priority argument\n");
00351 return CLI_FAILURE;
00352 }
00353 }
00354
00355
00356
00357
00358
00359 if (split_ec(a->argv[3], &exten, &context, &cid))
00360 return CLI_FAILURE;
00361 if ((!strlen(exten)) || (!(strlen(context)))) {
00362 ast_cli(a->fd, "Missing extension or context name in third argument '%s'\n",
00363 a->argv[3]);
00364 free(exten);
00365 return CLI_FAILURE;
00366 }
00367
00368 if (!ast_context_remove_extension_callerid(context, exten, removing_priority,
00369
00370 cid ? cid : (removing_priority ? "" : NULL), cid ? 1 : 0, registrar)) {
00371 if (!removing_priority)
00372 ast_cli(a->fd, "Whole extension %s@%s removed\n",
00373 exten, context);
00374 else
00375 ast_cli(a->fd, "Extension %s@%s with priority %d removed\n",
00376 exten, context, removing_priority);
00377
00378 ret = CLI_SUCCESS;
00379 } else {
00380 if (cid) {
00381 ast_cli(a->fd, "Failed to remove extension %s/%s@%s\n", exten, cid, context);
00382 } else {
00383 ast_cli(a->fd, "Failed to remove extension %s@%s\n", exten, context);
00384 }
00385 ret = CLI_FAILURE;
00386 }
00387 free(exten);
00388 return ret;
00389 }
00390
00391 static char *complete_dialplan_remove_extension(struct ast_cli_args *a)
00392 {
00393 char *ret = NULL;
00394 int which = 0;
00395
00396 if (a->pos == 3) {
00397 struct ast_context *c = NULL;
00398 char *context = NULL, *exten = NULL, *cid = NULL;
00399 int le = 0;
00400 int lc = 0;
00401 int lcid = 0;
00402
00403 lc = split_ec(a->word, &exten, &context, &cid);
00404 if (lc) {
00405 return NULL;
00406 }
00407 le = strlen(exten);
00408 lc = strlen(context);
00409 lcid = cid ? strlen(cid) : -1;
00410
00411 if (ast_rdlock_contexts()) {
00412 ast_log(LOG_ERROR, "Failed to lock context list\n");
00413 goto error2;
00414 }
00415
00416
00417 while ( (c = ast_walk_contexts(c)) ) {
00418 struct ast_exten *e = NULL;
00419
00420 if (!partial_match(ast_get_context_name(c), context, lc))
00421 continue;
00422 while ( (e = ast_walk_context_extensions(c, e)) ) {
00423 if ( !strchr(a->word, '/') ||
00424 (!strchr(a->word, '@') && partial_match(ast_get_extension_cidmatch(e), cid, lcid)) ||
00425 (strchr(a->word, '@') && !strcmp(ast_get_extension_cidmatch(e), cid))) {
00426 if ( ((strchr(a->word, '/') || strchr(a->word, '@')) && !strcmp(ast_get_extension_name(e), exten)) ||
00427 (!strchr(a->word, '/') && !strchr(a->word, '@') && partial_match(ast_get_extension_name(e), exten, le))) {
00428 if (++which > a->n) {
00429
00430 if (ast_get_extension_matchcid(e) && (!strchr(a->word, '@') || strchr(a->word, '/'))) {
00431 if (asprintf(&ret, "%s/%s@%s", ast_get_extension_name(e), ast_get_extension_cidmatch(e), ast_get_context_name(c)) < 0) {
00432 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00433 ret = NULL;
00434 }
00435 break;
00436 } else if (!ast_get_extension_matchcid(e) && !strchr(a->word, '/')) {
00437 if (asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c)) < 0) {
00438 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00439 ret = NULL;
00440 }
00441 break;
00442 }
00443 }
00444 }
00445 }
00446 }
00447 if (e)
00448 break;
00449 }
00450
00451 ast_unlock_contexts();
00452 error2:
00453 free(exten);
00454 } else if (a->pos == 4) {
00455 char *exten = NULL, *context, *cid, *p;
00456 struct ast_context *c;
00457 int le, lc, lcid, len;
00458 const char *s = skip_words(a->line, 3);
00459 int i = split_ec(s, &exten, &context, &cid);
00460
00461 if (i)
00462 goto error3;
00463 if ( (p = strchr(exten, ' ')) )
00464 *p = '\0';
00465 if ( (p = strchr(context, ' ')) )
00466 *p = '\0';
00467 le = strlen(exten);
00468 lc = strlen(context);
00469 lcid = strlen(cid);
00470 len = strlen(a->word);
00471 if (le == 0 || lc == 0)
00472 goto error3;
00473
00474 if (ast_rdlock_contexts()) {
00475 ast_log(LOG_ERROR, "Failed to lock context list\n");
00476 goto error3;
00477 }
00478
00479
00480 c = NULL;
00481 while ( (c = ast_walk_contexts(c)) ) {
00482
00483 struct ast_exten *e;
00484 if (strcmp(ast_get_context_name(c), context) != 0)
00485 continue;
00486
00487 e = NULL;
00488 while ( (e = ast_walk_context_extensions(c, e)) ) {
00489 struct ast_exten *priority;
00490 char buffer[10];
00491
00492 if (cid && strcmp(ast_get_extension_cidmatch(e), cid) != 0) {
00493 continue;
00494 }
00495 if (strcmp(ast_get_extension_name(e), exten) != 0)
00496 continue;
00497
00498 priority = NULL;
00499 while ( !ret && (priority = ast_walk_extension_priorities(e, priority)) ) {
00500 snprintf(buffer, sizeof(buffer), "%u", ast_get_extension_priority(priority));
00501 if (partial_match(buffer, a->word, len) && ++which > a->n)
00502 ret = strdup(buffer);
00503 }
00504 break;
00505 }
00506 break;
00507 }
00508 ast_unlock_contexts();
00509 error3:
00510 free(exten);
00511 }
00512 return ret;
00513 }
00514
00515
00516
00517
00518 static char *handle_cli_dialplan_add_include(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00519 {
00520 switch (cmd) {
00521 case CLI_INIT:
00522 e->command = "dialplan add include";
00523 e->usage =
00524 "Usage: dialplan add include <context> into <context>\n"
00525 " Include a context in another context.\n";
00526 return NULL;
00527 case CLI_GENERATE:
00528 return complete_dialplan_add_include(a);
00529 }
00530
00531 if (a->argc != 6)
00532 return CLI_SHOWUSAGE;
00533
00534
00535 if (strcmp(a->argv[4], "into"))
00536 return CLI_SHOWUSAGE;
00537
00538 if (ast_context_add_include(a->argv[5], a->argv[3], registrar)) {
00539 switch (errno) {
00540 case ENOMEM:
00541 ast_cli(a->fd, "Out of memory for context addition\n");
00542 break;
00543
00544 case EBUSY:
00545 ast_cli(a->fd, "Failed to lock context(s) list, please try again later\n");
00546 break;
00547
00548 case EEXIST:
00549 ast_cli(a->fd, "Context '%s' already included in '%s' context\n",
00550 a->argv[3], a->argv[5]);
00551 break;
00552
00553 case ENOENT:
00554 case EINVAL:
00555 ast_cli(a->fd, "There is no existence of context '%s'\n",
00556 errno == ENOENT ? a->argv[5] : a->argv[3]);
00557 break;
00558
00559 default:
00560 ast_cli(a->fd, "Failed to include '%s' in '%s' context\n",
00561 a->argv[3], a->argv[5]);
00562 break;
00563 }
00564 return CLI_FAILURE;
00565 }
00566
00567
00568 ast_cli(a->fd, "Context '%s' included in '%s' context\n",
00569 a->argv[3], a->argv[5]);
00570
00571 return CLI_SUCCESS;
00572 }
00573
00574 static char *complete_dialplan_add_include(struct ast_cli_args *a)
00575 {
00576 struct ast_context *c;
00577 int which = 0;
00578 char *ret = NULL;
00579 int len = strlen(a->word);
00580
00581 if (a->pos == 3) {
00582 if (ast_rdlock_contexts()) {
00583 ast_log(LOG_ERROR, "Failed to lock context list\n");
00584 return NULL;
00585 }
00586 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
00587 if (partial_match(ast_get_context_name(c), a->word, len) && ++which > a->n)
00588 ret = strdup(ast_get_context_name(c));
00589 ast_unlock_contexts();
00590 return ret;
00591 } else if (a->pos == 4) {
00592
00593 char *context, *dupline;
00594 struct ast_context *c;
00595 const char *s = skip_words(a->line, 3);
00596
00597 if (a->n != 0)
00598 return NULL;
00599
00600
00601 context = dupline = strdup(s);
00602 if (!context) {
00603 ast_log(LOG_ERROR, "Out of free memory\n");
00604 return strdup("into");
00605 }
00606 strsep(&dupline, " ");
00607
00608
00609 if (ast_rdlock_contexts()) {
00610 ast_log(LOG_ERROR, "Failed to lock context list\n");
00611
00612 ret = strdup("into");
00613 } else {
00614 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
00615 if (!strcmp(context, ast_get_context_name(c)))
00616 ret = strdup("into");
00617 ast_unlock_contexts();
00618 }
00619 free(context);
00620 return ret;
00621 } else if (a->pos == 5) {
00622 char *context, *dupline, *into;
00623 const char *s = skip_words(a->line, 3);
00624 context = dupline = strdup(s);
00625 if (!dupline) {
00626 ast_log(LOG_ERROR, "Out of free memory\n");
00627 return NULL;
00628 }
00629 strsep(&dupline, " ");
00630 into = strsep(&dupline, " ");
00631
00632 if (!strlen(context) || strcmp(into, "into")) {
00633 ast_log(LOG_ERROR, "bad context %s or missing into %s\n",
00634 context, into);
00635 goto error3;
00636 }
00637
00638 if (ast_rdlock_contexts()) {
00639 ast_log(LOG_ERROR, "Failed to lock context list\n");
00640 goto error3;
00641 }
00642
00643 for (c = NULL; (c = ast_walk_contexts(c)); )
00644 if (!strcmp(context, ast_get_context_name(c)))
00645 break;
00646 if (c) {
00647
00648 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
00649 if (!strcmp(context, ast_get_context_name(c)))
00650 continue;
00651 if (partial_match(ast_get_context_name(c), a->word, len) &&
00652 !lookup_ci(c, context) &&
00653 ++which > a->n)
00654 ret = strdup(ast_get_context_name(c));
00655 }
00656 } else {
00657 ast_log(LOG_ERROR, "context %s not found\n", context);
00658 }
00659 ast_unlock_contexts();
00660 error3:
00661 free(context);
00662 return ret;
00663 }
00664
00665 return NULL;
00666 }
00667
00668
00669
00670
00671 static char *handle_cli_dialplan_save(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00672 {
00673 char filename[256];
00674 struct ast_context *c;
00675 struct ast_config *cfg;
00676 struct ast_variable *v;
00677 int incomplete = 0;
00678 FILE *output;
00679 struct ast_flags config_flags = { 0 };
00680 const char *base, *slash, *file;
00681
00682 switch (cmd) {
00683 case CLI_INIT:
00684 e->command = "dialplan save";
00685 e->usage =
00686 "Usage: dialplan save [/path/to/extension/file]\n"
00687 " Save dialplan created by pbx_config module.\n"
00688 "\n"
00689 "Example: dialplan save (/etc/asterisk/extensions.conf)\n"
00690 " dialplan save /home/markster (/home/markster/extensions.conf)\n";
00691 return NULL;
00692 case CLI_GENERATE:
00693 return NULL;
00694 }
00695
00696 if (! (static_config && !write_protect_config)) {
00697 ast_cli(a->fd,
00698 "I can't save dialplan now, see '%s' example file.\n",
00699 config);
00700 return CLI_FAILURE;
00701 }
00702
00703 if (a->argc != 2 && a->argc != 3)
00704 return CLI_SHOWUSAGE;
00705
00706 if (ast_mutex_lock(&save_dialplan_lock)) {
00707 ast_cli(a->fd,
00708 "Failed to lock dialplan saving (another proccess saving?)\n");
00709 return CLI_FAILURE;
00710 }
00711
00712
00713
00714 if (a->argc == 3) {
00715 base = a->argv[2];
00716 if (!strstr(a->argv[2], ".conf")) {
00717
00718 slash = (*(a->argv[2] + strlen(a->argv[2]) -1) == '/') ? "/" : "";
00719 file = config;
00720 } else {
00721 slash = "";
00722 file = "";
00723 }
00724 } else {
00725
00726 base = ast_config_AST_CONFIG_DIR;
00727 slash = "/";
00728 file = config;
00729 }
00730 snprintf(filename, sizeof(filename), "%s%s%s", base, slash, config);
00731
00732 cfg = ast_config_load("extensions.conf", config_flags);
00733
00734
00735 if (ast_rdlock_contexts()) {
00736 ast_cli(a->fd, "Failed to lock contexts list\n");
00737 ast_mutex_unlock(&save_dialplan_lock);
00738 ast_config_destroy(cfg);
00739 return CLI_FAILURE;
00740 }
00741
00742
00743 if (!(output = fopen(filename, "wt"))) {
00744 ast_cli(a->fd, "Failed to create file '%s'\n",
00745 filename);
00746 ast_unlock_contexts();
00747 ast_mutex_unlock(&save_dialplan_lock);
00748 ast_config_destroy(cfg);
00749 return CLI_FAILURE;
00750 }
00751
00752
00753 fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\nextenpatternmatchnew=%s\n\n",
00754 static_config ? "yes" : "no",
00755 write_protect_config ? "yes" : "no",
00756 autofallthrough_config ? "yes" : "no",
00757 clearglobalvars_config ? "yes" : "no",
00758 extenpatternmatchnew_config ? "yes" : "no");
00759
00760 if ((v = ast_variable_browse(cfg, "globals"))) {
00761 fprintf(output, "[globals]\n");
00762 while(v) {
00763 fprintf(output, "%s => %s\n", v->name, v->value);
00764 v = v->next;
00765 }
00766 fprintf(output, "\n");
00767 }
00768
00769 ast_config_destroy(cfg);
00770
00771 #define PUT_CTX_HDR do { \
00772 if (!context_header_written) { \
00773 fprintf(output, "[%s]\n", ast_get_context_name(c)); \
00774 context_header_written = 1; \
00775 } \
00776 } while (0)
00777
00778
00779 for (c = NULL; (c = ast_walk_contexts(c)); ) {
00780 int context_header_written = 0;
00781 struct ast_exten *e, *last_written_e = NULL;
00782 struct ast_include *i;
00783 struct ast_ignorepat *ip;
00784 struct ast_sw *sw;
00785
00786
00787 if (ast_rdlock_context(c)) {
00788 incomplete = 1;
00789 continue;
00790 }
00791
00792
00793 if (!strcmp(ast_get_context_registrar(c), registrar)) {
00794 fprintf(output, "[%s]\n", ast_get_context_name(c));
00795 context_header_written = 1;
00796 }
00797
00798
00799 for (e = NULL; (e = ast_walk_context_extensions(c, e)); ) {
00800 struct ast_exten *p = NULL;
00801
00802
00803 while ( (p = ast_walk_extension_priorities(e, p)) ) {
00804 if (strcmp(ast_get_extension_registrar(p), registrar) != 0)
00805 continue;
00806
00807
00808 if (last_written_e != NULL &&
00809 strcmp(ast_get_extension_name(last_written_e),
00810 ast_get_extension_name(p)))
00811 fprintf(output, "\n");
00812 last_written_e = p;
00813
00814 PUT_CTX_HDR;
00815
00816 if (ast_get_extension_priority(p) == PRIORITY_HINT) {
00817 fprintf(output, "exten => %s,hint,%s\n",
00818 ast_get_extension_name(p),
00819 ast_get_extension_app(p));
00820 } else {
00821 const char *sep, *cid;
00822 const char *el = ast_get_extension_label(p);
00823 char label[128] = "";
00824
00825 if (ast_get_extension_matchcid(p)) {
00826 sep = "/";
00827 cid = ast_get_extension_cidmatch(p);
00828 } else
00829 sep = cid = "";
00830
00831 if (el && (snprintf(label, sizeof(label), "(%s)", el) != (strlen(el) + 2)))
00832 incomplete = 1;
00833
00834 fprintf(output, "exten => %s%s%s,%d%s,%s(%s)\n",
00835 ast_get_extension_name(p), (ast_strlen_zero(sep) ? "" : sep), (ast_strlen_zero(cid) ? "" : cid),
00836 ast_get_extension_priority(p), label,
00837 ast_get_extension_app(p), (ast_strlen_zero(ast_get_extension_app_data(p)) ? "" : (const char *)ast_get_extension_app_data(p)));
00838 }
00839 }
00840 }
00841
00842
00843 if (last_written_e)
00844 fprintf(output, "\n");
00845
00846
00847 for (i = NULL; (i = ast_walk_context_includes(c, i)) ; ) {
00848 if (strcmp(ast_get_include_registrar(i), registrar) != 0)
00849 continue;
00850 PUT_CTX_HDR;
00851 fprintf(output, "include => %s\n", ast_get_include_name(i));
00852 }
00853 if (ast_walk_context_includes(c, NULL))
00854 fprintf(output, "\n");
00855
00856
00857 for (sw = NULL; (sw = ast_walk_context_switches(c, sw)) ; ) {
00858 if (strcmp(ast_get_switch_registrar(sw), registrar) != 0)
00859 continue;
00860 PUT_CTX_HDR;
00861 fprintf(output, "switch => %s/%s\n",
00862 ast_get_switch_name(sw), ast_get_switch_data(sw));
00863 }
00864
00865 if (ast_walk_context_switches(c, NULL))
00866 fprintf(output, "\n");
00867
00868
00869 for (ip = NULL; (ip = ast_walk_context_ignorepats(c, ip)); ) {
00870 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) != 0)
00871 continue;
00872 PUT_CTX_HDR;
00873 fprintf(output, "ignorepat => %s\n",
00874 ast_get_ignorepat_name(ip));
00875 }
00876
00877 ast_unlock_context(c);
00878 }
00879
00880 ast_unlock_contexts();
00881 ast_mutex_unlock(&save_dialplan_lock);
00882 fclose(output);
00883
00884 if (incomplete) {
00885 ast_cli(a->fd, "Saved dialplan is incomplete\n");
00886 return CLI_FAILURE;
00887 }
00888
00889 ast_cli(a->fd, "Dialplan successfully saved into '%s'\n",
00890 filename);
00891 return CLI_SUCCESS;
00892 }
00893
00894
00895
00896
00897 static char *handle_cli_dialplan_add_extension(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00898 {
00899 char *whole_exten;
00900 char *exten, *prior;
00901 int iprior = -2;
00902 char *cidmatch, *app, *app_data;
00903 char *start, *end;
00904
00905 switch (cmd) {
00906 case CLI_INIT:
00907 e->command = "dialplan add extension";
00908 e->usage =
00909 "Usage: dialplan add extension <exten>,<priority>,<app>,<app-data>\n"
00910 " into <context> [replace]\n\n"
00911 " This command will add new extension into <context>. If there is an\n"
00912 " existence of extension with the same priority and last 'replace'\n"
00913 " arguments is given here we simply replace this extension.\n"
00914 "\n"
00915 "Example: dialplan add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n"
00916 " Now, you can dial 6123 and talk to Markster :)\n";
00917 return NULL;
00918 case CLI_GENERATE:
00919 return complete_dialplan_add_extension(a);
00920 }
00921
00922
00923 if (a->argc != 6 && a->argc != 7)
00924 return CLI_SHOWUSAGE;
00925 if (strcmp(a->argv[4], "into"))
00926 return CLI_SHOWUSAGE;
00927 if (a->argc == 7)
00928 if (strcmp(a->argv[6], "replace"))
00929 return CLI_SHOWUSAGE;
00930
00931
00932 whole_exten = a->argv[3];
00933 exten = strsep(&whole_exten,",");
00934 if (strchr(exten, '/')) {
00935 cidmatch = exten;
00936 strsep(&cidmatch,"/");
00937 } else {
00938 cidmatch = NULL;
00939 }
00940 prior = strsep(&whole_exten,",");
00941 if (prior) {
00942 if (!strcmp(prior, "hint")) {
00943 iprior = PRIORITY_HINT;
00944 } else {
00945 if (sscanf(prior, "%d", &iprior) != 1) {
00946 ast_cli(a->fd, "'%s' is not a valid priority\n", prior);
00947 prior = NULL;
00948 }
00949 }
00950 }
00951 app = whole_exten;
00952 if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
00953 *start = *end = '\0';
00954 app_data = start + 1;
00955 } else {
00956 if (app) {
00957 app_data = strchr(app, ',');
00958 if (app_data) {
00959 *app_data = '\0';
00960 app_data++;
00961 }
00962 } else
00963 app_data = NULL;
00964 }
00965
00966 if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT))
00967 return CLI_SHOWUSAGE;
00968
00969 if (!app_data)
00970 app_data="";
00971 if (ast_add_extension(a->argv[5], a->argc == 7 ? 1 : 0, exten, iprior, NULL, cidmatch, app,
00972 (void *)strdup(app_data), ast_free_ptr, registrar)) {
00973 switch (errno) {
00974 case ENOMEM:
00975 ast_cli(a->fd, "Out of free memory\n");
00976 break;
00977
00978 case EBUSY:
00979 ast_cli(a->fd, "Failed to lock context(s) list, please try again later\n");
00980 break;
00981
00982 case ENOENT:
00983 ast_cli(a->fd, "No existence of '%s' context\n", a->argv[5]);
00984 break;
00985
00986 case EEXIST:
00987 ast_cli(a->fd, "Extension %s@%s with priority %s already exists\n",
00988 exten, a->argv[5], prior);
00989 break;
00990
00991 default:
00992 ast_cli(a->fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
00993 exten, prior, app, app_data, a->argv[5]);
00994 break;
00995 }
00996 return CLI_FAILURE;
00997 }
00998
00999 if (a->argc == 7)
01000 ast_cli(a->fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
01001 exten, a->argv[5], prior, exten, prior, app, app_data);
01002 else
01003 ast_cli(a->fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
01004 exten, prior, app, app_data, a->argv[5]);
01005
01006 return CLI_SUCCESS;
01007 }
01008
01009
01010 static char *complete_dialplan_add_extension(struct ast_cli_args *a)
01011 {
01012 int which = 0;
01013
01014 if (a->pos == 4) {
01015 return (a->n == 0) ? strdup("into") : NULL;
01016 } else if (a->pos == 5) {
01017 struct ast_context *c = NULL;
01018 int len = strlen(a->word);
01019 char *res = NULL;
01020
01021
01022 if (ast_rdlock_contexts()) {
01023 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01024 return NULL;
01025 }
01026
01027
01028 while ( !res && (c = ast_walk_contexts(c)) )
01029 if (partial_match(ast_get_context_name(c), a->word, len) && ++which > a->n)
01030 res = strdup(ast_get_context_name(c));
01031 ast_unlock_contexts();
01032 return res;
01033 } else if (a->pos == 6) {
01034 return a->n == 0 ? strdup("replace") : NULL;
01035 }
01036 return NULL;
01037 }
01038
01039
01040
01041
01042 static char *handle_cli_dialplan_add_ignorepat(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01043 {
01044 switch (cmd) {
01045 case CLI_INIT:
01046 e->command = "dialplan add ignorepat";
01047 e->usage =
01048 "Usage: dialplan add ignorepat <pattern> into <context>\n"
01049 " This command adds a new ignore pattern into context <context>\n"
01050 "\n"
01051 "Example: dialplan add ignorepat _3XX into local\n";
01052 return NULL;
01053 case CLI_GENERATE:
01054 return complete_dialplan_add_ignorepat(a);
01055 }
01056
01057 if (a->argc != 6)
01058 return CLI_SHOWUSAGE;
01059
01060 if (strcmp(a->argv[4], "into"))
01061 return CLI_SHOWUSAGE;
01062
01063 if (ast_context_add_ignorepat(a->argv[5], a->argv[3], registrar)) {
01064 switch (errno) {
01065 case ENOMEM:
01066 ast_cli(a->fd, "Out of free memory\n");
01067 break;
01068
01069 case ENOENT:
01070 ast_cli(a->fd, "There is no existence of '%s' context\n", a->argv[5]);
01071 break;
01072
01073 case EEXIST:
01074 ast_cli(a->fd, "Ignore pattern '%s' already included in '%s' context\n",
01075 a->argv[3], a->argv[5]);
01076 break;
01077
01078 case EBUSY:
01079 ast_cli(a->fd, "Failed to lock context(s) list, please, try again later\n");
01080 break;
01081
01082 default:
01083 ast_cli(a->fd, "Failed to add ingore pattern '%s' into '%s' context\n",
01084 a->argv[3], a->argv[5]);
01085 break;
01086 }
01087 return CLI_FAILURE;
01088 }
01089
01090 ast_cli(a->fd, "Ignore pattern '%s' added into '%s' context\n",
01091 a->argv[3], a->argv[5]);
01092
01093 return CLI_SUCCESS;
01094 }
01095
01096 static char *complete_dialplan_add_ignorepat(struct ast_cli_args *a)
01097 {
01098 if (a->pos == 4)
01099 return a->n == 0 ? strdup("into") : NULL;
01100 else if (a->pos == 5) {
01101 struct ast_context *c;
01102 int which = 0;
01103 char *dupline, *ignorepat = NULL;
01104 const char *s;
01105 char *ret = NULL;
01106 int len = strlen(a->word);
01107
01108
01109 s = skip_words(a->line, 3);
01110 if (s == NULL)
01111 return NULL;
01112 dupline = strdup(s);
01113 if (!dupline) {
01114 ast_log(LOG_ERROR, "Malloc failure\n");
01115 return NULL;
01116 }
01117 ignorepat = strsep(&dupline, " ");
01118
01119 if (ast_rdlock_contexts()) {
01120 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
01121 return NULL;
01122 }
01123
01124 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
01125 int found = 0;
01126
01127 if (!partial_match(ast_get_context_name(c), a->word, len))
01128 continue;
01129 if (ignorepat)
01130 found = lookup_c_ip(c, ignorepat);
01131 if (!found && ++which > a->n)
01132 ret = strdup(ast_get_context_name(c));
01133 }
01134
01135 free(ignorepat);
01136 ast_unlock_contexts();
01137 return ret;
01138 }
01139
01140 return NULL;
01141 }
01142
01143 static char *handle_cli_dialplan_remove_ignorepat(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01144 {
01145 switch (cmd) {
01146 case CLI_INIT:
01147 e->command = "dialplan remove ignorepat";
01148 e->usage =
01149 "Usage: dialplan remove ignorepat <pattern> from <context>\n"
01150 " This command removes an ignore pattern from context <context>\n"
01151 "\n"
01152 "Example: dialplan remove ignorepat _3XX from local\n";
01153 return NULL;
01154 case CLI_GENERATE:
01155 return complete_dialplan_remove_ignorepat(a);
01156 }
01157
01158 if (a->argc != 6)
01159 return CLI_SHOWUSAGE;
01160
01161 if (strcmp(a->argv[4], "from"))
01162 return CLI_SHOWUSAGE;
01163
01164 if (ast_context_remove_ignorepat(a->argv[5], a->argv[3], registrar)) {
01165 switch (errno) {
01166 case EBUSY:
01167 ast_cli(a->fd, "Failed to lock context(s) list, please try again later\n");
01168 break;
01169
01170 case ENOENT:
01171 ast_cli(a->fd, "There is no existence of '%s' context\n", a->argv[5]);
01172 break;
01173
01174 case EINVAL:
01175 ast_cli(a->fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
01176 a->argv[3], a->argv[5]);
01177 break;
01178
01179 default:
01180 ast_cli(a->fd, "Failed to remove ignore pattern '%s' from '%s' context\n",
01181 a->argv[3], a->argv[5]);
01182 break;
01183 }
01184 return CLI_FAILURE;
01185 }
01186
01187 ast_cli(a->fd, "Ignore pattern '%s' removed from '%s' context\n",
01188 a->argv[3], a->argv[5]);
01189 return CLI_SUCCESS;
01190 }
01191
01192 static char *complete_dialplan_remove_ignorepat(struct ast_cli_args *a)
01193 {
01194 struct ast_context *c;
01195 int which = 0;
01196 char *ret = NULL;
01197
01198 if (a->pos == 3) {
01199 int len = strlen(a->word);
01200 if (ast_rdlock_contexts()) {
01201 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01202 return NULL;
01203 }
01204
01205 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
01206 struct ast_ignorepat *ip;
01207
01208 if (ast_rdlock_context(c))
01209 continue;
01210
01211 for (ip = NULL; !ret && (ip = ast_walk_context_ignorepats(c, ip));) {
01212 if (partial_match(ast_get_ignorepat_name(ip), a->word, len) && ++which > a->n) {
01213
01214 struct ast_context *cw = NULL;
01215 int found = 0;
01216 while ( (cw = ast_walk_contexts(cw)) && cw != c && !found) {
01217
01218 found = lookup_c_ip(cw, ast_get_ignorepat_name(ip));
01219 }
01220 if (!found)
01221 ret = strdup(ast_get_ignorepat_name(ip));
01222 }
01223 }
01224 ast_unlock_context(c);
01225 }
01226 ast_unlock_contexts();
01227 return ret;
01228 } else if (a->pos == 4) {
01229 return a->n == 0 ? strdup("from") : NULL;
01230 } else if (a->pos == 5) {
01231 char *dupline, *duplinet, *ignorepat;
01232 int len = strlen(a->word);
01233
01234 dupline = strdup(a->line);
01235 if (!dupline) {
01236 ast_log(LOG_WARNING, "Out of free memory\n");
01237 return NULL;
01238 }
01239
01240 duplinet = dupline;
01241 strsep(&duplinet, " ");
01242 strsep(&duplinet, " ");
01243 ignorepat = strsep(&duplinet, " ");
01244
01245 if (!ignorepat) {
01246 free(dupline);
01247 return NULL;
01248 }
01249
01250 if (ast_rdlock_contexts()) {
01251 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01252 free(dupline);
01253 return NULL;
01254 }
01255
01256 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
01257 if (ast_rdlock_context(c))
01258 continue;
01259 if (!partial_match(ast_get_context_name(c), a->word, len))
01260 continue;
01261 if (lookup_c_ip(c, ignorepat) && ++which > a->n)
01262 ret = strdup(ast_get_context_name(c));
01263 ast_unlock_context(c);
01264 }
01265 ast_unlock_contexts();
01266 free(dupline);
01267 return NULL;
01268 }
01269
01270 return NULL;
01271 }
01272
01273 static int pbx_load_module(void);
01274
01275 static char *handle_cli_dialplan_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
01276 {
01277 switch (cmd) {
01278 case CLI_INIT:
01279 e->command = "dialplan reload";
01280 e->usage =
01281 "Usage: dialplan reload\n"
01282 " Reload extensions.conf without reloading any other\n"
01283 " modules. This command does not delete global variables\n"
01284 " unless clearglobalvars is set to yes in extensions.conf\n";
01285 return NULL;
01286 case CLI_GENERATE:
01287 return NULL;
01288 }
01289
01290 if (a->argc != 2)
01291 return CLI_SHOWUSAGE;
01292
01293 if (clearglobalvars_config)
01294 pbx_builtin_clear_globals();
01295
01296 pbx_load_module();
01297 ast_cli(a->fd, "Dialplan reloaded.\n");
01298 return CLI_SUCCESS;
01299 }
01300
01301
01302
01303
01304 static struct ast_cli_entry cli_pbx_config[] = {
01305 AST_CLI_DEFINE(handle_cli_dialplan_add_extension, "Add new extension into context"),
01306 AST_CLI_DEFINE(handle_cli_dialplan_remove_extension, "Remove a specified extension"),
01307 AST_CLI_DEFINE(handle_cli_dialplan_add_ignorepat, "Add new ignore pattern"),
01308 AST_CLI_DEFINE(handle_cli_dialplan_remove_ignorepat, "Remove ignore pattern from context"),
01309 AST_CLI_DEFINE(handle_cli_dialplan_add_include, "Include context in other context"),
01310 AST_CLI_DEFINE(handle_cli_dialplan_remove_include, "Remove a specified include from context"),
01311 AST_CLI_DEFINE(handle_cli_dialplan_reload, "Reload extensions and *only* extensions")
01312 };
01313
01314 static struct ast_cli_entry cli_dialplan_save =
01315 AST_CLI_DEFINE(handle_cli_dialplan_save, "Save dialplan");
01316
01317
01318
01319
01320 static int unload_module(void)
01321 {
01322 if (static_config && !write_protect_config)
01323 ast_cli_unregister(&cli_dialplan_save);
01324 ast_cli_unregister_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry));
01325 ast_context_destroy(NULL, registrar);
01326 return 0;
01327 }
01328
01329 static int pbx_load_config(const char *config_file)
01330 {
01331 struct ast_config *cfg;
01332 char *end;
01333 char *label;
01334 #ifdef LOW_MEMORY
01335 char realvalue[256];
01336 #else
01337 char realvalue[8192];
01338 #endif
01339 int lastpri = -2;
01340 struct ast_context *con;
01341 struct ast_variable *v;
01342 const char *cxt;
01343 const char *aft;
01344 const char *newpm;
01345 struct ast_flags config_flags = { 0 };
01346 cfg = ast_config_load(config_file, config_flags);
01347 if (!cfg)
01348 return 0;
01349
01350
01351 static_config = ast_true(ast_variable_retrieve(cfg, "general", "static"));
01352 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", "writeprotect"));
01353 if ((aft = ast_variable_retrieve(cfg, "general", "autofallthrough")))
01354 autofallthrough_config = ast_true(aft);
01355 if ((newpm = ast_variable_retrieve(cfg, "general", "extenpatternmatchnew")))
01356 extenpatternmatchnew_config = ast_true(newpm);
01357 clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
01358
01359
01360 if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext")))
01361 ast_copy_string(userscontext, cxt, sizeof(userscontext));
01362 else
01363 ast_copy_string(userscontext, "default", sizeof(userscontext));
01364
01365 for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) {
01366 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
01367 pbx_builtin_setvar_helper(NULL, v->name, realvalue);
01368 }
01369 for (cxt = NULL; (cxt = ast_category_browse(cfg, cxt)); ) {
01370
01371 if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
01372 continue;
01373 con=ast_context_find_or_create(&local_contexts, local_table, cxt, registrar);
01374 if (con == NULL)
01375 continue;
01376
01377 for (v = ast_variable_browse(cfg, cxt); v; v = v->next) {
01378 if (!strcasecmp(v->name, "exten")) {
01379 char *tc = ast_strdup(v->value);
01380 if (tc) {
01381 int ipri = -2;
01382 char realext[256]="";
01383 char *plus, *firstp;
01384 char *pri, *appl, *data, *cidmatch;
01385 char *stringp = tc;
01386 char *ext = strsep(&stringp, ",");
01387 if (!ext)
01388 ext="";
01389 pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
01390 cidmatch = strchr(realext, '/');
01391 if (cidmatch) {
01392 *cidmatch++ = '\0';
01393 ast_shrink_phone_number(cidmatch);
01394 }
01395 pri = strsep(&stringp, ",");
01396 if (!pri)
01397 pri="";
01398 pri = ast_skip_blanks(pri);
01399 pri = ast_trim_blanks(pri);
01400 label = strchr(pri, '(');
01401 if (label) {
01402 *label++ = '\0';
01403 end = strchr(label, ')');
01404 if (end)
01405 *end = '\0';
01406 else
01407 ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
01408 }
01409 plus = strchr(pri, '+');
01410 if (plus)
01411 *plus++ = '\0';
01412 if (!strcmp(pri,"hint"))
01413 ipri=PRIORITY_HINT;
01414 else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
01415 if (lastpri > -2)
01416 ipri = lastpri + 1;
01417 else
01418 ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
01419 } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
01420 if (lastpri > -2)
01421 ipri = lastpri;
01422 else
01423 ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
01424 } else if (sscanf(pri, "%d", &ipri) != 1 &&
01425 (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
01426 ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
01427 ipri = 0;
01428 }
01429 appl = S_OR(stringp, "");
01430
01431 firstp = strchr(appl, '(');
01432 if (!firstp) {
01433
01434 data = "";
01435 } else {
01436 appl = strsep(&stringp, "(");
01437 data = stringp;
01438 end = strrchr(data, ')');
01439 if ((end = strrchr(data, ')'))) {
01440 *end = '\0';
01441 } else {
01442 ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
01443 }
01444 }
01445
01446 if (!data)
01447 data = "";
01448 appl = ast_skip_blanks(appl);
01449 if (ipri) {
01450 if (plus)
01451 ipri += atoi(plus);
01452 lastpri = ipri;
01453 if (!ast_opt_dont_warn && !strcmp(realext, "_."))
01454 ast_log(LOG_WARNING, "The use of '_.' for an extension is strongly discouraged and can have unexpected behavior. Please use '_X.' instead at line %d\n", v->lineno);
01455 if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free_ptr, registrar)) {
01456 ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
01457 }
01458 }
01459 free(tc);
01460 }
01461 } else if (!strcasecmp(v->name, "include")) {
01462 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
01463 if (ast_context_add_include2(con, realvalue, registrar))
01464 ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
01465 } else if (!strcasecmp(v->name, "ignorepat")) {
01466 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
01467 if (ast_context_add_ignorepat2(con, realvalue, registrar))
01468 ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
01469 } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
01470 char *stringp = realvalue;
01471 char *appl, *data;
01472
01473 if (!strcasecmp(v->name, "switch"))
01474 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
01475 else
01476 ast_copy_string(realvalue, v->value, sizeof(realvalue));
01477 appl = strsep(&stringp, "/");
01478 data = S_OR(stringp, "");
01479 if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar))
01480 ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
01481 } else {
01482 ast_log(LOG_WARNING, "==!!== Unknown directive: %s at line %d -- IGNORING!!!\n", v->name, v->lineno);
01483 }
01484 }
01485 }
01486 ast_config_destroy(cfg);
01487 return 1;
01488 }
01489
01490 static void append_interface(char *iface, int maxlen, char *add)
01491 {
01492 int len = strlen(iface);
01493 if (strlen(add) + len < maxlen - 2) {
01494 if (strlen(iface)) {
01495 iface[len] = '&';
01496 strcpy(iface + len + 1, add);
01497 } else
01498 strcpy(iface, add);
01499 }
01500 }
01501
01502 static void pbx_load_users(void)
01503 {
01504 struct ast_config *cfg;
01505 char *cat, *chan;
01506 const char *dahdichan;
01507 const char *hasexten;
01508 char tmp[256];
01509 char iface[256];
01510 char dahdicopy[256];
01511 char *c;
01512 int len;
01513 int hasvoicemail;
01514 int start, finish, x;
01515 struct ast_context *con = NULL;
01516 struct ast_flags config_flags = { 0 };
01517
01518 cfg = ast_config_load("users.conf", config_flags);
01519 if (!cfg)
01520 return;
01521
01522 for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
01523 if (!strcasecmp(cat, "general"))
01524 continue;
01525 iface[0] = '\0';
01526 len = sizeof(iface);
01527 if (ast_true(ast_config_option(cfg, cat, "hassip"))) {
01528 snprintf(tmp, sizeof(tmp), "SIP/%s", cat);
01529 append_interface(iface, sizeof(iface), tmp);
01530 }
01531 if (ast_true(ast_config_option(cfg, cat, "hasiax"))) {
01532 snprintf(tmp, sizeof(tmp), "IAX2/%s", cat);
01533 append_interface(iface, sizeof(iface), tmp);
01534 }
01535 if (ast_true(ast_config_option(cfg, cat, "hash323"))) {
01536 snprintf(tmp, sizeof(tmp), "H323/%s", cat);
01537 append_interface(iface, sizeof(iface), tmp);
01538 }
01539 hasexten = ast_config_option(cfg, cat, "hasexten");
01540 if (hasexten && !ast_true(hasexten))
01541 continue;
01542 hasvoicemail = ast_true(ast_config_option(cfg, cat, "hasvoicemail"));
01543 dahdichan = ast_variable_retrieve(cfg, cat, "dahdichan");
01544 if (!dahdichan)
01545 dahdichan = ast_variable_retrieve(cfg, "general", "dahdichan");
01546 if (!ast_strlen_zero(dahdichan)) {
01547 ast_copy_string(dahdicopy, dahdichan, sizeof(dahdicopy));
01548 c = dahdicopy;
01549 chan = strsep(&c, ",");
01550 while (chan) {
01551 if (sscanf(chan, "%d-%d", &start, &finish) == 2) {
01552
01553 } else if (sscanf(chan, "%d", &start)) {
01554
01555 finish = start;
01556 } else {
01557 start = 0; finish = 0;
01558 }
01559 if (finish < start) {
01560 x = finish;
01561 finish = start;
01562 start = x;
01563 }
01564 for (x = start; x <= finish; x++) {
01565 snprintf(tmp, sizeof(tmp), "DAHDI/%d", x);
01566 append_interface(iface, sizeof(iface), tmp);
01567 }
01568 chan = strsep(&c, ",");
01569 }
01570 }
01571 if (!ast_strlen_zero(iface)) {
01572
01573
01574 if (!con)
01575 con = ast_context_find_or_create(&local_contexts, local_table, userscontext, registrar);
01576
01577 if (!con) {
01578 ast_log(LOG_ERROR, "Can't find/create user context '%s'\n", userscontext);
01579 return;
01580 }
01581
01582
01583 ast_add_extension2(con, 0, cat, -1, NULL, NULL, iface, NULL, NULL, registrar);
01584
01585 if (hasvoicemail) {
01586 snprintf(tmp, sizeof(tmp), "stdexten,%s,${HINT}", cat);
01587 ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Macro", strdup(tmp), ast_free_ptr, registrar);
01588 } else {
01589 ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Dial", strdup("${HINT}"), ast_free_ptr, registrar);
01590 }
01591 }
01592 }
01593 ast_config_destroy(cfg);
01594 }
01595
01596 static int pbx_load_module(void)
01597 {
01598 struct ast_context *con;
01599
01600 if (!local_table)
01601 local_table = ast_hashtab_create(17, ast_hashtab_compare_contexts, ast_hashtab_resize_java, ast_hashtab_newsize_java, ast_hashtab_hash_contexts, 0);
01602
01603 if (!pbx_load_config(config))
01604 return AST_MODULE_LOAD_DECLINE;
01605
01606 pbx_load_users();
01607
01608 ast_merge_contexts_and_delete(&local_contexts, local_table, registrar);
01609 local_table = NULL;
01610 local_contexts = NULL;
01611
01612 for (con = NULL; (con = ast_walk_contexts(con));)
01613 ast_context_verify_includes(con);
01614
01615 pbx_set_autofallthrough(autofallthrough_config);
01616 pbx_set_extenpatternmatchnew(extenpatternmatchnew_config);
01617
01618 return AST_MODULE_LOAD_SUCCESS;
01619 }
01620
01621 static int load_module(void)
01622 {
01623 if (pbx_load_module())
01624 return AST_MODULE_LOAD_DECLINE;
01625
01626 if (static_config && !write_protect_config)
01627 ast_cli_register(&cli_dialplan_save);
01628 ast_cli_register_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry));
01629
01630 return AST_MODULE_LOAD_SUCCESS;
01631 }
01632
01633 static int reload(void)
01634 {
01635 if (clearglobalvars_config)
01636 pbx_builtin_clear_globals();
01637 return pbx_load_module();
01638 }
01639
01640 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Text Extension Configuration",
01641 .load = load_module,
01642 .unload = unload_module,
01643 .reload = reload,
01644 );