Wed Oct 28 15:47:55 2009

Asterisk developer's documentation


pbx_config.c

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

Generated on Wed Oct 28 15:47:55 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6