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: 285365 $")
00029
00030 #include <sys/types.h>
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033 #include <string.h>
00034 #include <ctype.h>
00035 #include <errno.h>
00036
00037 #include "asterisk/pbx.h"
00038 #include "asterisk/config.h"
00039 #include "asterisk/options.h"
00040 #include "asterisk/module.h"
00041 #include "asterisk/logger.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/callerid.h"
00044
00045 static char *config = "extensions.conf";
00046 static char *registrar = "pbx_config";
00047 static char userscontext[AST_MAX_EXTENSION] = "default";
00048
00049 static int static_config = 0;
00050 static int write_protect_config = 1;
00051 static int autofallthrough_config = 1;
00052 static int clearglobalvars_config = 0;
00053
00054 AST_MUTEX_DEFINE_STATIC(save_dialplan_lock);
00055
00056 static struct ast_context *local_contexts = NULL;
00057
00058
00059
00060
00061 static char context_add_extension_help[] =
00062 "Usage: dialplan add extension <exten>,<priority>,<app>,<app-data>\n"
00063 " into <context> [replace]\n\n"
00064 " This command will add new extension into <context>. If there is an\n"
00065 " existence of extension with the same priority and last 'replace'\n"
00066 " arguments is given here we simply replace this extension.\n"
00067 "\n"
00068 "Example: dialplan add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n"
00069 " Now, you can dial 6123 and talk to Markster :)\n";
00070
00071 static char context_remove_extension_help[] =
00072 "Usage: dialplan remove extension exten[/cid]@context [priority]\n"
00073 " Remove an extension from a given context. If a priority\n"
00074 " is given, only that specific priority from the given extension\n"
00075 " will be removed.\n";
00076
00077 static char context_add_ignorepat_help[] =
00078 "Usage: dialplan add ignorepat <pattern> into <context>\n"
00079 " This command adds a new ignore pattern into context <context>\n"
00080 "\n"
00081 "Example: dialplan add ignorepat _3XX into local\n";
00082
00083 static char context_remove_ignorepat_help[] =
00084 "Usage: dialplan remove ignorepat <pattern> from <context>\n"
00085 " This command removes an ignore pattern from context <context>\n"
00086 "\n"
00087 "Example: dialplan remove ignorepat _3XX from local\n";
00088
00089 static char context_add_include_help[] =
00090 "Usage: dialplan add include <context> into <context>\n"
00091 " Include a context in another context.\n";
00092
00093 static char context_remove_include_help[] =
00094 "Usage: dialplan remove include <context> from <context>\n"
00095 " Remove an included context from another context.\n";
00096
00097 static char save_dialplan_help[] =
00098 "Usage: dialplan save [/path/to/extension/file]\n"
00099 " Save dialplan created by pbx_config module.\n"
00100 "\n"
00101 "Example: dialplan save (/etc/asterisk/extensions.conf)\n"
00102 " dialplan save /home/markster (/home/markster/extensions.conf)\n";
00103
00104 static char reload_extensions_help[] =
00105 "Usage: dialplan reload\n"
00106 " reload extensions.conf without reloading any other modules\n"
00107 " This command does not delete global variables unless\n"
00108 " clearglobalvars is set to yes in extensions.conf\n";
00109
00110
00111
00112
00113
00114
00115
00116
00117 static int handle_context_dont_include_deprecated(int fd, int argc, char *argv[])
00118 {
00119 if (argc != 5)
00120 return RESULT_SHOWUSAGE;
00121
00122 if (strcmp(argv[3], "into"))
00123 return RESULT_SHOWUSAGE;
00124
00125 if (!ast_context_remove_include(argv[4], argv[2], registrar)) {
00126 ast_cli(fd, "We are not including '%s' into '%s' now\n",
00127 argv[2], argv[4]);
00128 return RESULT_SUCCESS;
00129 }
00130
00131 ast_cli(fd, "Failed to remove '%s' include from '%s' context\n",
00132 argv[2], argv[4]);
00133 return RESULT_FAILURE;
00134 }
00135
00136 static int handle_context_remove_include(int fd, int argc, char *argv[])
00137 {
00138 if (argc != 6) {
00139 return RESULT_SHOWUSAGE;
00140 }
00141
00142 if (strcmp(argv[4], "from")) {
00143 return RESULT_SHOWUSAGE;
00144 }
00145
00146 if (!ast_context_remove_include(argv[5], argv[3], registrar)) {
00147 ast_cli(fd, "The dialplan no longer includes '%s' into '%s'\n",
00148 argv[3], argv[5]);
00149 return RESULT_SUCCESS;
00150 }
00151
00152 ast_cli(fd, "Failed to remove '%s' include from '%s' context\n",
00153 argv[3], argv[5]);
00154
00155 return RESULT_FAILURE;
00156 }
00157
00158
00159 static int lookup_ci(struct ast_context *c, const char *name)
00160 {
00161 struct ast_include *i = NULL;
00162
00163 if (ast_lock_context(c))
00164 return 0;
00165 while ( (i = ast_walk_context_includes(c, i)) )
00166 if (!strcmp(name, ast_get_include_name(i)))
00167 break;
00168 ast_unlock_context(c);
00169 return i ? -1 : 0;
00170 }
00171
00172
00173 static int lookup_c_ip(struct ast_context *c, const char *name)
00174 {
00175 struct ast_ignorepat *ip = NULL;
00176
00177 if (ast_lock_context(c))
00178 return 0;
00179 while ( (ip = ast_walk_context_ignorepats(c, ip)) )
00180 if (!strcmp(name, ast_get_ignorepat_name(ip)))
00181 break;
00182 ast_unlock_context(c);
00183 return ip ? -1 : 0;
00184 }
00185
00186
00187 static const char *skip_words(const char *p, int n)
00188 {
00189 int in_blank = 0;
00190 for (;n && *p; p++) {
00191 if (isblank(*p) && !in_blank) {
00192 n--;
00193 in_blank = 1;
00194 } else if ( in_blank) {
00195 in_blank = 0;
00196 }
00197 }
00198 return p;
00199 }
00200
00201
00202 static int partial_match(const char *s, const char *word, int len)
00203 {
00204 return (len == 0 || !strncmp(s, word, len));
00205 }
00206
00207
00208
00209
00210 static int split_ec(const char *src, char **ext, char ** const ctx, char ** const cid)
00211 {
00212 char *i, *c, *e = ast_strdup(src);
00213
00214 if (e == NULL)
00215 return -1;
00216
00217 *ext = e;
00218 c = strchr(e, '@');
00219 if (c == NULL)
00220 *ctx = "";
00221 else {
00222 *c++ = '\0';
00223 *ctx = c;
00224 if (strchr(c, '@')) {
00225 free(e);
00226 return -1;
00227 }
00228 }
00229 if (cid && (i = strchr(e, '/'))) {
00230 *i++ = '\0';
00231 *cid = i;
00232 } else if (cid) {
00233
00234 *cid = NULL;
00235 }
00236 return 0;
00237 }
00238
00239
00240 static char *complete_context_dont_include_deprecated(const char *line, const char *word,
00241 int pos, int state)
00242 {
00243 int which = 0;
00244 char *res = NULL;
00245 int len = strlen(word);
00246 struct ast_context *c = NULL;
00247
00248 if (pos == 2) {
00249 if (ast_wrlock_contexts()) {
00250 ast_log(LOG_ERROR, "Failed to lock context list\n");
00251 return NULL;
00252 }
00253
00254 while (!res && (c = ast_walk_contexts(c))) {
00255 struct ast_include *i = NULL;
00256
00257 if (ast_lock_context(c))
00258 continue;
00259
00260 while ( !res && (i = ast_walk_context_includes(c, i)) ) {
00261 const char *i_name = ast_get_include_name(i);
00262 struct ast_context *nc = NULL;
00263 int already_served = 0;
00264
00265 if (!partial_match(i_name, word, len))
00266 continue;
00267
00268
00269
00270
00271
00272
00273 while ( (nc = ast_walk_contexts(nc)) && nc != c && !already_served)
00274 already_served = lookup_ci(nc, i_name);
00275
00276 if (!already_served && ++which > state)
00277 res = strdup(i_name);
00278 }
00279 ast_unlock_context(c);
00280 }
00281
00282 ast_unlock_contexts();
00283 return res;
00284 } else if (pos == 3) {
00285
00286
00287
00288
00289 char *context, *dupline;
00290 const char *s = skip_words(line, 2);
00291
00292 if (state > 0)
00293 return NULL;
00294 context = dupline = strdup(s);
00295 if (!dupline) {
00296 ast_log(LOG_ERROR, "Out of free memory\n");
00297 return NULL;
00298 }
00299 strsep(&dupline, " ");
00300
00301 if (ast_rdlock_contexts()) {
00302 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
00303 free(context);
00304 return NULL;
00305 }
00306
00307
00308 while (!res && (c = ast_walk_contexts(c)))
00309 if (lookup_ci(c, context))
00310 res = strdup("in");
00311 ast_unlock_contexts();
00312 if (!res)
00313 ast_log(LOG_WARNING, "%s not included anywhere\n", context);
00314 free(context);
00315 return res;
00316 } else if (pos == 4) {
00317
00318
00319
00320 char *context, *dupline, *in;
00321 const char *s = skip_words(line, 2);
00322 context = dupline = strdup(s);
00323 if (!dupline) {
00324 ast_log(LOG_ERROR, "Out of free memory\n");
00325 return NULL;
00326 }
00327
00328 strsep(&dupline, " ");
00329
00330
00331 in = strsep(&dupline, " ");
00332 if (!in || strcmp(in, "in")) {
00333 free(context);
00334 return NULL;
00335 }
00336
00337 if (ast_rdlock_contexts()) {
00338 ast_log(LOG_ERROR, "Failed to lock context list\n");
00339 free(context);
00340 return NULL;
00341 }
00342
00343
00344 c = NULL;
00345 while ( !res && (c = ast_walk_contexts(c))) {
00346 const char *c_name = ast_get_context_name(c);
00347 if (!partial_match(c_name, word, len))
00348 continue;
00349
00350 if (lookup_ci(c, context) && ++which > state)
00351 res = strdup(c_name);
00352 }
00353 ast_unlock_contexts();
00354 free(context);
00355 return res;
00356 }
00357
00358 return NULL;
00359 }
00360
00361 static char *complete_context_remove_include(const char *line, const char *word,
00362 int pos, int state)
00363 {
00364 int which = 0;
00365 char *res = NULL;
00366 int len = strlen(word);
00367 struct ast_context *c = NULL;
00368
00369 if (pos == 3) {
00370 if (ast_rdlock_contexts()) {
00371 ast_log(LOG_ERROR, "Failed to lock context list\n");
00372 return NULL;
00373 }
00374
00375 while (!res && (c = ast_walk_contexts(c))) {
00376 struct ast_include *i = NULL;
00377
00378 if (ast_lock_context(c))
00379 continue;
00380
00381 while ( !res && (i = ast_walk_context_includes(c, i)) ) {
00382 const char *i_name = ast_get_include_name(i);
00383 struct ast_context *nc = NULL;
00384 int already_served = 0;
00385
00386 if (!partial_match(i_name, word, len))
00387 continue;
00388
00389
00390
00391
00392
00393
00394 while ( (nc = ast_walk_contexts(nc)) && nc != c && !already_served)
00395 already_served = lookup_ci(nc, i_name);
00396
00397 if (!already_served && ++which > state)
00398 res = strdup(i_name);
00399 }
00400 ast_unlock_context(c);
00401 }
00402
00403 ast_unlock_contexts();
00404 return res;
00405 } else if (pos == 4) {
00406
00407
00408
00409
00410 char *context, *dupline;
00411 const char *s = skip_words(line, 3);
00412
00413 if (state > 0)
00414 return NULL;
00415 context = dupline = strdup(s);
00416 if (!dupline) {
00417 ast_log(LOG_ERROR, "Out of free memory\n");
00418 return NULL;
00419 }
00420 strsep(&dupline, " ");
00421
00422 if (ast_rdlock_contexts()) {
00423 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
00424 free(context);
00425 return NULL;
00426 }
00427
00428
00429 while (!res && (c = ast_walk_contexts(c)))
00430 if (lookup_ci(c, context))
00431 res = strdup("from");
00432 ast_unlock_contexts();
00433 if (!res)
00434 ast_log(LOG_WARNING, "%s not included anywhere\n", context);
00435 free(context);
00436 return res;
00437 } else if (pos == 5) {
00438
00439
00440
00441 char *context, *dupline, *from;
00442 const char *s = skip_words(line, 3);
00443 context = dupline = strdup(s);
00444 if (!dupline) {
00445 ast_log(LOG_ERROR, "Out of free memory\n");
00446 return NULL;
00447 }
00448
00449 strsep(&dupline, " ");
00450
00451
00452 from = strsep(&dupline, " ");
00453 if (!from || strcmp(from, "from")) {
00454 free(context);
00455 return NULL;
00456 }
00457
00458 if (ast_rdlock_contexts()) {
00459 ast_log(LOG_ERROR, "Failed to lock context list\n");
00460 free(context);
00461 return NULL;
00462 }
00463
00464
00465 c = NULL;
00466 while ( !res && (c = ast_walk_contexts(c))) {
00467 const char *c_name = ast_get_context_name(c);
00468 if (!partial_match(c_name, word, len))
00469 continue;
00470
00471 if (lookup_ci(c, context) && ++which > state)
00472 res = strdup(c_name);
00473 }
00474 ast_unlock_contexts();
00475 free(context);
00476 return res;
00477 }
00478
00479 return NULL;
00480 }
00481
00482
00483
00484
00485 static int handle_context_remove_extension_deprecated(int fd, int argc, char *argv[])
00486 {
00487 int removing_priority = 0;
00488 char *exten, *context, *cid;
00489 int ret = RESULT_FAILURE;
00490
00491 if (argc != 4 && argc != 3) return RESULT_SHOWUSAGE;
00492
00493
00494
00495
00496 if (argc == 4) {
00497 char *c = argv[3];
00498
00499
00500
00501
00502
00503 if (!strcmp("hint", c))
00504 removing_priority = PRIORITY_HINT;
00505 else {
00506 while (*c && isdigit(*c))
00507 c++;
00508 if (*c) {
00509 ast_cli(fd, "Invalid priority '%s'\n", argv[3]);
00510 return RESULT_FAILURE;
00511 }
00512 removing_priority = atoi(argv[3]);
00513 }
00514
00515 if (removing_priority == 0) {
00516 ast_cli(fd, "If you want to remove whole extension, please " \
00517 "omit priority argument\n");
00518 return RESULT_FAILURE;
00519 }
00520 }
00521
00522
00523
00524
00525
00526 if (split_ec(argv[2], &exten, &context, &cid))
00527 return RESULT_FAILURE;
00528 if ((!strlen(exten)) || (!(strlen(context)))) {
00529 ast_cli(fd, "Missing extension or context name in second argument '%s'\n",
00530 argv[2]);
00531 free(exten);
00532 return RESULT_FAILURE;
00533 }
00534
00535 if (!ast_context_remove_extension_callerid(context, exten, removing_priority,
00536
00537 cid ? cid : (removing_priority ? "" : NULL), cid ? 1 : 0, registrar)) {
00538 if (!removing_priority)
00539 ast_cli(fd, "Whole extension %s@%s removed\n",
00540 exten, context);
00541 else
00542 ast_cli(fd, "Extension %s@%s with priority %d removed\n",
00543 exten, context, removing_priority);
00544
00545 ret = RESULT_SUCCESS;
00546 } else {
00547 ast_cli(fd, "Failed to remove extension %s@%s\n", exten, context);
00548 ret = RESULT_FAILURE;
00549 }
00550 free(exten);
00551 return ret;
00552 }
00553
00554 static int handle_context_remove_extension(int fd, int argc, char *argv[])
00555 {
00556 int removing_priority = 0;
00557 char *exten, *context, *cid;
00558 int ret = RESULT_FAILURE;
00559
00560 if (argc != 5 && argc != 4) return RESULT_SHOWUSAGE;
00561
00562
00563
00564
00565 if (argc == 5) {
00566 char *c = argv[4];
00567
00568
00569
00570
00571
00572 if (!strcmp("hint", c))
00573 removing_priority = PRIORITY_HINT;
00574 else {
00575 while (*c && isdigit(*c))
00576 c++;
00577 if (*c) {
00578 ast_cli(fd, "Invalid priority '%s'\n", argv[4]);
00579 return RESULT_FAILURE;
00580 }
00581 removing_priority = atoi(argv[4]);
00582 }
00583
00584 if (removing_priority == 0) {
00585 ast_cli(fd, "If you want to remove whole extension, please " \
00586 "omit priority argument\n");
00587 return RESULT_FAILURE;
00588 }
00589 }
00590
00591
00592
00593
00594
00595 if (split_ec(argv[3], &exten, &context, &cid))
00596 return RESULT_FAILURE;
00597 if ((!strlen(exten)) || (!(strlen(context)))) {
00598 ast_cli(fd, "Missing extension or context name in third argument '%s'\n",
00599 argv[3]);
00600 free(exten);
00601 return RESULT_FAILURE;
00602 }
00603
00604 if (!ast_context_remove_extension_callerid(context, exten, removing_priority,
00605
00606 cid ? cid : (removing_priority ? "" : NULL), cid ? 1 : 0, registrar)) {
00607 if (!removing_priority)
00608 ast_cli(fd, "Whole extension %s@%s removed\n",
00609 exten, context);
00610 else
00611 ast_cli(fd, "Extension %s@%s with priority %d removed\n",
00612 exten, context, removing_priority);
00613
00614 ret = RESULT_SUCCESS;
00615 } else {
00616 ast_cli(fd, "Failed to remove extension %s@%s\n", exten, context);
00617 ret = RESULT_FAILURE;
00618 }
00619 free(exten);
00620 return ret;
00621 }
00622
00623 static char *complete_context_remove_extension_deprecated(const char *line, const char *word, int pos,
00624 int state)
00625 {
00626 char *ret = NULL;
00627 int which = 0;
00628
00629 if (pos == 2) {
00630 struct ast_context *c = NULL;
00631 char *context = NULL, *exten = NULL, *cid = NULL;
00632 int le = 0;
00633 int lc = 0;
00634 int lcid = 0;
00635
00636 lc = split_ec(word, &exten, &context, &cid);
00637 if (lc)
00638 return NULL;
00639 le = strlen(exten);
00640 lc = strlen(context);
00641 lcid = cid ? strlen(cid) : -1;
00642
00643 if (ast_rdlock_contexts()) {
00644 ast_log(LOG_ERROR, "Failed to lock context list\n");
00645 goto error2;
00646 }
00647
00648
00649 while ( (c = ast_walk_contexts(c)) ) {
00650 struct ast_exten *e = NULL;
00651
00652 if (!partial_match(ast_get_context_name(c), context, lc))
00653 continue;
00654 while ( (e = ast_walk_context_extensions(c, e)) ) {
00655 if ( !strchr(word, '/') ||
00656 (!strchr(word, '@') && partial_match(ast_get_extension_cidmatch(e), cid, lcid)) ||
00657 (strchr(word, '@') && !strcmp(ast_get_extension_cidmatch(e), cid))) {
00658 if ( ((strchr(word, '/') || strchr(word, '@')) && !strcmp(ast_get_extension_name(e), exten)) ||
00659 (!strchr(word, '/') && !strchr(word, '@') && partial_match(ast_get_extension_name(e), exten, le))) {
00660 if (++which > state) {
00661
00662 if (ast_get_extension_matchcid(e) && (!strchr(word, '@') || strchr(word, '/'))) {
00663 if (asprintf(&ret, "%s/%s@%s", ast_get_extension_name(e), ast_get_extension_cidmatch(e), ast_get_context_name(c)) < 0) {
00664 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00665 ret = NULL;
00666 }
00667 break;
00668 } else if (!ast_get_extension_matchcid(e) && !strchr(word, '/')) {
00669 if (asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c)) < 0) {
00670 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00671 ret = NULL;
00672 }
00673 break;
00674 }
00675 }
00676 }
00677 }
00678 }
00679 if (e)
00680 break;
00681 }
00682
00683 ast_unlock_contexts();
00684 error2:
00685 if (exten)
00686 free(exten);
00687 } else if (pos == 3) {
00688 char *exten = NULL, *context, *cid, *p;
00689 struct ast_context *c;
00690 int le, lc, lcid, len;
00691 const char *s = skip_words(line, 2);
00692 int i = split_ec(s, &exten, &context, &cid);
00693
00694 if (i)
00695 goto error3;
00696 if ( (p = strchr(exten, ' ')) )
00697 *p = '\0';
00698 if ( (p = strchr(context, ' ')) )
00699 *p = '\0';
00700 le = strlen(exten);
00701 lc = strlen(context);
00702 if (cid == NULL) {
00703 lcid = 0;
00704 } else {
00705 lcid = strlen(cid);
00706 }
00707 len = strlen(word);
00708 if (le == 0 || lc == 0)
00709 goto error3;
00710
00711 if (ast_rdlock_contexts()) {
00712 ast_log(LOG_ERROR, "Failed to lock context list\n");
00713 goto error3;
00714 }
00715
00716
00717 c = NULL;
00718 while ( (c = ast_walk_contexts(c)) ) {
00719
00720 struct ast_exten *e;
00721 if (strcmp(ast_get_context_name(c), context) != 0)
00722 continue;
00723
00724 e = NULL;
00725 while ( (e = ast_walk_context_extensions(c, e)) ) {
00726 struct ast_exten *priority;
00727 char buffer[10];
00728
00729 if (cid && strcmp(ast_get_extension_cidmatch(e), cid) != 0) {
00730 continue;
00731 }
00732 if (strcmp(ast_get_extension_name(e), exten) != 0)
00733 continue;
00734
00735 priority = NULL;
00736 while ( !ret && (priority = ast_walk_extension_priorities(e, priority)) ) {
00737 snprintf(buffer, sizeof(buffer), "%u", ast_get_extension_priority(priority));
00738 if (partial_match(buffer, word, len) && ++which > state)
00739 ret = strdup(buffer);
00740 }
00741 break;
00742 }
00743 break;
00744 }
00745 ast_unlock_contexts();
00746 error3:
00747 if (exten)
00748 free(exten);
00749 }
00750 return ret;
00751 }
00752
00753 static char *complete_context_remove_extension(const char *line, const char *word, int pos,
00754 int state)
00755 {
00756 char *ret = NULL;
00757 int which = 0;
00758
00759 if (pos == 3) {
00760 struct ast_context *c = NULL;
00761 char *context = NULL, *exten = NULL, *cid = NULL;
00762 int le = 0;
00763 int lc = 0;
00764 int lcid = 0;
00765
00766 lc = split_ec(word, &exten, &context, &cid);
00767 if (lc) {
00768 return NULL;
00769 }
00770 le = strlen(exten);
00771 lc = strlen(context);
00772 lcid = cid ? strlen(cid) : -1;
00773
00774 if (ast_rdlock_contexts()) {
00775 ast_log(LOG_ERROR, "Failed to lock context list\n");
00776 goto error2;
00777 }
00778
00779
00780 while ( (c = ast_walk_contexts(c)) ) {
00781 struct ast_exten *e = NULL;
00782
00783 if (!partial_match(ast_get_context_name(c), context, lc))
00784 continue;
00785 while ( (e = ast_walk_context_extensions(c, e)) ) {
00786 if ( !strchr(word, '/') ||
00787 (!strchr(word, '@') && partial_match(ast_get_extension_cidmatch(e), cid, lcid)) ||
00788 (strchr(word, '@') && !strcmp(ast_get_extension_cidmatch(e), cid))) {
00789 if ( ((strchr(word, '/') || strchr(word, '@')) && !strcmp(ast_get_extension_name(e), exten)) ||
00790 (!strchr(word, '/') && !strchr(word, '@') && partial_match(ast_get_extension_name(e), exten, le))) {
00791 if (++which > state) {
00792
00793 if (ast_get_extension_matchcid(e) && (!strchr(word, '@') || strchr(word, '/'))) {
00794 if (asprintf(&ret, "%s/%s@%s", ast_get_extension_name(e), ast_get_extension_cidmatch(e), ast_get_context_name(c)) < 0) {
00795 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00796 ret = NULL;
00797 }
00798 break;
00799 } else if (!ast_get_extension_matchcid(e) && !strchr(word, '/')) {
00800 if (asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c)) < 0) {
00801 ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
00802 ret = NULL;
00803 }
00804 break;
00805 }
00806 }
00807 }
00808 }
00809 }
00810 if (e)
00811 break;
00812 }
00813 ast_unlock_contexts();
00814 error2:
00815 if (exten)
00816 free(exten);
00817 } else if (pos == 4) {
00818 char *exten = NULL, *context, *cid, *p;
00819 struct ast_context *c;
00820 int le, lc, lcid, len;
00821 const char *s = skip_words(line, 3);
00822 int i = split_ec(s, &exten, &context, &cid);
00823
00824 if (i)
00825 goto error3;
00826 if ( (p = strchr(exten, ' ')) )
00827 *p = '\0';
00828 if ( (p = strchr(context, ' ')) )
00829 *p = '\0';
00830 le = strlen(exten);
00831 lc = strlen(context);
00832 lcid = cid ? strlen(cid) : -1;
00833 len = strlen(word);
00834 if (le == 0 || lc == 0)
00835 goto error3;
00836
00837 if (ast_rdlock_contexts()) {
00838 ast_log(LOG_ERROR, "Failed to lock context list\n");
00839 goto error3;
00840 }
00841
00842
00843 c = NULL;
00844 while ( (c = ast_walk_contexts(c)) ) {
00845
00846 struct ast_exten *e;
00847 if (strcmp(ast_get_context_name(c), context) != 0)
00848 continue;
00849
00850 e = NULL;
00851 while ( (e = ast_walk_context_extensions(c, e)) ) {
00852 struct ast_exten *priority;
00853 char buffer[10];
00854
00855 if (cid && strcmp(ast_get_extension_cidmatch(e), cid) != 0) {
00856 continue;
00857 }
00858 if (strcmp(ast_get_extension_name(e), exten) != 0)
00859 continue;
00860
00861 priority = NULL;
00862 while ( !ret && (priority = ast_walk_extension_priorities(e, priority)) ) {
00863 snprintf(buffer, sizeof(buffer), "%u", ast_get_extension_priority(priority));
00864 if (partial_match(buffer, word, len) && ++which > state)
00865 ret = strdup(buffer);
00866 }
00867 break;
00868 }
00869 break;
00870 }
00871 ast_unlock_contexts();
00872 error3:
00873 if (exten)
00874 free(exten);
00875 }
00876 return ret;
00877 }
00878
00879
00880
00881
00882 static int handle_context_add_include_deprecated(int fd, int argc, char *argv[])
00883 {
00884 if (argc != 5)
00885 return RESULT_SHOWUSAGE;
00886
00887
00888 if (strcmp(argv[3], "in") && strcmp(argv[3], "into"))
00889 return RESULT_SHOWUSAGE;
00890
00891 if (ast_context_add_include(argv[4], argv[2], registrar)) {
00892 switch (errno) {
00893 case ENOMEM:
00894 ast_cli(fd, "Out of memory for context addition\n");
00895 break;
00896
00897 case EBUSY:
00898 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
00899 break;
00900
00901 case EEXIST:
00902 ast_cli(fd, "Context '%s' already included in '%s' context\n",
00903 argv[2], argv[4]);
00904 break;
00905
00906 case ENOENT:
00907 case EINVAL:
00908 ast_cli(fd, "There is no existence of context '%s'\n",
00909 errno == ENOENT ? argv[4] : argv[2]);
00910 break;
00911
00912 default:
00913 ast_cli(fd, "Failed to include '%s' in '%s' context\n",
00914 argv[2], argv[4]);
00915 break;
00916 }
00917 return RESULT_FAILURE;
00918 }
00919
00920
00921 ast_cli(fd, "Context '%s' included in '%s' context\n",
00922 argv[2], argv[4]);
00923
00924 return RESULT_SUCCESS;
00925 }
00926
00927 static int handle_context_add_include(int fd, int argc, char *argv[])
00928 {
00929 if (argc != 6)
00930 return RESULT_SHOWUSAGE;
00931
00932
00933 if (strcmp(argv[4], "into"))
00934 return RESULT_SHOWUSAGE;
00935
00936 if (ast_context_add_include(argv[5], argv[3], registrar)) {
00937 switch (errno) {
00938 case ENOMEM:
00939 ast_cli(fd, "Out of memory for context addition\n");
00940 break;
00941
00942 case EBUSY:
00943 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
00944 break;
00945
00946 case EEXIST:
00947 ast_cli(fd, "Context '%s' already included in '%s' context\n",
00948 argv[3], argv[5]);
00949 break;
00950
00951 case ENOENT:
00952 case EINVAL:
00953 ast_cli(fd, "There is no existence of context '%s'\n",
00954 errno == ENOENT ? argv[5] : argv[3]);
00955 break;
00956
00957 default:
00958 ast_cli(fd, "Failed to include '%s' in '%s' context\n",
00959 argv[3], argv[5]);
00960 break;
00961 }
00962 return RESULT_FAILURE;
00963 }
00964
00965
00966 ast_cli(fd, "Context '%s' included in '%s' context\n",
00967 argv[3], argv[5]);
00968
00969 return RESULT_SUCCESS;
00970 }
00971
00972 static char *complete_context_add_include_deprecated(const char *line, const char *word, int pos,
00973 int state)
00974 {
00975 struct ast_context *c;
00976 int which = 0;
00977 char *ret = NULL;
00978 int len = strlen(word);
00979
00980 if (pos == 2) {
00981 if (ast_rdlock_contexts()) {
00982 ast_log(LOG_ERROR, "Failed to lock context list\n");
00983 return NULL;
00984 }
00985 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
00986 if (partial_match(ast_get_context_name(c), word, len) && ++which > state)
00987 ret = strdup(ast_get_context_name(c));
00988 ast_unlock_contexts();
00989 return ret;
00990 } else if (pos == 3) {
00991
00992 char *context, *dupline;
00993 struct ast_context *c;
00994 const char *s = skip_words(line, 2);
00995
00996 if (state != 0)
00997 return NULL;
00998
00999
01000 context = dupline = strdup(s);
01001 if (!context) {
01002 ast_log(LOG_ERROR, "Out of free memory\n");
01003 return strdup("in");
01004 }
01005 strsep(&dupline, " ");
01006
01007
01008 if (ast_rdlock_contexts()) {
01009 ast_log(LOG_ERROR, "Failed to lock context list\n");
01010
01011 ret = strdup("in");
01012 } else {
01013 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
01014 if (!strcmp(context, ast_get_context_name(c)))
01015 ret = strdup("in");
01016 ast_unlock_contexts();
01017 }
01018 free(context);
01019 return ret;
01020 } else if (pos == 4) {
01021 char *context, *dupline, *in;
01022 const char *s = skip_words(line, 2);
01023 context = dupline = strdup(s);
01024 if (!dupline) {
01025 ast_log(LOG_ERROR, "Out of free memory\n");
01026 return NULL;
01027 }
01028 strsep(&dupline, " ");
01029 in = strsep(&dupline, " ");
01030
01031 if (!strlen(context) || strcmp(in, "in")) {
01032 ast_log(LOG_ERROR, "bad context %s or missing in %s\n",
01033 context, in);
01034 goto error3;
01035 }
01036
01037 if (ast_rdlock_contexts()) {
01038 ast_log(LOG_ERROR, "Failed to lock context list\n");
01039 goto error3;
01040 }
01041
01042 for (c = NULL; (c = ast_walk_contexts(c)); )
01043 if (!strcmp(context, ast_get_context_name(c)))
01044 break;
01045 if (c) {
01046
01047 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
01048 if (!strcmp(context, ast_get_context_name(c)))
01049 continue;
01050 if (partial_match(ast_get_context_name(c), word, len) &&
01051 !lookup_ci(c, context) &&
01052 ++which > state)
01053 ret = strdup(ast_get_context_name(c));
01054 }
01055 } else {
01056 ast_log(LOG_ERROR, "context %s not found\n", context);
01057 }
01058 ast_unlock_contexts();
01059 error3:
01060 free(context);
01061 return ret;
01062 }
01063
01064 return NULL;
01065 }
01066
01067 static char *complete_context_add_include(const char *line, const char *word, int pos,
01068 int state)
01069 {
01070 struct ast_context *c;
01071 int which = 0;
01072 char *ret = NULL;
01073 int len = strlen(word);
01074
01075 if (pos == 3) {
01076 if (ast_rdlock_contexts()) {
01077 ast_log(LOG_ERROR, "Failed to lock context list\n");
01078 return NULL;
01079 }
01080 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
01081 if (partial_match(ast_get_context_name(c), word, len) && ++which > state)
01082 ret = strdup(ast_get_context_name(c));
01083 ast_unlock_contexts();
01084 return ret;
01085 } else if (pos == 4) {
01086
01087 char *context, *dupline;
01088 struct ast_context *c;
01089 const char *s = skip_words(line, 3);
01090
01091 if (state != 0)
01092 return NULL;
01093
01094
01095 context = dupline = strdup(s);
01096 if (!context) {
01097 ast_log(LOG_ERROR, "Out of free memory\n");
01098 return strdup("into");
01099 }
01100 strsep(&dupline, " ");
01101
01102
01103 if (ast_rdlock_contexts()) {
01104 ast_log(LOG_ERROR, "Failed to lock context list\n");
01105
01106 ret = strdup("into");
01107 } else {
01108 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
01109 if (!strcmp(context, ast_get_context_name(c)))
01110 ret = strdup("into");
01111 ast_unlock_contexts();
01112 }
01113 free(context);
01114 return ret;
01115 } else if (pos == 5) {
01116 char *context, *dupline, *into;
01117 const char *s = skip_words(line, 3);
01118 context = dupline = strdup(s);
01119 if (!dupline) {
01120 ast_log(LOG_ERROR, "Out of free memory\n");
01121 return NULL;
01122 }
01123 strsep(&dupline, " ");
01124 into = strsep(&dupline, " ");
01125
01126 if (!strlen(context) || strcmp(into, "into")) {
01127 ast_log(LOG_ERROR, "bad context %s or missing into %s\n",
01128 context, into);
01129 goto error3;
01130 }
01131
01132 if (ast_rdlock_contexts()) {
01133 ast_log(LOG_ERROR, "Failed to lock context list\n");
01134 goto error3;
01135 }
01136
01137 for (c = NULL; (c = ast_walk_contexts(c)); )
01138 if (!strcmp(context, ast_get_context_name(c)))
01139 break;
01140 if (c) {
01141
01142 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
01143 if (!strcmp(context, ast_get_context_name(c)))
01144 continue;
01145 if (partial_match(ast_get_context_name(c), word, len) &&
01146 !lookup_ci(c, context) &&
01147 ++which > state)
01148 ret = strdup(ast_get_context_name(c));
01149 }
01150 } else {
01151 ast_log(LOG_ERROR, "context %s not found\n", context);
01152 }
01153 ast_unlock_contexts();
01154 error3:
01155 free(context);
01156 return ret;
01157 }
01158
01159 return NULL;
01160 }
01161
01162
01163
01164
01165 static int handle_save_dialplan(int fd, int argc, char *argv[])
01166 {
01167 char filename[256];
01168 struct ast_context *c;
01169 struct ast_config *cfg;
01170 struct ast_variable *v;
01171 int incomplete = 0;
01172 FILE *output;
01173
01174 const char *base, *slash, *file;
01175
01176 if (! (static_config && !write_protect_config)) {
01177 ast_cli(fd,
01178 "I can't save dialplan now, see '%s' example file.\n",
01179 config);
01180 return RESULT_FAILURE;
01181 }
01182
01183 if (argc != 2 && argc != 3)
01184 return RESULT_SHOWUSAGE;
01185
01186 if (ast_mutex_lock(&save_dialplan_lock)) {
01187 ast_cli(fd,
01188 "Failed to lock dialplan saving (another proccess saving?)\n");
01189 return RESULT_FAILURE;
01190 }
01191
01192
01193
01194 if (argc == 3) {
01195 base = argv[2];
01196 if (!strstr(argv[2], ".conf")) {
01197
01198 slash = (*(argv[2] + strlen(argv[2]) -1) == '/') ? "/" : "";
01199 file = config;
01200 } else {
01201 slash = "";
01202 file = "";
01203 }
01204 } else {
01205
01206 base = ast_config_AST_CONFIG_DIR;
01207 slash = "/";
01208 file = config;
01209 }
01210 snprintf(filename, sizeof(filename), "%s%s%s", base, slash, config);
01211
01212 cfg = ast_config_load("extensions.conf");
01213
01214
01215 if (ast_rdlock_contexts()) {
01216 ast_cli(fd, "Failed to lock contexts list\n");
01217 ast_mutex_unlock(&save_dialplan_lock);
01218 ast_config_destroy(cfg);
01219 return RESULT_FAILURE;
01220 }
01221
01222
01223 if (!(output = fopen(filename, "wt"))) {
01224 ast_cli(fd, "Failed to create file '%s'\n",
01225 filename);
01226 ast_unlock_contexts();
01227 ast_mutex_unlock(&save_dialplan_lock);
01228 ast_config_destroy(cfg);
01229 return RESULT_FAILURE;
01230 }
01231
01232
01233 fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\npriorityjumping=%s\n\n",
01234 static_config ? "yes" : "no",
01235 write_protect_config ? "yes" : "no",
01236 autofallthrough_config ? "yes" : "no",
01237 clearglobalvars_config ? "yes" : "no",
01238 ast_true(ast_variable_retrieve(cfg, "general", "priorityjumping")) ? "yes" : "no");
01239
01240 if ((v = ast_variable_browse(cfg, "globals"))) {
01241 fprintf(output, "[globals]\n");
01242 while(v) {
01243 fprintf(output, "%s => %s\n", v->name, v->value);
01244 v = v->next;
01245 }
01246 fprintf(output, "\n");
01247 }
01248
01249 ast_config_destroy(cfg);
01250
01251 #define PUT_CTX_HDR do { \
01252 if (!context_header_written) { \
01253 fprintf(output, "[%s]\n", ast_get_context_name(c)); \
01254 context_header_written = 1; \
01255 } \
01256 } while (0)
01257
01258
01259 for (c = NULL; (c = ast_walk_contexts(c)); ) {
01260 int context_header_written = 0;
01261 struct ast_exten *e, *last_written_e = NULL;
01262 struct ast_include *i;
01263 struct ast_ignorepat *ip;
01264 struct ast_sw *sw;
01265
01266
01267 if (ast_lock_context(c)) {
01268 incomplete = 1;
01269 continue;
01270 }
01271
01272
01273 if (!strcmp(ast_get_context_registrar(c), registrar)) {
01274 fprintf(output, "[%s]\n", ast_get_context_name(c));
01275 context_header_written = 1;
01276 }
01277
01278
01279 for (e = NULL; (e = ast_walk_context_extensions(c, e)); ) {
01280 struct ast_exten *p = NULL;
01281
01282
01283 while ( (p = ast_walk_extension_priorities(e, p)) ) {
01284 if (strcmp(ast_get_extension_registrar(p), registrar) != 0)
01285 continue;
01286
01287
01288 if (last_written_e != NULL &&
01289 strcmp(ast_get_extension_name(last_written_e),
01290 ast_get_extension_name(p)))
01291 fprintf(output, "\n");
01292 last_written_e = p;
01293
01294 PUT_CTX_HDR;
01295
01296 if (ast_get_extension_priority(p)==PRIORITY_HINT) {
01297 fprintf(output, "exten => %s,hint,%s\n",
01298 ast_get_extension_name(p),
01299 ast_get_extension_app(p));
01300 } else {
01301 const char *sep, *cid;
01302 char *tempdata = "";
01303 char *s;
01304 const char *el = ast_get_extension_label(p);
01305 char label[128] = "";
01306
01307 s = ast_get_extension_app_data(p);
01308 if (s) {
01309 char *t;
01310 tempdata = alloca(strlen(tempdata) * 2 + 1);
01311
01312 for (t = tempdata; *s; s++, t++) {
01313 if (*s == '|')
01314 *t = ',';
01315 else {
01316 if (*s == ',' || *s == ';')
01317 *t++ = '\\';
01318 *t = *s;
01319 }
01320 }
01321
01322 *t = *s;
01323 }
01324
01325 if (ast_get_extension_matchcid(p)) {
01326 sep = "/";
01327 cid = ast_get_extension_cidmatch(p);
01328 } else
01329 sep = cid = "";
01330
01331 if (el && (snprintf(label, sizeof(label), "(%s)", el) != (strlen(el) + 2)))
01332 incomplete = 1;
01333
01334 fprintf(output, "exten => %s%s%s,%d%s,%s(%s)\n",
01335 ast_get_extension_name(p), (ast_strlen_zero(sep) ? "" : sep), (ast_strlen_zero(cid) ? "" : cid),
01336 ast_get_extension_priority(p), label,
01337 ast_get_extension_app(p), (ast_strlen_zero(tempdata) ? "" : tempdata));
01338 }
01339 }
01340 }
01341
01342
01343 if (last_written_e)
01344 fprintf(output, "\n");
01345
01346
01347 for (i = NULL; (i = ast_walk_context_includes(c, i)) ; ) {
01348 if (strcmp(ast_get_include_registrar(i), registrar) != 0)
01349 continue;
01350 PUT_CTX_HDR;
01351 fprintf(output, "include => %s\n", ast_get_include_name(i));
01352 }
01353 if (ast_walk_context_includes(c, NULL))
01354 fprintf(output, "\n");
01355
01356
01357 for (sw = NULL; (sw = ast_walk_context_switches(c, sw)) ; ) {
01358 if (strcmp(ast_get_switch_registrar(sw), registrar) != 0)
01359 continue;
01360 PUT_CTX_HDR;
01361 fprintf(output, "switch => %s/%s\n",
01362 ast_get_switch_name(sw), ast_get_switch_data(sw));
01363 }
01364
01365 if (ast_walk_context_switches(c, NULL))
01366 fprintf(output, "\n");
01367
01368
01369 for (ip = NULL; (ip = ast_walk_context_ignorepats(c, ip)); ) {
01370 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) != 0)
01371 continue;
01372 PUT_CTX_HDR;
01373 fprintf(output, "ignorepat => %s\n",
01374 ast_get_ignorepat_name(ip));
01375 }
01376
01377 ast_unlock_context(c);
01378 }
01379
01380 ast_unlock_contexts();
01381 ast_mutex_unlock(&save_dialplan_lock);
01382 fclose(output);
01383
01384 if (incomplete) {
01385 ast_cli(fd, "Saved dialplan is incomplete\n");
01386 return RESULT_FAILURE;
01387 }
01388
01389 ast_cli(fd, "Dialplan successfully saved into '%s'\n",
01390 filename);
01391 return RESULT_SUCCESS;
01392 }
01393
01394
01395
01396
01397 static int handle_context_add_extension_deprecated(int fd, int argc, char *argv[])
01398 {
01399 char *whole_exten;
01400 char *exten, *prior;
01401 int iprior = -2;
01402 char *cidmatch, *app, *app_data;
01403 char *start, *end;
01404
01405
01406 if (argc != 5 && argc != 6)
01407 return RESULT_SHOWUSAGE;
01408 if (strcmp(argv[3], "into"))
01409 return RESULT_SHOWUSAGE;
01410 if (argc == 6) if (strcmp(argv[5], "replace")) return RESULT_SHOWUSAGE;
01411
01412
01413 whole_exten = argv[2];
01414 exten = strsep(&whole_exten,",");
01415 if (strchr(exten, '/')) {
01416 cidmatch = exten;
01417 strsep(&cidmatch,"/");
01418 } else {
01419 cidmatch = NULL;
01420 }
01421 prior = strsep(&whole_exten,",");
01422 if (prior) {
01423 if (!strcmp(prior, "hint")) {
01424 iprior = PRIORITY_HINT;
01425 } else {
01426 if (sscanf(prior, "%30d", &iprior) != 1) {
01427 ast_cli(fd, "'%s' is not a valid priority\n", prior);
01428 prior = NULL;
01429 }
01430 }
01431 }
01432 app = whole_exten;
01433 if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
01434 *start = *end = '\0';
01435 app_data = start + 1;
01436 ast_process_quotes_and_slashes(app_data, ',', '|');
01437 } else {
01438 if (app) {
01439 app_data = strchr(app, ',');
01440 if (app_data) {
01441 *app_data = '\0';
01442 app_data++;
01443 }
01444 } else
01445 app_data = NULL;
01446 }
01447
01448 if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT))
01449 return RESULT_SHOWUSAGE;
01450
01451 if (!app_data)
01452 app_data="";
01453 if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, iprior, NULL, cidmatch, app,
01454 (void *)strdup(app_data), ast_free_ptr, registrar)) {
01455 switch (errno) {
01456 case ENOMEM:
01457 ast_cli(fd, "Out of free memory\n");
01458 break;
01459
01460 case EBUSY:
01461 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
01462 break;
01463
01464 case ENOENT:
01465 ast_cli(fd, "No existence of '%s' context\n", argv[4]);
01466 break;
01467
01468 case EEXIST:
01469 ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
01470 exten, argv[4], prior);
01471 break;
01472
01473 default:
01474 ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
01475 exten, prior, app, app_data, argv[4]);
01476 break;
01477 }
01478 return RESULT_FAILURE;
01479 }
01480
01481 if (argc == 6)
01482 ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
01483 exten, argv[4], prior, exten, prior, app, app_data);
01484 else
01485 ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
01486 exten, prior, app, app_data, argv[4]);
01487
01488 return RESULT_SUCCESS;
01489 }
01490 static int handle_context_add_extension(int fd, int argc, char *argv[])
01491 {
01492 char *whole_exten;
01493 char *exten, *prior;
01494 int iprior = -2;
01495 char *cidmatch, *app, *app_data;
01496 char *start, *end;
01497
01498
01499 if (argc != 6 && argc != 7)
01500 return RESULT_SHOWUSAGE;
01501 if (strcmp(argv[4], "into"))
01502 return RESULT_SHOWUSAGE;
01503 if (argc == 7) if (strcmp(argv[6], "replace")) return RESULT_SHOWUSAGE;
01504
01505
01506 whole_exten = argv[3];
01507 exten = strsep(&whole_exten,",");
01508 if (strchr(exten, '/')) {
01509 cidmatch = exten;
01510 strsep(&cidmatch,"/");
01511 } else {
01512 cidmatch = NULL;
01513 }
01514 prior = strsep(&whole_exten,",");
01515 if (prior) {
01516 if (!strcmp(prior, "hint")) {
01517 iprior = PRIORITY_HINT;
01518 } else {
01519 if (sscanf(prior, "%30d", &iprior) != 1) {
01520 ast_cli(fd, "'%s' is not a valid priority\n", prior);
01521 prior = NULL;
01522 }
01523 }
01524 }
01525 app = whole_exten;
01526 if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
01527 *start = *end = '\0';
01528 app_data = start + 1;
01529 ast_process_quotes_and_slashes(app_data, ',', '|');
01530 } else {
01531 if (app) {
01532 app_data = strchr(app, ',');
01533 if (app_data) {
01534 *app_data = '\0';
01535 app_data++;
01536 }
01537 } else
01538 app_data = NULL;
01539 }
01540
01541 if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT))
01542 return RESULT_SHOWUSAGE;
01543
01544 if (!app_data)
01545 app_data="";
01546 if (ast_add_extension(argv[5], argc == 7 ? 1 : 0, exten, iprior, NULL, cidmatch, app,
01547 (void *)strdup(app_data), ast_free_ptr, registrar)) {
01548 switch (errno) {
01549 case ENOMEM:
01550 ast_cli(fd, "Out of free memory\n");
01551 break;
01552
01553 case EBUSY:
01554 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
01555 break;
01556
01557 case ENOENT:
01558 ast_cli(fd, "No existence of '%s' context\n", argv[5]);
01559 break;
01560
01561 case EEXIST:
01562 ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
01563 exten, argv[5], prior);
01564 break;
01565
01566 default:
01567 ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
01568 exten, prior, app, app_data, argv[5]);
01569 break;
01570 }
01571 return RESULT_FAILURE;
01572 }
01573
01574 if (argc == 7)
01575 ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
01576 exten, argv[5], prior, exten, prior, app, app_data);
01577 else
01578 ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
01579 exten, prior, app, app_data, argv[5]);
01580
01581 return RESULT_SUCCESS;
01582 }
01583
01584
01585 static char *complete_context_add_extension_deprecated(const char *line, const char *word, int pos, int state)
01586 {
01587 int which = 0;
01588
01589 if (pos == 3) {
01590 return (state == 0) ? strdup("into") : NULL;
01591 } else if (pos == 4) {
01592 struct ast_context *c = NULL;
01593 int len = strlen(word);
01594 char *res = NULL;
01595
01596
01597 if (ast_rdlock_contexts()) {
01598 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01599 return NULL;
01600 }
01601
01602
01603 while ( !res && (c = ast_walk_contexts(c)) )
01604 if (partial_match(ast_get_context_name(c), word, len) && ++which > state)
01605 res = strdup(ast_get_context_name(c));
01606 ast_unlock_contexts();
01607 return res;
01608 } else if (pos == 5) {
01609 return state == 0 ? strdup("replace") : NULL;
01610 }
01611 return NULL;
01612 }
01613
01614 static char *complete_context_add_extension(const char *line, const char *word, int pos, int state)
01615 {
01616 int which = 0;
01617
01618 if (pos == 4) {
01619 return (state == 0) ? strdup("into") : NULL;
01620 } else if (pos == 5) {
01621 struct ast_context *c = NULL;
01622 int len = strlen(word);
01623 char *res = NULL;
01624
01625
01626 if (ast_rdlock_contexts()) {
01627 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01628 return NULL;
01629 }
01630
01631
01632 while ( !res && (c = ast_walk_contexts(c)) )
01633 if (partial_match(ast_get_context_name(c), word, len) && ++which > state)
01634 res = strdup(ast_get_context_name(c));
01635 ast_unlock_contexts();
01636 return res;
01637 } else if (pos == 6) {
01638 return state == 0 ? strdup("replace") : NULL;
01639 }
01640 return NULL;
01641 }
01642
01643
01644
01645
01646 static int handle_context_add_ignorepat_deprecated(int fd, int argc, char *argv[])
01647 {
01648 if (argc != 5)
01649 return RESULT_SHOWUSAGE;
01650 if (strcmp(argv[3], "into"))
01651 return RESULT_SHOWUSAGE;
01652
01653 if (ast_context_add_ignorepat(argv[4], argv[2], registrar)) {
01654 switch (errno) {
01655 case ENOMEM:
01656 ast_cli(fd, "Out of free memory\n");
01657 break;
01658
01659 case ENOENT:
01660 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
01661 break;
01662
01663 case EEXIST:
01664 ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
01665 argv[2], argv[4]);
01666 break;
01667
01668 case EBUSY:
01669 ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
01670 break;
01671
01672 default:
01673 ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
01674 argv[2], argv[4]);
01675 break;
01676 }
01677 return RESULT_FAILURE;
01678 }
01679
01680 ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
01681 argv[2], argv[4]);
01682 return RESULT_SUCCESS;
01683 }
01684
01685 static int handle_context_add_ignorepat(int fd, int argc, char *argv[])
01686 {
01687 if (argc != 6)
01688 return RESULT_SHOWUSAGE;
01689 if (strcmp(argv[4], "into"))
01690 return RESULT_SHOWUSAGE;
01691
01692 if (ast_context_add_ignorepat(argv[5], argv[3], registrar)) {
01693 switch (errno) {
01694 case ENOMEM:
01695 ast_cli(fd, "Out of free memory\n");
01696 break;
01697
01698 case ENOENT:
01699 ast_cli(fd, "There is no existence of '%s' context\n", argv[5]);
01700 break;
01701
01702 case EEXIST:
01703 ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
01704 argv[3], argv[5]);
01705 break;
01706
01707 case EBUSY:
01708 ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
01709 break;
01710
01711 default:
01712 ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
01713 argv[3], argv[5]);
01714 break;
01715 }
01716 return RESULT_FAILURE;
01717 }
01718
01719 ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
01720 argv[3], argv[5]);
01721 return RESULT_SUCCESS;
01722 }
01723
01724 static char *complete_context_add_ignorepat_deprecated(const char *line, const char *word,
01725 int pos, int state)
01726 {
01727 if (pos == 3)
01728 return state == 0 ? strdup("into") : NULL;
01729 else if (pos == 4) {
01730 struct ast_context *c;
01731 int which = 0;
01732 char *dupline, *ignorepat = NULL;
01733 const char *s;
01734 char *ret = NULL;
01735 int len = strlen(word);
01736
01737
01738 s = skip_words(line, 2);
01739 if (s == NULL)
01740 return NULL;
01741 dupline = strdup(s);
01742 if (!dupline) {
01743 ast_log(LOG_ERROR, "Malloc failure\n");
01744 return NULL;
01745 }
01746 ignorepat = strsep(&dupline, " ");
01747
01748 if (ast_rdlock_contexts()) {
01749 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
01750 return NULL;
01751 }
01752
01753 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
01754 int found = 0;
01755
01756 if (!partial_match(ast_get_context_name(c), word, len))
01757 continue;
01758 if (ignorepat)
01759 found = lookup_c_ip(c, ignorepat);
01760 if (!found && ++which > state)
01761 ret = strdup(ast_get_context_name(c));
01762 }
01763
01764 if (ignorepat)
01765 free(ignorepat);
01766 ast_unlock_contexts();
01767 return ret;
01768 }
01769
01770 return NULL;
01771 }
01772
01773 static char *complete_context_add_ignorepat(const char *line, const char *word,
01774 int pos, int state)
01775 {
01776 if (pos == 4)
01777 return state == 0 ? strdup("into") : NULL;
01778 else if (pos == 5) {
01779 struct ast_context *c;
01780 int which = 0;
01781 char *dupline, *ignorepat = NULL;
01782 const char *s;
01783 char *ret = NULL;
01784 int len = strlen(word);
01785
01786
01787 s = skip_words(line, 3);
01788 if (s == NULL)
01789 return NULL;
01790 dupline = strdup(s);
01791 if (!dupline) {
01792 ast_log(LOG_ERROR, "Malloc failure\n");
01793 return NULL;
01794 }
01795 ignorepat = strsep(&dupline, " ");
01796
01797 if (ast_rdlock_contexts()) {
01798 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
01799 return NULL;
01800 }
01801
01802 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
01803 int found = 0;
01804
01805 if (!partial_match(ast_get_context_name(c), word, len))
01806 continue;
01807 if (ignorepat)
01808 found = lookup_c_ip(c, ignorepat);
01809 if (!found && ++which > state)
01810 ret = strdup(ast_get_context_name(c));
01811 }
01812
01813 if (ignorepat)
01814 free(ignorepat);
01815 ast_unlock_contexts();
01816 return ret;
01817 }
01818
01819 return NULL;
01820 }
01821
01822 static int handle_context_remove_ignorepat_deprecated(int fd, int argc, char *argv[])
01823 {
01824 if (argc != 5)
01825 return RESULT_SHOWUSAGE;
01826 if (strcmp(argv[3], "from"))
01827 return RESULT_SHOWUSAGE;
01828
01829 if (ast_context_remove_ignorepat(argv[4], argv[2], registrar)) {
01830 switch (errno) {
01831 case EBUSY:
01832 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
01833 break;
01834
01835 case ENOENT:
01836 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
01837 break;
01838
01839 case EINVAL:
01840 ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
01841 argv[2], argv[4]);
01842 break;
01843
01844 default:
01845 ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n", argv[2], argv[4]);
01846 break;
01847 }
01848 return RESULT_FAILURE;
01849 }
01850
01851 ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
01852 argv[2], argv[4]);
01853 return RESULT_SUCCESS;
01854 }
01855
01856 static int handle_context_remove_ignorepat(int fd, int argc, char *argv[])
01857 {
01858 if (argc != 6)
01859 return RESULT_SHOWUSAGE;
01860 if (strcmp(argv[4], "from"))
01861 return RESULT_SHOWUSAGE;
01862
01863 if (ast_context_remove_ignorepat(argv[5], argv[3], registrar)) {
01864 switch (errno) {
01865 case EBUSY:
01866 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
01867 break;
01868
01869 case ENOENT:
01870 ast_cli(fd, "There is no existence of '%s' context\n", argv[5]);
01871 break;
01872
01873 case EINVAL:
01874 ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
01875 argv[3], argv[5]);
01876 break;
01877
01878 default:
01879 ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n", argv[3], argv[5]);
01880 break;
01881 }
01882 return RESULT_FAILURE;
01883 }
01884
01885 ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
01886 argv[3], argv[5]);
01887 return RESULT_SUCCESS;
01888 }
01889
01890 static char *complete_context_remove_ignorepat_deprecated(const char *line, const char *word,
01891 int pos, int state)
01892 {
01893 struct ast_context *c;
01894 int which = 0;
01895 char *ret = NULL;
01896
01897 if (pos == 2) {
01898 int len = strlen(word);
01899 if (ast_rdlock_contexts()) {
01900 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01901 return NULL;
01902 }
01903
01904 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
01905 struct ast_ignorepat *ip;
01906
01907 if (ast_lock_context(c))
01908 continue;
01909
01910 for (ip = NULL; !ret && (ip = ast_walk_context_ignorepats(c, ip));) {
01911 if (partial_match(ast_get_ignorepat_name(ip), word, len) && ++which > state) {
01912
01913 struct ast_context *cw = NULL;
01914 int found = 0;
01915 while ( (cw = ast_walk_contexts(cw)) && cw != c && !found) {
01916
01917 found = lookup_c_ip(cw, ast_get_ignorepat_name(ip));
01918 }
01919 if (!found)
01920 ret = strdup(ast_get_ignorepat_name(ip));
01921 }
01922 }
01923 ast_unlock_context(c);
01924 }
01925 ast_unlock_contexts();
01926 return ret;
01927 } else if (pos == 3) {
01928 return state == 0 ? strdup("from") : NULL;
01929 } else if (pos == 4) {
01930 char *dupline, *duplinet, *ignorepat;
01931 int len = strlen(word);
01932
01933 dupline = strdup(line);
01934 if (!dupline) {
01935 ast_log(LOG_WARNING, "Out of free memory\n");
01936 return NULL;
01937 }
01938
01939 duplinet = dupline;
01940 strsep(&duplinet, " ");
01941 strsep(&duplinet, " ");
01942 ignorepat = strsep(&duplinet, " ");
01943
01944 if (!ignorepat) {
01945 free(dupline);
01946 return NULL;
01947 }
01948
01949 if (ast_rdlock_contexts()) {
01950 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01951 free(dupline);
01952 return NULL;
01953 }
01954
01955 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
01956 if (ast_lock_context(c))
01957 continue;
01958 if (!partial_match(ast_get_context_name(c), word, len))
01959 continue;
01960 if (lookup_c_ip(c, ignorepat) && ++which > state)
01961 ret = strdup(ast_get_context_name(c));
01962 ast_unlock_context(c);
01963 }
01964 ast_unlock_contexts();
01965 free(dupline);
01966 return NULL;
01967 }
01968
01969 return NULL;
01970 }
01971
01972 static char *complete_context_remove_ignorepat(const char *line, const char *word,
01973 int pos, int state)
01974 {
01975 struct ast_context *c;
01976 int which = 0;
01977 char *ret = NULL;
01978
01979 if (pos == 3) {
01980 int len = strlen(word);
01981 if (ast_rdlock_contexts()) {
01982 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01983 return NULL;
01984 }
01985
01986 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
01987 struct ast_ignorepat *ip;
01988
01989 if (ast_lock_context(c))
01990 continue;
01991
01992 for (ip = NULL; !ret && (ip = ast_walk_context_ignorepats(c, ip));) {
01993 if (partial_match(ast_get_ignorepat_name(ip), word, len) && ++which > state) {
01994
01995 struct ast_context *cw = NULL;
01996 int found = 0;
01997 while ( (cw = ast_walk_contexts(cw)) && cw != c && !found) {
01998
01999 found = lookup_c_ip(cw, ast_get_ignorepat_name(ip));
02000 }
02001 if (!found)
02002 ret = strdup(ast_get_ignorepat_name(ip));
02003 }
02004 }
02005 ast_unlock_context(c);
02006 }
02007 ast_unlock_contexts();
02008 return ret;
02009 } else if (pos == 4) {
02010 return state == 0 ? strdup("from") : NULL;
02011 } else if (pos == 5) {
02012 char *dupline, *duplinet, *ignorepat;
02013 int len = strlen(word);
02014
02015 dupline = strdup(line);
02016 if (!dupline) {
02017 ast_log(LOG_WARNING, "Out of free memory\n");
02018 return NULL;
02019 }
02020
02021 duplinet = dupline;
02022 strsep(&duplinet, " ");
02023 strsep(&duplinet, " ");
02024 ignorepat = strsep(&duplinet, " ");
02025
02026 if (!ignorepat) {
02027 free(dupline);
02028 return NULL;
02029 }
02030
02031 if (ast_rdlock_contexts()) {
02032 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
02033 free(dupline);
02034 return NULL;
02035 }
02036
02037 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
02038 if (ast_lock_context(c))
02039 continue;
02040 if (!partial_match(ast_get_context_name(c), word, len))
02041 continue;
02042 if (lookup_c_ip(c, ignorepat) && ++which > state)
02043 ret = strdup(ast_get_context_name(c));
02044 ast_unlock_context(c);
02045 }
02046 ast_unlock_contexts();
02047 free(dupline);
02048 return NULL;
02049 }
02050
02051 return NULL;
02052 }
02053
02054 static int pbx_load_module(void);
02055
02056 static int handle_reload_extensions(int fd, int argc, char *argv[])
02057 {
02058 if (argc != 2)
02059 return RESULT_SHOWUSAGE;
02060 if (clearglobalvars_config)
02061 pbx_builtin_clear_globals();
02062 pbx_load_module();
02063 ast_cli(fd, "Dialplan reloaded.\n");
02064 return RESULT_SUCCESS;
02065 }
02066
02067
02068
02069
02070 static struct ast_cli_entry cli_dont_include_deprecated = {
02071 { "dont", "include", NULL },
02072 handle_context_dont_include_deprecated, NULL,
02073 NULL, complete_context_dont_include_deprecated };
02074
02075 static struct ast_cli_entry cli_remove_extension_deprecated = {
02076 { "remove", "extension", NULL },
02077 handle_context_remove_extension_deprecated, NULL,
02078 NULL, complete_context_remove_extension_deprecated };
02079
02080 static struct ast_cli_entry cli_include_context_deprecated = {
02081 { "include", "context", NULL },
02082 handle_context_add_include_deprecated, NULL,
02083 NULL, complete_context_add_include_deprecated };
02084
02085 static struct ast_cli_entry cli_add_extension_deprecated = {
02086 { "add", "extension", NULL },
02087 handle_context_add_extension_deprecated, NULL,
02088 NULL, complete_context_add_extension_deprecated };
02089
02090 static struct ast_cli_entry cli_add_ignorepat_deprecated = {
02091 { "add", "ignorepat", NULL },
02092 handle_context_add_ignorepat_deprecated, NULL,
02093 NULL, complete_context_add_ignorepat_deprecated };
02094
02095 static struct ast_cli_entry cli_remove_ignorepat_deprecated = {
02096 { "remove", "ignorepat", NULL },
02097 handle_context_remove_ignorepat_deprecated, NULL,
02098 NULL, complete_context_remove_ignorepat_deprecated };
02099
02100 static struct ast_cli_entry cli_extensions_reload_deprecated = {
02101 { "extensions", "reload", NULL },
02102 handle_reload_extensions, NULL,
02103 NULL };
02104
02105 static struct ast_cli_entry cli_save_dialplan_deprecated = {
02106 { "save", "dialplan", NULL },
02107 handle_save_dialplan, NULL,
02108 NULL };
02109
02110 static struct ast_cli_entry cli_pbx_config[] = {
02111 { { "dialplan", "add", "extension", NULL },
02112 handle_context_add_extension, "Add new extension into context",
02113 context_add_extension_help, complete_context_add_extension, &cli_add_extension_deprecated },
02114
02115 { { "dialplan", "remove", "extension", NULL },
02116 handle_context_remove_extension, "Remove a specified extension",
02117 context_remove_extension_help, complete_context_remove_extension, &cli_remove_extension_deprecated },
02118
02119 { { "dialplan", "add", "ignorepat", NULL },
02120 handle_context_add_ignorepat, "Add new ignore pattern",
02121 context_add_ignorepat_help, complete_context_add_ignorepat, &cli_add_ignorepat_deprecated },
02122
02123 { { "dialplan", "remove", "ignorepat", NULL },
02124 handle_context_remove_ignorepat, "Remove ignore pattern from context",
02125 context_remove_ignorepat_help, complete_context_remove_ignorepat, &cli_remove_ignorepat_deprecated },
02126
02127 { { "dialplan", "add", "include", NULL },
02128 handle_context_add_include, "Include context in other context",
02129 context_add_include_help, complete_context_add_include, &cli_include_context_deprecated },
02130
02131 { { "dialplan", "remove", "include", NULL },
02132 handle_context_remove_include, "Remove a specified include from context",
02133 context_remove_include_help, complete_context_remove_include, &cli_dont_include_deprecated },
02134
02135 { { "dialplan", "reload", NULL },
02136 handle_reload_extensions, "Reload extensions and *only* extensions",
02137 reload_extensions_help, NULL, &cli_extensions_reload_deprecated },
02138 };
02139
02140
02141 static struct ast_cli_entry cli_dialplan_save = {
02142 { "dialplan", "save", NULL },
02143 handle_save_dialplan, "Save dialplan",
02144 save_dialplan_help, NULL, &cli_save_dialplan_deprecated };
02145
02146
02147
02148
02149 static int unload_module(void)
02150 {
02151 if (static_config && !write_protect_config)
02152 ast_cli_unregister(&cli_dialplan_save);
02153 ast_cli_unregister_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry));
02154 ast_context_destroy(NULL, registrar);
02155 return 0;
02156 }
02157
02158 static int pbx_load_config(const char *config_file)
02159 {
02160 struct ast_config *cfg;
02161 char *end;
02162 char *label;
02163 #ifdef LOW_MEMORY
02164 char realvalue[256];
02165 #else
02166 char realvalue[8192];
02167 #endif
02168 int lastpri = -2;
02169 struct ast_context *con;
02170 struct ast_variable *v;
02171 const char *cxt;
02172 const char *aft;
02173
02174 cfg = ast_config_load(config_file);
02175 if (!cfg)
02176 return 0;
02177
02178
02179 static_config = ast_true(ast_variable_retrieve(cfg, "general", "static"));
02180 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", "writeprotect"));
02181 if ((aft = ast_variable_retrieve(cfg, "general", "autofallthrough")))
02182 autofallthrough_config = ast_true(aft);
02183 clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
02184 ast_set2_flag(&ast_options, ast_true(ast_variable_retrieve(cfg, "general", "priorityjumping")), AST_OPT_FLAG_PRIORITY_JUMPING);
02185
02186 if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext")))
02187 ast_copy_string(userscontext, cxt, sizeof(userscontext));
02188 else
02189 ast_copy_string(userscontext, "default", sizeof(userscontext));
02190
02191 for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) {
02192 memset(realvalue, 0, sizeof(realvalue));
02193 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
02194 pbx_builtin_setvar_helper(NULL, v->name, realvalue);
02195 }
02196 for (cxt = NULL; (cxt = ast_category_browse(cfg, cxt)); ) {
02197
02198 if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
02199 continue;
02200 con=ast_context_find_or_create(&local_contexts,cxt, registrar);
02201 if (con == NULL)
02202 continue;
02203
02204 for (v = ast_variable_browse(cfg, cxt); v; v = v->next) {
02205 if (!strcasecmp(v->name, "exten")) {
02206 char *tc = ast_strdup(v->value);
02207 if (tc) {
02208 int ipri = -2;
02209 char realext[256]="";
02210 char *plus, *firstp, *firstc;
02211 char *pri, *appl, *data, *cidmatch;
02212 char *stringp = tc;
02213 char *ext = strsep(&stringp, ",");
02214 if (!ext) {
02215 ast_log(LOG_WARNING, "Bogus extension at line %d\n", v->lineno);
02216 ast_free(tc);
02217 continue;
02218 }
02219 pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
02220 cidmatch = strchr(realext, '/');
02221 if (cidmatch) {
02222 *cidmatch++ = '\0';
02223 ast_shrink_phone_number(cidmatch);
02224 }
02225 pri = strsep(&stringp, ",");
02226 if (!pri) {
02227 ast_log(LOG_WARNING, "Bogus extension at line %d\n", v->lineno);
02228 ast_free(tc);
02229 continue;
02230 }
02231 pri = ast_skip_blanks(pri);
02232 pri = ast_trim_blanks(pri);
02233 label = strchr(pri, '(');
02234 if (label) {
02235 *label++ = '\0';
02236 end = strchr(label, ')');
02237 if (end)
02238 *end = '\0';
02239 else
02240 ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
02241 }
02242 plus = strchr(pri, '+');
02243 if (plus) {
02244 *plus++ = '\0';
02245 }
02246 if (!strcmp(pri, "hint")) {
02247 ipri = PRIORITY_HINT;
02248 } else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
02249 if (lastpri > -2) {
02250 ipri = lastpri + 1;
02251 } else {
02252 ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry at line %d!\n", v->lineno);
02253 ast_free(tc);
02254 continue;
02255 }
02256 } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
02257 if (lastpri > -2) {
02258 ipri = lastpri;
02259 } else {
02260 ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry at line %d!\n", v->lineno);
02261 ast_free(tc);
02262 continue;
02263 }
02264 } else if (sscanf(pri, "%30d", &ipri) != 1 &&
02265 (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
02266 ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
02267 ipri = 0;
02268 ast_free(tc);
02269 continue;
02270 }
02271 if (ast_strlen_zero(appl = S_OR(stringp, ""))) {
02272 ast_log(LOG_WARNING, "Bogus extension at line %d\n", v->lineno);
02273 ast_free(tc);
02274 continue;
02275 }
02276
02277 firstc = strchr(appl, ',');
02278 firstp = strchr(appl, '(');
02279 if (firstc && (!firstp || firstc < firstp)) {
02280
02281
02282 appl = strsep(&stringp, ",");
02283 data = stringp;
02284 } else if (!firstc && !firstp) {
02285
02286 data = "";
02287 } else {
02288 char *orig_appl = strdup(appl);
02289
02290 if (!orig_appl)
02291 return -1;
02292
02293
02294 appl = strsep(&stringp, "(");
02295
02296
02297 if (strstr(appl, "${") || strstr(appl, "$[")){
02298
02299 strcpy(appl, orig_appl);
02300 data = "";
02301 } else {
02302 data = stringp;
02303 end = strrchr(data, ')');
02304 if ((end = strrchr(data, ')'))) {
02305 *end = '\0';
02306 } else {
02307 ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
02308 }
02309 ast_process_quotes_and_slashes(data, ',', '|');
02310 }
02311 ast_free(orig_appl);
02312 }
02313
02314 if (!data)
02315 data="";
02316 appl = ast_skip_blanks(appl);
02317 if (ipri) {
02318 if (plus)
02319 ipri += atoi(plus);
02320 lastpri = ipri;
02321 if (!ast_opt_dont_warn && !strcmp(realext, "_."))
02322 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);
02323 if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free_ptr, registrar)) {
02324 ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
02325 }
02326 }
02327 free(tc);
02328 }
02329 } else if (!strcasecmp(v->name, "include")) {
02330 memset(realvalue, 0, sizeof(realvalue));
02331 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
02332 if (ast_context_add_include2(con, realvalue, registrar))
02333 ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
02334 } else if (!strcasecmp(v->name, "ignorepat")) {
02335 memset(realvalue, 0, sizeof(realvalue));
02336 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
02337 if (ast_context_add_ignorepat2(con, realvalue, registrar))
02338 ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
02339 } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
02340 char *stringp= realvalue;
02341 char *appl, *data;
02342
02343 memset(realvalue, 0, sizeof(realvalue));
02344 if (!strcasecmp(v->name, "switch"))
02345 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
02346 else
02347 ast_copy_string(realvalue, v->value, sizeof(realvalue));
02348 appl = strsep(&stringp, "/");
02349 data = strsep(&stringp, "");
02350 if (!data)
02351 data = "";
02352 if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar))
02353 ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
02354 }
02355 }
02356 }
02357 ast_config_destroy(cfg);
02358 return 1;
02359 }
02360
02361 static void append_interface(char *iface, int maxlen, char *add)
02362 {
02363 int len = strlen(iface);
02364 if (strlen(add) + len < maxlen - 2) {
02365 if (strlen(iface)) {
02366 iface[len] = '&';
02367 strcpy(iface + len + 1, add);
02368 } else
02369 strcpy(iface, add);
02370 }
02371 }
02372
02373 static void pbx_load_users(void)
02374 {
02375 struct ast_config *cfg;
02376 char *cat, *chan;
02377 const char *dahdichan;
02378 const char *hasexten;
02379 char tmp[256];
02380 char iface[256];
02381 char zapcopy[256];
02382 char *c;
02383 int len;
02384 int hasvoicemail;
02385 int start, finish, x;
02386 struct ast_context *con = NULL;
02387
02388 cfg = ast_config_load("users.conf");
02389 if (!cfg)
02390 return;
02391
02392 for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
02393 if (!strcasecmp(cat, "general"))
02394 continue;
02395 iface[0] = '\0';
02396 len = sizeof(iface);
02397 if (ast_true(ast_config_option(cfg, cat, "hassip"))) {
02398 snprintf(tmp, sizeof(tmp), "SIP/%s", cat);
02399 append_interface(iface, sizeof(iface), tmp);
02400 }
02401 if (ast_true(ast_config_option(cfg, cat, "hasiax"))) {
02402 snprintf(tmp, sizeof(tmp), "IAX2/%s", cat);
02403 append_interface(iface, sizeof(iface), tmp);
02404 }
02405 if (ast_true(ast_config_option(cfg, cat, "hash323"))) {
02406 snprintf(tmp, sizeof(tmp), "H323/%s", cat);
02407 append_interface(iface, sizeof(iface), tmp);
02408 }
02409 hasexten = ast_config_option(cfg, cat, "hasexten");
02410 if (hasexten && !ast_true(hasexten))
02411 continue;
02412 hasvoicemail = ast_true(ast_config_option(cfg, cat, "hasvoicemail"));
02413 dahdichan = ast_variable_retrieve(cfg, cat, "dahdichan");
02414 if (!dahdichan)
02415 dahdichan = ast_variable_retrieve(cfg, "general", "dahdichan");
02416 if (!dahdichan) {
02417
02418 dahdichan = ast_variable_retrieve(cfg, cat, "zapchan");
02419 if (!dahdichan) {
02420 dahdichan = ast_variable_retrieve(cfg, "general", "zapchan");
02421 }
02422 if (!ast_strlen_zero(dahdichan)) {
02423 ast_log(LOG_WARNING, "Use of zapchan in users.conf is deprecated. Please update configuration to use dahdichan instead.\n");
02424 }
02425 }
02426 if (!ast_strlen_zero(dahdichan)) {
02427 ast_copy_string(zapcopy, dahdichan, sizeof(zapcopy));
02428 c = zapcopy;
02429 chan = strsep(&c, ",");
02430 while (chan) {
02431 if (sscanf(chan, "%30d-%30d", &start, &finish) == 2) {
02432
02433 } else if (sscanf(chan, "%30d", &start)) {
02434
02435 finish = start;
02436 } else {
02437 start = 0; finish = 0;
02438 }
02439 if (finish < start) {
02440 x = finish;
02441 finish = start;
02442 start = x;
02443 }
02444 for (x = start; x <= finish; x++) {
02445 snprintf(tmp, sizeof(tmp), "%s/%d", dahdi_chan_name, x);
02446 append_interface(iface, sizeof(iface), tmp);
02447 }
02448 chan = strsep(&c, ",");
02449 }
02450 }
02451 if (!ast_strlen_zero(iface)) {
02452
02453
02454 if (!con)
02455 con = ast_context_find_or_create(&local_contexts, userscontext, registrar);
02456
02457 if (!con) {
02458 ast_log(LOG_ERROR, "Can't find/create user context '%s'\n", userscontext);
02459 return;
02460 }
02461
02462
02463 ast_add_extension2(con, 0, cat, -1, NULL, NULL, iface, NULL, NULL, registrar);
02464
02465 if (hasvoicemail) {
02466 snprintf(tmp, sizeof(tmp), "stdexten|%s|${HINT}", cat);
02467 ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Macro", strdup(tmp), ast_free_ptr, registrar);
02468 } else {
02469 ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Dial", strdup("${HINT}"), ast_free_ptr, registrar);
02470 }
02471 }
02472 }
02473 ast_config_destroy(cfg);
02474 }
02475
02476 static int pbx_load_module(void)
02477 {
02478 struct ast_context *con;
02479
02480 if(!pbx_load_config(config))
02481 return AST_MODULE_LOAD_DECLINE;
02482
02483 pbx_load_users();
02484
02485 ast_merge_contexts_and_delete(&local_contexts, registrar);
02486
02487 for (con = NULL; (con = ast_walk_contexts(con));)
02488 ast_context_verify_includes(con);
02489
02490 pbx_set_autofallthrough(autofallthrough_config);
02491
02492 return 0;
02493 }
02494
02495 static int load_module(void)
02496 {
02497
02498 if (static_config && !write_protect_config)
02499 ast_cli_register(&cli_dialplan_save);
02500 ast_cli_register_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry));
02501
02502 if (pbx_load_module())
02503 return AST_MODULE_LOAD_DECLINE;
02504
02505 return 0;
02506 }
02507
02508 static int reload(void)
02509 {
02510 if (clearglobalvars_config)
02511 pbx_builtin_clear_globals();
02512 pbx_load_module();
02513 return 0;
02514 }
02515
02516 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Text Extension Configuration",
02517 .load = load_module,
02518 .unload = unload_module,
02519 .reload = reload,
02520 );