Wed Aug 15 01:24:23 2007

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

Generated on Wed Aug 15 01:24:23 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3