Thu Oct 11 06:42:09 2012

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

Generated on Thu Oct 11 06:42:09 2012 for Asterisk - the Open Source PBX by  doxygen 1.5.6