Wed Oct 28 11:51:05 2009

Asterisk developer's documentation


pbx.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2008, 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 Core PBX routines.
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  */
00025 #include "asterisk.h"
00026 
00027 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 225362 $")
00028 
00029 #include "asterisk/_private.h"
00030 #include "asterisk/paths.h"   /* use ast_config_AST_SYSTEM_NAME */
00031 #include <ctype.h>
00032 #include <time.h>
00033 #include <sys/time.h>
00034 #if defined(HAVE_SYSINFO)
00035 #include <sys/sysinfo.h>
00036 #endif
00037 #if defined(SOLARIS)
00038 #include <sys/loadavg.h>
00039 #endif
00040 
00041 #include "asterisk/lock.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/callerid.h"
00047 #include "asterisk/cdr.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/term.h"
00050 #include "asterisk/time.h"
00051 #include "asterisk/manager.h"
00052 #include "asterisk/ast_expr.h"
00053 #include "asterisk/linkedlists.h"
00054 #define  SAY_STUBS   /* generate declarations and stubs for say methods */
00055 #include "asterisk/say.h"
00056 #include "asterisk/utils.h"
00057 #include "asterisk/causes.h"
00058 #include "asterisk/musiconhold.h"
00059 #include "asterisk/app.h"
00060 #include "asterisk/devicestate.h"
00061 #include "asterisk/stringfields.h"
00062 #include "asterisk/event.h"
00063 #include "asterisk/hashtab.h"
00064 #include "asterisk/module.h"
00065 #include "asterisk/indications.h"
00066 #include "asterisk/taskprocessor.h"
00067 
00068 /*!
00069  * \note I M P O R T A N T :
00070  *
00071  *    The speed of extension handling will likely be among the most important
00072  * aspects of this PBX.  The switching scheme as it exists right now isn't
00073  * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
00074  * of priorities, but a constant search time here would be great ;-)
00075  *
00076  * A new algorithm to do searching based on a 'compiled' pattern tree is introduced
00077  * here, and shows a fairly flat (constant) search time, even for over
00078  * 10000 patterns. 
00079  *
00080  * Also, using a hash table for context/priority name lookup can help prevent
00081  * the find_extension routines from absorbing exponential cpu cycles as the number 
00082  * of contexts/priorities grow. I've previously tested find_extension with red-black trees, 
00083  * which have O(log2(n)) speed. Right now, I'm using hash tables, which do 
00084  * searches (ideally) in O(1) time. While these techniques do not yield much 
00085  * speed in small dialplans, they are worth the trouble in large dialplans.
00086  *
00087  */
00088 
00089 #ifdef LOW_MEMORY
00090 #define EXT_DATA_SIZE 256
00091 #else
00092 #define EXT_DATA_SIZE 8192
00093 #endif
00094 
00095 #define SWITCH_DATA_LENGTH 256
00096 
00097 #define VAR_BUF_SIZE 4096
00098 
00099 #define  VAR_NORMAL     1
00100 #define  VAR_SOFTTRAN   2
00101 #define  VAR_HARDTRAN   3
00102 
00103 #define BACKGROUND_SKIP    (1 << 0)
00104 #define BACKGROUND_NOANSWER   (1 << 1)
00105 #define BACKGROUND_MATCHEXTEN (1 << 2)
00106 #define BACKGROUND_PLAYBACK   (1 << 3)
00107 
00108 AST_APP_OPTIONS(background_opts, {
00109    AST_APP_OPTION('s', BACKGROUND_SKIP),
00110    AST_APP_OPTION('n', BACKGROUND_NOANSWER),
00111    AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
00112    AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
00113 });
00114 
00115 #define WAITEXTEN_MOH      (1 << 0)
00116 #define WAITEXTEN_DIALTONE (1 << 1)
00117 
00118 AST_APP_OPTIONS(waitexten_opts, {
00119    AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
00120    AST_APP_OPTION_ARG('d', WAITEXTEN_DIALTONE, 0),
00121 });
00122 
00123 struct ast_context;
00124 struct ast_app;
00125 
00126 static struct ast_taskprocessor *device_state_tps;
00127 
00128 AST_THREADSTORAGE(switch_data);
00129 
00130 /*!
00131    \brief ast_exten: An extension
00132    The dialplan is saved as a linked list with each context
00133    having it's own linked list of extensions - one item per
00134    priority.
00135 */
00136 struct ast_exten {
00137    char *exten;         /*!< Extension name */
00138    int matchcid;        /*!< Match caller id ? */
00139    const char *cidmatch;      /*!< Caller id to match for this extension */
00140    int priority;        /*!< Priority */
00141    const char *label;      /*!< Label */
00142    struct ast_context *parent;   /*!< The context this extension belongs to  */
00143    const char *app;     /*!< Application to execute */
00144    struct ast_app *cached_app;     /*!< Cached location of application */
00145    void *data;       /*!< Data to use (arguments) */
00146    void (*datad)(void *);     /*!< Data destructor */
00147    struct ast_exten *peer;    /*!< Next higher priority with our extension */
00148    struct ast_hashtab *peer_table;    /*!< Priorities list in hashtab form -- only on the head of the peer list */
00149    struct ast_hashtab *peer_label_table; /*!< labeled priorities in the peers -- only on the head of the peer list */
00150    const char *registrar;     /*!< Registrar */
00151    struct ast_exten *next;    /*!< Extension with a greater ID */
00152    char stuff[0];
00153 };
00154 
00155 /*! \brief ast_include: include= support in extensions.conf */
00156 struct ast_include {
00157    const char *name;
00158    const char *rname;         /*!< Context to include */
00159    const char *registrar;        /*!< Registrar */
00160    int hastime;            /*!< If time construct exists */
00161    struct ast_timing timing;               /*!< time construct */
00162    struct ast_include *next;     /*!< Link them together */
00163    char stuff[0];
00164 };
00165 
00166 /*! \brief ast_sw: Switch statement in extensions.conf */
00167 struct ast_sw {
00168    char *name;
00169    const char *registrar;        /*!< Registrar */
00170    char *data;          /*!< Data load */
00171    int eval;
00172    AST_LIST_ENTRY(ast_sw) list;
00173    char stuff[0];
00174 };
00175 
00176 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
00177 struct ast_ignorepat {
00178    const char *registrar;
00179    struct ast_ignorepat *next;
00180    const char pattern[0];
00181 };
00182 
00183 /*! \brief match_char: forms a syntax tree for quick matching of extension patterns */
00184 struct match_char
00185 {
00186    int is_pattern; /* the pattern started with '_' */
00187    int deleted;    /* if this is set, then... don't return it */
00188    char *x;       /* the pattern itself-- matches a single char */
00189    int specificity; /* simply the strlen of x, or 10 for X, 9 for Z, and 8 for N; and '.' and '!' will add 11 ? */
00190    struct match_char *alt_char;
00191    struct match_char *next_char;
00192    struct ast_exten *exten; /* attached to last char of a pattern for exten */
00193 };
00194 
00195 struct scoreboard  /* make sure all fields are 0 before calling new_find_extension */
00196 {
00197    int total_specificity;
00198    int total_length;
00199    char last_char;   /* set to ! or . if they are the end of the pattern */
00200    int canmatch;     /* if the string to match was just too short */
00201    struct match_char *node;
00202    struct ast_exten *canmatch_exten;
00203    struct ast_exten *exten;
00204 };
00205 
00206 /*! \brief ast_context: An extension context */
00207 struct ast_context {
00208    ast_rwlock_t lock;         /*!< A lock to prevent multiple threads from clobbering the context */
00209    struct ast_exten *root;       /*!< The root of the list of extensions */
00210    struct ast_hashtab *root_table;            /*!< For exact matches on the extensions in the pattern tree, and for traversals of the pattern_tree  */
00211    struct match_char *pattern_tree;        /*!< A tree to speed up extension pattern matching */
00212    struct ast_context *next;     /*!< Link them together */
00213    struct ast_include *includes;    /*!< Include other contexts */
00214    struct ast_ignorepat *ignorepats;   /*!< Patterns for which to continue playing dialtone */
00215    char *registrar;        /*!< Registrar -- make sure you malloc this, as the registrar may have to survive module unloads */
00216    int refcount;                   /*!< each module that would have created this context should inc/dec this as appropriate */
00217    AST_LIST_HEAD_NOLOCK(, ast_sw) alts;   /*!< Alternative switches */
00218    ast_mutex_t macrolock;        /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
00219    char name[0];           /*!< Name of the context */
00220 };
00221 
00222 
00223 /*! \brief ast_app: A registered application */
00224 struct ast_app {
00225    int (*execute)(struct ast_channel *chan, void *data);
00226    const char *synopsis;         /*!< Synopsis text for 'show applications' */
00227    const char *description;      /*!< Description (help text) for 'show application &lt;name&gt;' */
00228    AST_RWLIST_ENTRY(ast_app) list;     /*!< Next app in list */
00229    struct ast_module *module;    /*!< Module this app belongs to */
00230    char name[0];           /*!< Name of the application */
00231 };
00232 
00233 /*! \brief ast_state_cb: An extension state notify register item */
00234 struct ast_state_cb {
00235    int id;
00236    void *data;
00237    ast_state_cb_type callback;
00238    AST_LIST_ENTRY(ast_state_cb) entry;
00239 };
00240 
00241 /*! \brief Structure for dial plan hints
00242 
00243   \note Hints are pointers from an extension in the dialplan to one or
00244   more devices (tech/name) 
00245    - See \ref AstExtState
00246 */
00247 struct ast_hint {
00248    struct ast_exten *exten;   /*!< Extension */
00249    int laststate;          /*!< Last known state */
00250    AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks; /*!< Callback list for this extension */
00251    AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
00252 };
00253 
00254 static const struct cfextension_states {
00255    int extension_state;
00256    const char * const text;
00257 } extension_states[] = {
00258    { AST_EXTENSION_NOT_INUSE,                     "Idle" },
00259    { AST_EXTENSION_INUSE,                         "InUse" },
00260    { AST_EXTENSION_BUSY,                          "Busy" },
00261    { AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
00262    { AST_EXTENSION_RINGING,                       "Ringing" },
00263    { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
00264    { AST_EXTENSION_ONHOLD,                        "Hold" },
00265    { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
00266 };
00267 
00268 struct statechange {
00269    AST_LIST_ENTRY(statechange) entry;
00270    char dev[0];
00271 };
00272 
00273 struct pbx_exception {
00274    AST_DECLARE_STRING_FIELDS(
00275       AST_STRING_FIELD(context); /*!< Context associated with this exception */
00276       AST_STRING_FIELD(exten);   /*!< Exten associated with this exception */
00277       AST_STRING_FIELD(reason);     /*!< The exception reason */
00278    );
00279 
00280    int priority;           /*!< Priority associated with this exception */
00281 };
00282 
00283 static int pbx_builtin_answer(struct ast_channel *, void *);
00284 static int pbx_builtin_goto(struct ast_channel *, void *);
00285 static int pbx_builtin_hangup(struct ast_channel *, void *);
00286 static int pbx_builtin_background(struct ast_channel *, void *);
00287 static int pbx_builtin_wait(struct ast_channel *, void *);
00288 static int pbx_builtin_waitexten(struct ast_channel *, void *);
00289 static int pbx_builtin_incomplete(struct ast_channel *, void *);
00290 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
00291 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
00292 static int pbx_builtin_ringing(struct ast_channel *, void *);
00293 static int pbx_builtin_proceeding(struct ast_channel *, void *);
00294 static int pbx_builtin_progress(struct ast_channel *, void *);
00295 static int pbx_builtin_congestion(struct ast_channel *, void *);
00296 static int pbx_builtin_busy(struct ast_channel *, void *);
00297 static int pbx_builtin_noop(struct ast_channel *, void *);
00298 static int pbx_builtin_gotoif(struct ast_channel *, void *);
00299 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
00300 static int pbx_builtin_execiftime(struct ast_channel *, void *);
00301 static int pbx_builtin_saynumber(struct ast_channel *, void *);
00302 static int pbx_builtin_saydigits(struct ast_channel *, void *);
00303 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
00304 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
00305 static int matchcid(const char *cidpattern, const char *callerid);
00306 int pbx_builtin_setvar(struct ast_channel *, void *);
00307 void log_match_char_tree(struct match_char *node, char *prefix); /* for use anywhere */
00308 int pbx_builtin_setvar_multiple(struct ast_channel *, void *);
00309 static int pbx_builtin_importvar(struct ast_channel *, void *);
00310 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri); 
00311 static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid, const char *label, enum ext_match_t action);
00312 static struct match_char *already_in_tree(struct match_char *current, char *pat);
00313 static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly);
00314 static struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity, struct match_char **parent);
00315 static void create_match_char_tree(struct ast_context *con);
00316 static struct ast_exten *get_canmatch_exten(struct match_char *node);
00317 static void destroy_pattern_tree(struct match_char *pattern_tree);
00318 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b);
00319 static int hashtab_compare_extens(const void *ha_a, const void *ah_b);
00320 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b);
00321 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b);
00322 unsigned int ast_hashtab_hash_contexts(const void *obj);
00323 static unsigned int hashtab_hash_extens(const void *obj);
00324 static unsigned int hashtab_hash_priority(const void *obj);
00325 static unsigned int hashtab_hash_labels(const void *obj);
00326 static void __ast_internal_context_destroy( struct ast_context *con);
00327 static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
00328    int priority, const char *label, const char *callerid,
00329    const char *application, void *data, void (*datad)(void *), const char *registrar);
00330 static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
00331    struct ast_exten *el, struct ast_exten *e, int replace, int lockhints);
00332 static int ast_add_extension2_lockopt(struct ast_context *con,
00333    int replace, const char *extension, int priority, const char *label, const char *callerid,
00334    const char *application, void *data, void (*datad)(void *),
00335    const char *registrar, int lockconts, int lockhints);
00336 
00337 /* a func for qsort to use to sort a char array */
00338 static int compare_char(const void *a, const void *b)
00339 {
00340    const char *ac = a;
00341    const char *bc = b;
00342    if ((*ac) < (*bc))
00343       return -1;
00344    else if ((*ac) == (*bc))
00345       return 0;
00346    else
00347       return 1;
00348 }
00349 
00350 /* labels, contexts are case sensitive  priority numbers are ints */
00351 int ast_hashtab_compare_contexts(const void *ah_a, const void *ah_b)
00352 {
00353    const struct ast_context *ac = ah_a;
00354    const struct ast_context *bc = ah_b;
00355    if (!ac || !bc) /* safety valve, but it might prevent a crash you'd rather have happen */
00356       return 1;
00357    /* assume context names are registered in a string table! */
00358    return strcmp(ac->name, bc->name);
00359 }
00360 
00361 static int hashtab_compare_extens(const void *ah_a, const void *ah_b)
00362 {
00363    const struct ast_exten *ac = ah_a;
00364    const struct ast_exten *bc = ah_b;
00365    int x = strcmp(ac->exten, bc->exten);
00366    if (x) { /* if exten names are diff, then return */
00367       return x;
00368    }
00369    
00370    /* but if they are the same, do the cidmatch values match? */
00371    if (ac->matchcid && bc->matchcid) {
00372       return strcmp(ac->cidmatch,bc->cidmatch);
00373    } else if (!ac->matchcid && !bc->matchcid) {
00374       return 0; /* if there's no matchcid on either side, then this is a match */
00375    } else {
00376       return 1; /* if there's matchcid on one but not the other, they are different */
00377    }
00378 }
00379 
00380 static int hashtab_compare_exten_numbers(const void *ah_a, const void *ah_b)
00381 {
00382    const struct ast_exten *ac = ah_a;
00383    const struct ast_exten *bc = ah_b;
00384    return ac->priority != bc->priority;
00385 }
00386 
00387 static int hashtab_compare_exten_labels(const void *ah_a, const void *ah_b)
00388 {
00389    const struct ast_exten *ac = ah_a;
00390    const struct ast_exten *bc = ah_b;
00391    return strcmp(S_OR(ac->label, ""), S_OR(bc->label, ""));
00392 }
00393 
00394 unsigned int ast_hashtab_hash_contexts(const void *obj)
00395 {
00396    const struct ast_context *ac = obj;
00397    return ast_hashtab_hash_string(ac->name);
00398 }
00399 
00400 static unsigned int hashtab_hash_extens(const void *obj)
00401 {
00402    const struct ast_exten *ac = obj;
00403    unsigned int x = ast_hashtab_hash_string(ac->exten);
00404    unsigned int y = 0;
00405    if (ac->matchcid)
00406       y = ast_hashtab_hash_string(ac->cidmatch);
00407    return x+y;
00408 }
00409 
00410 static unsigned int hashtab_hash_priority(const void *obj)
00411 {
00412    const struct ast_exten *ac = obj;
00413    return ast_hashtab_hash_int(ac->priority);
00414 }
00415 
00416 static unsigned int hashtab_hash_labels(const void *obj)
00417 {
00418    const struct ast_exten *ac = obj;
00419    return ast_hashtab_hash_string(S_OR(ac->label, ""));
00420 }
00421 
00422 
00423 AST_RWLOCK_DEFINE_STATIC(globalslock);
00424 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00425 
00426 static int autofallthrough = 1;
00427 static int extenpatternmatchnew = 0;
00428 static char *overrideswitch = NULL;
00429 
00430 /*! \brief Subscription for device state change events */
00431 static struct ast_event_sub *device_state_sub;
00432 
00433 AST_MUTEX_DEFINE_STATIC(maxcalllock);
00434 static int countcalls;
00435 static int totalcalls;
00436 
00437 static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
00438 
00439 /*! \brief Declaration of builtin applications */
00440 static struct pbx_builtin {
00441    char name[AST_MAX_APP];
00442    int (*execute)(struct ast_channel *chan, void *data);
00443    char *synopsis;
00444    char *description;
00445 } builtins[] =
00446 {
00447    /* These applications are built into the PBX core and do not
00448       need separate modules */
00449 
00450    { "Answer", pbx_builtin_answer,
00451    "Answer a channel if ringing",
00452    "  Answer([delay]): If the call has not been answered, this application will\n"
00453    "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
00454    "Asterisk will wait this number of milliseconds before returning to\n"
00455    "the dialplan after answering the call.\n"
00456    },
00457 
00458    { "BackGround", pbx_builtin_background,
00459    "Play an audio file while waiting for digits of an extension to go to.",
00460    "  Background(filename1[&filename2...][,options[,langoverride][,context]]):\n"
00461    "This application will play the given list of files (do not put extension)\n"
00462    "while waiting for an extension to be dialed by the calling channel. To\n"
00463    "continue waiting for digits after this application has finished playing\n"
00464    "files, the WaitExten application should be used. The 'langoverride' option\n"
00465    "explicitly specifies which language to attempt to use for the requested sound\n"
00466    "files. If a 'context' is specified, this is the dialplan context that this\n"
00467    "application will use when exiting to a dialed extension."
00468    "  If one of the requested sound files does not exist, call processing will be\n"
00469    "terminated.\n"
00470    "  Options:\n"
00471    "    s - Causes the playback of the message to be skipped\n"
00472    "          if the channel is not in the 'up' state (i.e. it\n"
00473    "          hasn't been answered yet). If this happens, the\n"
00474    "          application will return immediately.\n"
00475    "    n - Don't answer the channel before playing the files.\n"
00476    "    m - Only break if a digit hit matches a one digit\n"
00477    "          extension in the destination context.\n"
00478    "This application sets the following channel variable upon completion:\n"
00479    " BACKGROUNDSTATUS    The status of the background attempt as a text string, one of\n"
00480    "               SUCCESS | FAILED\n"
00481    "See Also: Playback (application) -- Play sound file(s) to the channel,\n"
00482    "                                    that cannot be interrupted\n"
00483    },
00484 
00485    { "Busy", pbx_builtin_busy,
00486    "Indicate the Busy condition",
00487    "  Busy([timeout]): This application will indicate the busy condition to\n"
00488    "the calling channel. If the optional timeout is specified, the calling channel\n"
00489    "will be hung up after the specified number of seconds. Otherwise, this\n"
00490    "application will wait until the calling channel hangs up.\n"
00491    },
00492 
00493    { "Congestion", pbx_builtin_congestion,
00494    "Indicate the Congestion condition",
00495    "  Congestion([timeout]): This application will indicate the congestion\n"
00496    "condition to the calling channel. If the optional timeout is specified, the\n"
00497    "calling channel will be hung up after the specified number of seconds.\n"
00498    "Otherwise, this application will wait until the calling channel hangs up.\n"
00499    },
00500 
00501    { "ExecIfTime", pbx_builtin_execiftime,
00502    "Conditional application execution based on the current time",
00503    "  ExecIfTime(<times>,<weekdays>,<mdays>,<months>?appname[(appargs)]):\n"
00504    "This application will execute the specified dialplan application, with optional\n"
00505    "arguments, if the current time matches the given time specification.\n"
00506    },
00507 
00508    { "Goto", pbx_builtin_goto,
00509    "Jump to a particular priority, extension, or context",
00510    "  Goto([[context,]extension,]priority): This application will set the current\n"
00511    "context, extension, and priority in the channel structure. After it completes, the\n"
00512    "pbx engine will continue dialplan execution at the specified location.\n"
00513    "If no specific extension, or extension and context, are specified, then this\n"
00514    "application will just set the specified priority of the current extension.\n"
00515    "  At least a priority is required as an argument, or the goto will return a -1,\n"
00516    "and the channel and call will be terminated.\n"
00517    "  If the location that is put into the channel information is bogus, and asterisk cannot\n"
00518    "find that location in the dialplan,\n"
00519    "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
00520    "extension in the current context. If that does not exist, it will try to execute the\n"
00521    "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
00522    "channel is hung up, and the execution of instructions on the channel is terminated.\n"
00523    "What this means is that, for example, you specify a context that does not exist, then\n"
00524    "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n"
00525    },
00526 
00527    { "GotoIf", pbx_builtin_gotoif,
00528    "Conditional goto",
00529    "  GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n"
00530    "context, extension, and priority in the channel structure based on the evaluation of\n"
00531    "the given condition. After this application completes, the\n"
00532    "pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
00533    "The channel will continue at\n"
00534    "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
00535    "false. The labels are specified with the same syntax as used within the Goto\n"
00536    "application.  If the label chosen by the condition is omitted, no jump is\n"
00537    "performed, and the execution passes to the next instruction.\n"
00538    "If the target location is bogus, and does not exist, the execution engine will try \n"
00539    "to find and execute the code in the 'i' (invalid)\n"
00540    "extension in the current context. If that does not exist, it will try to execute the\n"
00541    "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
00542    "channel is hung up, and the execution of instructions on the channel is terminated.\n"
00543    "Remember that this command can set the current context, and if the context specified\n"
00544    "does not exist, then it will not be able to find any 'h' or 'i' extensions there, and\n"
00545    "the channel and call will both be terminated!\n"
00546    },
00547 
00548    { "GotoIfTime", pbx_builtin_gotoiftime,
00549    "Conditional Goto based on the current time",
00550    "  GotoIfTime(<times>,<weekdays>,<mdays>,<months>?[labeliftrue]:[labeliffalse]):\n"
00551    "This application will set the context, extension, and priority in the channel structure\n"
00552    "based on the evaluation of the given time specification. After this application completes,\n"
00553    "the pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
00554    "If the current time is within the given time specification, the channel will continue at\n"
00555    "'labeliftrue'. Otherwise the channel will continue at 'labeliffalse'. If the label chosen\n"
00556    "by the condition is omitted, no jump is performed, and execution passes to the next\n"
00557    "instruction. If the target jump location is bogus, the same actions would be taken as for\n"
00558    "Goto.\n"
00559    "Further information on the time specification can be found in examples\n"
00560    "illustrating how to do time-based context includes in the dialplan.\n"
00561    },
00562 
00563    { "ImportVar", pbx_builtin_importvar,
00564    "Import a variable from a channel into a new variable",
00565    "  ImportVar(newvar=channelname,variable): This application imports a variable\n"
00566    "from the specified channel (as opposed to the current one) and stores it as\n"
00567    "a variable in the current channel (the channel that is calling this\n"
00568    "application). Variables created by this application have the same inheritance\n"
00569    "properties as those created with the Set application. See the documentation for\n"
00570    "Set for more information.\n"
00571    },
00572 
00573    { "Hangup", pbx_builtin_hangup,
00574    "Hang up the calling channel",
00575    "  Hangup([causecode]): This application will hang up the calling channel.\n"
00576    "If a causecode is given the channel's hangup cause will be set to the given\n"
00577    "value.\n"
00578    },
00579 
00580    { "Incomplete", pbx_builtin_incomplete,
00581    "returns AST_PBX_INCOMPLETE value",
00582    "  Incomplete([n]): Signals the PBX routines that the previous matched extension\n"
00583    "is incomplete and that further input should be allowed before matching can\n"
00584    "be considered to be complete.  Can be used within a pattern match when\n"
00585    "certain criteria warrants a longer match.\n"
00586    "  If the 'n' option is specified, then Incomplete will not attempt to answer\n"
00587    "the channel first.  Note that most channel types need to be in Answer state\n"
00588    "in order to receive DTMF.\n"
00589    },
00590 
00591    { "NoOp", pbx_builtin_noop,
00592    "Do Nothing (No Operation)",
00593    "  NoOp(): This application does nothing. However, it is useful for debugging\n"
00594    "purposes. Any text that is provided as arguments to this application can be\n"
00595    "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
00596    "variables or functions without having any effect. Alternatively, see the\n"
00597       "Verbose() application for finer grain control of output at custom verbose levels.\n"
00598    },
00599    
00600    { "Proceeding", pbx_builtin_proceeding,
00601    "Indicate proceeding",
00602    "  Proceeding(): This application will request that a proceeding message\n"
00603    "be provided to the calling channel.\n"
00604    },
00605    
00606    { "Progress", pbx_builtin_progress,
00607    "Indicate progress",
00608    "  Progress(): This application will request that in-band progress information\n"
00609    "be provided to the calling channel.\n"
00610    },
00611 
00612    { "RaiseException", pbx_builtin_raise_exception,
00613    "Handle an exceptional condition",
00614    "  RaiseException(<reason>): This application will jump to the \"e\" extension\n"
00615    "in the current context, setting the dialplan function EXCEPTION(). If the \"e\"\n"
00616    "extension does not exist, the call will hangup.\n"
00617    },
00618 
00619    { "ResetCDR", pbx_builtin_resetcdr,
00620    "Resets the Call Data Record",
00621    "  ResetCDR([options]):  This application causes the Call Data Record to be\n"
00622    "reset.\n"
00623    "  Options:\n"
00624    "    w -- Store the current CDR record before resetting it.\n"
00625    "    a -- Store any stacked records.\n"
00626    "    v -- Save CDR variables.\n"
00627    "    e -- Enable CDR only (negate effects of NoCDR).\n"
00628    },
00629 
00630    { "Ringing", pbx_builtin_ringing,
00631    "Indicate ringing tone",
00632    "  Ringing(): This application will request that the channel indicate a ringing\n"
00633    "tone to the user.\n"
00634    },
00635 
00636    { "SayAlpha", pbx_builtin_saycharacters,
00637    "Say Alpha",
00638    "  SayAlpha(string): This application will play the sounds that correspond to\n"
00639    "the letters of the given string.\n"
00640    },
00641 
00642    { "SayDigits", pbx_builtin_saydigits,
00643    "Say Digits",
00644    "  SayDigits(digits): This application will play the sounds that correspond\n"
00645    "to the digits of the given number. This will use the language that is currently\n"
00646    "set for the channel. See the LANGUAGE function for more information on setting\n"
00647    "the language for the channel.\n"
00648    },
00649 
00650    { "SayNumber", pbx_builtin_saynumber,
00651    "Say Number",
00652    "  SayNumber(digits[,gender]): This application will play the sounds that\n"
00653    "correspond to the given number. Optionally, a gender may be specified.\n"
00654    "This will use the language that is currently set for the channel. See the\n"
00655    "LANGUAGE function for more information on setting the language for the channel.\n"
00656    },
00657 
00658    { "SayPhonetic", pbx_builtin_sayphonetic,
00659    "Say Phonetic",
00660    "  SayPhonetic(string): This application will play the sounds from the phonetic\n"
00661    "alphabet that correspond to the letters in the given string.\n"
00662    },
00663 
00664    { "Set", pbx_builtin_setvar,
00665    "Set channel variable or function value",
00666    "  Set(name=value)\n"
00667    "This function can be used to set the value of channel variables or dialplan\n"
00668    "functions. When setting variables, if the variable name is prefixed with _,\n"
00669    "the variable will be inherited into channels created from the current\n"
00670    "channel. If the variable name is prefixed with __, the variable will be\n"
00671    "inherited into channels created from the current channel and all children\n"
00672    "channels.\n"
00673    "Compatibility note: If (and only if), in /etc/asterisk/asterisk.conf, you have a [compat]\n"
00674     "category, and you have app_set = 1.6 under that, then the behavior of this\n"
00675     "app changes, and does not strip surrounding quotes from the right hand side\n"
00676     "as it did previously in 1.4. The app_set = 1.6 is only inserted if 'make samples'\n"
00677    "is executed, or if users insert this by hand into the asterisk.conf file.\n"
00678    "/nThe advantages of not stripping out quoting, and not caring about the\n"
00679    "separator characters (comma and vertical bar) were sufficient to make these\n"
00680    "changes in 1.6. Confusion about how many backslashes would be needed to properly\n"
00681    "protect separators and quotes in various database access strings has been greatly\n"
00682    "reduced by these changes.\n"
00683    },
00684 
00685    { "MSet", pbx_builtin_setvar_multiple,
00686    "Set channel variable(s) or function value(s)",
00687    "  MSet(name1=value1,name2=value2,...)\n"
00688    "This function can be used to set the value of channel variables or dialplan\n"
00689    "functions. When setting variables, if the variable name is prefixed with _,\n"
00690    "the variable will be inherited into channels created from the current\n"
00691    "channel. If the variable name is prefixed with __, the variable will be\n"
00692    "inherited into channels created from the current channel and all children\n"
00693    "channels.\n\n"
00694    "MSet behaves in a similar fashion to the way Set worked in 1.2/1.4 and is thus\n"
00695    "prone to doing things that you may not expect. For example, it strips surrounding\n"
00696    "double-quotes from the right-hand side (value). If you need to put a separator\n"
00697         "character (comma or vert-bar), you will need to escape them by inserting a backslash\n"
00698    "before them. Avoid its use if possible.\n"
00699    },
00700 
00701    { "SetAMAFlags", pbx_builtin_setamaflags,
00702    "Set the AMA Flags",
00703    "  SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
00704    "  billing purposes.\n"
00705    },
00706 
00707    { "Wait", pbx_builtin_wait,
00708    "Waits for some time",
00709    "  Wait(seconds): This application waits for a specified number of seconds.\n"
00710    "Then, dialplan execution will continue at the next priority.\n"
00711    "  Note that the seconds can be passed with fractions of a second. For example,\n"
00712    "'1.5' will ask the application to wait for 1.5 seconds.\n"
00713    },
00714 
00715    { "WaitExten", pbx_builtin_waitexten,
00716    "Waits for an extension to be entered",
00717    "  WaitExten([seconds][,options]): This application waits for the user to enter\n"
00718    "a new extension for a specified number of seconds.\n"
00719    "  Note that the seconds can be passed with fractions of a second. For example,\n"
00720    "'1.5' will ask the application to wait for 1.5 seconds.\n"
00721    "  Options:\n"
00722    "    m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
00723    "               Optionally, specify the class for music on hold within parenthesis.\n"
00724    "Warning: Attempting to use this application from within a Macro will not work as\n"
00725    "desired. The Read() application is recommended as an alternative to WaitExten when\n"
00726    "used from a macro\n"
00727    "See Also: Playback(application), Background(application).\n"
00728    },
00729 };
00730 
00731 static struct ast_context *contexts;
00732 static struct ast_hashtab *contexts_table = NULL;
00733 
00734 AST_RWLOCK_DEFINE_STATIC(conlock);     /*!< Lock for the ast_context list */
00735 
00736 static AST_RWLIST_HEAD_STATIC(apps, ast_app);
00737 
00738 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
00739 
00740 static int stateid = 1;
00741 /* WARNING:
00742    When holding this list's lock, do _not_ do anything that will cause conlock
00743    to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
00744    function will take the locks in conlock/hints order, so any other
00745    paths that require both locks must also take them in that order.
00746 */
00747 static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
00748 
00749 static AST_LIST_HEAD_NOLOCK_STATIC(statecbs, ast_state_cb);
00750 
00751 #ifdef CONTEXT_DEBUG
00752 
00753 /* these routines are provided for doing run-time checks
00754    on the extension structures, in case you are having
00755    problems, this routine might help you localize where
00756    the problem is occurring. It's kinda like a debug memory
00757    allocator's arena checker... It'll eat up your cpu cycles!
00758    but you'll see, if you call it in the right places,
00759    right where your problems began...
00760 */
00761 
00762 /* you can break on the check_contexts_trouble()
00763 routine in your debugger to stop at the moment
00764 there's a problem */
00765 void check_contexts_trouble(void);
00766 
00767 void check_contexts_trouble(void)
00768 {
00769    int x = 1;
00770    x = 2;
00771 }
00772 
00773 static struct ast_context *find_context_locked(const char *context);
00774 static struct ast_context *find_context(const char *context);
00775 int check_contexts(char *, int);
00776 
00777 int check_contexts(char *file, int line )
00778 {
00779    struct ast_hashtab_iter *t1;
00780    struct ast_context *c1, *c2;
00781    int found = 0;
00782    struct ast_exten *e1, *e2, *e3;
00783    struct ast_exten ex;
00784    
00785    /* try to find inconsistencies */
00786    /* is every context in the context table in the context list and vice-versa ? */
00787    
00788    if (!contexts_table) {
00789       ast_log(LOG_NOTICE,"Called from: %s:%d: No contexts_table!\n", file, line);
00790       usleep(500000);
00791    }
00792 
00793    t1 = ast_hashtab_start_traversal(contexts_table);
00794    while( (c1 = ast_hashtab_next(t1))) {
00795       for(c2=contexts;c2;c2=c2->next) {
00796          if (!strcmp(c1->name, c2->name)) {
00797             found = 1;
00798             break;
00799          }
00800       }
00801       if (!found) {
00802          ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the linked list\n", file, line, c1->name);
00803          check_contexts_trouble();
00804       }
00805    }
00806    ast_hashtab_end_traversal(t1);
00807    for(c2=contexts;c2;c2=c2->next) {
00808       c1 = find_context_locked(c2->name);
00809       if (!c1) {
00810          ast_log(LOG_NOTICE,"Called from: %s:%d: Could not find the %s context in the hashtab\n", file, line, c2->name);
00811          check_contexts_trouble();
00812       } else
00813          ast_unlock_contexts();
00814    }
00815 
00816    /* loop thru all contexts, and verify the exten structure compares to the 
00817       hashtab structure */
00818    for(c2=contexts;c2;c2=c2->next) {
00819       c1 = find_context_locked(c2->name);
00820       if (c1)
00821       {
00822 
00823          ast_unlock_contexts();
00824 
00825          /* is every entry in the root list also in the root_table? */
00826          for(e1 = c1->root; e1; e1=e1->next)
00827          {
00828             char dummy_name[1024];
00829             ex.exten = dummy_name;
00830             ex.matchcid = e1->matchcid;
00831             ex.cidmatch = e1->cidmatch;
00832             ast_copy_string(dummy_name, e1->exten, sizeof(dummy_name));
00833             e2 = ast_hashtab_lookup(c1->root_table, &ex);
00834             if (!e2) {
00835                if (e1->matchcid) {
00836                   ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s (CID match: %s) but it is not in its root_table\n", file, line, c2->name, dummy_name, e1->cidmatch );
00837                } else {
00838                   ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, dummy_name );
00839                }
00840                check_contexts_trouble();
00841             }
00842          }
00843          
00844          /* is every entry in the root_table also in the root list? */ 
00845          if (!c2->root_table) {
00846             if (c2->root) {
00847                ast_log(LOG_NOTICE,"Called from: %s:%d: No c2->root_table for context %s!\n", file, line, c2->name);
00848                usleep(500000);
00849             }
00850          } else {
00851             t1 = ast_hashtab_start_traversal(c2->root_table);
00852             while( (e2 = ast_hashtab_next(t1)) ) {
00853                for(e1=c2->root;e1;e1=e1->next) {
00854                   if (!strcmp(e1->exten, e2->exten)) {
00855                      found = 1;
00856                      break;
00857                   }
00858                }
00859                if (!found) {
00860                   ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context records the exten %s but it is not in its root_table\n", file, line, c2->name, e2->exten);
00861                   check_contexts_trouble();
00862                }
00863                
00864             }
00865             ast_hashtab_end_traversal(t1);
00866          }
00867       }
00868       /* is every priority reflected in the peer_table at the head of the list? */
00869       
00870       /* is every entry in the root list also in the root_table? */
00871       /* are the per-extension peer_tables in the right place? */
00872 
00873       for(e1 = c2->root; e1; e1 = e1->next) {
00874          
00875          for(e2=e1;e2;e2=e2->peer) {
00876             ex.priority = e2->priority;
00877             if (e2 != e1 && e2->peer_table) {
00878                ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
00879                check_contexts_trouble();
00880             }
00881             
00882             if (e2 != e1 && e2->peer_label_table) {
00883                ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority has a peer_label_table entry, and shouldn't!\n", file, line, c2->name, e1->exten, e2->priority );
00884                check_contexts_trouble();
00885             }
00886             
00887             if (e2 == e1 && !e2->peer_table){
00888                ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_table!\n", file, line, c2->name, e1->exten, e2->priority );
00889                check_contexts_trouble();
00890             }
00891             
00892             if (e2 == e1 && !e2->peer_label_table) {
00893                ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority doesn't have a peer_label_table!\n", file, line, c2->name, e1->exten, e2->priority );
00894                check_contexts_trouble();
00895             }
00896             
00897 
00898             e3 = ast_hashtab_lookup(e1->peer_table, &ex);
00899             if (!e3) {
00900                ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer_table\n", file, line, c2->name, e1->exten, e2->priority );
00901                check_contexts_trouble();
00902             }
00903          }
00904          
00905          if (!e1->peer_table){
00906             ast_log(LOG_NOTICE,"Called from: %s:%d: No e1->peer_table!\n", file, line);
00907             usleep(500000);
00908          }
00909          
00910          /* is every entry in the peer_table also in the peer list? */ 
00911          t1 = ast_hashtab_start_traversal(e1->peer_table);
00912          while( (e2 = ast_hashtab_next(t1)) ) {
00913             for(e3=e1;e3;e3=e3->peer) {
00914                if (e3->priority == e2->priority) {
00915                   found = 1;
00916                   break;
00917                }
00918             }
00919             if (!found) {
00920                ast_log(LOG_NOTICE,"Called from: %s:%d: The %s context, %s exten, %d priority is not reflected in the peer list\n", file, line, c2->name, e1->exten, e2->priority );
00921                check_contexts_trouble();
00922             }
00923          }
00924          ast_hashtab_end_traversal(t1);
00925       }
00926    }
00927    return 0;
00928 }
00929 #endif
00930 
00931 /*
00932    \note This function is special. It saves the stack so that no matter
00933    how many times it is called, it returns to the same place */
00934 int pbx_exec(struct ast_channel *c,       /*!< Channel */
00935         struct ast_app *app,     /*!< Application */
00936         void *data)        /*!< Data for execution */
00937 {
00938    int res;
00939    struct ast_module_user *u = NULL;
00940    const char *saved_c_appl;
00941    const char *saved_c_data;
00942 
00943    if (c->cdr && !ast_check_hangup(c))
00944       ast_cdr_setapp(c->cdr, app->name, data);
00945 
00946    /* save channel values */
00947    saved_c_appl= c->appl;
00948    saved_c_data= c->data;
00949 
00950    c->appl = app->name;
00951    c->data = data;
00952    if (app->module)
00953       u = __ast_module_user_add(app->module, c);
00954    if (strcasecmp(app->name, "system") && !ast_strlen_zero(data) &&
00955          strchr(data, '|') && !strchr(data, ',') && !ast_opt_dont_warn) {
00956       ast_log(LOG_WARNING, "The application delimiter is now the comma, not "
00957          "the pipe.  Did you forget to convert your dialplan?  (%s(%s))\n",
00958          app->name, (char *) data);
00959    }
00960    res = app->execute(c, S_OR(data, ""));
00961    if (app->module && u)
00962       __ast_module_user_remove(app->module, u);
00963    /* restore channel values */
00964    c->appl = saved_c_appl;
00965    c->data = saved_c_data;
00966    return res;
00967 }
00968 
00969 
00970 /*! Go no deeper than this through includes (not counting loops) */
00971 #define AST_PBX_MAX_STACK  128
00972 
00973 /*! \brief Find application handle in linked list
00974  */
00975 struct ast_app *pbx_findapp(const char *app)
00976 {
00977    struct ast_app *tmp;
00978 
00979    AST_RWLIST_RDLOCK(&apps);
00980    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
00981       if (!strcasecmp(tmp->name, app))
00982          break;
00983    }
00984    AST_RWLIST_UNLOCK(&apps);
00985 
00986    return tmp;
00987 }
00988 
00989 static struct ast_switch *pbx_findswitch(const char *sw)
00990 {
00991    struct ast_switch *asw;
00992 
00993    AST_RWLIST_RDLOCK(&switches);
00994    AST_RWLIST_TRAVERSE(&switches, asw, list) {
00995       if (!strcasecmp(asw->name, sw))
00996          break;
00997    }
00998    AST_RWLIST_UNLOCK(&switches);
00999 
01000    return asw;
01001 }
01002 
01003 static inline int include_valid(struct ast_include *i)
01004 {
01005    if (!i->hastime)
01006       return 1;
01007 
01008    return ast_check_timing(&(i->timing));
01009 }
01010 
01011 static void pbx_destroy(struct ast_pbx *p)
01012 {
01013    ast_free(p);
01014 }
01015 
01016 /* form a tree that fully describes all the patterns in a context's extensions 
01017  * in this tree, a "node" represents an individual character or character set
01018  * meant to match the corresponding character in a dial string. The tree 
01019  * consists of a series of match_char structs linked in a chain
01020  * via the alt_char pointers. More than one pattern can share the same parts of the 
01021  * tree as other extensions with the same pattern to that point. 
01022  * My first attempt to duplicate the finding of the 'best' pattern was flawed in that
01023  * I misunderstood the general algorithm. I thought that the 'best' pattern
01024  * was the one with lowest total score. This was not true. Thus, if you have
01025  * patterns "1XXXXX" and "X11111", you would be tempted to say that "X11111" is
01026  * the "best" match because it has fewer X's, and is therefore more specific, 
01027  * but this is not how the old algorithm works. It sorts matching patterns
01028  * in a similar collating sequence as sorting alphabetic strings, from left to 
01029  * right. Thus, "1XXXXX" comes before "X11111", and would be the "better" match,
01030  * because "1" is more specific than "X".
01031  * So, to accomodate this philosophy, I sort the tree branches along the alt_char
01032  * line so they are lowest to highest in specificity numbers. This way, as soon
01033  * as we encounter our first complete match, we automatically have the "best" 
01034  * match and can stop the traversal immediately. Same for CANMATCH/MATCHMORE.
01035  * If anyone would like to resurrect the "wrong" pattern trie searching algorithm,
01036  * they are welcome to revert pbx to before 1 Apr 2008.
01037  * As an example, consider these 4 extensions:
01038  * (a) NXXNXXXXXX
01039  * (b) 307754XXXX 
01040  * (c) fax
01041  * (d) NXXXXXXXXX
01042  *
01043  * In the above, between (a) and (d), (a) is a more specific pattern than (d), and would win over
01044  * most numbers. For all numbers beginning with 307754, (b) should always win.
01045  *
01046  * These pattern should form a (sorted) tree that looks like this:
01047  *   { "3" }  --next-->  { "0" }  --next--> { "7" } --next--> { "7" } --next--> { "5" } ... blah ... --> { "X" exten_match: (b) }
01048  *      |
01049  *      |alt
01050  *      |
01051  *   { "f" }  --next-->  { "a" }  --next--> { "x"  exten_match: (c) }
01052  *   { "N" }  --next-->  { "X" }  --next--> { "X" } --next--> { "N" } --next--> { "X" } ... blah ... --> { "X" exten_match: (a) }
01053  *      |                                                        |
01054  *      |                                                        |alt
01055  *      |alt                                                     |
01056  *      |                                                     { "X" } --next--> { "X" } ... blah ... --> { "X" exten_match: (d) }
01057  *      |
01058  *     NULL
01059  *
01060  *   In the above, I could easily turn "N" into "23456789", but I think that a quick "if( *z >= '2' && *z <= '9' )" might take
01061  *   fewer CPU cycles than a call to strchr("23456789",*z), where *z is the char to match...
01062  *
01063  *   traversal is pretty simple: one routine merely traverses the alt list, and for each matching char in the pattern,  it calls itself
01064  *   on the corresponding next pointer, incrementing also the pointer of the string to be matched, and passing the total specificity and length.
01065  *   We pass a pointer to a scoreboard down through, also.
01066  *   The scoreboard isn't as necessary to the revised algorithm, but I kept it as a handy way to return the matched extension.
01067  *   The first complete match ends the traversal, which should make this version of the pattern matcher faster
01068  *   the previous. The same goes for "CANMATCH" or "MATCHMORE"; the first such match ends the traversal. In both
01069  *   these cases, the reason we can stop immediately, is because the first pattern match found will be the "best"
01070  *   according to the sort criteria.
01071  *   Hope the limit on stack depth won't be a problem... this routine should 
01072  *   be pretty lean as far a stack usage goes. Any non-match terminates the recursion down a branch.
01073  *
01074  *   In the above example, with the number "3077549999" as the pattern, the traversor could match extensions a, b and d.  All are
01075  *   of length 10; they have total specificities of  24580, 10246, and 25090, respectively, not that this matters
01076  *   at all. (b) wins purely because the first character "3" is much more specific (lower specificity) than "N". I have
01077  *   left the specificity totals in the code as an artifact; at some point, I will strip it out.
01078  *
01079  *   Just how much time this algorithm might save over a plain linear traversal over all possible patterns is unknown,
01080  *   because it's a function of how many extensions are stored in a context. With thousands of extensions, the speedup
01081  *   can be very noticeable. The new matching algorithm can run several hundreds of times faster, if not a thousand or
01082  *   more times faster in extreme cases.
01083  *
01084  *   MatchCID patterns are also supported, and stored in the tree just as the extension pattern is. Thus, you
01085  *   can have patterns in your CID field as well.
01086  *
01087  * */
01088 
01089 
01090 static void update_scoreboard(struct scoreboard *board, int length, int spec, struct ast_exten *exten, char last, const char *callerid, int deleted, struct match_char *node)
01091 {
01092    /* if this extension is marked as deleted, then skip this -- if it never shows
01093       on the scoreboard, it will never be found, nor will halt the traversal. */
01094    if (deleted)
01095       return;
01096    board->total_specificity = spec;
01097    board->total_length = length;
01098    board->exten = exten;
01099    board->last_char = last;
01100    board->node = node;
01101 #ifdef NEED_DEBUG_HERE
01102    ast_log(LOG_NOTICE,"Scoreboarding (LONGER) %s, len=%d, score=%d\n", exten->exten, length, spec);
01103 #endif
01104 }
01105 
01106 void log_match_char_tree(struct match_char *node, char *prefix)
01107 {
01108    char extenstr[40];
01109    struct ast_str *my_prefix = ast_str_alloca(1024); 
01110 
01111    extenstr[0] = '\0';
01112 
01113    if (node && node->exten && node->exten)
01114       snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
01115    
01116    if (strlen(node->x) > 1) {
01117       ast_debug(1, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', 
01118          node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"", 
01119          node->exten ? node->exten->exten : "", extenstr);
01120    } else {
01121       ast_debug(1, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y':'N', 
01122          node->deleted? 'D':'-', node->specificity, node->exten? "EXTEN:":"", 
01123          node->exten ? node->exten->exten : "", extenstr);
01124    }
01125 
01126    ast_str_set(&my_prefix, 0, "%s+       ", prefix);
01127 
01128    if (node->next_char)
01129       log_match_char_tree(node->next_char, my_prefix->str);
01130 
01131    if (node->alt_char)
01132       log_match_char_tree(node->alt_char, prefix);
01133 }
01134 
01135 static void cli_match_char_tree(struct match_char *node, char *prefix, int fd)
01136 {
01137    char extenstr[40];
01138    struct ast_str *my_prefix = ast_str_alloca(1024);
01139    
01140    extenstr[0] = '\0';
01141 
01142    if (node && node->exten && node->exten)
01143       snprintf(extenstr, sizeof(extenstr), "(%p)", node->exten);
01144    
01145    if (strlen(node->x) > 1) {
01146       ast_cli(fd, "%s[%s]:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N', 
01147          node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "", 
01148          node->exten ? node->exten->exten : "", extenstr);
01149    } else {
01150       ast_cli(fd, "%s%s:%c:%c:%d:%s%s%s\n", prefix, node->x, node->is_pattern ? 'Y' : 'N', 
01151          node->deleted ? 'D' : '-', node->specificity, node->exten? "EXTEN:" : "", 
01152          node->exten ? node->exten->exten : "", extenstr);
01153    }
01154 
01155    ast_str_set(&my_prefix, 0, "%s+       ", prefix);
01156 
01157    if (node->next_char)
01158       cli_match_char_tree(node->next_char, my_prefix->str, fd);
01159 
01160    if (node->alt_char)
01161       cli_match_char_tree(node->alt_char, prefix, fd);
01162 }
01163 
01164 static struct ast_exten *get_canmatch_exten(struct match_char *node)
01165 {
01166    /* find the exten at the end of the rope */
01167    struct match_char *node2 = node;
01168 
01169    for (node2 = node; node2; node2 = node2->next_char) {
01170       if (node2->exten) {
01171 #ifdef NEED_DEBUG_HERE
01172          ast_log(LOG_NOTICE,"CanMatch_exten returns exten %s(%p)\n", node2->exten->exten, node2->exten);
01173 #endif
01174          return node2->exten;
01175       }
01176    }
01177 #ifdef NEED_DEBUG_HERE
01178    ast_log(LOG_NOTICE,"CanMatch_exten returns NULL, match_char=%s\n", node->x);
01179 #endif
01180    return 0;
01181 }
01182 
01183 static struct ast_exten *trie_find_next_match(struct match_char *node)
01184 {
01185    struct match_char *m3;
01186    struct match_char *m4;
01187    struct ast_exten *e3;
01188    
01189    if (node && node->x[0] == '.' && !node->x[1]) /* dot and ! will ALWAYS be next match in a matchmore */
01190       return node->exten;
01191    
01192    if (node && node->x[0] == '!' && !node->x[1])
01193       return node->exten;
01194    
01195    if (!node || !node->next_char)
01196       return NULL;
01197    
01198    m3 = node->next_char;
01199 
01200    if (m3->exten)
01201       return m3->exten;
01202    for(m4=m3->alt_char; m4; m4 = m4->alt_char) {
01203       if (m4->exten)
01204          return m4->exten;
01205    }
01206    for(m4=m3; m4; m4 = m4->alt_char) {
01207       e3 = trie_find_next_match(m3);
01208       if (e3)
01209          return e3;
01210    }
01211    return NULL;
01212 }
01213 
01214 #ifdef DEBUG_THIS
01215 static char *action2str(enum ext_match_t action)
01216 {
01217    switch(action)
01218    {
01219    case E_MATCH:
01220       return "MATCH";
01221    case E_CANMATCH:
01222       return "CANMATCH";
01223    case E_MATCHMORE:
01224       return "MATCHMORE";
01225    case E_FINDLABEL:
01226       return "FINDLABEL";
01227    case E_SPAWN:
01228       return "SPAWN";
01229    default:
01230       return "?ACTION?";
01231    }
01232 }
01233 
01234 #endif
01235 
01236 static void new_find_extension(const char *str, struct scoreboard *score, struct match_char *tree, int length, int spec, const char *callerid, const char *label, enum ext_match_t action)
01237 {
01238    struct match_char *p; /* note minimal stack storage requirements */
01239    struct ast_exten pattern = { .label = label };
01240 #ifdef DEBUG_THIS
01241    if (tree)
01242       ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree %s action=%s\n", str, tree->x, action2str(action));
01243    else
01244       ast_log(LOG_NOTICE,"new_find_extension called with %s on (sub)tree NULL action=%s\n", str, action2str(action));
01245 #endif
01246    for (p=tree; p; p=p->alt_char) {
01247       if (p->x[0] == 'N') {
01248          if (p->x[1] == 0 && *str >= '2' && *str <= '9' ) {
01249 #define NEW_MATCHER_CHK_MATCH        \
01250             if (p->exten && !(*(str+1))) { /* if a shorter pattern matches along the way, might as well report it */             \
01251                if (action == E_MATCH || action == E_SPAWN || action == E_FINDLABEL) { /* if in CANMATCH/MATCHMORE, don't let matches get in the way */   \
01252                   update_scoreboard(score, length+1, spec+p->specificity, p->exten,0,callerid, p->deleted, p);                 \
01253                   if (!p->deleted) {                                                                                           \
01254                      if (action == E_FINDLABEL) {                                                                             \
01255                         if (ast_hashtab_lookup(score->exten->peer_label_table, &pattern)) {                                  \
01256                            ast_debug(4, "Found label in preferred extension\n");                                            \
01257                            return;                                                                                          \
01258                         }                                                                                                    \
01259                      } else {                                                                                                 \
01260                         ast_debug(4,"returning an exact match-- first found-- %s\n", p->exten->exten);                       \
01261                         return; /* the first match, by definition, will be the best, because of the sorted tree */           \
01262                      }                                                                                                        \
01263                   }                                                                                                            \
01264                }                                                                                                                \
01265             }
01266             
01267 #define NEW_MATCHER_RECURSE              \
01268             if (p->next_char && ( *(str+1) || (p->next_char->x[0] == '/' && p->next_char->x[1] == 0)                 \
01269                                                || p->next_char->x[0] == '!')) {                                          \
01270                if (*(str+1) || p->next_char->x[0] == '!') {                                                         \
01271                   new_find_extension(str+1, score, p->next_char, length+1, spec+p->specificity, callerid, label, action); \
01272                   if (score->exten)  {                                                                             \
01273                        ast_debug(4,"returning an exact match-- %s\n", score->exten->exten);                         \
01274                      return; /* the first match is all we need */                                                 \
01275                   }                                                                                    \
01276                } else {                                                                                             \
01277                   new_find_extension("/", score, p->next_char, length+1, spec+p->specificity, callerid, label, action);  \
01278                   if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {      \
01279                        ast_debug(4,"returning a (can/more) match--- %s\n", score->exten ? score->exten->exten :     \
01280                                        "NULL");                                                                        \
01281                      return; /* the first match is all we need */                                                 \
01282                   }                                                                                    \
01283                }                                                                                                    \
01284             } else if (p->next_char && !*(str+1)) {                                                                  \
01285                score->canmatch = 1;                                                                                 \
01286                score->canmatch_exten = get_canmatch_exten(p);                                                       \
01287                if (action == E_CANMATCH || action == E_MATCHMORE) {                                                 \
01288                     ast_debug(4,"returning a canmatch/matchmore--- str=%s\n", str);                                  \
01289                   return;                                                                                          \
01290                }                                                                                        \
01291             }
01292             
01293             NEW_MATCHER_CHK_MATCH;
01294             NEW_MATCHER_RECURSE;
01295          }
01296       } else if (p->x[0] == 'Z') {
01297          if (p->x[1] == 0 && *str >= '1' && *str <= '9' ) {
01298             NEW_MATCHER_CHK_MATCH;
01299             NEW_MATCHER_RECURSE;
01300          }
01301       } else if (p->x[0] == 'X') { 
01302          if (p->x[1] == 0 && *str >= '0' && *str <= '9' ) {
01303             NEW_MATCHER_CHK_MATCH;
01304             NEW_MATCHER_RECURSE;
01305          }
01306       } else if (p->x[0] == '.' && p->x[1] == 0) {
01307          /* how many chars will the . match against? */
01308          int i = 0;
01309          const char *str2 = str;
01310          while (*str2 && *str2 != '/') {
01311             str2++;
01312             i++;
01313          }
01314          if (p->exten && *str2 != '/') {
01315             update_scoreboard(score, length+i, spec+(i*p->specificity), p->exten, '.', callerid, p->deleted, p);
01316             if (score->exten) {
01317                ast_debug(4,"return because scoreboard has a match with '/'--- %s\n", score->exten->exten);
01318                return; /* the first match is all we need */
01319             }
01320          }
01321          if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
01322             new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid, label, action);
01323             if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01324                ast_debug(4,"return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set--- %s\n", score->exten ? score->exten->exten : "NULL");
01325                return; /* the first match is all we need */
01326             }
01327          }
01328       } else if (p->x[0] == '!' && p->x[1] == 0) {
01329          /* how many chars will the . match against? */
01330          int i = 1;
01331          const char *str2 = str;
01332          while (*str2 && *str2 != '/') {
01333             str2++;
01334             i++;
01335          }
01336          if (p->exten && *str2 != '/') {
01337             update_scoreboard(score, length+1, spec+(p->specificity*i), p->exten, '!', callerid, p->deleted, p);
01338             if (score->exten) {
01339                ast_debug(4,"return because scoreboard has a '!' match--- %s\n", score->exten->exten);
01340                return; /* the first match is all we need */
01341             }
01342          }
01343          if (p->next_char && p->next_char->x[0] == '/' && p->next_char->x[1] == 0) {
01344             new_find_extension("/", score, p->next_char, length+i, spec+(p->specificity*i), callerid, label, action);
01345             if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01346                ast_debug(4,"return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/' and '!'--- %s\n", score->exten ? score->exten->exten : "NULL");
01347                return; /* the first match is all we need */
01348             }
01349          }
01350       } else if (p->x[0] == '/' && p->x[1] == 0) {
01351          /* the pattern in the tree includes the cid match! */
01352          if (p->next_char && callerid && *callerid) {
01353             new_find_extension(callerid, score, p->next_char, length+1, spec, callerid, label, action);
01354             if (score->exten || ((action == E_CANMATCH || action == E_MATCHMORE) && score->canmatch)) {
01355                ast_debug(4,"return because scoreboard has exact match OR CANMATCH/MATCHMORE & canmatch set with '/'--- %s\n", score->exten ? score->exten->exten : "NULL");
01356                return; /* the first match is all we need */
01357             }
01358          }
01359       } else if (strchr(p->x, *str)) {
01360          ast_debug(4, "Nothing strange about this match\n");
01361          NEW_MATCHER_CHK_MATCH;
01362          NEW_MATCHER_RECURSE;
01363       }
01364    }
01365    ast_debug(4,"return at end of func\n");
01366 }
01367 
01368 /* the algorithm for forming the extension pattern tree is also a bit simple; you 
01369  * traverse all the extensions in a context, and for each char of the extension,
01370  * you see if it exists in the tree; if it doesn't, you add it at the appropriate
01371  * spot. What more can I say? At the end of each exten, you cap it off by adding the
01372  * address of the extension involved. Duplicate patterns will be complained about.
01373  *
01374  * Ideally, this would be done for each context after it is created and fully 
01375  * filled. It could be done as a finishing step after extensions.conf or .ael is
01376  * loaded, or it could be done when the first search is encountered. It should only
01377  * have to be done once, until the next unload or reload.
01378  *
01379  * I guess forming this pattern tree would be analogous to compiling a regex. Except
01380  * that a regex only handles 1 pattern, really. This trie holds any number
01381  * of patterns. Well, really, it **could** be considered a single pattern,
01382  * where the "|" (or) operator is allowed, I guess, in a way, sort of...
01383  */
01384 
01385 static struct match_char *already_in_tree(struct match_char *current, char *pat)
01386 {
01387    struct match_char *t;
01388 
01389    if (!current)
01390       return 0;
01391 
01392    for (t = current; t; t = t->alt_char) {
01393       if (!strcmp(pat, t->x)) /* uh, we may want to sort exploded [] contents to make matching easy */
01394          return t;
01395    }
01396 
01397    return 0;
01398 }
01399 
01400 /* The first arg is the location of the tree ptr, or the 
01401    address of the next_char ptr in the node, so we can mess
01402    with it, if we need to insert at the beginning of the list */
01403 
01404 static void insert_in_next_chars_alt_char_list(struct match_char **parent_ptr, struct match_char *node)
01405 {
01406    struct match_char *curr, *lcurr;
01407    
01408    /* insert node into the tree at "current", so the alt_char list from current is
01409       sorted in increasing value as you go to the leaves */
01410    if (!(*parent_ptr)) {
01411       *parent_ptr = node;
01412    } else {
01413       if ((*parent_ptr)->specificity > node->specificity){
01414          /* insert at head */
01415          node->alt_char = (*parent_ptr);
01416          *parent_ptr = node;
01417       } else {
01418          lcurr = *parent_ptr;
01419          for (curr=(*parent_ptr)->alt_char; curr; curr = curr->alt_char) {
01420             if (curr->specificity > node->specificity) {
01421                node->alt_char = curr;
01422                lcurr->alt_char = node;
01423                break;
01424             }
01425             lcurr = curr;
01426          }
01427          if (!curr)
01428          {
01429             lcurr->alt_char = node;
01430          }
01431       }
01432    }
01433 }
01434 
01435 
01436 
01437 static struct match_char *add_pattern_node(struct ast_context *con, struct match_char *current, char *pattern, int is_pattern, int already, int specificity, struct match_char **nextcharptr)
01438 {
01439    struct match_char *m;
01440    
01441    if (!(m = ast_calloc(1, sizeof(*m))))
01442       return NULL;
01443 
01444    if (!(m->x = ast_strdup(pattern))) {
01445       ast_free(m);
01446       return NULL;
01447    }
01448 
01449    /* the specificity scores are the same as used in the old
01450       pattern matcher. */
01451    m->is_pattern = is_pattern;
01452    if (specificity == 1 && is_pattern && pattern[0] == 'N')
01453       m->specificity = 0x0802;
01454    else if (specificity == 1 && is_pattern && pattern[0] == 'Z')
01455       m->specificity = 0x0901;
01456    else if (specificity == 1 && is_pattern && pattern[0] == 'X')
01457       m->specificity = 0x0a00;
01458    else if (specificity == 1 && is_pattern && pattern[0] == '.')
01459       m->specificity = 0x10000;
01460    else if (specificity == 1 && is_pattern && pattern[0] == '!')
01461       m->specificity = 0x20000;
01462    else
01463       m->specificity = specificity;
01464    
01465    if (!con->pattern_tree) {
01466       insert_in_next_chars_alt_char_list(&con->pattern_tree, m);
01467    } else {
01468       if (already) { /* switch to the new regime (traversing vs appending)*/
01469          insert_in_next_chars_alt_char_list(nextcharptr, m);
01470       } else {
01471          insert_in_next_chars_alt_char_list(&current->next_char, m);
01472       }
01473    }
01474 
01475    return m;
01476 }
01477 
01478 static struct match_char *add_exten_to_pattern_tree(struct ast_context *con, struct ast_exten *e1, int findonly)
01479 {
01480    struct match_char *m1 = NULL, *m2 = NULL, **m0;
01481    int specif;
01482    int already;
01483    int pattern = 0;
01484    char buf[256];
01485    char extenbuf[512];
01486    char *s1 = extenbuf;
01487    int l1 = strlen(e1->exten) + strlen(e1->cidmatch) + 2;
01488    
01489 
01490    ast_copy_string(extenbuf, e1->exten, sizeof(extenbuf));
01491 
01492    if (e1->matchcid &&  l1 <= sizeof(extenbuf)) {
01493       strcat(extenbuf,"/");
01494       strcat(extenbuf,e1->cidmatch);
01495    } else if (l1 > sizeof(extenbuf)) {
01496       ast_log(LOG_ERROR,"The pattern %s/%s is too big to deal with: it will be ignored! Disaster!\n", e1->exten, e1->cidmatch);
01497       return 0;
01498    }
01499 #ifdef NEED_DEBUG
01500    ast_log(LOG_DEBUG,"Adding exten %s%c%s to tree\n", s1, e1->matchcid? '/':' ', e1->matchcid? e1->cidmatch : "");
01501 #endif
01502    m1 = con->pattern_tree; /* each pattern starts over at the root of the pattern tree */
01503    m0 = &con->pattern_tree;
01504    already = 1;
01505 
01506    if ( *s1 == '_') {
01507       pattern = 1;
01508       s1++;
01509    }
01510    while( *s1 ) {
01511       if (pattern && *s1 == '[' && *(s1-1) != '\\') {
01512          char *s2 = buf;
01513          buf[0] = 0;
01514          s1++; /* get past the '[' */
01515          while (*s1 != ']' && *(s1-1) != '\\' ) {
01516             if (*s1 == '\\') {
01517                if (*(s1+1) == ']') {
01518                   *s2++ = ']';
01519                   s1++;s1++;
01520                } else if (*(s1+1) == '\\') {
01521                   *s2++ = '\\';
01522                   s1++;s1++;
01523                } else if (*(s1+1) == '-') {
01524                   *s2++ = '-';
01525                   s1++; s1++;
01526                } else if (*(s1+1) == '[') {
01527                   *s2++ = '[';
01528                   s1++; s1++;
01529                }
01530             } else if (*s1 == '-') { /* remember to add some error checking to all this! */
01531                char s3 = *(s1-1);
01532                char s4 = *(s1+1);
01533                for (s3++; s3 <= s4; s3++) {
01534                   *s2++ = s3;
01535                }
01536                s1++; s1++;
01537             } else if (*s1 == '\0') {
01538                ast_log(LOG_WARNING, "A matching ']' was not found for '[' in pattern string '%s'\n", extenbuf);
01539                break;
01540             } else {
01541                *s2++ = *s1++;
01542             }
01543          }
01544          *s2 = 0; /* null terminate the exploded range */
01545          /* sort the characters */
01546 
01547          specif = strlen(buf);
01548          qsort(buf, specif, 1, compare_char);
01549          specif <<= 8;
01550          specif += buf[0];
01551       } else {
01552          
01553          if (*s1 == '\\') {
01554             s1++;
01555             buf[0] = *s1;
01556          } else {
01557             if (pattern) {
01558                if (*s1 == 'n') /* make sure n,x,z patterns are canonicalized to N,X,Z */
01559                   *s1 = 'N';
01560                else if (*s1 == 'x')
01561                   *s1 = 'X';
01562                else if (*s1 == 'z')
01563                   *s1 = 'Z';
01564             }
01565             buf[0] = *s1;
01566          }
01567          buf[1] = 0;
01568          specif = 1;
01569       }
01570       m2 = 0;
01571       if (already && (m2=already_in_tree(m1,buf)) && m2->next_char) {
01572          if (!(*(s1+1))) {  /* if this is the end of the pattern, but not the end of the tree, then mark this node with the exten...
01573                         a shorter pattern might win if the longer one doesn't match */
01574             m2->exten = e1;
01575             m2->deleted = 0;
01576          }
01577          m1 = m2->next_char; /* m1 points to the node to compare against */
01578          m0 = &m2->next_char; /* m0 points to the ptr that points to m1 */
01579       } else { /* not already OR not m2 OR nor m2->next_char */
01580          if (m2) {
01581             if (findonly)
01582                return m2;
01583             m1 = m2; /* while m0 stays the same */
01584          } else {
01585             if (findonly)
01586                return m1;
01587             m1 = add_pattern_node(con, m1, buf, pattern, already,specif, m0); /* m1 is the node just added */
01588             m0 = &m1->next_char;
01589          }
01590          
01591          if (!(*(s1+1))) {
01592             m1->deleted = 0;
01593             m1->exten = e1;
01594          }
01595          
01596          already = 0;
01597       }
01598       s1++; /* advance to next char */
01599    }
01600    return m1;
01601 }
01602 
01603 static void create_match_char_tree(struct ast_context *con)
01604 {
01605    struct ast_hashtab_iter *t1;
01606    struct ast_exten *e1;
01607 #ifdef NEED_DEBUG
01608    int biggest_bucket, resizes, numobjs, numbucks;
01609    
01610    ast_log(LOG_DEBUG,"Creating Extension Trie for context %s\n", con->name);
01611    ast_hashtab_get_stats(con->root_table, &biggest_bucket, &resizes, &numobjs, &numbucks);
01612    ast_log(LOG_DEBUG,"This tree has %d objects in %d bucket lists, longest list=%d objects, and has resized %d times\n",
01613          numobjs, numbucks, biggest_bucket, resizes);
01614 #endif
01615    t1 = ast_hashtab_start_traversal(con->root_table);
01616    while( (e1 = ast_hashtab_next(t1)) ) {
01617       if (e1->exten)
01618          add_exten_to_pattern_tree(con, e1, 0);
01619       else
01620          ast_log(LOG_ERROR,"Attempt to create extension with no extension name.\n");
01621    }
01622    ast_hashtab_end_traversal(t1);
01623 }
01624 
01625 static void destroy_pattern_tree(struct match_char *pattern_tree) /* pattern tree is a simple binary tree, sort of, so the proper way to destroy it is... recursively! */
01626 {
01627    /* destroy all the alternates */
01628    if (pattern_tree->alt_char) {
01629       destroy_pattern_tree(pattern_tree->alt_char);
01630       pattern_tree->alt_char = 0;
01631    }
01632    /* destroy all the nexts */
01633    if (pattern_tree->next_char) {
01634       destroy_pattern_tree(pattern_tree->next_char);
01635       pattern_tree->next_char = 0;
01636    }
01637    pattern_tree->exten = 0; /* never hurts to make sure there's no pointers laying around */
01638    if (pattern_tree->x)
01639       free(pattern_tree->x);
01640    free(pattern_tree);
01641 }
01642 
01643 /*
01644  * Special characters used in patterns:
01645  * '_'   underscore is the leading character of a pattern.
01646  *    In other position it is treated as a regular char.
01647  * .  one or more of any character. Only allowed at the end of
01648  *    a pattern.
01649  * !  zero or more of anything. Also impacts the result of CANMATCH
01650  *    and MATCHMORE. Only allowed at the end of a pattern.
01651  *    In the core routine, ! causes a match with a return code of 2.
01652  *    In turn, depending on the search mode: (XXX check if it is implemented)
01653  *    - E_MATCH retuns 1 (does match)
01654  *    - E_MATCHMORE returns 0 (no match)
01655  *    - E_CANMATCH returns 1 (does match)
01656  *
01657  * /  should not appear as it is considered the separator of the CID info.
01658  *    XXX at the moment we may stop on this char.
01659  *
01660  * X Z N match ranges 0-9, 1-9, 2-9 respectively.
01661  * [  denotes the start of a set of character. Everything inside
01662  *    is considered literally. We can have ranges a-d and individual
01663  *    characters. A '[' and '-' can be considered literally if they
01664  *    are just before ']'.
01665  *    XXX currently there is no way to specify ']' in a range, nor \ is
01666  *    considered specially.
01667  *
01668  * When we compare a pattern with a specific extension, all characters in the extension
01669  * itself are considered literally.
01670  * XXX do we want to consider space as a separator as well ?
01671  * XXX do we want to consider the separators in non-patterns as well ?
01672  */
01673 
01674 /*!
01675  * \brief helper functions to sort extensions and patterns in the desired way,
01676  * so that more specific patterns appear first.
01677  *
01678  * ext_cmp1 compares individual characters (or sets of), returning
01679  * an int where bits 0-7 are the ASCII code of the first char in the set,
01680  * while bit 8-15 are the cardinality of the set minus 1.
01681  * This way more specific patterns (smaller cardinality) appear first.
01682  * Wildcards have a special value, so that we can directly compare them to
01683  * sets by subtracting the two values. In particular:
01684  *    0x000xx     one character, xx
01685  *    0x0yyxx     yy character set starting with xx
01686  *    0x10000     '.' (one or more of anything)
01687  *    0x20000     '!' (zero or more of anything)
01688  *    0x30000     NUL (end of string)
01689  *    0x40000     error in set.
01690  * The pointer to the string is advanced according to needs.
01691  * NOTES:
01692  * 1. the empty set is equivalent to NUL.
01693  * 2. given that a full set has always 0 as the first element,
01694  *    we could encode the special cases as 0xffXX where XX
01695  *    is 1, 2, 3, 4 as used above.
01696  */
01697 static int ext_cmp1(const char **p)
01698 {
01699    uint32_t chars[8];
01700    int c, cmin = 0xff, count = 0;
01701    const char *end;
01702 
01703    /* load, sign extend and advance pointer until we find
01704     * a valid character.
01705     */
01706    c = *(*p)++;
01707 
01708    /* always return unless we have a set of chars */
01709    switch (toupper(c)) {
01710    default: /* ordinary character */
01711       return 0x0000 | (c & 0xff);
01712 
01713    case 'N':   /* 2..9 */
01714       return 0x0800 | '2' ;
01715 
01716    case 'X':   /* 0..9 */
01717       return 0x0A00 | '0';
01718 
01719    case 'Z':   /* 1..9 */
01720       return 0x0900 | '1';
01721 
01722    case '.':   /* wildcard */
01723       return 0x10000;
01724 
01725    case '!':   /* earlymatch */
01726       return 0x20000;   /* less specific than NULL */
01727 
01728    case '\0':  /* empty string */
01729       *p = NULL;
01730       return 0x30000;
01731 
01732    case '[':   /* pattern */
01733       break;
01734    }
01735    /* locate end of set */
01736    end = strchr(*p, ']');  
01737 
01738    if (end == NULL) {
01739       ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
01740       return 0x40000;   /* XXX make this entry go last... */
01741    }
01742 
01743    memset(chars, '\0', sizeof(chars)); /* clear all chars in the set */
01744    for (; *p < end  ; (*p)++) {
01745       unsigned char c1, c2;   /* first-last char in range */
01746       c1 = (unsigned char)((*p)[0]);
01747       if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
01748          c2 = (unsigned char)((*p)[2]);
01749          *p += 2; /* skip a total of 3 chars */
01750       } else         /* individual character */
01751          c2 = c1;
01752       if (c1 < cmin)
01753          cmin = c1;
01754       for (; c1 <= c2; c1++) {
01755          uint32_t mask = 1 << (c1 % 32);
01756          if ( (chars[ c1 / 32 ] & mask) == 0)
01757             count += 0x100;
01758          chars[ c1 / 32 ] |= mask;
01759       }
01760    }
01761    (*p)++;
01762    return count == 0 ? 0x30000 : (count | cmin);
01763 }
01764 
01765 /*!
01766  * \brief the full routine to compare extensions in rules.
01767  */
01768 static int ext_cmp(const char *a, const char *b)
01769 {
01770    /* make sure non-patterns come first.
01771     * If a is not a pattern, it either comes first or
01772     * we use strcmp to compare the strings.
01773     */
01774    int ret = 0;
01775 
01776    if (a[0] != '_')
01777       return (b[0] == '_') ? -1 : strcmp(a, b);
01778 
01779    /* Now we know a is a pattern; if b is not, a comes first */
01780    if (b[0] != '_')
01781       return 1;
01782 #if 0 /* old mode for ext matching */
01783    return strcmp(a, b);
01784 #endif
01785    /* ok we need full pattern sorting routine */
01786    while (!ret && a && b)
01787       ret = ext_cmp1(&a) - ext_cmp1(&b);
01788    if (ret == 0)
01789       return 0;
01790    else
01791       return (ret > 0) ? 1 : -1;
01792 }
01793 
01794 int ast_extension_cmp(const char *a, const char *b)
01795 {
01796    return ext_cmp(a, b);
01797 }
01798 
01799 /*!
01800  * \internal
01801  * \brief used ast_extension_{match|close}
01802  * mode is as follows:
01803  * E_MATCH     success only on exact match
01804  * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
01805  * E_CANMATCH  either of the above.
01806  * \retval 0 on no-match
01807  * \retval 1 on match
01808  * \retval 2 on early match.
01809  */
01810 
01811 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
01812 {
01813    mode &= E_MATCH_MASK;   /* only consider the relevant bits */
01814    
01815 #ifdef NEED_DEBUG_HERE
01816    ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
01817 #endif
01818    
01819    if ( (mode == E_MATCH) && (pattern[0] == '_') && (!strcasecmp(pattern,data)) ) { /* note: if this test is left out, then _x. will not match _x. !!! */
01820 #ifdef NEED_DEBUG_HERE
01821       ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
01822 #endif
01823       return 1;
01824    }
01825 
01826    if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
01827       int ld = strlen(data), lp = strlen(pattern);
01828       
01829       if (lp < ld) {    /* pattern too short, cannot match */
01830 #ifdef NEED_DEBUG_HERE
01831          ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
01832 #endif
01833          return 0;
01834       }
01835       /* depending on the mode, accept full or partial match or both */
01836       if (mode == E_MATCH) {
01837 #ifdef NEED_DEBUG_HERE
01838          ast_log(LOG_NOTICE,"return (!strcmp(%s,%s) when mode== E_MATCH)\n", pattern, data);
01839 #endif
01840          return !strcmp(pattern, data); /* 1 on match, 0 on fail */
01841       } 
01842       if (ld == 0 || !strncasecmp(pattern, data, ld)) { /* partial or full match */
01843 #ifdef NEED_DEBUG_HERE
01844          ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
01845 #endif
01846          return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
01847       } else {
01848 #ifdef NEED_DEBUG_HERE
01849          ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
01850 #endif
01851          return 0;
01852       }
01853    }
01854    pattern++; /* skip leading _ */
01855    /*
01856     * XXX below we stop at '/' which is a separator for the CID info. However we should
01857     * not store '/' in the pattern at all. When we insure it, we can remove the checks.
01858     */
01859    while (*data && *pattern && *pattern != '/') {
01860       const char *end;
01861 
01862       if (*data == '-') { /* skip '-' in data (just a separator) */
01863          data++;
01864          continue;
01865       }
01866       switch (toupper(*pattern)) {
01867       case '[':   /* a range */
01868          end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
01869          if (end == NULL) {
01870             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
01871             return 0;   /* unconditional failure */
01872          }
01873          for (pattern++; pattern != end; pattern++) {
01874             if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
01875                if (*data >= pattern[0] && *data <= pattern[2])
01876                   break;   /* match found */
01877                else {
01878                   pattern += 2; /* skip a total of 3 chars */
01879                   continue;
01880                }
01881             } else if (*data == pattern[0])
01882                break;   /* match found */
01883          }
01884          if (pattern == end) {
01885 #ifdef NEED_DEBUG_HERE
01886             ast_log(LOG_NOTICE,"return (0) when pattern==end\n");
01887 #endif
01888             return 0;
01889          }
01890          pattern = end; /* skip and continue */
01891          break;
01892       case 'N':
01893          if (*data < '2' || *data > '9') {
01894 #ifdef NEED_DEBUG_HERE
01895             ast_log(LOG_NOTICE,"return (0) N is matched\n");
01896 #endif
01897             return 0;
01898          }
01899          break;
01900       case 'X':
01901          if (*data < '0' || *data > '9') {
01902 #ifdef NEED_DEBUG_HERE
01903             ast_log(LOG_NOTICE,"return (0) X is matched\n");
01904 #endif
01905             return 0;
01906          }
01907          break;
01908       case 'Z':
01909          if (*data < '1' || *data > '9') {
01910 #ifdef NEED_DEBUG_HERE
01911             ast_log(LOG_NOTICE,"return (0) Z is matched\n");
01912 #endif
01913             return 0;
01914          }
01915          break;
01916       case '.':   /* Must match, even with more digits */
01917 #ifdef NEED_DEBUG_HERE
01918          ast_log(LOG_NOTICE,"return (1) when '.' is matched\n");
01919 #endif
01920          return 1;
01921       case '!':   /* Early match */
01922 #ifdef NEED_DEBUG_HERE
01923          ast_log(LOG_NOTICE,"return (2) when '!' is matched\n");
01924 #endif
01925          return 2;
01926       case ' ':
01927       case '-':   /* Ignore these in patterns */
01928          data--; /* compensate the final data++ */
01929          break;
01930       default:
01931          if (*data != *pattern) {
01932 #ifdef NEED_DEBUG_HERE
01933             ast_log(LOG_NOTICE,"return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
01934 #endif
01935             return 0;
01936          }
01937          
01938       }
01939       data++;
01940       pattern++;
01941    }
01942    if (*data)        /* data longer than pattern, no match */ {
01943 #ifdef NEED_DEBUG_HERE
01944       ast_log(LOG_NOTICE,"return (0) when data longer than pattern\n");
01945 #endif
01946       return 0;
01947    }
01948    
01949    /*
01950     * match so far, but ran off the end of the data.
01951     * Depending on what is next, determine match or not.
01952     */
01953    if (*pattern == '\0' || *pattern == '/') {   /* exact match */
01954 #ifdef NEED_DEBUG_HERE
01955       ast_log(LOG_NOTICE,"at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
01956 #endif
01957       return (mode == E_MATCHMORE) ? 0 : 1;  /* this is a failure for E_MATCHMORE */
01958    } else if (*pattern == '!')   {     /* early match */
01959 #ifdef NEED_DEBUG_HERE
01960       ast_log(LOG_NOTICE,"at end, return (2) when '!' is matched\n");
01961 #endif
01962       return 2;
01963    } else {                /* partial match */
01964 #ifdef NEED_DEBUG_HERE
01965       ast_log(LOG_NOTICE,"at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
01966 #endif
01967       return (mode == E_MATCH) ? 0 : 1;   /* this is a failure for E_MATCH */
01968    }
01969 }
01970 
01971 /*
01972  * Wrapper around _extension_match_core() to do performance measurement
01973  * using the profiling code.
01974  */
01975 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
01976 {
01977    int i;
01978    static int prof_id = -2;   /* marker for 'unallocated' id */
01979    if (prof_id == -2)
01980       prof_id = ast_add_profile("ext_match", 0);
01981    ast_mark(prof_id, 1);
01982    i = _extension_match_core(pattern, data, mode);
01983    ast_mark(prof_id, 0);
01984    return i;
01985 }
01986 
01987 int ast_extension_match(const char *pattern, const char *data)
01988 {
01989    return extension_match_core(pattern, data, E_MATCH);
01990 }
01991 
01992 int ast_extension_close(const char *pattern, const char *data, int needmore)
01993 {
01994    if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
01995       ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
01996    return extension_match_core(pattern, data, needmore);
01997 }
01998 
01999 struct fake_context /* this struct is purely for matching in the hashtab */
02000 {
02001    ast_rwlock_t lock;         
02002    struct ast_exten *root;    
02003    struct ast_hashtab *root_table;            
02004    struct match_char *pattern_tree;       
02005    struct ast_context *next;  
02006    struct ast_include *includes;    
02007    struct ast_ignorepat *ignorepats;   
02008    const char *registrar;
02009    int refcount;
02010    AST_LIST_HEAD_NOLOCK(, ast_sw) alts;   
02011    ast_mutex_t macrolock;     
02012    char name[256];      
02013 };
02014 
02015 struct ast_context *ast_context_find(const char *name)
02016 {
02017    struct ast_context *tmp = NULL;
02018    struct fake_context item;
02019 
02020    ast_copy_string(item.name, name, sizeof(item.name));
02021 
02022    ast_rdlock_contexts();
02023    if( contexts_table ) {
02024       tmp = ast_hashtab_lookup(contexts_table,&item);
02025    } else {
02026       while ( (tmp = ast_walk_contexts(tmp)) ) {
02027          if (!name || !strcasecmp(name, tmp->name))
02028             break;
02029       }
02030    }
02031    ast_unlock_contexts();
02032    return tmp;
02033 }
02034 
02035 #define STATUS_NO_CONTEXT  1
02036 #define STATUS_NO_EXTENSION   2
02037 #define STATUS_NO_PRIORITY 3
02038 #define STATUS_NO_LABEL    4
02039 #define STATUS_SUCCESS     5
02040 
02041 static int matchcid(const char *cidpattern, const char *callerid)
02042 {
02043    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
02044       failing to get a number should count as a match, otherwise not */
02045 
02046    if (ast_strlen_zero(callerid))
02047       return ast_strlen_zero(cidpattern) ? 1 : 0;
02048 
02049    return ast_extension_match(cidpattern, callerid);
02050 }
02051 
02052 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
02053    struct ast_context *bypass, struct pbx_find_info *q,
02054    const char *context, const char *exten, int priority,
02055    const char *label, const char *callerid, enum ext_match_t action)
02056 {
02057    int x, res;
02058    struct ast_context *tmp = NULL;
02059    struct ast_exten *e = NULL, *eroot = NULL;
02060    struct ast_include *i = NULL;
02061    struct ast_sw *sw = NULL;
02062    struct ast_exten pattern = {NULL, };
02063    struct scoreboard score = {0, };
02064    struct ast_str *tmpdata = NULL;
02065 
02066    pattern.label = label;
02067    pattern.priority = priority;
02068 #ifdef NEED_DEBUG_HERE
02069    ast_log(LOG_NOTICE,"Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int)action);
02070 #endif
02071 
02072    /* Initialize status if appropriate */
02073    if (q->stacklen == 0) {
02074       q->status = STATUS_NO_CONTEXT;
02075       q->swo = NULL;
02076       q->data = NULL;
02077       q->foundcontext = NULL;
02078    } else if (q->stacklen >= AST_PBX_MAX_STACK) {
02079       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
02080       return NULL;
02081    }
02082 
02083    /* Check first to see if we've already been checked */
02084    for (x = 0; x < q->stacklen; x++) {
02085       if (!strcasecmp(q->incstack[x], context))
02086          return NULL;
02087    }
02088 
02089    if (bypass) /* bypass means we only look there */
02090       tmp = bypass;
02091    else {   /* look in contexts */
02092       struct fake_context item;
02093 
02094       ast_copy_string(item.name, context, sizeof(item.name));
02095 
02096       tmp = ast_hashtab_lookup(contexts_table, &item);
02097 #ifdef NOTNOW
02098       tmp = NULL;
02099       while ((tmp = ast_walk_contexts(tmp)) ) {
02100          if (!strcmp(tmp->name, context))
02101             break;
02102       }
02103 #endif
02104       if (!tmp)
02105          return NULL;
02106       
02107    }
02108 
02109    if (q->status < STATUS_NO_EXTENSION)
02110       q->status = STATUS_NO_EXTENSION;
02111    
02112    /* Do a search for matching extension */
02113 
02114    eroot = NULL;
02115    score.total_specificity = 0;
02116    score.exten = 0;
02117    score.total_length = 0;
02118    if (!tmp->pattern_tree && tmp->root_table)
02119    {
02120       create_match_char_tree(tmp);
02121 #ifdef NEED_DEBUG
02122       ast_log(LOG_DEBUG,"Tree Created in context %s:\n", context);
02123       log_match_char_tree(tmp->pattern_tree," ");
02124 #endif
02125    }
02126 #ifdef NEED_DEBUG
02127    ast_log(LOG_NOTICE,"The Trie we are searching in:\n");
02128    log_match_char_tree(tmp->pattern_tree, "::  ");
02129 #endif
02130 
02131    do {
02132       if (!ast_strlen_zero(overrideswitch)) {
02133          char *osw = ast_strdupa(overrideswitch), *name;
02134          struct ast_switch *asw;
02135          ast_switch_f *aswf = NULL;
02136          char *datap;
02137          int eval = 0;
02138 
02139          name = strsep(&osw, "/");
02140          asw = pbx_findswitch(name);
02141 
02142          if (!asw) {
02143             ast_log(LOG_WARNING, "No such switch '%s'\n", name);
02144             break;
02145          }
02146 
02147          if (osw && strchr(osw, '$')) {
02148             eval = 1;
02149          }
02150 
02151          if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
02152             ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!");
02153             break;
02154          } else if (eval) {
02155             /* Substitute variables now */
02156             pbx_substitute_variables_helper(chan, osw, tmpdata->str, tmpdata->len);
02157             datap = tmpdata->str;
02158          } else {
02159             datap = osw;
02160          }
02161 
02162          /* equivalent of extension_match_core() at the switch level */
02163          if (action == E_CANMATCH)
02164             aswf = asw->canmatch;
02165          else if (action == E_MATCHMORE)
02166             aswf = asw->matchmore;
02167          else /* action == E_MATCH */
02168             aswf = asw->exists;
02169          if (!aswf) {
02170             res = 0;
02171          } else {
02172             if (chan) {
02173                ast_autoservice_start(chan);
02174             }
02175             res = aswf(chan, context, exten, priority, callerid, datap);
02176             if (chan) {
02177                ast_autoservice_stop(chan);
02178             }
02179          }
02180          if (res) {  /* Got a match */
02181             q->swo = asw;
02182             q->data = datap;
02183             q->foundcontext = context;
02184             /* XXX keep status = STATUS_NO_CONTEXT ? */
02185             return NULL;
02186          }
02187       }
02188    } while (0);
02189 
02190    if (extenpatternmatchnew) {
02191       new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
02192       eroot = score.exten;
02193       
02194       if (score.last_char == '!' && action == E_MATCHMORE) {
02195          /* We match an extension ending in '!'.
02196           * The decision in this case is final and is NULL (no match).
02197           */
02198 #ifdef NEED_DEBUG_HERE
02199          ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
02200 #endif
02201          return NULL;
02202       }
02203       
02204       if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
02205          q->status = STATUS_SUCCESS;
02206 #ifdef NEED_DEBUG_HERE
02207          ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
02208 #endif
02209          return score.canmatch_exten;
02210       }
02211       
02212       if ((action == E_MATCHMORE || action == E_CANMATCH)  && eroot) {
02213          if (score.node) {
02214             struct ast_exten *z = trie_find_next_match(score.node);
02215             if (z) {
02216 #ifdef NEED_DEBUG_HERE
02217                ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
02218 #endif
02219             } else {
02220                if (score.canmatch_exten) {
02221 #ifdef NEED_DEBUG_HERE
02222                   ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
02223 #endif
02224                   return score.canmatch_exten;
02225                } else {
02226 #ifdef NEED_DEBUG_HERE
02227                   ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
02228 #endif
02229                }
02230             }
02231             return z;
02232          }
02233 #ifdef NEED_DEBUG_HERE
02234          ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
02235 #endif
02236          return NULL;  /* according to the code, complete matches are null matches in MATCHMORE mode */
02237       }
02238       
02239       if (eroot) {
02240          /* found entry, now look for the right priority */
02241          if (q->status < STATUS_NO_PRIORITY)
02242             q->status = STATUS_NO_PRIORITY;
02243          e = NULL;
02244          if (action == E_FINDLABEL && label ) {
02245             if (q->status < STATUS_NO_LABEL)
02246                q->status = STATUS_NO_LABEL;
02247             e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
02248          } else {
02249             e = ast_hashtab_lookup(eroot->peer_table, &pattern);
02250          }
02251          if (e) { /* found a valid match */
02252             q->status = STATUS_SUCCESS;
02253             q->foundcontext = context;
02254 #ifdef NEED_DEBUG_HERE
02255             ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
02256 #endif
02257             return e;
02258          }
02259       }
02260    } else {   /* the old/current default exten pattern match algorithm */
02261       
02262       /* scan the list trying to match extension and CID */
02263       eroot = NULL;
02264       while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
02265          int match = extension_match_core(eroot->exten, exten, action);
02266          /* 0 on fail, 1 on match, 2 on earlymatch */
02267          
02268          if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
02269             continue;   /* keep trying */
02270          if (match == 2 && action == E_MATCHMORE) {
02271             /* We match an extension ending in '!'.
02272              * The decision in this case is final and is NULL (no match).
02273              */
02274             return NULL;
02275          }
02276          /* found entry, now look for the right priority */
02277          if (q->status < STATUS_NO_PRIORITY)
02278             q->status = STATUS_NO_PRIORITY;
02279          e = NULL;
02280          if (action == E_FINDLABEL && label ) {
02281             if (q->status < STATUS_NO_LABEL)
02282                q->status = STATUS_NO_LABEL;
02283             e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
02284          } else {
02285             e = ast_hashtab_lookup(eroot->peer_table, &pattern);
02286          }
02287 #ifdef NOTNOW
02288          while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
02289             /* Match label or priority */
02290             if (action == E_FINDLABEL) {
02291                if (q->status < STATUS_NO_LABEL)
02292                   q->status = STATUS_NO_LABEL;
02293                if (label && e->label && !strcmp(label, e->label))
02294                   break;   /* found it */
02295             } else if (e->priority == priority) {
02296                break;   /* found it */
02297             } /* else keep searching */
02298          }
02299 #endif
02300          if (e) { /* found a valid match */
02301             q->status = STATUS_SUCCESS;
02302             q->foundcontext = context;
02303             return e;
02304          }
02305       }
02306    }
02307    
02308    
02309    /* Check alternative switches */
02310    AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
02311       struct ast_switch *asw = pbx_findswitch(sw->name);
02312       ast_switch_f *aswf = NULL;
02313       char *datap;
02314 
02315       if (!asw) {
02316          ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
02317          continue;
02318       }
02319       /* Substitute variables now */
02320       
02321       if (sw->eval) {
02322          if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
02323             ast_log(LOG_WARNING, "Can't evaluate switch?!");
02324             continue;
02325          }
02326          pbx_substitute_variables_helper(chan, sw->data, tmpdata->str, tmpdata->len);
02327       }
02328 
02329       /* equivalent of extension_match_core() at the switch level */
02330       if (action == E_CANMATCH)
02331          aswf = asw->canmatch;
02332       else if (action == E_MATCHMORE)
02333          aswf = asw->matchmore;
02334       else /* action == E_MATCH */
02335          aswf = asw->exists;
02336       datap = sw->eval ? tmpdata->str : sw->data;
02337       if (!aswf)
02338          res = 0;
02339       else {
02340          if (chan)
02341             ast_autoservice_start(chan);
02342          res = aswf(chan, context, exten, priority, callerid, datap);
02343          if (chan)
02344             ast_autoservice_stop(chan);
02345       }
02346       if (res) {  /* Got a match */
02347          q->swo = asw;
02348          q->data = datap;
02349          q->foundcontext = context;
02350          /* XXX keep status = STATUS_NO_CONTEXT ? */
02351          return NULL;
02352       }
02353    }
02354    q->incstack[q->stacklen++] = tmp->name;   /* Setup the stack */
02355    /* Now try any includes we have in this context */
02356    for (i = tmp->includes; i; i = i->next) {
02357       if (include_valid(i)) {
02358          if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
02359 #ifdef NEED_DEBUG_HERE
02360             ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
02361 #endif
02362             return e;
02363          }
02364          if (q->swo)
02365             return NULL;
02366       }
02367    }
02368    return NULL;
02369 }
02370 
02371 /*! 
02372  * \brief extract offset:length from variable name.
02373  * \return 1 if there is a offset:length part, which is
02374  * trimmed off (values go into variables)
02375  */
02376 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
02377 {
02378    int parens = 0;
02379 
02380    *offset = 0;
02381    *length = INT_MAX;
02382    *isfunc = 0;
02383    for (; *var; var++) {
02384       if (*var == '(') {
02385          (*isfunc)++;
02386          parens++;
02387       } else if (*var == ')') {
02388          parens--;
02389       } else if (*var == ':' && parens == 0) {
02390          *var++ = '\0';
02391          sscanf(var, "%30d:%30d", offset, length);
02392          return 1; /* offset:length valid */
02393       }
02394    }
02395    return 0;
02396 }
02397 
02398 /*! 
02399  *\brief takes a substring. It is ok to call with value == workspace.
02400  * \param value
02401  * \param offset < 0 means start from the end of the string and set the beginning
02402  *   to be that many characters back.
02403  * \param length is the length of the substring, a value less than 0 means to leave
02404  * that many off the end.
02405  * \param workspace
02406  * \param workspace_len
02407  * Always return a copy in workspace.
02408  */
02409 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
02410 {
02411    char *ret = workspace;
02412    int lr;  /* length of the input string after the copy */
02413 
02414    ast_copy_string(workspace, value, workspace_len); /* always make a copy */
02415 
02416    lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
02417 
02418    /* Quick check if no need to do anything */
02419    if (offset == 0 && length >= lr) /* take the whole string */
02420       return ret;
02421 
02422    if (offset < 0)   {  /* translate negative offset into positive ones */
02423       offset = lr + offset;
02424       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
02425          offset = 0;
02426    }
02427 
02428    /* too large offset result in empty string so we know what to return */
02429    if (offset >= lr)
02430       return ret + lr;  /* the final '\0' */
02431 
02432    ret += offset;    /* move to the start position */
02433    if (length >= 0 && length < lr - offset)  /* truncate if necessary */
02434       ret[length] = '\0';
02435    else if (length < 0) {
02436       if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
02437          ret[lr + length - offset] = '\0';
02438       else
02439          ret[0] = '\0';
02440    }
02441 
02442    return ret;
02443 }
02444 
02445 /*! \brief  Support for Asterisk built-in variables in the dialplan
02446 
02447 \note See also
02448    - \ref AstVar  Channel variables
02449    - \ref AstCauses The HANGUPCAUSE variable
02450  */
02451 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
02452 {
02453    const char not_found = '\0';
02454    char *tmpvar;
02455    const char *s; /* the result */
02456    int offset, length;
02457    int i, need_substring;
02458    struct varshead *places[2] = { headp, &globals };  /* list of places where we may look */
02459 
02460    if (c) {
02461       ast_channel_lock(c);
02462       places[0] = &c->varshead;
02463    }
02464    /*
02465     * Make a copy of var because parse_variable_name() modifies the string.
02466     * Then if called directly, we might need to run substring() on the result;
02467     * remember this for later in 'need_substring', 'offset' and 'length'
02468     */
02469    tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
02470    need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
02471 
02472    /*
02473     * Look first into predefined variables, then into variable lists.
02474     * Variable 's' points to the result, according to the following rules:
02475     * s == &not_found (set at the beginning) means that we did not find a
02476     * matching variable and need to look into more places.
02477     * If s != &not_found, s is a valid result string as follows:
02478     * s = NULL if the variable does not have a value;
02479     * you typically do this when looking for an unset predefined variable.
02480     * s = workspace if the result has been assembled there;
02481     * typically done when the result is built e.g. with an snprintf(),
02482     * so we don't need to do an additional copy.
02483     * s != workspace in case we have a string, that needs to be copied
02484     * (the ast_copy_string is done once for all at the end).
02485     * Typically done when the result is already available in some string.
02486     */
02487    s = &not_found;   /* default value */
02488    if (c) { /* This group requires a valid channel */
02489       /* Names with common parts are looked up a piece at a time using strncmp. */
02490       if (!strncmp(var, "CALL", 4)) {
02491          if (!strncmp(var + 4, "ING", 3)) {
02492             if (!strcmp(var + 7, "PRES")) {        /* CALLINGPRES */
02493                snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
02494                s = workspace;
02495             } else if (!strcmp(var + 7, "ANI2")) {    /* CALLINGANI2 */
02496                snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
02497                s = workspace;
02498             } else if (!strcmp(var + 7, "TON")) {     /* CALLINGTON */
02499                snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
02500                s = workspace;
02501             } else if (!strcmp(var + 7, "TNS")) {     /* CALLINGTNS */
02502                snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
02503                s = workspace;
02504             }
02505          }
02506       } else if (!strcmp(var, "HINT")) {
02507          s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
02508       } else if (!strcmp(var, "HINTNAME")) {
02509          s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
02510       } else if (!strcmp(var, "EXTEN")) {
02511          s = c->exten;
02512       } else if (!strcmp(var, "CONTEXT")) {
02513          s = c->context;
02514       } else if (!strcmp(var, "PRIORITY")) {
02515          snprintf(workspace, workspacelen, "%d", c->priority);
02516          s = workspace;
02517       } else if (!strcmp(var, "CHANNEL")) {
02518          s = c->name;
02519       } else if (!strcmp(var, "UNIQUEID")) {
02520          s = c->uniqueid;
02521       } else if (!strcmp(var, "HANGUPCAUSE")) {
02522          snprintf(workspace, workspacelen, "%d", c->hangupcause);
02523          s = workspace;
02524       }
02525    }
02526    if (s == &not_found) { /* look for more */
02527       if (!strcmp(var, "EPOCH")) {
02528          snprintf(workspace, workspacelen, "%u",(int)time(NULL));
02529          s = workspace;
02530       } else if (!strcmp(var, "SYSTEMNAME")) {
02531          s = ast_config_AST_SYSTEM_NAME;
02532       } else if (!strcmp(var, "ENTITYID")) {
02533          ast_eid_to_str(workspace, workspacelen, &ast_eid_default);
02534          s = workspace;
02535       }
02536    }
02537    /* if not found, look into chanvars or global vars */
02538    for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
02539       struct ast_var_t *variables;
02540       if (!places[i])
02541          continue;
02542       if (places[i] == &globals)
02543          ast_rwlock_rdlock(&globalslock);
02544       AST_LIST_TRAVERSE(places[i], variables, entries) {
02545          if (!strcasecmp(ast_var_name(variables), var)) {
02546             s = ast_var_value(variables);
02547             break;
02548          }
02549       }
02550       if (places[i] == &globals)
02551          ast_rwlock_unlock(&globalslock);
02552    }
02553    if (s == &not_found || s == NULL)
02554       *ret = NULL;
02555    else {
02556       if (s != workspace)
02557          ast_copy_string(workspace, s, workspacelen);
02558       *ret = workspace;
02559       if (need_substring)
02560          *ret = substring(*ret, offset, length, workspace, workspacelen);
02561    }
02562 
02563    if (c)
02564       ast_channel_unlock(c);
02565 }
02566 
02567 static void exception_store_free(void *data)
02568 {
02569    struct pbx_exception *exception = data;
02570    ast_string_field_free_memory(exception);
02571    ast_free(exception);
02572 }
02573 
02574 static struct ast_datastore_info exception_store_info = {
02575    .type = "EXCEPTION",
02576    .destroy = exception_store_free,
02577 };
02578 
02579 int pbx_builtin_raise_exception(struct ast_channel *chan, void *vreason)
02580 {
02581    const char *reason = vreason;
02582    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
02583    struct pbx_exception *exception = NULL;
02584 
02585    if (!ds) {
02586       ds = ast_datastore_alloc(&exception_store_info, NULL);
02587       if (!ds)
02588          return -1;
02589       exception = ast_calloc(1, sizeof(struct pbx_exception));
02590       if (!exception) {
02591          ast_datastore_free(ds);
02592          return -1;
02593       }
02594       if (ast_string_field_init(exception, 128)) {
02595          ast_free(exception);
02596          ast_datastore_free(ds);
02597          return -1;
02598       }
02599       ds->data = exception;
02600       ast_channel_datastore_add(chan, ds);
02601    } else
02602       exception = ds->data;
02603 
02604    ast_string_field_set(exception, reason, reason);
02605    ast_string_field_set(exception, context, chan->context);
02606    ast_string_field_set(exception, exten, chan->exten);
02607    exception->priority = chan->priority;
02608    set_ext_pri(chan, "e", 0);
02609    return 0;
02610 }
02611 
02612 static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
02613 {
02614    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
02615    struct pbx_exception *exception = NULL;
02616    if (!ds || !ds->data)
02617       return -1;
02618    exception = ds->data;
02619    if (!strcasecmp(data, "REASON"))
02620       ast_copy_string(buf, exception->reason, buflen);
02621    else if (!strcasecmp(data, "CONTEXT"))
02622       ast_copy_string(buf, exception->context, buflen);
02623    else if (!strncasecmp(data, "EXTEN", 5))
02624       ast_copy_string(buf, exception->exten, buflen);
02625    else if (!strcasecmp(data, "PRIORITY"))
02626       snprintf(buf, buflen, "%d", exception->priority);
02627    else
02628       return -1;
02629    return 0;
02630 }
02631 
02632 static struct ast_custom_function exception_function = {
02633    .name = "EXCEPTION",
02634    .synopsis = "Retrieve the details of the current dialplan exception",
02635    .desc =
02636 "The following fields are available for retrieval:\n"
02637 "  reason    INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom\n"
02638 "               value set by the RaiseException() application\n"
02639 "  context   The context executing when the exception occurred\n"
02640 "  exten     The extension executing when the exception occurred\n"
02641 "  priority  The numeric priority executing when the exception occurred\n",
02642    .syntax = "EXCEPTION(<field>)",
02643    .read = acf_exception_read,
02644 };
02645 
02646 static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02647 {
02648    struct ast_custom_function *acf;
02649    int count_acf = 0;
02650    int like = 0;
02651 
02652    switch (cmd) {
02653    case CLI_INIT:
02654       e->command = "core show functions [like]";
02655       e->usage = 
02656          "Usage: core show functions [like <text>]\n"
02657          "       List builtin functions, optionally only those matching a given string\n";
02658       return NULL;
02659    case CLI_GENERATE:
02660       return NULL;
02661    }
02662 
02663    if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
02664       like = 1;
02665    } else if (a->argc != 3) {
02666       return CLI_SHOWUSAGE;
02667    }
02668 
02669    ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
02670 
02671    AST_RWLIST_RDLOCK(&acf_root);
02672    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02673       if (!like || strstr(acf->name, a->argv[4])) {
02674          count_acf++;
02675          ast_cli(a->fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
02676       }
02677    }
02678    AST_RWLIST_UNLOCK(&acf_root);
02679 
02680    ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
02681 
02682    return CLI_SUCCESS;
02683 }
02684 
02685 static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02686 {
02687    struct ast_custom_function *acf;
02688    /* Maximum number of characters added by terminal coloring is 22 */
02689    char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
02690    char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
02691    char stxtitle[40], *syntax = NULL;
02692    int synopsis_size, description_size, syntax_size;
02693    char *ret = NULL;
02694    int which = 0;
02695    int wordlen;
02696 
02697    switch (cmd) {
02698    case CLI_INIT:
02699       e->command = "core show function";
02700       e->usage = 
02701          "Usage: core show function <function>\n"
02702          "       Describe a particular dialplan function.\n";
02703       return NULL;
02704    case CLI_GENERATE:   
02705       wordlen = strlen(a->word);
02706       /* case-insensitive for convenience in this 'complete' function */
02707       AST_RWLIST_RDLOCK(&acf_root);
02708       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02709          if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
02710             ret = ast_strdup(acf->name);
02711             break;
02712          }
02713       }
02714       AST_RWLIST_UNLOCK(&acf_root);
02715 
02716       return ret;
02717    }
02718 
02719    if (a->argc < 4)
02720       return CLI_SHOWUSAGE;
02721 
02722    if (!(acf = ast_custom_function_find(a->argv[3]))) {
02723       ast_cli(a->fd, "No function by that name registered.\n");
02724       return CLI_FAILURE;
02725 
02726    }
02727 
02728    if (acf->synopsis)
02729       synopsis_size = strlen(acf->synopsis) + 23;
02730    else
02731       synopsis_size = strlen("Not available") + 23;
02732    synopsis = alloca(synopsis_size);
02733 
02734    if (acf->desc)
02735       description_size = strlen(acf->desc) + 23;
02736    else
02737       description_size = strlen("Not available") + 23;
02738    description = alloca(description_size);
02739 
02740    if (acf->syntax)
02741       syntax_size = strlen(acf->syntax) + 23;
02742    else
02743       syntax_size = strlen("Not available") + 23;
02744    syntax = alloca(syntax_size);
02745 
02746    snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
02747    term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
02748    term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
02749    term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
02750    term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
02751    term_color(syntax,
02752          acf->syntax ? acf->syntax : "Not available",
02753          COLOR_CYAN, 0, syntax_size);
02754    term_color(synopsis,
02755          acf->synopsis ? acf->synopsis : "Not available",
02756          COLOR_CYAN, 0, synopsis_size);
02757    term_color(description,
02758          acf->desc ? acf->desc : "Not available",
02759          COLOR_CYAN, 0, description_size);
02760 
02761    ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
02762 
02763    return CLI_SUCCESS;
02764 }
02765 
02766 struct ast_custom_function *ast_custom_function_find(const char *name)
02767 {
02768    struct ast_custom_function *acf = NULL;
02769 
02770    AST_RWLIST_RDLOCK(&acf_root);
02771    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02772       if (!strcmp(name, acf->name))
02773          break;
02774    }
02775    AST_RWLIST_UNLOCK(&acf_root);
02776 
02777    return acf;
02778 }
02779 
02780 int ast_custom_function_unregister(struct ast_custom_function *acf)
02781 {
02782    struct ast_custom_function *cur;
02783 
02784    if (!acf)
02785       return -1;
02786 
02787    AST_RWLIST_WRLOCK(&acf_root);
02788    if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist)))
02789       ast_verb(2, "Unregistered custom function %s\n", cur->name);
02790    AST_RWLIST_UNLOCK(&acf_root);
02791 
02792    return cur ? 0 : -1;
02793 }
02794 
02795 int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
02796 {
02797    struct ast_custom_function *cur;
02798    char tmps[80];
02799 
02800    if (!acf)
02801       return -1;
02802 
02803    acf->mod = mod;
02804 
02805    AST_RWLIST_WRLOCK(&acf_root);
02806 
02807    AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
02808       if (!strcmp(acf->name, cur->name)) {
02809          ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
02810          AST_RWLIST_UNLOCK(&acf_root);
02811          return -1;
02812       }
02813    }
02814 
02815    /* Store in alphabetical order */
02816    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
02817       if (strcasecmp(acf->name, cur->name) < 0) {
02818          AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
02819          break;
02820       }
02821    }
02822    AST_RWLIST_TRAVERSE_SAFE_END;
02823    if (!cur)
02824       AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
02825 
02826    AST_RWLIST_UNLOCK(&acf_root);
02827 
02828    ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02829 
02830    return 0;
02831 }
02832 
02833 /*! \brief return a pointer to the arguments of the function,
02834  * and terminates the function name with '\\0'
02835  */
02836 static char *func_args(char *function)
02837 {
02838    char *args = strchr(function, '(');
02839 
02840    if (!args)
02841       ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses.  Assuming null argument.\n", function);
02842    else {
02843       char *p;
02844       *args++ = '\0';
02845       if ((p = strrchr(args, ')')) )
02846          *p = '\0';
02847       else
02848          ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
02849    }
02850    return args;
02851 }
02852 
02853 int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
02854 {
02855    char *copy = ast_strdupa(function);
02856    char *args = func_args(copy);
02857    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02858 
02859    if (acfptr == NULL)
02860       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02861    else if (!acfptr->read)
02862       ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
02863    else {
02864       int res;
02865       struct ast_module_user *u = NULL;
02866       if (acfptr->mod)
02867          u = __ast_module_user_add(acfptr->mod, chan);
02868       res = acfptr->read(chan, copy, args, workspace, len);
02869       if (acfptr->mod && u)
02870          __ast_module_user_remove(acfptr->mod, u);
02871       return res;
02872    }
02873    return -1;
02874 }
02875 
02876 int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
02877 {
02878    char *copy = ast_strdupa(function);
02879    char *args = func_args(copy);
02880    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02881 
02882    if (acfptr == NULL)
02883       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02884    else if (!acfptr->write)
02885       ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
02886    else {
02887       int res;
02888       struct ast_module_user *u = NULL;
02889       if (acfptr->mod)
02890          u = __ast_module_user_add(acfptr->mod, chan);
02891       res = acfptr->write(chan, copy, args, value);
02892       if (acfptr->mod && u)
02893          __ast_module_user_remove(acfptr->mod, u);
02894       return res;
02895    }
02896 
02897    return -1;
02898 }
02899 
02900 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
02901 {
02902    /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
02903    char *cp4;
02904    const char *tmp, *whereweare;
02905    int length, offset, offset2, isfunction;
02906    char *workspace = NULL;
02907    char *ltmp = NULL, *var = NULL;
02908    char *nextvar, *nextexp, *nextthing;
02909    char *vars, *vare;
02910    int pos, brackets, needsub, len;
02911    
02912    *cp2 = 0; /* just in case nothing ends up there */
02913    whereweare=tmp=cp1;
02914    while (!ast_strlen_zero(whereweare) && count) {
02915       /* Assume we're copying the whole remaining string */
02916       pos = strlen(whereweare);
02917       nextvar = NULL;
02918       nextexp = NULL;
02919       nextthing = strchr(whereweare, '$');
02920       if (nextthing) {
02921          switch (nextthing[1]) {
02922          case '{':
02923             nextvar = nextthing;
02924             pos = nextvar - whereweare;
02925             break;
02926          case '[':
02927             nextexp = nextthing;
02928             pos = nextexp - whereweare;
02929             break;
02930          default:
02931             pos = 1;
02932          }
02933       }
02934 
02935       if (pos) {
02936          /* Can't copy more than 'count' bytes */
02937          if (pos > count)
02938             pos = count;
02939 
02940          /* Copy that many bytes */
02941          memcpy(cp2, whereweare, pos);
02942 
02943          count -= pos;
02944          cp2 += pos;
02945          whereweare += pos;
02946          *cp2 = 0;
02947       }
02948 
02949       if (nextvar) {
02950          /* We have a variable.  Find the start and end, and determine
02951             if we are going to have to recursively call ourselves on the
02952             contents */
02953          vars = vare = nextvar + 2;
02954          brackets = 1;
02955          needsub = 0;
02956 
02957          /* Find the end of it */
02958          while (brackets && *vare) {
02959             if ((vare[0] == '$') && (vare[1] == '{')) {
02960                needsub++;
02961             } else if (vare[0] == '{') {
02962                brackets++;
02963             } else if (vare[0] == '}') {
02964                brackets--;
02965             } else if ((vare[0] == '$') && (vare[1] == '['))
02966                needsub++;
02967             vare++;
02968          }
02969          if (brackets)
02970             ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
02971          len = vare - vars - 1;
02972 
02973          /* Skip totally over variable string */
02974          whereweare += (len + 3);
02975 
02976          if (!var)
02977             var = alloca(VAR_BUF_SIZE);
02978 
02979          /* Store variable name (and truncate) */
02980          ast_copy_string(var, vars, len + 1);
02981 
02982          /* Substitute if necessary */
02983          if (needsub) {
02984             if (!ltmp)
02985                ltmp = alloca(VAR_BUF_SIZE);
02986 
02987             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
02988             vars = ltmp;
02989          } else {
02990             vars = var;
02991          }
02992 
02993          if (!workspace)
02994             workspace = alloca(VAR_BUF_SIZE);
02995 
02996          workspace[0] = '\0';
02997 
02998          parse_variable_name(vars, &offset, &offset2, &isfunction);
02999          if (isfunction) {
03000             /* Evaluate function */
03001             if (c || !headp)
03002                cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
03003             else {
03004                struct varshead old;
03005                struct ast_channel *bogus = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars);
03006                if (bogus) {
03007                   memcpy(&old, &bogus->varshead, sizeof(old));
03008                   memcpy(&bogus->varshead, headp, sizeof(bogus->varshead));
03009                   cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
03010                   /* Don't deallocate the varshead that was passed in */
03011                   memcpy(&bogus->varshead, &old, sizeof(bogus->varshead));
03012                   ast_channel_free(bogus);
03013                } else
03014                   ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
03015             }
03016             ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
03017          } else {
03018             /* Retrieve variable value */
03019             pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
03020          }
03021          if (cp4) {
03022             cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
03023 
03024             length = strlen(cp4);
03025             if (length > count)
03026                length = count;
03027             memcpy(cp2, cp4, length);
03028             count -= length;
03029             cp2 += length;
03030             *cp2 = 0;
03031          }
03032       } else if (nextexp) {
03033          /* We have an expression.  Find the start and end, and determine
03034             if we are going to have to recursively call ourselves on the
03035             contents */
03036          vars = vare = nextexp + 2;
03037          brackets = 1;
03038          needsub = 0;
03039 
03040          /* Find the end of it */
03041          while (brackets && *vare) {
03042             if ((vare[0] == '$') && (vare[1] == '[')) {
03043                needsub++;
03044                brackets++;
03045                vare++;
03046             } else if (vare[0] == '[') {
03047                brackets++;
03048             } else if (vare[0] == ']') {
03049                brackets--;
03050             } else if ((vare[0] == '$') && (vare[1] == '{')) {
03051                needsub++;
03052                vare++;
03053             }
03054             vare++;
03055          }
03056          if (brackets)
03057             ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
03058          len = vare - vars - 1;
03059 
03060          /* Skip totally over expression */
03061          whereweare += (len + 3);
03062 
03063          if (!var)
03064             var = alloca(VAR_BUF_SIZE);
03065 
03066          /* Store variable name (and truncate) */
03067          ast_copy_string(var, vars, len + 1);
03068 
03069          /* Substitute if necessary */
03070          if (needsub) {
03071             if (!ltmp)
03072                ltmp = alloca(VAR_BUF_SIZE);
03073 
03074             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
03075             vars = ltmp;
03076          } else {
03077             vars = var;
03078          }
03079 
03080          length = ast_expr(vars, cp2, count, c);
03081 
03082          if (length) {
03083             ast_debug(1, "Expression result is '%s'\n", cp2);
03084             count -= length;
03085             cp2 += length;
03086             *cp2 = 0;
03087          }
03088       }
03089    }
03090 }
03091 
03092 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
03093 {
03094    pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
03095 }
03096 
03097 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
03098 {
03099    pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
03100 }
03101 
03102 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
03103 {
03104    const char *tmp;
03105 
03106    /* Nothing more to do */
03107    if (!e->data)
03108       return;
03109 
03110    /* No variables or expressions in e->data, so why scan it? */
03111    if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
03112       ast_copy_string(passdata, e->data, datalen);
03113       return;
03114    }
03115 
03116    pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
03117 }
03118 
03119 /*! 
03120  * \brief The return value depends on the action:
03121  *
03122  * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
03123  * and return 0 on failure, -1 on match;
03124  * E_FINDLABEL maps the label to a priority, and returns
03125  * the priority on success, ... XXX
03126  * E_SPAWN, spawn an application,
03127  * 
03128  * \retval 0 on success.
03129  * \retval  -1 on failure.
03130  *
03131  * \note The channel is auto-serviced in this function, because doing an extension
03132  * match may block for a long time.  For example, if the lookup has to use a network
03133  * dialplan switch, such as DUNDi or IAX2, it may take a while.  However, the channel
03134  * auto-service code will queue up any important signalling frames to be processed
03135  * after this is done.
03136  */
03137 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
03138   const char *context, const char *exten, int priority,
03139   const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
03140 {
03141    struct ast_exten *e;
03142    struct ast_app *app;
03143    int res;
03144    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
03145    char passdata[EXT_DATA_SIZE];
03146 
03147    int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
03148 
03149    ast_rdlock_contexts();
03150    if (found)
03151       *found = 0;
03152 
03153    e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
03154    if (e) {
03155       if (found)
03156          *found = 1;
03157       if (matching_action) {
03158          ast_unlock_contexts();
03159          return -1;  /* success, we found it */
03160       } else if (action == E_FINDLABEL) { /* map the label to a priority */
03161          res = e->priority;
03162          ast_unlock_contexts();
03163          return res; /* the priority we were looking for */
03164       } else { /* spawn */
03165          if (!e->cached_app)
03166             e->cached_app = pbx_findapp(e->app);
03167          app = e->cached_app;
03168          ast_unlock_contexts();
03169          if (!app) {
03170             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
03171             return -1;
03172          }
03173          if (c->context != context)
03174             ast_copy_string(c->context, context, sizeof(c->context));
03175          if (c->exten != exten)
03176             ast_copy_string(c->exten, exten, sizeof(c->exten));
03177          c->priority = priority;
03178          pbx_substitute_variables(passdata, sizeof(passdata), c, e);
03179 #ifdef CHANNEL_TRACE
03180          ast_channel_trace_update(c);
03181 #endif
03182          ast_debug(1, "Launching '%s'\n", app->name);
03183          if (VERBOSITY_ATLEAST(3)) {
03184             char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
03185             ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
03186                exten, context, priority,
03187                term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
03188                term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
03189                term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
03190                "in new stack");
03191          }
03192          manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
03193                "Channel: %s\r\n"
03194                "Context: %s\r\n"
03195                "Extension: %s\r\n"
03196                "Priority: %d\r\n"
03197                "Application: %s\r\n"
03198                "AppData: %s\r\n"
03199                "Uniqueid: %s\r\n",
03200                c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
03201          return pbx_exec(c, app, passdata);  /* 0 on success, -1 on failure */
03202       }
03203    } else if (q.swo) {  /* not found here, but in another switch */
03204       if (found)
03205          *found = 1;
03206       ast_unlock_contexts();
03207       if (matching_action) {
03208          return -1;
03209       } else {
03210          if (!q.swo->exec) {
03211             ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
03212             res = -1;
03213          }
03214          return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
03215       }
03216    } else { /* not found anywhere, see what happened */
03217       ast_unlock_contexts();
03218       switch (q.status) {
03219       case STATUS_NO_CONTEXT:
03220          if (!matching_action && !combined_find_spawn)
03221             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
03222          break;
03223       case STATUS_NO_EXTENSION:
03224          if (!matching_action && !combined_find_spawn)
03225             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
03226          break;
03227       case STATUS_NO_PRIORITY:
03228          if (!matching_action && !combined_find_spawn)
03229             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
03230          break;
03231       case STATUS_NO_LABEL:
03232          if (context && !combined_find_spawn)
03233             ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
03234          break;
03235       default:
03236          ast_debug(1, "Shouldn't happen!\n");
03237       }
03238 
03239       return (matching_action) ? 0 : -1;
03240    }
03241 }
03242 
03243 /*! \brief Find hint for given extension in context */
03244 static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
03245 {
03246    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
03247    return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
03248 }
03249 
03250 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
03251 {
03252    struct ast_exten *e;
03253    ast_rdlock_contexts();
03254    e = ast_hint_extension_nolock(c, context, exten);
03255    ast_unlock_contexts();
03256    return e;
03257 }
03258 
03259 enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
03260 {
03261    switch (devstate) {
03262    case AST_DEVICE_ONHOLD:
03263       return AST_EXTENSION_ONHOLD;
03264    case AST_DEVICE_BUSY:
03265       return AST_EXTENSION_BUSY;
03266    case AST_DEVICE_UNAVAILABLE:
03267    case AST_DEVICE_UNKNOWN:
03268    case AST_DEVICE_INVALID:
03269       return AST_EXTENSION_UNAVAILABLE;
03270    case AST_DEVICE_RINGINUSE:
03271       return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
03272    case AST_DEVICE_RINGING:
03273       return AST_EXTENSION_RINGING;
03274    case AST_DEVICE_INUSE:
03275       return AST_EXTENSION_INUSE;
03276    case AST_DEVICE_NOT_INUSE:
03277       return AST_EXTENSION_NOT_INUSE;
03278    case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
03279       break;
03280    }
03281 
03282    return AST_EXTENSION_NOT_INUSE;
03283 }
03284 
03285 /*! \brief Check state of extension by using hints */
03286 static int ast_extension_state2(struct ast_exten *e)
03287 {
03288    char hint[AST_MAX_EXTENSION] = "";
03289    char *cur, *rest;
03290    struct ast_devstate_aggregate agg;
03291 
03292    if (!e)
03293       return -1;
03294 
03295    ast_devstate_aggregate_init(&agg);
03296 
03297    ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
03298 
03299    rest = hint;   /* One or more devices separated with a & character */
03300 
03301    while ( (cur = strsep(&rest, "&")) ) {
03302       ast_devstate_aggregate_add(&agg, ast_device_state(cur));
03303    }
03304 
03305    return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
03306 }
03307 
03308 /*! \brief Return extension_state as string */
03309 const char *ast_extension_state2str(int extension_state)
03310 {
03311    int i;
03312 
03313    for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
03314       if (extension_states[i].extension_state == extension_state)
03315          return extension_states[i].text;
03316    }
03317    return "Unknown";
03318 }
03319 
03320 /*! \brief Check extension state for an extension by using hint */
03321 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
03322 {
03323    struct ast_exten *e;
03324 
03325    e = ast_hint_extension(c, context, exten);   /* Do we have a hint for this extension ? */
03326    if (!e)
03327       return -1;           /* No hint, return -1 */
03328 
03329    return ast_extension_state2(e);        /* Check all devices in the hint */
03330 }
03331 
03332 static int handle_statechange(void *datap)
03333 {
03334    struct ast_hint *hint;
03335    struct statechange *sc = datap;
03336 
03337    ast_rdlock_contexts();
03338    AST_RWLIST_RDLOCK(&hints);
03339 
03340    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03341       struct ast_state_cb *cblist;
03342       char buf[AST_MAX_EXTENSION];
03343       char *parse = buf;
03344       char *cur;
03345       int state;
03346 
03347       ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
03348       while ( (cur = strsep(&parse, "&")) ) {
03349          if (!strcasecmp(cur, sc->dev))
03350             break;
03351       }
03352       if (!cur)
03353          continue;
03354 
03355       /* Get device state for this hint */
03356       state = ast_extension_state2(hint->exten);
03357 
03358       if ((state == -1) || (state == hint->laststate))
03359          continue;
03360 
03361       /* Device state changed since last check - notify the watchers */
03362 
03363       /* For general callbacks */
03364       AST_LIST_TRAVERSE(&statecbs, cblist, entry) {
03365          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03366       }
03367 
03368       /* For extension callbacks */
03369       AST_LIST_TRAVERSE(&hint->callbacks, cblist, entry) {
03370          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03371       }
03372 
03373       hint->laststate = state;   /* record we saw the change */
03374    }
03375    AST_RWLIST_UNLOCK(&hints);
03376    ast_unlock_contexts();
03377    ast_free(sc);
03378    return 0;
03379 }
03380 
03381 /*! \brief  Add watcher for extension states */
03382 int ast_extension_state_add(const char *context, const char *exten,
03383              ast_state_cb_type callback, void *data)
03384 {
03385    struct ast_hint *hint;
03386    struct ast_state_cb *cblist;
03387    struct ast_exten *e;
03388 
03389    /* If there's no context and extension:  add callback to statecbs list */
03390    if (!context && !exten) {
03391       AST_RWLIST_WRLOCK(&hints);
03392 
03393       AST_LIST_TRAVERSE(&statecbs, cblist, entry) {
03394          if (cblist->callback == callback) {
03395             cblist->data = data;
03396             AST_RWLIST_UNLOCK(&hints);
03397             return 0;
03398          }
03399       }
03400 
03401       /* Now insert the callback */
03402       if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
03403          AST_RWLIST_UNLOCK(&hints);
03404          return -1;
03405       }
03406       cblist->id = 0;
03407       cblist->callback = callback;
03408       cblist->data = data;
03409 
03410       AST_LIST_INSERT_HEAD(&statecbs, cblist, entry);
03411 
03412       AST_RWLIST_UNLOCK(&hints);
03413 
03414       return 0;
03415    }
03416 
03417    if (!context || !exten)
03418       return -1;
03419 
03420    /* This callback type is for only one hint, so get the hint */
03421    e = ast_hint_extension(NULL, context, exten);
03422    if (!e) {
03423       return -1;
03424    }
03425 
03426    /* If this is a pattern, dynamically create a new extension for this
03427     * particular match.  Note that this will only happen once for each
03428     * individual extension, because the pattern will no longer match first.
03429     */
03430    if (e->exten[0] == '_') {
03431       ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
03432          e->cidmatch, e->app, ast_strdup(e->data), ast_free_ptr,
03433          e->registrar);
03434       e = ast_hint_extension(NULL, context, exten);
03435       if (!e || e->exten[0] == '_') {
03436          return -1;
03437       }
03438    }
03439 
03440    /* Find the hint in the list of hints */
03441    AST_RWLIST_WRLOCK(&hints);
03442 
03443    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03444       if (hint->exten == e)
03445          break;
03446    }
03447 
03448    if (!hint) {
03449       /* We have no hint, sorry */
03450       AST_RWLIST_UNLOCK(&hints);
03451       return -1;
03452    }
03453 
03454    /* Now insert the callback in the callback list  */
03455    if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
03456       AST_RWLIST_UNLOCK(&hints);
03457       return -1;
03458    }
03459 
03460    cblist->id = stateid++;    /* Unique ID for this callback */
03461    cblist->callback = callback;  /* Pointer to callback routine */
03462    cblist->data = data;    /* Data for the callback */
03463 
03464    AST_LIST_INSERT_HEAD(&hint->callbacks, cblist, entry);
03465 
03466    AST_RWLIST_UNLOCK(&hints);
03467 
03468    return cblist->id;
03469 }
03470 
03471 /*! \brief Remove a watcher from the callback list */
03472 int ast_extension_state_del(int id, ast_state_cb_type callback)
03473 {
03474    struct ast_state_cb *p_cur = NULL;
03475    int ret = -1;
03476 
03477    if (!id && !callback)
03478       return -1;
03479 
03480    AST_RWLIST_WRLOCK(&hints);
03481 
03482    if (!id) {  /* id == 0 is a callback without extension */
03483       AST_LIST_TRAVERSE_SAFE_BEGIN(&statecbs, p_cur, entry) {
03484          if (p_cur->callback == callback) {
03485             AST_LIST_REMOVE_CURRENT(entry);
03486             break;
03487          }
03488       }
03489       AST_LIST_TRAVERSE_SAFE_END;
03490    } else { /* callback with extension, find the callback based on ID */
03491       struct ast_hint *hint;
03492       AST_RWLIST_TRAVERSE(&hints, hint, list) {
03493          AST_LIST_TRAVERSE_SAFE_BEGIN(&hint->callbacks, p_cur, entry) {
03494             if (p_cur->id == id) {
03495                AST_LIST_REMOVE_CURRENT(entry);
03496                break;
03497             }
03498          }
03499          AST_LIST_TRAVERSE_SAFE_END;
03500 
03501          if (p_cur)
03502             break;
03503       }
03504    }
03505 
03506    if (p_cur) {
03507       ast_free(p_cur);
03508    }
03509 
03510    AST_RWLIST_UNLOCK(&hints);
03511 
03512    return ret;
03513 }
03514 
03515 
03516 /*! \brief Add hint to hint list, check initial extension state; the hints had better be WRLOCKED already! */
03517 static int ast_add_hint_nolock(struct ast_exten *e)
03518 {
03519    struct ast_hint *hint;
03520 
03521    if (!e)
03522       return -1;
03523 
03524    /* Search if hint exists, do nothing */
03525    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03526       if (hint->exten == e) {
03527          ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03528          return -1;
03529       }
03530    }
03531 
03532    ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03533 
03534    if (!(hint = ast_calloc(1, sizeof(*hint)))) {
03535       return -1;
03536    }
03537    /* Initialize and insert new item at the top */
03538    hint->exten = e;
03539    hint->laststate = ast_extension_state2(e);
03540    AST_RWLIST_INSERT_HEAD(&hints, hint, list);
03541 
03542    return 0;
03543 }
03544 
03545 /*! \brief Add hint to hint list, check initial extension state */
03546 static int ast_add_hint(struct ast_exten *e)
03547 {
03548    int ret;
03549 
03550    AST_RWLIST_WRLOCK(&hints);
03551    ret = ast_add_hint_nolock(e);
03552    AST_RWLIST_UNLOCK(&hints);
03553    
03554    return ret;
03555 }
03556 
03557 /*! \brief Change hint for an extension */
03558 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
03559 {
03560    struct ast_hint *hint;
03561    int res = -1;
03562 
03563    AST_RWLIST_WRLOCK(&hints);
03564    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03565       if (hint->exten == oe) {
03566             hint->exten = ne;
03567          res = 0;
03568          break;
03569       }
03570    }
03571    AST_RWLIST_UNLOCK(&hints);
03572 
03573    return res;
03574 }
03575 
03576 /*! \brief Remove hint from extension */
03577 static int ast_remove_hint(struct ast_exten *e)
03578 {
03579    /* Cleanup the Notifys if hint is removed */
03580    struct ast_hint *hint;
03581    struct ast_state_cb *cblist;
03582    int res = -1;
03583 
03584    if (!e)
03585       return -1;
03586 
03587    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
03588       if (hint->exten != e)
03589          continue;
03590 
03591       while ((cblist = AST_LIST_REMOVE_HEAD(&hint->callbacks, entry))) {
03592          /* Notify with -1 and remove all callbacks */
03593          cblist->callback(hint->exten->parent->name, hint->exten->exten, 
03594             AST_EXTENSION_DEACTIVATED, cblist->data);
03595          ast_free(cblist);
03596       }
03597 
03598       AST_RWLIST_REMOVE_CURRENT(list);
03599       ast_free(hint);
03600 
03601          res = 0;
03602 
03603       break;
03604    }
03605    AST_RWLIST_TRAVERSE_SAFE_END;
03606 
03607    return res;
03608 }
03609 
03610 
03611 /*! \brief Get hint for channel */
03612 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
03613 {
03614    struct ast_exten *e = ast_hint_extension(c, context, exten);
03615 
03616    if (e) {
03617       if (hint)
03618          ast_copy_string(hint, ast_get_extension_app(e), hintsize);
03619       if (name) {
03620          const char *tmp = ast_get_extension_app_data(e);
03621          if (tmp)
03622             ast_copy_string(name, tmp, namesize);
03623       }
03624       return -1;
03625    }
03626    return 0;
03627 }
03628 
03629 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
03630 {
03631    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
03632 }
03633 
03634 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
03635 {
03636    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03637 }
03638 
03639 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
03640 {
03641    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03642 }
03643 
03644 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
03645 {
03646    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
03647 }
03648 
03649 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
03650 {
03651    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
03652 }
03653 
03654 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid, int *found, int combined_find_spawn)
03655 {
03656    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
03657 }
03658 
03659 /*! helper function to set extension and priority */
03660 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
03661 {
03662    ast_channel_lock(c);
03663    ast_copy_string(c->exten, exten, sizeof(c->exten));
03664    c->priority = pri;
03665    ast_channel_unlock(c);
03666 }
03667 
03668 /*!
03669  * \brief collect digits from the channel into the buffer.
03670  * \retval 0 on timeout or done.
03671  * \retval -1 on error.
03672 */
03673 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
03674 {
03675    int digit;
03676 
03677    buf[pos] = '\0';  /* make sure it is properly terminated */
03678    while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
03679       /* As long as we're willing to wait, and as long as it's not defined,
03680          keep reading digits until we can't possibly get a right answer anymore.  */
03681       digit = ast_waitfordigit(c, waittime);
03682       if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03683          c->_softhangup = 0;
03684       } else {
03685          if (!digit) /* No entry */
03686             break;
03687          if (digit < 0) /* Error, maybe a  hangup */
03688             return -1;
03689          if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
03690             buf[pos++] = digit;
03691             buf[pos] = '\0';
03692          }
03693          waittime = c->pbx->dtimeoutms;
03694       }
03695    }
03696    return 0;
03697 }
03698 
03699 static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, 
03700       struct ast_pbx_args *args)
03701 {
03702    int found = 0; /* set if we find at least one match */
03703    int res = 0;
03704    int autoloopflag;
03705    int error = 0;    /* set an error conditions */
03706 
03707    /* A little initial setup here */
03708    if (c->pbx) {
03709       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
03710       /* XXX and now what ? */
03711       ast_free(c->pbx);
03712    }
03713    if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
03714       return -1;
03715    /* Set reasonable defaults */
03716    c->pbx->rtimeoutms = 10000;
03717    c->pbx->dtimeoutms = 5000;
03718 
03719    autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);   /* save value to restore at the end */
03720    ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
03721 
03722    /* Start by trying whatever the channel is set to */
03723    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
03724       /* If not successful fall back to 's' */
03725       ast_verb(2, "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
03726       /* XXX the original code used the existing priority in the call to
03727        * ast_exists_extension(), and reset it to 1 afterwards.
03728        * I believe the correct thing is to set it to 1 immediately.
03729        */
03730       set_ext_pri(c, "s", 1);
03731       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
03732          /* JK02: And finally back to default if everything else failed */
03733          ast_verb(2, "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
03734          ast_copy_string(c->context, "default", sizeof(c->context));
03735       }
03736    }
03737    for (;;) {
03738       char dst_exten[256]; /* buffer to accumulate digits */
03739       int pos = 0;      /* XXX should check bounds */
03740       int digit = 0;
03741       int invalid = 0;
03742       int timeout = 0;
03743 
03744       /* loop on priorities in this context/exten */
03745       while ( !(res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found,1))) {
03746          if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
03747             set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
03748             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03749             memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03750             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03751          } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03752             pbx_builtin_raise_exception(c, "ABSOLUTETIMEOUT");
03753             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03754             memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03755             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03756          } else if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03757             c->_softhangup = 0;
03758             continue;
03759          } else if (ast_check_hangup(c)) {
03760             ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
03761                c->exten, c->priority);
03762             error = 1;
03763             break;
03764          }
03765          c->priority++;
03766       } /* end while  - from here on we can use 'break' to go out */
03767       if (found && res) {
03768          /* Something bad happened, or a hangup has been requested. */
03769          if (strchr("0123456789ABCDEF*#", res)) {
03770             ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
03771             pos = 0;
03772             dst_exten[pos++] = digit = res;
03773             dst_exten[pos] = '\0';
03774          } else if (res == AST_PBX_INCOMPLETE) {
03775             ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
03776             ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
03777 
03778             /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
03779             if (!ast_matchmore_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
03780                invalid = 1;
03781             } else {
03782                ast_copy_string(dst_exten, c->exten, sizeof(dst_exten));
03783                digit = 1;
03784                pos = strlen(dst_exten);
03785             }
03786          } else {
03787             ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03788             ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03789             
03790             if ((res == AST_PBX_ERROR) && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03791                /* if we are already on the 'e' exten, don't jump to it again */
03792                if (!strcmp(c->exten, "e")) {
03793                   ast_verb(2, "Spawn extension (%s, %s, %d) exited ERROR while already on 'e' exten on '%s'\n", c->context, c->exten, c->priority, c->name);
03794                   error = 1;
03795                } else {
03796                   pbx_builtin_raise_exception(c, "ERROR");
03797                   continue;
03798                }
03799             }
03800             
03801             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03802                c->_softhangup = 0;
03803                continue;
03804             } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
03805                set_ext_pri(c, "T", 1); 
03806                /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03807                memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03808                c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03809                continue;
03810             } else {
03811                if (c->cdr)
03812                   ast_cdr_update(c);
03813                error = 1;
03814                break;
03815             }
03816          }
03817       }
03818       if (error)
03819          break;
03820 
03821       /*!\note
03822        * We get here on a failure of some kind:  non-existing extension or
03823        * hangup.  We have options, here.  We can either catch the failure
03824        * and continue, or we can drop out entirely. */
03825 
03826       if (invalid || !ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
03827          /*!\note
03828           * If there is no match at priority 1, it is not a valid extension anymore.
03829           * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
03830           * neither exist.
03831           */
03832          if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
03833             ast_verb(3, "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
03834             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
03835             set_ext_pri(c, "i", 1);
03836          } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03837             pbx_builtin_raise_exception(c, "INVALID");
03838          } else {
03839             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
03840                c->name, c->exten, c->context);
03841             error = 1; /* we know what to do with it */
03842             break;
03843          }
03844       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
03845          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
03846          c->_softhangup = 0;
03847       } else { /* keypress received, get more digits for a full extension */
03848          int waittime = 0;
03849          if (digit)
03850             waittime = c->pbx->dtimeoutms;
03851          else if (!autofallthrough)
03852             waittime = c->pbx->rtimeoutms;
03853          if (!waittime) {
03854             const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
03855             if (!status)
03856                status = "UNKNOWN";
03857             ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
03858             if (!strcasecmp(status, "CONGESTION"))
03859                res = pbx_builtin_congestion(c, "10");
03860             else if (!strcasecmp(status, "CHANUNAVAIL"))
03861                res = pbx_builtin_congestion(c, "10");
03862             else if (!strcasecmp(status, "BUSY"))
03863                res = pbx_builtin_busy(c, "10");
03864             error = 1; /* XXX disable message */
03865             break;   /* exit from the 'for' loop */
03866          }
03867 
03868          if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
03869             break;
03870          if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
03871             timeout = 1;
03872          if (!timeout && ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
03873             set_ext_pri(c, dst_exten, 1);
03874          else {
03875             /* No such extension */
03876             if (!timeout && !ast_strlen_zero(dst_exten)) {
03877                /* An invalid extension */
03878                if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
03879                   ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
03880                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
03881                   set_ext_pri(c, "i", 1);
03882                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03883                   pbx_builtin_raise_exception(c, "INVALID");
03884                } else {
03885                   ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
03886                   found = 1; /* XXX disable message */
03887                   break;
03888                }
03889             } else {
03890                /* A simple timeout */
03891                if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
03892                   ast_verb(3, "Timeout on %s\n", c->name);
03893                   set_ext_pri(c, "t", 1);
03894                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03895                   pbx_builtin_raise_exception(c, "RESPONSETIMEOUT");
03896                } else {
03897                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
03898                   found = 1; /* XXX disable message */
03899                   break;
03900                }
03901             }
03902          }
03903          if (c->cdr) {
03904             ast_verb(2, "CDR updated on %s\n",c->name);
03905             ast_cdr_update(c);
03906          }
03907       }
03908    }
03909 
03910    if (!found && !error) {
03911       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
03912    }
03913 
03914    if (!args || !args->no_hangup_chan) {
03915       ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
03916    }
03917 
03918    if ((!args || !args->no_hangup_chan) &&
03919          !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) && 
03920          ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
03921       set_ext_pri(c, "h", 1);
03922       if (c->cdr && ast_opt_end_cdr_before_h_exten) {
03923          ast_cdr_end(c->cdr);
03924       }
03925       while ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found, 1)) == 0) {
03926          c->priority++;
03927       }
03928       if (found && res) {
03929          /* Something bad happened, or a hangup has been requested. */
03930          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03931          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03932       }
03933    }
03934    ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03935    ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
03936    pbx_destroy(c->pbx);
03937    c->pbx = NULL;
03938 
03939    if (!args || !args->no_hangup_chan) {
03940       ast_hangup(c);
03941    }
03942 
03943    return 0;
03944 }
03945 
03946 /*! 
03947  * \brief Increase call count for channel
03948  * \retval 0 on success
03949  * \retval non-zero if a configured limit (maxcalls, maxload, minmemfree) was reached 
03950 */
03951 static int increase_call_count(const struct ast_channel *c)
03952 {
03953    int failed = 0;
03954    double curloadavg;
03955 #if defined(HAVE_SYSINFO)
03956    long curfreemem;
03957    struct sysinfo sys_info;
03958 #endif
03959 
03960    ast_mutex_lock(&maxcalllock);
03961    if (option_maxcalls) {
03962       if (countcalls >= option_maxcalls) {
03963          ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
03964          failed = -1;
03965       }
03966    }
03967    if (option_maxload) {
03968       getloadavg(&curloadavg, 1);
03969       if (curloadavg >= option_maxload) {
03970          ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
03971          failed = -1;
03972       }
03973    }
03974 #if defined(HAVE_SYSINFO)
03975    if (option_minmemfree) {
03976       if (!sysinfo(&sys_info)) {
03977          /* make sure that the free system memory is above the configured low watermark
03978           * convert the amount of freeram from mem_units to MB */
03979          curfreemem = sys_info.freeram / sys_info.mem_unit; 
03980          curfreemem /= 1024*1024; 
03981          if (curfreemem < option_minmemfree) {
03982             ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
03983             failed = -1;
03984          }
03985       }
03986    }
03987 #endif
03988       
03989    if (!failed) {
03990       countcalls++;
03991       totalcalls++;
03992    }
03993    ast_mutex_unlock(&maxcalllock);
03994 
03995    return failed;
03996 }
03997 
03998 static void decrease_call_count(void)
03999 {
04000    ast_mutex_lock(&maxcalllock);
04001    if (countcalls > 0)
04002       countcalls--;
04003    ast_mutex_unlock(&maxcalllock);
04004 }
04005 
04006 static void destroy_exten(struct ast_exten *e)
04007 {
04008    if (e->priority == PRIORITY_HINT)
04009       ast_remove_hint(e);
04010 
04011    if (e->peer_table)
04012       ast_hashtab_destroy(e->peer_table,0);
04013    if (e->peer_label_table)
04014       ast_hashtab_destroy(e->peer_label_table, 0);
04015    if (e->datad)
04016       e->datad(e->data);
04017    ast_free(e);
04018 }
04019 
04020 static void *pbx_thread(void *data)
04021 {
04022    /* Oh joyeous kernel, we're a new thread, with nothing to do but
04023       answer this channel and get it going.
04024    */
04025    /* NOTE:
04026       The launcher of this function _MUST_ increment 'countcalls'
04027       before invoking the function; it will be decremented when the
04028       PBX has finished running on the channel
04029     */
04030    struct ast_channel *c = data;
04031 
04032    __ast_pbx_run(c, NULL);
04033    decrease_call_count();
04034 
04035    pthread_exit(NULL);
04036 
04037    return NULL;
04038 }
04039 
04040 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
04041 {
04042    pthread_t t;
04043 
04044    if (!c) {
04045       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
04046       return AST_PBX_FAILED;
04047    }
04048 
04049    if (increase_call_count(c))
04050       return AST_PBX_CALL_LIMIT;
04051 
04052    /* Start a new thread, and get something handling this channel. */
04053    if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
04054       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
04055       decrease_call_count();
04056       return AST_PBX_FAILED;
04057    }
04058 
04059    return AST_PBX_SUCCESS;
04060 }
04061 
04062 enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
04063 {
04064    enum ast_pbx_result res = AST_PBX_SUCCESS;
04065 
04066    if (increase_call_count(c)) {
04067       return AST_PBX_CALL_LIMIT;
04068    }
04069 
04070    res = __ast_pbx_run(c, args);
04071 
04072    decrease_call_count();
04073 
04074    return res;
04075 }
04076 
04077 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
04078 {
04079    return ast_pbx_run_args(c, NULL);
04080 }
04081 
04082 int ast_active_calls(void)
04083 {
04084    return countcalls;
04085 }
04086 
04087 int ast_processed_calls(void)
04088 {
04089    return totalcalls;
04090 }
04091 
04092 int pbx_set_autofallthrough(int newval)
04093 {
04094    int oldval = autofallthrough;
04095    autofallthrough = newval;
04096    return oldval;
04097 }
04098 
04099 int pbx_set_extenpatternmatchnew(int newval)
04100 {
04101    int oldval = extenpatternmatchnew;
04102    extenpatternmatchnew = newval;
04103    return oldval;
04104 }
04105 
04106 void pbx_set_overrideswitch(const char *newval)
04107 {
04108    if (overrideswitch) {
04109       ast_free(overrideswitch);
04110    }
04111    if (!ast_strlen_zero(newval)) {
04112       overrideswitch = ast_strdup(newval);
04113    } else {
04114       overrideswitch = NULL;
04115    }
04116 }
04117 
04118 /*!
04119  * \brief lookup for a context with a given name,
04120  * \retval found context or NULL if not found.
04121 */
04122 static struct ast_context *find_context(const char *context)
04123 {
04124    struct ast_context *c = NULL;
04125    struct fake_context item;
04126 
04127    ast_copy_string(item.name, context, sizeof(item.name));
04128 
04129    c = ast_hashtab_lookup(contexts_table,&item);
04130 
04131    return c;
04132 }
04133 
04134 /*!
04135  * \brief lookup for a context with a given name,
04136  * \retval with conlock held if found.
04137  * \retval NULL if not found.
04138 */
04139 static struct ast_context *find_context_locked(const char *context)
04140 {
04141    struct ast_context *c = NULL;
04142    struct fake_context item;
04143 
04144    ast_copy_string(item.name, context, sizeof(item.name));
04145 
04146    ast_rdlock_contexts();
04147    c = ast_hashtab_lookup(contexts_table,&item);
04148 
04149 #ifdef NOTNOW
04150 
04151    while ( (c = ast_walk_contexts(c)) ) {
04152       if (!strcmp(ast_get_context_name(c), context))
04153          return c;
04154    }
04155 #endif
04156    if (!c)
04157       ast_unlock_contexts();
04158 
04159    return c;
04160 }
04161 
04162 /*!
04163  * \brief Remove included contexts.
04164  * This function locks contexts list by &conlist, search for the right context
04165  * structure, leave context list locked and call ast_context_remove_include2
04166  * which removes include, unlock contexts list and return ...
04167 */
04168 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
04169 {
04170    int ret = -1;
04171    struct ast_context *c = find_context_locked(context);
04172 
04173    if (c) {
04174       /* found, remove include from this context ... */
04175       ret = ast_context_remove_include2(c, include, registrar);
04176       ast_unlock_contexts();
04177    }
04178    return ret;
04179 }
04180 
04181 /*!
04182  * \brief Locks context, remove included contexts, unlocks context.
04183  * When we call this function, &conlock lock must be locked, because when
04184  * we giving *con argument, some process can remove/change this context
04185  * and after that there can be segfault.
04186  *
04187  * \retval 0 on success.
04188  * \retval -1 on failure.
04189  */
04190 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
04191 {
04192    struct ast_include *i, *pi = NULL;
04193    int ret = -1;
04194 
04195    ast_wrlock_context(con);
04196 
04197    /* find our include */
04198    for (i = con->includes; i; pi = i, i = i->next) {
04199       if (!strcmp(i->name, include) &&
04200             (!registrar || !strcmp(i->registrar, registrar))) {
04201          /* remove from list */
04202          ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
04203          if (pi)
04204             pi->next = i->next;
04205          else
04206             con->includes = i->next;
04207          /* free include and return */
04208          ast_free(i);
04209          ret = 0;
04210          break;
04211       }
04212    }
04213 
04214    ast_unlock_context(con);
04215 
04216    return ret;
04217 }
04218 
04219 /*!
04220  * \note This function locks contexts list by &conlist, search for the rigt context
04221  * structure, leave context list locked and call ast_context_remove_switch2
04222  * which removes switch, unlock contexts list and return ...
04223  */
04224 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
04225 {
04226    int ret = -1; /* default error return */
04227    struct ast_context *c = find_context_locked(context);
04228 
04229    if (c) {
04230       /* remove switch from this context ... */
04231       ret = ast_context_remove_switch2(c, sw, data, registrar);
04232       ast_unlock_contexts();
04233    }
04234    return ret;
04235 }
04236 
04237 /*!
04238  * \brief This function locks given context, removes switch, unlock context and
04239  * return.
04240  * \note When we call this function, &conlock lock must be locked, because when
04241  * we giving *con argument, some process can remove/change this context
04242  * and after that there can be segfault.
04243  *
04244  */
04245 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
04246 {
04247    struct ast_sw *i;
04248    int ret = -1;
04249 
04250    ast_wrlock_context(con);
04251 
04252    /* walk switches */
04253    AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
04254       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
04255          (!registrar || !strcmp(i->registrar, registrar))) {
04256          /* found, remove from list */
04257          ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
04258          AST_LIST_REMOVE_CURRENT(list);
04259          ast_free(i); /* free switch and return */
04260          ret = 0;
04261          break;
04262       }
04263    }
04264    AST_LIST_TRAVERSE_SAFE_END;
04265 
04266    ast_unlock_context(con);
04267 
04268    return ret;
04269 }
04270 
04271 /*
04272  * \note This functions lock contexts list, search for the right context,
04273  * call ast_context_remove_extension2, unlock contexts list and return.
04274  * In this function we are using
04275  */
04276 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
04277 {
04278    return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
04279 }
04280 
04281 int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
04282 {
04283    int ret = -1; /* default error return */
04284    struct ast_context *c = find_context_locked(context);
04285 
04286    if (c) { /* ... remove extension ... */
04287       ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcallerid, registrar, 1);
04288       ast_unlock_contexts();
04289    }
04290    return ret;
04291 }
04292 
04293 /*!
04294  * \brief This functionc locks given context, search for the right extension and
04295  * fires out all peer in this extensions with given priority. If priority
04296  * is set to 0, all peers are removed. After that, unlock context and
04297  * return.
04298  * \note When do you want to call this function, make sure that &conlock is locked,
04299  * because some process can handle with your *con context before you lock
04300  * it.
04301  *
04302  */
04303 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
04304 {
04305    return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked);
04306 }
04307 
04308 int ast_context_remove_extension_callerid2(struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar, int already_locked)
04309 {
04310    struct ast_exten *exten, *prev_exten = NULL;
04311    struct ast_exten *peer;
04312    struct ast_exten ex, *exten2, *exten3;
04313    char dummy_name[1024];
04314    struct ast_exten *previous_peer = NULL;
04315    struct ast_exten *next_peer = NULL;
04316    int found = 0;
04317 
04318    if (!already_locked)
04319       ast_wrlock_context(con);
04320 
04321    /* Handle this is in the new world */
04322 
04323    /* FIXME For backwards compatibility, if callerid==NULL, then remove ALL
04324     * peers, not just those matching the callerid. */
04325 #ifdef NEED_DEBUG
04326    ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
04327 #endif
04328 #ifdef CONTEXT_DEBUG
04329    check_contexts(__FILE__, __LINE__);
04330 #endif
04331    /* find this particular extension */
04332    ex.exten = dummy_name;
04333    ex.matchcid = matchcallerid && !ast_strlen_zero(callerid); /* don't say match if there's no callerid */
04334    ex.cidmatch = callerid;
04335    ast_copy_string(dummy_name, extension, sizeof(dummy_name));
04336    exten = ast_hashtab_lookup(con->root_table, &ex);
04337    if (exten) {
04338       if (priority == 0) {
04339          exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04340          if (!exten2)
04341             ast_log(LOG_ERROR,"Trying to delete the exten %s from context %s, but could not remove from the root_table\n", extension, con->name);
04342          if (con->pattern_tree) {
04343             
04344             struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04345             
04346             if (x->exten) { /* this test for safety purposes */
04347                x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
04348                x->exten = 0; /* get rid of what will become a bad pointer */
04349             } else {
04350                ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
04351             }
04352          }
04353       } else {
04354          ex.priority = priority;
04355          exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
04356          if (exten2) {
04357             
04358             if (exten2->label) { /* if this exten has a label, remove that, too */
04359                exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
04360                if (!exten3)
04361                   ast_log(LOG_ERROR,"Did not remove this priority label (%d/%s) from the peer_label_table of context %s, extension %s!\n", priority, exten2->label, con->name, exten2->exten);
04362             }
04363          
04364             exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
04365             if (!exten3)
04366                ast_log(LOG_ERROR,"Did not remove this priority (%d) from the peer_table of context %s, extension %s!\n", priority, con->name, exten2->exten);
04367             if (exten2 == exten && exten2->peer) {
04368                exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04369                ast_hashtab_insert_immediate(con->root_table, exten2->peer);
04370             }
04371             if (ast_hashtab_size(exten->peer_table) == 0) {
04372                /* well, if the last priority of an exten is to be removed,
04373                   then, the extension is removed, too! */
04374                exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
04375                if (!exten3)
04376                   ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
04377                if (con->pattern_tree) {
04378                   struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04379                   if (x->exten) { /* this test for safety purposes */
04380                      x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
04381                      x->exten = 0; /* get rid of what will become a bad pointer */
04382                   }
04383                }
04384             }
04385          } else {
04386             ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
04387                   priority, exten->exten, con->name);
04388          }
04389       }
04390    } else {
04391       /* hmmm? this exten is not in this pattern tree? */
04392       ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
04393             extension, con->name);
04394    }
04395 #ifdef NEED_DEBUG
04396    if (con->pattern_tree) {
04397       ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
04398       log_match_char_tree(con->pattern_tree, " ");
04399    }
04400 #endif
04401 
04402    /* scan the extension list to find first matching extension-registrar */
04403    for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
04404       if (!strcmp(exten->exten, extension) &&
04405          (!registrar || !strcmp(exten->registrar, registrar)) &&
04406          (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
04407          break;
04408    }
04409    if (!exten) {
04410       /* we can't find right extension */
04411       if (!already_locked)
04412          ast_unlock_context(con);
04413       return -1;
04414    }
04415 
04416    /* scan the priority list to remove extension with exten->priority == priority */
04417    for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
04418        peer && !strcmp(peer->exten, extension) && (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(peer->cidmatch) && !strcmp(peer->cidmatch,callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(peer->cidmatch)));
04419          peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
04420       if ((priority == 0 || peer->priority == priority) &&
04421             (!callerid || !matchcallerid || (matchcallerid && !strcmp(peer->cidmatch, callerid))) &&
04422             (!registrar || !strcmp(peer->registrar, registrar) )) {
04423          found = 1;
04424 
04425          /* we are first priority extension? */
04426          if (!previous_peer) {
04427             /*
04428              * We are first in the priority chain, so must update the extension chain.
04429              * The next node is either the next priority or the next extension
04430              */
04431             struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
04432             if (peer->peer) {
04433                /* move the peer_table and peer_label_table down to the next peer, if
04434                   it is there */
04435                peer->peer->peer_table = peer->peer_table;
04436                peer->peer->peer_label_table = peer->peer_label_table;
04437                peer->peer_table = NULL;
04438                peer->peer_label_table = NULL;
04439             }
04440             if (!prev_exten) {   /* change the root... */
04441                con->root = next_node;
04442             } else {
04443                prev_exten->next = next_node; /* unlink */
04444             }
04445             if (peer->peer)   { /* update the new head of the pri list */
04446                peer->peer->next = peer->next;
04447             }
04448          } else { /* easy, we are not first priority in extension */
04449             previous_peer->peer = peer->peer;
04450          }
04451 
04452          /* now, free whole priority extension */
04453          destroy_exten(peer);
04454       } else {
04455          previous_peer = peer;
04456       }
04457    }
04458    if (!already_locked)
04459       ast_unlock_context(con);
04460    return found ? 0 : -1;
04461 }
04462 
04463 
04464 /*!
04465  * \note This function locks contexts list by &conlist, searches for the right context
04466  * structure, and locks the macrolock mutex in that context.
04467  * macrolock is used to limit a macro to be executed by one call at a time.
04468  */
04469 int ast_context_lockmacro(const char *context)
04470 {
04471    struct ast_context *c = NULL;
04472    int ret = -1;
04473    struct fake_context item;
04474 
04475    ast_rdlock_contexts();
04476 
04477    ast_copy_string(item.name, context, sizeof(item.name));
04478 
04479    c = ast_hashtab_lookup(contexts_table,&item);
04480    if (c)
04481       ret = 0;
04482 
04483 
04484 #ifdef NOTNOW
04485 
04486    while ((c = ast_walk_contexts(c))) {
04487       if (!strcmp(ast_get_context_name(c), context)) {
04488          ret = 0;
04489          break;
04490       }
04491    }
04492 
04493 #endif
04494    ast_unlock_contexts();
04495 
04496    /* if we found context, lock macrolock */
04497    if (ret == 0) 
04498       ret = ast_mutex_lock(&c->macrolock);
04499 
04500    return ret;
04501 }
04502 
04503 /*!
04504  * \note This function locks contexts list by &conlist, searches for the right context
04505  * structure, and unlocks the macrolock mutex in that context.
04506  * macrolock is used to limit a macro to be executed by one call at a time.
04507  */
04508 int ast_context_unlockmacro(const char *context)
04509 {
04510    struct ast_context *c = NULL;
04511    int ret = -1;
04512    struct fake_context item;
04513 
04514    ast_rdlock_contexts();
04515 
04516    ast_copy_string(item.name, context, sizeof(item.name));
04517 
04518    c = ast_hashtab_lookup(contexts_table,&item);
04519    if (c)
04520       ret = 0;
04521 #ifdef NOTNOW
04522 
04523    while ((c = ast_walk_contexts(c))) {
04524       if (!strcmp(ast_get_context_name(c), context)) {
04525          ret = 0;
04526          break;
04527       }
04528    }
04529 
04530 #endif
04531    ast_unlock_contexts();
04532 
04533    /* if we found context, unlock macrolock */
04534    if (ret == 0) 
04535       ret = ast_mutex_unlock(&c->macrolock);
04536 
04537    return ret;
04538 }
04539 
04540 /*! \brief Dynamically register a new dial plan application */
04541 int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description, void *mod)
04542 {
04543    struct ast_app *tmp, *cur = NULL;
04544    char tmps[80];
04545    int length, res;
04546 
04547    AST_RWLIST_WRLOCK(&apps);
04548    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
04549       if (!(res = strcasecmp(app, tmp->name))) {
04550          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
04551          AST_RWLIST_UNLOCK(&apps);
04552          return -1;
04553       } else if (res < 0)
04554          break;
04555    }
04556 
04557    length = sizeof(*tmp) + strlen(app) + 1;
04558 
04559    if (!(tmp = ast_calloc(1, length))) {
04560       AST_RWLIST_UNLOCK(&apps);
04561       return -1;
04562    }
04563 
04564    strcpy(tmp->name, app);
04565    tmp->execute = execute;
04566    tmp->synopsis = synopsis;
04567    tmp->description = description;
04568    tmp->module = mod;
04569 
04570    /* Store in alphabetical order */
04571    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
04572       if (strcasecmp(tmp->name, cur->name) < 0) {
04573          AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
04574          break;
04575       }
04576    }
04577    AST_RWLIST_TRAVERSE_SAFE_END;
04578    if (!cur)
04579       AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
04580 
04581    ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
04582 
04583    AST_RWLIST_UNLOCK(&apps);
04584 
04585    return 0;
04586 }
04587 
04588 /*
04589  * Append to the list. We don't have a tail pointer because we need
04590  * to scan the list anyways to check for duplicates during insertion.
04591  */
04592 int ast_register_switch(struct ast_switch *sw)
04593 {
04594    struct ast_switch *tmp;
04595 
04596    AST_RWLIST_WRLOCK(&switches);
04597    AST_RWLIST_TRAVERSE(&switches, tmp, list) {
04598       if (!strcasecmp(tmp->name, sw->name)) {
04599          AST_RWLIST_UNLOCK(&switches);
04600          ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
04601          return -1;
04602       }
04603    }
04604    AST_RWLIST_INSERT_TAIL(&switches, sw, list);
04605    AST_RWLIST_UNLOCK(&switches);
04606 
04607    return 0;
04608 }
04609 
04610 void ast_unregister_switch(struct ast_switch *sw)
04611 {
04612    AST_RWLIST_WRLOCK(&switches);
04613    AST_RWLIST_REMOVE(&switches, sw, list);
04614    AST_RWLIST_UNLOCK(&switches);
04615 }
04616 
04617 /*
04618  * Help for CLI commands ...
04619  */
04620 
04621 /*
04622  * \brief 'show application' CLI command implementation function...
04623  */
04624 static char *handle_show_application(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04625 {
04626    struct ast_app *aa;
04627    int app, no_registered_app = 1;
04628    char *ret = NULL;
04629    int which = 0;
04630    int wordlen;
04631 
04632    switch (cmd) {
04633    case CLI_INIT: 
04634       e->command = "core show application";
04635       e->usage = 
04636          "Usage: core show application <application> [<application> [<application> [...]]]\n"
04637          "       Describes a particular application.\n";
04638       return NULL;
04639    case CLI_GENERATE:
04640       /*
04641        * There is a possibility to show informations about more than one
04642        * application at one time. You can type 'show application Dial Echo' and
04643        * you will see informations about these two applications ...
04644        */
04645       wordlen = strlen(a->word);
04646       /* return the n-th [partial] matching entry */
04647       AST_RWLIST_RDLOCK(&apps);
04648       AST_RWLIST_TRAVERSE(&apps, aa, list) {
04649          if (!strncasecmp(a->word, aa->name, wordlen) && ++which > a->n) {
04650             ret = ast_strdup(aa->name);
04651             break;
04652          }
04653       }
04654       AST_RWLIST_UNLOCK(&apps);
04655 
04656       return ret;
04657    }
04658 
04659    if (a->argc < 4)
04660       return CLI_SHOWUSAGE;
04661 
04662    /* ... go through all applications ... */
04663    AST_RWLIST_RDLOCK(&apps);
04664    AST_RWLIST_TRAVERSE(&apps, aa, list) {
04665       /* ... compare this application name with all arguments given
04666        * to 'show application' command ... */
04667       for (app = 3; app < a->argc; app++) {
04668          if (!strcasecmp(aa->name, a->argv[app])) {
04669             /* Maximum number of characters added by terminal coloring is 22 */
04670             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
04671             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
04672             int synopsis_size, description_size;
04673 
04674             no_registered_app = 0;
04675 
04676             if (aa->synopsis)
04677                synopsis_size = strlen(aa->synopsis) + 23;
04678             else
04679                synopsis_size = strlen("Not available") + 23;
04680             synopsis = alloca(synopsis_size);
04681 
04682             if (aa->description)
04683                description_size = strlen(aa->description) + 23;
04684             else
04685                description_size = strlen("Not available") + 23;
04686             description = alloca(description_size);
04687 
04688             if (synopsis && description) {
04689                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", aa->name);
04690                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
04691                term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
04692                term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
04693                term_color(synopsis,
04694                            aa->synopsis ? aa->synopsis : "Not available",
04695                            COLOR_CYAN, 0, synopsis_size);
04696                term_color(description,
04697                            aa->description ? aa->description : "Not available",
04698                            COLOR_CYAN, 0, description_size);
04699 
04700                ast_cli(a->fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
04701             } else {
04702                /* ... one of our applications, show info ...*/
04703                ast_cli(a->fd,"\n  -= Info about application '%s' =- \n\n"
04704                   "[Synopsis]\n  %s\n\n"
04705                   "[Description]\n%s\n",
04706                   aa->name,
04707                   aa->synopsis ? aa->synopsis : "Not available",
04708                   aa->description ? aa->description : "Not available");
04709             }
04710          }
04711       }
04712    }
04713    AST_RWLIST_UNLOCK(&apps);
04714 
04715    /* we found at least one app? no? */
04716    if (no_registered_app) {
04717       ast_cli(a->fd, "Your application(s) is (are) not registered\n");
04718       return CLI_FAILURE;
04719    }
04720 
04721    return CLI_SUCCESS;
04722 }
04723 
04724 /*! \brief  handle_show_hints: CLI support for listing registered dial plan hints */
04725 static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04726 {
04727    struct ast_hint *hint;
04728    int num = 0;
04729    int watchers;
04730    struct ast_state_cb *watcher;
04731 
04732    switch (cmd) {
04733    case CLI_INIT:
04734       e->command = "core show hints";
04735       e->usage = 
04736          "Usage: core show hints\n"
04737          "       List registered hints\n";
04738       return NULL;
04739    case CLI_GENERATE:
04740       return NULL;   
04741    }
04742 
04743    AST_RWLIST_RDLOCK(&hints);
04744    if (AST_RWLIST_EMPTY(&hints)) {
04745       ast_cli(a->fd, "There are no registered dialplan hints\n");
04746       AST_RWLIST_UNLOCK(&hints);
04747       return CLI_SUCCESS;
04748    }
04749    /* ... we have hints ... */
04750    ast_cli(a->fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
04751    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04752       watchers = 0;
04753       AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
04754          watchers++;
04755       }
04756       ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
04757          ast_get_extension_name(hint->exten),
04758          ast_get_context_name(ast_get_extension_context(hint->exten)),
04759          ast_get_extension_app(hint->exten),
04760          ast_extension_state2str(hint->laststate), watchers);
04761       num++;
04762    }
04763    ast_cli(a->fd, "----------------\n");
04764    ast_cli(a->fd, "- %d hints registered\n", num);
04765    AST_RWLIST_UNLOCK(&hints);
04766    return CLI_SUCCESS;
04767 }
04768 
04769 /*! \brief autocomplete for CLI command 'core show hint' */
04770 static char *complete_core_show_hint(const char *line, const char *word, int pos, int state)
04771 {
04772    struct ast_hint *hint;
04773    char *ret = NULL;
04774    int which = 0;
04775    int wordlen;
04776 
04777    if (pos != 3)
04778       return NULL;
04779    
04780    wordlen = strlen(word);
04781 
04782    AST_RWLIST_RDLOCK(&hints);
04783    /* walk through all hints */
04784    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04785       if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
04786          ret = ast_strdup(ast_get_extension_name(hint->exten));
04787          break;
04788       }
04789    }
04790    AST_RWLIST_UNLOCK(&hints);
04791 
04792    return ret;
04793 }
04794 
04795 /*! \brief  handle_show_hint: CLI support for listing registered dial plan hint */
04796 static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04797 {
04798    struct ast_hint *hint;
04799    int watchers;
04800    int num = 0, extenlen;
04801    struct ast_state_cb *watcher;
04802 
04803    switch (cmd) {
04804    case CLI_INIT:
04805       e->command = "core show hint";
04806       e->usage =
04807          "Usage: core show hint <exten>\n"
04808          "       List registered hint\n";
04809       return NULL;
04810    case CLI_GENERATE:
04811       return complete_core_show_hint(a->line, a->word, a->pos, a->n);
04812    }
04813 
04814    if (a->argc < 4)
04815       return CLI_SHOWUSAGE;
04816 
04817    AST_RWLIST_RDLOCK(&hints);
04818    if (AST_RWLIST_EMPTY(&hints)) {
04819       ast_cli(a->fd, "There are no registered dialplan hints\n");
04820       AST_RWLIST_UNLOCK(&hints);
04821       return CLI_SUCCESS;
04822    }
04823    extenlen = strlen(a->argv[3]);
04824    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04825       if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
04826          watchers = 0;
04827          AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
04828             watchers++;
04829          }
04830          ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
04831             ast_get_extension_name(hint->exten),
04832             ast_get_context_name(ast_get_extension_context(hint->exten)),
04833             ast_get_extension_app(hint->exten),
04834             ast_extension_state2str(hint->laststate), watchers);
04835          num++;
04836       }
04837    }
04838    AST_RWLIST_UNLOCK(&hints);
04839    if (!num)
04840       ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
04841    else
04842       ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
04843    return CLI_SUCCESS;
04844 }
04845 
04846 
04847 /*! \brief  handle_show_switches: CLI support for listing registered dial plan switches */
04848 static char *handle_show_switches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04849 {
04850    struct ast_switch *sw;
04851 
04852    switch (cmd) {
04853    case CLI_INIT:
04854       e->command = "core show switches";
04855       e->usage = 
04856          "Usage: core show switches\n"
04857          "       List registered switches\n";
04858       return NULL;
04859    case CLI_GENERATE:
04860       return NULL;   
04861    }
04862 
04863    AST_RWLIST_RDLOCK(&switches);
04864 
04865    if (AST_RWLIST_EMPTY(&switches)) {
04866       AST_RWLIST_UNLOCK(&switches);
04867       ast_cli(a->fd, "There are no registered alternative switches\n");
04868       return CLI_SUCCESS;
04869    }
04870 
04871    ast_cli(a->fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
04872    AST_RWLIST_TRAVERSE(&switches, sw, list)
04873       ast_cli(a->fd, "%s: %s\n", sw->name, sw->description);
04874 
04875    AST_RWLIST_UNLOCK(&switches);
04876 
04877    return CLI_SUCCESS;
04878 }
04879 
04880 static char *handle_show_applications(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04881 {
04882    struct ast_app *aa;
04883    int like = 0, describing = 0;
04884    int total_match = 0;    /* Number of matches in like clause */
04885    int total_apps = 0;  /* Number of apps registered */
04886    static char* choices[] = { "like", "describing", NULL };
04887 
04888    switch (cmd) {
04889    case CLI_INIT:
04890       e->command = "core show applications [like|describing]";
04891       e->usage = 
04892          "Usage: core show applications [{like|describing} <text>]\n"
04893          "       List applications which are currently available.\n"
04894          "       If 'like', <text> will be a substring of the app name\n"
04895          "       If 'describing', <text> will be a substring of the description\n";
04896       return NULL;
04897    case CLI_GENERATE:
04898       return (a->pos != 3) ? NULL : ast_cli_complete(a->word, choices, a->n);
04899    }
04900 
04901    AST_RWLIST_RDLOCK(&apps);
04902 
04903    if (AST_RWLIST_EMPTY(&apps)) {
04904       ast_cli(a->fd, "There are no registered applications\n");
04905       AST_RWLIST_UNLOCK(&apps);
04906       return CLI_SUCCESS;
04907    }
04908 
04909    /* core list applications like <keyword> */
04910    if ((a->argc == 5) && (!strcmp(a->argv[3], "like"))) {
04911       like = 1;
04912    } else if ((a->argc > 4) && (!strcmp(a->argv[3], "describing"))) {
04913       describing = 1;
04914    }
04915 
04916    /* core list applications describing <keyword1> [<keyword2>] [...] */
04917    if ((!like) && (!describing)) {
04918       ast_cli(a->fd, "    -= Registered Asterisk Applications =-\n");
04919    } else {
04920       ast_cli(a->fd, "    -= Matching Asterisk Applications =-\n");
04921    }
04922 
04923    AST_RWLIST_TRAVERSE(&apps, aa, list) {
04924       int printapp = 0;
04925       total_apps++;
04926       if (like) {
04927          if (strcasestr(aa->name, a->argv[4])) {
04928             printapp = 1;
04929             total_match++;
04930          }
04931       } else if (describing) {
04932          if (aa->description) {
04933             /* Match all words on command line */
04934             int i;
04935             printapp = 1;
04936             for (i = 4; i < a->argc; i++) {
04937                if (!strcasestr(aa->description, a->argv[i])) {
04938                   printapp = 0;
04939                } else {
04940                   total_match++;
04941                }
04942             }
04943          }
04944       } else {
04945          printapp = 1;
04946       }
04947 
04948       if (printapp) {
04949          ast_cli(a->fd,"  %20s: %s\n", aa->name, aa->synopsis ? aa->synopsis : "<Synopsis not available>");
04950       }
04951    }
04952    if ((!like) && (!describing)) {
04953       ast_cli(a->fd, "    -= %d Applications Registered =-\n",total_apps);
04954    } else {
04955       ast_cli(a->fd, "    -= %d Applications Matching =-\n",total_match);
04956    }
04957 
04958    AST_RWLIST_UNLOCK(&apps);
04959 
04960    return CLI_SUCCESS;
04961 }
04962 
04963 /*
04964  * 'show dialplan' CLI command implementation functions ...
04965  */
04966 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
04967    int state)
04968 {
04969    struct ast_context *c = NULL;
04970    char *ret = NULL;
04971    int which = 0;
04972    int wordlen;
04973 
04974    /* we are do completion of [exten@]context on second position only */
04975    if (pos != 2)
04976       return NULL;
04977 
04978    ast_rdlock_contexts();
04979 
04980    wordlen = strlen(word);
04981 
04982    /* walk through all contexts and return the n-th match */
04983    while ( (c = ast_walk_contexts(c)) ) {
04984       if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
04985          ret = ast_strdup(ast_get_context_name(c));
04986          break;
04987       }
04988    }
04989 
04990    ast_unlock_contexts();
04991 
04992    return ret;
04993 }
04994 
04995 /*! \brief Counters for the show dialplan manager command */
04996 struct dialplan_counters {
04997    int total_items;
04998    int total_context;
04999    int total_exten;
05000    int total_prio;
05001    int context_existence;
05002    int extension_existence;
05003 };
05004 
05005 /*! \brief helper function to print an extension */
05006 static void print_ext(struct ast_exten *e, char * buf, int buflen)
05007 {
05008    int prio = ast_get_extension_priority(e);
05009    if (prio == PRIORITY_HINT) {
05010       snprintf(buf, buflen, "hint: %s",
05011          ast_get_extension_app(e));
05012    } else {
05013       snprintf(buf, buflen, "%d. %s(%s)",
05014          prio, ast_get_extension_app(e),
05015          (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
05016    }
05017 }
05018 
05019 /* XXX not verified */
05020 static int show_dialplan_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
05021 {
05022    struct ast_context *c = NULL;
05023    int res = 0, old_total_exten = dpc->total_exten;
05024 
05025    ast_rdlock_contexts();
05026 
05027    /* walk all contexts ... */
05028    while ( (c = ast_walk_contexts(c)) ) {
05029       struct ast_exten *e;
05030       struct ast_include *i;
05031       struct ast_ignorepat *ip;
05032       char buf[256], buf2[256];
05033       int context_info_printed = 0;
05034 
05035       if (context && strcmp(ast_get_context_name(c), context))
05036          continue;   /* skip this one, name doesn't match */
05037 
05038       dpc->context_existence = 1;
05039 
05040       ast_rdlock_context(c);
05041 
05042       /* are we looking for exten too? if yes, we print context
05043        * only if we find our extension.
05044        * Otherwise print context even if empty ?
05045        * XXX i am not sure how the rinclude is handled.
05046        * I think it ought to go inside.
05047        */
05048       if (!exten) {
05049          dpc->total_context++;
05050          ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05051             ast_get_context_name(c), ast_get_context_registrar(c));
05052          context_info_printed = 1;
05053       }
05054 
05055       /* walk extensions ... */
05056       e = NULL;
05057       while ( (e = ast_walk_context_extensions(c, e)) ) {
05058          struct ast_exten *p;
05059 
05060          if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
05061             continue;   /* skip, extension match failed */
05062 
05063          dpc->extension_existence = 1;
05064 
05065          /* may we print context info? */
05066          if (!context_info_printed) {
05067             dpc->total_context++;
05068             if (rinclude) { /* TODO Print more info about rinclude */
05069                ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
05070                   ast_get_context_name(c), ast_get_context_registrar(c));
05071             } else {
05072                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05073                   ast_get_context_name(c), ast_get_context_registrar(c));
05074             }
05075             context_info_printed = 1;
05076          }
05077          dpc->total_prio++;
05078 
05079          /* write extension name and first peer */
05080          if (e->matchcid)
05081             snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
05082          else
05083             snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
05084 
05085          print_ext(e, buf2, sizeof(buf2));
05086 
05087          ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
05088             ast_get_extension_registrar(e));
05089 
05090          dpc->total_exten++;
05091          /* walk next extension peers */
05092          p = e;   /* skip the first one, we already got it */
05093          while ( (p = ast_walk_extension_priorities(e, p)) ) {
05094             const char *el = ast_get_extension_label(p);
05095             dpc->total_prio++;
05096             if (el)
05097                snprintf(buf, sizeof(buf), "   [%s]", el);
05098             else
05099                buf[0] = '\0';
05100             print_ext(p, buf2, sizeof(buf2));
05101 
05102             ast_cli(fd,"  %-17s %-45s [%s]\n", buf, buf2,
05103                ast_get_extension_registrar(p));
05104          }
05105       }
05106 
05107       /* walk included and write info ... */
05108       i = NULL;
05109       while ( (i = ast_walk_context_includes(c, i)) ) {
05110          snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
05111          if (exten) {
05112             /* Check all includes for the requested extension */
05113             if (includecount >= AST_PBX_MAX_STACK) {
05114                ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
05115             } else {
05116                int dupe = 0;
05117                int x;
05118                for (x = 0; x < includecount; x++) {
05119                   if (!strcasecmp(includes[x], ast_get_include_name(i))) {
05120                      dupe++;
05121                      break;
05122                   }
05123                }
05124                if (!dupe) {
05125                   includes[includecount] = ast_get_include_name(i);
05126                   show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
05127                } else {
05128                   ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
05129                }
05130             }
05131          } else {
05132             ast_cli(fd, "  Include =>        %-45s [%s]\n",
05133                buf, ast_get_include_registrar(i));
05134          }
05135       }
05136 
05137       /* walk ignore patterns and write info ... */
05138       ip = NULL;
05139       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05140          const char *ipname = ast_get_ignorepat_name(ip);
05141          char ignorepat[AST_MAX_EXTENSION];
05142          snprintf(buf, sizeof(buf), "'%s'", ipname);
05143          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05144          if (!exten || ast_extension_match(ignorepat, exten)) {
05145             ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
05146                buf, ast_get_ignorepat_registrar(ip));
05147          }
05148       }
05149       if (!rinclude) {
05150          struct ast_sw *sw = NULL;
05151          while ( (sw = ast_walk_context_switches(c, sw)) ) {
05152             snprintf(buf, sizeof(buf), "'%s/%s'",
05153                ast_get_switch_name(sw),
05154                ast_get_switch_data(sw));
05155             ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
05156                buf, ast_get_switch_registrar(sw));
05157          }
05158       }
05159       
05160       ast_unlock_context(c);
05161 
05162       /* if we print something in context, make an empty line */
05163       if (context_info_printed)
05164          ast_cli(fd, "\n");
05165    }
05166    ast_unlock_contexts();
05167 
05168    return (dpc->total_exten == old_total_exten) ? -1 : res;
05169 }
05170 
05171 static int show_debug_helper(int fd, const char *context, const char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude, int includecount, const char *includes[])
05172 {
05173    struct ast_context *c = NULL;
05174    int res = 0, old_total_exten = dpc->total_exten;
05175 
05176    ast_cli(fd,"\n     In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
05177 
05178    ast_cli(fd,"\n           Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
05179    ast_cli(fd,    "                        Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
05180    ast_cli(fd,    "                              <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
05181    ast_cli(fd,    "                              <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
05182    ast_cli(fd,    "                              [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
05183    ast_cli(fd,    "                        In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
05184    ast_cli(fd,    "                        are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
05185    ast_rdlock_contexts();
05186 
05187    /* walk all contexts ... */
05188    while ( (c = ast_walk_contexts(c)) ) {
05189       int context_info_printed = 0;
05190 
05191       if (context && strcmp(ast_get_context_name(c), context))
05192          continue;   /* skip this one, name doesn't match */
05193 
05194       dpc->context_existence = 1;
05195 
05196       if (!c->pattern_tree)
05197          ast_exists_extension(NULL, c->name, "s", 1, ""); /* do this to force the trie to built, if it is not already */
05198 
05199       ast_rdlock_context(c);
05200 
05201       dpc->total_context++;
05202       ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05203          ast_get_context_name(c), ast_get_context_registrar(c));
05204       context_info_printed = 1;
05205       
05206       if (c->pattern_tree)
05207       {
05208          cli_match_char_tree(c->pattern_tree, " ", fd);
05209       } else {
05210          ast_cli(fd,"\n     No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
05211       }
05212 
05213       ast_unlock_context(c);
05214 
05215       /* if we print something in context, make an empty line */
05216       if (context_info_printed)
05217          ast_cli(fd, "\n");
05218    }
05219    ast_unlock_contexts();
05220 
05221    return (dpc->total_exten == old_total_exten) ? -1 : res;
05222 }
05223 
05224 static char *handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05225 {
05226    char *exten = NULL, *context = NULL;
05227    /* Variables used for different counters */
05228    struct dialplan_counters counters;
05229    const char *incstack[AST_PBX_MAX_STACK];
05230 
05231    switch (cmd) {
05232    case CLI_INIT:
05233       e->command = "dialplan show";
05234       e->usage = 
05235          "Usage: dialplan show [[exten@]context]\n"
05236          "       Show dialplan\n";
05237       return NULL;
05238    case CLI_GENERATE:   
05239       return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05240    }
05241 
05242    memset(&counters, 0, sizeof(counters));
05243 
05244    if (a->argc != 2 && a->argc != 3)
05245       return CLI_SHOWUSAGE;
05246 
05247    /* we obtain [exten@]context? if yes, split them ... */
05248    if (a->argc == 3) {
05249       if (strchr(a->argv[2], '@')) {   /* split into exten & context */
05250          context = ast_strdupa(a->argv[2]);
05251          exten = strsep(&context, "@");
05252          /* change empty strings to NULL */
05253          if (ast_strlen_zero(exten))
05254             exten = NULL;
05255       } else { /* no '@' char, only context given */
05256          context = a->argv[2];
05257       }
05258       if (ast_strlen_zero(context))
05259          context = NULL;
05260    }
05261    /* else Show complete dial plan, context and exten are NULL */
05262    show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05263 
05264    /* check for input failure and throw some error messages */
05265    if (context && !counters.context_existence) {
05266       ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05267       return CLI_FAILURE;
05268    }
05269 
05270    if (exten && !counters.extension_existence) {
05271       if (context)
05272          ast_cli(a->fd, "There is no existence of %s@%s extension\n",
05273             exten, context);
05274       else
05275          ast_cli(a->fd,
05276             "There is no existence of '%s' extension in all contexts\n",
05277             exten);
05278       return CLI_FAILURE;
05279    }
05280 
05281    ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
05282             counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
05283             counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
05284             counters.total_context, counters.total_context == 1 ? "context" : "contexts");
05285 
05286    /* everything ok */
05287    return CLI_SUCCESS;
05288 }
05289 
05290 /*! \brief Send ack once */
05291 static char *handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05292 {
05293    char *exten = NULL, *context = NULL;
05294    /* Variables used for different counters */
05295    struct dialplan_counters counters;
05296    const char *incstack[AST_PBX_MAX_STACK];
05297 
05298    switch (cmd) {
05299    case CLI_INIT:
05300       e->command = "dialplan debug";
05301       e->usage = 
05302          "Usage: dialplan debug [context]\n"
05303          "       Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
05304       return NULL;
05305    case CLI_GENERATE:   
05306       return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05307    }
05308 
05309    memset(&counters, 0, sizeof(counters));
05310 
05311    if (a->argc != 2 && a->argc != 3)
05312       return CLI_SHOWUSAGE;
05313 
05314    /* we obtain [exten@]context? if yes, split them ... */
05315    /* note: we ignore the exten totally here .... */
05316    if (a->argc == 3) {
05317       if (strchr(a->argv[2], '@')) {   /* split into exten & context */
05318          context = ast_strdupa(a->argv[2]);
05319          exten = strsep(&context, "@");
05320          /* change empty strings to NULL */
05321          if (ast_strlen_zero(exten))
05322             exten = NULL;
05323       } else { /* no '@' char, only context given */
05324          context = a->argv[2];
05325       }
05326       if (ast_strlen_zero(context))
05327          context = NULL;
05328    }
05329    /* else Show complete dial plan, context and exten are NULL */
05330    show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05331 
05332    /* check for input failure and throw some error messages */
05333    if (context && !counters.context_existence) {
05334       ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05335       return CLI_FAILURE;
05336    }
05337 
05338 
05339    ast_cli(a->fd,"-= %d %s. =-\n",
05340          counters.total_context, counters.total_context == 1 ? "context" : "contexts");
05341 
05342    /* everything ok */
05343    return CLI_SUCCESS;
05344 }
05345 
05346 /*! \brief Send ack once */
05347 static void manager_dpsendack(struct mansession *s, const struct message *m)
05348 {
05349    astman_send_listack(s, m, "DialPlan list will follow", "start");
05350 }
05351 
05352 /*! \brief Show dialplan extensions
05353  * XXX this function is similar but not exactly the same as the CLI's
05354  * show dialplan. Must check whether the difference is intentional or not.
05355  */
05356 static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
05357                const char *actionidtext, const char *context,
05358                const char *exten, struct dialplan_counters *dpc,
05359                struct ast_include *rinclude)
05360 {
05361    struct ast_context *c;
05362    int res = 0, old_total_exten = dpc->total_exten;
05363 
05364    if (ast_strlen_zero(exten))
05365       exten = NULL;
05366    if (ast_strlen_zero(context))
05367       context = NULL;
05368 
05369    ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
05370 
05371    /* try to lock contexts */
05372    if (ast_rdlock_contexts()) {
05373       astman_send_error(s, m, "Failed to lock contexts");
05374       ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
05375       return -1;
05376    }
05377 
05378    c = NULL;      /* walk all contexts ... */
05379    while ( (c = ast_walk_contexts(c)) ) {
05380       struct ast_exten *e;
05381       struct ast_include *i;
05382       struct ast_ignorepat *ip;
05383 
05384       if (context && strcmp(ast_get_context_name(c), context) != 0)
05385          continue;   /* not the name we want */
05386 
05387       dpc->context_existence = 1;
05388 
05389       ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
05390 
05391       if (ast_rdlock_context(c)) {  /* failed to lock */
05392          ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
05393          continue;
05394       }
05395 
05396       /* XXX note- an empty context is not printed */
05397       e = NULL;      /* walk extensions in context  */
05398       while ( (e = ast_walk_context_extensions(c, e)) ) {
05399          struct ast_exten *p;
05400 
05401          /* looking for extension? is this our extension? */
05402          if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
05403             /* not the one we are looking for, continue */
05404             ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
05405             continue;
05406          }
05407          ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
05408 
05409          dpc->extension_existence = 1;
05410 
05411          /* may we print context info? */ 
05412          dpc->total_context++;
05413          dpc->total_exten++;
05414 
05415          p = NULL;      /* walk next extension peers */
05416          while ( (p = ast_walk_extension_priorities(e, p)) ) {
05417             int prio = ast_get_extension_priority(p);
05418 
05419             dpc->total_prio++;
05420             if (!dpc->total_items++)
05421                manager_dpsendack(s, m);
05422             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05423             astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
05424 
05425             /* XXX maybe make this conditional, if p != e ? */
05426             if (ast_get_extension_label(p))
05427                astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
05428 
05429             if (prio == PRIORITY_HINT) {
05430                astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
05431             } else {
05432                astman_append(s, "Priority: %d\r\nApplication: %s\r\nAppData: %s\r\n", prio, ast_get_extension_app(p), (char *) ast_get_extension_app_data(p));
05433             }
05434             astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
05435          }
05436       }
05437 
05438       i = NULL;      /* walk included and write info ... */
05439       while ( (i = ast_walk_context_includes(c, i)) ) {
05440          if (exten) {
05441             /* Check all includes for the requested extension */
05442             manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
05443          } else {
05444             if (!dpc->total_items++)
05445                manager_dpsendack(s, m);
05446             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05447             astman_append(s, "Context: %s\r\nIncludeContext: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_include_name(i), ast_get_include_registrar(i));
05448             astman_append(s, "\r\n");
05449             ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
05450          }
05451       }
05452 
05453       ip = NULL;  /* walk ignore patterns and write info ... */
05454       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05455          const char *ipname = ast_get_ignorepat_name(ip);
05456          char ignorepat[AST_MAX_EXTENSION];
05457 
05458          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05459          if (!exten || ast_extension_match(ignorepat, exten)) {
05460             if (!dpc->total_items++)
05461                manager_dpsendack(s, m);
05462             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05463             astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
05464             astman_append(s, "\r\n");
05465          }
05466       }
05467       if (!rinclude) {
05468          struct ast_sw *sw = NULL;
05469          while ( (sw = ast_walk_context_switches(c, sw)) ) {
05470             if (!dpc->total_items++)
05471                manager_dpsendack(s, m);
05472             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05473             astman_append(s, "Context: %s\r\nSwitch: %s/%s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_registrar(sw));  
05474             astman_append(s, "\r\n");
05475             ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
05476          }
05477       }
05478 
05479       ast_unlock_context(c);
05480    }
05481    ast_unlock_contexts();
05482 
05483    if (dpc->total_exten == old_total_exten) {
05484       ast_debug(3, "manager_show_dialplan: Found nothing new\n");
05485       /* Nothing new under the sun */
05486       return -1;
05487    } else {
05488       return res;
05489    }
05490 }
05491 
05492 /*! \brief  Manager listing of dial plan */
05493 static int manager_show_dialplan(struct mansession *s, const struct message *m)
05494 {
05495    const char *exten, *context;
05496    const char *id = astman_get_header(m, "ActionID");
05497    char idtext[256];
05498    int res;
05499 
05500    /* Variables used for different counters */
05501    struct dialplan_counters counters;
05502 
05503    if (!ast_strlen_zero(id))
05504       snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
05505    else
05506       idtext[0] = '\0';
05507 
05508    memset(&counters, 0, sizeof(counters));
05509 
05510    exten = astman_get_header(m, "Extension");
05511    context = astman_get_header(m, "Context");
05512    
05513    res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
05514 
05515    if (context && !counters.context_existence) {
05516       char errorbuf[BUFSIZ];
05517    
05518       snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
05519       astman_send_error(s, m, errorbuf);
05520       return 0;
05521    }
05522    if (exten && !counters.extension_existence) {
05523       char errorbuf[BUFSIZ];
05524 
05525       if (context)
05526          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
05527       else
05528          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
05529       astman_send_error(s, m, errorbuf);
05530       return 0;
05531    }
05532 
05533    manager_event(EVENT_FLAG_CONFIG, "ShowDialPlanComplete",
05534       "EventList: Complete\r\n"
05535       "ListItems: %d\r\n"
05536       "ListExtensions: %d\r\n"
05537       "ListPriorities: %d\r\n"   
05538       "ListContexts: %d\r\n"  
05539       "%s"
05540       "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
05541 
05542    /* everything ok */
05543    return 0;
05544 }
05545 
05546 static char mandescr_show_dialplan[] =
05547 "Description: Show dialplan contexts and extensions.\n"
05548 "Be aware that showing the full dialplan may take a lot of capacity\n"
05549 "Variables: \n"
05550 " ActionID: <id>     Action ID for this AMI transaction (optional)\n"
05551 " Extension: <extension>   Extension (Optional)\n"
05552 " Context: <context>    Context (Optional)\n"
05553 "\n";
05554 
05555 /*! \brief CLI support for listing global variables in a parseable way */
05556 static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05557 {
05558    int i = 0;
05559    struct ast_var_t *newvariable;
05560 
05561    switch (cmd) {
05562    case CLI_INIT:
05563       e->command = "dialplan show globals";
05564       e->usage = 
05565          "Usage: dialplan show globals\n"
05566          "       List current global dialplan variables and their values\n";
05567       return NULL;
05568    case CLI_GENERATE:
05569       return NULL;
05570    }
05571 
05572    ast_rwlock_rdlock(&globalslock);
05573    AST_LIST_TRAVERSE (&globals, newvariable, entries) {
05574       i++;
05575       ast_cli(a->fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
05576    }
05577    ast_rwlock_unlock(&globalslock);
05578    ast_cli(a->fd, "\n    -- %d variable(s)\n", i);
05579 
05580    return CLI_SUCCESS;
05581 }
05582 
05583 static char *handle_show_globals_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05584 {
05585 
05586    char *res = handle_show_globals(e, cmd, a);
05587    if (cmd == CLI_INIT)
05588       e->command = "core show globals";
05589    return res;
05590 }
05591 
05592 #ifdef AST_DEVMODE
05593 static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05594 {
05595    struct ast_devstate_aggregate agg;
05596    int i, j, exten, combined;
05597 
05598    switch (cmd) {
05599    case CLI_INIT:
05600       e->command = "core show device2extenstate";
05601       e->usage =
05602          "Usage: core show device2extenstate\n"
05603          "       Lists device state to extension state combinations.\n";
05604    case CLI_GENERATE:
05605       return NULL;
05606    }
05607    for (i = 0; i < AST_DEVICE_TOTAL; i++) {
05608       for (j = 0; j < AST_DEVICE_TOTAL; j++) {
05609          ast_devstate_aggregate_init(&agg);
05610          ast_devstate_aggregate_add(&agg, i);
05611          ast_devstate_aggregate_add(&agg, j);
05612          combined = ast_devstate_aggregate_result(&agg);
05613          exten = ast_devstate_to_extenstate(combined);
05614          ast_cli(a->fd, "\n Exten:%14s  CombinedDevice:%12s  Dev1:%12s  Dev2:%12s", ast_extension_state2str(exten), ast_devstate_str(combined), ast_devstate_str(j), ast_devstate_str(i));
05615       }
05616    }
05617    ast_cli(a->fd, "\n");
05618    return CLI_SUCCESS;
05619 }
05620 #endif
05621 
05622 /*! \brief CLI support for listing chanvar's variables in a parseable way */
05623 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05624 {
05625    struct ast_channel *chan = NULL;
05626    struct ast_str *vars = ast_str_alloca(BUFSIZ * 4); /* XXX large because we might have lots of channel vars */
05627 
05628    switch (cmd) {
05629    case CLI_INIT:
05630       e->command = "dialplan show chanvar";
05631       e->usage = 
05632          "Usage: dialplan show chanvar <channel>\n"
05633          "       List current channel variables and their values\n";
05634       return NULL;
05635    case CLI_GENERATE:
05636       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05637    }
05638 
05639    if (a->argc != e->args + 1)
05640       return CLI_SHOWUSAGE;
05641 
05642    if (!(chan = ast_get_channel_by_name_locked(a->argv[e->args]))) {
05643       ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
05644       return CLI_FAILURE;
05645    }
05646 
05647    pbx_builtin_serialize_variables(chan, &vars);
05648    if (vars->str) {
05649       ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], vars->str);
05650    }
05651    ast_channel_unlock(chan);
05652    return CLI_SUCCESS;
05653 }
05654 
05655 static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05656 {
05657    switch (cmd) {
05658    case CLI_INIT:
05659       e->command = "dialplan set global";
05660       e->usage = 
05661          "Usage: dialplan set global <name> <value>\n"
05662          "       Set global dialplan variable <name> to <value>\n";
05663       return NULL;
05664    case CLI_GENERATE:
05665       return NULL;   
05666    }
05667 
05668    if (a->argc != e->args + 2)
05669       return CLI_SHOWUSAGE;
05670 
05671    pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
05672    ast_cli(a->fd, "\n    -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
05673 
05674    return CLI_SUCCESS;
05675 }
05676 
05677 static char *handle_set_global_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05678 {
05679    char *res = handle_set_global(e, cmd, a);
05680    if (cmd == CLI_INIT)
05681       e->command = "core set global";
05682    return res;
05683 }
05684 
05685 static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05686 {
05687    struct ast_channel *chan;
05688    const char *chan_name, *var_name, *var_value;
05689 
05690    switch (cmd) {
05691    case CLI_INIT:
05692       e->command = "dialplan set chanvar";
05693       e->usage = 
05694          "Usage: dialplan set chanvar <channel> <varname> <value>\n"
05695          "       Set channel variable <varname> to <value>\n";
05696       return NULL;
05697    case CLI_GENERATE:
05698       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05699    }
05700 
05701    if (a->argc != e->args + 3)
05702       return CLI_SHOWUSAGE;
05703 
05704    chan_name = a->argv[e->args];
05705    var_name = a->argv[e->args + 1];
05706    var_value = a->argv[e->args + 2];
05707 
05708    if (!(chan = ast_get_channel_by_name_locked(chan_name))) {
05709       ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
05710       return CLI_FAILURE;
05711    }
05712 
05713    pbx_builtin_setvar_helper(chan, var_name, var_value);
05714    ast_channel_unlock(chan);
05715    ast_cli(a->fd, "\n    -- Channel variable '%s' set to '%s' for '%s'\n",  var_name, var_value, chan_name);
05716 
05717    return CLI_SUCCESS;
05718 }
05719 
05720 static char *handle_set_chanvar_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05721 {
05722    char *res = handle_set_chanvar(e, cmd, a);
05723    if (cmd == CLI_INIT)
05724       e->command = "core set chanvar";
05725    return res;
05726 }
05727 
05728 static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05729 {
05730    int oldval = 0;
05731    
05732    switch (cmd) {
05733    case CLI_INIT:
05734       e->command = "dialplan set extenpatternmatchnew true";
05735       e->usage = 
05736          "Usage: dialplan set extenpatternmatchnew true|false\n"
05737          "       Use the NEW extension pattern matching algorithm, true or false.\n";
05738       return NULL;
05739    case CLI_GENERATE:
05740       return NULL;   
05741    }
05742 
05743    if (a->argc != 4)
05744       return CLI_SHOWUSAGE;
05745 
05746    oldval =  pbx_set_extenpatternmatchnew(1);
05747    
05748    if (oldval)
05749       ast_cli(a->fd, "\n    -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
05750    else
05751       ast_cli(a->fd, "\n    -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
05752 
05753    return CLI_SUCCESS;
05754 }
05755 
05756 static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05757 {
05758    int oldval = 0;
05759    
05760    switch (cmd) {
05761    case CLI_INIT:
05762       e->command = "dialplan set extenpatternmatchnew false";
05763       e->usage = 
05764          "Usage: dialplan set extenpatternmatchnew true|false\n"
05765          "       Use the NEW extension pattern matching algorithm, true or false.\n";
05766       return NULL;
05767    case CLI_GENERATE:
05768       return NULL;   
05769    }
05770 
05771    if (a->argc != 4)
05772       return CLI_SHOWUSAGE;
05773 
05774    oldval =  pbx_set_extenpatternmatchnew(0);
05775    
05776    if (!oldval)
05777       ast_cli(a->fd, "\n    -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
05778    else
05779       ast_cli(a->fd, "\n    -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
05780 
05781    return CLI_SUCCESS;
05782 }
05783 
05784 /*
05785  * Deprecated CLI commands
05786  */
05787 
05788 static struct ast_cli_entry cli_show_globals_deprecated = AST_CLI_DEFINE(handle_show_globals_deprecated, "Show global dialplan variables.");
05789 static struct ast_cli_entry cli_set_chanvar_deprecated = AST_CLI_DEFINE(handle_set_chanvar_deprecated, "Set a channel variable.");
05790 static struct ast_cli_entry cli_set_global_deprecated = AST_CLI_DEFINE(handle_set_global_deprecated, "Set global dialplan variable.");
05791 
05792 /*
05793  * CLI entries for upper commands ...
05794  */
05795 static struct ast_cli_entry pbx_cli[] = {
05796    AST_CLI_DEFINE(handle_show_applications, "Shows registered dialplan applications"),
05797    AST_CLI_DEFINE(handle_show_functions, "Shows registered dialplan functions"),
05798    AST_CLI_DEFINE(handle_show_switches, "Show alternative switches"),
05799    AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
05800    AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
05801    AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables", .deprecate_cmd = &cli_show_globals_deprecated),
05802 #ifdef AST_DEVMODE
05803    AST_CLI_DEFINE(handle_show_device2extenstate, "Show expected exten state from multiple device states"),
05804 #endif
05805    AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
05806    AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
05807    AST_CLI_DEFINE(handle_show_application, "Describe a specific dialplan application"),
05808    AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable", .deprecate_cmd = &cli_set_global_deprecated),
05809    AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable", .deprecate_cmd = &cli_set_chanvar_deprecated),
05810    AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
05811    AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
05812    AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
05813    AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
05814 };
05815 
05816 static void unreference_cached_app(struct ast_app *app)
05817 {
05818    struct ast_context *context = NULL;
05819    struct ast_exten *eroot = NULL, *e = NULL;
05820 
05821    ast_rdlock_contexts();
05822    while ((context = ast_walk_contexts(context))) {
05823       while ((eroot = ast_walk_context_extensions(context, eroot))) {
05824          while ((e = ast_walk_extension_priorities(eroot, e))) {
05825             if (e->cached_app == app)
05826                e->cached_app = NULL;
05827          }
05828       }
05829    }
05830    ast_unlock_contexts();
05831 
05832    return;
05833 }
05834 
05835 int ast_unregister_application(const char *app)
05836 {
05837    struct ast_app *tmp;
05838 
05839    AST_RWLIST_WRLOCK(&apps);
05840    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
05841       if (!strcasecmp(app, tmp->name)) {
05842          unreference_cached_app(tmp);
05843          AST_RWLIST_REMOVE_CURRENT(list);
05844          ast_verb(2, "Unregistered application '%s'\n", tmp->name);
05845          ast_free(tmp);
05846          break;
05847       }
05848    }
05849    AST_RWLIST_TRAVERSE_SAFE_END;
05850    AST_RWLIST_UNLOCK(&apps);
05851 
05852    return tmp ? 0 : -1;
05853 }
05854 
05855 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
05856 {
05857    struct ast_context *tmp, **local_contexts;
05858    struct fake_context search;
05859    int length = sizeof(struct ast_context) + strlen(name) + 1;
05860 
05861    if (!contexts_table) {
05862       contexts_table = ast_hashtab_create(17,
05863                                  ast_hashtab_compare_contexts, 
05864                                  ast_hashtab_resize_java,
05865                                  ast_hashtab_newsize_java,
05866                                  ast_hashtab_hash_contexts,
05867                                  0);
05868    }
05869    
05870    ast_copy_string(search.name, name, sizeof(search.name));
05871    if (!extcontexts) {
05872       ast_rdlock_contexts();
05873       local_contexts = &contexts;
05874       tmp = ast_hashtab_lookup(contexts_table, &search);
05875       ast_unlock_contexts();
05876       if (tmp) {
05877          tmp->refcount++;
05878          return tmp;
05879       }
05880    } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
05881       local_contexts = extcontexts;
05882       tmp = ast_hashtab_lookup(exttable, &search);
05883       if (tmp) {
05884          tmp->refcount++;
05885          return tmp;
05886       }
05887    }
05888    
05889    if ((tmp = ast_calloc(1, length))) {
05890       ast_rwlock_init(&tmp->lock);
05891       ast_mutex_init(&tmp->macrolock);
05892       strcpy(tmp->name, name);
05893       tmp->root = NULL;
05894       tmp->root_table = NULL;
05895       tmp->registrar = ast_strdup(registrar);
05896       tmp->includes = NULL;
05897       tmp->ignorepats = NULL;
05898       tmp->refcount = 1;
05899    } else {
05900       ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
05901       return NULL;
05902    }
05903    
05904    if (!extcontexts) {
05905       ast_wrlock_contexts();
05906       tmp->next = *local_contexts;
05907       *local_contexts = tmp;
05908       ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
05909       ast_unlock_contexts();
05910       ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
05911       ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
05912    } else {
05913       tmp->next = *local_contexts;
05914       if (exttable)
05915          ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
05916       
05917       *local_contexts = tmp;
05918       ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
05919       ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
05920    }
05921    return tmp;
05922 }
05923 
05924 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
05925 
05926 struct store_hint {
05927    char *context;
05928    char *exten;
05929    AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks;
05930    int laststate;
05931    AST_LIST_ENTRY(store_hint) list;
05932    char data[1];
05933 };
05934 
05935 AST_LIST_HEAD(store_hints, store_hint);
05936 
05937 static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
05938 {
05939    struct ast_include *i;
05940    struct ast_ignorepat *ip;
05941    struct ast_sw *sw;
05942    
05943    ast_verb(3, "merging incls/swits/igpats from old(%s) to new(%s) context, registrar = %s\n", ast_get_context_name(old), ast_get_context_name(new), registrar);
05944    /* copy in the includes, switches, and ignorepats */
05945    /* walk through includes */
05946    for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
05947       if (strcmp(ast_get_include_registrar(i), registrar) == 0)
05948          continue; /* not mine */
05949       ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
05950    }
05951    
05952    /* walk through switches */
05953    for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
05954       if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
05955          continue; /* not mine */
05956       ast_context_add_switch2(new, ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_eval(sw), ast_get_switch_registrar(sw));
05957    }
05958    
05959    /* walk thru ignorepats ... */
05960    for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
05961       if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
05962          continue; /* not mine */
05963       ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
05964    }
05965 }
05966 
05967 
05968 /* the purpose of this routine is to duplicate a context, with all its substructure,
05969    except for any extens that have a matching registrar */
05970 static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
05971 {
05972    struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
05973    struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
05974    struct ast_hashtab_iter *exten_iter;
05975    struct ast_hashtab_iter *prio_iter;
05976    int insert_count = 0;
05977    int first = 1;
05978    
05979    /* We'll traverse all the extensions/prios, and see which are not registrar'd with
05980       the current registrar, and copy them to the new context. If the new context does not
05981       exist, we'll create it "on demand". If no items are in this context to copy, then we'll
05982       only create the empty matching context if the old one meets the criteria */
05983    
05984    if (context->root_table) {
05985       exten_iter = ast_hashtab_start_traversal(context->root_table);
05986       while ((exten_item=ast_hashtab_next(exten_iter))) {
05987          if (new) {
05988             new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
05989          } else {
05990             new_exten_item = NULL;
05991          }
05992          prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
05993          while ((prio_item=ast_hashtab_next(prio_iter))) {
05994             int res1;
05995             char *dupdstr;
05996             
05997             if (new_exten_item) {
05998                new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
05999             } else {
06000                new_prio_item = NULL;
06001             }
06002             if (strcmp(prio_item->registrar,registrar) == 0) {
06003                continue;
06004             }
06005             /* make sure the new context exists, so we have somewhere to stick this exten/prio */
06006             if (!new) {
06007                new = ast_context_find_or_create(extcontexts, exttable, context->name, prio_item->registrar); /* a new context created via priority from a different context in the old dialplan, gets its registrar from the prio's registrar */
06008             }
06009 
06010             /* copy in the includes, switches, and ignorepats */
06011             if (first) { /* but, only need to do this once */
06012                context_merge_incls_swits_igps_other_registrars(new, context, registrar);
06013                first = 0;
06014             }
06015             
06016             if (!new) {
06017                ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
06018                return; /* no sense continuing. */
06019             }
06020             /* we will not replace existing entries in the new context with stuff from the old context.
06021                but, if this is because of some sort of registrar conflict, we ought to say something... */
06022             
06023             dupdstr = ast_strdup(prio_item->data);
06024             
06025             res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label, 
06026                                 prio_item->cidmatch, prio_item->app, dupdstr, prio_item->datad, prio_item->registrar);
06027             if (!res1 && new_exten_item && new_prio_item){
06028                ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
06029                      context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
06030             } else {
06031                /* we do NOT pass the priority data from the old to the new -- we pass a copy of it, so no changes to the current dialplan take place,
06032                 and no double frees take place, either! */
06033                insert_count++;
06034             }
06035          }
06036          ast_hashtab_end_traversal(prio_iter);
06037       }
06038       ast_hashtab_end_traversal(exten_iter);
06039    }
06040    
06041    if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
06042         (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
06043       /* we could have given it the registrar of the other module who incremented the refcount,
06044          but that's not available, so we give it the registrar we know about */
06045       new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
06046       
06047       /* copy in the includes, switches, and ignorepats */
06048       context_merge_incls_swits_igps_other_registrars(new, context, registrar);
06049    }
06050 }
06051 
06052 
06053 /* XXX this does not check that multiple contexts are merged */
06054 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
06055 {
06056    double ft;
06057    struct ast_context *tmp, *oldcontextslist;
06058    struct ast_hashtab *oldtable;
06059    struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
06060    struct store_hint *this;
06061    struct ast_hint *hint;
06062    struct ast_exten *exten;
06063    int length;
06064    struct ast_state_cb *thiscb;
06065    struct ast_hashtab_iter *iter;
06066    
06067    /* it is very important that this function hold the hint list lock _and_ the conlock
06068       during its operation; not only do we need to ensure that the list of contexts
06069       and extensions does not change, but also that no hint callbacks (watchers) are
06070       added or removed during the merge/delete process
06071 
06072       in addition, the locks _must_ be taken in this order, because there are already
06073       other code paths that use this order
06074    */
06075    
06076    struct timeval begintime, writelocktime, endlocktime, enddeltime;
06077    int wrlock_ver;
06078    
06079    begintime = ast_tvnow();
06080    ast_rdlock_contexts();
06081    iter = ast_hashtab_start_traversal(contexts_table);
06082    while ((tmp = ast_hashtab_next(iter))) {
06083       context_merge(extcontexts, exttable, tmp, registrar);
06084    }
06085    ast_hashtab_end_traversal(iter);
06086    wrlock_ver = ast_wrlock_contexts_version();
06087    
06088    ast_unlock_contexts(); /* this feels real retarded, but you must do
06089                        what you must do If this isn't done, the following 
06090                         wrlock is a guraranteed deadlock */
06091    ast_wrlock_contexts();
06092    if (ast_wrlock_contexts_version() > wrlock_ver+1) {
06093       ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n");
06094    }
06095    
06096    AST_RWLIST_WRLOCK(&hints);
06097    writelocktime = ast_tvnow();
06098 
06099    /* preserve all watchers for hints associated with this registrar */
06100    AST_RWLIST_TRAVERSE(&hints, hint, list) {
06101       if (!AST_LIST_EMPTY(&hint->callbacks) && !strcmp(registrar, hint->exten->parent->registrar)) {
06102          length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
06103          if (!(this = ast_calloc(1, length)))
06104             continue;
06105          AST_LIST_APPEND_LIST(&this->callbacks, &hint->callbacks, entry);
06106          this->laststate = hint->laststate;
06107          this->context = this->data;
06108          strcpy(this->data, hint->exten->parent->name);
06109          this->exten = this->data + strlen(this->context) + 1;
06110          strcpy(this->exten, hint->exten->exten);
06111          AST_LIST_INSERT_HEAD(&store, this, list);
06112       }
06113    }
06114 
06115    /* save the old table and list */
06116    oldtable = contexts_table;
06117    oldcontextslist = contexts;
06118 
06119    /* move in the new table and list */
06120    contexts_table = exttable;
06121    contexts = *extcontexts;
06122    
06123    /* restore the watchers for hints that can be found; notify those that
06124       cannot be restored
06125    */
06126    while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
06127       struct pbx_find_info q = { .stacklen = 0 };
06128       exten = pbx_find_extension(NULL, NULL, &q, this->context, this->exten, PRIORITY_HINT, NULL, "", E_MATCH);
06129       /* If this is a pattern, dynamically create a new extension for this
06130        * particular match.  Note that this will only happen once for each
06131        * individual extension, because the pattern will no longer match first.
06132        */
06133       if (exten && exten->exten[0] == '_') {
06134          ast_add_extension_nolock(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL,
06135             0, exten->app, ast_strdup(exten->data), ast_free_ptr, registrar);
06136          /* rwlocks are not recursive locks */
06137          exten = ast_hint_extension_nolock(NULL, this->context, this->exten);
06138       }
06139 
06140       /* Find the hint in the list of hints */
06141       AST_RWLIST_TRAVERSE(&hints, hint, list) {
06142          if (hint->exten == exten)
06143             break;
06144       }
06145       if (!exten || !hint) {
06146          /* this hint has been removed, notify the watchers */
06147          while ((thiscb = AST_LIST_REMOVE_HEAD(&this->callbacks, entry))) {
06148             thiscb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, thiscb->data);
06149             ast_free(thiscb);
06150          }
06151       } else {
06152          AST_LIST_APPEND_LIST(&hint->callbacks, &this->callbacks, entry);
06153          hint->laststate = this->laststate;
06154       }
06155       ast_free(this);
06156    }
06157 
06158    AST_RWLIST_UNLOCK(&hints);
06159    ast_unlock_contexts();
06160    endlocktime = ast_tvnow();
06161    
06162    /* the old list and hashtab no longer are relevant, delete them while the rest of asterisk
06163       is now freely using the new stuff instead */
06164    
06165    ast_hashtab_destroy(oldtable, NULL);
06166    
06167    for (tmp = oldcontextslist; tmp; ) {
06168       struct ast_context *next;  /* next starting point */
06169       next = tmp->next;
06170       __ast_internal_context_destroy(tmp);
06171       tmp = next;
06172    }
06173    enddeltime = ast_tvnow();
06174    
06175    ft = ast_tvdiff_us(writelocktime, begintime);
06176    ft /= 1000000.0;
06177    ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
06178    
06179    ft = ast_tvdiff_us(endlocktime, writelocktime);
06180    ft /= 1000000.0;
06181    ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
06182 
06183    ft = ast_tvdiff_us(enddeltime, endlocktime);
06184    ft /= 1000000.0;
06185    ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
06186 
06187    ft = ast_tvdiff_us(enddeltime, begintime);
06188    ft /= 1000000.0;
06189    ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
06190    return;
06191 }
06192 
06193 /*
06194  * errno values
06195  *  EBUSY  - can't lock
06196  *  ENOENT - no existence of context
06197  */
06198 int ast_context_add_include(const char *context, const char *include, const char *registrar)
06199 {
06200    int ret = -1;
06201    struct ast_context *c = find_context_locked(context);
06202 
06203    if (c) {
06204       ret = ast_context_add_include2(c, include, registrar);
06205       ast_unlock_contexts();
06206    }
06207    return ret;
06208 }
06209 
06210 /*! \brief Helper for get_range.
06211  * return the index of the matching entry, starting from 1.
06212  * If names is not supplied, try numeric values.
06213  */
06214 static int lookup_name(const char *s, char *const names[], int max)
06215 {
06216    int i;
06217 
06218    if (names) {
06219       for (i = 0; names[i]; i++) {
06220          if (!strcasecmp(s, names[i]))
06221             return i+1;
06222       }
06223    } else if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
06224       return i;
06225    }
06226    return 0; /* error return */
06227 }
06228 
06229 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
06230  * names, if supplied, is an array of names that should be mapped to numbers.
06231  */
06232 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
06233 {
06234    int s, e; /* start and ending position */
06235    unsigned int mask = 0;
06236 
06237    /* Check for whole range */
06238    if (ast_strlen_zero(src) || !strcmp(src, "*")) {
06239       s = 0;
06240       e = max - 1;
06241    } else {
06242       /* Get start and ending position */
06243       char *c = strchr(src, '-');
06244       if (c)
06245          *c++ = '\0';
06246       /* Find the start */
06247       s = lookup_name(src, names, max);
06248       if (!s) {
06249          ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
06250          return 0;
06251       }
06252       s--;
06253       if (c) { /* find end of range */
06254          e = lookup_name(c, names, max);
06255          if (!e) {
06256             ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
06257             return 0;
06258          }
06259          e--;
06260       } else
06261          e = s;
06262    }
06263    /* Fill the mask. Remember that ranges are cyclic */
06264    mask = 1 << e; /* initialize with last element */
06265    while (s != e) {
06266       if (s >= max) {
06267          s = 0;
06268          mask |= (1 << s);
06269       } else {
06270          mask |= (1 << s);
06271          s++;
06272       }
06273    }
06274    return mask;
06275 }
06276 
06277 /*! \brief store a bitmask of valid times, one bit each 2 minute */
06278 static void get_timerange(struct ast_timing *i, char *times)
06279 {
06280    char *e;
06281    int x;
06282    int s1, s2;
06283    int e1, e2;
06284    /* int cth, ctm; */
06285 
06286    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
06287    memset(i->minmask, 0, sizeof(i->minmask));
06288 
06289    /* 2-minutes per bit, since the mask has only 32 bits :( */
06290    /* Star is all times */
06291    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
06292       for (x = 0; x < 24; x++)
06293          i->minmask[x] = 0x3fffffff; /* 30 bits */
06294       return;
06295    }
06296    /* Otherwise expect a range */
06297    e = strchr(times, '-');
06298    if (!e) {
06299       ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
06300       return;
06301    }
06302    *e++ = '\0';
06303    /* XXX why skip non digits ? */
06304    while (*e && !isdigit(*e))
06305       e++;
06306    if (!*e) {
06307       ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
06308       return;
06309    }
06310    if (sscanf(times, "%2d:%2d", &s1, &s2) != 2) {
06311       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
06312       return;
06313    }
06314    if (sscanf(e, "%2d:%2d", &e1, &e2) != 2) {
06315       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
06316       return;
06317    }
06318    /* XXX this needs to be optimized */
06319 #if 1
06320    s1 = s1 * 30 + s2/2;
06321    if ((s1 < 0) || (s1 >= 24*30)) {
06322       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
06323       return;
06324    }
06325    e1 = e1 * 30 + e2/2;
06326    if ((e1 < 0) || (e1 >= 24*30)) {
06327       ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
06328       return;
06329    }
06330    /* Go through the time and enable each appropriate bit */
06331    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
06332       i->minmask[x/30] |= (1 << (x % 30));
06333    }
06334    /* Do the last one */
06335    i->minmask[x/30] |= (1 << (x % 30));
06336 #else
06337    for (cth = 0; cth < 24; cth++) {
06338       /* Initialize masks to blank */
06339       i->minmask[cth] = 0;
06340       for (ctm = 0; ctm < 30; ctm++) {
06341          if (
06342          /* First hour with more than one hour */
06343                (((cth == s1) && (ctm >= s2)) &&
06344                 ((cth < e1)))
06345          /* Only one hour */
06346          ||    (((cth == s1) && (ctm >= s2)) &&
06347                 ((cth == e1) && (ctm <= e2)))
06348          /* In between first and last hours (more than 2 hours) */
06349          ||    ((cth > s1) &&
06350                 (cth < e1))
06351          /* Last hour with more than one hour */
06352          ||    ((cth > s1) &&
06353                 ((cth == e1) && (ctm <= e2)))
06354          )
06355             i->minmask[cth] |= (1 << (ctm / 2));
06356       }
06357    }
06358 #endif
06359    /* All done */
06360    return;
06361 }
06362 
06363 static char *days[] =
06364 {
06365    "sun",
06366    "mon",
06367    "tue",
06368    "wed",
06369    "thu",
06370    "fri",
06371    "sat",
06372    NULL,
06373 };
06374 
06375 static char *months[] =
06376 {
06377    "jan",
06378    "feb",
06379    "mar",
06380    "apr",
06381    "may",
06382    "jun",
06383    "jul",
06384    "aug",
06385    "sep",
06386    "oct",
06387    "nov",
06388    "dec",
06389    NULL,
06390 };
06391 
06392 int ast_build_timing(struct ast_timing *i, const char *info_in)
06393 {
06394    char info_save[256];
06395    char *info;
06396 
06397    /* Check for empty just in case */
06398    if (ast_strlen_zero(info_in))
06399       return 0;
06400    /* make a copy just in case we were passed a static string */
06401    ast_copy_string(info_save, info_in, sizeof(info_save));
06402    info = info_save;
06403    /* Assume everything except time */
06404    i->monthmask = 0xfff;   /* 12 bits */
06405    i->daymask = 0x7fffffffU; /* 31 bits */
06406    i->dowmask = 0x7f; /* 7 bits */
06407    /* on each call, use strsep() to move info to the next argument */
06408    get_timerange(i, strsep(&info, "|,"));
06409    if (info)
06410       i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
06411    if (info)
06412       i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
06413    if (info)
06414       i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
06415    return 1;
06416 }
06417 
06418 int ast_check_timing(const struct ast_timing *i)
06419 {
06420    struct ast_tm tm;
06421    struct timeval now = ast_tvnow();
06422 
06423    ast_localtime(&now, &tm, NULL);
06424 
06425    /* If it's not the right month, return */
06426    if (!(i->monthmask & (1 << tm.tm_mon)))
06427       return 0;
06428 
06429    /* If it's not that time of the month.... */
06430    /* Warning, tm_mday has range 1..31! */
06431    if (!(i->daymask & (1 << (tm.tm_mday-1))))
06432       return 0;
06433 
06434    /* If it's not the right day of the week */
06435    if (!(i->dowmask & (1 << tm.tm_wday)))
06436       return 0;
06437 
06438    /* Sanity check the hour just to be safe */
06439    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
06440       ast_log(LOG_WARNING, "Insane time...\n");
06441       return 0;
06442    }
06443 
06444    /* Now the tough part, we calculate if it fits
06445       in the right time based on min/hour */
06446    if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
06447       return 0;
06448 
06449    /* If we got this far, then we're good */
06450    return 1;
06451 }
06452 
06453 /*
06454  * errno values
06455  *  ENOMEM - out of memory
06456  *  EBUSY  - can't lock
06457  *  EEXIST - already included
06458  *  EINVAL - there is no existence of context for inclusion
06459  */
06460 int ast_context_add_include2(struct ast_context *con, const char *value,
06461    const char *registrar)
06462 {
06463    struct ast_include *new_include;
06464    char *c;
06465    struct ast_include *i, *il = NULL; /* include, include_last */
06466    int length;
06467    char *p;
06468 
06469    length = sizeof(struct ast_include);
06470    length += 2 * (strlen(value) + 1);
06471 
06472    /* allocate new include structure ... */
06473    if (!(new_include = ast_calloc(1, length)))
06474       return -1;
06475    /* Fill in this structure. Use 'p' for assignments, as the fields
06476     * in the structure are 'const char *'
06477     */
06478    p = new_include->stuff;
06479    new_include->name = p;
06480    strcpy(p, value);
06481    p += strlen(value) + 1;
06482    new_include->rname = p;
06483    strcpy(p, value);
06484    /* Strip off timing info, and process if it is there */
06485    if ( (c = strchr(p, ',')) ) {
06486       *c++ = '\0';
06487            new_include->hastime = ast_build_timing(&(new_include->timing), c);
06488    }
06489    new_include->next      = NULL;
06490    new_include->registrar = registrar;
06491 
06492    ast_wrlock_context(con);
06493 
06494    /* ... go to last include and check if context is already included too... */
06495    for (i = con->includes; i; i = i->next) {
06496       if (!strcasecmp(i->name, new_include->name)) {
06497          ast_free(new_include);
06498          ast_unlock_context(con);
06499          errno = EEXIST;
06500          return -1;
06501       }
06502       il = i;
06503    }
06504 
06505    /* ... include new context into context list, unlock, return */
06506    if (il)
06507       il->next = new_include;
06508    else
06509       con->includes = new_include;
06510    ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
06511 
06512    ast_unlock_context(con);
06513 
06514    return 0;
06515 }
06516 
06517 /*
06518  * errno values
06519  *  EBUSY  - can't lock
06520  *  ENOENT - no existence of context
06521  */
06522 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
06523 {
06524    int ret = -1;
06525    struct ast_context *c = find_context_locked(context);
06526 
06527    if (c) { /* found, add switch to this context */
06528       ret = ast_context_add_switch2(c, sw, data, eval, registrar);
06529       ast_unlock_contexts();
06530    }
06531    return ret;
06532 }
06533 
06534 /*
06535  * errno values
06536  *  ENOMEM - out of memory
06537  *  EBUSY  - can't lock
06538  *  EEXIST - already included
06539  *  EINVAL - there is no existence of context for inclusion
06540  */
06541 int ast_context_add_switch2(struct ast_context *con, const char *value,
06542    const char *data, int eval, const char *registrar)
06543 {
06544    struct ast_sw *new_sw;
06545    struct ast_sw *i;
06546    int length;
06547    char *p;
06548 
06549    length = sizeof(struct ast_sw);
06550    length += strlen(value) + 1;
06551    if (data)
06552       length += strlen(data);
06553    length++;
06554 
06555    /* allocate new sw structure ... */
06556    if (!(new_sw = ast_calloc(1, length)))
06557       return -1;
06558    /* ... fill in this structure ... */
06559    p = new_sw->stuff;
06560    new_sw->name = p;
06561    strcpy(new_sw->name, value);
06562    p += strlen(value) + 1;
06563    new_sw->data = p;
06564    if (data) {
06565       strcpy(new_sw->data, data);
06566       p += strlen(data) + 1;
06567    } else {
06568       strcpy(new_sw->data, "");
06569       p++;
06570    }
06571    new_sw->eval     = eval;
06572    new_sw->registrar = registrar;
06573 
06574    /* ... try to lock this context ... */
06575    ast_wrlock_context(con);
06576 
06577    /* ... go to last sw and check if context is already swd too... */
06578    AST_LIST_TRAVERSE(&con->alts, i, list) {
06579       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
06580          ast_free(new_sw);
06581          ast_unlock_context(con);
06582          errno = EEXIST;
06583          return -1;
06584       }
06585    }
06586 
06587    /* ... sw new context into context list, unlock, return */
06588    AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
06589 
06590    ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
06591 
06592    ast_unlock_context(con);
06593 
06594    return 0;
06595 }
06596 
06597 /*
06598  * EBUSY  - can't lock
06599  * ENOENT - there is not context existence
06600  */
06601 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
06602 {
06603    int ret = -1;
06604    struct ast_context *c = find_context_locked(context);
06605 
06606    if (c) {
06607       ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
06608       ast_unlock_contexts();
06609    }
06610    return ret;
06611 }
06612 
06613 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
06614 {
06615    struct ast_ignorepat *ip, *ipl = NULL;
06616 
06617    ast_wrlock_context(con);
06618 
06619    for (ip = con->ignorepats; ip; ip = ip->next) {
06620       if (!strcmp(ip->pattern, ignorepat) &&
06621          (!registrar || (registrar == ip->registrar))) {
06622          if (ipl) {
06623             ipl->next = ip->next;
06624             ast_free(ip);
06625          } else {
06626             con->ignorepats = ip->next;
06627             ast_free(ip);
06628          }
06629          ast_unlock_context(con);
06630          return 0;
06631       }
06632       ipl = ip;
06633    }
06634 
06635    ast_unlock_context(con);
06636    errno = EINVAL;
06637    return -1;
06638 }
06639 
06640 /*
06641  * EBUSY - can't lock
06642  * ENOENT - there is no existence of context
06643  */
06644 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
06645 {
06646    int ret = -1;
06647    struct ast_context *c = find_context_locked(context);
06648 
06649    if (c) {
06650       ret = ast_context_add_ignorepat2(c, value, registrar);
06651       ast_unlock_contexts();
06652    }
06653    return ret;
06654 }
06655 
06656 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
06657 {
06658    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
06659    int length;
06660    char *pattern;
06661    length = sizeof(struct ast_ignorepat);
06662    length += strlen(value) + 1;
06663    if (!(ignorepat = ast_calloc(1, length)))
06664       return -1;
06665    /* The cast to char * is because we need to write the initial value.
06666     * The field is not supposed to be modified otherwise.  Also, gcc 4.2
06667     * sees the cast as dereferencing a type-punned pointer and warns about
06668     * it.  This is the workaround (we're telling gcc, yes, that's really
06669     * what we wanted to do).
06670     */
06671    pattern = (char *) ignorepat->pattern;
06672    strcpy(pattern, value);
06673    ignorepat->next = NULL;
06674    ignorepat->registrar = registrar;
06675    ast_wrlock_context(con);
06676    for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
06677       ignorepatl = ignorepatc;
06678       if (!strcasecmp(ignorepatc->pattern, value)) {
06679          /* Already there */
06680          ast_unlock_context(con);
06681          errno = EEXIST;
06682          return -1;
06683       }
06684    }
06685    if (ignorepatl)
06686       ignorepatl->next = ignorepat;
06687    else
06688       con->ignorepats = ignorepat;
06689    ast_unlock_context(con);
06690    return 0;
06691 
06692 }
06693 
06694 int ast_ignore_pattern(const char *context, const char *pattern)
06695 {
06696    struct ast_context *con = ast_context_find(context);
06697    if (con) {
06698       struct ast_ignorepat *pat;
06699       for (pat = con->ignorepats; pat; pat = pat->next) {
06700          if (ast_extension_match(pat->pattern, pattern))
06701             return 1;
06702       }
06703    }
06704 
06705    return 0;
06706 }
06707 
06708 /*
06709  * ast_add_extension_nolock -- use only in situations where the conlock is already held
06710  * ENOENT  - no existence of context
06711  *
06712  */
06713 static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
06714    int priority, const char *label, const char *callerid,
06715    const char *application, void *data, void (*datad)(void *), const char *registrar)
06716 {
06717    int ret = -1;
06718    struct ast_context *c = find_context(context);
06719 
06720    if (c) {
06721       ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
06722          application, data, datad, registrar, 0, 0);
06723    }
06724    
06725    return ret;
06726 }
06727 /*
06728  * EBUSY   - can't lock
06729  * ENOENT  - no existence of context
06730  *
06731  */
06732 int ast_add_extension(const char *context, int replace, const char *extension,
06733    int priority, const char *label, const char *callerid,
06734    const char *application, void *data, void (*datad)(void *), const char *registrar)
06735 {
06736    int ret = -1;
06737    struct ast_context *c = find_context_locked(context);
06738 
06739    if (c) {
06740       ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
06741          application, data, datad, registrar);
06742       ast_unlock_contexts();
06743    }
06744    
06745    return ret;
06746 }
06747 
06748 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
06749 {
06750    if (!chan)
06751       return -1;
06752 
06753    ast_channel_lock(chan);
06754 
06755    if (!ast_strlen_zero(context))
06756       ast_copy_string(chan->context, context, sizeof(chan->context));
06757    if (!ast_strlen_zero(exten))
06758       ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06759    if (priority > -1) {
06760       chan->priority = priority;
06761       /* see flag description in channel.h for explanation */
06762       if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
06763          chan->priority--;
06764    }
06765 
06766    ast_channel_unlock(chan);
06767 
06768    return 0;
06769 }
06770 
06771 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
06772 {
06773    int res = 0;
06774 
06775    ast_channel_lock(chan);
06776 
06777    if (chan->pbx) { /* This channel is currently in the PBX */
06778       ast_explicit_goto(chan, context, exten, priority + 1);
06779       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
06780    } else {
06781       /* In order to do it when the channel doesn't really exist within
06782          the PBX, we have to make a new channel, masquerade, and start the PBX
06783          at the new location */
06784       struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
06785       if (!tmpchan) {
06786          res = -1;
06787       } else {
06788          if (chan->cdr) {
06789             ast_cdr_discard(tmpchan->cdr);
06790             tmpchan->cdr = ast_cdr_dup(chan->cdr);  /* share the love */
06791          }
06792          /* Make formats okay */
06793          tmpchan->readformat = chan->readformat;
06794          tmpchan->writeformat = chan->writeformat;
06795          /* Setup proper location */
06796          ast_explicit_goto(tmpchan,
06797             S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
06798 
06799          /* Masquerade into temp channel */
06800          if (ast_channel_masquerade(tmpchan, chan)) {
06801             /* Failed to set up the masquerade.  It's probably chan_local
06802              * in the middle of optimizing itself out.  Sad. :( */
06803             ast_hangup(tmpchan);
06804             tmpchan = NULL;
06805             res = -1;
06806          } else {
06807             /* Grab the locks and get going */
06808             ast_channel_lock(tmpchan);
06809             ast_do_masquerade(tmpchan);
06810             ast_channel_unlock(tmpchan);
06811             /* Start the PBX going on our stolen channel */
06812             if (ast_pbx_start(tmpchan)) {
06813                ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
06814                ast_hangup(tmpchan);
06815                res = -1;
06816             }
06817          }
06818       }
06819    }
06820    ast_channel_unlock(chan);
06821    return res;
06822 }
06823 
06824 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
06825 {
06826    struct ast_channel *chan;
06827    int res = -1;
06828 
06829    chan = ast_get_channel_by_name_locked(channame);
06830    if (chan) {
06831       res = ast_async_goto(chan, context, exten, priority);
06832       ast_channel_unlock(chan);
06833    }
06834    return res;
06835 }
06836 
06837 /*! \brief copy a string skipping whitespace */
06838 static int ext_strncpy(char *dst, const char *src, int len)
06839 {
06840    int count = 0;
06841 
06842    while (*src && (count < len - 1)) {
06843       switch (*src) {
06844       case ' ':
06845          /* otherwise exten => [a-b],1,... doesn't work */
06846          /*    case '-': */
06847          /* Ignore */
06848          break;
06849       default:
06850          *dst = *src;
06851          dst++;
06852       }
06853       src++;
06854       count++;
06855    }
06856    *dst = '\0';
06857 
06858    return count;
06859 }
06860 
06861 /*! 
06862  * \brief add the extension in the priority chain.
06863  * \retval 0 on success.
06864  * \retval -1 on failure.
06865 */
06866 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
06867    struct ast_exten *el, struct ast_exten *e, int replace)
06868 {
06869    return add_pri_lockopt(con, tmp, el, e, replace, 1);
06870 }
06871 
06872 /*! 
06873  * \brief add the extension in the priority chain.
06874  * \retval 0 on success.
06875  * \retval -1 on failure.
06876 */
06877 static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
06878    struct ast_exten *el, struct ast_exten *e, int replace, int lockhints)
06879 {
06880    struct ast_exten *ep;
06881    struct ast_exten *eh=e;
06882 
06883    for (ep = NULL; e ; ep = e, e = e->peer) {
06884       if (e->priority >= tmp->priority)
06885          break;
06886    }
06887    if (!e) {   /* go at the end, and ep is surely set because the list is not empty */
06888       ast_hashtab_insert_safe(eh->peer_table, tmp);
06889       
06890       if (tmp->label) {
06891          ast_hashtab_insert_safe(eh->peer_label_table, tmp);
06892       }
06893       ep->peer = tmp;
06894       return 0;   /* success */
06895    }
06896    if (e->priority == tmp->priority) {
06897       /* Can't have something exactly the same.  Is this a
06898          replacement?  If so, replace, otherwise, bonk. */
06899       if (!replace) {
06900          ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
06901          if (tmp->datad) {
06902             tmp->datad(tmp->data);
06903             /* if you free this, null it out */
06904             tmp->data = NULL;
06905          }
06906          
06907          ast_free(tmp);
06908          return -1;
06909       }
06910       /* we are replacing e, so copy the link fields and then update
06911        * whoever pointed to e to point to us
06912        */
06913       tmp->next = e->next; /* not meaningful if we are not first in the peer list */
06914       tmp->peer = e->peer; /* always meaningful */
06915       if (ep)  {     /* We're in the peer list, just insert ourselves */
06916          ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
06917 
06918          if (e->label) {
06919             ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
06920          }
06921          
06922          ast_hashtab_insert_safe(eh->peer_table,tmp);
06923          if (tmp->label) {
06924             ast_hashtab_insert_safe(eh->peer_label_table,tmp);
06925          }
06926          
06927          ep->peer = tmp;
06928       } else if (el) {     /* We're the first extension. Take over e's functions */
06929          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
06930          tmp->peer_table = e->peer_table;
06931          tmp->peer_label_table = e->peer_label_table;
06932          ast_hashtab_remove_object_via_lookup(tmp->peer_table,e);
06933          ast_hashtab_insert_safe(tmp->peer_table,tmp);
06934          if (e->label) {
06935             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
06936          }
06937          if (tmp->label) {
06938             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06939          }
06940          
06941          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06942          ast_hashtab_insert_safe(con->root_table, tmp);
06943          el->next = tmp;
06944          /* The pattern trie points to this exten; replace the pointer,
06945             and all will be well */
06946          if (x) { /* if the trie isn't formed yet, don't sweat this */
06947             if (x->exten) { /* this test for safety purposes */
06948                x->exten = tmp; /* replace what would become a bad pointer */
06949             } else {
06950                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
06951             }
06952          }
06953       } else {       /* We're the very first extension.  */
06954          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
06955          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06956          ast_hashtab_insert_safe(con->root_table, tmp);
06957          tmp->peer_table = e->peer_table;
06958          tmp->peer_label_table = e->peer_label_table;
06959          ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
06960          ast_hashtab_insert_safe(tmp->peer_table, tmp);
06961          if (e->label) {
06962             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
06963          }
06964          if (tmp->label) {
06965             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06966          }
06967          
06968          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06969          ast_hashtab_insert_safe(con->root_table, tmp);
06970          con->root = tmp;
06971          /* The pattern trie points to this exten; replace the pointer,
06972             and all will be well */
06973          if (x) { /* if the trie isn't formed yet; no problem */
06974             if (x->exten) { /* this test for safety purposes */
06975                x->exten = tmp; /* replace what would become a bad pointer */
06976             } else {
06977                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
06978             }
06979          }
06980       }
06981       if (tmp->priority == PRIORITY_HINT)
06982          ast_change_hint(e,tmp);
06983       /* Destroy the old one */
06984       if (e->datad)
06985          e->datad(e->data);
06986       ast_free(e);
06987    } else { /* Slip ourselves in just before e */
06988       tmp->peer = e;
06989       tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
06990       if (ep) {         /* Easy enough, we're just in the peer list */
06991          if (tmp->label) {
06992             ast_hashtab_insert_safe(eh->peer_label_table, tmp);
06993          }
06994          ast_hashtab_insert_safe(eh->peer_table, tmp);
06995          ep->peer = tmp;
06996       } else {       /* we are the first in some peer list, so link in the ext list */
06997          tmp->peer_table = e->peer_table;
06998          tmp->peer_label_table = e->peer_label_table;
06999          e->peer_table = 0;
07000          e->peer_label_table = 0;
07001          ast_hashtab_insert_safe(tmp->peer_table, tmp);
07002          if (tmp->label) {
07003             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07004          }
07005          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07006          ast_hashtab_insert_safe(con->root_table, tmp);
07007          if (el)
07008             el->next = tmp;   /* in the middle... */
07009          else
07010             con->root = tmp; /* ... or at the head */
07011          e->next = NULL;   /* e is no more at the head, so e->next must be reset */
07012       }
07013       /* And immediately return success. */
07014       if (tmp->priority == PRIORITY_HINT) {
07015          if (lockhints) {
07016             ast_add_hint(tmp);
07017          } else {
07018             ast_add_hint_nolock(tmp);
07019          }
07020       }
07021    }
07022    return 0;
07023 }
07024 
07025 /*! \brief
07026  * Main interface to add extensions to the list for out context.
07027  *
07028  * We sort extensions in order of matching preference, so that we can
07029  * stop the search as soon as we find a suitable match.
07030  * This ordering also takes care of wildcards such as '.' (meaning
07031  * "one or more of any character") and '!' (which is 'earlymatch',
07032  * meaning "zero or more of any character" but also impacts the
07033  * return value from CANMATCH and EARLYMATCH.
07034  *
07035  * The extension match rules defined in the devmeeting 2006.05.05 are
07036  * quite simple: WE SELECT THE LONGEST MATCH.
07037  * In detail, "longest" means the number of matched characters in
07038  * the extension. In case of ties (e.g. _XXX and 333) in the length
07039  * of a pattern, we give priority to entries with the smallest cardinality
07040  * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
07041  * while the latter has 7, etc.
07042  * In case of same cardinality, the first element in the range counts.
07043  * If we still have a tie, any final '!' will make this as a possibly
07044  * less specific pattern.
07045  *
07046  * EBUSY - can't lock
07047  * EEXIST - extension with the same priority exist and no replace is set
07048  *
07049  */
07050 int ast_add_extension2(struct ast_context *con,
07051    int replace, const char *extension, int priority, const char *label, const char *callerid,
07052    const char *application, void *data, void (*datad)(void *),
07053    const char *registrar)
07054 {
07055    return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1);
07056 }
07057 
07058 /*! \brief
07059  * Does all the work of ast_add_extension2, but adds two args, to determine if 
07060  * context and hint locking should be done. In merge_and_delete, we need to do
07061  * this without locking, as the locks are already held.
07062  */
07063 static int ast_add_extension2_lockopt(struct ast_context *con,
07064    int replace, const char *extension, int priority, const char *label, const char *callerid,
07065    const char *application, void *data, void (*datad)(void *),
07066    const char *registrar, int lockconts, int lockhints)
07067 {
07068    /*
07069     * Sort extensions (or patterns) according to the rules indicated above.
07070     * These are implemented by the function ext_cmp()).
07071     * All priorities for the same ext/pattern/cid are kept in a list,
07072     * using the 'peer' field  as a link field..
07073     */
07074    struct ast_exten *tmp, *tmp2, *e, *el = NULL;
07075    int res;
07076    int length;
07077    char *p;
07078    char expand_buf[VAR_BUF_SIZE];
07079    struct ast_exten dummy_exten = {0};
07080    char dummy_name[1024];
07081 
07082    if (ast_strlen_zero(extension)) {
07083       ast_log(LOG_ERROR,"You have to be kidding-- add exten '' to context %s? Figure out a name and call me back. Action ignored.\n",
07084             con->name);
07085       return -1;
07086    }
07087    
07088    /* If we are adding a hint evalulate in variables and global variables */
07089    if (priority == PRIORITY_HINT && strstr(application, "${") && !strstr(extension, "_")) {
07090       struct