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: 128029 $")
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 #define BROKEN_READLINE 1
00624
00625 #ifdef BROKEN_READLINE
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638 static int fix_complete_args(const char *line, char **word, int *pos)
00639 {
00640 char *_line, *_strsep_line, *_previous_word = NULL, *_word = NULL;
00641 int words = 0;
00642
00643 _line = strdup(line);
00644
00645 _strsep_line = _line;
00646 while (_strsep_line) {
00647 _previous_word = _word;
00648 _word = strsep(&_strsep_line, " ");
00649
00650 if (_word && strlen(_word)) words++;
00651 }
00652
00653
00654 if (_word || _previous_word) {
00655 if (_word) {
00656 if (!strlen(_word)) words++;
00657 *word = strdup(_word);
00658 } else
00659 *word = strdup(_previous_word);
00660 *pos = words - 1;
00661 free(_line);
00662 return 0;
00663 }
00664
00665 free(_line);
00666 return -1;
00667 }
00668 #endif
00669
00670 static char *complete_context_remove_extension_deprecated(const char *line, const char *word, int pos,
00671 int state)
00672 {
00673 char *ret = NULL;
00674 int which = 0;
00675
00676 #ifdef BROKEN_READLINE
00677 char *word2;
00678
00679
00680
00681
00682 if (fix_complete_args(line, &word2, &pos)) {
00683 ast_log(LOG_ERROR, "Out of free memory\n");
00684 return NULL;
00685 }
00686 word = word2;
00687 #endif
00688
00689 if (pos == 2) {
00690 struct ast_context *c = NULL;
00691 char *context = NULL, *exten = NULL, *cid = NULL;
00692 int le = 0;
00693 int lc = 0;
00694 int lcid = 0;
00695
00696 lc = split_ec(word, &exten, &context, &cid);
00697 #ifdef BROKEN_READLINE
00698 free(word2);
00699 #endif
00700 if (lc)
00701 return NULL;
00702 le = strlen(exten);
00703 lc = strlen(context);
00704 lcid = cid ? strlen(cid) : -1;
00705
00706 if (ast_rdlock_contexts()) {
00707 ast_log(LOG_ERROR, "Failed to lock context list\n");
00708 goto error2;
00709 }
00710
00711
00712 while ( (c = ast_walk_contexts(c)) ) {
00713 struct ast_exten *e = NULL;
00714
00715 if (!partial_match(ast_get_context_name(c), context, lc))
00716 continue;
00717 while ( (e = ast_walk_context_extensions(c, e)) ) {
00718 if ( !strchr(word, '/') ||
00719 (!strchr(word, '@') && partial_match(ast_get_extension_cidmatch(e), cid, lcid)) ||
00720 (strchr(word, '@') && !strcmp(ast_get_extension_cidmatch(e), cid))) {
00721 if ( ((strchr(word, '/') || strchr(word, '@')) && !strcmp(ast_get_extension_name(e), exten)) ||
00722 (!strchr(word, '/') && !strchr(word, '@') && partial_match(ast_get_extension_name(e), exten, le))) {
00723 if (++which > state) {
00724
00725 if (ast_get_extension_matchcid(e) && (!strchr(word, '@') || strchr(word, '/'))) {
00726 asprintf(&ret, "%s/%s@%s", ast_get_extension_name(e), ast_get_extension_cidmatch(e), ast_get_context_name(c));
00727 break;
00728 } else if (!ast_get_extension_matchcid(e) && !strchr(word, '/')) {
00729 asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c));
00730 break;
00731 }
00732 }
00733 }
00734 }
00735 }
00736 if (e)
00737 break;
00738 }
00739
00740 ast_unlock_contexts();
00741 error2:
00742 if (exten)
00743 free(exten);
00744 } else if (pos == 3) {
00745 char *exten = NULL, *context, *cid, *p;
00746 struct ast_context *c;
00747 int le, lc, lcid, len;
00748 const char *s = skip_words(line, 2);
00749 int i = split_ec(s, &exten, &context, &cid);
00750
00751 if (i)
00752 goto error3;
00753 if ( (p = strchr(exten, ' ')) )
00754 *p = '\0';
00755 if ( (p = strchr(context, ' ')) )
00756 *p = '\0';
00757 le = strlen(exten);
00758 lc = strlen(context);
00759 lcid = strlen(cid);
00760 len = strlen(word);
00761 if (le == 0 || lc == 0)
00762 goto error3;
00763
00764 if (ast_rdlock_contexts()) {
00765 ast_log(LOG_ERROR, "Failed to lock context list\n");
00766 goto error3;
00767 }
00768
00769
00770 c = NULL;
00771 while ( (c = ast_walk_contexts(c)) ) {
00772
00773 struct ast_exten *e;
00774 if (strcmp(ast_get_context_name(c), context) != 0)
00775 continue;
00776
00777 e = NULL;
00778 while ( (e = ast_walk_context_extensions(c, e)) ) {
00779 struct ast_exten *priority;
00780 char buffer[10];
00781
00782 if (cid && strcmp(ast_get_extension_cidmatch(e), cid) != 0) {
00783 continue;
00784 }
00785 if (strcmp(ast_get_extension_name(e), exten) != 0)
00786 continue;
00787
00788 priority = NULL;
00789 while ( !ret && (priority = ast_walk_extension_priorities(e, priority)) ) {
00790 snprintf(buffer, sizeof(buffer), "%u", ast_get_extension_priority(priority));
00791 if (partial_match(buffer, word, len) && ++which > state)
00792 ret = strdup(buffer);
00793 }
00794 break;
00795 }
00796 break;
00797 }
00798 ast_unlock_contexts();
00799 error3:
00800 if (exten)
00801 free(exten);
00802 }
00803 #ifdef BROKEN_READLINE
00804 free(word2);
00805 #endif
00806 return ret;
00807 }
00808
00809 static char *complete_context_remove_extension(const char *line, const char *word, int pos,
00810 int state)
00811 {
00812 char *ret = NULL;
00813 int which = 0;
00814
00815 #ifdef BROKEN_READLINE
00816 char *word2;
00817
00818
00819
00820
00821 if (fix_complete_args(line, &word2, &pos)) {
00822 ast_log(LOG_ERROR, "Out of free memory\n");
00823 return NULL;
00824 }
00825 word = word2;
00826 #endif
00827
00828 if (pos == 3) {
00829 struct ast_context *c = NULL;
00830 char *context = NULL, *exten = NULL, *cid = NULL;
00831 int le = 0;
00832 int lc = 0;
00833 int lcid = 0;
00834
00835 lc = split_ec(word, &exten, &context, &cid);
00836 if (lc) {
00837 #ifdef BROKEN_READLINE
00838 free(word2);
00839 #endif
00840 return NULL;
00841 }
00842 le = strlen(exten);
00843 lc = strlen(context);
00844 lcid = cid ? strlen(cid) : -1;
00845
00846 if (ast_rdlock_contexts()) {
00847 ast_log(LOG_ERROR, "Failed to lock context list\n");
00848 goto error2;
00849 }
00850
00851
00852 while ( (c = ast_walk_contexts(c)) ) {
00853 struct ast_exten *e = NULL;
00854
00855 if (!partial_match(ast_get_context_name(c), context, lc))
00856 continue;
00857 while ( (e = ast_walk_context_extensions(c, e)) ) {
00858 if ( !strchr(word, '/') ||
00859 (!strchr(word, '@') && partial_match(ast_get_extension_cidmatch(e), cid, lcid)) ||
00860 (strchr(word, '@') && !strcmp(ast_get_extension_cidmatch(e), cid))) {
00861 if ( ((strchr(word, '/') || strchr(word, '@')) && !strcmp(ast_get_extension_name(e), exten)) ||
00862 (!strchr(word, '/') && !strchr(word, '@') && partial_match(ast_get_extension_name(e), exten, le))) {
00863 if (++which > state) {
00864
00865 if (ast_get_extension_matchcid(e) && (!strchr(word, '@') || strchr(word, '/'))) {
00866 asprintf(&ret, "%s/%s@%s", ast_get_extension_name(e), ast_get_extension_cidmatch(e), ast_get_context_name(c));
00867 break;
00868 } else if (!ast_get_extension_matchcid(e) && !strchr(word, '/')) {
00869 asprintf(&ret, "%s@%s", ast_get_extension_name(e), ast_get_context_name(c));
00870 break;
00871 }
00872 }
00873 }
00874 }
00875 }
00876 if (e)
00877 break;
00878 }
00879 #ifdef BROKEN_READLINE
00880 free(word2);
00881 #endif
00882
00883 ast_unlock_contexts();
00884 error2:
00885 if (exten)
00886 free(exten);
00887 } else if (pos == 4) {
00888 char *exten = NULL, *context, *cid, *p;
00889 struct ast_context *c;
00890 int le, lc, lcid, len;
00891 const char *s = skip_words(line, 3);
00892 int i = split_ec(s, &exten, &context, &cid);
00893
00894 if (i)
00895 goto error3;
00896 if ( (p = strchr(exten, ' ')) )
00897 *p = '\0';
00898 if ( (p = strchr(context, ' ')) )
00899 *p = '\0';
00900 le = strlen(exten);
00901 lc = strlen(context);
00902 lcid = cid ? strlen(cid) : -1;
00903 len = strlen(word);
00904 if (le == 0 || lc == 0)
00905 goto error3;
00906
00907 if (ast_rdlock_contexts()) {
00908 ast_log(LOG_ERROR, "Failed to lock context list\n");
00909 goto error3;
00910 }
00911
00912
00913 c = NULL;
00914 while ( (c = ast_walk_contexts(c)) ) {
00915
00916 struct ast_exten *e;
00917 if (strcmp(ast_get_context_name(c), context) != 0)
00918 continue;
00919
00920 e = NULL;
00921 while ( (e = ast_walk_context_extensions(c, e)) ) {
00922 struct ast_exten *priority;
00923 char buffer[10];
00924
00925 if (cid && strcmp(ast_get_extension_cidmatch(e), cid) != 0) {
00926 continue;
00927 }
00928 if (strcmp(ast_get_extension_name(e), exten) != 0)
00929 continue;
00930
00931 priority = NULL;
00932 while ( !ret && (priority = ast_walk_extension_priorities(e, priority)) ) {
00933 snprintf(buffer, sizeof(buffer), "%u", ast_get_extension_priority(priority));
00934 if (partial_match(buffer, word, len) && ++which > state)
00935 ret = strdup(buffer);
00936 }
00937 break;
00938 }
00939 break;
00940 }
00941 ast_unlock_contexts();
00942 error3:
00943 if (exten)
00944 free(exten);
00945 #ifdef BROKEN_READLINE
00946 free(word2);
00947 #endif
00948 }
00949 return ret;
00950 }
00951
00952
00953
00954
00955 static int handle_context_add_include_deprecated(int fd, int argc, char *argv[])
00956 {
00957 if (argc != 5)
00958 return RESULT_SHOWUSAGE;
00959
00960
00961 if (strcmp(argv[3], "in") && strcmp(argv[3], "into"))
00962 return RESULT_SHOWUSAGE;
00963
00964 if (ast_context_add_include(argv[4], argv[2], registrar)) {
00965 switch (errno) {
00966 case ENOMEM:
00967 ast_cli(fd, "Out of memory for context addition\n");
00968 break;
00969
00970 case EBUSY:
00971 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
00972 break;
00973
00974 case EEXIST:
00975 ast_cli(fd, "Context '%s' already included in '%s' context\n",
00976 argv[2], argv[4]);
00977 break;
00978
00979 case ENOENT:
00980 case EINVAL:
00981 ast_cli(fd, "There is no existence of context '%s'\n",
00982 errno == ENOENT ? argv[4] : argv[2]);
00983 break;
00984
00985 default:
00986 ast_cli(fd, "Failed to include '%s' in '%s' context\n",
00987 argv[2], argv[4]);
00988 break;
00989 }
00990 return RESULT_FAILURE;
00991 }
00992
00993
00994 ast_cli(fd, "Context '%s' included in '%s' context\n",
00995 argv[2], argv[4]);
00996
00997 return RESULT_SUCCESS;
00998 }
00999
01000 static int handle_context_add_include(int fd, int argc, char *argv[])
01001 {
01002 if (argc != 6)
01003 return RESULT_SHOWUSAGE;
01004
01005
01006 if (strcmp(argv[4], "into"))
01007 return RESULT_SHOWUSAGE;
01008
01009 if (ast_context_add_include(argv[5], argv[3], registrar)) {
01010 switch (errno) {
01011 case ENOMEM:
01012 ast_cli(fd, "Out of memory for context addition\n");
01013 break;
01014
01015 case EBUSY:
01016 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
01017 break;
01018
01019 case EEXIST:
01020 ast_cli(fd, "Context '%s' already included in '%s' context\n",
01021 argv[3], argv[5]);
01022 break;
01023
01024 case ENOENT:
01025 case EINVAL:
01026 ast_cli(fd, "There is no existence of context '%s'\n",
01027 errno == ENOENT ? argv[5] : argv[3]);
01028 break;
01029
01030 default:
01031 ast_cli(fd, "Failed to include '%s' in '%s' context\n",
01032 argv[3], argv[5]);
01033 break;
01034 }
01035 return RESULT_FAILURE;
01036 }
01037
01038
01039 ast_cli(fd, "Context '%s' included in '%s' context\n",
01040 argv[3], argv[5]);
01041
01042 return RESULT_SUCCESS;
01043 }
01044
01045 static char *complete_context_add_include_deprecated(const char *line, const char *word, int pos,
01046 int state)
01047 {
01048 struct ast_context *c;
01049 int which = 0;
01050 char *ret = NULL;
01051 int len = strlen(word);
01052
01053 if (pos == 2) {
01054 if (ast_rdlock_contexts()) {
01055 ast_log(LOG_ERROR, "Failed to lock context list\n");
01056 return NULL;
01057 }
01058 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
01059 if (partial_match(ast_get_context_name(c), word, len) && ++which > state)
01060 ret = strdup(ast_get_context_name(c));
01061 ast_unlock_contexts();
01062 return ret;
01063 } else if (pos == 3) {
01064
01065 char *context, *dupline;
01066 struct ast_context *c;
01067 const char *s = skip_words(line, 2);
01068
01069 if (state != 0)
01070 return NULL;
01071
01072
01073 context = dupline = strdup(s);
01074 if (!context) {
01075 ast_log(LOG_ERROR, "Out of free memory\n");
01076 return strdup("in");
01077 }
01078 strsep(&dupline, " ");
01079
01080
01081 if (ast_rdlock_contexts()) {
01082 ast_log(LOG_ERROR, "Failed to lock context list\n");
01083
01084 ret = strdup("in");
01085 } else {
01086 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
01087 if (!strcmp(context, ast_get_context_name(c)))
01088 ret = strdup("in");
01089 ast_unlock_contexts();
01090 }
01091 free(context);
01092 return ret;
01093 } else if (pos == 4) {
01094 char *context, *dupline, *in;
01095 const char *s = skip_words(line, 2);
01096 context = dupline = strdup(s);
01097 if (!dupline) {
01098 ast_log(LOG_ERROR, "Out of free memory\n");
01099 return NULL;
01100 }
01101 strsep(&dupline, " ");
01102 in = strsep(&dupline, " ");
01103
01104 if (!strlen(context) || strcmp(in, "in")) {
01105 ast_log(LOG_ERROR, "bad context %s or missing in %s\n",
01106 context, in);
01107 goto error3;
01108 }
01109
01110 if (ast_rdlock_contexts()) {
01111 ast_log(LOG_ERROR, "Failed to lock context list\n");
01112 goto error3;
01113 }
01114
01115 for (c = NULL; (c = ast_walk_contexts(c)); )
01116 if (!strcmp(context, ast_get_context_name(c)))
01117 break;
01118 if (c) {
01119
01120 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
01121 if (!strcmp(context, ast_get_context_name(c)))
01122 continue;
01123 if (partial_match(ast_get_context_name(c), word, len) &&
01124 !lookup_ci(c, context) &&
01125 ++which > state)
01126 ret = strdup(ast_get_context_name(c));
01127 }
01128 } else {
01129 ast_log(LOG_ERROR, "context %s not found\n", context);
01130 }
01131 ast_unlock_contexts();
01132 error3:
01133 free(context);
01134 return ret;
01135 }
01136
01137 return NULL;
01138 }
01139
01140 static char *complete_context_add_include(const char *line, const char *word, int pos,
01141 int state)
01142 {
01143 struct ast_context *c;
01144 int which = 0;
01145 char *ret = NULL;
01146 int len = strlen(word);
01147
01148 if (pos == 3) {
01149 if (ast_rdlock_contexts()) {
01150 ast_log(LOG_ERROR, "Failed to lock context list\n");
01151 return NULL;
01152 }
01153 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
01154 if (partial_match(ast_get_context_name(c), word, len) && ++which > state)
01155 ret = strdup(ast_get_context_name(c));
01156 ast_unlock_contexts();
01157 return ret;
01158 } else if (pos == 4) {
01159
01160 char *context, *dupline;
01161 struct ast_context *c;
01162 const char *s = skip_words(line, 3);
01163
01164 if (state != 0)
01165 return NULL;
01166
01167
01168 context = dupline = strdup(s);
01169 if (!context) {
01170 ast_log(LOG_ERROR, "Out of free memory\n");
01171 return strdup("into");
01172 }
01173 strsep(&dupline, " ");
01174
01175
01176 if (ast_rdlock_contexts()) {
01177 ast_log(LOG_ERROR, "Failed to lock context list\n");
01178
01179 ret = strdup("into");
01180 } else {
01181 for (c = NULL; !ret && (c = ast_walk_contexts(c)); )
01182 if (!strcmp(context, ast_get_context_name(c)))
01183 ret = strdup("into");
01184 ast_unlock_contexts();
01185 }
01186 free(context);
01187 return ret;
01188 } else if (pos == 5) {
01189 char *context, *dupline, *into;
01190 const char *s = skip_words(line, 3);
01191 context = dupline = strdup(s);
01192 if (!dupline) {
01193 ast_log(LOG_ERROR, "Out of free memory\n");
01194 return NULL;
01195 }
01196 strsep(&dupline, " ");
01197 into = strsep(&dupline, " ");
01198
01199 if (!strlen(context) || strcmp(into, "into")) {
01200 ast_log(LOG_ERROR, "bad context %s or missing into %s\n",
01201 context, into);
01202 goto error3;
01203 }
01204
01205 if (ast_rdlock_contexts()) {
01206 ast_log(LOG_ERROR, "Failed to lock context list\n");
01207 goto error3;
01208 }
01209
01210 for (c = NULL; (c = ast_walk_contexts(c)); )
01211 if (!strcmp(context, ast_get_context_name(c)))
01212 break;
01213 if (c) {
01214
01215 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
01216 if (!strcmp(context, ast_get_context_name(c)))
01217 continue;
01218 if (partial_match(ast_get_context_name(c), word, len) &&
01219 !lookup_ci(c, context) &&
01220 ++which > state)
01221 ret = strdup(ast_get_context_name(c));
01222 }
01223 } else {
01224 ast_log(LOG_ERROR, "context %s not found\n", context);
01225 }
01226 ast_unlock_contexts();
01227 error3:
01228 free(context);
01229 return ret;
01230 }
01231
01232 return NULL;
01233 }
01234
01235
01236
01237
01238 static int handle_save_dialplan(int fd, int argc, char *argv[])
01239 {
01240 char filename[256];
01241 struct ast_context *c;
01242 struct ast_config *cfg;
01243 struct ast_variable *v;
01244 int incomplete = 0;
01245 FILE *output;
01246
01247 const char *base, *slash, *file;
01248
01249 if (! (static_config && !write_protect_config)) {
01250 ast_cli(fd,
01251 "I can't save dialplan now, see '%s' example file.\n",
01252 config);
01253 return RESULT_FAILURE;
01254 }
01255
01256 if (argc != 2 && argc != 3)
01257 return RESULT_SHOWUSAGE;
01258
01259 if (ast_mutex_lock(&save_dialplan_lock)) {
01260 ast_cli(fd,
01261 "Failed to lock dialplan saving (another proccess saving?)\n");
01262 return RESULT_FAILURE;
01263 }
01264
01265
01266
01267 if (argc == 3) {
01268 base = argv[2];
01269 if (!strstr(argv[2], ".conf")) {
01270
01271 slash = (*(argv[2] + strlen(argv[2]) -1) == '/') ? "/" : "";
01272 file = config;
01273 } else {
01274 slash = "";
01275 file = "";
01276 }
01277 } else {
01278
01279 base = ast_config_AST_CONFIG_DIR;
01280 slash = "/";
01281 file = config;
01282 }
01283 snprintf(filename, sizeof(filename), "%s%s%s", base, slash, config);
01284
01285 cfg = ast_config_load("extensions.conf");
01286
01287
01288 if (ast_rdlock_contexts()) {
01289 ast_cli(fd, "Failed to lock contexts list\n");
01290 ast_mutex_unlock(&save_dialplan_lock);
01291 ast_config_destroy(cfg);
01292 return RESULT_FAILURE;
01293 }
01294
01295
01296 if (!(output = fopen(filename, "wt"))) {
01297 ast_cli(fd, "Failed to create file '%s'\n",
01298 filename);
01299 ast_unlock_contexts();
01300 ast_mutex_unlock(&save_dialplan_lock);
01301 ast_config_destroy(cfg);
01302 return RESULT_FAILURE;
01303 }
01304
01305
01306 fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\npriorityjumping=%s\n\n",
01307 static_config ? "yes" : "no",
01308 write_protect_config ? "yes" : "no",
01309 autofallthrough_config ? "yes" : "no",
01310 clearglobalvars_config ? "yes" : "no",
01311 ast_true(ast_variable_retrieve(cfg, "general", "priorityjumping")) ? "yes" : "no");
01312
01313 if ((v = ast_variable_browse(cfg, "globals"))) {
01314 fprintf(output, "[globals]\n");
01315 while(v) {
01316 fprintf(output, "%s => %s\n", v->name, v->value);
01317 v = v->next;
01318 }
01319 fprintf(output, "\n");
01320 }
01321
01322 ast_config_destroy(cfg);
01323
01324 #define PUT_CTX_HDR do { \
01325 if (!context_header_written) { \
01326 fprintf(output, "[%s]\n", ast_get_context_name(c)); \
01327 context_header_written = 1; \
01328 } \
01329 } while (0)
01330
01331
01332 for (c = NULL; (c = ast_walk_contexts(c)); ) {
01333 int context_header_written = 0;
01334 struct ast_exten *e, *last_written_e = NULL;
01335 struct ast_include *i;
01336 struct ast_ignorepat *ip;
01337 struct ast_sw *sw;
01338
01339
01340 if (ast_lock_context(c)) {
01341 incomplete = 1;
01342 continue;
01343 }
01344
01345
01346 if (!strcmp(ast_get_context_registrar(c), registrar)) {
01347 fprintf(output, "[%s]\n", ast_get_context_name(c));
01348 context_header_written = 1;
01349 }
01350
01351
01352 for (e = NULL; (e = ast_walk_context_extensions(c, e)); ) {
01353 struct ast_exten *p = NULL;
01354
01355
01356 while ( (p = ast_walk_extension_priorities(e, p)) ) {
01357 if (strcmp(ast_get_extension_registrar(p), registrar) != 0)
01358 continue;
01359
01360
01361 if (last_written_e != NULL &&
01362 strcmp(ast_get_extension_name(last_written_e),
01363 ast_get_extension_name(p)))
01364 fprintf(output, "\n");
01365 last_written_e = p;
01366
01367 PUT_CTX_HDR;
01368
01369 if (ast_get_extension_priority(p)==PRIORITY_HINT) {
01370 fprintf(output, "exten => %s,hint,%s\n",
01371 ast_get_extension_name(p),
01372 ast_get_extension_app(p));
01373 } else {
01374 const char *sep, *cid;
01375 char *tempdata = "";
01376 char *s;
01377 const char *el = ast_get_extension_label(p);
01378 char label[128] = "";
01379
01380 s = ast_get_extension_app_data(p);
01381 if (s) {
01382 char *t;
01383 tempdata = alloca(strlen(tempdata) * 2 + 1);
01384
01385 for (t = tempdata; *s; s++, t++) {
01386 if (*s == '|')
01387 *t = ',';
01388 else {
01389 if (*s == ',' || *s == ';')
01390 *t++ = '\\';
01391 *t = *s;
01392 }
01393 }
01394
01395 *t = *s;
01396 }
01397
01398 if (ast_get_extension_matchcid(p)) {
01399 sep = "/";
01400 cid = ast_get_extension_cidmatch(p);
01401 } else
01402 sep = cid = "";
01403
01404 if (el && (snprintf(label, sizeof(label), "(%s)", el) != (strlen(el) + 2)))
01405 incomplete = 1;
01406
01407 fprintf(output, "exten => %s%s%s,%d%s,%s(%s)\n",
01408 ast_get_extension_name(p), (ast_strlen_zero(sep) ? "" : sep), (ast_strlen_zero(cid) ? "" : cid),
01409 ast_get_extension_priority(p), label,
01410 ast_get_extension_app(p), (ast_strlen_zero(tempdata) ? "" : tempdata));
01411 }
01412 }
01413 }
01414
01415
01416 if (last_written_e)
01417 fprintf(output, "\n");
01418
01419
01420 for (i = NULL; (i = ast_walk_context_includes(c, i)) ; ) {
01421 if (strcmp(ast_get_include_registrar(i), registrar) != 0)
01422 continue;
01423 PUT_CTX_HDR;
01424 fprintf(output, "include => %s\n", ast_get_include_name(i));
01425 }
01426 if (ast_walk_context_includes(c, NULL))
01427 fprintf(output, "\n");
01428
01429
01430 for (sw = NULL; (sw = ast_walk_context_switches(c, sw)) ; ) {
01431 if (strcmp(ast_get_switch_registrar(sw), registrar) != 0)
01432 continue;
01433 PUT_CTX_HDR;
01434 fprintf(output, "switch => %s/%s\n",
01435 ast_get_switch_name(sw), ast_get_switch_data(sw));
01436 }
01437
01438 if (ast_walk_context_switches(c, NULL))
01439 fprintf(output, "\n");
01440
01441
01442 for (ip = NULL; (ip = ast_walk_context_ignorepats(c, ip)); ) {
01443 if (strcmp(ast_get_ignorepat_registrar(ip), registrar) != 0)
01444 continue;
01445 PUT_CTX_HDR;
01446 fprintf(output, "ignorepat => %s\n",
01447 ast_get_ignorepat_name(ip));
01448 }
01449
01450 ast_unlock_context(c);
01451 }
01452
01453 ast_unlock_contexts();
01454 ast_mutex_unlock(&save_dialplan_lock);
01455 fclose(output);
01456
01457 if (incomplete) {
01458 ast_cli(fd, "Saved dialplan is incomplete\n");
01459 return RESULT_FAILURE;
01460 }
01461
01462 ast_cli(fd, "Dialplan successfully saved into '%s'\n",
01463 filename);
01464 return RESULT_SUCCESS;
01465 }
01466
01467
01468
01469
01470 static int handle_context_add_extension_deprecated(int fd, int argc, char *argv[])
01471 {
01472 char *whole_exten;
01473 char *exten, *prior;
01474 int iprior = -2;
01475 char *cidmatch, *app, *app_data;
01476 char *start, *end;
01477
01478
01479 if (argc != 5 && argc != 6)
01480 return RESULT_SHOWUSAGE;
01481 if (strcmp(argv[3], "into"))
01482 return RESULT_SHOWUSAGE;
01483 if (argc == 6) if (strcmp(argv[5], "replace")) return RESULT_SHOWUSAGE;
01484
01485
01486 whole_exten = argv[2];
01487 exten = strsep(&whole_exten,",");
01488 if (strchr(exten, '/')) {
01489 cidmatch = exten;
01490 strsep(&cidmatch,"/");
01491 } else {
01492 cidmatch = NULL;
01493 }
01494 prior = strsep(&whole_exten,",");
01495 if (prior) {
01496 if (!strcmp(prior, "hint")) {
01497 iprior = PRIORITY_HINT;
01498 } else {
01499 if (sscanf(prior, "%d", &iprior) != 1) {
01500 ast_cli(fd, "'%s' is not a valid priority\n", prior);
01501 prior = NULL;
01502 }
01503 }
01504 }
01505 app = whole_exten;
01506 if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
01507 *start = *end = '\0';
01508 app_data = start + 1;
01509 ast_process_quotes_and_slashes(app_data, ',', '|');
01510 } else {
01511 if (app) {
01512 app_data = strchr(app, ',');
01513 if (app_data) {
01514 *app_data = '\0';
01515 app_data++;
01516 }
01517 } else
01518 app_data = NULL;
01519 }
01520
01521 if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT))
01522 return RESULT_SHOWUSAGE;
01523
01524 if (!app_data)
01525 app_data="";
01526 if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, iprior, NULL, cidmatch, app,
01527 (void *)strdup(app_data), ast_free, registrar)) {
01528 switch (errno) {
01529 case ENOMEM:
01530 ast_cli(fd, "Out of free memory\n");
01531 break;
01532
01533 case EBUSY:
01534 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
01535 break;
01536
01537 case ENOENT:
01538 ast_cli(fd, "No existence of '%s' context\n", argv[4]);
01539 break;
01540
01541 case EEXIST:
01542 ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
01543 exten, argv[4], prior);
01544 break;
01545
01546 default:
01547 ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
01548 exten, prior, app, app_data, argv[4]);
01549 break;
01550 }
01551 return RESULT_FAILURE;
01552 }
01553
01554 if (argc == 6)
01555 ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
01556 exten, argv[4], prior, exten, prior, app, app_data);
01557 else
01558 ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
01559 exten, prior, app, app_data, argv[4]);
01560
01561 return RESULT_SUCCESS;
01562 }
01563 static int handle_context_add_extension(int fd, int argc, char *argv[])
01564 {
01565 char *whole_exten;
01566 char *exten, *prior;
01567 int iprior = -2;
01568 char *cidmatch, *app, *app_data;
01569 char *start, *end;
01570
01571
01572 if (argc != 6 && argc != 7)
01573 return RESULT_SHOWUSAGE;
01574 if (strcmp(argv[4], "into"))
01575 return RESULT_SHOWUSAGE;
01576 if (argc == 7) if (strcmp(argv[6], "replace")) return RESULT_SHOWUSAGE;
01577
01578
01579 whole_exten = argv[3];
01580 exten = strsep(&whole_exten,",");
01581 if (strchr(exten, '/')) {
01582 cidmatch = exten;
01583 strsep(&cidmatch,"/");
01584 } else {
01585 cidmatch = NULL;
01586 }
01587 prior = strsep(&whole_exten,",");
01588 if (prior) {
01589 if (!strcmp(prior, "hint")) {
01590 iprior = PRIORITY_HINT;
01591 } else {
01592 if (sscanf(prior, "%d", &iprior) != 1) {
01593 ast_cli(fd, "'%s' is not a valid priority\n", prior);
01594 prior = NULL;
01595 }
01596 }
01597 }
01598 app = whole_exten;
01599 if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
01600 *start = *end = '\0';
01601 app_data = start + 1;
01602 ast_process_quotes_and_slashes(app_data, ',', '|');
01603 } else {
01604 if (app) {
01605 app_data = strchr(app, ',');
01606 if (app_data) {
01607 *app_data = '\0';
01608 app_data++;
01609 }
01610 } else
01611 app_data = NULL;
01612 }
01613
01614 if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT))
01615 return RESULT_SHOWUSAGE;
01616
01617 if (!app_data)
01618 app_data="";
01619 if (ast_add_extension(argv[5], argc == 7 ? 1 : 0, exten, iprior, NULL, cidmatch, app,
01620 (void *)strdup(app_data), ast_free, registrar)) {
01621 switch (errno) {
01622 case ENOMEM:
01623 ast_cli(fd, "Out of free memory\n");
01624 break;
01625
01626 case EBUSY:
01627 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
01628 break;
01629
01630 case ENOENT:
01631 ast_cli(fd, "No existence of '%s' context\n", argv[5]);
01632 break;
01633
01634 case EEXIST:
01635 ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
01636 exten, argv[5], prior);
01637 break;
01638
01639 default:
01640 ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
01641 exten, prior, app, app_data, argv[5]);
01642 break;
01643 }
01644 return RESULT_FAILURE;
01645 }
01646
01647 if (argc == 7)
01648 ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
01649 exten, argv[5], prior, exten, prior, app, app_data);
01650 else
01651 ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
01652 exten, prior, app, app_data, argv[5]);
01653
01654 return RESULT_SUCCESS;
01655 }
01656
01657
01658 static char *complete_context_add_extension_deprecated(const char *line, const char *word, int pos, int state)
01659 {
01660 int which = 0;
01661
01662 if (pos == 3) {
01663 return (state == 0) ? strdup("into") : NULL;
01664 } else if (pos == 4) {
01665 struct ast_context *c = NULL;
01666 int len = strlen(word);
01667 char *res = NULL;
01668
01669
01670 if (ast_rdlock_contexts()) {
01671 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01672 return NULL;
01673 }
01674
01675
01676 while ( !res && (c = ast_walk_contexts(c)) )
01677 if (partial_match(ast_get_context_name(c), word, len) && ++which > state)
01678 res = strdup(ast_get_context_name(c));
01679 ast_unlock_contexts();
01680 return res;
01681 } else if (pos == 5) {
01682 return state == 0 ? strdup("replace") : NULL;
01683 }
01684 return NULL;
01685 }
01686
01687 static char *complete_context_add_extension(const char *line, const char *word, int pos, int state)
01688 {
01689 int which = 0;
01690
01691 if (pos == 4) {
01692 return (state == 0) ? strdup("into") : NULL;
01693 } else if (pos == 5) {
01694 struct ast_context *c = NULL;
01695 int len = strlen(word);
01696 char *res = NULL;
01697
01698
01699 if (ast_rdlock_contexts()) {
01700 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01701 return NULL;
01702 }
01703
01704
01705 while ( !res && (c = ast_walk_contexts(c)) )
01706 if (partial_match(ast_get_context_name(c), word, len) && ++which > state)
01707 res = strdup(ast_get_context_name(c));
01708 ast_unlock_contexts();
01709 return res;
01710 } else if (pos == 6) {
01711 return state == 0 ? strdup("replace") : NULL;
01712 }
01713 return NULL;
01714 }
01715
01716
01717
01718
01719 static int handle_context_add_ignorepat_deprecated(int fd, int argc, char *argv[])
01720 {
01721 if (argc != 5)
01722 return RESULT_SHOWUSAGE;
01723 if (strcmp(argv[3], "into"))
01724 return RESULT_SHOWUSAGE;
01725
01726 if (ast_context_add_ignorepat(argv[4], argv[2], registrar)) {
01727 switch (errno) {
01728 case ENOMEM:
01729 ast_cli(fd, "Out of free memory\n");
01730 break;
01731
01732 case ENOENT:
01733 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
01734 break;
01735
01736 case EEXIST:
01737 ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
01738 argv[2], argv[4]);
01739 break;
01740
01741 case EBUSY:
01742 ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
01743 break;
01744
01745 default:
01746 ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
01747 argv[2], argv[4]);
01748 break;
01749 }
01750 return RESULT_FAILURE;
01751 }
01752
01753 ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
01754 argv[2], argv[4]);
01755 return RESULT_SUCCESS;
01756 }
01757
01758 static int handle_context_add_ignorepat(int fd, int argc, char *argv[])
01759 {
01760 if (argc != 6)
01761 return RESULT_SHOWUSAGE;
01762 if (strcmp(argv[4], "into"))
01763 return RESULT_SHOWUSAGE;
01764
01765 if (ast_context_add_ignorepat(argv[5], argv[3], registrar)) {
01766 switch (errno) {
01767 case ENOMEM:
01768 ast_cli(fd, "Out of free memory\n");
01769 break;
01770
01771 case ENOENT:
01772 ast_cli(fd, "There is no existence of '%s' context\n", argv[5]);
01773 break;
01774
01775 case EEXIST:
01776 ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
01777 argv[3], argv[5]);
01778 break;
01779
01780 case EBUSY:
01781 ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
01782 break;
01783
01784 default:
01785 ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
01786 argv[3], argv[5]);
01787 break;
01788 }
01789 return RESULT_FAILURE;
01790 }
01791
01792 ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
01793 argv[3], argv[5]);
01794 return RESULT_SUCCESS;
01795 }
01796
01797 static char *complete_context_add_ignorepat_deprecated(const char *line, const char *word,
01798 int pos, int state)
01799 {
01800 if (pos == 3)
01801 return state == 0 ? strdup("into") : NULL;
01802 else if (pos == 4) {
01803 struct ast_context *c;
01804 int which = 0;
01805 char *dupline, *ignorepat = NULL;
01806 const char *s;
01807 char *ret = NULL;
01808 int len = strlen(word);
01809
01810
01811 s = skip_words(line, 2);
01812 if (s == NULL)
01813 return NULL;
01814 dupline = strdup(s);
01815 if (!dupline) {
01816 ast_log(LOG_ERROR, "Malloc failure\n");
01817 return NULL;
01818 }
01819 ignorepat = strsep(&dupline, " ");
01820
01821 if (ast_rdlock_contexts()) {
01822 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
01823 return NULL;
01824 }
01825
01826 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
01827 int found = 0;
01828
01829 if (!partial_match(ast_get_context_name(c), word, len))
01830 continue;
01831 if (ignorepat)
01832 found = lookup_c_ip(c, ignorepat);
01833 if (!found && ++which > state)
01834 ret = strdup(ast_get_context_name(c));
01835 }
01836
01837 if (ignorepat)
01838 free(ignorepat);
01839 ast_unlock_contexts();
01840 return ret;
01841 }
01842
01843 return NULL;
01844 }
01845
01846 static char *complete_context_add_ignorepat(const char *line, const char *word,
01847 int pos, int state)
01848 {
01849 if (pos == 4)
01850 return state == 0 ? strdup("into") : NULL;
01851 else if (pos == 5) {
01852 struct ast_context *c;
01853 int which = 0;
01854 char *dupline, *ignorepat = NULL;
01855 const char *s;
01856 char *ret = NULL;
01857 int len = strlen(word);
01858
01859
01860 s = skip_words(line, 3);
01861 if (s == NULL)
01862 return NULL;
01863 dupline = strdup(s);
01864 if (!dupline) {
01865 ast_log(LOG_ERROR, "Malloc failure\n");
01866 return NULL;
01867 }
01868 ignorepat = strsep(&dupline, " ");
01869
01870 if (ast_rdlock_contexts()) {
01871 ast_log(LOG_ERROR, "Failed to lock contexts list\n");
01872 return NULL;
01873 }
01874
01875 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
01876 int found = 0;
01877
01878 if (!partial_match(ast_get_context_name(c), word, len))
01879 continue;
01880 if (ignorepat)
01881 found = lookup_c_ip(c, ignorepat);
01882 if (!found && ++which > state)
01883 ret = strdup(ast_get_context_name(c));
01884 }
01885
01886 if (ignorepat)
01887 free(ignorepat);
01888 ast_unlock_contexts();
01889 return ret;
01890 }
01891
01892 return NULL;
01893 }
01894
01895 static int handle_context_remove_ignorepat_deprecated(int fd, int argc, char *argv[])
01896 {
01897 if (argc != 5)
01898 return RESULT_SHOWUSAGE;
01899 if (strcmp(argv[3], "from"))
01900 return RESULT_SHOWUSAGE;
01901
01902 if (ast_context_remove_ignorepat(argv[4], argv[2], registrar)) {
01903 switch (errno) {
01904 case EBUSY:
01905 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
01906 break;
01907
01908 case ENOENT:
01909 ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
01910 break;
01911
01912 case EINVAL:
01913 ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
01914 argv[2], argv[4]);
01915 break;
01916
01917 default:
01918 ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n", argv[2], argv[4]);
01919 break;
01920 }
01921 return RESULT_FAILURE;
01922 }
01923
01924 ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
01925 argv[2], argv[4]);
01926 return RESULT_SUCCESS;
01927 }
01928
01929 static int handle_context_remove_ignorepat(int fd, int argc, char *argv[])
01930 {
01931 if (argc != 6)
01932 return RESULT_SHOWUSAGE;
01933 if (strcmp(argv[4], "from"))
01934 return RESULT_SHOWUSAGE;
01935
01936 if (ast_context_remove_ignorepat(argv[5], argv[3], registrar)) {
01937 switch (errno) {
01938 case EBUSY:
01939 ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
01940 break;
01941
01942 case ENOENT:
01943 ast_cli(fd, "There is no existence of '%s' context\n", argv[5]);
01944 break;
01945
01946 case EINVAL:
01947 ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
01948 argv[3], argv[5]);
01949 break;
01950
01951 default:
01952 ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n", argv[3], argv[5]);
01953 break;
01954 }
01955 return RESULT_FAILURE;
01956 }
01957
01958 ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
01959 argv[3], argv[5]);
01960 return RESULT_SUCCESS;
01961 }
01962
01963 static char *complete_context_remove_ignorepat_deprecated(const char *line, const char *word,
01964 int pos, int state)
01965 {
01966 struct ast_context *c;
01967 int which = 0;
01968 char *ret = NULL;
01969
01970 if (pos == 2) {
01971 int len = strlen(word);
01972 if (ast_rdlock_contexts()) {
01973 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01974 return NULL;
01975 }
01976
01977 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
01978 struct ast_ignorepat *ip;
01979
01980 if (ast_lock_context(c))
01981 continue;
01982
01983 for (ip = NULL; !ret && (ip = ast_walk_context_ignorepats(c, ip));) {
01984 if (partial_match(ast_get_ignorepat_name(ip), word, len) && ++which > state) {
01985
01986 struct ast_context *cw = NULL;
01987 int found = 0;
01988 while ( (cw = ast_walk_contexts(cw)) && cw != c && !found) {
01989
01990 found = lookup_c_ip(cw, ast_get_ignorepat_name(ip));
01991 }
01992 if (!found)
01993 ret = strdup(ast_get_ignorepat_name(ip));
01994 }
01995 }
01996 ast_unlock_context(c);
01997 }
01998 ast_unlock_contexts();
01999 return ret;
02000 } else if (pos == 3) {
02001 return state == 0 ? strdup("from") : NULL;
02002 } else if (pos == 4) {
02003 char *dupline, *duplinet, *ignorepat;
02004 int len = strlen(word);
02005
02006 dupline = strdup(line);
02007 if (!dupline) {
02008 ast_log(LOG_WARNING, "Out of free memory\n");
02009 return NULL;
02010 }
02011
02012 duplinet = dupline;
02013 strsep(&duplinet, " ");
02014 strsep(&duplinet, " ");
02015 ignorepat = strsep(&duplinet, " ");
02016
02017 if (!ignorepat) {
02018 free(dupline);
02019 return NULL;
02020 }
02021
02022 if (ast_rdlock_contexts()) {
02023 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
02024 free(dupline);
02025 return NULL;
02026 }
02027
02028 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
02029 if (ast_lock_context(c))
02030 continue;
02031 if (!partial_match(ast_get_context_name(c), word, len))
02032 continue;
02033 if (lookup_c_ip(c, ignorepat) && ++which > state)
02034 ret = strdup(ast_get_context_name(c));
02035 ast_unlock_context(c);
02036 }
02037 ast_unlock_contexts();
02038 free(dupline);
02039 return NULL;
02040 }
02041
02042 return NULL;
02043 }
02044
02045 static char *complete_context_remove_ignorepat(const char *line, const char *word,
02046 int pos, int state)
02047 {
02048 struct ast_context *c;
02049 int which = 0;
02050 char *ret = NULL;
02051
02052 if (pos == 3) {
02053 int len = strlen(word);
02054 if (ast_rdlock_contexts()) {
02055 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
02056 return NULL;
02057 }
02058
02059 for (c = NULL; !ret && (c = ast_walk_contexts(c));) {
02060 struct ast_ignorepat *ip;
02061
02062 if (ast_lock_context(c))
02063 continue;
02064
02065 for (ip = NULL; !ret && (ip = ast_walk_context_ignorepats(c, ip));) {
02066 if (partial_match(ast_get_ignorepat_name(ip), word, len) && ++which > state) {
02067
02068 struct ast_context *cw = NULL;
02069 int found = 0;
02070 while ( (cw = ast_walk_contexts(cw)) && cw != c && !found) {
02071
02072 found = lookup_c_ip(cw, ast_get_ignorepat_name(ip));
02073 }
02074 if (!found)
02075 ret = strdup(ast_get_ignorepat_name(ip));
02076 }
02077 }
02078 ast_unlock_context(c);
02079 }
02080 ast_unlock_contexts();
02081 return ret;
02082 } else if (pos == 4) {
02083 return state == 0 ? strdup("from") : NULL;
02084 } else if (pos == 5) {
02085 char *dupline, *duplinet, *ignorepat;
02086 int len = strlen(word);
02087
02088 dupline = strdup(line);
02089 if (!dupline) {
02090 ast_log(LOG_WARNING, "Out of free memory\n");
02091 return NULL;
02092 }
02093
02094 duplinet = dupline;
02095 strsep(&duplinet, " ");
02096 strsep(&duplinet, " ");
02097 ignorepat = strsep(&duplinet, " ");
02098
02099 if (!ignorepat) {
02100 free(dupline);
02101 return NULL;
02102 }
02103
02104 if (ast_rdlock_contexts()) {
02105 ast_log(LOG_WARNING, "Failed to lock contexts list\n");
02106 free(dupline);
02107 return NULL;
02108 }
02109
02110 for (c = NULL; !ret && (c = ast_walk_contexts(c)); ) {
02111 if (ast_lock_context(c))
02112 continue;
02113 if (!partial_match(ast_get_context_name(c), word, len))
02114 continue;
02115 if (lookup_c_ip(c, ignorepat) && ++which > state)
02116 ret = strdup(ast_get_context_name(c));
02117 ast_unlock_context(c);
02118 }
02119 ast_unlock_contexts();
02120 free(dupline);
02121 return NULL;
02122 }
02123
02124 return NULL;
02125 }
02126
02127 static int pbx_load_module(void);
02128
02129 static int handle_reload_extensions(int fd, int argc, char *argv[])
02130 {
02131 if (argc != 2)
02132 return RESULT_SHOWUSAGE;
02133 if (clearglobalvars_config)
02134 pbx_builtin_clear_globals();
02135 pbx_load_module();
02136 ast_cli(fd, "Dialplan reloaded.\n");
02137 return RESULT_SUCCESS;
02138 }
02139
02140
02141
02142
02143 static struct ast_cli_entry cli_dont_include_deprecated = {
02144 { "dont", "include", NULL },
02145 handle_context_dont_include_deprecated, NULL,
02146 NULL, complete_context_dont_include_deprecated };
02147
02148 static struct ast_cli_entry cli_remove_extension_deprecated = {
02149 { "remove", "extension", NULL },
02150 handle_context_remove_extension_deprecated, NULL,
02151 NULL, complete_context_remove_extension_deprecated };
02152
02153 static struct ast_cli_entry cli_include_context_deprecated = {
02154 { "include", "context", NULL },
02155 handle_context_add_include_deprecated, NULL,
02156 NULL, complete_context_add_include_deprecated };
02157
02158 static struct ast_cli_entry cli_add_extension_deprecated = {
02159 { "add", "extension", NULL },
02160 handle_context_add_extension_deprecated, NULL,
02161 NULL, complete_context_add_extension_deprecated };
02162
02163 static struct ast_cli_entry cli_add_ignorepat_deprecated = {
02164 { "add", "ignorepat", NULL },
02165 handle_context_add_ignorepat_deprecated, NULL,
02166 NULL, complete_context_add_ignorepat_deprecated };
02167
02168 static struct ast_cli_entry cli_remove_ignorepat_deprecated = {
02169 { "remove", "ignorepat", NULL },
02170 handle_context_remove_ignorepat_deprecated, NULL,
02171 NULL, complete_context_remove_ignorepat_deprecated };
02172
02173 static struct ast_cli_entry cli_extensions_reload_deprecated = {
02174 { "extensions", "reload", NULL },
02175 handle_reload_extensions, NULL,
02176 NULL };
02177
02178 static struct ast_cli_entry cli_save_dialplan_deprecated = {
02179 { "save", "dialplan", NULL },
02180 handle_save_dialplan, NULL,
02181 NULL };
02182
02183 static struct ast_cli_entry cli_pbx_config[] = {
02184 { { "dialplan", "add", "extension", NULL },
02185 handle_context_add_extension, "Add new extension into context",
02186 context_add_extension_help, complete_context_add_extension, &cli_add_extension_deprecated },
02187
02188 { { "dialplan", "remove", "extension", NULL },
02189 handle_context_remove_extension, "Remove a specified extension",
02190 context_remove_extension_help, complete_context_remove_extension, &cli_remove_extension_deprecated },
02191
02192 { { "dialplan", "add", "ignorepat", NULL },
02193 handle_context_add_ignorepat, "Add new ignore pattern",
02194 context_add_ignorepat_help, complete_context_add_ignorepat, &cli_add_ignorepat_deprecated },
02195
02196 { { "dialplan", "remove", "ignorepat", NULL },
02197 handle_context_remove_ignorepat, "Remove ignore pattern from context",
02198 context_remove_ignorepat_help, complete_context_remove_ignorepat, &cli_remove_ignorepat_deprecated },
02199
02200 { { "dialplan", "add", "include", NULL },
02201 handle_context_add_include, "Include context in other context",
02202 context_add_include_help, complete_context_add_include, &cli_include_context_deprecated },
02203
02204 { { "dialplan", "remove", "include", NULL },
02205 handle_context_remove_include, "Remove a specified include from context",
02206 context_remove_include_help, complete_context_remove_include, &cli_dont_include_deprecated },
02207
02208 { { "dialplan", "reload", NULL },
02209 handle_reload_extensions, "Reload extensions and *only* extensions",
02210 reload_extensions_help, NULL, &cli_extensions_reload_deprecated },
02211 };
02212
02213
02214 static struct ast_cli_entry cli_dialplan_save = {
02215 { "dialplan", "save", NULL },
02216 handle_save_dialplan, "Save dialplan",
02217 save_dialplan_help, NULL, &cli_save_dialplan_deprecated };
02218
02219
02220
02221
02222 static int unload_module(void)
02223 {
02224 if (static_config && !write_protect_config)
02225 ast_cli_unregister(&cli_dialplan_save);
02226 ast_cli_unregister_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry));
02227 ast_context_destroy(NULL, registrar);
02228 return 0;
02229 }
02230
02231 static int pbx_load_config(const char *config_file)
02232 {
02233 struct ast_config *cfg;
02234 char *end;
02235 char *label;
02236 char realvalue[256];
02237 int lastpri = -2;
02238 struct ast_context *con;
02239 struct ast_variable *v;
02240 const char *cxt;
02241 const char *aft;
02242
02243 cfg = ast_config_load(config_file);
02244 if (!cfg)
02245 return 0;
02246
02247
02248 static_config = ast_true(ast_variable_retrieve(cfg, "general", "static"));
02249 write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", "writeprotect"));
02250 if ((aft = ast_variable_retrieve(cfg, "general", "autofallthrough")))
02251 autofallthrough_config = ast_true(aft);
02252 clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", "clearglobalvars"));
02253 ast_set2_flag(&ast_options, ast_true(ast_variable_retrieve(cfg, "general", "priorityjumping")), AST_OPT_FLAG_PRIORITY_JUMPING);
02254
02255 if ((cxt = ast_variable_retrieve(cfg, "general", "userscontext")))
02256 ast_copy_string(userscontext, cxt, sizeof(userscontext));
02257 else
02258 ast_copy_string(userscontext, "default", sizeof(userscontext));
02259
02260 for (v = ast_variable_browse(cfg, "globals"); v; v = v->next) {
02261 memset(realvalue, 0, sizeof(realvalue));
02262 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
02263 pbx_builtin_setvar_helper(NULL, v->name, realvalue);
02264 }
02265 for (cxt = NULL; (cxt = ast_category_browse(cfg, cxt)); ) {
02266
02267 if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals"))
02268 continue;
02269 con=ast_context_find_or_create(&local_contexts,cxt, registrar);
02270 if (con == NULL)
02271 continue;
02272
02273 for (v = ast_variable_browse(cfg, cxt); v; v = v->next) {
02274 if (!strcasecmp(v->name, "exten")) {
02275 char *tc = ast_strdup(v->value);
02276 if (tc) {
02277 int ipri = -2;
02278 char realext[256]="";
02279 char *plus, *firstp, *firstc;
02280 char *pri, *appl, *data, *cidmatch;
02281 char *stringp = tc;
02282 char *ext = strsep(&stringp, ",");
02283 if (!ext)
02284 ext="";
02285 pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
02286 cidmatch = strchr(realext, '/');
02287 if (cidmatch) {
02288 *cidmatch++ = '\0';
02289 ast_shrink_phone_number(cidmatch);
02290 }
02291 pri = strsep(&stringp, ",");
02292 if (!pri)
02293 pri="";
02294 pri = ast_skip_blanks(pri);
02295 pri = ast_trim_blanks(pri);
02296 label = strchr(pri, '(');
02297 if (label) {
02298 *label++ = '\0';
02299 end = strchr(label, ')');
02300 if (end)
02301 *end = '\0';
02302 else
02303 ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
02304 }
02305 plus = strchr(pri, '+');
02306 if (plus)
02307 *plus++ = '\0';
02308 if (!strcmp(pri,"hint"))
02309 ipri=PRIORITY_HINT;
02310 else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
02311 if (lastpri > -2)
02312 ipri = lastpri + 1;
02313 else
02314 ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
02315 } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
02316 if (lastpri > -2)
02317 ipri = lastpri;
02318 else
02319 ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
02320 } else if (sscanf(pri, "%d", &ipri) != 1 &&
02321 (ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
02322 ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
02323 ipri = 0;
02324 }
02325 appl = S_OR(stringp, "");
02326
02327 firstc = strchr(appl, ',');
02328 firstp = strchr(appl, '(');
02329 if (firstc && (!firstp || firstc < firstp)) {
02330
02331
02332 appl = strsep(&stringp, ",");
02333 data = stringp;
02334 } else if (!firstc && !firstp) {
02335
02336 data = "";
02337 } else {
02338
02339 appl = strsep(&stringp, "(");
02340 data = stringp;
02341 end = strrchr(data, ')');
02342 if ((end = strrchr(data, ')'))) {
02343 *end = '\0';
02344 } else {
02345 ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
02346 }
02347 ast_process_quotes_and_slashes(data, ',', '|');
02348 }
02349
02350 if (!data)
02351 data="";
02352 appl = ast_skip_blanks(appl);
02353 if (ipri) {
02354 if (plus)
02355 ipri += atoi(plus);
02356 lastpri = ipri;
02357 if (!ast_opt_dont_warn && !strcmp(realext, "_."))
02358 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);
02359 if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), ast_free, registrar)) {
02360 ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
02361 }
02362 }
02363 free(tc);
02364 }
02365 } else if (!strcasecmp(v->name, "include")) {
02366 memset(realvalue, 0, sizeof(realvalue));
02367 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
02368 if (ast_context_add_include2(con, realvalue, registrar))
02369 ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
02370 } else if (!strcasecmp(v->name, "ignorepat")) {
02371 memset(realvalue, 0, sizeof(realvalue));
02372 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
02373 if (ast_context_add_ignorepat2(con, realvalue, registrar))
02374 ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
02375 } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
02376 char *stringp= realvalue;
02377 char *appl, *data;
02378
02379 memset(realvalue, 0, sizeof(realvalue));
02380 if (!strcasecmp(v->name, "switch"))
02381 pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
02382 else
02383 ast_copy_string(realvalue, v->value, sizeof(realvalue));
02384 appl = strsep(&stringp, "/");
02385 data = strsep(&stringp, "");
02386 if (!data)
02387 data = "";
02388 if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar))
02389 ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
02390 }
02391 }
02392 }
02393 ast_config_destroy(cfg);
02394 return 1;
02395 }
02396
02397 static void append_interface(char *iface, int maxlen, char *add)
02398 {
02399 int len = strlen(iface);
02400 if (strlen(add) + len < maxlen - 2) {
02401 if (strlen(iface)) {
02402 iface[len] = '&';
02403 strcpy(iface + len + 1, add);
02404 } else
02405 strcpy(iface, add);
02406 }
02407 }
02408
02409 static void pbx_load_users(void)
02410 {
02411 struct ast_config *cfg;
02412 char *cat, *chan;
02413 const char *dahdichan;
02414 const char *hasexten;
02415 char tmp[256];
02416 char iface[256];
02417 char zapcopy[256];
02418 char *c;
02419 int len;
02420 int hasvoicemail;
02421 int start, finish, x;
02422 struct ast_context *con = NULL;
02423
02424 cfg = ast_config_load("users.conf");
02425 if (!cfg)
02426 return;
02427
02428 for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
02429 if (!strcasecmp(cat, "general"))
02430 continue;
02431 iface[0] = '\0';
02432 len = sizeof(iface);
02433 if (ast_true(ast_config_option(cfg, cat, "hassip"))) {
02434 snprintf(tmp, sizeof(tmp), "SIP/%s", cat);
02435 append_interface(iface, sizeof(iface), tmp);
02436 }
02437 if (ast_true(ast_config_option(cfg, cat, "hasiax"))) {
02438 snprintf(tmp, sizeof(tmp), "IAX2/%s", cat);
02439 append_interface(iface, sizeof(iface), tmp);
02440 }
02441 if (ast_true(ast_config_option(cfg, cat, "hash323"))) {
02442 snprintf(tmp, sizeof(tmp), "H323/%s", cat);
02443 append_interface(iface, sizeof(iface), tmp);
02444 }
02445 hasexten = ast_config_option(cfg, cat, "hasexten");
02446 if (hasexten && !ast_true(hasexten))
02447 continue;
02448 hasvoicemail = ast_true(ast_config_option(cfg, cat, "hasvoicemail"));
02449 dahdichan = ast_variable_retrieve(cfg, cat, "dahdichan");
02450 if (!dahdichan)
02451 dahdichan = ast_variable_retrieve(cfg, "general", "dahdichan");
02452 if (!dahdichan) {
02453
02454 dahdichan = ast_variable_retrieve(cfg, cat, "zapchan");
02455 if (!dahdichan) {
02456 dahdichan = ast_variable_retrieve(cfg, "general", "zapchan");
02457 }
02458 if (!ast_strlen_zero(dahdichan)) {
02459 ast_log(LOG_WARNING, "Use of zapchan in users.conf is deprecated. Please update configuration to use dahdichan instead.\n");
02460 }
02461 }
02462 if (!ast_strlen_zero(dahdichan)) {
02463 ast_copy_string(zapcopy, dahdichan, sizeof(zapcopy));
02464 c = zapcopy;
02465 chan = strsep(&c, ",");
02466 while (chan) {
02467 if (sscanf(chan, "%d-%d", &start, &finish) == 2) {
02468
02469 } else if (sscanf(chan, "%d", &start)) {
02470
02471 finish = start;
02472 } else {
02473 start = 0; finish = 0;
02474 }
02475 if (finish < start) {
02476 x = finish;
02477 finish = start;
02478 start = x;
02479 }
02480 for (x = start; x <= finish; x++) {
02481 snprintf(tmp, sizeof(tmp), "Zap/%d", x);
02482 append_interface(iface, sizeof(iface), tmp);
02483 }
02484 chan = strsep(&c, ",");
02485 }
02486 }
02487 if (!ast_strlen_zero(iface)) {
02488
02489
02490 if (!con)
02491 con = ast_context_find_or_create(&local_contexts, userscontext, registrar);
02492
02493 if (!con) {
02494 ast_log(LOG_ERROR, "Can't find/create user context '%s'\n", userscontext);
02495 return;
02496 }
02497
02498
02499 ast_add_extension2(con, 0, cat, -1, NULL, NULL, iface, NULL, NULL, registrar);
02500
02501 if (hasvoicemail) {
02502 snprintf(tmp, sizeof(tmp), "stdexten|%s|${HINT}", cat);
02503 ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Macro", strdup(tmp), ast_free, registrar);
02504 } else {
02505 ast_add_extension2(con, 0, cat, 1, NULL, NULL, "Dial", strdup("${HINT}"), ast_free, registrar);
02506 }
02507 }
02508 }
02509 ast_config_destroy(cfg);
02510 }
02511
02512 static int pbx_load_module(void)
02513 {
02514 struct ast_context *con;
02515
02516 if(!pbx_load_config(config))
02517 return AST_MODULE_LOAD_DECLINE;
02518
02519 pbx_load_users();
02520
02521 ast_merge_contexts_and_delete(&local_contexts, registrar);
02522
02523 for (con = NULL; (con = ast_walk_contexts(con));)
02524 ast_context_verify_includes(con);
02525
02526 pbx_set_autofallthrough(autofallthrough_config);
02527
02528 return 0;
02529 }
02530
02531 static int load_module(void)
02532 {
02533 if (pbx_load_module())
02534 return AST_MODULE_LOAD_DECLINE;
02535
02536 if (static_config && !write_protect_config)
02537 ast_cli_register(&cli_dialplan_save);
02538 ast_cli_register_multiple(cli_pbx_config, sizeof(cli_pbx_config) / sizeof(struct ast_cli_entry));
02539
02540 return 0;
02541 }
02542
02543 static int reload(void)
02544 {
02545 if (clearglobalvars_config)
02546 pbx_builtin_clear_globals();
02547 pbx_load_module();
02548 return 0;
02549 }
02550
02551 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Text Extension Configuration",
02552 .load = load_module,
02553 .unload = unload_module,
02554 .reload = reload,
02555 );