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