Mon Mar 20 08:25:43 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

pbx_config.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, 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: 7831 $")
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\n\n",
00989       static_config ? "yes" : "no",
00990       write_protect_config ? "yes" : "no");
00991 
00992    if ((v = ast_variable_browse(cfg, "globals"))) {
00993       fprintf(output, "[globals]\n");
00994       while(v) {
00995          fprintf(output, "%s => %s\n", v->name, v->value);
00996          v = v->next;
00997       }
00998       fprintf(output, "\n");
00999    }
01000 
01001    ast_config_destroy(cfg);
01002    
01003    /* walk all contexts */
01004    c = ast_walk_contexts(NULL);
01005    while (c) {
01006       context_header_written = 0;
01007    
01008       /* try to lock context and fireout all info */  
01009       if (!ast_lock_context(c)) {
01010          struct ast_exten *e, *last_written_e = NULL;
01011          struct ast_include *i;
01012          struct ast_ignorepat *ip;
01013          struct ast_sw *sw;
01014 
01015          /* registered by this module? */
01016          if (!strcmp(ast_get_context_registrar(c), registrar)) {
01017             fprintf(output, "[%s]\n", ast_get_context_name(c));
01018             context_header_written = 1;
01019          }
01020 
01021          /* walk extensions ... */
01022          e = ast_walk_context_extensions(c, NULL);
01023          while (e) {
01024             struct ast_exten *p;
01025 
01026             /* fireout priorities */
01027             p = ast_walk_extension_priorities(e, NULL);
01028             while (p) {
01029                if (!strcmp(ast_get_extension_registrar(p),
01030                   registrar)) {
01031          
01032                   /* make empty line between different extensions */ 
01033                   if (last_written_e != NULL &&
01034                      strcmp(ast_get_extension_name(last_written_e),
01035                         ast_get_extension_name(p)))
01036                      fprintf(output, "\n");
01037                   last_written_e = p;
01038             
01039                   if (!context_header_written) {
01040                      fprintf(output, "[%s]\n", ast_get_context_name(c));
01041                      context_header_written = 1;
01042                   }
01043 
01044                   if (ast_get_extension_priority(p)!=PRIORITY_HINT) {
01045                      char *tempdata = NULL, *startdata;
01046                      tempdata = strdup((char *)ast_get_extension_app_data(p));
01047                      if (tempdata) {
01048                         startdata = tempdata;
01049                         while (*tempdata) {
01050                            if (*tempdata == '|')
01051                               *tempdata = ',';
01052                            tempdata++;
01053                         }
01054                         tempdata = startdata;
01055                      }
01056                      if (ast_get_extension_matchcid(p))
01057                         fprintf(output, "exten => %s/%s,%d,%s(%s)\n",
01058                             ast_get_extension_name(p),
01059                             ast_get_extension_cidmatch(p),
01060                             ast_get_extension_priority(p),
01061                             ast_get_extension_app(p),
01062                             tempdata);
01063                      else
01064                         fprintf(output, "exten => %s,%d,%s(%s)\n",
01065                             ast_get_extension_name(p),
01066                             ast_get_extension_priority(p),
01067                             ast_get_extension_app(p),
01068                             tempdata);
01069                      if (tempdata)
01070                         free(tempdata);
01071                   } else
01072                      fprintf(output, "exten => %s,hint,%s\n",
01073                          ast_get_extension_name(p),
01074                          ast_get_extension_app(p));
01075                   
01076                }
01077                p = ast_walk_extension_priorities(e, p);
01078             }
01079 
01080             e = ast_walk_context_extensions(c, e);
01081          }
01082 
01083          /* written any extensions? ok, write space between exten & inc */
01084          if (last_written_e) fprintf(output, "\n");
01085 
01086          /* walk through includes */
01087          i = ast_walk_context_includes(c, NULL);
01088          while (i) {
01089             if (!strcmp(ast_get_include_registrar(i), registrar)) {
01090                if (!context_header_written) {
01091                   fprintf(output, "[%s]\n", ast_get_context_name(c));
01092                   context_header_written = 1;
01093                }
01094                fprintf(output, "include => %s\n",
01095                   ast_get_include_name(i));
01096             }
01097             i = ast_walk_context_includes(c, i);
01098          }
01099 
01100          if (ast_walk_context_includes(c, NULL))
01101             fprintf(output, "\n");
01102 
01103          /* walk through switches */
01104          sw = ast_walk_context_switches(c, NULL);
01105          while (sw) {
01106             if (!strcmp(ast_get_switch_registrar(sw), registrar)) {
01107                if (!context_header_written) {
01108                   fprintf(output, "[%s]\n", ast_get_context_name(c));
01109                   context_header_written = 1;
01110                }
01111                fprintf(output, "switch => %s/%s\n",
01112                   ast_get_switch_name(sw),
01113                   ast_get_switch_data(sw));
01114             }
01115             sw = ast_walk_context_switches(c, sw);
01116          }
01117 
01118          if (ast_walk_context_switches(c, NULL))
01119             fprintf(output, "\n");
01120 
01121          /* fireout ignorepats ... */
01122          ip = ast_walk_context_ignorepats(c, NULL);
01123          while (ip) {
01124             if (!strcmp(ast_get_ignorepat_registrar(ip), registrar)) {
01125                if (!context_header_written) {
01126                   fprintf(output, "[%s]\n", ast_get_context_name(c));
01127                   context_header_written = 1;
01128                }
01129 
01130                fprintf(output, "ignorepat => %s\n",
01131                   ast_get_ignorepat_name(ip));
01132             }
01133             ip = ast_walk_context_ignorepats(c, ip);
01134          }
01135 
01136          ast_unlock_context(c);
01137       } else
01138          incomplete = 1;
01139 
01140       c = ast_walk_contexts(c);
01141    }  
01142 
01143    ast_unlock_contexts();
01144    ast_mutex_unlock(&save_dialplan_lock);
01145    fclose(output);
01146 
01147    if (incomplete) {
01148       ast_cli(fd, "Saved dialplan is incomplete\n");
01149       return RESULT_FAILURE;
01150    }
01151 
01152    ast_cli(fd, "Dialplan successfully saved into '%s'\n",
01153       filename);
01154    return RESULT_SUCCESS;
01155 }
01156 
01157 /*!
01158  * \brief ADD EXTENSION command stuff
01159  */
01160 static int handle_context_add_extension(int fd, int argc, char *argv[])
01161 {
01162    char *whole_exten;
01163    char *exten, *prior;
01164    int iprior = -2;
01165    char *cidmatch, *app, *app_data;
01166    char *start, *end;
01167 
01168    /* check for arguments at first */
01169    if (argc != 5 && argc != 6) return RESULT_SHOWUSAGE;
01170    if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
01171    if (argc == 6) if (strcmp(argv[5], "replace")) return RESULT_SHOWUSAGE;
01172 
01173    whole_exten = argv[2];
01174    exten       = strsep(&whole_exten,",");
01175    if (strchr(exten, '/')) {
01176       cidmatch = exten;
01177       strsep(&cidmatch,"/");
01178    } else {
01179       cidmatch = NULL;
01180    }
01181    prior       = strsep(&whole_exten,",");
01182    if (prior) {
01183       if (!strcmp(prior, "hint")) {
01184          iprior = PRIORITY_HINT;
01185       } else {
01186          if (sscanf(prior, "%d", &iprior) != 1) {
01187             ast_cli(fd, "'%s' is not a valid priority\n", prior);
01188             prior = NULL;
01189          }
01190       }
01191    }
01192    app = whole_exten;
01193    if (app && (start = strchr(app, '(')) && (end = strrchr(app, ')'))) {
01194       *start = *end = '\0';
01195       app_data = start + 1;
01196       ast_process_quotes_and_slashes(app_data, ',', '|');
01197    } else {
01198       if (app) {
01199          app_data = strchr(app, ',');
01200          if (app_data) {
01201             *app_data = '\0';
01202             app_data++;
01203          }
01204       } else   
01205          app_data = NULL;
01206    }
01207 
01208    if (!exten || !prior || !app || (!app_data && iprior != PRIORITY_HINT)) return RESULT_SHOWUSAGE;
01209 
01210    if (!app_data)
01211       app_data="";
01212    if (ast_add_extension(argv[4], argc == 6 ? 1 : 0, exten, iprior, NULL, cidmatch, app,
01213       (void *)strdup(app_data), free, registrar)) {
01214       switch (errno) {
01215          case ENOMEM:
01216             ast_cli(fd, "Out of free memory\n"); break;
01217 
01218          case EBUSY:
01219             ast_cli(fd, "Failed to lock context(s) list, please try again later\n"); break;
01220 
01221          case ENOENT:
01222             ast_cli(fd, "No existence of '%s' context\n", argv[4]); break;
01223 
01224          case EEXIST:
01225             ast_cli(fd, "Extension %s@%s with priority %s already exists\n",
01226                exten, argv[4], prior); break;
01227 
01228          default:
01229             ast_cli(fd, "Failed to add '%s,%s,%s,%s' extension into '%s' context\n",
01230                exten, prior, app, app_data, argv[4]); break;
01231       }
01232       return RESULT_FAILURE;
01233    }
01234 
01235    if (argc == 6) 
01236       ast_cli(fd, "Extension %s@%s (%s) replace by '%s,%s,%s,%s'\n",
01237          exten, argv[4], prior, exten, prior, app, app_data);
01238    else
01239       ast_cli(fd, "Extension '%s,%s,%s,%s' added into '%s' context\n",
01240          exten, prior, app, app_data, argv[4]);
01241 
01242    return RESULT_SUCCESS;
01243 }
01244 
01245 /*! add extension 6123,1,Dial,IAX/212.71.138.13/6123 into local */
01246 static char *complete_context_add_extension(char *line, char *word,
01247    int pos, int state)
01248 {
01249    int which = 0;
01250 
01251    /* complete 'into' word ... */
01252    if (pos == 3) {
01253       if (state == 0) return strdup("into");
01254       return NULL;
01255    }
01256 
01257    /* complete context */
01258    if (pos == 4) {
01259       struct ast_context *c;
01260 
01261       /* try to lock contexts list ... */
01262       if (ast_lock_contexts()) {
01263          ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01264          return NULL;
01265       }
01266 
01267       /* walk through all contexts */
01268       c = ast_walk_contexts(NULL);
01269       while (c) {
01270          /* matching context? */
01271          if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
01272             if (++which > state) {
01273                char *res = strdup(ast_get_context_name(c));
01274                ast_unlock_contexts();
01275                return res;
01276             }
01277          }
01278          c = ast_walk_contexts(c);
01279       }
01280 
01281       ast_unlock_contexts();
01282       return NULL;
01283    }
01284 
01285    if (pos == 5) return state == 0 ? strdup("replace") : NULL;
01286 
01287    return NULL;
01288 }
01289 
01290 /*!
01291  * IGNOREPAT CLI stuff
01292  */
01293 static int handle_context_add_ignorepat(int fd, int argc, char *argv[])
01294 {
01295    if (argc != 5) return RESULT_SHOWUSAGE;
01296    if (strcmp(argv[3], "into")) return RESULT_SHOWUSAGE;
01297 
01298    if (ast_context_add_ignorepat(argv[4], argv[2], registrar)) {
01299       switch (errno) {
01300          case ENOMEM:
01301             ast_cli(fd, "Out of free memory\n"); break;
01302 
01303          case ENOENT:
01304             ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
01305             break;
01306 
01307          case EEXIST:
01308             ast_cli(fd, "Ignore pattern '%s' already included in '%s' context\n",
01309                argv[2], argv[4]);
01310             break;
01311 
01312          case EBUSY:
01313             ast_cli(fd, "Failed to lock context(s) list, please, try again later\n");
01314             break;
01315 
01316          default:
01317             ast_cli(fd, "Failed to add ingore pattern '%s' into '%s' context\n",
01318                argv[2], argv[4]);
01319             break;
01320       }
01321       return RESULT_FAILURE;
01322    }
01323 
01324    ast_cli(fd, "Ignore pattern '%s' added into '%s' context\n",
01325       argv[2], argv[4]);
01326    return RESULT_SUCCESS;
01327 }
01328 
01329 static char *complete_context_add_ignorepat(char *line, char *word,
01330    int pos, int state)
01331 {
01332    if (pos == 3) return state == 0 ? strdup("into") : NULL;
01333 
01334    if (pos == 4) {
01335       struct ast_context *c;
01336       int which = 0;
01337       char *dupline, *duplinet, *ignorepat = NULL;
01338 
01339       dupline = strdup(line);
01340       duplinet = dupline;
01341 
01342       if (duplinet) {
01343          strsep(&duplinet, " "); /* skip 'add' */
01344          strsep(&duplinet, " "); /* skip 'ignorepat' */
01345          ignorepat = strsep(&duplinet, " ");
01346       }
01347 
01348       if (ast_lock_contexts()) {
01349          ast_log(LOG_ERROR, "Failed to lock contexts list\n");
01350          return NULL;
01351       }
01352 
01353       c = ast_walk_contexts(NULL);
01354       while (c) {
01355          if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
01356             int serve_context = 1;
01357             if (ignorepat) {
01358                if (!ast_lock_context(c)) {
01359                   struct ast_ignorepat *ip;
01360                   ip = ast_walk_context_ignorepats(c, NULL);
01361                   while (ip && serve_context) {
01362                      if (!strcmp(ast_get_ignorepat_name(ip), ignorepat))
01363                         serve_context = 0;
01364                      ip = ast_walk_context_ignorepats(c, ip);
01365                   }
01366                   ast_unlock_context(c);
01367                }
01368             }
01369             if (serve_context) {
01370                if (++which > state) {
01371                   char *context = strdup(ast_get_context_name(c));
01372                   if (dupline) free(dupline);
01373                   ast_unlock_contexts();
01374                   return context;
01375                }
01376             }
01377          }
01378          c = ast_walk_contexts(c);
01379       }
01380 
01381       if (dupline) free(dupline);
01382       ast_unlock_contexts();
01383       return NULL;
01384    }
01385 
01386    return NULL;
01387 }
01388 
01389 static int handle_context_remove_ignorepat(int fd, int argc, char *argv[])
01390 {
01391    if (argc != 5) return RESULT_SHOWUSAGE;
01392    if (strcmp(argv[3], "from")) return RESULT_SHOWUSAGE;
01393 
01394    if (ast_context_remove_ignorepat(argv[4], argv[2], registrar)) {
01395       switch (errno) {
01396          case EBUSY:
01397             ast_cli(fd, "Failed to lock context(s) list, please try again later\n");
01398             break;
01399 
01400          case ENOENT:
01401             ast_cli(fd, "There is no existence of '%s' context\n", argv[4]);
01402             break;
01403 
01404          case EINVAL:
01405             ast_cli(fd, "There is no existence of '%s' ignore pattern in '%s' context\n",
01406                argv[2], argv[4]);
01407             break;
01408 
01409          default:
01410             ast_cli(fd, "Failed to remove ignore pattern '%s' from '%s' context\n", argv[2], argv[4]);
01411             break;
01412       }
01413       return RESULT_FAILURE;
01414    }
01415 
01416    ast_cli(fd, "Ignore pattern '%s' removed from '%s' context\n",
01417       argv[2], argv[4]);
01418    return RESULT_SUCCESS;
01419 }
01420 
01421 static int pbx_load_module(void);
01422 
01423 static int handle_reload_extensions(int fd, int argc, char *argv[])
01424 {
01425    if (argc!=2) return RESULT_SHOWUSAGE;
01426    pbx_load_module();
01427    return RESULT_SUCCESS;
01428 }
01429 
01430 static char *complete_context_remove_ignorepat(char *line, char *word,
01431    int pos, int state)
01432 {
01433    struct ast_context *c;
01434    int which = 0;
01435 
01436    if (pos == 2) {
01437       if (ast_lock_contexts()) {
01438          ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01439          return NULL;
01440       }
01441 
01442       c = ast_walk_contexts(NULL);
01443       while (c) {
01444          if (!ast_lock_context(c)) {
01445             struct ast_ignorepat *ip;
01446          
01447             ip = ast_walk_context_ignorepats(c, NULL);
01448             while (ip) {
01449                if (!strncmp(ast_get_ignorepat_name(ip), word, strlen(word))) {
01450                   if (which + 1 > state) {
01451                      struct ast_context *cw;
01452                      int already_served = 0;
01453                      cw = ast_walk_contexts(NULL);
01454                      while (cw && cw != c && !already_served) {
01455                         if (!ast_lock_context(cw)) {
01456                            struct ast_ignorepat *ipw;
01457                            ipw = ast_walk_context_ignorepats(cw, NULL);
01458                            while (ipw) {
01459                               if (!strcmp(ast_get_ignorepat_name(ipw),
01460                                  ast_get_ignorepat_name(ip))) already_served = 1;
01461                               ipw = ast_walk_context_ignorepats(cw, ipw);
01462                            }
01463                            ast_unlock_context(cw);
01464                         }
01465                         cw = ast_walk_contexts(cw);
01466                      }
01467                      if (!already_served) {
01468                         char *ret = strdup(ast_get_ignorepat_name(ip));
01469                         ast_unlock_context(c);
01470                         ast_unlock_contexts();
01471                         return ret;
01472                      }
01473                   } else
01474                      which++;
01475                }
01476                ip = ast_walk_context_ignorepats(c, ip);
01477             }
01478 
01479             ast_unlock_context(c);
01480          }
01481          c = ast_walk_contexts(c);
01482       }
01483 
01484       ast_unlock_contexts();
01485       return NULL;
01486    }
01487  
01488    if (pos == 3) return state == 0 ? strdup("from") : NULL;
01489 
01490    if (pos == 4) {
01491       char *dupline, *duplinet, *ignorepat;
01492 
01493       dupline = strdup(line);
01494       if (!dupline) {
01495          ast_log(LOG_WARNING, "Out of free memory\n");
01496          return NULL;
01497       }
01498 
01499       duplinet = dupline;
01500       strsep(&duplinet, " ");
01501       strsep(&duplinet, " ");
01502       ignorepat = strsep(&duplinet, " ");
01503 
01504       if (!ignorepat) {
01505          free(dupline);
01506          return NULL;
01507       }
01508 
01509       if (ast_lock_contexts()) {
01510          ast_log(LOG_WARNING, "Failed to lock contexts list\n");
01511          free(dupline);
01512          return NULL;
01513       }
01514 
01515       c = ast_walk_contexts(NULL);
01516       while (c) {
01517          if (!ast_lock_context(c)) {
01518             struct ast_ignorepat *ip;
01519             ip = ast_walk_context_ignorepats(c, NULL);
01520             while (ip) {
01521                if (!strcmp(ast_get_ignorepat_name(ip), ignorepat)) {
01522                   if (!strncmp(ast_get_context_name(c), word, strlen(word))) {
01523                      if (++which > state) {
01524                         char *ret = strdup(ast_get_context_name(c));
01525                         free(dupline);
01526                         ast_unlock_context(c);
01527                         ast_unlock_contexts();
01528                         return ret;
01529                      }
01530                   }
01531                }
01532                ip = ast_walk_context_ignorepats(c, ip);
01533             }
01534 
01535             ast_unlock_context(c);
01536          }
01537          c = ast_walk_contexts(c);
01538       }
01539 
01540       free(dupline);
01541       ast_unlock_contexts();
01542       return NULL;
01543    }
01544 
01545    return NULL;
01546 }
01547 
01548 /*!
01549  * CLI entries for commands provided by this module
01550  */
01551 static struct ast_cli_entry context_dont_include_cli =
01552    { { "dont", "include", NULL }, handle_context_dont_include,
01553       "Remove a specified include from context", context_dont_include_help,
01554       complete_context_dont_include };
01555 
01556 static struct ast_cli_entry context_remove_extension_cli =
01557    { { "remove", "extension", NULL }, handle_context_remove_extension,
01558       "Remove a specified extension", context_remove_extension_help,
01559       complete_context_remove_extension };
01560 
01561 static struct ast_cli_entry context_add_include_cli =
01562    { { "include", "context", NULL }, handle_context_add_include,
01563       "Include context in other context", context_add_include_help,
01564       complete_context_add_include };
01565 
01566 static struct ast_cli_entry save_dialplan_cli =
01567    { { "save", "dialplan", NULL }, handle_save_dialplan,
01568       "Save dialplan", save_dialplan_help };
01569 
01570 static struct ast_cli_entry context_add_extension_cli =
01571    { { "add", "extension", NULL }, handle_context_add_extension,
01572       "Add new extension into context", context_add_extension_help,
01573       complete_context_add_extension };
01574 
01575 static struct ast_cli_entry context_add_ignorepat_cli =
01576    { { "add", "ignorepat", NULL }, handle_context_add_ignorepat,
01577       "Add new ignore pattern", context_add_ignorepat_help,
01578       complete_context_add_ignorepat };
01579 
01580 static struct ast_cli_entry context_remove_ignorepat_cli =
01581    { { "remove", "ignorepat", NULL }, handle_context_remove_ignorepat,
01582       "Remove ignore pattern from context", context_remove_ignorepat_help,
01583       complete_context_remove_ignorepat };
01584 
01585 static struct ast_cli_entry reload_extensions_cli = 
01586    { { "extensions", "reload", NULL}, handle_reload_extensions,
01587       "Reload extensions and *only* extensions", reload_extensions_help };
01588 
01589 /*!
01590  * Standard module functions ...
01591  */
01592 int unload_module(void)
01593 {
01594    ast_cli_unregister(&context_add_extension_cli);
01595    if (static_config && !write_protect_config)
01596       ast_cli_unregister(&save_dialplan_cli);
01597    ast_cli_unregister(&context_add_include_cli);
01598    ast_cli_unregister(&context_dont_include_cli);
01599    ast_cli_unregister(&context_remove_extension_cli);
01600    ast_cli_unregister(&context_remove_ignorepat_cli);
01601    ast_cli_unregister(&context_add_ignorepat_cli);
01602    ast_cli_unregister(&reload_extensions_cli);
01603    ast_context_destroy(NULL, registrar);
01604    return 0;
01605 }
01606 
01607 static int pbx_load_module(void)
01608 {
01609    struct ast_config *cfg;
01610    struct ast_variable *v;
01611    char *cxt, *ext, *pri, *appl, *data, *tc, *cidmatch;
01612    struct ast_context *con;
01613    char *end;
01614    char *label;
01615    char realvalue[256];
01616    int lastpri = -2;
01617 
01618    cfg = ast_config_load(config);
01619    if (cfg) {
01620       /* Use existing config to populate the PBX table */
01621       static_config = ast_true(ast_variable_retrieve(cfg, "general",
01622                             "static"));
01623       write_protect_config = ast_true(ast_variable_retrieve(cfg, "general",
01624                               "writeprotect"));
01625       autofallthrough_config = ast_true(ast_variable_retrieve(cfg, "general",
01626                            "autofallthrough"));
01627       clearglobalvars_config = ast_true(ast_variable_retrieve(cfg, "general", 
01628                            "clearglobalvars"));
01629       option_priority_jumping = !ast_false(ast_variable_retrieve(cfg, "general",
01630                               "priorityjumping"));
01631 
01632       v = ast_variable_browse(cfg, "globals");
01633       while(v) {
01634          memset(realvalue, 0, sizeof(realvalue));
01635          pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
01636          pbx_builtin_setvar_helper(NULL, v->name, realvalue);
01637          v = v->next;
01638       }
01639       cxt = ast_category_browse(cfg, NULL);
01640       while(cxt) {
01641          /* All categories but "general" or "globals" are considered contexts */
01642          if (!strcasecmp(cxt, "general") || !strcasecmp(cxt, "globals")) {
01643             cxt = ast_category_browse(cfg, cxt);
01644             continue;
01645          }
01646          if ((con=ast_context_create(&local_contexts,cxt, registrar))) {
01647             v = ast_variable_browse(cfg, cxt);
01648             while(v) {
01649                if (!strcasecmp(v->name, "exten")) {
01650                   char *stringp=NULL;
01651                   int ipri = -2;
01652                   char realext[256]="";
01653                   char *plus, *firstp, *firstc;
01654                   tc = strdup(v->value);
01655                   if(tc!=NULL){
01656                      stringp=tc;
01657                      ext = strsep(&stringp, ",");
01658                      if (!ext)
01659                         ext="";
01660                      pbx_substitute_variables_helper(NULL, ext, realext, sizeof(realext) - 1);
01661                      cidmatch = strchr(realext, '/');
01662                      if (cidmatch) {
01663                         *cidmatch = '\0';
01664                         cidmatch++;
01665                         ast_shrink_phone_number(cidmatch);
01666                      }
01667                      pri = strsep(&stringp, ",");
01668                      if (!pri)
01669                         pri="";
01670                      label = strchr(pri, '(');
01671                      if (label) {
01672                         *label = '\0';
01673                         label++;
01674                         end = strchr(label, ')');
01675                         if (end)
01676                            *end = '\0';
01677                         else
01678                            ast_log(LOG_WARNING, "Label missing trailing ')' at line %d\n", v->lineno);
01679                      }
01680                      plus = strchr(pri, '+');
01681                      if (plus) {
01682                         *plus = '\0';
01683                         plus++;
01684                      }
01685                      if (!strcmp(pri,"hint"))
01686                         ipri=PRIORITY_HINT;
01687                      else if (!strcmp(pri, "next") || !strcmp(pri, "n")) {
01688                         if (lastpri > -2)
01689                            ipri = lastpri + 1;
01690                         else
01691                            ast_log(LOG_WARNING, "Can't use 'next' priority on the first entry!\n");
01692                      } else if (!strcmp(pri, "same") || !strcmp(pri, "s")) {
01693                         if (lastpri > -2)
01694                            ipri = lastpri;
01695                         else
01696                            ast_log(LOG_WARNING, "Can't use 'same' priority on the first entry!\n");
01697                      } else  {
01698                         if (sscanf(pri, "%d", &ipri) != 1) {
01699                            if ((ipri = ast_findlabel_extension2(NULL, con, realext, pri, cidmatch)) < 1) {
01700                               ast_log(LOG_WARNING, "Invalid priority/label '%s' at line %d\n", pri, v->lineno);
01701                               ipri = 0;
01702                            }
01703                         }
01704                      }
01705                      appl = stringp;
01706                      if (!appl)
01707                         appl="";
01708                      /* Find the first occurrence of either '(' or ',' */
01709                      firstc = strchr(appl, ',');
01710                      firstp = strchr(appl, '(');
01711                      if (firstc && ((!firstp) || (firstc < firstp))) {
01712                         /* comma found, no parenthesis */
01713                         /* or both found, but comma found first */
01714                         appl = strsep(&stringp, ",");
01715                         data = stringp;
01716                      } else if ((!firstc) && (!firstp)) {
01717                         /* Neither found */
01718                         data = "";
01719                      } else {
01720                         /* Final remaining case is parenthesis found first */
01721                         appl = strsep(&stringp, "(");
01722                         data = stringp;
01723                         end = strrchr(data, ')');
01724                         if ((end = strrchr(data, ')'))) {
01725                            *end = '\0';
01726                         } else {
01727                            ast_log(LOG_WARNING, "No closing parenthesis found? '%s(%s'\n", appl, data);
01728                         }
01729                         ast_process_quotes_and_slashes(data, ',', '|');
01730                      }
01731 
01732                      if (!data)
01733                         data="";
01734                      while(*appl && (*appl < 33)) appl++;
01735                      if (ipri) {
01736                         if (plus)
01737                            ipri += atoi(plus);
01738                         lastpri = ipri;
01739                         if(!option_dontwarn) {
01740                            if (!strcmp(realext, "_."))
01741                               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);
01742                         }
01743                         if (ast_add_extension2(con, 0, realext, ipri, label, cidmatch, appl, strdup(data), FREE, registrar)) {
01744                            ast_log(LOG_WARNING, "Unable to register extension at line %d\n", v->lineno);
01745                         }
01746                      }
01747                      free(tc);
01748                   } else fprintf(stderr,"Error strdup returned NULL in %s\n",__PRETTY_FUNCTION__);
01749                } else if(!strcasecmp(v->name, "include")) {
01750                   memset(realvalue, 0, sizeof(realvalue));
01751                   pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
01752                   if (ast_context_add_include2(con, realvalue, registrar))
01753                      ast_log(LOG_WARNING, "Unable to include context '%s' in context '%s'\n", v->value, cxt);
01754                } else if(!strcasecmp(v->name, "ignorepat")) {
01755                   memset(realvalue, 0, sizeof(realvalue));
01756                   pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
01757                   if (ast_context_add_ignorepat2(con, realvalue, registrar))
01758                      ast_log(LOG_WARNING, "Unable to include ignorepat '%s' in context '%s'\n", v->value, cxt);
01759                } else if (!strcasecmp(v->name, "switch") || !strcasecmp(v->name, "lswitch") || !strcasecmp(v->name, "eswitch")) {
01760                   char *stringp=NULL;
01761                   memset(realvalue, 0, sizeof(realvalue));
01762                   if (!strcasecmp(v->name, "switch"))
01763                      pbx_substitute_variables_helper(NULL, v->value, realvalue, sizeof(realvalue) - 1);
01764                   else
01765                      strncpy(realvalue, v->value, sizeof(realvalue) - 1);
01766                   tc = realvalue;
01767                   stringp=tc;
01768                   appl = strsep(&stringp, "/");
01769                   data = strsep(&stringp, "");
01770                   if (!data)
01771                      data = "";
01772                   if (ast_context_add_switch2(con, appl, data, !strcasecmp(v->name, "eswitch"), registrar))
01773                      ast_log(LOG_WARNING, "Unable to include switch '%s' in context '%s'\n", v->value, cxt);
01774                }
01775                v = v->next;
01776             }
01777          }
01778          cxt = ast_category_browse(cfg, cxt);
01779       }
01780       ast_config_destroy(cfg);
01781    }
01782    ast_merge_contexts_and_delete(&local_contexts,registrar);
01783 
01784    for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
01785       ast_context_verify_includes(con);
01786 
01787    pbx_set_autofallthrough(autofallthrough_config);
01788 
01789    return 0;
01790 }
01791 
01792 int load_module(void)
01793 {
01794    if (pbx_load_module()) return -1;
01795  
01796    ast_cli_register(&context_remove_extension_cli);
01797    ast_cli_register(&context_dont_include_cli);
01798    ast_cli_register(&context_add_include_cli);
01799    if (static_config && !write_protect_config)
01800       ast_cli_register(&save_dialplan_cli);
01801    ast_cli_register(&context_add_extension_cli);
01802    ast_cli_register(&context_add_ignorepat_cli);
01803    ast_cli_register(&context_remove_ignorepat_cli);
01804    ast_cli_register(&reload_extensions_cli);
01805 
01806    return 0;
01807 }
01808 
01809 int reload(void)
01810 {
01811    ast_context_destroy(NULL, registrar);
01812    if (clearglobalvars_config)
01813       pbx_builtin_clear_globals();
01814    pbx_load_module();
01815    return 0;
01816 }
01817 
01818 int usecount(void)
01819 {
01820    return 0;
01821 }
01822 
01823 char *description(void)
01824 {
01825    return dtext;
01826 }
01827 
01828 char *key(void)
01829 {
01830    return ASTERISK_GPL_KEY;
01831 }

Generated on Mon Mar 20 08:25:43 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1