Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:47:55 2009

## Asterisk developer's documentation

# pbx_config.c

Go to the documentation of this file.

    00001 /*
    00002  * Asterisk -- An open source telephony toolkit.
    00003  *
    00004  * Copyright (C) 1999 - 2006, Digium, Inc.
    00005  *
    00006  * Mark Spencer <markster@digium.com>
    00007  *
    00008  * See http://www.asterisk.org for more information about
    00009  * the Asterisk project. Please do not directly contact
    00010  * any of the maintainers of this project for assistance;
    00011  * the project provides a web site, mailing lists and IRC
    00012  * channels for your use.
    00013  *
    00014  * This program is free software, distributed under the terms of
    00015  * the GNU General Public License Version 2. See the LICENSE file
    00016  * at the top of the source tree.
    00017  */
    00018
    00019 /*! \file
    00020  *
    00021  * \brief Populate and remember extensions from static config file
    00022  *
    00023  *
    00024  */
    00025
    00026 #include <sys/types.h>
    00027 #include <stdlib.h>
    00028 #include <stdio.h>
    00029 #include <string.h>
    00030 #include <ctype.h>
    00031 #include <errno.h>
    00032
    00033 #include "asterisk.h"
    00034
    00035 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 211526 $")
    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 #ifdef __AST_DEBUG_MALLOC
    00046 static void FREE(void *ptr)
    00047 {
    00048    free(ptr);
    00049 }
    00050 #else
    00051 #define FREE free
    00052 #endif
    00053
    00054 static char *dtext = "Text Extension Configuration";
    00055 static char *config = "extensions.conf";
    00056 static char *registrar = "pbx_config";
    00057
    00058 static int static_config = 0;
    00059 static int write_protect_config = 1;
    00060 static int autofallthrough_config = 0;
    00061 static int clearglobalvars_config = 0;
    00062
    00063 AST_MUTEX_DEFINE_STATIC(save_dialplan_lock);
    00064
    00065 static struct ast_context *local_contexts = NULL;
    00066
    00067 /*
    00068  * Help for commands provided by this module ...
    00069  */
    00070 static char context_dont_include_help[] =
    00071 "Usage: dont include <context> in <context>\n"
    00072 "       Remove an included context from another context.\n";
    00073
    00074 static char context_remove_extension_help[] =
    00075 "Usage: remove extension exten@context [priority]\n"
    00076 "       Remove an extension from a given context. If a priority\n"
    00077 "       is given, only that specific priority from the given extension\n"
    00078 "       will be removed.\n";
    00079
    00080 static char context_add_include_help[] =
    00081 "Usage: include <context> in <context>\n"
    00082 "       Include a context in another context.\n";
    00083
    00084 static char save_dialplan_help[] =
    00085 "Usage: save dialplan [/path/to/extension/file]\n"
    00086 "       Save dialplan created by pbx_config module.\n"
    00087 "\n"
    00088 "Example: save dialplan                 (/etc/asterisk/extensions.conf)\n"
    00089 "         save dialplan /home/markster  (/home/markster/extensions.conf)\n";
    00090
    00091 static char context_add_extension_help[] =
    00092 "Usage: add extension <exten>,<priority>,<app>,<app-data> into <context>\n"
    00093 "       [replace]\n\n"
    00094 "       This command will add new extension into <context>. If there is an\n"
    00095 "       existence of extension with the same priority and last 'replace'\n"
    00096 "       arguments is given here we simply replace this extension.\n"
    00097 "\n"
    00098 "Example: add extension 6123,1,Dial,IAX/216.207.245.56/6123 into local\n"
    00099 "         Now, you can dial 6123 and talk to Markster :)\n";
    00100
    00101 static char context_add_ignorepat_help[] =
    00102 "Usage: add ignorepat <pattern> into <context>\n"
    00103 "       This command adds a new ignore pattern into context <context>\n"
    00104 "\n"
    00105 "Example: add ignorepat _3XX into local\n";
    00106
    00107 static char context_remove_ignorepat_help[] =
    00108 "Usage: remove ignorepat <pattern> from <context>\n"
    00109 "       This command removes an ignore pattern from context <context>\n"
    00110 "\n"
    00111 "Example: remove ignorepat _3XX from local\n";
    00112
    00113 static char reload_extensions_help[] =
    00114 "Usage: reload extensions.conf without reloading any other modules\n"
    00115 "       This command does not delete global variables unless\n"
    00116 "       clearglobalvars is set to yes in extensions.conf\n"
    00117 "\n"
    00118 "Example: extensions reload\n";
    00119
    00120 /*
    00121  * Implementation of functions provided by this module
    00122  */
    00123
    00124 /*!
    00125  * REMOVE INCLUDE command stuff
    00126  */
    00127 static int handle_context_dont_include(int fd, int argc, char *argv[])
    00128 {
    00129    if (argc != 5)
    00130       return RESULT_SHOWUSAGE;
    00131
    00132    if (strcmp(argv[3], "in"))
    00133       return RESULT_SHOWUSAGE;
    00134
    00135    if (!ast_context_remove_include(argv[4], argv[2], registrar)) {
    00136       ast_cli(fd, "We are not including '%s' in '%s' now\n",
    00137          argv[2], argv[4]);
    00138       return RESULT_SUCCESS;
    00139    }
    00140
    00141    ast_cli(fd, "Failed to remove '%s' include from '%s' context\n",
    00142       argv[2], argv[4]);
    00143    return RESULT_FAILURE;
    00144 }
    00145
    00146 static char *complete_context_dont_include(char *line, char *word,
    00147    int pos, int state)
    00148 {
    00149    int which = 0;
    00150
    00151    /*
    00152     * Context completion ...
    00153     */
    00154    if (pos == 2) {
    00155       struct ast_context *c;
    00156
    00157       if (ast_lock_contexts()) {
    00158          ast_log(LOG_ERROR, "Failed to lock context list\n");
    00159          return NULL;
    00160       }
    00161
    00162       /* walk pbx_get_contexts ... */
    00163       c = ast_walk_contexts(NULL);
    00164       while (c) {
    00165          struct ast_include *i;
    00166
    00167          if (ast_lock_context(c)) {
    00168             c = ast_walk_contexts(c);
    00169             continue;
    00170          }
    00171
    00172          i = ast_walk_context_includes(c, NULL);
    00173          while (i) {
    00174             if (!strlen(word) ||
    00175                !strncmp(ast_get_include_name(i), word, strlen(word))) {
    00176                struct ast_context *nc;
    00177                int already_served = 0;
    00178
    00179                /* check if this include is already served or not */
    00180
    00181                /* go through all contexts again till we reach actuall
    00182                 * context or already_served = 1
    00183                 */
    00184                nc = ast_walk_contexts(NULL);
    00185                while (nc && nc != c && !already_served) {
    00186                   if (!ast_lock_context(nc)) {
    00187                      struct ast_include *ni;
    00188
    00189                      ni = ast_walk_context_includes(nc, NULL);
    00190                      while (ni && !already_served) {
    00191                         if (!strcmp(ast_get_include_name(i),
    00192                            ast_get_include_name(ni)))
    00193                            already_served = 1;
    00194                         ni = ast_walk_context_includes(nc, ni);
    00195                      }
    00196
    00197                      ast_unlock_context(nc);
    00198                   }
    00199                   nc = ast_walk_contexts(nc);
    00200                }
    00201
    00202                if (!already_served) {
    00203                   if (++which > state) {
    00204                      char *res =
    00205                         strdup(ast_get_include_name(i));
    00206                      ast_unlock_context(c);
    00207                      ast_unlock_contexts();
    00208                      return res;
    00209                   }
    00210                }
    00211             }
    00212             i = ast_walk_context_includes(c, i);
    00213          }
    00214
    00215          ast_unlock_context(c);
    00216          c = ast_walk_contexts(c);
    00217       }
    00218
    00219       ast_unlock_contexts();
    00220       return NULL;
    00221    }
    00222
    00223    /*
    00224     * 'in' completion ... (complete only if previous context is really
    00225     * included somewhere)
    00226     */
    00227    if (pos == 3) {
    00228       struct ast_context *c;
    00229       char *context, *dupline, *duplinet;
    00230
    00231       if (state > 0) return NULL;
    00232
    00233       /* take 'context' from line ... */
    00234       if (!(dupline = strdup(line))) {
    00235          ast_log(LOG_ERROR, "Out of free memory\n");
    00236          return NULL;
    00237       }
    00238
    00239       duplinet = dupline;
    00240       strsep(&duplinet, " "); /* skip 'dont' */
    00241       strsep(&duplinet, " "); /* skip 'include' */
    00242       context = strsep(&duplinet, " ");
    00243
    00244       if (!context) {
    00245          free(dupline);
    00246          return NULL;
    00247       }
    00248
    00249       if (ast_lock_contexts()) {
    00250          ast_log(LOG_WARNING, "Failed to lock contexts list\n");
    00251          free(dupline);
    00252          return NULL;
    00253       }
    00254
    00255       /* go through all contexts and check if is included ... */
    00256       c = ast_walk_contexts(NULL);
    00257       while (c) {
    00258          struct ast_include *i;
    00259          if (ast_lock_context(c)) {
    00260             free(dupline);
    00261             ast_unlock_contexts();
    00262             return NULL;
    00263          }
    00264
    00265          i = ast_walk_context_includes(c, NULL);
    00266          while (i) {
    00267             /* is it our context? */
    00268             if (!strcmp(ast_get_include_name(i), context)) {
    00269                /* yes, it is, context is really included, so
    00270                 * complete "in" command
    00271                 */
    00272                free(dupline);
    00273                ast_unlock_context(c);
    00274                ast_unlock_contexts();
    00275                return strdup("in");
    00276             }
    00277             i = ast_walk_context_includes(c, i);
    00278          }
    00279          ast_unlock_context(c);
    00280          c = ast_walk_contexts(c);
    00281       }
    00282       free(dupline);
    00283       ast_unlock_contexts();
    00284       return NULL;
    00285    }
    00286
    00287    /*
    00288     * Context from which we removing include ...
    00289     */
    00290    if (pos == 4) {
    00291       struct ast_context *c;
    00292       char *context, *dupline, *duplinet, *in;
    00293
    00294       if (!(dupline = strdup(line))) {
    00295          ast_log(LOG_ERROR, "Out of free memory\n");
    00296          return NULL;
    00297       }
    00298
    00299       duplinet = dupline;
    00300
    00301       strsep(&duplinet, " "); /* skip 'dont' */
    00302       strsep(&duplinet, " "); /* skip 'include' */
    00303
    00304       if (!(context = strsep(&duplinet, " "))) {
    00305          free(dupline);
    00306          return NULL;
    00307       }
    00308
    00309       /* third word must be in */
    00310       in = strsep(&duplinet, " ");
    00311       if (!in ||
    00312          strcmp(in, "in")) {
    00313          free(dupline);
    00314          return NULL;
    00315       }
    00316
    00317       if (ast_lock_contexts()) {
    00318          ast_log(LOG_ERROR, "Failed to lock context list\n");
    00319          free(dupline);
    00320          return NULL;
    00321       }
    00322
    00323       /* walk through all contexts ... */
    00324       c = ast_walk_contexts(NULL);
    00325       while (c) {
    00326          struct ast_include *i;
    00327          if (ast_lock_context(c)) {
    00328             free(dupline);
    00329             return NULL;
    00330          }
    00331
    00332          /* walk through all includes and check if it is our context */
    00333          i = ast_walk_context_includes(c, NULL);
    00334          while (i) {
    00335             /* is in this context included another on which we want to
    00336              * remove?
    00337              */
    00338             if (!strcmp(context, ast_get_include_name(i))) {
    00339                /* yes, it's included, is matching our word too? */
    00340                if (!strncmp(ast_get_context_name(c),
    00341                      word, strlen(word))) {
    00342                   /* check state for completion */
    00343                   if (++which > state) {
    00344                      char *res = strdup(ast_get_context_name(c));
    00345                      free(dupline);
    00346                      ast_unlock_context(c);
    00347                      ast_unlock_contexts();
    00348                      return res;
    00349                   }
    00350                }
    00351                break;
    00352             }
    00353             i = ast_walk_context_includes(c, i);
    00354          }
    00355          ast_unlock_context(c);
    00356          c = ast_walk_contexts(c);
    00357       }
    00358
    00359       free(dupline);
    00360       ast_unlock_contexts();
    00361       return NULL;
    00362    }
    00363
    00364    return NULL;
    00365 }
    00366
    00367 /*!
    00368  * REMOVE EXTENSION command stuff
    00369  */
    00370 static int handle_context_remove_extension(int fd, int argc, char *argv[])
    00371 {
    00372    int removing_priority = 0;
    00373    char *exten, *context;
    00374
    00375    if (argc != 4 && argc != 3) return RESULT_SHOWUSAGE;
    00376
    00377    /*
    00378     * Priority input checking ...
    00379     */
    00380    if (argc == 4) {
    00381       char *c = argv[3];
    00382
    00383       /* check for digits in whole parameter for right priority ...
    00384        * why? because atoi (strtol) returns 0 if any characters in
    00385        * string and whole extension will be removed, it's not good
    00386        */
    00387       if (strcmp("hint", c)) {
    00388              while (*c != '\0') {
    00389          if (!isdigit(*c++)) {
    00390             ast_cli(fd, "Invalid priority '%s'\n", argv[3]);
    00391             return RESULT_FAILURE;
    00392          }
    00393           }
    00394           removing_priority = atoi(argv[3]);
    00395       } else
    00396           removing_priority = PRIORITY_HINT;
    00397
    00398       if (removing_priority == 0) {
    00399          ast_cli(fd, "If you want to remove whole extension, please " \
    00400             "omit priority argument\n");
    00401          return RESULT_FAILURE;
    00402       }
    00403    }
    00404
    00405    /*
    00406     * Format exten@context checking ...
    00407     */
    00408    if (!(context = strchr(argv[2], (int)'@'))) {
    00409       ast_cli(fd, "First argument must be in exten@context format\n");
    00410       return RESULT_FAILURE;
    00411    }
    00412
    00413    *context++ = '\0';
    00414    exten = argv[2];
    00415    if ((!strlen(exten)) || (!(strlen(context)))) {
    00416       ast_cli(fd, "Missing extension or context name in second argument '%s@%s'\n",
    00417          exten == NULL ? "?" : exten, context == NULL ? "?" : context);
    00418       return RESULT_FAILURE;
    00419    }
    00420
    00421    if (!ast_context_remove_extension(context, exten, removing_priority, registrar)) {
    00422       if (!removing_priority)
    00423          ast_cli(fd, "Whole extension %s@%s removed\n",
    00424             exten, context);
    00425       else
    00426          ast_cli(fd, "Extension %s@%s with priority %d removed\n",
    00427             exten, context, removing_priority);
    00428
    00429       return RESULT_SUCCESS;
    00430    }
    00431
    00432    ast_cli(fd, "Failed to remove extension %s@%s\n", exten, context);
    00433
    00434    return RESULT_FAILURE;
    00435 }
    00436
    00437 #define BROKEN_READLINE 1
    00438
    00439 #ifdef BROKEN_READLINE
    00440 /*
    00441  * There is one funny thing, when you have word like 300@ and you hit
    00442  * <tab>, you arguments will like as your word is '300 ', so it '@'
    00443  * characters acts sometimes as word delimiter and sometimes as a part
    00444  * of word
    00445  *
    00446  * This fix function, allocates new word variable and store here every
    00447  * time xxx@yyy always as one word and correct pos is set too
    00448  *
    00449  * It's ugly, I know, but I'm waiting for Mark suggestion if upper is
    00450  * bug or feature ...
    00451  */
    00452 static int fix_complete_args(char *line, char **word, int *pos)
    00453 {
    00454    char *_line, *_strsep_line, *_previous_word = NULL, *_word = NULL;
    00455    int words = 0;
    00456
    00457    _line = strdup(line);
    00458
    00459    _strsep_line = _line;
    00460    while (_strsep_line) {
    00461       _previous_word = _word;
    00462       _word = strsep(&_strsep_line, " ");
    00463
    00464       if (_word && strlen(_word)) words++;
    00465    }
    00466
    00467
    00468    if (_word || _previous_word) {
    00469       if (_word) {
    00470          if (!strlen(_word)) words++;
    00471          *word = strdup(_word);
    00472       } else
    00473          *word = strdup(_previous_word);
    00474       *pos = words - 1;
    00475       free(_line);
    00476       return 0;
    00477    }
    00478
    00479    free(_line);
    00480    return -1;
    00481 }
    00482 #endif /* BROKEN_READLINE */
    00483
    00484 static char *complete_context_remove_extension(char *line, char *word, int pos,
    00485    int state)
    00486 {
    00487    char *ret = NULL;
    00488    int which = 0;
    00489
    00490 #ifdef BROKEN_READLINE
    00491    /*
    00492     * Fix arguments, *word is a new allocated structure, REMEMBER to
    00493     * free *word when you want to return from this function ...
    00494     */
    00495    if (fix_complete_args(line, &word, &pos)) {
    00496       ast_log(LOG_ERROR, "Out of free memory\n");
    00497       return NULL;
    00498    }
    00499 #endif
    00500
    00501    /*
    00502     * exten@context completion ...
    00503     */
    00504    if (pos == 2) {
    00505       struct ast_context *c;
    00506       struct ast_exten *e;
    00507       char *context = NULL, *exten = NULL, *delim = NULL;
    00508
    00509       /* now, parse values from word = exten@context */
    00510       if ((delim = strchr(word, (int)'@'))) {
    00511          /* check for duplicity ... */
    00512          if (delim != strrchr(word, (int)'@')) {
    00513 #ifdef BROKEN_READLINE
    00514             free(word);
    00515 #endif
    00516             return NULL;
    00517          }
    00518
    00519          *delim = '\0';
    00520          exten = strdup(word);
    00521          context = strdup(delim + 1);
    00522          *delim = '@';
    00523       } else {
    00524          exten = strdup(word);
    00525       }
    00526 #ifdef BROKEN_READLINE
    00527       free(word);
    00528 #endif
    00529
    00530       if (ast_lock_contexts()) {
    00531          ast_log(LOG_ERROR, "Failed to lock context list\n");
    00532          free(context); free(exten);
    00533          return NULL;
    00534       }
    00535
    00536       /* find our context ... */
    00537       c = ast_walk_contexts(NULL);
    00538       while (c) {
    00539          /* our context? */
    00540          if ( (!context || !strlen(context)) ||                            /* if no input, all contexts ... */
    00541              (context && !strncmp(ast_get_context_name(c),
    00542                           context, strlen(context))) ) {                  /* if input, compare ... */
    00543             /* try to complete extensions ... */
    00544             e = ast_walk_context_extensions(c, NULL);
    00545             while (e) {
    00546                /* our extension? */
    00547                if ( (!exten || !strlen(exten)) ||                           /* if not input, all extensions ... */
    00548                    (exten && !strncmp(ast_get_extension_name(e), exten,
    00549                                       strlen(exten))) ) { /* if input, compare ... */
    00550                   if (++which > state) {
    00551                      /* If there is an extension then return
    00552                       * exten@context.
    00553                       */
    00554                      if (exten) {
    00555                         ret = malloc(strlen(ast_get_extension_name(e)) +
    00556                            strlen(ast_get_context_name(c)) + 2);
    00557                         if (ret)
    00558                            sprintf(ret, "%s@%s", ast_get_extension_name(e),
    00559                               ast_get_context_name(c));
    00560                      }
    00561                      free(exten); free(context);
    00562
    00563                      ast_unlock_contexts();
    00564
    00565                      return ret;
    00566                   }
    00567                }
    00568                e = ast_walk_context_extensions(c, e);
    00569             }
    00570          }
    00571          c = ast_walk_contexts(c);
    00572       }
    00573
    00574       ast_unlock_contexts();
    00575
    00576       free(exten); free(context);
    00577
    00578       return NULL;
    00579    }
    00580
    00581    /*
    00582     * Complete priority ...
    00583     */
    00584    if (pos == 3) {
    00585       char *delim, *exten, *context, *dupline, *duplinet, *ec;
    00586       struct ast_context *c;
    00587
    00588       dupline = strdup(line);
    00589       if (!dupline) {
    00590 #ifdef BROKEN_READLINE
    00591          free(word);
    00592 #endif
    00593          return NULL;
    00594       }
    00595       duplinet = dupline;
    00596
    00597       strsep(&duplinet, " "); /* skip 'remove' */
    00598       strsep(&duplinet, " "); /* skip 'extension */
    00599
    00600       if (!(ec = strsep(&duplinet, " "))) {
    00601          free(dupline);
    00602 #ifdef BROKEN_READLINE
    00603          free(word);
    00604 #endif
    00605          return NULL;
    00606       }
    00607
    00608       /* wrong exten@context format? */
    00609       if (!(delim = strchr(ec, (int)'@')) ||
    00610          (strchr(ec, (int)'@') != strrchr(ec, (int)'@'))) {
    00611 #ifdef BROKEN_READLINE
    00612          free(word);
    00613 #endif
    00614          free(dupline);
    00615          return NULL;
    00616       }
    00617
    00618       /* check if there is exten and context too ... */
    00619       *delim = '\0';
    00620       if ((!strlen(ec)) || (!strlen(delim + 1))) {
    00621 #ifdef BROKEN_READLINE
    00622          free(word);
    00623 #endif
    00624          free(dupline);
    00625          return NULL;
    00626       }
    00627
    00628       exten = strdup(ec);
    00629       context = strdup(delim + 1);
    00630       free(dupline);
    00631
    00632       if (ast_lock_contexts()) {
    00633          ast_log(LOG_ERROR, "Failed to lock context list\n");
    00634 #ifdef BROKEN_READLINE
    00635          free(word);
    00636 #endif
    00637          free(exten); free(context);
    00638          return NULL;
    00639       }
    00640
    00641       /* walk contexts */
    00642       c = ast_walk_contexts(NULL);
    00643       while (c) {
    00644          if (!strcmp(ast_get_context_name(c), context)) {
    00645             struct ast_exten *e;
    00646
    00647             /* walk extensions */
    00648             free(context);
    00649             e = ast_walk_context_extensions(c, NULL);
    00650             while (e) {
    00651                if (!strcmp(ast_get_extension_name(e), exten)) {
    00652                   struct ast_exten *priority;
    00653                   char buffer[10];
    00654
    00655                   free(exten);
    00656                   priority = ast_walk_extension_priorities(e, NULL);
    00657                   /* serve priorities */
    00658                   do {
    00659                      snprintf(buffer, 10, "%u",
    00660                         ast_get_extension_priority(priority));
    00661                      if (!strncmp(word, buffer, strlen(word))) {
    00662                         if (++which > state) {
    00663 #ifdef BROKEN_READLINE
    00664                            free(word);
    00665 #endif
    00666                            ast_unlock_contexts();
    00667                            return strdup(buffer);
    00668                         }
    00669                      }
    00670                      priority = ast_walk_extension_priorities(e,
    00671                         priority);
    00672                   } while (priority);
    00673
    00674 #ifdef BROKEN_READLINE
    00675                   free(word);
    00676 #endif
    00677                   ast_unlock_contexts();
    00678                   return NULL;
    00679                }
    00680                e = ast_walk_context_extensions(c, e);
    00681             }
    00682 #ifdef BROKEN_READLINE
    00683             free(word);
    00684 #endif
    00685             free(exten);
    00686             ast_unlock_contexts();
    00687             return NULL;
    00688          }
    00689          c = ast_walk_contexts(c);
    00690       }
    00691
    00692 #ifdef BROKEN_READLINE
    00693       free(word);
    00694 #endif
    00695       free(exten); free(context);
    00696
    00697       ast_unlock_contexts();
    00698       return NULL;
    00699    }
    00700
    00701 #ifdef BROKEN_READLINE
    00702    free(word);
    00703 #endif
    00704    return NULL;
    00705 }
    00706
    00707 /*!
    00708  * Include context ...
    00709  */
    00710 static int handle_context_add_include(int fd, int argc, char *argv[])
    00711 {
    00712    if (argc != 5) return RESULT_SHOWUSAGE;
    00713
    00714    /* third arg must be 'in' ... */
    00715    if (strcmp(argv[3], "in") && strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
    00716
    00717    if (ast_context_add_include(argv[4], argv[2], registrar)) {
    00718       switch (errno) {
    00719          case ENOMEM:
    00720             ast_cli(fd, "Out of memory for context addition\n"); break;
    00721
    00722          case EBUSY:
    00723             ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
    00724
    00725          case EEXIST:
    00726             ast_cli(fd, "Context '%s' already included in '%s' context\n",
    00727                argv[2], argv[4]); break;
    00728
    00729          case ENOENT:
    00730          case EINVAL:
    00731             ast_cli(fd, "There is no existence of context '%s'\n",
    00732                errno == ENOENT ? argv[4] : argv[2]); break;
    00733
    00734          default:
    00735             ast_cli(fd, "Failed to include '%s' in '%s' context\n",
    00736                argv[2], argv[4]); break;
    00737       }
    00738       return RESULT_FAILURE;
    00739    }
    00740
    00741    /* show some info ... */
    00742    ast_cli(fd, "Context '%s' included in '%s' context\n",
    00743       argv[2], argv[4]);
    00744
    00745    return RESULT_SUCCESS;
    00746 }
    00747
    00748 static char *complete_context_add_include(char *line, char *word, int pos,
    00749     int state)
    00750 {
    00751    struct ast_context *c;
    00752    int which = 0;
    00753
    00754    /* server context for inclusion ... */
    00755    if (pos == 1)
    00756    {
    00757       if (ast_lock_contexts()) {
    00758          ast_log(LOG_ERROR, "Failed to lock context list\n");
    00759          return NULL;
    00760       }
    00761
    00762       /* server all contexts */
    00763       c = ast_walk_contexts(NULL);
    00764       while (c) {
    00765          if ((!strlen(word) ||
    00766              !strncmp(ast_get_context_name(c), word, strlen(word))) &&
    00767             ++which > state)
    00768          {
    00769             char *context = strdup(ast_get_context_name(c));
    00770             ast_unlock_contexts();
    00771             return context;
    00772          }
    00773          c = ast_walk_contexts(c);
    00774       }
    00775
    00776       ast_unlock_contexts();
    00777    }
    00778
    00779    /* complete 'in' only if context exist ... */
    00780    if (pos == 2)
    00781    {
    00782       char *context, *dupline, *duplinet;
    00783
    00784       if (state != 0) return NULL;
    00785
    00786       /* parse context from line ... */
    00787       if (!(dupline = strdup(line))) {
    00788          ast_log(LOG_ERROR, "Out of free memory\n");
    00789          if (state == 0) return strdup("in");
    00790          return NULL;
    00791       }
    00792
    00793       duplinet = dupline;
    00794
    00795       strsep(&duplinet, " ");
    00796       context = strsep(&duplinet, " ");
    00797       if (context) {
    00798          struct ast_context *c;
    00799          int context_existence = 0;
    00800
    00801          /* check for context existence ... */
    00802          if (ast_lock_contexts()) {
    00803             ast_log(LOG_ERROR, "Failed to lock context list\n");
    00804             free(dupline);
    00805             /* our fault, we can't check, so complete 'in' ... */
    00806             return strdup("in");
    00807          }
    00808
    00809          c = ast_walk_contexts(NULL);
    00810          while (c && !context_existence) {
    00811             if (!strcmp(context, ast_get_context_name(c))) {
    00812                context_existence = 1;
    00813                continue;
    00814             }
    00815             c = ast_walk_contexts(c);
    00816          }
    00817
    00818          /* if context exists, return 'into' ... */
    00819          if (context_existence) {
    00820             free(dupline);
    00821             ast_unlock_contexts();
    00822             return strdup("into");
    00823          }
    00824
    00825          ast_unlock_contexts();
    00826       }
    00827
    00828       free(dupline);
    00829       return NULL;
    00830    }
    00831
    00832    /* serve context into which we include another context */
    00833    if (pos == 3)
    00834    {
    00835       char *context, *dupline, *duplinet, *in;
    00836       int context_existence = 0;
    00837
    00838       if (!(dupline = strdup(line))) {
    00839          ast_log(LOG_ERROR, "Out of free memory\n");
    00840          return NULL;
    00841       }
    00842
    00843       duplinet = dupline;
    00844
    00845       strsep(&duplinet, " "); /* skip 'include' */
    00846       context = strsep(&duplinet, " ");
    00847       in = strsep(&duplinet, " ");
    00848
    00849       /* given some context and third word is in? */
    00850       if (!strlen(context) || strcmp(in, "in")) {
    00851          free(dupline);
    00852          return NULL;
    00853       }
    00854
    00855       if (ast_lock_contexts()) {
    00856          ast_log(LOG_ERROR, "Failed to lock context list\n");
    00857          free(dupline);
    00858          return NULL;
    00859       }
    00860
    00861       /* check for context existence ... */
    00862       c = ast_walk_contexts(NULL);
    00863       while (c && !context_existence) {
    00864          if (!strcmp(context, ast_get_context_name(c))) {
    00865             context_existence = 1;
    00866             continue;
    00867          }
    00868          c = ast_walk_contexts(c);
    00869       }
    00870
    00871       if (!context_existence) {
    00872          free(dupline);
    00873          ast_unlock_contexts();
    00874          return NULL;
    00875       }
    00876
    00877       /* go through all contexts ... */
    00878       c = ast_walk_contexts(NULL);
    00879       while (c) {
    00880          /* must be different contexts ... */
    00881          if (strcmp(context, ast_get_context_name(c))) {
    00882             if (!ast_lock_context(c)) {
    00883                struct ast_include *i;
    00884                int included = 0;
    00885
    00886                /* check for duplicity inclusion ... */
    00887                i = ast_walk_context_includes(c, NULL);
    00888                while (i && !included) {
    00889                   if (!strcmp(ast_get_include_name(i), context))
    00890                      included = 1;
    00891                   i = ast_walk_context_includes(c, i);
    00892                }
    00893                ast_unlock_context(c);
    00894
    00895                /* not included yet, so show possibility ... */
    00896                if (!included &&
    00897                   !strncmp(ast_get_context_name(c), word, strlen(word))){
    00898
    00899                   if (++which > state) {
    00900                      char *res = strdup(ast_get_context_name(c));
    00901                      free(dupline);
    00902                      ast_unlock_contexts();
    00903                      return res;
    00904                   }
    00905                }
    00906             }
    00907          }
    00908          c = ast_walk_contexts(c);
    00909       }
    00910
    00911       ast_unlock_contexts();
    00912       free(dupline);
    00913       return NULL;
    00914    }
    00915
    00916    return NULL;
    00917 }
    00918
    00919 /*!
    00920  * \brief 'save dialplan' CLI command implementation functions ...
    00921  */
    00922 static int handle_save_dialplan(int fd, int argc, char *argv[])
    00923 {
    00924    char filename[256];
    00925    struct ast_context *c;
    00926    struct ast_config *cfg;
    00927    struct ast_variable *v;
    00928    int context_header_written;
    00929    int incomplete = 0; /* incomplete config write? */
    00930    FILE *output;
    00931
    00932    if (! (static_config && !write_protect_config)) {
    00933       ast_cli(fd,
    00934          "I can't save dialplan now, see '%s' example file.\n",
    00935          config);
    00936       return RESULT_FAILURE;
    00937    }
    00938
    00939    if (argc != 2 && argc != 3) return RESULT_SHOWUSAGE;
    00940
    00941    if (ast_mutex_lock(&save_dialplan_lock)) {
    00942       ast_cli(fd,
    00943          "Failed to lock dialplan saving (another proccess saving?)\n");
    00944       return RESULT_FAILURE;
    00945    }
    00946
    00947    /* have config path? */
    00948    if (argc == 3) {
    00949       /* is there extension.conf too? */
    00950       if (!strstr(argv[2], ".conf")) {
    00951          /* no, only directory path, check for last '/' occurence */
    00952          if (*(argv[2] + strlen(argv[2]) -1) == '/')
    00953             snprintf(filename, sizeof(filename), "%s%s",
    00954                argv[2], config);
    00955          else
    00956             /* without config extensions.conf, add it */
    00957             snprintf(filename, sizeof(filename), "%s/%s",
    00958                argv[2], config);
    00959       } else
    00960          /* there is an .conf */
    00961          snprintf(filename, sizeof(filename), argv[2]);
    00962    } else
    00963       /* no config file, default one */
    00964       snprintf(filename, sizeof(filename), "%s/%s",
    00965          (char *)ast_config_AST_CONFIG_DIR, config);
    00966
    00967    cfg = ast_config_load("extensions.conf");
    00968
    00969    /* try to lock contexts list */
    00970    if (ast_lock_contexts()) {
    00971       ast_cli(fd, "Failed to lock contexts list\n");
    00972       ast_mutex_unlock(&save_dialplan_lock);
    00973       ast_config_destroy(cfg);
    00974       return RESULT_FAILURE;
    00975    }
    00976
    00977    /* create new file ... */
    00978    if (!(output = fopen(filename, "wt"))) {
    00979       ast_cli(fd, "Failed to create file '%s'\n",
    00980          filename);
    00981       ast_unlock_contexts();
    00982       ast_mutex_unlock(&save_dialplan_lock);
    00983       ast_config_destroy(cfg);
    00984       return RESULT_FAILURE;
    00985    }
    00986
    00987    /* fireout general info */
    00988    fprintf(output, "[general]\nstatic=%s\nwriteprotect=%s\nautofallthrough=%s\nclearglobalvars=%s\npriorityjumping=%s\n\n",
    00989       static_config ? "yes" : "no",
    00990       write_protect_config ? "yes" : "no",
    00991       autofallthrough_config ? "yes" : "no",
    00992       clearglobalvars_config ? "yes" : "no",
    00993       option_priority_jumping ? "yes" : "no");
    00994
    00995    if ((v = ast_variable_browse(cfg, "globals"))) {
    00996       fprintf(output, "[globals]\n");
    00997       while(v) {
    00998          fprintf(output, "%s => %s\n", v->name, v->value);
    00999          v = v->next;
    01000       }
    01001       fprintf(output, "\n");
    01002    }
    01003
    01004    ast_config_destroy(cfg);
    01005
    01006    /* walk all contexts */
    01007    c = ast_walk_contexts(NULL);
    01008    while (c) {
    01009       context_header_written = 0;
    01010
    01011       /* try to lock context and fireout all info */
    01012       if (!ast_lock_context(c)) {
    01013          struct ast_exten *e, *last_written_e = NULL;
    01014          struct ast_include *i;
    01015          struct ast_ignorepat *ip;
    01016          struct ast_sw *sw;
    01017
    01018          /* registered by this module? */
    01019          if (!strcmp(ast_get_context_registrar(c), registrar)) {
    01020             fprintf(output, "[%s]\n", ast_get_context_name(c));
    01021             context_header_written = 1;
    01022          }
    01023
    01024          /* walk extensions ... */
    01025          e = ast_walk_context_extensions(c, NULL);
    01026          while (e) {
    01027             struct ast_exten *p;
    01028
    01029             /* fireout priorities */
    01030             p = ast_walk_extension_priorities(e, NULL);
    01031             while (p) {
    01032                if (!strcmp(ast_get_extension_registrar(p),
    01033                   registrar)) {
    01034
    01035                   /* make empty line between different extensions */
    01036                   if (last_written_e != NULL &&
    01037                      strcmp(ast_get_extension_name(last_written_e),
    01038                         ast_get_extension_name(p)))
    01039                      fprintf(output, "\n");
    01040                   last_written_e = p;
    01041
    01042                   if (!context_header_written) {
    01043                      fprintf(output, "[%s]\n", ast_get_context_name(c));
    01044                      context_header_written = 1;
    01045                   }
    01046
    01047                   if (ast_get_extension_priority(p)!=PRIORITY_HINT) {
    01048                      char *tempdata, *startdata;
    01049                      const char *el = ast_get_extension_label(p);
    01050                      char label[128] = "";
    01051
    01052                      tempdata = ast_strdupa(ast_get_extension_app_data(p));
    01053
    01054                      startdata = tempdata;
    01055                      while (*tempdata) {
    01056                         if (*tempdata == '|')
    01057                            *tempdata = ',';
    01058                         tempdata++;
    01059                      }
    01060                      tempdata = startdata;
    01061
    01062                      if (el && (snprintf(label, sizeof(label), "(%s)", el) != (strlen(el) + 2)))
    01063                         incomplete = 1; // error encountered or label is > 125 chars
    01064
    01065                      if (ast_get_extension_matchcid(p)) {
    01066                         fprintf(output, "exten => %s/%s,%d%s,%s(%s)\n",
    01067                             ast_get_extension_name(p),
    01068                             ast_get_extension_cidmatch(p),
    01069                             ast_get_extension_priority(p), label,
    01070                             ast_get_extension_app(p),
    01071                             tempdata);
    01072                      } else {
    01073                         fprintf(output, "exten => %s,%d%s,%s(%s)\n",
    01074                             ast_get_extension_name(p),
    01075                             ast_get_extension_priority(p), label,
    01076                             ast_get_extension_app(p),
    01077                             tempdata);
    01078                      }
    01079                   } else {
    01080                      fprintf(output, "exten => %s,hint,%s\n",
    01081                          ast_get_extension_name(p),
    01082                          ast_get_extension_app(p));
    01083                   }
    01084
    01085                }
    01086                p = ast_walk_extension_priorities(e, p);
    01087             }
    01088
    01089             e = ast_walk_context_extensions(c, e);
    01090          }
    01091
    01092          /* written any extensions? ok, write space between exten & inc */
    01093          if (last_written_e) fprintf(output, "\n");
    01094
    01095          /* walk through includes */
    01096          i = ast_walk_context_includes(c, NULL);
    01097          while (i) {
    01098             if (!strcmp(ast_get_include_registrar(i), registrar)) {
    01099                if (!context_header_written) {
    01100                   fprintf(output, "[%s]\n", ast_get_context_name(c));
    01101                   context_header_written = 1;
    01102                }
    01103                fprintf(output, "include => %s\n",
    01104                   ast_get_include_name(i));
    01105             }
    01106             i = ast_walk_context_includes(c, i);
    01107          }
    01108
    01109          if (ast_walk_context_includes(c, NULL))
    01110             fprintf(output, "\n");
    01111
    01112          /* walk through switches */
    01113          sw = ast_walk_context_switches(c, NULL);
    01114          while (sw) {
    01115             if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
    01116                if (!context_header_written) {
    01117                   fprintf(output, "[%s]\n", ast_get_context_name(c));
    01118                   context_header_written = 1;
    01119                }
    01120                fprintf(output, "switch => %s/%s\n",
    01121                   ast_get_switch_name(sw),
    01122                   ast_get_switch_data(sw));
    01123             }
    01124             sw = ast_walk_context_switches(c, sw);
    01125          }
    01126
    01127          if (ast_walk_context_switches(c, NULL))
    01128             fprintf(output, "\n");
    01129
    01130          /* fireout ignorepats ... */
    01131          ip = ast_walk_context_ignorepats(c, NULL);
    01132          while (ip) {
    01133             if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
    01134                if (!context_header_written) {
    01135                   fprintf(output, "[%s]\n", ast_get_context_name(c));
    01136                   context_header_written = 1;
    01137                }
    01138
    01139                fprintf(output, "ignorepat => %s\n",
    01140                   ast_get_ignorepat_name(ip));
    01141             }
    01142             ip = ast_walk_context_ignorepats(c, ip);
    01143          }
    01144
    01145          ast_unlock_context(c);
    01146       } else
    01147          incomplete = 1;
    01148
    01149       c = ast_walk_contexts(c);
    01150    }
    01151
    01152    ast_unlock_contexts();
    01153    ast_mutex_unlock(&save_dialplan_lock);
    01154    fclose(output);
    01155
    01156    if (incomplete) {
    01157       ast_cli(fd, "Saved dialplan is incomplete\n");
    01158       return RESULT_FAILURE;
    01159    }
    01160
    01161    ast_cli(fd, "Dialplan successfully saved into '%s'\n",
    01162       filename);
    01163    return RESULT_SUCCESS;
    01164 }
    01165
    01166 /*!
    01167  * \brief ADD EXTENSION command stuff
    01168  */
    01169 static int handle_context_add_extension(int fd, int argc, char *argv[])
    01170 {
    01171    char *whole_exten;
    01172    char *exten, *prior;
    01173    int iprior = -2;
    01174    char *cidmatch, *app, *app_data;
    01175    char *start, *end;
    01176
    01177    /* check for arguments at first */
    01178    if (argc != 5 && argc != 6) return RESULT_SHOWUSAGE;
    01179    if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
    01180    if (argc == 6) if (strcmp(argv[5], "replace")) return RESULT_SHOWUSAGE;
    01181
    01182    whole_exten = argv[2];
    01183    exten       = strsep(&whole_exten,",");
    01184    if (strchr(exten, '/')) {
    01185       cidmatch = exten;
    01186       strsep(&cidmatch,"/");
    01187    } else {
    01188       cidmatch = NULL;
    01189    }
    01190    prior       = strsep(&whole_exten,",");
    01191    if (prior) {
    01192       if (!strcmp(prior, "hint")) {
    01193          iprior = PRIORITY_HINT;
    01194       } else {
    01195          if (sscanf(prior, "%30d", &iprior) != 1) {
    01196             ast_cli(fd, "'%s' is not a valid priority\n", prior);
    01197             prior = NULL;
    01198          }
    01199       }
    01200    }
    01201    app = whole_exten;
    01202    if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
    01203       *start = *end = '\0';
    01204       app_data = start + 1;
    01205       ast_process_quotes_and_slashes(app_data, ',', '|');
    01206    } else {
    01207       if (app) {
    01208          app_data = strchr(app, ',');
    01209          if (app_data) {
    01210             *app_data = '\0';
    01211             app_data++;
    01212          }
    01213       } else
    01214          app_data = NULL;
    01215    }
    01216
    01217    if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT)) return RESULT_SHOWUSAGE;
    01218
    01219    if (!app_data)
    01220       app_data="";
    01221    if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, iprior, NULL, cidmatch, app,
    01222       (void *)strdup(app_data), free, registrar)) {
    01223       switch (errno) {
    01224          case ENOMEM:
    01225             ast_cli(fd, "Out of free memory\n"); break;
    01226
    01227          case EBUSY:
    01228             ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
    01229
    01230          case ENOENT:
    01231             ast_cli(fd, "No existence of '%s' context\n", argv[4]); break;
    01232
    01233          case EEXIST:
    01234             ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
    01235                exten, argv[4], prior); break;
    01236
    01237          default:
    01238             ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
    01239                exten, prior, app, app_data, argv[4]); break;
    01240       }
    01241       return RESULT_FAILURE;
    01242    }
    01243
    01244    if (argc == 6)
    01245       ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
    01246          exten, argv[4], prior, exten, prior, app, app_data);
    01247    else
    01248       ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
    01249          exten, prior, app, app_data, argv[4]);
    01250
    01251    return RESULT_SUCCESS;
    01252 }
    01253
    01254 /*! add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
    01255 static char *complete_context_add_extension(char *line, char *word,
    01256    int pos, int state)
    01257 {
    01258    int which = 0;
    01259
    01260    /* complete 'into' word ... */
    01261    if (pos == 3) {
    01262       if (state == 0) return strdup("into");
    01263       return NULL;
    01264    }
    01265
    01266    /* complete context */
    01267    if (pos == 4) {
    01268       struct ast_context *c;
    01269
    01270       /* try to lock contexts list ... */
    01271       if (ast_lock_contexts()) {
    01272          ast_log(LOG_WARNING, "Failed to lock contexts list\n");
    01273          return NULL;
    01274       }
    01275
    01276       /* walk through all contexts */
    01277       c = ast_walk_contexts(NULL);
    01278       while (c) {
    01279          /* matching context? */
    01280          if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
    01281             if (++which > state) {
    01282                char *res = strdup(ast_get_context_name(c));
    01283                ast_unlock_contexts();
    01284                return res;
    01285             }
    01286          }
    01287          c = ast_walk_contexts(c);
    01288       }
    01289
    01290       ast_unlock_contexts();
    01291       return NULL;
    01292    }
    01293
    01294    if (pos == 5) return state == 0 ? strdup("replace") : NULL;
    01295
    01296    return NULL;
    01297 }
    01298
    01299 /*!
    01300  * IGNOREPAT CLI stuff
    01301  */
    01302 static int handle_context_add_ignorepat(int fd, int argc, char *argv[])
    01303 {
    01304    if (argc != 5) return RESULT_SHOWUSAGE;
    01305    if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
    01306
    01307    if (ast_context_add_ignorepat(argv[4], argv[2], registrar)) {
    01308       switch (errno) {
    01309          case ENOMEM:
    01310             ast_cli(fd, "Out of free memory\n"); break;
    01311
    01312          case ENOENT:
    01313             ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
    01314             break;
    01315
    01316          case EEXIST:
    01317             ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
    01318                argv[2], argv[4]);
    01319             break;
    01320
    01321          case EBUSY:
    01322             ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
    01323             break;
    01324
    01325          default:
    01326             ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
    01327                argv[2], argv[4]);
    01328             break;
    01329       }
    01330       return RESULT_FAILURE;
    01331    }
    01332
    01333    ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
    01334       argv[2], argv[4]);
    01335    return RESULT_SUCCESS;
    01336 }
    01337
    01338 static char *complete_context_add_ignorepat(char *line, char *word,
    01339    int pos, int state)
    01340 {
    01341    if (pos == 3) return state == 0 ? strdup("into") : NULL;
    01342
    01343    if (pos == 4) {
    01344       struct ast_context *c;
    01345       int which = 0;
    01346       char *dupline, *duplinet, *ignorepat = NULL;
    01347
    01348       dupline = strdup(line);
    01349       duplinet = dupline;
    01350
    01351       if (duplinet) {
    01352          strsep(&duplinet, " "); /* skip 'add' */
    01353          strsep(&duplinet, " "); /* skip 'ignorepat' */
    01354          ignorepat = strsep(&duplinet, " ");
    01355       }
    01356
    01357       if (ast_lock_contexts()) {
    01358          ast_log(LOG_ERROR, "Failed to lock contexts list\n");
    01359          return NULL;
    01360       }
    01361
    01362       c = ast_walk_contexts(NULL);
    01363       while (c) {
    01364          if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
    01365             int serve_context = 1;
    01366             if (ignorepat) {
    01367                if (!ast_lock_context(c)) {
    01368                   struct ast_ignorepat *ip;
    01369                   ip = ast_walk_context_ignorepats(c, NULL);
    01370                   while (ip && serve_context) {
    01371                      if (!strcmp(ast_get_ignorepat_name(ip), ignorepat))
    01372                         serve_context = 0;
    01373                      ip = ast_walk_context_ignorepats(c, ip);
    01374                   }
    01375                   ast_unlock_context(c);
    01376                }
    01377             }
    01378             if (serve_context) {
    01379                if (++which > state) {
    01380                   char *context = strdup(ast_get_context_name(c));
    01381                   if (dupline) free(dupline);
    01382                   ast_unlock_contexts();
    01383                   return context;
    01384                }
    01385             }
    01386          }
    01387          c = ast_walk_contexts(c);
    01388       }
    01389
    01390       if (dupline) free(dupline);
    01391       ast_unlock_contexts();
    01392       return NULL;
    01393    }
    01394
    01395    return NULL;
    01396 }
    01397
    01398 static int handle_context_remove_ignorepat(int fd, int argc, char *argv[])
    01399 {
    01400    if (argc != 5) return RESULT_SHOWUSAGE;
    01401    if (strcmp(argv[3], "from")) return RESULT_SHOWUSAGE;
    01402
    01403    if (ast_context_remove_ignorepat(argv[4], argv[2], registrar)) {
    01404       switch (errno) {
    01405          case EBUSY:
    01406             ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
    01407             break;
    01408
    01409          case ENOENT:
    01410             ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
    01411             break;
    01412
    01413          case EINVAL:
    01414             ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
    01415                argv[2], argv[4]);
    01416             break;
    01417
    01418          default:
    01419             ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n", argv[2], argv[4]);
    01420             break;
    01421       }
    01422       return RESULT_FAILURE;
    01423    }
    01424
    01425    ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
    01426       argv[2], argv[4]);
    01427    return RESULT_SUCCESS;
    01428 }
    01429
    01430 static int pbx_load_module(void);
    01431
    01432 static int handle_reload_extensions(int fd, int argc, char *argv[])
    01433 {
    01434    if (argc!=2) return RESULT_SHOWUSAGE;
    01435    if (clearglobalvars_config)
    01436       pbx_builtin_clear_globals();
    01437    pbx_load_module();
    01438    return RESULT_SUCCESS;
    01439 }
    01440
    01441 static char *complete_context_remove_ignorepat(char *line, char *word,
    01442    int pos, int state)
    01443 {
    01444    struct ast_context *c;
    01445    int which = 0;
    01446
    01447    if (pos == 2) {
    01448       if (ast_lock_contexts()) {
    01449          ast_log(LOG_WARNING, "Failed to lock contexts list\n");
    01450          return NULL;
    01451       }
    01452
    01453       c = ast_walk_contexts(NULL);
    01454       while (c) {
    01455          if (!ast_lock_context(c)) {
    01456             struct ast_ignorepat *ip;
    01457
    01458             ip = ast_walk_context_ignorepats(c, NULL);
    01459             while (ip) {
    01460                if (!strncmp(ast_get_ignorepat_name(ip), word, strlen(word))) {
    01461                   if (which + 1 > state) {
    01462                      struct ast_context *cw;
    01463                      int already_served = 0;
    01464                      cw = ast_walk_contexts(NULL);
    01465                      while (cw && cw != c && !already_served) {
    01466                         if (!ast_lock_context(cw)) {
    01467                            struct ast_ignorepat *ipw;
    01468                            ipw = ast_walk_context_ignorepats(cw, NULL);
    01469                            while (ipw) {
    01470                               if (!strcmp(ast_get_ignorepat_name(ipw),
    01471                                  ast_get_ignorepat_name(ip))) already_served = 1;
    01472                               ipw = ast_walk_context_ignorepats(cw, ipw);
    01473                            }
    01474                            ast_unlock_context(cw);
    01475                         }
    01476                         cw = ast_walk_contexts(cw);
    01477                      }
    01478                      if (!already_served) {
    01479                         char *ret = strdup(ast_get_ignorepat_name(ip));
    01480                         ast_unlock_context(c);
    01481                         ast_unlock_contexts();
    01482                         return ret;
    01483                      }
    01484                   } else
    01485                      which++;
    01486                }
    01487                ip = ast_walk_context_ignorepats(c, ip);
    01488             }
    01489
    01490             ast_unlock_context(c);
    01491          }
    01492          c = ast_walk_contexts(c);
    01493       }
    01494
    01495       ast_unlock_contexts();
    01496       return NULL;
    01497    }
    01498
    01499    if (pos == 3) return state == 0 ? strdup("from") : NULL;
    01500
    01501    if (pos == 4) {
    01502       char *dupline, *duplinet, *ignorepat;
    01503
    01504       dupline = strdup(line);
    01505       if (!dupline) {
    01506          ast_log(LOG_WARNING, "Out of free memory\n");
    01507          return NULL;
    01508       }
    01509
    01510       duplinet = dupline;
    01511       strsep(&duplinet, " ");
    01512       strsep(&duplinet, " ");
    01513       ignorepat = strsep(&duplinet, " ");
    01514
    01515       if (!ignorepat) {
    01516          free(dupline);
    01517          return NULL;
    01518       }
    01519
    01520       if (ast_lock_contexts()) {
    01521          ast_log(LOG_WARNING, "Failed to lock contexts list\n");
    01522          free(dupline);
    01523          return NULL;
    01524       }
    01525
    01526       c = ast_walk_contexts(NULL);
    01527       while (c) {
    01528          if (!ast_lock_context(c)) {
    01529             struct ast_ignorepat *ip;
    01530             ip = ast_walk_context_ignorepats(c, NULL);
    01531             while (ip) {
    01532                if (!strcmp(ast_get_ignorepat_name(ip), ignorepat)) {
    01533                   if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
    01534                      if (++which > state) {
    01535                         char *ret = strdup(ast_get_context_name(c));
    01536                         free(dupline);
    01537                         ast_unlock_context(c);
    01538                         ast_unlock_contexts();
    01539                         return ret;
    01540                      }
    01541                   }
    01542                }
    01543                ip = ast_walk_context_ignorepats(c, ip);
    01544             }
    01545
    01546             ast_unlock_context(c);
    01547          }
    01548          c = ast_walk_contexts(c);
    01549       }
    01550
    01551       free(dupline);
    01552       ast_unlock_contexts();
    01553       return NULL;
    01554    }
    01555
    01556    return NULL;
    01557 }
    01558
    01559 /*!
    01560  * CLI entries for commands provided by this module
    01561  */
    01562 static struct ast_cli_entry context_dont_include_cli =
    01563    { { "dont", "include", NULL }, handle_context_dont_include,
    01564       "Remove a specified include from context", context_dont_include_help,
    01565       complete_context_dont_include };
    01566
    01567 static struct ast_cli_entry context_remove_extension_cli =
    01568    { { "remove", "extension", NULL }, handle_context_remove_extension,
    01569       "Remove a specified extension", context_remove_extension_help,
    01570       complete_context_remove_extension };
    01571
    01572 static struct ast_cli_entry context_add_include_cli =
    01573    { { "include", "context", NULL }, handle_context_add_include,
    01574       "Include context in other context", context_add_include_help,
    01575       complete_context_add_include };
    01576
    01577 static struct ast_cli_entry save_dialplan_cli =
    01578    { { "save", "dialplan", NULL }, handle_save_dialplan,
    01579       "Save dialplan", save_dialplan_help };
    01580
    01581 static struct ast_cli_entry context_add_extension_cli =
    01582    { { "add", "extension", NULL }, handle_context_add_extension,
    01583       "Add new extension into context", context_add_extension_help,
    01584       complete_context_add_extension };
    01585
    01586 static struct ast_cli_entry context_add_ignorepat_cli =
    01587    { { "add", "ignorepat", NULL }, handle_context_add_ignorepat,
    01588       "Add new ignore pattern", context_add_ignorepat_help,
    01589       complete_context_add_ignorepat };
    01590
    01591 static struct ast_cli_entry context_remove_ignorepat_cli =
    01592    { { "remove", "ignorepat", NULL }, handle_context_remove_ignorepat,
    01593       "Remove ignore pattern from context", context_remove_ignorepat_help,
    01594       complete_context_remove_ignorepat };
    01595
    01596 static struct ast_cli_entry reload_extensions_cli =
    01597    { { "extensions", "reload", NULL}, handle_reload_extensions,
    01598       "Reload extensions and *only* extensions", reload_extensions_help };
    01599
    01600 /*!
    01601  * Standard module functions ...
    01602  */
    01603 int unload_module(void)
    01604 {
    01605    ast_cli_unregister(&context_add_extension_cli);
    01606    if (static_config && !write_protect_config)
    01607       ast_cli_unregister(&save_dialplan_cli);
    01608    ast_cli_unregister(&context_add_include_cli);
    01609    ast_cli_unregister(&context_dont_include_cli);
    01610    ast_cli_unregister(&context_remove_extension_cli);
    01611    ast_cli_unregister(&context_remove_ignorepat_cli);
    01612    ast_cli_unregister(&context_add_ignorepat_cli);
    01613    ast_cli_unregister(&reload_extensions_cli);
    01614    ast_context_destroy(NULL, registrar);
    01615    return 0;
    01616 }
    01617
    01618 static int pbx_load_module(void)
    01619 {
    01620    struct ast_config *cfg;
    01621    struct ast_variable *v;
    01622    char *cxt, *ext, *pri, *appl, *data, *tc, *cidmatch;
    01623    struct ast_context *con;
    01624    char *end;
    01625    char *label;
    01626    char realvalue[256];
    01627    int lastpri = -2;
    01628
    01629    cfg = ast_config_load(config);
    01630    if (cfg) {
    01631       /* Use existing config to populate the PBX table */
    01632       static_config = ast_true(ast_variable_retrieve(cfg, "general",
    01633                             "static"));
    01634       write_protect_config = ast_true(ast_variable_retrieve(cfg, "general",
    01635                               "writeprotect"));
    01636       autofallthrough_config = ast_true(ast_variable_retrieve(cfg, "general",
    01637                            "autofallthrough"));
    01638       clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general",
    01639                            "clearglobalvars"));
    01640       option_priority_jumping = !ast_false(ast_variable_retrieve(cfg, "general",
    01641                               "priorityjumping"));
    01642
    01643       v = ast_variable_browse(cfg, "globals");
    01644       while(v) {
    01645          memset(realvalue, 0, sizeof(realvalue));
    01646          pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
    01647          pbx_builtin_setvar_helper(NULL, v->name, realvalue);
    01648          v = v->next;
    01649       }
    01650       cxt = ast_category_browse(cfg, NULL);
    01651       while(cxt) {
    01652          /* All categories but "general" or "globals" are considered contexts */
    01653          if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) {
    01654             cxt = ast_category_browse(cfg, cxt);
    01655             continue;
    01656          }
    01657          if ((con=ast_context_create(&local_contexts,cxt, registrar))) {
    01658             v = ast_variable_browse(cfg, cxt);
    01659             while(v) {
    01660                if (!strcasecmp(v->name, "exten")) {
    01661                   char *stringp=NULL;
    01662                   int ipri = -2;
    01663                   char realext[256]="";
    01664                   char *plus, *firstp, *firstc;
    01665                   tc = strdup(v->value);
    01666                   if(tc!=NULL){
    01667                      stringp=tc;
    01668                      ext = strsep(&stringp, ",");
    01669                      if (!ext)
    01670                         ext="";
    01671                      pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
    01672                      cidmatch = strchr(realext, '/');
    01673                      if (cidmatch) {
    01674                         *cidmatch = '\0';
    01675                         cidmatch++;
    01676                         ast_shrink_phone_number(cidmatch);
    01677                      }
    01678                      pri = strsep(&stringp, ",");
    01679                      if (!pri)
    01680                         pri="";
    01681                      pri = ast_skip_blanks(pri);
    01682                      pri = ast_trim_blanks(pri);
    01683                      label = strchr(pri, '(');
    01684                      if (label) {
    01685                         *label = '\0';
    01686                         label++;
    01687                         end = strchr(label, ')');
    01688                         if (end)
    01689                            *end = '\0';
    01690                         else
    01691                            ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
    01692                      }
    01693                      plus = strchr(pri, '+');
    01694                      if (plus) {
    01695                         *plus = '\0';
    01696                         plus++;
    01697                      }
    01698                      if (!strcmp(pri,"hint"))
    01699                         ipri=PRIORITY_HINT;
    01700                      else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
    01701                         if (lastpri > -2)
    01702                            ipri = lastpri + 1;
    01703                         else
    01704                            ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
    01705                      } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
    01706                         if (lastpri > -2)
    01707                            ipri = lastpri;
    01708                         else
    01709                            ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
    01710                      } else  {
    01711                         if (sscanf(pri, "%30d", &ipri) != 1) {
    01712                            if ((ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
    01713                               ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
    01714                               ipri = 0;
    01715                            }
    01716                         }
    01717                      }
    01718                      appl = stringp;
    01719                      if (!appl)
    01720                         appl="";
    01721                      /* Find the first occurrence of either '(' or ',' */
    01722                      firstc = strchr(appl, ',');
    01723                      firstp = strchr(appl, '(');
    01724                      if (firstc && ((!firstp) || (firstc < firstp))) {
    01725                         /* comma found, no parenthesis */
    01726                         /* or both found, but comma found first */
    01727                         appl = strsep(&stringp, ",");
    01728                         data = stringp;
    01729                      } else if ((!firstc) && (!firstp)) {
    01730                         /* Neither found */
    01731                         data = "";
    01732                      } else {
    01733                         /* Final remaining case is parenthesis found first */
    01734                         appl = strsep(&stringp, "(");
    01735                         data = stringp;
    01736                         end = strrchr(data, ')');
    01737                         if ((end = strrchr(data, ')'))) {
    01738                            *end = '\0';
    01739                         } else {
    01740                            ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
    01741                         }
    01742                         ast_process_quotes_and_slashes(data, ',', '|');
    01743                      }
    01744
    01745                      if (!data)
    01746                         data="";
    01747                      while(*appl && (*appl < 33)) appl++;
    01748                      if (ipri) {
    01749                         if (plus)
    01750                            ipri += atoi(plus);
    01751                         lastpri = ipri;
    01752                         if(!option_dontwarn) {
    01753                            if (!strcmp(realext, "_."))
    01754                               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);
    01755                         }
    01756                         if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), FREE, registrar)) {
    01757                            ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
    01758                         }
    01759                      }
    01760                      free(tc);
    01761                   } else {
    01762                      ast_log(LOG_ERROR, "Memory allocation failure\n");
    01763                   }
    01764                } else if(!strcasecmp(v->name, "include")) {
    01765                   memset(realvalue, 0, sizeof(realvalue));
    01766                   pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
    01767                   if (ast_context_add_include2(con, realvalue, registrar))
    01768                      ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
    01769                } else if(!strcasecmp(v->name, "ignorepat")) {
    01770                   memset(realvalue, 0, sizeof(realvalue));
    01771                   pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
    01772                   if (ast_context_add_ignorepat2(con, realvalue, registrar))
    01773                      ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
    01774                } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
    01775                   char *stringp=NULL;
    01776                   memset(realvalue, 0, sizeof(realvalue));
    01777                   if (!strcasecmp(v->name, "switch"))
    01778                      pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
    01779                   else
    01780                      strncpy(realvalue, v->value, sizeof(realvalue) - 1);
    01781                   tc = realvalue;
    01782                   stringp=tc;
    01783                   appl = strsep(&stringp, "/");
    01784                   data = strsep(&stringp, "");
    01785                   if (!data)
    01786                      data = "";
    01787                   if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar))
    01788                      ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
    01789                }
    01790                v = v->next;
    01791             }
    01792          }
    01793          cxt = ast_category_browse(cfg, cxt);
    01794       }
    01795       ast_config_destroy(cfg);
    01796    }
    01797    ast_merge_contexts_and_delete(&local_contexts,registrar);
    01798
    01799    for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
    01800       ast_context_verify_includes(con);
    01801
    01802    pbx_set_autofallthrough(autofallthrough_config);
    01803
    01804    return 0;
    01805 }
    01806
    01807 int load_module(void)
    01808 {
    01809    if (pbx_load_module()) return -1;
    01810
    01811    ast_cli_register(&context_remove_extension_cli);
    01812    ast_cli_register(&context_dont_include_cli);
    01813    ast_cli_register(&context_add_include_cli);
    01814    if (static_config && !write_protect_config)
    01815       ast_cli_register(&save_dialplan_cli);
    01816    ast_cli_register(&context_add_extension_cli);
    01817    ast_cli_register(&context_add_ignorepat_cli);
    01818    ast_cli_register(&context_remove_ignorepat_cli);
    01819    ast_cli_register(&reload_extensions_cli);
    01820
    01821    return 0;
    01822 }
    01823
    01824 int reload(void)
    01825 {
    01826    if (clearglobalvars_config)
    01827       pbx_builtin_clear_globals();
    01828    pbx_load_module();
    01829    return 0;
    01830 }
    01831
    01832 int usecount(void)
    01833 {
    01834    return 0;
    01835 }
    01836
    01837 char *description(void)
    01838 {
    01839    return dtext;
    01840 }
    01841
    01842 char *key(void)
    01843 {
    01844    return ASTERISK_GPL_KEY;
    01845 }