Wed Aug 18 22:33:53 2010

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: 243489 $")
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, unsigned char *bitwise)
01698 {
01699    int c, cmin = 0xff, count = 0;
01700    const char *end;
01701 
01702    /* load value and advance pointer */
01703    c = *(*p)++;
01704 
01705    /* always return unless we have a set of chars */
01706    switch (toupper(c)) {
01707    default: /* ordinary character */
01708       bitwise[c / 8] = 1 << (c % 8);
01709       return 0x0100 | (c & 0xff);
01710 
01711    case 'N':   /* 2..9 */
01712       bitwise[6] = 0xfc;
01713       bitwise[7] = 0x03;
01714       return 0x0800 | '2';
01715 
01716    case 'X':   /* 0..9 */
01717       bitwise[6] = 0xff;
01718       bitwise[7] = 0x03;
01719       return 0x0A00 | '0';
01720 
01721    case 'Z':   /* 1..9 */
01722       bitwise[6] = 0xfe;
01723       bitwise[7] = 0x03;
01724       return 0x0900 | '1';
01725 
01726    case '.':   /* wildcard */
01727       return 0x10000;
01728 
01729    case '!':   /* earlymatch */
01730       return 0x20000;   /* less specific than NULL */
01731 
01732    case '\0':  /* empty string */
01733       *p = NULL;
01734       return 0x30000;
01735 
01736    case '[':   /* pattern */
01737       break;
01738    }
01739    /* locate end of set */
01740    end = strchr(*p, ']');  
01741 
01742    if (end == NULL) {
01743       ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
01744       return 0x40000;   /* XXX make this entry go last... */
01745    }
01746 
01747    for (; *p < end  ; (*p)++) {
01748       unsigned char c1, c2;   /* first-last char in range */
01749       c1 = (unsigned char)((*p)[0]);
01750       if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
01751          c2 = (unsigned char)((*p)[2]);
01752          *p += 2;    /* skip a total of 3 chars */
01753       } else {        /* individual character */
01754          c2 = c1;
01755       }
01756       if (c1 < cmin) {
01757          cmin = c1;
01758       }
01759       for (; c1 <= c2; c1++) {
01760          unsigned char mask = 1 << (c1 % 8);
01761          /*!\note If two patterns score the same, the one with the lowest
01762           * ascii values will compare as coming first. */
01763          /* Flag the character as included (used) and count it. */
01764          if (!(bitwise[ c1 / 8 ] & mask)) {
01765             bitwise[ c1 / 8 ] |= mask;
01766             count += 0x100;
01767          }
01768       }
01769    }
01770    (*p)++;
01771    return count == 0 ? 0x30000 : (count | cmin);
01772 }
01773 
01774 /*!
01775  * \brief the full routine to compare extensions in rules.
01776  */
01777 static int ext_cmp(const char *a, const char *b)
01778 {
01779    /* make sure non-patterns come first.
01780     * If a is not a pattern, it either comes first or
01781     * we do a more complex pattern comparison.
01782     */
01783    int ret = 0;
01784 
01785    if (a[0] != '_')
01786       return (b[0] == '_') ? -1 : strcmp(a, b);
01787 
01788    /* Now we know a is a pattern; if b is not, a comes first */
01789    if (b[0] != '_')
01790       return 1;
01791 
01792    /* ok we need full pattern sorting routine.
01793     * skip past the underscores */
01794    ++a; ++b;
01795    do {
01796       unsigned char bitwise[2][32] = { { 0, } };
01797       ret = ext_cmp1(&a, bitwise[0]) - ext_cmp1(&b, bitwise[1]);
01798       if (ret == 0) {
01799          /* Are the classes different, even though they score the same? */
01800          ret = memcmp(bitwise[0], bitwise[1], 32);
01801       }
01802    } while (!ret && a && b);
01803    if (ret == 0) {
01804       return 0;
01805    } else {
01806       return (ret > 0) ? 1 : -1;
01807    }
01808 }
01809 
01810 int ast_extension_cmp(const char *a, const char *b)
01811 {
01812    return ext_cmp(a, b);
01813 }
01814 
01815 /*!
01816  * \internal
01817  * \brief used ast_extension_{match|close}
01818  * mode is as follows:
01819  * E_MATCH     success only on exact match
01820  * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
01821  * E_CANMATCH  either of the above.
01822  * \retval 0 on no-match
01823  * \retval 1 on match
01824  * \retval 2 on early match.
01825  */
01826 
01827 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
01828 {
01829    mode &= E_MATCH_MASK;   /* only consider the relevant bits */
01830    
01831 #ifdef NEED_DEBUG_HERE
01832    ast_log(LOG_NOTICE,"match core: pat: '%s', dat: '%s', mode=%d\n", pattern, data, (int)mode);
01833 #endif
01834    
01835    if ( (mode == E_MATCH) && (pattern[0] == '_') && (!strcasecmp(pattern,data)) ) { /* note: if this test is left out, then _x. will not match _x. !!! */
01836 #ifdef NEED_DEBUG_HERE
01837       ast_log(LOG_NOTICE,"return (1) - pattern matches pattern\n");
01838 #endif
01839       return 1;
01840    }
01841 
01842    if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
01843       int ld = strlen(data), lp = strlen(pattern);
01844       
01845       if (lp < ld) {    /* pattern too short, cannot match */
01846 #ifdef NEED_DEBUG_HERE
01847          ast_log(LOG_NOTICE,"return (0) - pattern too short, cannot match\n");
01848 #endif
01849          return 0;
01850       }
01851       /* depending on the mode, accept full or partial match or both */
01852       if (mode == E_MATCH) {
01853 #ifdef NEED_DEBUG_HERE
01854          ast_log(LOG_NOTICE,"return (!strcmp(%s,%s) when mode== E_MATCH)\n", pattern, data);
01855 #endif
01856          return !strcmp(pattern, data); /* 1 on match, 0 on fail */
01857       } 
01858       if (ld == 0 || !strncasecmp(pattern, data, ld)) { /* partial or full match */
01859 #ifdef NEED_DEBUG_HERE
01860          ast_log(LOG_NOTICE,"return (mode(%d) == E_MATCHMORE ? lp(%d) > ld(%d) : 1)\n", mode, lp, ld);
01861 #endif
01862          return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
01863       } else {
01864 #ifdef NEED_DEBUG_HERE
01865          ast_log(LOG_NOTICE,"return (0) when ld(%d) > 0 && pattern(%s) != data(%s)\n", ld, pattern, data);
01866 #endif
01867          return 0;
01868       }
01869    }
01870    pattern++; /* skip leading _ */
01871    /*
01872     * XXX below we stop at '/' which is a separator for the CID info. However we should
01873     * not store '/' in the pattern at all. When we insure it, we can remove the checks.
01874     */
01875    while (*data && *pattern && *pattern != '/') {
01876       const char *end;
01877 
01878       if (*data == '-') { /* skip '-' in data (just a separator) */
01879          data++;
01880          continue;
01881       }
01882       switch (toupper(*pattern)) {
01883       case '[':   /* a range */
01884          end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
01885          if (end == NULL) {
01886             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
01887             return 0;   /* unconditional failure */
01888          }
01889          for (pattern++; pattern != end; pattern++) {
01890             if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
01891                if (*data >= pattern[0] && *data <= pattern[2])
01892                   break;   /* match found */
01893                else {
01894                   pattern += 2; /* skip a total of 3 chars */
01895                   continue;
01896                }
01897             } else if (*data == pattern[0])
01898                break;   /* match found */
01899          }
01900          if (pattern == end) {
01901 #ifdef NEED_DEBUG_HERE
01902             ast_log(LOG_NOTICE,"return (0) when pattern==end\n");
01903 #endif
01904             return 0;
01905          }
01906          pattern = end; /* skip and continue */
01907          break;
01908       case 'N':
01909          if (*data < '2' || *data > '9') {
01910 #ifdef NEED_DEBUG_HERE
01911             ast_log(LOG_NOTICE,"return (0) N is matched\n");
01912 #endif
01913             return 0;
01914          }
01915          break;
01916       case 'X':
01917          if (*data < '0' || *data > '9') {
01918 #ifdef NEED_DEBUG_HERE
01919             ast_log(LOG_NOTICE,"return (0) X is matched\n");
01920 #endif
01921             return 0;
01922          }
01923          break;
01924       case 'Z':
01925          if (*data < '1' || *data > '9') {
01926 #ifdef NEED_DEBUG_HERE
01927             ast_log(LOG_NOTICE,"return (0) Z is matched\n");
01928 #endif
01929             return 0;
01930          }
01931          break;
01932       case '.':   /* Must match, even with more digits */
01933 #ifdef NEED_DEBUG_HERE
01934          ast_log(LOG_NOTICE,"return (1) when '.' is matched\n");
01935 #endif
01936          return 1;
01937       case '!':   /* Early match */
01938 #ifdef NEED_DEBUG_HERE
01939          ast_log(LOG_NOTICE,"return (2) when '!' is matched\n");
01940 #endif
01941          return 2;
01942       case ' ':
01943       case '-':   /* Ignore these in patterns */
01944          data--; /* compensate the final data++ */
01945          break;
01946       default:
01947          if (*data != *pattern) {
01948 #ifdef NEED_DEBUG_HERE
01949             ast_log(LOG_NOTICE,"return (0) when *data(%c) != *pattern(%c)\n", *data, *pattern);
01950 #endif
01951             return 0;
01952          }
01953          
01954       }
01955       data++;
01956       pattern++;
01957    }
01958    if (*data)        /* data longer than pattern, no match */ {
01959 #ifdef NEED_DEBUG_HERE
01960       ast_log(LOG_NOTICE,"return (0) when data longer than pattern\n");
01961 #endif
01962       return 0;
01963    }
01964    
01965    /*
01966     * match so far, but ran off the end of the data.
01967     * Depending on what is next, determine match or not.
01968     */
01969    if (*pattern == '\0' || *pattern == '/') {   /* exact match */
01970 #ifdef NEED_DEBUG_HERE
01971       ast_log(LOG_NOTICE,"at end, return (%d) in 'exact match'\n", (mode==E_MATCHMORE) ? 0 : 1);
01972 #endif
01973       return (mode == E_MATCHMORE) ? 0 : 1;  /* this is a failure for E_MATCHMORE */
01974    } else if (*pattern == '!')   {     /* early match */
01975 #ifdef NEED_DEBUG_HERE
01976       ast_log(LOG_NOTICE,"at end, return (2) when '!' is matched\n");
01977 #endif
01978       return 2;
01979    } else {                /* partial match */
01980 #ifdef NEED_DEBUG_HERE
01981       ast_log(LOG_NOTICE,"at end, return (%d) which deps on E_MATCH\n", (mode == E_MATCH) ? 0 : 1);
01982 #endif
01983       return (mode == E_MATCH) ? 0 : 1;   /* this is a failure for E_MATCH */
01984    }
01985 }
01986 
01987 /*
01988  * Wrapper around _extension_match_core() to do performance measurement
01989  * using the profiling code.
01990  */
01991 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
01992 {
01993    int i;
01994    static int prof_id = -2;   /* marker for 'unallocated' id */
01995    if (prof_id == -2)
01996       prof_id = ast_add_profile("ext_match", 0);
01997    ast_mark(prof_id, 1);
01998    i = _extension_match_core(pattern, data, mode);
01999    ast_mark(prof_id, 0);
02000    return i;
02001 }
02002 
02003 int ast_extension_match(const char *pattern, const char *data)
02004 {
02005    return extension_match_core(pattern, data, E_MATCH);
02006 }
02007 
02008 int ast_extension_close(const char *pattern, const char *data, int needmore)
02009 {
02010    if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
02011       ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
02012    return extension_match_core(pattern, data, needmore);
02013 }
02014 
02015 struct fake_context /* this struct is purely for matching in the hashtab */
02016 {
02017    ast_rwlock_t lock;         
02018    struct ast_exten *root;    
02019    struct ast_hashtab *root_table;            
02020    struct match_char *pattern_tree;       
02021    struct ast_context *next;  
02022    struct ast_include *includes;    
02023    struct ast_ignorepat *ignorepats;   
02024    const char *registrar;
02025    int refcount;
02026    AST_LIST_HEAD_NOLOCK(, ast_sw) alts;   
02027    ast_mutex_t macrolock;     
02028    char name[256];      
02029 };
02030 
02031 struct ast_context *ast_context_find(const char *name)
02032 {
02033    struct ast_context *tmp = NULL;
02034    struct fake_context item;
02035 
02036    ast_copy_string(item.name, name, sizeof(item.name));
02037 
02038    ast_rdlock_contexts();
02039    if( contexts_table ) {
02040       tmp = ast_hashtab_lookup(contexts_table,&item);
02041    } else {
02042       while ( (tmp = ast_walk_contexts(tmp)) ) {
02043          if (!name || !strcasecmp(name, tmp->name))
02044             break;
02045       }
02046    }
02047    ast_unlock_contexts();
02048    return tmp;
02049 }
02050 
02051 #define STATUS_NO_CONTEXT  1
02052 #define STATUS_NO_EXTENSION   2
02053 #define STATUS_NO_PRIORITY 3
02054 #define STATUS_NO_LABEL    4
02055 #define STATUS_SUCCESS     5
02056 
02057 static int matchcid(const char *cidpattern, const char *callerid)
02058 {
02059    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
02060       failing to get a number should count as a match, otherwise not */
02061 
02062    if (ast_strlen_zero(callerid))
02063       return ast_strlen_zero(cidpattern) ? 1 : 0;
02064 
02065    return ast_extension_match(cidpattern, callerid);
02066 }
02067 
02068 struct ast_exten *pbx_find_extension(struct ast_channel *chan,
02069    struct ast_context *bypass, struct pbx_find_info *q,
02070    const char *context, const char *exten, int priority,
02071    const char *label, const char *callerid, enum ext_match_t action)
02072 {
02073    int x, res;
02074    struct ast_context *tmp = NULL;
02075    struct ast_exten *e = NULL, *eroot = NULL;
02076    struct ast_include *i = NULL;
02077    struct ast_sw *sw = NULL;
02078    struct ast_exten pattern = {NULL, };
02079    struct scoreboard score = {0, };
02080    struct ast_str *tmpdata = NULL;
02081 
02082    pattern.label = label;
02083    pattern.priority = priority;
02084 #ifdef NEED_DEBUG_HERE
02085    ast_log(LOG_NOTICE,"Looking for cont/ext/prio/label/action = %s/%s/%d/%s/%d\n", context, exten, priority, label, (int)action);
02086 #endif
02087 
02088    /* Initialize status if appropriate */
02089    if (q->stacklen == 0) {
02090       q->status = STATUS_NO_CONTEXT;
02091       q->swo = NULL;
02092       q->data = NULL;
02093       q->foundcontext = NULL;
02094    } else if (q->stacklen >= AST_PBX_MAX_STACK) {
02095       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
02096       return NULL;
02097    }
02098 
02099    /* Check first to see if we've already been checked */
02100    for (x = 0; x < q->stacklen; x++) {
02101       if (!strcasecmp(q->incstack[x], context))
02102          return NULL;
02103    }
02104 
02105    if (bypass) /* bypass means we only look there */
02106       tmp = bypass;
02107    else {   /* look in contexts */
02108       struct fake_context item;
02109 
02110       ast_copy_string(item.name, context, sizeof(item.name));
02111 
02112       tmp = ast_hashtab_lookup(contexts_table, &item);
02113 #ifdef NOTNOW
02114       tmp = NULL;
02115       while ((tmp = ast_walk_contexts(tmp)) ) {
02116          if (!strcmp(tmp->name, context))
02117             break;
02118       }
02119 #endif
02120       if (!tmp)
02121          return NULL;
02122       
02123    }
02124 
02125    if (q->status < STATUS_NO_EXTENSION)
02126       q->status = STATUS_NO_EXTENSION;
02127    
02128    /* Do a search for matching extension */
02129 
02130    eroot = NULL;
02131    score.total_specificity = 0;
02132    score.exten = 0;
02133    score.total_length = 0;
02134    if (!tmp->pattern_tree && tmp->root_table)
02135    {
02136       create_match_char_tree(tmp);
02137 #ifdef NEED_DEBUG
02138       ast_log(LOG_DEBUG,"Tree Created in context %s:\n", context);
02139       log_match_char_tree(tmp->pattern_tree," ");
02140 #endif
02141    }
02142 #ifdef NEED_DEBUG
02143    ast_log(LOG_NOTICE,"The Trie we are searching in:\n");
02144    log_match_char_tree(tmp->pattern_tree, "::  ");
02145 #endif
02146 
02147    do {
02148       if (!ast_strlen_zero(overrideswitch)) {
02149          char *osw = ast_strdupa(overrideswitch), *name;
02150          struct ast_switch *asw;
02151          ast_switch_f *aswf = NULL;
02152          char *datap;
02153          int eval = 0;
02154 
02155          name = strsep(&osw, "/");
02156          asw = pbx_findswitch(name);
02157 
02158          if (!asw) {
02159             ast_log(LOG_WARNING, "No such switch '%s'\n", name);
02160             break;
02161          }
02162 
02163          if (osw && strchr(osw, '$')) {
02164             eval = 1;
02165          }
02166 
02167          if (eval && !(tmpdata = ast_str_thread_get(&switch_data, 512))) {
02168             ast_log(LOG_WARNING, "Can't evaluate overrideswitch?!");
02169             break;
02170          } else if (eval) {
02171             /* Substitute variables now */
02172             pbx_substitute_variables_helper(chan, osw, tmpdata->str, tmpdata->len);
02173             datap = tmpdata->str;
02174          } else {
02175             datap = osw;
02176          }
02177 
02178          /* equivalent of extension_match_core() at the switch level */
02179          if (action == E_CANMATCH)
02180             aswf = asw->canmatch;
02181          else if (action == E_MATCHMORE)
02182             aswf = asw->matchmore;
02183          else /* action == E_MATCH */
02184             aswf = asw->exists;
02185          if (!aswf) {
02186             res = 0;
02187          } else {
02188             if (chan) {
02189                ast_autoservice_start(chan);
02190             }
02191             res = aswf(chan, context, exten, priority, callerid, datap);
02192             if (chan) {
02193                ast_autoservice_stop(chan);
02194             }
02195          }
02196          if (res) {  /* Got a match */
02197             q->swo = asw;
02198             q->data = datap;
02199             q->foundcontext = context;
02200             /* XXX keep status = STATUS_NO_CONTEXT ? */
02201             return NULL;
02202          }
02203       }
02204    } while (0);
02205 
02206    if (extenpatternmatchnew) {
02207       new_find_extension(exten, &score, tmp->pattern_tree, 0, 0, callerid, label, action);
02208       eroot = score.exten;
02209       
02210       if (score.last_char == '!' && action == E_MATCHMORE) {
02211          /* We match an extension ending in '!'.
02212           * The decision in this case is final and is NULL (no match).
02213           */
02214 #ifdef NEED_DEBUG_HERE
02215          ast_log(LOG_NOTICE,"Returning MATCHMORE NULL with exclamation point.\n");
02216 #endif
02217          return NULL;
02218       }
02219       
02220       if (!eroot && (action == E_CANMATCH || action == E_MATCHMORE) && score.canmatch_exten) {
02221          q->status = STATUS_SUCCESS;
02222 #ifdef NEED_DEBUG_HERE
02223          ast_log(LOG_NOTICE,"Returning CANMATCH exten %s\n", score.canmatch_exten->exten);
02224 #endif
02225          return score.canmatch_exten;
02226       }
02227       
02228       if ((action == E_MATCHMORE || action == E_CANMATCH)  && eroot) {
02229          if (score.node) {
02230             struct ast_exten *z = trie_find_next_match(score.node);
02231             if (z) {
02232 #ifdef NEED_DEBUG_HERE
02233                ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten %s\n", z->exten);
02234 #endif
02235             } else {
02236                if (score.canmatch_exten) {
02237 #ifdef NEED_DEBUG_HERE
02238                   ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE canmatchmatch exten %s(%p)\n", score.canmatch_exten->exten, score.canmatch_exten);
02239 #endif
02240                   return score.canmatch_exten;
02241                } else {
02242 #ifdef NEED_DEBUG_HERE
02243                   ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE next_match exten NULL\n");
02244 #endif
02245                }
02246             }
02247             return z;
02248          }
02249 #ifdef NEED_DEBUG_HERE
02250          ast_log(LOG_NOTICE,"Returning CANMATCH/MATCHMORE NULL (no next_match)\n");
02251 #endif
02252          return NULL;  /* according to the code, complete matches are null matches in MATCHMORE mode */
02253       }
02254       
02255       if (eroot) {
02256          /* found entry, now look for the right priority */
02257          if (q->status < STATUS_NO_PRIORITY)
02258             q->status = STATUS_NO_PRIORITY;
02259          e = NULL;
02260          if (action == E_FINDLABEL && label ) {
02261             if (q->status < STATUS_NO_LABEL)
02262                q->status = STATUS_NO_LABEL;
02263             e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
02264          } else {
02265             e = ast_hashtab_lookup(eroot->peer_table, &pattern);
02266          }
02267          if (e) { /* found a valid match */
02268             q->status = STATUS_SUCCESS;
02269             q->foundcontext = context;
02270 #ifdef NEED_DEBUG_HERE
02271             ast_log(LOG_NOTICE,"Returning complete match of exten %s\n", e->exten);
02272 #endif
02273             return e;
02274          }
02275       }
02276    } else {   /* the old/current default exten pattern match algorithm */
02277       
02278       /* scan the list trying to match extension and CID */
02279       eroot = NULL;
02280       while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
02281          int match = extension_match_core(eroot->exten, exten, action);
02282          /* 0 on fail, 1 on match, 2 on earlymatch */
02283          
02284          if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
02285             continue;   /* keep trying */
02286          if (match == 2 && action == E_MATCHMORE) {
02287             /* We match an extension ending in '!'.
02288              * The decision in this case is final and is NULL (no match).
02289              */
02290             return NULL;
02291          }
02292          /* found entry, now look for the right priority */
02293          if (q->status < STATUS_NO_PRIORITY)
02294             q->status = STATUS_NO_PRIORITY;
02295          e = NULL;
02296          if (action == E_FINDLABEL && label ) {
02297             if (q->status < STATUS_NO_LABEL)
02298                q->status = STATUS_NO_LABEL;
02299             e = ast_hashtab_lookup(eroot->peer_label_table, &pattern);
02300          } else {
02301             e = ast_hashtab_lookup(eroot->peer_table, &pattern);
02302          }
02303 #ifdef NOTNOW
02304          while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
02305             /* Match label or priority */
02306             if (action == E_FINDLABEL) {
02307                if (q->status < STATUS_NO_LABEL)
02308                   q->status = STATUS_NO_LABEL;
02309                if (label && e->label && !strcmp(label, e->label))
02310                   break;   /* found it */
02311             } else if (e->priority == priority) {
02312                break;   /* found it */
02313             } /* else keep searching */
02314          }
02315 #endif
02316          if (e) { /* found a valid match */
02317             q->status = STATUS_SUCCESS;
02318             q->foundcontext = context;
02319             return e;
02320          }
02321       }
02322    }
02323    
02324    
02325    /* Check alternative switches */
02326    AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
02327       struct ast_switch *asw = pbx_findswitch(sw->name);
02328       ast_switch_f *aswf = NULL;
02329       char *datap;
02330 
02331       if (!asw) {
02332          ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
02333          continue;
02334       }
02335       /* Substitute variables now */
02336       
02337       if (sw->eval) {
02338          if (!(tmpdata = ast_str_thread_get(&switch_data, 512))) {
02339             ast_log(LOG_WARNING, "Can't evaluate switch?!");
02340             continue;
02341          }
02342          pbx_substitute_variables_helper(chan, sw->data, tmpdata->str, tmpdata->len);
02343       }
02344 
02345       /* equivalent of extension_match_core() at the switch level */
02346       if (action == E_CANMATCH)
02347          aswf = asw->canmatch;
02348       else if (action == E_MATCHMORE)
02349          aswf = asw->matchmore;
02350       else /* action == E_MATCH */
02351          aswf = asw->exists;
02352       datap = sw->eval ? tmpdata->str : sw->data;
02353       if (!aswf)
02354          res = 0;
02355       else {
02356          if (chan)
02357             ast_autoservice_start(chan);
02358          res = aswf(chan, context, exten, priority, callerid, datap);
02359          if (chan)
02360             ast_autoservice_stop(chan);
02361       }
02362       if (res) {  /* Got a match */
02363          q->swo = asw;
02364          q->data = datap;
02365          q->foundcontext = context;
02366          /* XXX keep status = STATUS_NO_CONTEXT ? */
02367          return NULL;
02368       }
02369    }
02370    q->incstack[q->stacklen++] = tmp->name;   /* Setup the stack */
02371    /* Now try any includes we have in this context */
02372    for (i = tmp->includes; i; i = i->next) {
02373       if (include_valid(i)) {
02374          if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action))) {
02375 #ifdef NEED_DEBUG_HERE
02376             ast_log(LOG_NOTICE,"Returning recursive match of %s\n", e->exten);
02377 #endif
02378             return e;
02379          }
02380          if (q->swo)
02381             return NULL;
02382       }
02383    }
02384    return NULL;
02385 }
02386 
02387 /*! 
02388  * \brief extract offset:length from variable name.
02389  * \return 1 if there is a offset:length part, which is
02390  * trimmed off (values go into variables)
02391  */
02392 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
02393 {
02394    int parens = 0;
02395 
02396    *offset = 0;
02397    *length = INT_MAX;
02398    *isfunc = 0;
02399    for (; *var; var++) {
02400       if (*var == '(') {
02401          (*isfunc)++;
02402          parens++;
02403       } else if (*var == ')') {
02404          parens--;
02405       } else if (*var == ':' && parens == 0) {
02406          *var++ = '\0';
02407          sscanf(var, "%30d:%30d", offset, length);
02408          return 1; /* offset:length valid */
02409       }
02410    }
02411    return 0;
02412 }
02413 
02414 /*! 
02415  *\brief takes a substring. It is ok to call with value == workspace.
02416  * \param value
02417  * \param offset < 0 means start from the end of the string and set the beginning
02418  *   to be that many characters back.
02419  * \param length is the length of the substring, a value less than 0 means to leave
02420  * that many off the end.
02421  * \param workspace
02422  * \param workspace_len
02423  * Always return a copy in workspace.
02424  */
02425 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
02426 {
02427    char *ret = workspace;
02428    int lr;  /* length of the input string after the copy */
02429 
02430    ast_copy_string(workspace, value, workspace_len); /* always make a copy */
02431 
02432    lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
02433 
02434    /* Quick check if no need to do anything */
02435    if (offset == 0 && length >= lr) /* take the whole string */
02436       return ret;
02437 
02438    if (offset < 0)   {  /* translate negative offset into positive ones */
02439       offset = lr + offset;
02440       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
02441          offset = 0;
02442    }
02443 
02444    /* too large offset result in empty string so we know what to return */
02445    if (offset >= lr)
02446       return ret + lr;  /* the final '\0' */
02447 
02448    ret += offset;    /* move to the start position */
02449    if (length >= 0 && length < lr - offset)  /* truncate if necessary */
02450       ret[length] = '\0';
02451    else if (length < 0) {
02452       if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
02453          ret[lr + length - offset] = '\0';
02454       else
02455          ret[0] = '\0';
02456    }
02457 
02458    return ret;
02459 }
02460 
02461 /*! \brief  Support for Asterisk built-in variables in the dialplan
02462 
02463 \note See also
02464    - \ref AstVar  Channel variables
02465    - \ref AstCauses The HANGUPCAUSE variable
02466  */
02467 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
02468 {
02469    const char not_found = '\0';
02470    char *tmpvar;
02471    const char *s; /* the result */
02472    int offset, length;
02473    int i, need_substring;
02474    struct varshead *places[2] = { headp, &globals };  /* list of places where we may look */
02475 
02476    if (c) {
02477       ast_channel_lock(c);
02478       places[0] = &c->varshead;
02479    }
02480    /*
02481     * Make a copy of var because parse_variable_name() modifies the string.
02482     * Then if called directly, we might need to run substring() on the result;
02483     * remember this for later in 'need_substring', 'offset' and 'length'
02484     */
02485    tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
02486    need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
02487 
02488    /*
02489     * Look first into predefined variables, then into variable lists.
02490     * Variable 's' points to the result, according to the following rules:
02491     * s == &not_found (set at the beginning) means that we did not find a
02492     * matching variable and need to look into more places.
02493     * If s != &not_found, s is a valid result string as follows:
02494     * s = NULL if the variable does not have a value;
02495     * you typically do this when looking for an unset predefined variable.
02496     * s = workspace if the result has been assembled there;
02497     * typically done when the result is built e.g. with an snprintf(),
02498     * so we don't need to do an additional copy.
02499     * s != workspace in case we have a string, that needs to be copied
02500     * (the ast_copy_string is done once for all at the end).
02501     * Typically done when the result is already available in some string.
02502     */
02503    s = &not_found;   /* default value */
02504    if (c) { /* This group requires a valid channel */
02505       /* Names with common parts are looked up a piece at a time using strncmp. */
02506       if (!strncmp(var, "CALL", 4)) {
02507          if (!strncmp(var + 4, "ING", 3)) {
02508             if (!strcmp(var + 7, "PRES")) {        /* CALLINGPRES */
02509                snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
02510                s = workspace;
02511             } else if (!strcmp(var + 7, "ANI2")) {    /* CALLINGANI2 */
02512                snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
02513                s = workspace;
02514             } else if (!strcmp(var + 7, "TON")) {     /* CALLINGTON */
02515                snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
02516                s = workspace;
02517             } else if (!strcmp(var + 7, "TNS")) {     /* CALLINGTNS */
02518                snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
02519                s = workspace;
02520             }
02521          }
02522       } else if (!strcmp(var, "HINT")) {
02523          s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
02524       } else if (!strcmp(var, "HINTNAME")) {
02525          s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
02526       } else if (!strcmp(var, "EXTEN")) {
02527          s = c->exten;
02528       } else if (!strcmp(var, "CONTEXT")) {
02529          s = c->context;
02530       } else if (!strcmp(var, "PRIORITY")) {
02531          snprintf(workspace, workspacelen, "%d", c->priority);
02532          s = workspace;
02533       } else if (!strcmp(var, "CHANNEL")) {
02534          s = c->name;
02535       } else if (!strcmp(var, "UNIQUEID")) {
02536          s = c->uniqueid;
02537       } else if (!strcmp(var, "HANGUPCAUSE")) {
02538          snprintf(workspace, workspacelen, "%d", c->hangupcause);
02539          s = workspace;
02540       }
02541    }
02542    if (s == &not_found) { /* look for more */
02543       if (!strcmp(var, "EPOCH")) {
02544          snprintf(workspace, workspacelen, "%u",(int)time(NULL));
02545          s = workspace;
02546       } else if (!strcmp(var, "SYSTEMNAME")) {
02547          s = ast_config_AST_SYSTEM_NAME;
02548       } else if (!strcmp(var, "ENTITYID")) {
02549          ast_eid_to_str(workspace, workspacelen, &ast_eid_default);
02550          s = workspace;
02551       }
02552    }
02553    /* if not found, look into chanvars or global vars */
02554    for (i = 0; s == &not_found && i < ARRAY_LEN(places); i++) {
02555       struct ast_var_t *variables;
02556       if (!places[i])
02557          continue;
02558       if (places[i] == &globals)
02559          ast_rwlock_rdlock(&globalslock);
02560       AST_LIST_TRAVERSE(places[i], variables, entries) {
02561          if (!strcasecmp(ast_var_name(variables), var)) {
02562             s = ast_var_value(variables);
02563             break;
02564          }
02565       }
02566       if (places[i] == &globals)
02567          ast_rwlock_unlock(&globalslock);
02568    }
02569    if (s == &not_found || s == NULL)
02570       *ret = NULL;
02571    else {
02572       if (s != workspace)
02573          ast_copy_string(workspace, s, workspacelen);
02574       *ret = workspace;
02575       if (need_substring)
02576          *ret = substring(*ret, offset, length, workspace, workspacelen);
02577    }
02578 
02579    if (c)
02580       ast_channel_unlock(c);
02581 }
02582 
02583 static void exception_store_free(void *data)
02584 {
02585    struct pbx_exception *exception = data;
02586    ast_string_field_free_memory(exception);
02587    ast_free(exception);
02588 }
02589 
02590 static struct ast_datastore_info exception_store_info = {
02591    .type = "EXCEPTION",
02592    .destroy = exception_store_free,
02593 };
02594 
02595 int pbx_builtin_raise_exception(struct ast_channel *chan, void *vreason)
02596 {
02597    const char *reason = vreason;
02598    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
02599    struct pbx_exception *exception = NULL;
02600 
02601    if (!ds) {
02602       ds = ast_datastore_alloc(&exception_store_info, NULL);
02603       if (!ds)
02604          return -1;
02605       exception = ast_calloc(1, sizeof(struct pbx_exception));
02606       if (!exception) {
02607          ast_datastore_free(ds);
02608          return -1;
02609       }
02610       if (ast_string_field_init(exception, 128)) {
02611          ast_free(exception);
02612          ast_datastore_free(ds);
02613          return -1;
02614       }
02615       ds->data = exception;
02616       ast_channel_datastore_add(chan, ds);
02617    } else
02618       exception = ds->data;
02619 
02620    ast_string_field_set(exception, reason, reason);
02621    ast_string_field_set(exception, context, chan->context);
02622    ast_string_field_set(exception, exten, chan->exten);
02623    exception->priority = chan->priority;
02624    set_ext_pri(chan, "e", 0);
02625    return 0;
02626 }
02627 
02628 static int acf_exception_read(struct ast_channel *chan, const char *name, char *data, char *buf, size_t buflen)
02629 {
02630    struct ast_datastore *ds = ast_channel_datastore_find(chan, &exception_store_info, NULL);
02631    struct pbx_exception *exception = NULL;
02632    if (!ds || !ds->data)
02633       return -1;
02634    exception = ds->data;
02635    if (!strcasecmp(data, "REASON"))
02636       ast_copy_string(buf, exception->reason, buflen);
02637    else if (!strcasecmp(data, "CONTEXT"))
02638       ast_copy_string(buf, exception->context, buflen);
02639    else if (!strncasecmp(data, "EXTEN", 5))
02640       ast_copy_string(buf, exception->exten, buflen);
02641    else if (!strcasecmp(data, "PRIORITY"))
02642       snprintf(buf, buflen, "%d", exception->priority);
02643    else
02644       return -1;
02645    return 0;
02646 }
02647 
02648 static struct ast_custom_function exception_function = {
02649    .name = "EXCEPTION",
02650    .synopsis = "Retrieve the details of the current dialplan exception",
02651    .desc =
02652 "The following fields are available for retrieval:\n"
02653 "  reason    INVALID, ERROR, RESPONSETIMEOUT, ABSOLUTETIMEOUT, or custom\n"
02654 "               value set by the RaiseException() application\n"
02655 "  context   The context executing when the exception occurred\n"
02656 "  exten     The extension executing when the exception occurred\n"
02657 "  priority  The numeric priority executing when the exception occurred\n",
02658    .syntax = "EXCEPTION(<field>)",
02659    .read = acf_exception_read,
02660 };
02661 
02662 static char *handle_show_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02663 {
02664    struct ast_custom_function *acf;
02665    int count_acf = 0;
02666    int like = 0;
02667 
02668    switch (cmd) {
02669    case CLI_INIT:
02670       e->command = "core show functions [like]";
02671       e->usage = 
02672          "Usage: core show functions [like <text>]\n"
02673          "       List builtin functions, optionally only those matching a given string\n";
02674       return NULL;
02675    case CLI_GENERATE:
02676       return NULL;
02677    }
02678 
02679    if (a->argc == 5 && (!strcmp(a->argv[3], "like")) ) {
02680       like = 1;
02681    } else if (a->argc != 3) {
02682       return CLI_SHOWUSAGE;
02683    }
02684 
02685    ast_cli(a->fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
02686 
02687    AST_RWLIST_RDLOCK(&acf_root);
02688    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02689       if (!like || strstr(acf->name, a->argv[4])) {
02690          count_acf++;
02691          ast_cli(a->fd, "%-20.20s  %-35.35s  %s\n",
02692             S_OR(acf->name, ""),
02693             S_OR(acf->syntax, ""),
02694             S_OR(acf->synopsis, ""));
02695       }
02696    }
02697    AST_RWLIST_UNLOCK(&acf_root);
02698 
02699    ast_cli(a->fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
02700 
02701    return CLI_SUCCESS;
02702 }
02703 
02704 static char *handle_show_function(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
02705 {
02706    struct ast_custom_function *acf;
02707    /* Maximum number of characters added by terminal coloring is 22 */
02708    char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
02709    char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
02710    char stxtitle[40], *syntax = NULL;
02711    int synopsis_size, description_size, syntax_size;
02712    char *ret = NULL;
02713    int which = 0;
02714    int wordlen;
02715 
02716    switch (cmd) {
02717    case CLI_INIT:
02718       e->command = "core show function";
02719       e->usage = 
02720          "Usage: core show function <function>\n"
02721          "       Describe a particular dialplan function.\n";
02722       return NULL;
02723    case CLI_GENERATE:   
02724       wordlen = strlen(a->word);
02725       /* case-insensitive for convenience in this 'complete' function */
02726       AST_RWLIST_RDLOCK(&acf_root);
02727       AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02728          if (!strncasecmp(a->word, acf->name, wordlen) && ++which > a->n) {
02729             ret = ast_strdup(acf->name);
02730             break;
02731          }
02732       }
02733       AST_RWLIST_UNLOCK(&acf_root);
02734 
02735       return ret;
02736    }
02737 
02738    if (a->argc < 4)
02739       return CLI_SHOWUSAGE;
02740 
02741    if (!(acf = ast_custom_function_find(a->argv[3]))) {
02742       ast_cli(a->fd, "No function by that name registered.\n");
02743       return CLI_FAILURE;
02744 
02745    }
02746 
02747    if (acf->synopsis)
02748       synopsis_size = strlen(acf->synopsis) + 23;
02749    else
02750       synopsis_size = strlen("Not available") + 23;
02751    synopsis = alloca(synopsis_size);
02752 
02753    if (acf->desc)
02754       description_size = strlen(acf->desc) + 23;
02755    else
02756       description_size = strlen("Not available") + 23;
02757    description = alloca(description_size);
02758 
02759    if (acf->syntax)
02760       syntax_size = strlen(acf->syntax) + 23;
02761    else
02762       syntax_size = strlen("Not available") + 23;
02763    syntax = alloca(syntax_size);
02764 
02765    snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
02766    term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
02767    term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
02768    term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
02769    term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
02770    term_color(syntax,
02771          acf->syntax ? acf->syntax : "Not available",
02772          COLOR_CYAN, 0, syntax_size);
02773    term_color(synopsis,
02774          acf->synopsis ? acf->synopsis : "Not available",
02775          COLOR_CYAN, 0, synopsis_size);
02776    term_color(description,
02777          acf->desc ? acf->desc : "Not available",
02778          COLOR_CYAN, 0, description_size);
02779 
02780    ast_cli(a->fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
02781 
02782    return CLI_SUCCESS;
02783 }
02784 
02785 struct ast_custom_function *ast_custom_function_find(const char *name)
02786 {
02787    struct ast_custom_function *acf = NULL;
02788 
02789    AST_RWLIST_RDLOCK(&acf_root);
02790    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
02791       if (!strcmp(name, acf->name))
02792          break;
02793    }
02794    AST_RWLIST_UNLOCK(&acf_root);
02795 
02796    return acf;
02797 }
02798 
02799 int ast_custom_function_unregister(struct ast_custom_function *acf)
02800 {
02801    struct ast_custom_function *cur;
02802 
02803    if (!acf)
02804       return -1;
02805 
02806    AST_RWLIST_WRLOCK(&acf_root);
02807    if ((cur = AST_RWLIST_REMOVE(&acf_root, acf, acflist)))
02808       ast_verb(2, "Unregistered custom function %s\n", cur->name);
02809    AST_RWLIST_UNLOCK(&acf_root);
02810 
02811    return cur ? 0 : -1;
02812 }
02813 
02814 int __ast_custom_function_register(struct ast_custom_function *acf, struct ast_module *mod)
02815 {
02816    struct ast_custom_function *cur;
02817    char tmps[80];
02818 
02819    if (!acf)
02820       return -1;
02821 
02822    acf->mod = mod;
02823 
02824    AST_RWLIST_WRLOCK(&acf_root);
02825 
02826    AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
02827       if (!strcmp(acf->name, cur->name)) {
02828          ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
02829          AST_RWLIST_UNLOCK(&acf_root);
02830          return -1;
02831       }
02832    }
02833 
02834    /* Store in alphabetical order */
02835    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
02836       if (strcasecmp(acf->name, cur->name) < 0) {
02837          AST_RWLIST_INSERT_BEFORE_CURRENT(acf, acflist);
02838          break;
02839       }
02840    }
02841    AST_RWLIST_TRAVERSE_SAFE_END;
02842    if (!cur)
02843       AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
02844 
02845    AST_RWLIST_UNLOCK(&acf_root);
02846 
02847    ast_verb(2, "Registered custom function '%s'\n", term_color(tmps, acf->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02848 
02849    return 0;
02850 }
02851 
02852 /*! \brief return a pointer to the arguments of the function,
02853  * and terminates the function name with '\\0'
02854  */
02855 static char *func_args(char *function)
02856 {
02857    char *args = strchr(function, '(');
02858 
02859    if (!args)
02860       ast_log(LOG_WARNING, "Function '%s' doesn't contain parentheses.  Assuming null argument.\n", function);
02861    else {
02862       char *p;
02863       *args++ = '\0';
02864       if ((p = strrchr(args, ')')) )
02865          *p = '\0';
02866       else
02867          ast_log(LOG_WARNING, "Can't find trailing parenthesis for function '%s(%s'?\n", function, args);
02868    }
02869    return args;
02870 }
02871 
02872 int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
02873 {
02874    char *copy = ast_strdupa(function);
02875    char *args = func_args(copy);
02876    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02877 
02878    if (acfptr == NULL)
02879       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02880    else if (!acfptr->read)
02881       ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
02882    else {
02883       int res;
02884       struct ast_module_user *u = NULL;
02885       if (acfptr->mod)
02886          u = __ast_module_user_add(acfptr->mod, chan);
02887       res = acfptr->read(chan, copy, args, workspace, len);
02888       if (acfptr->mod && u)
02889          __ast_module_user_remove(acfptr->mod, u);
02890       return res;
02891    }
02892    return -1;
02893 }
02894 
02895 int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
02896 {
02897    char *copy = ast_strdupa(function);
02898    char *args = func_args(copy);
02899    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
02900 
02901    if (acfptr == NULL)
02902       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
02903    else if (!acfptr->write)
02904       ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
02905    else {
02906       int res;
02907       struct ast_module_user *u = NULL;
02908       if (acfptr->mod)
02909          u = __ast_module_user_add(acfptr->mod, chan);
02910       res = acfptr->write(chan, copy, args, value);
02911       if (acfptr->mod && u)
02912          __ast_module_user_remove(acfptr->mod, u);
02913       return res;
02914    }
02915 
02916    return -1;
02917 }
02918 
02919 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
02920 {
02921    /* Substitutes variables into cp2, based on string cp1, cp2 NO LONGER NEEDS TO BE ZEROED OUT!!!!  */
02922    char *cp4;
02923    const char *tmp, *whereweare;
02924    int length, offset, offset2, isfunction;
02925    char *workspace = NULL;
02926    char *ltmp = NULL, *var = NULL;
02927    char *nextvar, *nextexp, *nextthing;
02928    char *vars, *vare;
02929    int pos, brackets, needsub, len;
02930    
02931    *cp2 = 0; /* just in case nothing ends up there */
02932    whereweare=tmp=cp1;
02933    while (!ast_strlen_zero(whereweare) && count) {
02934       /* Assume we're copying the whole remaining string */
02935       pos = strlen(whereweare);
02936       nextvar = NULL;
02937       nextexp = NULL;
02938       nextthing = strchr(whereweare, '$');
02939       if (nextthing) {
02940          switch (nextthing[1]) {
02941          case '{':
02942             nextvar = nextthing;
02943             pos = nextvar - whereweare;
02944             break;
02945          case '[':
02946             nextexp = nextthing;
02947             pos = nextexp - whereweare;
02948             break;
02949          default:
02950             pos = 1;
02951          }
02952       }
02953 
02954       if (pos) {
02955          /* Can't copy more than 'count' bytes */
02956          if (pos > count)
02957             pos = count;
02958 
02959          /* Copy that many bytes */
02960          memcpy(cp2, whereweare, pos);
02961 
02962          count -= pos;
02963          cp2 += pos;
02964          whereweare += pos;
02965          *cp2 = 0;
02966       }
02967 
02968       if (nextvar) {
02969          /* We have a variable.  Find the start and end, and determine
02970             if we are going to have to recursively call ourselves on the
02971             contents */
02972          vars = vare = nextvar + 2;
02973          brackets = 1;
02974          needsub = 0;
02975 
02976          /* Find the end of it */
02977          while (brackets && *vare) {
02978             if ((vare[0] == '$') && (vare[1] == '{')) {
02979                needsub++;
02980             } else if (vare[0] == '{') {
02981                brackets++;
02982             } else if (vare[0] == '}') {
02983                brackets--;
02984             } else if ((vare[0] == '$') && (vare[1] == '['))
02985                needsub++;
02986             vare++;
02987          }
02988          if (brackets)
02989             ast_log(LOG_WARNING, "Error in extension logic (missing '}')\n");
02990          len = vare - vars - 1;
02991 
02992          /* Skip totally over variable string */
02993          whereweare += (len + 3);
02994 
02995          if (!var)
02996             var = alloca(VAR_BUF_SIZE);
02997 
02998          /* Store variable name (and truncate) */
02999          ast_copy_string(var, vars, len + 1);
03000 
03001          /* Substitute if necessary */
03002          if (needsub) {
03003             if (!ltmp)
03004                ltmp = alloca(VAR_BUF_SIZE);
03005 
03006             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
03007             vars = ltmp;
03008          } else {
03009             vars = var;
03010          }
03011 
03012          if (!workspace)
03013             workspace = alloca(VAR_BUF_SIZE);
03014 
03015          workspace[0] = '\0';
03016 
03017          parse_variable_name(vars, &offset, &offset2, &isfunction);
03018          if (isfunction) {
03019             /* Evaluate function */
03020             if (c || !headp)
03021                cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
03022             else {
03023                struct varshead old;
03024                struct ast_channel *bogus = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars);
03025                if (bogus) {
03026                   memcpy(&old, &bogus->varshead, sizeof(old));
03027                   memcpy(&bogus->varshead, headp, sizeof(bogus->varshead));
03028                   cp4 = ast_func_read(bogus, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
03029                   /* Don't deallocate the varshead that was passed in */
03030                   memcpy(&bogus->varshead, &old, sizeof(bogus->varshead));
03031                   ast_channel_free(bogus);
03032                } else
03033                   ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
03034             }
03035             ast_debug(2, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
03036          } else {
03037             /* Retrieve variable value */
03038             pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
03039          }
03040          if (cp4) {
03041             cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
03042 
03043             length = strlen(cp4);
03044             if (length > count)
03045                length = count;
03046             memcpy(cp2, cp4, length);
03047             count -= length;
03048             cp2 += length;
03049             *cp2 = 0;
03050          }
03051       } else if (nextexp) {
03052          /* We have an expression.  Find the start and end, and determine
03053             if we are going to have to recursively call ourselves on the
03054             contents */
03055          vars = vare = nextexp + 2;
03056          brackets = 1;
03057          needsub = 0;
03058 
03059          /* Find the end of it */
03060          while (brackets && *vare) {
03061             if ((vare[0] == '$') && (vare[1] == '[')) {
03062                needsub++;
03063                brackets++;
03064                vare++;
03065             } else if (vare[0] == '[') {
03066                brackets++;
03067             } else if (vare[0] == ']') {
03068                brackets--;
03069             } else if ((vare[0] == '$') && (vare[1] == '{')) {
03070                needsub++;
03071                vare++;
03072             }
03073             vare++;
03074          }
03075          if (brackets)
03076             ast_log(LOG_WARNING, "Error in extension logic (missing ']')\n");
03077          len = vare - vars - 1;
03078 
03079          /* Skip totally over expression */
03080          whereweare += (len + 3);
03081 
03082          if (!var)
03083             var = alloca(VAR_BUF_SIZE);
03084 
03085          /* Store variable name (and truncate) */
03086          ast_copy_string(var, vars, len + 1);
03087 
03088          /* Substitute if necessary */
03089          if (needsub) {
03090             if (!ltmp)
03091                ltmp = alloca(VAR_BUF_SIZE);
03092 
03093             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
03094             vars = ltmp;
03095          } else {
03096             vars = var;
03097          }
03098 
03099          length = ast_expr(vars, cp2, count, c);
03100 
03101          if (length) {
03102             ast_debug(1, "Expression result is '%s'\n", cp2);
03103             count -= length;
03104             cp2 += length;
03105             *cp2 = 0;
03106          }
03107       }
03108    }
03109 }
03110 
03111 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
03112 {
03113    pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
03114 }
03115 
03116 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
03117 {
03118    pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
03119 }
03120 
03121 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
03122 {
03123    const char *tmp;
03124 
03125    /* Nothing more to do */
03126    if (!e->data) {
03127       *passdata = '\0';
03128       return;
03129    }
03130 
03131    /* No variables or expressions in e->data, so why scan it? */
03132    if ((!(tmp = strchr(e->data, '$'))) || (!strstr(tmp, "${") && !strstr(tmp, "$["))) {
03133       ast_copy_string(passdata, e->data, datalen);
03134       return;
03135    }
03136 
03137    pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
03138 }
03139 
03140 /*! 
03141  * \brief The return value depends on the action:
03142  *
03143  * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
03144  * and return 0 on failure, -1 on match;
03145  * E_FINDLABEL maps the label to a priority, and returns
03146  * the priority on success, ... XXX
03147  * E_SPAWN, spawn an application,
03148  * 
03149  * \retval 0 on success.
03150  * \retval  -1 on failure.
03151  *
03152  * \note The channel is auto-serviced in this function, because doing an extension
03153  * match may block for a long time.  For example, if the lookup has to use a network
03154  * dialplan switch, such as DUNDi or IAX2, it may take a while.  However, the channel
03155  * auto-service code will queue up any important signalling frames to be processed
03156  * after this is done.
03157  */
03158 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
03159   const char *context, const char *exten, int priority,
03160   const char *label, const char *callerid, enum ext_match_t action, int *found, int combined_find_spawn)
03161 {
03162    struct ast_exten *e;
03163    struct ast_app *app;
03164    int res;
03165    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
03166    char passdata[EXT_DATA_SIZE];
03167 
03168    int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
03169 
03170    ast_rdlock_contexts();
03171    if (found)
03172       *found = 0;
03173 
03174    e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
03175    if (e) {
03176       if (found)
03177          *found = 1;
03178       if (matching_action) {
03179          ast_unlock_contexts();
03180          return -1;  /* success, we found it */
03181       } else if (action == E_FINDLABEL) { /* map the label to a priority */
03182          res = e->priority;
03183          ast_unlock_contexts();
03184          return res; /* the priority we were looking for */
03185       } else { /* spawn */
03186          if (!e->cached_app)
03187             e->cached_app = pbx_findapp(e->app);
03188          app = e->cached_app;
03189          ast_unlock_contexts();
03190          if (!app) {
03191             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
03192             return -1;
03193          }
03194          if (c->context != context)
03195             ast_copy_string(c->context, context, sizeof(c->context));
03196          if (c->exten != exten)
03197             ast_copy_string(c->exten, exten, sizeof(c->exten));
03198          c->priority = priority;
03199          pbx_substitute_variables(passdata, sizeof(passdata), c, e);
03200 #ifdef CHANNEL_TRACE
03201          ast_channel_trace_update(c);
03202 #endif
03203          ast_debug(1, "Launching '%s'\n", app->name);
03204          if (VERBOSITY_ATLEAST(3)) {
03205             char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
03206             ast_verb(3, "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
03207                exten, context, priority,
03208                term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
03209                term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
03210                term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
03211                "in new stack");
03212          }
03213          manager_event(EVENT_FLAG_DIALPLAN, "Newexten",
03214                "Channel: %s\r\n"
03215                "Context: %s\r\n"
03216                "Extension: %s\r\n"
03217                "Priority: %d\r\n"
03218                "Application: %s\r\n"
03219                "AppData: %s\r\n"
03220                "Uniqueid: %s\r\n",
03221                c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
03222          return pbx_exec(c, app, passdata);  /* 0 on success, -1 on failure */
03223       }
03224    } else if (q.swo) {  /* not found here, but in another switch */
03225       if (found)
03226          *found = 1;
03227       ast_unlock_contexts();
03228       if (matching_action) {
03229          return -1;
03230       } else {
03231          if (!q.swo->exec) {
03232             ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
03233             res = -1;
03234          }
03235          return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
03236       }
03237    } else { /* not found anywhere, see what happened */
03238       ast_unlock_contexts();
03239       /* Using S_OR here because Solaris doesn't like NULL being passed to ast_log */
03240       switch (q.status) {
03241       case STATUS_NO_CONTEXT:
03242          if (!matching_action && !combined_find_spawn)
03243             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", S_OR(context, ""));
03244          break;
03245       case STATUS_NO_EXTENSION:
03246          if (!matching_action && !combined_find_spawn)
03247             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, S_OR(context, ""));
03248          break;
03249       case STATUS_NO_PRIORITY:
03250          if (!matching_action && !combined_find_spawn)
03251             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, S_OR(context, ""));
03252          break;
03253       case STATUS_NO_LABEL:
03254          if (context && !combined_find_spawn)
03255             ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, S_OR(context, ""));
03256          break;
03257       default:
03258          ast_debug(1, "Shouldn't happen!\n");
03259       }
03260 
03261       return (matching_action) ? 0 : -1;
03262    }
03263 }
03264 
03265 /*! \brief Find hint for given extension in context */
03266 static struct ast_exten *ast_hint_extension_nolock(struct ast_channel *c, const char *context, const char *exten)
03267 {
03268    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
03269    return pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
03270 }
03271 
03272 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
03273 {
03274    struct ast_exten *e;
03275    ast_rdlock_contexts();
03276    e = ast_hint_extension_nolock(c, context, exten);
03277    ast_unlock_contexts();
03278    return e;
03279 }
03280 
03281 enum ast_extension_states ast_devstate_to_extenstate(enum ast_device_state devstate)
03282 {
03283    switch (devstate) {
03284    case AST_DEVICE_ONHOLD:
03285       return AST_EXTENSION_ONHOLD;
03286    case AST_DEVICE_BUSY:
03287       return AST_EXTENSION_BUSY;
03288    case AST_DEVICE_UNAVAILABLE:
03289    case AST_DEVICE_UNKNOWN:
03290    case AST_DEVICE_INVALID:
03291       return AST_EXTENSION_UNAVAILABLE;
03292    case AST_DEVICE_RINGINUSE:
03293       return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
03294    case AST_DEVICE_RINGING:
03295       return AST_EXTENSION_RINGING;
03296    case AST_DEVICE_INUSE:
03297       return AST_EXTENSION_INUSE;
03298    case AST_DEVICE_NOT_INUSE:
03299       return AST_EXTENSION_NOT_INUSE;
03300    case AST_DEVICE_TOTAL: /* not a device state, included for completeness */
03301       break;
03302    }
03303 
03304    return AST_EXTENSION_NOT_INUSE;
03305 }
03306 
03307 /*! \brief Check state of extension by using hints */
03308 static int ast_extension_state2(struct ast_exten *e)
03309 {
03310    char hint[AST_MAX_EXTENSION] = "";
03311    char *cur, *rest;
03312    struct ast_devstate_aggregate agg;
03313 
03314    if (!e)
03315       return -1;
03316 
03317    ast_devstate_aggregate_init(&agg);
03318 
03319    ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
03320 
03321    rest = hint;   /* One or more devices separated with a & character */
03322 
03323    while ( (cur = strsep(&rest, "&")) ) {
03324       ast_devstate_aggregate_add(&agg, ast_device_state(cur));
03325    }
03326 
03327    return ast_devstate_to_extenstate(ast_devstate_aggregate_result(&agg));
03328 }
03329 
03330 /*! \brief Return extension_state as string */
03331 const char *ast_extension_state2str(int extension_state)
03332 {
03333    int i;
03334 
03335    for (i = 0; (i < ARRAY_LEN(extension_states)); i++) {
03336       if (extension_states[i].extension_state == extension_state)
03337          return extension_states[i].text;
03338    }
03339    return "Unknown";
03340 }
03341 
03342 /*! \brief Check extension state for an extension by using hint */
03343 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
03344 {
03345    struct ast_exten *e;
03346 
03347    e = ast_hint_extension(c, context, exten);   /* Do we have a hint for this extension ? */
03348    if (!e)
03349       return -1;           /* No hint, return -1 */
03350 
03351    return ast_extension_state2(e);        /* Check all devices in the hint */
03352 }
03353 
03354 static int handle_statechange(void *datap)
03355 {
03356    struct ast_hint *hint;
03357    struct statechange *sc = datap;
03358 
03359    ast_rdlock_contexts();
03360    AST_RWLIST_RDLOCK(&hints);
03361 
03362    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03363       struct ast_state_cb *cblist;
03364       char buf[AST_MAX_EXTENSION];
03365       char *parse = buf;
03366       char *cur;
03367       int state;
03368 
03369       ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
03370       while ( (cur = strsep(&parse, "&")) ) {
03371          if (!strcasecmp(cur, sc->dev))
03372             break;
03373       }
03374       if (!cur)
03375          continue;
03376 
03377       /* Get device state for this hint */
03378       state = ast_extension_state2(hint->exten);
03379 
03380       if ((state == -1) || (state == hint->laststate))
03381          continue;
03382 
03383       /* Device state changed since last check - notify the watchers */
03384 
03385       /* For general callbacks */
03386       AST_LIST_TRAVERSE(&statecbs, cblist, entry) {
03387          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03388       }
03389 
03390       /* For extension callbacks */
03391       AST_LIST_TRAVERSE(&hint->callbacks, cblist, entry) {
03392          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
03393       }
03394 
03395       hint->laststate = state;   /* record we saw the change */
03396    }
03397    AST_RWLIST_UNLOCK(&hints);
03398    ast_unlock_contexts();
03399    ast_free(sc);
03400    return 0;
03401 }
03402 
03403 /*! \brief  Add watcher for extension states */
03404 int ast_extension_state_add(const char *context, const char *exten,
03405              ast_state_cb_type callback, void *data)
03406 {
03407    struct ast_hint *hint;
03408    struct ast_state_cb *cblist;
03409    struct ast_exten *e;
03410 
03411    /* If there's no context and extension:  add callback to statecbs list */
03412    if (!context && !exten) {
03413       AST_RWLIST_WRLOCK(&hints);
03414 
03415       AST_LIST_TRAVERSE(&statecbs, cblist, entry) {
03416          if (cblist->callback == callback) {
03417             cblist->data = data;
03418             AST_RWLIST_UNLOCK(&hints);
03419             return 0;
03420          }
03421       }
03422 
03423       /* Now insert the callback */
03424       if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
03425          AST_RWLIST_UNLOCK(&hints);
03426          return -1;
03427       }
03428       cblist->id = 0;
03429       cblist->callback = callback;
03430       cblist->data = data;
03431 
03432       AST_LIST_INSERT_HEAD(&statecbs, cblist, entry);
03433 
03434       AST_RWLIST_UNLOCK(&hints);
03435 
03436       return 0;
03437    }
03438 
03439    if (!context || !exten)
03440       return -1;
03441 
03442    /* This callback type is for only one hint, so get the hint */
03443    e = ast_hint_extension(NULL, context, exten);
03444    if (!e) {
03445       return -1;
03446    }
03447 
03448    /* If this is a pattern, dynamically create a new extension for this
03449     * particular match.  Note that this will only happen once for each
03450     * individual extension, because the pattern will no longer match first.
03451     */
03452    if (e->exten[0] == '_') {
03453       ast_add_extension(e->parent->name, 0, exten, e->priority, e->label,
03454          e->matchcid ? e->cidmatch : NULL, e->app, ast_strdup(e->data), ast_free_ptr,
03455          e->registrar);
03456       e = ast_hint_extension(NULL, context, exten);
03457       if (!e || e->exten[0] == '_') {
03458          return -1;
03459       }
03460    }
03461 
03462    /* Find the hint in the list of hints */
03463    AST_RWLIST_WRLOCK(&hints);
03464 
03465    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03466       if (hint->exten == e)
03467          break;
03468    }
03469 
03470    if (!hint) {
03471       /* We have no hint, sorry */
03472       AST_RWLIST_UNLOCK(&hints);
03473       return -1;
03474    }
03475 
03476    /* Now insert the callback in the callback list  */
03477    if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
03478       AST_RWLIST_UNLOCK(&hints);
03479       return -1;
03480    }
03481 
03482    cblist->id = stateid++;    /* Unique ID for this callback */
03483    cblist->callback = callback;  /* Pointer to callback routine */
03484    cblist->data = data;    /* Data for the callback */
03485 
03486    AST_LIST_INSERT_HEAD(&hint->callbacks, cblist, entry);
03487 
03488    AST_RWLIST_UNLOCK(&hints);
03489 
03490    return cblist->id;
03491 }
03492 
03493 /*! \brief Remove a watcher from the callback list */
03494 int ast_extension_state_del(int id, ast_state_cb_type callback)
03495 {
03496    struct ast_state_cb *p_cur = NULL;
03497    int ret = -1;
03498 
03499    if (!id && !callback)
03500       return -1;
03501 
03502    AST_RWLIST_WRLOCK(&hints);
03503 
03504    if (!id) {  /* id == 0 is a callback without extension */
03505       AST_LIST_TRAVERSE_SAFE_BEGIN(&statecbs, p_cur, entry) {
03506          if (p_cur->callback == callback) {
03507             AST_LIST_REMOVE_CURRENT(entry);
03508             break;
03509          }
03510       }
03511       AST_LIST_TRAVERSE_SAFE_END;
03512    } else { /* callback with extension, find the callback based on ID */
03513       struct ast_hint *hint;
03514       AST_RWLIST_TRAVERSE(&hints, hint, list) {
03515          AST_LIST_TRAVERSE_SAFE_BEGIN(&hint->callbacks, p_cur, entry) {
03516             if (p_cur->id == id) {
03517                AST_LIST_REMOVE_CURRENT(entry);
03518                break;
03519             }
03520          }
03521          AST_LIST_TRAVERSE_SAFE_END;
03522 
03523          if (p_cur)
03524             break;
03525       }
03526    }
03527 
03528    if (p_cur) {
03529       ast_free(p_cur);
03530    }
03531 
03532    AST_RWLIST_UNLOCK(&hints);
03533 
03534    return ret;
03535 }
03536 
03537 
03538 /*! \brief Add hint to hint list, check initial extension state; the hints had better be WRLOCKED already! */
03539 static int ast_add_hint_nolock(struct ast_exten *e)
03540 {
03541    struct ast_hint *hint;
03542 
03543    if (!e)
03544       return -1;
03545 
03546    /* Search if hint exists, do nothing */
03547    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03548       if (hint->exten == e) {
03549          ast_debug(2, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03550          return -1;
03551       }
03552    }
03553 
03554    ast_debug(2, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
03555 
03556    if (!(hint = ast_calloc(1, sizeof(*hint)))) {
03557       return -1;
03558    }
03559    /* Initialize and insert new item at the top */
03560    hint->exten = e;
03561    hint->laststate = ast_extension_state2(e);
03562    AST_RWLIST_INSERT_HEAD(&hints, hint, list);
03563 
03564    return 0;
03565 }
03566 
03567 /*! \brief Add hint to hint list, check initial extension state */
03568 static int ast_add_hint(struct ast_exten *e)
03569 {
03570    int ret;
03571 
03572    AST_RWLIST_WRLOCK(&hints);
03573    ret = ast_add_hint_nolock(e);
03574    AST_RWLIST_UNLOCK(&hints);
03575    
03576    return ret;
03577 }
03578 
03579 /*! \brief Change hint for an extension */
03580 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
03581 {
03582    struct ast_hint *hint;
03583    int res = -1;
03584 
03585    AST_RWLIST_WRLOCK(&hints);
03586    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03587       if (hint->exten == oe) {
03588             hint->exten = ne;
03589          res = 0;
03590          break;
03591       }
03592    }
03593    AST_RWLIST_UNLOCK(&hints);
03594 
03595    return res;
03596 }
03597 
03598 /*! \brief Remove hint from extension */
03599 static int ast_remove_hint(struct ast_exten *e)
03600 {
03601    /* Cleanup the Notifys if hint is removed */
03602    struct ast_hint *hint;
03603    struct ast_state_cb *cblist;
03604    int res = -1;
03605 
03606    if (!e)
03607       return -1;
03608 
03609    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
03610       if (hint->exten != e)
03611          continue;
03612 
03613       while ((cblist = AST_LIST_REMOVE_HEAD(&hint->callbacks, entry))) {
03614          /* Notify with -1 and remove all callbacks */
03615          cblist->callback(hint->exten->parent->name, hint->exten->exten, 
03616             AST_EXTENSION_DEACTIVATED, cblist->data);
03617          ast_free(cblist);
03618       }
03619 
03620       AST_RWLIST_REMOVE_CURRENT(list);
03621       ast_free(hint);
03622 
03623          res = 0;
03624 
03625       break;
03626    }
03627    AST_RWLIST_TRAVERSE_SAFE_END;
03628 
03629    return res;
03630 }
03631 
03632 
03633 /*! \brief Get hint for channel */
03634 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
03635 {
03636    struct ast_exten *e = ast_hint_extension(c, context, exten);
03637 
03638    if (e) {
03639       if (hint)
03640          ast_copy_string(hint, ast_get_extension_app(e), hintsize);
03641       if (name) {
03642          const char *tmp = ast_get_extension_app_data(e);
03643          if (tmp)
03644             ast_copy_string(name, tmp, namesize);
03645       }
03646       return -1;
03647    }
03648    return 0;
03649 }
03650 
03651 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
03652 {
03653    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH, 0, 0);
03654 }
03655 
03656 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
03657 {
03658    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03659 }
03660 
03661 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
03662 {
03663    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL, 0, 0);
03664 }
03665 
03666 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
03667 {
03668    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH, 0, 0);
03669 }
03670 
03671 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
03672 {
03673    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE, 0, 0);
03674 }
03675 
03676 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)
03677 {
03678    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN, found, combined_find_spawn);
03679 }
03680 
03681 /*! helper function to set extension and priority */
03682 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
03683 {
03684    ast_channel_lock(c);
03685    ast_copy_string(c->exten, exten, sizeof(c->exten));
03686    c->priority = pri;
03687    ast_channel_unlock(c);
03688 }
03689 
03690 /*!
03691  * \brief collect digits from the channel into the buffer.
03692  * \retval 0 on timeout or done.
03693  * \retval -1 on error.
03694 */
03695 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
03696 {
03697    int digit;
03698 
03699    buf[pos] = '\0';  /* make sure it is properly terminated */
03700    while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
03701       /* As long as we're willing to wait, and as long as it's not defined,
03702          keep reading digits until we can't possibly get a right answer anymore.  */
03703       digit = ast_waitfordigit(c, waittime);
03704       if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03705          c->_softhangup = 0;
03706       } else {
03707          if (!digit) /* No entry */
03708             break;
03709          if (digit < 0) /* Error, maybe a  hangup */
03710             return -1;
03711          if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
03712             buf[pos++] = digit;
03713             buf[pos] = '\0';
03714          }
03715          waittime = c->pbx->dtimeoutms;
03716       }
03717    }
03718    return 0;
03719 }
03720 
03721 static enum ast_pbx_result __ast_pbx_run(struct ast_channel *c, 
03722       struct ast_pbx_args *args)
03723 {
03724    int found = 0; /* set if we find at least one match */
03725    int res = 0;
03726    int autoloopflag;
03727    int error = 0;    /* set an error conditions */
03728 
03729    /* A little initial setup here */
03730    if (c->pbx) {
03731       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
03732       /* XXX and now what ? */
03733       ast_free(c->pbx);
03734    }
03735    if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
03736       return -1;
03737    /* Set reasonable defaults */
03738    c->pbx->rtimeoutms = 10000;
03739    c->pbx->dtimeoutms = 5000;
03740 
03741    autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);   /* save value to restore at the end */
03742    ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
03743 
03744    /* Start by trying whatever the channel is set to */
03745    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
03746       /* If not successful fall back to 's' */
03747       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);
03748       /* XXX the original code used the existing priority in the call to
03749        * ast_exists_extension(), and reset it to 1 afterwards.
03750        * I believe the correct thing is to set it to 1 immediately.
03751        */
03752       set_ext_pri(c, "s", 1);
03753       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
03754          /* JK02: And finally back to default if everything else failed */
03755          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);
03756          ast_copy_string(c->context, "default", sizeof(c->context));
03757       }
03758    }
03759    if (c->cdr) {
03760       /* allow CDR variables that have been collected after channel was created to be visible during call */
03761       ast_cdr_update(c);
03762    }
03763    for (;;) {
03764       char dst_exten[256]; /* buffer to accumulate digits */
03765       int pos = 0;      /* XXX should check bounds */
03766       int digit = 0;
03767       int invalid = 0;
03768       int timeout = 0;
03769 
03770       /* loop on priorities in this context/exten */
03771       while ( !(res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found,1))) {
03772          if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
03773             set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
03774             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03775             memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03776             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03777          } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03778             pbx_builtin_raise_exception(c, "ABSOLUTETIMEOUT");
03779             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03780             memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03781             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03782          } else if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03783             c->_softhangup = 0;
03784             continue;
03785          } else if (ast_check_hangup(c)) {
03786             ast_debug(1, "Extension %s, priority %d returned normally even though call was hung up\n",
03787                c->exten, c->priority);
03788             error = 1;
03789             break;
03790          }
03791          c->priority++;
03792       } /* end while  - from here on we can use 'break' to go out */
03793       if (found && res) {
03794          /* Something bad happened, or a hangup has been requested. */
03795          if (strchr("0123456789ABCDEF*#", res)) {
03796             ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
03797             pos = 0;
03798             dst_exten[pos++] = digit = res;
03799             dst_exten[pos] = '\0';
03800          } else if (res == AST_PBX_INCOMPLETE) {
03801             ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
03802             ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name);
03803 
03804             /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */
03805             if (!ast_matchmore_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
03806                invalid = 1;
03807             } else {
03808                ast_copy_string(dst_exten, c->exten, sizeof(dst_exten));
03809                digit = 1;
03810                pos = strlen(dst_exten);
03811             }
03812          } else {
03813             ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03814             ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03815             
03816             if ((res == AST_PBX_ERROR) && ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03817                /* if we are already on the 'e' exten, don't jump to it again */
03818                if (!strcmp(c->exten, "e")) {
03819                   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);
03820                   error = 1;
03821                } else {
03822                   pbx_builtin_raise_exception(c, "ERROR");
03823                   continue;
03824                }
03825             }
03826             
03827             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
03828                c->_softhangup = 0;
03829                continue;
03830             } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c, c->context, "T", 1, c->cid.cid_num)) {
03831                set_ext_pri(c, "T", 1); 
03832                /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
03833                memset(&c->whentohangup, 0, sizeof(c->whentohangup));
03834                c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
03835                continue;
03836             } else {
03837                if (c->cdr)
03838                   ast_cdr_update(c);
03839                error = 1;
03840                break;
03841             }
03842          }
03843       }
03844       if (error)
03845          break;
03846 
03847       /*!\note
03848        * We get here on a failure of some kind:  non-existing extension or
03849        * hangup.  We have options, here.  We can either catch the failure
03850        * and continue, or we can drop out entirely. */
03851 
03852       if (invalid || !ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
03853          /*!\note
03854           * If there is no match at priority 1, it is not a valid extension anymore.
03855           * Try to continue at "i" (for invalid) or "e" (for exception) or exit if
03856           * neither exist.
03857           */
03858          if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
03859             ast_verb(3, "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
03860             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
03861             set_ext_pri(c, "i", 1);
03862          } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03863             pbx_builtin_raise_exception(c, "INVALID");
03864          } else {
03865             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
03866                c->name, c->exten, c->context);
03867             error = 1; /* we know what to do with it */
03868             break;
03869          }
03870       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
03871          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
03872          c->_softhangup = 0;
03873       } else { /* keypress received, get more digits for a full extension */
03874          int waittime = 0;
03875          if (digit)
03876             waittime = c->pbx->dtimeoutms;
03877          else if (!autofallthrough)
03878             waittime = c->pbx->rtimeoutms;
03879          if (!waittime) {
03880             const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
03881             if (!status)
03882                status = "UNKNOWN";
03883             ast_verb(3, "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
03884             if (!strcasecmp(status, "CONGESTION"))
03885                res = pbx_builtin_congestion(c, "10");
03886             else if (!strcasecmp(status, "CHANUNAVAIL"))
03887                res = pbx_builtin_congestion(c, "10");
03888             else if (!strcasecmp(status, "BUSY"))
03889                res = pbx_builtin_busy(c, "10");
03890             error = 1; /* XXX disable message */
03891             break;   /* exit from the 'for' loop */
03892          }
03893 
03894          if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
03895             break;
03896          if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos]))
03897             timeout = 1;
03898          if (!timeout && ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
03899             set_ext_pri(c, dst_exten, 1);
03900          else {
03901             /* No such extension */
03902             if (!timeout && !ast_strlen_zero(dst_exten)) {
03903                /* An invalid extension */
03904                if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
03905                   ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
03906                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
03907                   set_ext_pri(c, "i", 1);
03908                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03909                   pbx_builtin_raise_exception(c, "INVALID");
03910                } else {
03911                   ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
03912                   found = 1; /* XXX disable message */
03913                   break;
03914                }
03915             } else {
03916                /* A simple timeout */
03917                if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
03918                   ast_verb(3, "Timeout on %s\n", c->name);
03919                   set_ext_pri(c, "t", 1);
03920                } else if (ast_exists_extension(c, c->context, "e", 1, c->cid.cid_num)) {
03921                   pbx_builtin_raise_exception(c, "RESPONSETIMEOUT");
03922                } else {
03923                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
03924                   found = 1; /* XXX disable message */
03925                   break;
03926                }
03927             }
03928          }
03929          if (c->cdr) {
03930             ast_verb(2, "CDR updated on %s\n",c->name);
03931             ast_cdr_update(c);
03932          }
03933       }
03934    }
03935 
03936    if (!found && !error) {
03937       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
03938    }
03939 
03940    if (!args || !args->no_hangup_chan) {
03941       ast_softhangup(c, AST_SOFTHANGUP_APPUNLOAD);
03942    }
03943 
03944    if ((!args || !args->no_hangup_chan) &&
03945          !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) && 
03946          ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
03947       set_ext_pri(c, "h", 1);
03948       if (c->cdr && ast_opt_end_cdr_before_h_exten) {
03949          ast_cdr_end(c->cdr);
03950       }
03951       while ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found, 1)) == 0) {
03952          c->priority++;
03953       }
03954       if (found && res) {
03955          /* Something bad happened, or a hangup has been requested. */
03956          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03957          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
03958       }
03959    }
03960    ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
03961    ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
03962    pbx_destroy(c->pbx);
03963    c->pbx = NULL;
03964 
03965    if (!args || !args->no_hangup_chan) {
03966       ast_hangup(c);
03967    }
03968 
03969    return 0;
03970 }
03971 
03972 /*! 
03973  * \brief Increase call count for channel
03974  * \retval 0 on success
03975  * \retval non-zero if a configured limit (maxcalls, maxload, minmemfree) was reached 
03976 */
03977 static int increase_call_count(const struct ast_channel *c)
03978 {
03979    int failed = 0;
03980    double curloadavg;
03981 #if defined(HAVE_SYSINFO)
03982    long curfreemem;
03983    struct sysinfo sys_info;
03984 #endif
03985 
03986    ast_mutex_lock(&maxcalllock);
03987    if (option_maxcalls) {
03988       if (countcalls >= option_maxcalls) {
03989          ast_log(LOG_WARNING, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
03990          failed = -1;
03991       }
03992    }
03993    if (option_maxload) {
03994       getloadavg(&curloadavg, 1);
03995       if (curloadavg >= option_maxload) {
03996          ast_log(LOG_WARNING, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
03997          failed = -1;
03998       }
03999    }
04000 #if defined(HAVE_SYSINFO)
04001    if (option_minmemfree) {
04002       if (!sysinfo(&sys_info)) {
04003          /* make sure that the free system memory is above the configured low watermark
04004           * convert the amount of freeram from mem_units to MB */
04005          curfreemem = sys_info.freeram / sys_info.mem_unit; 
04006          curfreemem /= 1024*1024; 
04007          if (curfreemem < option_minmemfree) {
04008             ast_log(LOG_WARNING, "Available system memory (~%ldMB) is below the configured low watermark (%ldMB)\n", curfreemem, option_minmemfree);
04009             failed = -1;
04010          }
04011       }
04012    }
04013 #endif
04014       
04015    if (!failed) {
04016       countcalls++;
04017       totalcalls++;
04018    }
04019    ast_mutex_unlock(&maxcalllock);
04020 
04021    return failed;
04022 }
04023 
04024 static void decrease_call_count(void)
04025 {
04026    ast_mutex_lock(&maxcalllock);
04027    if (countcalls > 0)
04028       countcalls--;
04029    ast_mutex_unlock(&maxcalllock);
04030 }
04031 
04032 static void destroy_exten(struct ast_exten *e)
04033 {
04034    if (e->priority == PRIORITY_HINT)
04035       ast_remove_hint(e);
04036 
04037    if (e->peer_table)
04038       ast_hashtab_destroy(e->peer_table,0);
04039    if (e->peer_label_table)
04040       ast_hashtab_destroy(e->peer_label_table, 0);
04041    if (e->datad)
04042       e->datad(e->data);
04043    ast_free(e);
04044 }
04045 
04046 static void *pbx_thread(void *data)
04047 {
04048    /* Oh joyeous kernel, we're a new thread, with nothing to do but
04049       answer this channel and get it going.
04050    */
04051    /* NOTE:
04052       The launcher of this function _MUST_ increment 'countcalls'
04053       before invoking the function; it will be decremented when the
04054       PBX has finished running on the channel
04055     */
04056    struct ast_channel *c = data;
04057 
04058    __ast_pbx_run(c, NULL);
04059    decrease_call_count();
04060 
04061    pthread_exit(NULL);
04062 
04063    return NULL;
04064 }
04065 
04066 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
04067 {
04068    pthread_t t;
04069 
04070    if (!c) {
04071       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
04072       return AST_PBX_FAILED;
04073    }
04074 
04075    if (increase_call_count(c))
04076       return AST_PBX_CALL_LIMIT;
04077 
04078    /* Start a new thread, and get something handling this channel. */
04079    if (ast_pthread_create_detached(&t, NULL, pbx_thread, c)) {
04080       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
04081       decrease_call_count();
04082       return AST_PBX_FAILED;
04083    }
04084 
04085    return AST_PBX_SUCCESS;
04086 }
04087 
04088 enum ast_pbx_result ast_pbx_run_args(struct ast_channel *c, struct ast_pbx_args *args)
04089 {
04090    enum ast_pbx_result res = AST_PBX_SUCCESS;
04091 
04092    if (increase_call_count(c)) {
04093       return AST_PBX_CALL_LIMIT;
04094    }
04095 
04096    res = __ast_pbx_run(c, args);
04097 
04098    decrease_call_count();
04099 
04100    return res;
04101 }
04102 
04103 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
04104 {
04105    return ast_pbx_run_args(c, NULL);
04106 }
04107 
04108 int ast_active_calls(void)
04109 {
04110    return countcalls;
04111 }
04112 
04113 int ast_processed_calls(void)
04114 {
04115    return totalcalls;
04116 }
04117 
04118 int pbx_set_autofallthrough(int newval)
04119 {
04120    int oldval = autofallthrough;
04121    autofallthrough = newval;
04122    return oldval;
04123 }
04124 
04125 int pbx_set_extenpatternmatchnew(int newval)
04126 {
04127    int oldval = extenpatternmatchnew;
04128    extenpatternmatchnew = newval;
04129    return oldval;
04130 }
04131 
04132 void pbx_set_overrideswitch(const char *newval)
04133 {
04134    if (overrideswitch) {
04135       ast_free(overrideswitch);
04136    }
04137    if (!ast_strlen_zero(newval)) {
04138       overrideswitch = ast_strdup(newval);
04139    } else {
04140       overrideswitch = NULL;
04141    }
04142 }
04143 
04144 /*!
04145  * \brief lookup for a context with a given name,
04146  * \retval found context or NULL if not found.
04147 */
04148 static struct ast_context *find_context(const char *context)
04149 {
04150    struct ast_context *c = NULL;
04151    struct fake_context item;
04152 
04153    ast_copy_string(item.name, context, sizeof(item.name));
04154 
04155    c = ast_hashtab_lookup(contexts_table,&item);
04156 
04157    return c;
04158 }
04159 
04160 /*!
04161  * \brief lookup for a context with a given name,
04162  * \retval with conlock held if found.
04163  * \retval NULL if not found.
04164 */
04165 static struct ast_context *find_context_locked(const char *context)
04166 {
04167    struct ast_context *c = NULL;
04168    struct fake_context item;
04169 
04170    ast_copy_string(item.name, context, sizeof(item.name));
04171 
04172    ast_rdlock_contexts();
04173    c = ast_hashtab_lookup(contexts_table,&item);
04174 
04175 #ifdef NOTNOW
04176 
04177    while ( (c = ast_walk_contexts(c)) ) {
04178       if (!strcmp(ast_get_context_name(c), context))
04179          return c;
04180    }
04181 #endif
04182    if (!c)
04183       ast_unlock_contexts();
04184 
04185    return c;
04186 }
04187 
04188 /*!
04189  * \brief Remove included contexts.
04190  * This function locks contexts list by &conlist, search for the right context
04191  * structure, leave context list locked and call ast_context_remove_include2
04192  * which removes include, unlock contexts list and return ...
04193 */
04194 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
04195 {
04196    int ret = -1;
04197    struct ast_context *c = find_context_locked(context);
04198 
04199    if (c) {
04200       /* found, remove include from this context ... */
04201       ret = ast_context_remove_include2(c, include, registrar);
04202       ast_unlock_contexts();
04203    }
04204    return ret;
04205 }
04206 
04207 /*!
04208  * \brief Locks context, remove included contexts, unlocks context.
04209  * When we call this function, &conlock lock must be locked, because when
04210  * we giving *con argument, some process can remove/change this context
04211  * and after that there can be segfault.
04212  *
04213  * \retval 0 on success.
04214  * \retval -1 on failure.
04215  */
04216 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
04217 {
04218    struct ast_include *i, *pi = NULL;
04219    int ret = -1;
04220 
04221    ast_wrlock_context(con);
04222 
04223    /* find our include */
04224    for (i = con->includes; i; pi = i, i = i->next) {
04225       if (!strcmp(i->name, include) &&
04226             (!registrar || !strcmp(i->registrar, registrar))) {
04227          /* remove from list */
04228          ast_verb(3, "Removing inclusion of context '%s' in context '%s; registrar=%s'\n", include, ast_get_context_name(con), registrar);
04229          if (pi)
04230             pi->next = i->next;
04231          else
04232             con->includes = i->next;
04233          /* free include and return */
04234          ast_free(i);
04235          ret = 0;
04236          break;
04237       }
04238    }
04239 
04240    ast_unlock_context(con);
04241 
04242    return ret;
04243 }
04244 
04245 /*!
04246  * \note This function locks contexts list by &conlist, search for the rigt context
04247  * structure, leave context list locked and call ast_context_remove_switch2
04248  * which removes switch, unlock contexts list and return ...
04249  */
04250 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
04251 {
04252    int ret = -1; /* default error return */
04253    struct ast_context *c = find_context_locked(context);
04254 
04255    if (c) {
04256       /* remove switch from this context ... */
04257       ret = ast_context_remove_switch2(c, sw, data, registrar);
04258       ast_unlock_contexts();
04259    }
04260    return ret;
04261 }
04262 
04263 /*!
04264  * \brief This function locks given context, removes switch, unlock context and
04265  * return.
04266  * \note When we call this function, &conlock lock must be locked, because when
04267  * we giving *con argument, some process can remove/change this context
04268  * and after that there can be segfault.
04269  *
04270  */
04271 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
04272 {
04273    struct ast_sw *i;
04274    int ret = -1;
04275 
04276    ast_wrlock_context(con);
04277 
04278    /* walk switches */
04279    AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
04280       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
04281          (!registrar || !strcmp(i->registrar, registrar))) {
04282          /* found, remove from list */
04283          ast_verb(3, "Removing switch '%s' from context '%s; registrar=%s'\n", sw, ast_get_context_name(con), registrar);
04284          AST_LIST_REMOVE_CURRENT(list);
04285          ast_free(i); /* free switch and return */
04286          ret = 0;
04287          break;
04288       }
04289    }
04290    AST_LIST_TRAVERSE_SAFE_END;
04291 
04292    ast_unlock_context(con);
04293 
04294    return ret;
04295 }
04296 
04297 /*
04298  * \note This functions lock contexts list, search for the right context,
04299  * call ast_context_remove_extension2, unlock contexts list and return.
04300  * In this function we are using
04301  */
04302 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
04303 {
04304    return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
04305 }
04306 
04307 int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcallerid, const char *registrar)
04308 {
04309    int ret = -1; /* default error return */
04310    struct ast_context *c = find_context_locked(context);
04311 
04312    if (c) { /* ... remove extension ... */
04313       ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcallerid, registrar, 1);
04314       ast_unlock_contexts();
04315    }
04316    return ret;
04317 }
04318 
04319 /*!
04320  * \brief This functionc locks given context, search for the right extension and
04321  * fires out all peer in this extensions with given priority. If priority
04322  * is set to 0, all peers are removed. After that, unlock context and
04323  * return.
04324  * \note When do you want to call this function, make sure that &conlock is locked,
04325  * because some process can handle with your *con context before you lock
04326  * it.
04327  *
04328  */
04329 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar, int already_locked)
04330 {
04331    return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar, already_locked);
04332 }
04333 
04334 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)
04335 {
04336    struct ast_exten *exten, *prev_exten = NULL;
04337    struct ast_exten *peer;
04338    struct ast_exten ex, *exten2, *exten3;
04339    char dummy_name[1024];
04340    struct ast_exten *previous_peer = NULL;
04341    struct ast_exten *next_peer = NULL;
04342    int found = 0;
04343 
04344    if (!already_locked)
04345       ast_wrlock_context(con);
04346 
04347    /* Handle this is in the new world */
04348 
04349    /* FIXME For backwards compatibility, if callerid==NULL, then remove ALL
04350     * peers, not just those matching the callerid. */
04351 #ifdef NEED_DEBUG
04352    ast_verb(3,"Removing %s/%s/%d%s%s from trees, registrar=%s\n", con->name, extension, priority, matchcallerid ? "/" : "", matchcallerid ? callerid : "", registrar);
04353 #endif
04354 #ifdef CONTEXT_DEBUG
04355    check_contexts(__FILE__, __LINE__);
04356 #endif
04357    /* find this particular extension */
04358    ex.exten = dummy_name;
04359    ex.matchcid = matchcallerid && !ast_strlen_zero(callerid); /* don't say match if there's no callerid */
04360    ex.cidmatch = callerid;
04361    ast_copy_string(dummy_name, extension, sizeof(dummy_name));
04362    exten = ast_hashtab_lookup(con->root_table, &ex);
04363    if (exten) {
04364       if (priority == 0) {
04365          exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04366          if (!exten2)
04367             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);
04368          if (con->pattern_tree) {
04369             
04370             struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04371             
04372             if (x->exten) { /* this test for safety purposes */
04373                x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
04374                x->exten = 0; /* get rid of what will become a bad pointer */
04375             } else {
04376                ast_log(LOG_WARNING,"Trying to delete an exten from a context, but the pattern tree node returned isn't a full extension\n");
04377             }
04378          }
04379       } else {
04380          ex.priority = priority;
04381          exten2 = ast_hashtab_lookup(exten->peer_table, &ex);
04382          if (exten2) {
04383             
04384             if (exten2->label) { /* if this exten has a label, remove that, too */
04385                exten3 = ast_hashtab_remove_this_object(exten->peer_label_table,exten2);
04386                if (!exten3)
04387                   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);
04388             }
04389          
04390             exten3 = ast_hashtab_remove_this_object(exten->peer_table, exten2);
04391             if (!exten3)
04392                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);
04393             if (exten2 == exten && exten2->peer) {
04394                exten2 = ast_hashtab_remove_this_object(con->root_table, exten);
04395                ast_hashtab_insert_immediate(con->root_table, exten2->peer);
04396             }
04397             if (ast_hashtab_size(exten->peer_table) == 0) {
04398                /* well, if the last priority of an exten is to be removed,
04399                   then, the extension is removed, too! */
04400                exten3 = ast_hashtab_remove_this_object(con->root_table, exten);
04401                if (!exten3)
04402                   ast_log(LOG_ERROR,"Did not remove this exten (%s) from the context root_table (%s) (priority %d)\n", exten->exten, con->name, priority);
04403                if (con->pattern_tree) {
04404                   struct match_char *x = add_exten_to_pattern_tree(con, exten, 1);
04405                   if (x->exten) { /* this test for safety purposes */
04406                      x->deleted = 1; /* with this marked as deleted, it will never show up in the scoreboard, and therefore never be found */
04407                      x->exten = 0; /* get rid of what will become a bad pointer */
04408                   }
04409                }
04410             }
04411          } else {
04412             ast_log(LOG_ERROR,"Could not find priority %d of exten %s in context %s!\n",
04413                   priority, exten->exten, con->name);
04414          }
04415       }
04416    } else {
04417       /* hmmm? this exten is not in this pattern tree? */
04418       ast_log(LOG_WARNING,"Cannot find extension %s in root_table in context %s\n",
04419             extension, con->name);
04420    }
04421 #ifdef NEED_DEBUG
04422    if (con->pattern_tree) {
04423       ast_log(LOG_NOTICE,"match char tree after exten removal:\n");
04424       log_match_char_tree(con->pattern_tree, " ");
04425    }
04426 #endif
04427 
04428    /* scan the extension list to find first matching extension-registrar */
04429    for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
04430       if (!strcmp(exten->exten, extension) &&
04431          (!registrar || !strcmp(exten->registrar, registrar)) &&
04432          (!matchcallerid || (!ast_strlen_zero(callerid) && !ast_strlen_zero(exten->cidmatch) && !strcmp(exten->cidmatch, callerid)) || (ast_strlen_zero(callerid) && ast_strlen_zero(exten->cidmatch))))
04433          break;
04434    }
04435    if (!exten) {
04436       /* we can't find right extension */
04437       if (!already_locked)
04438          ast_unlock_context(con);
04439       return -1;
04440    }
04441 
04442    /* scan the priority list to remove extension with exten->priority == priority */
04443    for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
04444        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)));
04445          peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
04446       if ((priority == 0 || peer->priority == priority) &&
04447             (!callerid || !matchcallerid || (matchcallerid && !strcmp(peer->cidmatch, callerid))) &&
04448             (!registrar || !strcmp(peer->registrar, registrar) )) {
04449          found = 1;
04450 
04451          /* we are first priority extension? */
04452          if (!previous_peer) {
04453             /*
04454              * We are first in the priority chain, so must update the extension chain.
04455              * The next node is either the next priority or the next extension
04456              */
04457             struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
04458             if (peer->peer) {
04459                /* move the peer_table and peer_label_table down to the next peer, if
04460                   it is there */
04461                peer->peer->peer_table = peer->peer_table;
04462                peer->peer->peer_label_table = peer->peer_label_table;
04463                peer->peer_table = NULL;
04464                peer->peer_label_table = NULL;
04465             }
04466             if (!prev_exten) {   /* change the root... */
04467                con->root = next_node;
04468             } else {
04469                prev_exten->next = next_node; /* unlink */
04470             }
04471             if (peer->peer)   { /* update the new head of the pri list */
04472                peer->peer->next = peer->next;
04473             }
04474          } else { /* easy, we are not first priority in extension */
04475             previous_peer->peer = peer->peer;
04476          }
04477 
04478          /* now, free whole priority extension */
04479          destroy_exten(peer);
04480       } else {
04481          previous_peer = peer;
04482       }
04483    }
04484    if (!already_locked)
04485       ast_unlock_context(con);
04486    return found ? 0 : -1;
04487 }
04488 
04489 
04490 /*!
04491  * \note This function locks contexts list by &conlist, searches for the right context
04492  * structure, and locks the macrolock mutex in that context.
04493  * macrolock is used to limit a macro to be executed by one call at a time.
04494  */
04495 int ast_context_lockmacro(const char *context)
04496 {
04497    struct ast_context *c = NULL;
04498    int ret = -1;
04499    struct fake_context item;
04500 
04501    ast_rdlock_contexts();
04502 
04503    ast_copy_string(item.name, context, sizeof(item.name));
04504 
04505    c = ast_hashtab_lookup(contexts_table,&item);
04506    if (c)
04507       ret = 0;
04508 
04509 
04510 #ifdef NOTNOW
04511 
04512    while ((c = ast_walk_contexts(c))) {
04513       if (!strcmp(ast_get_context_name(c), context)) {
04514          ret = 0;
04515          break;
04516       }
04517    }
04518 
04519 #endif
04520    ast_unlock_contexts();
04521 
04522    /* if we found context, lock macrolock */
04523    if (ret == 0) 
04524       ret = ast_mutex_lock(&c->macrolock);
04525 
04526    return ret;
04527 }
04528 
04529 /*!
04530  * \note This function locks contexts list by &conlist, searches for the right context
04531  * structure, and unlocks the macrolock mutex in that context.
04532  * macrolock is used to limit a macro to be executed by one call at a time.
04533  */
04534 int ast_context_unlockmacro(const char *context)
04535 {
04536    struct ast_context *c = NULL;
04537    int ret = -1;
04538    struct fake_context item;
04539 
04540    ast_rdlock_contexts();
04541 
04542    ast_copy_string(item.name, context, sizeof(item.name));
04543 
04544    c = ast_hashtab_lookup(contexts_table,&item);
04545    if (c)
04546       ret = 0;
04547 #ifdef NOTNOW
04548 
04549    while ((c = ast_walk_contexts(c))) {
04550       if (!strcmp(ast_get_context_name(c), context)) {
04551          ret = 0;
04552          break;
04553       }
04554    }
04555 
04556 #endif
04557    ast_unlock_contexts();
04558 
04559    /* if we found context, unlock macrolock */
04560    if (ret == 0) 
04561       ret = ast_mutex_unlock(&c->macrolock);
04562 
04563    return ret;
04564 }
04565 
04566 /*! \brief Dynamically register a new dial plan application */
04567 int ast_register_application2(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description, void *mod)
04568 {
04569    struct ast_app *tmp, *cur = NULL;
04570    char tmps[80];
04571    int length, res;
04572 
04573    AST_RWLIST_WRLOCK(&apps);
04574    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
04575       if (!(res = strcasecmp(app, tmp->name))) {
04576          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
04577          AST_RWLIST_UNLOCK(&apps);
04578          return -1;
04579       } else if (res < 0)
04580          break;
04581    }
04582 
04583    length = sizeof(*tmp) + strlen(app) + 1;
04584 
04585    if (!(tmp = ast_calloc(1, length))) {
04586       AST_RWLIST_UNLOCK(&apps);
04587       return -1;
04588    }
04589 
04590    strcpy(tmp->name, app);
04591    tmp->execute = execute;
04592    tmp->synopsis = synopsis;
04593    tmp->description = description;
04594    tmp->module = mod;
04595 
04596    /* Store in alphabetical order */
04597    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
04598       if (strcasecmp(tmp->name, cur->name) < 0) {
04599          AST_RWLIST_INSERT_BEFORE_CURRENT(tmp, list);
04600          break;
04601       }
04602    }
04603    AST_RWLIST_TRAVERSE_SAFE_END;
04604    if (!cur)
04605       AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
04606 
04607    ast_verb(2, "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
04608 
04609    AST_RWLIST_UNLOCK(&apps);
04610 
04611    return 0;
04612 }
04613 
04614 /*
04615  * Append to the list. We don't have a tail pointer because we need
04616  * to scan the list anyways to check for duplicates during insertion.
04617  */
04618 int ast_register_switch(struct ast_switch *sw)
04619 {
04620    struct ast_switch *tmp;
04621 
04622    AST_RWLIST_WRLOCK(&switches);
04623    AST_RWLIST_TRAVERSE(&switches, tmp, list) {
04624       if (!strcasecmp(tmp->name, sw->name)) {
04625          AST_RWLIST_UNLOCK(&switches);
04626          ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
04627          return -1;
04628       }
04629    }
04630    AST_RWLIST_INSERT_TAIL(&switches, sw, list);
04631    AST_RWLIST_UNLOCK(&switches);
04632 
04633    return 0;
04634 }
04635 
04636 void ast_unregister_switch(struct ast_switch *sw)
04637 {
04638    AST_RWLIST_WRLOCK(&switches);
04639    AST_RWLIST_REMOVE(&switches, sw, list);
04640    AST_RWLIST_UNLOCK(&switches);
04641 }
04642 
04643 /*
04644  * Help for CLI commands ...
04645  */
04646 
04647 /*
04648  * \brief 'show application' CLI command implementation function...
04649  */
04650 static char *handle_show_application(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04651 {
04652    struct ast_app *aa;
04653    int app, no_registered_app = 1;
04654    char *ret = NULL;
04655    int which = 0;
04656    int wordlen;
04657 
04658    switch (cmd) {
04659    case CLI_INIT: 
04660       e->command = "core show application";
04661       e->usage = 
04662          "Usage: core show application <application> [<application> [<application> [...]]]\n"
04663          "       Describes a particular application.\n";
04664       return NULL;
04665    case CLI_GENERATE:
04666       /*
04667        * There is a possibility to show informations about more than one
04668        * application at one time. You can type 'show application Dial Echo' and
04669        * you will see informations about these two applications ...
04670        */
04671       wordlen = strlen(a->word);
04672       /* return the n-th [partial] matching entry */
04673       AST_RWLIST_RDLOCK(&apps);
04674       AST_RWLIST_TRAVERSE(&apps, aa, list) {
04675          if (!strncasecmp(a->word, aa->name, wordlen) && ++which > a->n) {
04676             ret = ast_strdup(aa->name);
04677             break;
04678          }
04679       }
04680       AST_RWLIST_UNLOCK(&apps);
04681 
04682       return ret;
04683    }
04684 
04685    if (a->argc < 4)
04686       return CLI_SHOWUSAGE;
04687 
04688    /* ... go through all applications ... */
04689    AST_RWLIST_RDLOCK(&apps);
04690    AST_RWLIST_TRAVERSE(&apps, aa, list) {
04691       /* ... compare this application name with all arguments given
04692        * to 'show application' command ... */
04693       for (app = 3; app < a->argc; app++) {
04694          if (!strcasecmp(aa->name, a->argv[app])) {
04695             /* Maximum number of characters added by terminal coloring is 22 */
04696             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
04697             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
04698             int synopsis_size, description_size;
04699 
04700             no_registered_app = 0;
04701 
04702             if (aa->synopsis)
04703                synopsis_size = strlen(aa->synopsis) + 23;
04704             else
04705                synopsis_size = strlen("Not available") + 23;
04706             synopsis = alloca(synopsis_size);
04707 
04708             if (aa->description)
04709                description_size = strlen(aa->description) + 23;
04710             else
04711                description_size = strlen("Not available") + 23;
04712             description = alloca(description_size);
04713 
04714             if (synopsis && description) {
04715                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", aa->name);
04716                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
04717                term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
04718                term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
04719                term_color(synopsis,
04720                            aa->synopsis ? aa->synopsis : "Not available",
04721                            COLOR_CYAN, 0, synopsis_size);
04722                term_color(description,
04723                            aa->description ? aa->description : "Not available",
04724                            COLOR_CYAN, 0, description_size);
04725 
04726                ast_cli(a->fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
04727             } else {
04728                /* ... one of our applications, show info ...*/
04729                ast_cli(a->fd,"\n  -= Info about application '%s' =- \n\n"
04730                   "[Synopsis]\n  %s\n\n"
04731                   "[Description]\n%s\n",
04732                   aa->name,
04733                   aa->synopsis ? aa->synopsis : "Not available",
04734                   aa->description ? aa->description : "Not available");
04735             }
04736          }
04737       }
04738    }
04739    AST_RWLIST_UNLOCK(&apps);
04740 
04741    /* we found at least one app? no? */
04742    if (no_registered_app) {
04743       ast_cli(a->fd, "Your application(s) is (are) not registered\n");
04744       return CLI_FAILURE;
04745    }
04746 
04747    return CLI_SUCCESS;
04748 }
04749 
04750 /*! \brief  handle_show_hints: CLI support for listing registered dial plan hints */
04751 static char *handle_show_hints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04752 {
04753    struct ast_hint *hint;
04754    int num = 0;
04755    int watchers;
04756    struct ast_state_cb *watcher;
04757 
04758    switch (cmd) {
04759    case CLI_INIT:
04760       e->command = "core show hints";
04761       e->usage = 
04762          "Usage: core show hints\n"
04763          "       List registered hints\n";
04764       return NULL;
04765    case CLI_GENERATE:
04766       return NULL;   
04767    }
04768 
04769    AST_RWLIST_RDLOCK(&hints);
04770    if (AST_RWLIST_EMPTY(&hints)) {
04771       ast_cli(a->fd, "There are no registered dialplan hints\n");
04772       AST_RWLIST_UNLOCK(&hints);
04773       return CLI_SUCCESS;
04774    }
04775    /* ... we have hints ... */
04776    ast_cli(a->fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
04777    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04778       watchers = 0;
04779       AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
04780          watchers++;
04781       }
04782       ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
04783          ast_get_extension_name(hint->exten),
04784          ast_get_context_name(ast_get_extension_context(hint->exten)),
04785          ast_get_extension_app(hint->exten),
04786          ast_extension_state2str(hint->laststate), watchers);
04787       num++;
04788    }
04789    ast_cli(a->fd, "----------------\n");
04790    ast_cli(a->fd, "- %d hints registered\n", num);
04791    AST_RWLIST_UNLOCK(&hints);
04792    return CLI_SUCCESS;
04793 }
04794 
04795 /*! \brief autocomplete for CLI command 'core show hint' */
04796 static char *complete_core_show_hint(const char *line, const char *word, int pos, int state)
04797 {
04798    struct ast_hint *hint;
04799    char *ret = NULL;
04800    int which = 0;
04801    int wordlen;
04802 
04803    if (pos != 3)
04804       return NULL;
04805    
04806    wordlen = strlen(word);
04807 
04808    AST_RWLIST_RDLOCK(&hints);
04809    /* walk through all hints */
04810    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04811       if (!strncasecmp(word, ast_get_extension_name(hint->exten), wordlen) && ++which > state) {
04812          ret = ast_strdup(ast_get_extension_name(hint->exten));
04813          break;
04814       }
04815    }
04816    AST_RWLIST_UNLOCK(&hints);
04817 
04818    return ret;
04819 }
04820 
04821 /*! \brief  handle_show_hint: CLI support for listing registered dial plan hint */
04822 static char *handle_show_hint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04823 {
04824    struct ast_hint *hint;
04825    int watchers;
04826    int num = 0, extenlen;
04827    struct ast_state_cb *watcher;
04828 
04829    switch (cmd) {
04830    case CLI_INIT:
04831       e->command = "core show hint";
04832       e->usage =
04833          "Usage: core show hint <exten>\n"
04834          "       List registered hint\n";
04835       return NULL;
04836    case CLI_GENERATE:
04837       return complete_core_show_hint(a->line, a->word, a->pos, a->n);
04838    }
04839 
04840    if (a->argc < 4)
04841       return CLI_SHOWUSAGE;
04842 
04843    AST_RWLIST_RDLOCK(&hints);
04844    if (AST_RWLIST_EMPTY(&hints)) {
04845       ast_cli(a->fd, "There are no registered dialplan hints\n");
04846       AST_RWLIST_UNLOCK(&hints);
04847       return CLI_SUCCESS;
04848    }
04849    extenlen = strlen(a->argv[3]);
04850    AST_RWLIST_TRAVERSE(&hints, hint, list) {
04851       if (!strncasecmp(ast_get_extension_name(hint->exten), a->argv[3], extenlen)) {
04852          watchers = 0;
04853          AST_LIST_TRAVERSE(&hint->callbacks, watcher, entry) {
04854             watchers++;
04855          }
04856          ast_cli(a->fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
04857             ast_get_extension_name(hint->exten),
04858             ast_get_context_name(ast_get_extension_context(hint->exten)),
04859             ast_get_extension_app(hint->exten),
04860             ast_extension_state2str(hint->laststate), watchers);
04861          num++;
04862       }
04863    }
04864    AST_RWLIST_UNLOCK(&hints);
04865    if (!num)
04866       ast_cli(a->fd, "No hints matching extension %s\n", a->argv[3]);
04867    else
04868       ast_cli(a->fd, "%d hint%s matching extension %s\n", num, (num!=1 ? "s":""), a->argv[3]);
04869    return CLI_SUCCESS;
04870 }
04871 
04872 
04873 /*! \brief  handle_show_switches: CLI support for listing registered dial plan switches */
04874 static char *handle_show_switches(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04875 {
04876    struct ast_switch *sw;
04877 
04878    switch (cmd) {
04879    case CLI_INIT:
04880       e->command = "core show switches";
04881       e->usage = 
04882          "Usage: core show switches\n"
04883          "       List registered switches\n";
04884       return NULL;
04885    case CLI_GENERATE:
04886       return NULL;   
04887    }
04888 
04889    AST_RWLIST_RDLOCK(&switches);
04890 
04891    if (AST_RWLIST_EMPTY(&switches)) {
04892       AST_RWLIST_UNLOCK(&switches);
04893       ast_cli(a->fd, "There are no registered alternative switches\n");
04894       return CLI_SUCCESS;
04895    }
04896 
04897    ast_cli(a->fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
04898    AST_RWLIST_TRAVERSE(&switches, sw, list)
04899       ast_cli(a->fd, "%s: %s\n", sw->name, sw->description);
04900 
04901    AST_RWLIST_UNLOCK(&switches);
04902 
04903    return CLI_SUCCESS;
04904 }
04905 
04906 static char *handle_show_applications(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04907 {
04908    struct ast_app *aa;
04909    int like = 0, describing = 0;
04910    int total_match = 0;    /* Number of matches in like clause */
04911    int total_apps = 0;  /* Number of apps registered */
04912    static char* choices[] = { "like", "describing", NULL };
04913 
04914    switch (cmd) {
04915    case CLI_INIT:
04916       e->command = "core show applications [like|describing]";
04917       e->usage = 
04918          "Usage: core show applications [{like|describing} <text>]\n"
04919          "       List applications which are currently available.\n"
04920          "       If 'like', <text> will be a substring of the app name\n"
04921          "       If 'describing', <text> will be a substring of the description\n";
04922       return NULL;
04923    case CLI_GENERATE:
04924       return (a->pos != 3) ? NULL : ast_cli_complete(a->word, choices, a->n);
04925    }
04926 
04927    AST_RWLIST_RDLOCK(&apps);
04928 
04929    if (AST_RWLIST_EMPTY(&apps)) {
04930       ast_cli(a->fd, "There are no registered applications\n");
04931       AST_RWLIST_UNLOCK(&apps);
04932       return CLI_SUCCESS;
04933    }
04934 
04935    /* core list applications like <keyword> */
04936    if ((a->argc == 5) && (!strcmp(a->argv[3], "like"))) {
04937       like = 1;
04938    } else if ((a->argc > 4) && (!strcmp(a->argv[3], "describing"))) {
04939       describing = 1;
04940    }
04941 
04942    /* core list applications describing <keyword1> [<keyword2>] [...] */
04943    if ((!like) && (!describing)) {
04944       ast_cli(a->fd, "    -= Registered Asterisk Applications =-\n");
04945    } else {
04946       ast_cli(a->fd, "    -= Matching Asterisk Applications =-\n");
04947    }
04948 
04949    AST_RWLIST_TRAVERSE(&apps, aa, list) {
04950       int printapp = 0;
04951       total_apps++;
04952       if (like) {
04953          if (strcasestr(aa->name, a->argv[4])) {
04954             printapp = 1;
04955             total_match++;
04956          }
04957       } else if (describing) {
04958          if (aa->description) {
04959             /* Match all words on command line */
04960             int i;
04961             printapp = 1;
04962             for (i = 4; i < a->argc; i++) {
04963                if (!strcasestr(aa->description, a->argv[i])) {
04964                   printapp = 0;
04965                } else {
04966                   total_match++;
04967                }
04968             }
04969          }
04970       } else {
04971          printapp = 1;
04972       }
04973 
04974       if (printapp) {
04975          ast_cli(a->fd,"  %20s: %s\n", aa->name, aa->synopsis ? aa->synopsis : "<Synopsis not available>");
04976       }
04977    }
04978    if ((!like) && (!describing)) {
04979       ast_cli(a->fd, "    -= %d Applications Registered =-\n",total_apps);
04980    } else {
04981       ast_cli(a->fd, "    -= %d Applications Matching =-\n",total_match);
04982    }
04983 
04984    AST_RWLIST_UNLOCK(&apps);
04985 
04986    return CLI_SUCCESS;
04987 }
04988 
04989 /*
04990  * 'show dialplan' CLI command implementation functions ...
04991  */
04992 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
04993    int state)
04994 {
04995    struct ast_context *c = NULL;
04996    char *ret = NULL;
04997    int which = 0;
04998    int wordlen;
04999 
05000    /* we are do completion of [exten@]context on second position only */
05001    if (pos != 2)
05002       return NULL;
05003 
05004    ast_rdlock_contexts();
05005 
05006    wordlen = strlen(word);
05007 
05008    /* walk through all contexts and return the n-th match */
05009    while ( (c = ast_walk_contexts(c)) ) {
05010       if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
05011          ret = ast_strdup(ast_get_context_name(c));
05012          break;
05013       }
05014    }
05015 
05016    ast_unlock_contexts();
05017 
05018    return ret;
05019 }
05020 
05021 /*! \brief Counters for the show dialplan manager command */
05022 struct dialplan_counters {
05023    int total_items;
05024    int total_context;
05025    int total_exten;
05026    int total_prio;
05027    int context_existence;
05028    int extension_existence;
05029 };
05030 
05031 /*! \brief helper function to print an extension */
05032 static void print_ext(struct ast_exten *e, char * buf, int buflen)
05033 {
05034    int prio = ast_get_extension_priority(e);
05035    if (prio == PRIORITY_HINT) {
05036       snprintf(buf, buflen, "hint: %s",
05037          ast_get_extension_app(e));
05038    } else {
05039       snprintf(buf, buflen, "%d. %s(%s)",
05040          prio, ast_get_extension_app(e),
05041          (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
05042    }
05043 }
05044 
05045 /* XXX not verified */
05046 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[])
05047 {
05048    struct ast_context *c = NULL;
05049    int res = 0, old_total_exten = dpc->total_exten;
05050 
05051    ast_rdlock_contexts();
05052 
05053    /* walk all contexts ... */
05054    while ( (c = ast_walk_contexts(c)) ) {
05055       struct ast_exten *e;
05056       struct ast_include *i;
05057       struct ast_ignorepat *ip;
05058       char buf[256], buf2[256];
05059       int context_info_printed = 0;
05060 
05061       if (context && strcmp(ast_get_context_name(c), context))
05062          continue;   /* skip this one, name doesn't match */
05063 
05064       dpc->context_existence = 1;
05065 
05066       ast_rdlock_context(c);
05067 
05068       /* are we looking for exten too? if yes, we print context
05069        * only if we find our extension.
05070        * Otherwise print context even if empty ?
05071        * XXX i am not sure how the rinclude is handled.
05072        * I think it ought to go inside.
05073        */
05074       if (!exten) {
05075          dpc->total_context++;
05076          ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05077             ast_get_context_name(c), ast_get_context_registrar(c));
05078          context_info_printed = 1;
05079       }
05080 
05081       /* walk extensions ... */
05082       e = NULL;
05083       while ( (e = ast_walk_context_extensions(c, e)) ) {
05084          struct ast_exten *p;
05085 
05086          if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
05087             continue;   /* skip, extension match failed */
05088 
05089          dpc->extension_existence = 1;
05090 
05091          /* may we print context info? */
05092          if (!context_info_printed) {
05093             dpc->total_context++;
05094             if (rinclude) { /* TODO Print more info about rinclude */
05095                ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
05096                   ast_get_context_name(c), ast_get_context_registrar(c));
05097             } else {
05098                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05099                   ast_get_context_name(c), ast_get_context_registrar(c));
05100             }
05101             context_info_printed = 1;
05102          }
05103          dpc->total_prio++;
05104 
05105          /* write extension name and first peer */
05106          if (e->matchcid)
05107             snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
05108          else
05109             snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
05110 
05111          print_ext(e, buf2, sizeof(buf2));
05112 
05113          ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
05114             ast_get_extension_registrar(e));
05115 
05116          dpc->total_exten++;
05117          /* walk next extension peers */
05118          p = e;   /* skip the first one, we already got it */
05119          while ( (p = ast_walk_extension_priorities(e, p)) ) {
05120             const char *el = ast_get_extension_label(p);
05121             dpc->total_prio++;
05122             if (el)
05123                snprintf(buf, sizeof(buf), "   [%s]", el);
05124             else
05125                buf[0] = '\0';
05126             print_ext(p, buf2, sizeof(buf2));
05127 
05128             ast_cli(fd,"  %-17s %-45s [%s]\n", buf, buf2,
05129                ast_get_extension_registrar(p));
05130          }
05131       }
05132 
05133       /* walk included and write info ... */
05134       i = NULL;
05135       while ( (i = ast_walk_context_includes(c, i)) ) {
05136          snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
05137          if (exten) {
05138             /* Check all includes for the requested extension */
05139             if (includecount >= AST_PBX_MAX_STACK) {
05140                ast_log(LOG_WARNING, "Maximum include depth exceeded!\n");
05141             } else {
05142                int dupe = 0;
05143                int x;
05144                for (x = 0; x < includecount; x++) {
05145                   if (!strcasecmp(includes[x], ast_get_include_name(i))) {
05146                      dupe++;
05147                      break;
05148                   }
05149                }
05150                if (!dupe) {
05151                   includes[includecount] = ast_get_include_name(i);
05152                   show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
05153                } else {
05154                   ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
05155                }
05156             }
05157          } else {
05158             ast_cli(fd, "  Include =>        %-45s [%s]\n",
05159                buf, ast_get_include_registrar(i));
05160          }
05161       }
05162 
05163       /* walk ignore patterns and write info ... */
05164       ip = NULL;
05165       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05166          const char *ipname = ast_get_ignorepat_name(ip);
05167          char ignorepat[AST_MAX_EXTENSION];
05168          snprintf(buf, sizeof(buf), "'%s'", ipname);
05169          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05170          if (!exten || ast_extension_match(ignorepat, exten)) {
05171             ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
05172                buf, ast_get_ignorepat_registrar(ip));
05173          }
05174       }
05175       if (!rinclude) {
05176          struct ast_sw *sw = NULL;
05177          while ( (sw = ast_walk_context_switches(c, sw)) ) {
05178             snprintf(buf, sizeof(buf), "'%s/%s'",
05179                ast_get_switch_name(sw),
05180                ast_get_switch_data(sw));
05181             ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
05182                buf, ast_get_switch_registrar(sw));
05183          }
05184       }
05185       
05186       ast_unlock_context(c);
05187 
05188       /* if we print something in context, make an empty line */
05189       if (context_info_printed)
05190          ast_cli(fd, "\n");
05191    }
05192    ast_unlock_contexts();
05193 
05194    return (dpc->total_exten == old_total_exten) ? -1 : res;
05195 }
05196 
05197 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[])
05198 {
05199    struct ast_context *c = NULL;
05200    int res = 0, old_total_exten = dpc->total_exten;
05201 
05202    ast_cli(fd,"\n     In-mem exten Trie for Fast Extension Pattern Matching:\n\n");
05203 
05204    ast_cli(fd,"\n           Explanation: Node Contents Format = <char(s) to match>:<pattern?>:<specif>:[matched extension]\n");
05205    ast_cli(fd,    "                        Where <char(s) to match> is a set of chars, any one of which should match the current character\n");
05206    ast_cli(fd,    "                              <pattern?>: Y if this a pattern match (eg. _XZN[5-7]), N otherwise\n");
05207    ast_cli(fd,    "                              <specif>: an assigned 'exactness' number for this matching char. The lower the number, the more exact the match\n");
05208    ast_cli(fd,    "                              [matched exten]: If all chars matched to this point, which extension this matches. In form: EXTEN:<exten string>\n");
05209    ast_cli(fd,    "                        In general, you match a trie node to a string character, from left to right. All possible matching chars\n");
05210    ast_cli(fd,    "                        are in a string vertically, separated by an unbroken string of '+' characters.\n\n");
05211    ast_rdlock_contexts();
05212 
05213    /* walk all contexts ... */
05214    while ( (c = ast_walk_contexts(c)) ) {
05215       int context_info_printed = 0;
05216 
05217       if (context && strcmp(ast_get_context_name(c), context))
05218          continue;   /* skip this one, name doesn't match */
05219 
05220       dpc->context_existence = 1;
05221 
05222       if (!c->pattern_tree)
05223          ast_exists_extension(NULL, c->name, "s", 1, ""); /* do this to force the trie to built, if it is not already */
05224 
05225       ast_rdlock_context(c);
05226 
05227       dpc->total_context++;
05228       ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
05229          ast_get_context_name(c), ast_get_context_registrar(c));
05230       context_info_printed = 1;
05231       
05232       if (c->pattern_tree)
05233       {
05234          cli_match_char_tree(c->pattern_tree, " ", fd);
05235       } else {
05236          ast_cli(fd,"\n     No Pattern Trie present. Perhaps the context is empty...or there is trouble...\n\n");
05237       }
05238 
05239       ast_unlock_context(c);
05240 
05241       /* if we print something in context, make an empty line */
05242       if (context_info_printed)
05243          ast_cli(fd, "\n");
05244    }
05245    ast_unlock_contexts();
05246 
05247    return (dpc->total_exten == old_total_exten) ? -1 : res;
05248 }
05249 
05250 static char *handle_show_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05251 {
05252    char *exten = NULL, *context = NULL;
05253    /* Variables used for different counters */
05254    struct dialplan_counters counters;
05255    const char *incstack[AST_PBX_MAX_STACK];
05256 
05257    switch (cmd) {
05258    case CLI_INIT:
05259       e->command = "dialplan show";
05260       e->usage = 
05261          "Usage: dialplan show [[exten@]context]\n"
05262          "       Show dialplan\n";
05263       return NULL;
05264    case CLI_GENERATE:   
05265       return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05266    }
05267 
05268    memset(&counters, 0, sizeof(counters));
05269 
05270    if (a->argc != 2 && a->argc != 3)
05271       return CLI_SHOWUSAGE;
05272 
05273    /* we obtain [exten@]context? if yes, split them ... */
05274    if (a->argc == 3) {
05275       if (strchr(a->argv[2], '@')) {   /* split into exten & context */
05276          context = ast_strdupa(a->argv[2]);
05277          exten = strsep(&context, "@");
05278          /* change empty strings to NULL */
05279          if (ast_strlen_zero(exten))
05280             exten = NULL;
05281       } else { /* no '@' char, only context given */
05282          context = a->argv[2];
05283       }
05284       if (ast_strlen_zero(context))
05285          context = NULL;
05286    }
05287    /* else Show complete dial plan, context and exten are NULL */
05288    show_dialplan_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05289 
05290    /* check for input failure and throw some error messages */
05291    if (context && !counters.context_existence) {
05292       ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05293       return CLI_FAILURE;
05294    }
05295 
05296    if (exten && !counters.extension_existence) {
05297       if (context)
05298          ast_cli(a->fd, "There is no existence of %s@%s extension\n",
05299             exten, context);
05300       else
05301          ast_cli(a->fd,
05302             "There is no existence of '%s' extension in all contexts\n",
05303             exten);
05304       return CLI_FAILURE;
05305    }
05306 
05307    ast_cli(a->fd,"-= %d %s (%d %s) in %d %s. =-\n",
05308             counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
05309             counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
05310             counters.total_context, counters.total_context == 1 ? "context" : "contexts");
05311 
05312    /* everything ok */
05313    return CLI_SUCCESS;
05314 }
05315 
05316 /*! \brief Send ack once */
05317 static char *handle_debug_dialplan(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05318 {
05319    char *exten = NULL, *context = NULL;
05320    /* Variables used for different counters */
05321    struct dialplan_counters counters;
05322    const char *incstack[AST_PBX_MAX_STACK];
05323 
05324    switch (cmd) {
05325    case CLI_INIT:
05326       e->command = "dialplan debug";
05327       e->usage = 
05328          "Usage: dialplan debug [context]\n"
05329          "       Show dialplan context Trie(s). Usually only useful to folks debugging the deep internals of the fast pattern matcher\n";
05330       return NULL;
05331    case CLI_GENERATE:   
05332       return complete_show_dialplan_context(a->line, a->word, a->pos, a->n);
05333    }
05334 
05335    memset(&counters, 0, sizeof(counters));
05336 
05337    if (a->argc != 2 && a->argc != 3)
05338       return CLI_SHOWUSAGE;
05339 
05340    /* we obtain [exten@]context? if yes, split them ... */
05341    /* note: we ignore the exten totally here .... */
05342    if (a->argc == 3) {
05343       if (strchr(a->argv[2], '@')) {   /* split into exten & context */
05344          context = ast_strdupa(a->argv[2]);
05345          exten = strsep(&context, "@");
05346          /* change empty strings to NULL */
05347          if (ast_strlen_zero(exten))
05348             exten = NULL;
05349       } else { /* no '@' char, only context given */
05350          context = a->argv[2];
05351       }
05352       if (ast_strlen_zero(context))
05353          context = NULL;
05354    }
05355    /* else Show complete dial plan, context and exten are NULL */
05356    show_debug_helper(a->fd, context, exten, &counters, NULL, 0, incstack);
05357 
05358    /* check for input failure and throw some error messages */
05359    if (context && !counters.context_existence) {
05360       ast_cli(a->fd, "There is no existence of '%s' context\n", context);
05361       return CLI_FAILURE;
05362    }
05363 
05364 
05365    ast_cli(a->fd,"-= %d %s. =-\n",
05366          counters.total_context, counters.total_context == 1 ? "context" : "contexts");
05367 
05368    /* everything ok */
05369    return CLI_SUCCESS;
05370 }
05371 
05372 /*! \brief Send ack once */
05373 static void manager_dpsendack(struct mansession *s, const struct message *m)
05374 {
05375    astman_send_listack(s, m, "DialPlan list will follow", "start");
05376 }
05377 
05378 /*! \brief Show dialplan extensions
05379  * XXX this function is similar but not exactly the same as the CLI's
05380  * show dialplan. Must check whether the difference is intentional or not.
05381  */
05382 static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
05383                const char *actionidtext, const char *context,
05384                const char *exten, struct dialplan_counters *dpc,
05385                struct ast_include *rinclude)
05386 {
05387    struct ast_context *c;
05388    int res = 0, old_total_exten = dpc->total_exten;
05389 
05390    if (ast_strlen_zero(exten))
05391       exten = NULL;
05392    if (ast_strlen_zero(context))
05393       context = NULL;
05394 
05395    ast_debug(3, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
05396 
05397    /* try to lock contexts */
05398    if (ast_rdlock_contexts()) {
05399       astman_send_error(s, m, "Failed to lock contexts");
05400       ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
05401       return -1;
05402    }
05403 
05404    c = NULL;      /* walk all contexts ... */
05405    while ( (c = ast_walk_contexts(c)) ) {
05406       struct ast_exten *e;
05407       struct ast_include *i;
05408       struct ast_ignorepat *ip;
05409 
05410       if (context && strcmp(ast_get_context_name(c), context) != 0)
05411          continue;   /* not the name we want */
05412 
05413       dpc->context_existence = 1;
05414 
05415       ast_debug(3, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
05416 
05417       if (ast_rdlock_context(c)) {  /* failed to lock */
05418          ast_debug(3, "manager_show_dialplan: Failed to lock context\n");
05419          continue;
05420       }
05421 
05422       /* XXX note- an empty context is not printed */
05423       e = NULL;      /* walk extensions in context  */
05424       while ( (e = ast_walk_context_extensions(c, e)) ) {
05425          struct ast_exten *p;
05426 
05427          /* looking for extension? is this our extension? */
05428          if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
05429             /* not the one we are looking for, continue */
05430             ast_debug(3, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
05431             continue;
05432          }
05433          ast_debug(3, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
05434 
05435          dpc->extension_existence = 1;
05436 
05437          /* may we print context info? */ 
05438          dpc->total_context++;
05439          dpc->total_exten++;
05440 
05441          p = NULL;      /* walk next extension peers */
05442          while ( (p = ast_walk_extension_priorities(e, p)) ) {
05443             int prio = ast_get_extension_priority(p);
05444 
05445             dpc->total_prio++;
05446             if (!dpc->total_items++)
05447                manager_dpsendack(s, m);
05448             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05449             astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
05450 
05451             /* XXX maybe make this conditional, if p != e ? */
05452             if (ast_get_extension_label(p))
05453                astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
05454 
05455             if (prio == PRIORITY_HINT) {
05456                astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
05457             } else {
05458                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));
05459             }
05460             astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
05461          }
05462       }
05463 
05464       i = NULL;      /* walk included and write info ... */
05465       while ( (i = ast_walk_context_includes(c, i)) ) {
05466          if (exten) {
05467             /* Check all includes for the requested extension */
05468             manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
05469          } else {
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\nIncludeContext: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_include_name(i), ast_get_include_registrar(i));
05474             astman_append(s, "\r\n");
05475             ast_debug(3, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
05476          }
05477       }
05478 
05479       ip = NULL;  /* walk ignore patterns and write info ... */
05480       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
05481          const char *ipname = ast_get_ignorepat_name(ip);
05482          char ignorepat[AST_MAX_EXTENSION];
05483 
05484          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
05485          if (!exten || ast_extension_match(ignorepat, exten)) {
05486             if (!dpc->total_items++)
05487                manager_dpsendack(s, m);
05488             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05489             astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
05490             astman_append(s, "\r\n");
05491          }
05492       }
05493       if (!rinclude) {
05494          struct ast_sw *sw = NULL;
05495          while ( (sw = ast_walk_context_switches(c, sw)) ) {
05496             if (!dpc->total_items++)
05497                manager_dpsendack(s, m);
05498             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
05499             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));  
05500             astman_append(s, "\r\n");
05501             ast_debug(3, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
05502          }
05503       }
05504 
05505       ast_unlock_context(c);
05506    }
05507    ast_unlock_contexts();
05508 
05509    if (dpc->total_exten == old_total_exten) {
05510       ast_debug(3, "manager_show_dialplan: Found nothing new\n");
05511       /* Nothing new under the sun */
05512       return -1;
05513    } else {
05514       return res;
05515    }
05516 }
05517 
05518 /*! \brief  Manager listing of dial plan */
05519 static int manager_show_dialplan(struct mansession *s, const struct message *m)
05520 {
05521    const char *exten, *context;
05522    const char *id = astman_get_header(m, "ActionID");
05523    char idtext[256];
05524    int res;
05525 
05526    /* Variables used for different counters */
05527    struct dialplan_counters counters;
05528 
05529    if (!ast_strlen_zero(id))
05530       snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
05531    else
05532       idtext[0] = '\0';
05533 
05534    memset(&counters, 0, sizeof(counters));
05535 
05536    exten = astman_get_header(m, "Extension");
05537    context = astman_get_header(m, "Context");
05538    
05539    res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
05540 
05541    if (context && !counters.context_existence) {
05542       char errorbuf[BUFSIZ];
05543    
05544       snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s", context);
05545       astman_send_error(s, m, errorbuf);
05546       return 0;
05547    }
05548    if (exten && !counters.extension_existence) {
05549       char errorbuf[BUFSIZ];
05550 
05551       if (context)
05552          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s", exten, context);
05553       else
05554          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context", exten);
05555       astman_send_error(s, m, errorbuf);
05556       return 0;
05557    }
05558 
05559    manager_event(EVENT_FLAG_CONFIG, "ShowDialPlanComplete",
05560       "EventList: Complete\r\n"
05561       "ListItems: %d\r\n"
05562       "ListExtensions: %d\r\n"
05563       "ListPriorities: %d\r\n"   
05564       "ListContexts: %d\r\n"  
05565       "%s"
05566       "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
05567 
05568    /* everything ok */
05569    return 0;
05570 }
05571 
05572 static char mandescr_show_dialplan[] =
05573 "Description: Show dialplan contexts and extensions.\n"
05574 "Be aware that showing the full dialplan may take a lot of capacity\n"
05575 "Variables: \n"
05576 " ActionID: <id>     Action ID for this AMI transaction (optional)\n"
05577 " Extension: <extension>   Extension (Optional)\n"
05578 " Context: <context>    Context (Optional)\n"
05579 "\n";
05580 
05581 /*! \brief CLI support for listing global variables in a parseable way */
05582 static char *handle_show_globals(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05583 {
05584    int i = 0;
05585    struct ast_var_t *newvariable;
05586 
05587    switch (cmd) {
05588    case CLI_INIT:
05589       e->command = "dialplan show globals";
05590       e->usage = 
05591          "Usage: dialplan show globals\n"
05592          "       List current global dialplan variables and their values\n";
05593       return NULL;
05594    case CLI_GENERATE:
05595       return NULL;
05596    }
05597 
05598    ast_rwlock_rdlock(&globalslock);
05599    AST_LIST_TRAVERSE (&globals, newvariable, entries) {
05600       i++;
05601       ast_cli(a->fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
05602    }
05603    ast_rwlock_unlock(&globalslock);
05604    ast_cli(a->fd, "\n    -- %d variable(s)\n", i);
05605 
05606    return CLI_SUCCESS;
05607 }
05608 
05609 static char *handle_show_globals_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05610 {
05611 
05612    char *res = handle_show_globals(e, cmd, a);
05613    if (cmd == CLI_INIT)
05614       e->command = "core show globals";
05615    return res;
05616 }
05617 
05618 #ifdef AST_DEVMODE
05619 static char *handle_show_device2extenstate(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05620 {
05621    struct ast_devstate_aggregate agg;
05622    int i, j, exten, combined;
05623 
05624    switch (cmd) {
05625    case CLI_INIT:
05626       e->command = "core show device2extenstate";
05627       e->usage =
05628          "Usage: core show device2extenstate\n"
05629          "       Lists device state to extension state combinations.\n";
05630    case CLI_GENERATE:
05631       return NULL;
05632    }
05633    for (i = 0; i < AST_DEVICE_TOTAL; i++) {
05634       for (j = 0; j < AST_DEVICE_TOTAL; j++) {
05635          ast_devstate_aggregate_init(&agg);
05636          ast_devstate_aggregate_add(&agg, i);
05637          ast_devstate_aggregate_add(&agg, j);
05638          combined = ast_devstate_aggregate_result(&agg);
05639          exten = ast_devstate_to_extenstate(combined);
05640          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));
05641       }
05642    }
05643    ast_cli(a->fd, "\n");
05644    return CLI_SUCCESS;
05645 }
05646 #endif
05647 
05648 /*! \brief CLI support for listing chanvar's variables in a parseable way */
05649 static char *handle_show_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05650 {
05651    struct ast_channel *chan = NULL;
05652    struct ast_str *vars = ast_str_alloca(BUFSIZ * 4); /* XXX large because we might have lots of channel vars */
05653 
05654    switch (cmd) {
05655    case CLI_INIT:
05656       e->command = "dialplan show chanvar";
05657       e->usage = 
05658          "Usage: dialplan show chanvar <channel>\n"
05659          "       List current channel variables and their values\n";
05660       return NULL;
05661    case CLI_GENERATE:
05662       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05663    }
05664 
05665    if (a->argc != e->args + 1)
05666       return CLI_SHOWUSAGE;
05667 
05668    if (!(chan = ast_get_channel_by_name_locked(a->argv[e->args]))) {
05669       ast_cli(a->fd, "Channel '%s' not found\n", a->argv[e->args]);
05670       return CLI_FAILURE;
05671    }
05672 
05673    pbx_builtin_serialize_variables(chan, &vars);
05674    if (vars->str) {
05675       ast_cli(a->fd, "\nVariables for channel %s:\n%s\n", a->argv[e->args], vars->str);
05676    }
05677    ast_channel_unlock(chan);
05678    return CLI_SUCCESS;
05679 }
05680 
05681 static char *handle_set_global(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05682 {
05683    switch (cmd) {
05684    case CLI_INIT:
05685       e->command = "dialplan set global";
05686       e->usage = 
05687          "Usage: dialplan set global <name> <value>\n"
05688          "       Set global dialplan variable <name> to <value>\n";
05689       return NULL;
05690    case CLI_GENERATE:
05691       return NULL;   
05692    }
05693 
05694    if (a->argc != e->args + 2)
05695       return CLI_SHOWUSAGE;
05696 
05697    pbx_builtin_setvar_helper(NULL, a->argv[3], a->argv[4]);
05698    ast_cli(a->fd, "\n    -- Global variable '%s' set to '%s'\n", a->argv[3], a->argv[4]);
05699 
05700    return CLI_SUCCESS;
05701 }
05702 
05703 static char *handle_set_global_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05704 {
05705    char *res = handle_set_global(e, cmd, a);
05706    if (cmd == CLI_INIT)
05707       e->command = "core set global";
05708    return res;
05709 }
05710 
05711 static char *handle_set_chanvar(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05712 {
05713    struct ast_channel *chan;
05714    const char *chan_name, *var_name, *var_value;
05715 
05716    switch (cmd) {
05717    case CLI_INIT:
05718       e->command = "dialplan set chanvar";
05719       e->usage = 
05720          "Usage: dialplan set chanvar <channel> <varname> <value>\n"
05721          "       Set channel variable <varname> to <value>\n";
05722       return NULL;
05723    case CLI_GENERATE:
05724       return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05725    }
05726 
05727    if (a->argc != e->args + 3)
05728       return CLI_SHOWUSAGE;
05729 
05730    chan_name = a->argv[e->args];
05731    var_name = a->argv[e->args + 1];
05732    var_value = a->argv[e->args + 2];
05733 
05734    if (!(chan = ast_get_channel_by_name_locked(chan_name))) {
05735       ast_cli(a->fd, "Channel '%s' not found\n", chan_name);
05736       return CLI_FAILURE;
05737    }
05738 
05739    pbx_builtin_setvar_helper(chan, var_name, var_value);
05740    ast_channel_unlock(chan);
05741    ast_cli(a->fd, "\n    -- Channel variable '%s' set to '%s' for '%s'\n",  var_name, var_value, chan_name);
05742 
05743    return CLI_SUCCESS;
05744 }
05745 
05746 static char *handle_set_chanvar_deprecated(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05747 {
05748    char *res = handle_set_chanvar(e, cmd, a);
05749    if (cmd == CLI_INIT)
05750       e->command = "core set chanvar";
05751    return res;
05752 }
05753 
05754 static char *handle_set_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05755 {
05756    int oldval = 0;
05757    
05758    switch (cmd) {
05759    case CLI_INIT:
05760       e->command = "dialplan set extenpatternmatchnew true";
05761       e->usage = 
05762          "Usage: dialplan set extenpatternmatchnew true|false\n"
05763          "       Use the NEW extension pattern matching algorithm, true or false.\n";
05764       return NULL;
05765    case CLI_GENERATE:
05766       return NULL;   
05767    }
05768 
05769    if (a->argc != 4)
05770       return CLI_SHOWUSAGE;
05771 
05772    oldval =  pbx_set_extenpatternmatchnew(1);
05773    
05774    if (oldval)
05775       ast_cli(a->fd, "\n    -- Still using the NEW pattern match algorithm for extension names in the dialplan.\n");
05776    else
05777       ast_cli(a->fd, "\n    -- Switched to using the NEW pattern match algorithm for extension names in the dialplan.\n");
05778 
05779    return CLI_SUCCESS;
05780 }
05781 
05782 static char *handle_unset_extenpatternmatchnew(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05783 {
05784    int oldval = 0;
05785    
05786    switch (cmd) {
05787    case CLI_INIT:
05788       e->command = "dialplan set extenpatternmatchnew false";
05789       e->usage = 
05790          "Usage: dialplan set extenpatternmatchnew true|false\n"
05791          "       Use the NEW extension pattern matching algorithm, true or false.\n";
05792       return NULL;
05793    case CLI_GENERATE:
05794       return NULL;   
05795    }
05796 
05797    if (a->argc != 4)
05798       return CLI_SHOWUSAGE;
05799 
05800    oldval =  pbx_set_extenpatternmatchnew(0);
05801    
05802    if (!oldval)
05803       ast_cli(a->fd, "\n    -- Still using the OLD pattern match algorithm for extension names in the dialplan.\n");
05804    else
05805       ast_cli(a->fd, "\n    -- Switched to using the OLD pattern match algorithm for extension names in the dialplan.\n");
05806 
05807    return CLI_SUCCESS;
05808 }
05809 
05810 /*
05811  * Deprecated CLI commands
05812  */
05813 
05814 static struct ast_cli_entry cli_show_globals_deprecated = AST_CLI_DEFINE(handle_show_globals_deprecated, "Show global dialplan variables.");
05815 static struct ast_cli_entry cli_set_chanvar_deprecated = AST_CLI_DEFINE(handle_set_chanvar_deprecated, "Set a channel variable.");
05816 static struct ast_cli_entry cli_set_global_deprecated = AST_CLI_DEFINE(handle_set_global_deprecated, "Set global dialplan variable.");
05817 
05818 /*
05819  * CLI entries for upper commands ...
05820  */
05821 static struct ast_cli_entry pbx_cli[] = {
05822    AST_CLI_DEFINE(handle_show_applications, "Shows registered dialplan applications"),
05823    AST_CLI_DEFINE(handle_show_functions, "Shows registered dialplan functions"),
05824    AST_CLI_DEFINE(handle_show_switches, "Show alternative switches"),
05825    AST_CLI_DEFINE(handle_show_hints, "Show dialplan hints"),
05826    AST_CLI_DEFINE(handle_show_hint, "Show dialplan hint"),
05827    AST_CLI_DEFINE(handle_show_globals, "Show global dialplan variables", .deprecate_cmd = &cli_show_globals_deprecated),
05828 #ifdef AST_DEVMODE
05829    AST_CLI_DEFINE(handle_show_device2extenstate, "Show expected exten state from multiple device states"),
05830 #endif
05831    AST_CLI_DEFINE(handle_show_chanvar, "Show channel variables"),
05832    AST_CLI_DEFINE(handle_show_function, "Describe a specific dialplan function"),
05833    AST_CLI_DEFINE(handle_show_application, "Describe a specific dialplan application"),
05834    AST_CLI_DEFINE(handle_set_global, "Set global dialplan variable", .deprecate_cmd = &cli_set_global_deprecated),
05835    AST_CLI_DEFINE(handle_set_chanvar, "Set a channel variable", .deprecate_cmd = &cli_set_chanvar_deprecated),
05836    AST_CLI_DEFINE(handle_show_dialplan, "Show dialplan"),
05837    AST_CLI_DEFINE(handle_debug_dialplan, "Show fast extension pattern matching data structures"),
05838    AST_CLI_DEFINE(handle_unset_extenpatternmatchnew, "Use the Old extension pattern matching algorithm."),
05839    AST_CLI_DEFINE(handle_set_extenpatternmatchnew, "Use the New extension pattern matching algorithm."),
05840 };
05841 
05842 static void unreference_cached_app(struct ast_app *app)
05843 {
05844    struct ast_context *context = NULL;
05845    struct ast_exten *eroot = NULL, *e = NULL;
05846 
05847    ast_rdlock_contexts();
05848    while ((context = ast_walk_contexts(context))) {
05849       while ((eroot = ast_walk_context_extensions(context, eroot))) {
05850          while ((e = ast_walk_extension_priorities(eroot, e))) {
05851             if (e->cached_app == app)
05852                e->cached_app = NULL;
05853          }
05854       }
05855    }
05856    ast_unlock_contexts();
05857 
05858    return;
05859 }
05860 
05861 int ast_unregister_application(const char *app)
05862 {
05863    struct ast_app *tmp;
05864 
05865    AST_RWLIST_WRLOCK(&apps);
05866    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
05867       if (!strcasecmp(app, tmp->name)) {
05868          unreference_cached_app(tmp);
05869          AST_RWLIST_REMOVE_CURRENT(list);
05870          ast_verb(2, "Unregistered application '%s'\n", tmp->name);
05871          ast_free(tmp);
05872          break;
05873       }
05874    }
05875    AST_RWLIST_TRAVERSE_SAFE_END;
05876    AST_RWLIST_UNLOCK(&apps);
05877 
05878    return tmp ? 0 : -1;
05879 }
05880 
05881 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
05882 {
05883    struct ast_context *tmp, **local_contexts;
05884    struct fake_context search;
05885    int length = sizeof(struct ast_context) + strlen(name) + 1;
05886 
05887    if (!contexts_table) {
05888       contexts_table = ast_hashtab_create(17,
05889                                  ast_hashtab_compare_contexts, 
05890                                  ast_hashtab_resize_java,
05891                                  ast_hashtab_newsize_java,
05892                                  ast_hashtab_hash_contexts,
05893                                  0);
05894    }
05895    
05896    ast_copy_string(search.name, name, sizeof(search.name));
05897    if (!extcontexts) {
05898       ast_rdlock_contexts();
05899       local_contexts = &contexts;
05900       tmp = ast_hashtab_lookup(contexts_table, &search);
05901       ast_unlock_contexts();
05902       if (tmp) {
05903          tmp->refcount++;
05904          return tmp;
05905       }
05906    } else { /* local contexts just in a linked list; search there for the new context; slow, linear search, but not frequent */
05907       local_contexts = extcontexts;
05908       tmp = ast_hashtab_lookup(exttable, &search);
05909       if (tmp) {
05910          tmp->refcount++;
05911          return tmp;
05912       }
05913    }
05914    
05915    if ((tmp = ast_calloc(1, length))) {
05916       ast_rwlock_init(&tmp->lock);
05917       ast_mutex_init(&tmp->macrolock);
05918       strcpy(tmp->name, name);
05919       tmp->root = NULL;
05920       tmp->root_table = NULL;
05921       tmp->registrar = ast_strdup(registrar);
05922       tmp->includes = NULL;
05923       tmp->ignorepats = NULL;
05924       tmp->refcount = 1;
05925    } else {
05926       ast_log(LOG_ERROR, "Danger! We failed to allocate a context for %s!\n", name);
05927       return NULL;
05928    }
05929    
05930    if (!extcontexts) {
05931       ast_wrlock_contexts();
05932       tmp->next = *local_contexts;
05933       *local_contexts = tmp;
05934       ast_hashtab_insert_safe(contexts_table, tmp); /*put this context into the tree */
05935       ast_unlock_contexts();
05936       ast_debug(1, "Registered context '%s'(%p) in table %p registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
05937       ast_verb(3, "Registered extension context '%s' (%p) in table %p; registrar: %s\n", tmp->name, tmp, contexts_table, registrar);
05938    } else {
05939       tmp->next = *local_contexts;
05940       if (exttable)
05941          ast_hashtab_insert_immediate(exttable, tmp); /*put this context into the tree */
05942       
05943       *local_contexts = tmp;
05944       ast_debug(1, "Registered context '%s'(%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
05945       ast_verb(3, "Registered extension context '%s' (%p) in local table %p; registrar: %s\n", tmp->name, tmp, exttable, registrar);
05946    }
05947    return tmp;
05948 }
05949 
05950 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar);
05951 
05952 struct store_hint {
05953    char *context;
05954    char *exten;
05955    AST_LIST_HEAD_NOLOCK(, ast_state_cb) callbacks;
05956    int laststate;
05957    AST_LIST_ENTRY(store_hint) list;
05958    char data[1];
05959 };
05960 
05961 AST_LIST_HEAD(store_hints, store_hint);
05962 
05963 static void context_merge_incls_swits_igps_other_registrars(struct ast_context *new, struct ast_context *old, const char *registrar)
05964 {
05965    struct ast_include *i;
05966    struct ast_ignorepat *ip;
05967    struct ast_sw *sw;
05968    
05969    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);
05970    /* copy in the includes, switches, and ignorepats */
05971    /* walk through includes */
05972    for (i = NULL; (i = ast_walk_context_includes(old, i)) ; ) {
05973       if (strcmp(ast_get_include_registrar(i), registrar) == 0)
05974          continue; /* not mine */
05975       ast_context_add_include2(new, ast_get_include_name(i), ast_get_include_registrar(i));
05976    }
05977    
05978    /* walk through switches */
05979    for (sw = NULL; (sw = ast_walk_context_switches(old, sw)) ; ) {
05980       if (strcmp(ast_get_switch_registrar(sw), registrar) == 0)
05981          continue; /* not mine */
05982       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));
05983    }
05984    
05985    /* walk thru ignorepats ... */
05986    for (ip = NULL; (ip = ast_walk_context_ignorepats(old, ip)); ) {
05987       if (strcmp(ast_get_ignorepat_registrar(ip), registrar) == 0)
05988          continue; /* not mine */
05989       ast_context_add_ignorepat2(new, ast_get_ignorepat_name(ip), ast_get_ignorepat_registrar(ip));
05990    }
05991 }
05992 
05993 
05994 /* the purpose of this routine is to duplicate a context, with all its substructure,
05995    except for any extens that have a matching registrar */
05996 static void context_merge(struct ast_context **extcontexts, struct ast_hashtab *exttable, struct ast_context *context, const char *registrar)
05997 {
05998    struct ast_context *new = ast_hashtab_lookup(exttable, context); /* is there a match in the new set? */
05999    struct ast_exten *exten_item, *prio_item, *new_exten_item, *new_prio_item;
06000    struct ast_hashtab_iter *exten_iter;
06001    struct ast_hashtab_iter *prio_iter;
06002    int insert_count = 0;
06003    int first = 1;
06004    
06005    /* We'll traverse all the extensions/prios, and see which are not registrar'd with
06006       the current registrar, and copy them to the new context. If the new context does not
06007       exist, we'll create it "on demand". If no items are in this context to copy, then we'll
06008       only create the empty matching context if the old one meets the criteria */
06009    
06010    if (context->root_table) {
06011       exten_iter = ast_hashtab_start_traversal(context->root_table);
06012       while ((exten_item=ast_hashtab_next(exten_iter))) {
06013          if (new) {
06014             new_exten_item = ast_hashtab_lookup(new->root_table, exten_item);
06015          } else {
06016             new_exten_item = NULL;
06017          }
06018          prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
06019          while ((prio_item=ast_hashtab_next(prio_iter))) {
06020             int res1;
06021             char *dupdstr;
06022             
06023             if (new_exten_item) {
06024                new_prio_item = ast_hashtab_lookup(new_exten_item->peer_table, prio_item);
06025             } else {
06026                new_prio_item = NULL;
06027             }
06028             if (strcmp(prio_item->registrar,registrar) == 0) {
06029                continue;
06030             }
06031             /* make sure the new context exists, so we have somewhere to stick this exten/prio */
06032             if (!new) {
06033                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 */
06034             }
06035 
06036             /* copy in the includes, switches, and ignorepats */
06037             if (first) { /* but, only need to do this once */
06038                context_merge_incls_swits_igps_other_registrars(new, context, registrar);
06039                first = 0;
06040             }
06041             
06042             if (!new) {
06043                ast_log(LOG_ERROR,"Could not allocate a new context for %s in merge_and_delete! Danger!\n", context->name);
06044                return; /* no sense continuing. */
06045             }
06046             /* we will not replace existing entries in the new context with stuff from the old context.
06047                but, if this is because of some sort of registrar conflict, we ought to say something... */
06048             
06049             dupdstr = ast_strdup(prio_item->data);
06050             
06051             res1 = ast_add_extension2(new, 0, prio_item->exten, prio_item->priority, prio_item->label, 
06052                                 prio_item->matchcid ? prio_item->cidmatch : NULL, prio_item->app, dupdstr, prio_item->datad, prio_item->registrar);
06053             if (!res1 && new_exten_item && new_prio_item){
06054                ast_verb(3,"Dropping old dialplan item %s/%s/%d [%s(%s)] (registrar=%s) due to conflict with new dialplan\n",
06055                      context->name, prio_item->exten, prio_item->priority, prio_item->app, (char*)prio_item->data, prio_item->registrar);
06056             } else {
06057                /* 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,
06058                 and no double frees take place, either! */
06059                insert_count++;
06060             }
06061          }
06062          ast_hashtab_end_traversal(prio_iter);
06063       }
06064       ast_hashtab_end_traversal(exten_iter);
06065    }
06066    
06067    if (!insert_count && !new && (strcmp(context->registrar, registrar) != 0 ||
06068         (strcmp(context->registrar, registrar) == 0 && context->refcount > 1))) {
06069       /* we could have given it the registrar of the other module who incremented the refcount,
06070          but that's not available, so we give it the registrar we know about */
06071       new = ast_context_find_or_create(extcontexts, exttable, context->name, context->registrar);
06072       
06073       /* copy in the includes, switches, and ignorepats */
06074       context_merge_incls_swits_igps_other_registrars(new, context, registrar);
06075    }
06076 }
06077 
06078 
06079 /* XXX this does not check that multiple contexts are merged */
06080 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *registrar)
06081 {
06082    double ft;
06083    struct ast_context *tmp, *oldcontextslist;
06084    struct ast_hashtab *oldtable;
06085    struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
06086    struct store_hint *this;
06087    struct ast_hint *hint;
06088    struct ast_exten *exten;
06089    int length;
06090    struct ast_state_cb *thiscb;
06091    struct ast_hashtab_iter *iter;
06092    
06093    /* it is very important that this function hold the hint list lock _and_ the conlock
06094       during its operation; not only do we need to ensure that the list of contexts
06095       and extensions does not change, but also that no hint callbacks (watchers) are
06096       added or removed during the merge/delete process
06097 
06098       in addition, the locks _must_ be taken in this order, because there are already
06099       other code paths that use this order
06100    */
06101    
06102    struct timeval begintime, writelocktime, endlocktime, enddeltime;
06103    int wrlock_ver;
06104    
06105    begintime = ast_tvnow();
06106    ast_rdlock_contexts();
06107    iter = ast_hashtab_start_traversal(contexts_table);
06108    while ((tmp = ast_hashtab_next(iter))) {
06109       context_merge(extcontexts, exttable, tmp, registrar);
06110    }
06111    ast_hashtab_end_traversal(iter);
06112    wrlock_ver = ast_wrlock_contexts_version();
06113    
06114    ast_unlock_contexts(); /* this feels real retarded, but you must do
06115                        what you must do If this isn't done, the following 
06116                         wrlock is a guraranteed deadlock */
06117    ast_wrlock_contexts();
06118    if (ast_wrlock_contexts_version() > wrlock_ver+1) {
06119       ast_log(LOG_WARNING,"==================!!!!!!!!!!!!!!!Something changed the contexts in the middle of merging contexts!\n");
06120    }
06121    
06122    AST_RWLIST_WRLOCK(&hints);
06123    writelocktime = ast_tvnow();
06124 
06125    /* preserve all watchers for hints */
06126    AST_RWLIST_TRAVERSE(&hints, hint, list) {
06127       if (!AST_LIST_EMPTY(&hint->callbacks)) {
06128          length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
06129          if (!(this = ast_calloc(1, length)))
06130             continue;
06131          /* this removes all the callbacks from the hint into this. */
06132          AST_LIST_APPEND_LIST(&this->callbacks, &hint->callbacks, entry);
06133          this->laststate = hint->laststate;
06134          this->context = this->data;
06135          strcpy(this->data, hint->exten->parent->name);
06136          this->exten = this->data + strlen(this->context) + 1;
06137          strcpy(this->exten, hint->exten->exten);
06138          AST_LIST_INSERT_HEAD(&store, this, list);
06139       }
06140    }
06141 
06142    /* save the old table and list */
06143    oldtable = contexts_table;
06144    oldcontextslist = contexts;
06145 
06146    /* move in the new table and list */
06147    contexts_table = exttable;
06148    contexts = *extcontexts;
06149    
06150    /* restore the watchers for hints that can be found; notify those that
06151       cannot be restored
06152    */
06153    while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
06154       struct pbx_find_info q = { .stacklen = 0 };
06155       exten = pbx_find_extension(NULL, NULL, &q, this->context, this->exten, PRIORITY_HINT, NULL, "", E_MATCH);
06156       /* If this is a pattern, dynamically create a new extension for this
06157        * particular match.  Note that this will only happen once for each
06158        * individual extension, because the pattern will no longer match first.
06159        */
06160       if (exten && exten->exten[0] == '_') {
06161          ast_add_extension_nolock(exten->parent->name, 0, this->exten, PRIORITY_HINT, NULL,
06162             0, exten->app, ast_strdup(exten->data), ast_free_ptr, exten->registrar);
06163          /* rwlocks are not recursive locks */
06164          exten = ast_hint_extension_nolock(NULL, this->context, this->exten);
06165       }
06166 
06167       /* Find the hint in the list of hints */
06168       AST_RWLIST_TRAVERSE(&hints, hint, list) {
06169          if (hint->exten == exten)
06170             break;
06171       }
06172       if (!exten || !hint) {
06173          /* this hint has been removed, notify the watchers */
06174          while ((thiscb = AST_LIST_REMOVE_HEAD(&this->callbacks, entry))) {
06175             thiscb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, thiscb->data);
06176             ast_free(thiscb);
06177          }
06178       } else {
06179          AST_LIST_APPEND_LIST(&hint->callbacks, &this->callbacks, entry);
06180          hint->laststate = this->laststate;
06181       }
06182       ast_free(this);
06183    }
06184 
06185    AST_RWLIST_UNLOCK(&hints);
06186    ast_unlock_contexts();
06187    endlocktime = ast_tvnow();
06188    
06189    /* the old list and hashtab no longer are relevant, delete them while the rest of asterisk
06190       is now freely using the new stuff instead */
06191    
06192    ast_hashtab_destroy(oldtable, NULL);
06193    
06194    for (tmp = oldcontextslist; tmp; ) {
06195       struct ast_context *next;  /* next starting point */
06196       next = tmp->next;
06197       __ast_internal_context_destroy(tmp);
06198       tmp = next;
06199    }
06200    enddeltime = ast_tvnow();
06201    
06202    ft = ast_tvdiff_us(writelocktime, begintime);
06203    ft /= 1000000.0;
06204    ast_verb(3,"Time to scan old dialplan and merge leftovers back into the new: %8.6f sec\n", ft);
06205    
06206    ft = ast_tvdiff_us(endlocktime, writelocktime);
06207    ft /= 1000000.0;
06208    ast_verb(3,"Time to restore hints and swap in new dialplan: %8.6f sec\n", ft);
06209 
06210    ft = ast_tvdiff_us(enddeltime, endlocktime);
06211    ft /= 1000000.0;
06212    ast_verb(3,"Time to delete the old dialplan: %8.6f sec\n", ft);
06213 
06214    ft = ast_tvdiff_us(enddeltime, begintime);
06215    ft /= 1000000.0;
06216    ast_verb(3,"Total time merge_contexts_delete: %8.6f sec\n", ft);
06217    return;
06218 }
06219 
06220 /*
06221  * errno values
06222  *  EBUSY  - can't lock
06223  *  ENOENT - no existence of context
06224  */
06225 int ast_context_add_include(const char *context, const char *include, const char *registrar)
06226 {
06227    int ret = -1;
06228    struct ast_context *c = find_context_locked(context);
06229 
06230    if (c) {
06231       ret = ast_context_add_include2(c, include, registrar);
06232       ast_unlock_contexts();
06233    }
06234    return ret;
06235 }
06236 
06237 /*! \brief Helper for get_range.
06238  * return the index of the matching entry, starting from 1.
06239  * If names is not supplied, try numeric values.
06240  */
06241 static int lookup_name(const char *s, char *const names[], int max)
06242 {
06243    int i;
06244 
06245    if (names) {
06246       for (i = 0; names[i]; i++) {
06247          if (!strcasecmp(s, names[i]))
06248             return i+1;
06249       }
06250    } else if (sscanf(s, "%2d", &i) == 1 && i >= 1 && i <= max) {
06251       return i;
06252    }
06253    return 0; /* error return */
06254 }
06255 
06256 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
06257  * names, if supplied, is an array of names that should be mapped to numbers.
06258  */
06259 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
06260 {
06261    int s, e; /* start and ending position */
06262    unsigned int mask = 0;
06263 
06264    /* Check for whole range */
06265    if (ast_strlen_zero(src) || !strcmp(src, "*")) {
06266       s = 0;
06267       e = max - 1;
06268    } else {
06269       /* Get start and ending position */
06270       char *c = strchr(src, '-');
06271       if (c)
06272          *c++ = '\0';
06273       /* Find the start */
06274       s = lookup_name(src, names, max);
06275       if (!s) {
06276          ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
06277          return 0;
06278       }
06279       s--;
06280       if (c) { /* find end of range */
06281          e = lookup_name(c, names, max);
06282          if (!e) {
06283             ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
06284             return 0;
06285          }
06286          e--;
06287       } else
06288          e = s;
06289    }
06290    /* Fill the mask. Remember that ranges are cyclic */
06291    mask = 1 << e; /* initialize with last element */
06292    while (s != e) {
06293       if (s >= max) {
06294          s = 0;
06295          mask |= (1 << s);
06296       } else {
06297          mask |= (1 << s);
06298          s++;
06299       }
06300    }
06301    return mask;
06302 }
06303 
06304 /*! \brief store a bitmask of valid times, one bit each 2 minute */
06305 static void get_timerange(struct ast_timing *i, char *times)
06306 {
06307    char *e;
06308    int x;
06309    int s1, s2;
06310    int e1, e2;
06311    /* int cth, ctm; */
06312 
06313    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
06314    memset(i->minmask, 0, sizeof(i->minmask));
06315 
06316    /* 2-minutes per bit, since the mask has only 32 bits :( */
06317    /* Star is all times */
06318    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
06319       for (x = 0; x < 24; x++)
06320          i->minmask[x] = 0x3fffffff; /* 30 bits */
06321       return;
06322    }
06323    /* Otherwise expect a range */
06324    e = strchr(times, '-');
06325    if (!e) {
06326       ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
06327       return;
06328    }
06329    *e++ = '\0';
06330    /* XXX why skip non digits ? */
06331    while (*e && !isdigit(*e))
06332       e++;
06333    if (!*e) {
06334       ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
06335       return;
06336    }
06337    if (sscanf(times, "%2d:%2d", &s1, &s2) != 2) {
06338       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
06339       return;
06340    }
06341    if (sscanf(e, "%2d:%2d", &e1, &e2) != 2) {
06342       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
06343       return;
06344    }
06345    /* XXX this needs to be optimized */
06346 #if 1
06347    s1 = s1 * 30 + s2/2;
06348    if ((s1 < 0) || (s1 >= 24*30)) {
06349       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
06350       return;
06351    }
06352    e1 = e1 * 30 + e2/2;
06353    if ((e1 < 0) || (e1 >= 24*30)) {
06354       ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
06355       return;
06356    }
06357    /* Go through the time and enable each appropriate bit */
06358    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
06359       i->minmask[x/30] |= (1 << (x % 30));
06360    }
06361    /* Do the last one */
06362    i->minmask[x/30] |= (1 << (x % 30));
06363 #else
06364    for (cth = 0; cth < 24; cth++) {
06365       /* Initialize masks to blank */
06366       i->minmask[cth] = 0;
06367       for (ctm = 0; ctm < 30; ctm++) {
06368          if (
06369          /* First hour with more than one hour */
06370                (((cth == s1) && (ctm >= s2)) &&
06371                 ((cth < e1)))
06372          /* Only one hour */
06373          ||    (((cth == s1) && (ctm >= s2)) &&
06374                 ((cth == e1) && (ctm <= e2)))
06375          /* In between first and last hours (more than 2 hours) */
06376          ||    ((cth > s1) &&
06377                 (cth < e1))
06378          /* Last hour with more than one hour */
06379          ||    ((cth > s1) &&
06380                 ((cth == e1) && (ctm <= e2)))
06381          )
06382             i->minmask[cth] |= (1 << (ctm / 2));
06383       }
06384    }
06385 #endif
06386    /* All done */
06387    return;
06388 }
06389 
06390 static char *days[] =
06391 {
06392    "sun",
06393    "mon",
06394    "tue",
06395    "wed",
06396    "thu",
06397    "fri",
06398    "sat",
06399    NULL,
06400 };
06401 
06402 static char *months[] =
06403 {
06404    "jan",
06405    "feb",
06406    "mar",
06407    "apr",
06408    "may",
06409    "jun",
06410    "jul",
06411    "aug",
06412    "sep",
06413    "oct",
06414    "nov",
06415    "dec",
06416    NULL,
06417 };
06418 
06419 int ast_build_timing(struct ast_timing *i, const char *info_in)
06420 {
06421    char info_save[256];
06422    char *info;
06423 
06424    /* Check for empty just in case */
06425    if (ast_strlen_zero(info_in))
06426       return 0;
06427    /* make a copy just in case we were passed a static string */
06428    ast_copy_string(info_save, info_in, sizeof(info_save));
06429    info = info_save;
06430    /* Assume everything except time */
06431    i->monthmask = 0xfff;   /* 12 bits */
06432    i->daymask = 0x7fffffffU; /* 31 bits */
06433    i->dowmask = 0x7f; /* 7 bits */
06434    /* on each call, use strsep() to move info to the next argument */
06435    get_timerange(i, strsep(&info, "|,"));
06436    if (info)
06437       i->dowmask = get_range(strsep(&info, "|,"), 7, days, "day of week");
06438    if (info)
06439       i->daymask = get_range(strsep(&info, "|,"), 31, NULL, "day");
06440    if (info)
06441       i->monthmask = get_range(strsep(&info, "|,"), 12, months, "month");
06442    return 1;
06443 }
06444 
06445 int ast_check_timing(const struct ast_timing *i)
06446 {
06447    struct ast_tm tm;
06448    struct timeval now = ast_tvnow();
06449 
06450    ast_localtime(&now, &tm, NULL);
06451 
06452    /* If it's not the right month, return */
06453    if (!(i->monthmask & (1 << tm.tm_mon)))
06454       return 0;
06455 
06456    /* If it's not that time of the month.... */
06457    /* Warning, tm_mday has range 1..31! */
06458    if (!(i->daymask & (1 << (tm.tm_mday-1))))
06459       return 0;
06460 
06461    /* If it's not the right day of the week */
06462    if (!(i->dowmask & (1 << tm.tm_wday)))
06463       return 0;
06464 
06465    /* Sanity check the hour just to be safe */
06466    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
06467       ast_log(LOG_WARNING, "Insane time...\n");
06468       return 0;
06469    }
06470 
06471    /* Now the tough part, we calculate if it fits
06472       in the right time based on min/hour */
06473    if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
06474       return 0;
06475 
06476    /* If we got this far, then we're good */
06477    return 1;
06478 }
06479 
06480 /*
06481  * errno values
06482  *  ENOMEM - out of memory
06483  *  EBUSY  - can't lock
06484  *  EEXIST - already included
06485  *  EINVAL - there is no existence of context for inclusion
06486  */
06487 int ast_context_add_include2(struct ast_context *con, const char *value,
06488    const char *registrar)
06489 {
06490    struct ast_include *new_include;
06491    char *c;
06492    struct ast_include *i, *il = NULL; /* include, include_last */
06493    int length;
06494    char *p;
06495 
06496    length = sizeof(struct ast_include);
06497    length += 2 * (strlen(value) + 1);
06498 
06499    /* allocate new include structure ... */
06500    if (!(new_include = ast_calloc(1, length)))
06501       return -1;
06502    /* Fill in this structure. Use 'p' for assignments, as the fields
06503     * in the structure are 'const char *'
06504     */
06505    p = new_include->stuff;
06506    new_include->name = p;
06507    strcpy(p, value);
06508    p += strlen(value) + 1;
06509    new_include->rname = p;
06510    strcpy(p, value);
06511    /* Strip off timing info, and process if it is there */
06512    if ( (c = strchr(p, ',')) ) {
06513       *c++ = '\0';
06514            new_include->hastime = ast_build_timing(&(new_include->timing), c);
06515    }
06516    new_include->next      = NULL;
06517    new_include->registrar = registrar;
06518 
06519    ast_wrlock_context(con);
06520 
06521    /* ... go to last include and check if context is already included too... */
06522    for (i = con->includes; i; i = i->next) {
06523       if (!strcasecmp(i->name, new_include->name)) {
06524          ast_free(new_include);
06525          ast_unlock_context(con);
06526          errno = EEXIST;
06527          return -1;
06528       }
06529       il = i;
06530    }
06531 
06532    /* ... include new context into context list, unlock, return */
06533    if (il)
06534       il->next = new_include;
06535    else
06536       con->includes = new_include;
06537    ast_verb(3, "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
06538 
06539    ast_unlock_context(con);
06540 
06541    return 0;
06542 }
06543 
06544 /*
06545  * errno values
06546  *  EBUSY  - can't lock
06547  *  ENOENT - no existence of context
06548  */
06549 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
06550 {
06551    int ret = -1;
06552    struct ast_context *c = find_context_locked(context);
06553 
06554    if (c) { /* found, add switch to this context */
06555       ret = ast_context_add_switch2(c, sw, data, eval, registrar);
06556       ast_unlock_contexts();
06557    }
06558    return ret;
06559 }
06560 
06561 /*
06562  * errno values
06563  *  ENOMEM - out of memory
06564  *  EBUSY  - can't lock
06565  *  EEXIST - already included
06566  *  EINVAL - there is no existence of context for inclusion
06567  */
06568 int ast_context_add_switch2(struct ast_context *con, const char *value,
06569    const char *data, int eval, const char *registrar)
06570 {
06571    struct ast_sw *new_sw;
06572    struct ast_sw *i;
06573    int length;
06574    char *p;
06575 
06576    length = sizeof(struct ast_sw);
06577    length += strlen(value) + 1;
06578    if (data)
06579       length += strlen(data);
06580    length++;
06581 
06582    /* allocate new sw structure ... */
06583    if (!(new_sw = ast_calloc(1, length)))
06584       return -1;
06585    /* ... fill in this structure ... */
06586    p = new_sw->stuff;
06587    new_sw->name = p;
06588    strcpy(new_sw->name, value);
06589    p += strlen(value) + 1;
06590    new_sw->data = p;
06591    if (data) {
06592       strcpy(new_sw->data, data);
06593       p += strlen(data) + 1;
06594    } else {
06595       strcpy(new_sw->data, "");
06596       p++;
06597    }
06598    new_sw->eval     = eval;
06599    new_sw->registrar = registrar;
06600 
06601    /* ... try to lock this context ... */
06602    ast_wrlock_context(con);
06603 
06604    /* ... go to last sw and check if context is already swd too... */
06605    AST_LIST_TRAVERSE(&con->alts, i, list) {
06606       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
06607          ast_free(new_sw);
06608          ast_unlock_context(con);
06609          errno = EEXIST;
06610          return -1;
06611       }
06612    }
06613 
06614    /* ... sw new context into context list, unlock, return */
06615    AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
06616 
06617    ast_verb(3, "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
06618 
06619    ast_unlock_context(con);
06620 
06621    return 0;
06622 }
06623 
06624 /*
06625  * EBUSY  - can't lock
06626  * ENOENT - there is not context existence
06627  */
06628 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
06629 {
06630    int ret = -1;
06631    struct ast_context *c = find_context_locked(context);
06632 
06633    if (c) {
06634       ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
06635       ast_unlock_contexts();
06636    }
06637    return ret;
06638 }
06639 
06640 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
06641 {
06642    struct ast_ignorepat *ip, *ipl = NULL;
06643 
06644    ast_wrlock_context(con);
06645 
06646    for (ip = con->ignorepats; ip; ip = ip->next) {
06647       if (!strcmp(ip->pattern, ignorepat) &&
06648          (!registrar || (registrar == ip->registrar))) {
06649          if (ipl) {
06650             ipl->next = ip->next;
06651             ast_free(ip);
06652          } else {
06653             con->ignorepats = ip->next;
06654             ast_free(ip);
06655          }
06656          ast_unlock_context(con);
06657          return 0;
06658       }
06659       ipl = ip;
06660    }
06661 
06662    ast_unlock_context(con);
06663    errno = EINVAL;
06664    return -1;
06665 }
06666 
06667 /*
06668  * EBUSY - can't lock
06669  * ENOENT - there is no existence of context
06670  */
06671 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
06672 {
06673    int ret = -1;
06674    struct ast_context *c = find_context_locked(context);
06675 
06676    if (c) {
06677       ret = ast_context_add_ignorepat2(c, value, registrar);
06678       ast_unlock_contexts();
06679    }
06680    return ret;
06681 }
06682 
06683 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
06684 {
06685    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
06686    int length;
06687    char *pattern;
06688    length = sizeof(struct ast_ignorepat);
06689    length += strlen(value) + 1;
06690    if (!(ignorepat = ast_calloc(1, length)))
06691       return -1;
06692    /* The cast to char * is because we need to write the initial value.
06693     * The field is not supposed to be modified otherwise.  Also, gcc 4.2
06694     * sees the cast as dereferencing a type-punned pointer and warns about
06695     * it.  This is the workaround (we're telling gcc, yes, that's really
06696     * what we wanted to do).
06697     */
06698    pattern = (char *) ignorepat->pattern;
06699    strcpy(pattern, value);
06700    ignorepat->next = NULL;
06701    ignorepat->registrar = registrar;
06702    ast_wrlock_context(con);
06703    for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
06704       ignorepatl = ignorepatc;
06705       if (!strcasecmp(ignorepatc->pattern, value)) {
06706          /* Already there */
06707          ast_unlock_context(con);
06708          errno = EEXIST;
06709          return -1;
06710       }
06711    }
06712    if (ignorepatl)
06713       ignorepatl->next = ignorepat;
06714    else
06715       con->ignorepats = ignorepat;
06716    ast_unlock_context(con);
06717    return 0;
06718 
06719 }
06720 
06721 int ast_ignore_pattern(const char *context, const char *pattern)
06722 {
06723    struct ast_context *con = ast_context_find(context);
06724    if (con) {
06725       struct ast_ignorepat *pat;
06726       for (pat = con->ignorepats; pat; pat = pat->next) {
06727          if (ast_extension_match(pat->pattern, pattern))
06728             return 1;
06729       }
06730    }
06731 
06732    return 0;
06733 }
06734 
06735 /*
06736  * ast_add_extension_nolock -- use only in situations where the conlock is already held
06737  * ENOENT  - no existence of context
06738  *
06739  */
06740 static int ast_add_extension_nolock(const char *context, int replace, const char *extension,
06741    int priority, const char *label, const char *callerid,
06742    const char *application, void *data, void (*datad)(void *), const char *registrar)
06743 {
06744    int ret = -1;
06745    struct ast_context *c = find_context(context);
06746 
06747    if (c) {
06748       ret = ast_add_extension2_lockopt(c, replace, extension, priority, label, callerid,
06749          application, data, datad, registrar, 0, 0);
06750    }
06751    
06752    return ret;
06753 }
06754 /*
06755  * EBUSY   - can't lock
06756  * ENOENT  - no existence of context
06757  *
06758  */
06759 int ast_add_extension(const char *context, int replace, const char *extension,
06760    int priority, const char *label, const char *callerid,
06761    const char *application, void *data, void (*datad)(void *), const char *registrar)
06762 {
06763    int ret = -1;
06764    struct ast_context *c = find_context_locked(context);
06765 
06766    if (c) {
06767       ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
06768          application, data, datad, registrar);
06769       ast_unlock_contexts();
06770    }
06771    
06772    return ret;
06773 }
06774 
06775 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
06776 {
06777    if (!chan)
06778       return -1;
06779 
06780    ast_channel_lock(chan);
06781 
06782    if (!ast_strlen_zero(context))
06783       ast_copy_string(chan->context, context, sizeof(chan->context));
06784    if (!ast_strlen_zero(exten))
06785       ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06786    if (priority > -1) {
06787       chan->priority = priority;
06788       /* see flag description in channel.h for explanation */
06789       if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
06790          chan->priority--;
06791    }
06792 
06793    ast_channel_unlock(chan);
06794 
06795    return 0;
06796 }
06797 
06798 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
06799 {
06800    int res = 0;
06801 
06802    ast_channel_lock(chan);
06803 
06804    if (chan->pbx) { /* This channel is currently in the PBX */
06805       ast_explicit_goto(chan, context, exten, priority + 1);
06806       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
06807    } else {
06808       /* In order to do it when the channel doesn't really exist within
06809          the PBX, we have to make a new channel, masquerade, and start the PBX
06810          at the new location */
06811       struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
06812       if (!tmpchan) {
06813          res = -1;
06814       } else {
06815          if (chan->cdr) {
06816             ast_cdr_discard(tmpchan->cdr);
06817             tmpchan->cdr = ast_cdr_dup(chan->cdr);  /* share the love */
06818          }
06819          /* Make formats okay */
06820          tmpchan->readformat = chan->readformat;
06821          tmpchan->writeformat = chan->writeformat;
06822          /* Setup proper location */
06823          ast_explicit_goto(tmpchan,
06824             S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
06825 
06826          /* Masquerade into temp channel */
06827          if (ast_channel_masquerade(tmpchan, chan)) {
06828             /* Failed to set up the masquerade.  It's probably chan_local
06829              * in the middle of optimizing itself out.  Sad. :( */
06830             ast_hangup(tmpchan);
06831             tmpchan = NULL;
06832             res = -1;
06833          } else {
06834             /* Grab the locks and get going */
06835             ast_channel_lock(tmpchan);
06836             ast_do_masquerade(tmpchan);
06837             ast_channel_unlock(tmpchan);
06838             /* Start the PBX going on our stolen channel */
06839             if (ast_pbx_start(tmpchan)) {
06840                ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
06841                ast_hangup(tmpchan);
06842                res = -1;
06843             }
06844          }
06845       }
06846    }
06847    ast_channel_unlock(chan);
06848    return res;
06849 }
06850 
06851 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
06852 {
06853    struct ast_channel *chan;
06854    int res = -1;
06855 
06856    chan = ast_get_channel_by_name_locked(channame);
06857    if (chan) {
06858       res = ast_async_goto(chan, context, exten, priority);
06859       ast_channel_unlock(chan);
06860    }
06861    return res;
06862 }
06863 
06864 /*! \brief copy a string skipping whitespace */
06865 static int ext_strncpy(char *dst, const char *src, int len)
06866 {
06867    int count = 0;
06868 
06869    while (*src && (count < len - 1)) {
06870       switch (*src) {
06871       case ' ':
06872          /* otherwise exten => [a-b],1,... doesn't work */
06873          /*    case '-': */
06874          /* Ignore */
06875          break;
06876       default:
06877          *dst = *src;
06878          dst++;
06879       }
06880       src++;
06881       count++;
06882    }
06883    *dst = '\0';
06884 
06885    return count;
06886 }
06887 
06888 /*! 
06889  * \brief add the extension in the priority chain.
06890  * \retval 0 on success.
06891  * \retval -1 on failure.
06892 */
06893 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
06894    struct ast_exten *el, struct ast_exten *e, int replace)
06895 {
06896    return add_pri_lockopt(con, tmp, el, e, replace, 1);
06897 }
06898 
06899 /*! 
06900  * \brief add the extension in the priority chain.
06901  * \retval 0 on success.
06902  * \retval -1 on failure.
06903 */
06904 static int add_pri_lockopt(struct ast_context *con, struct ast_exten *tmp,
06905    struct ast_exten *el, struct ast_exten *e, int replace, int lockhints)
06906 {
06907    struct ast_exten *ep;
06908    struct ast_exten *eh=e;
06909 
06910    for (ep = NULL; e ; ep = e, e = e->peer) {
06911       if (e->priority >= tmp->priority)
06912          break;
06913    }
06914    if (!e) {   /* go at the end, and ep is surely set because the list is not empty */
06915       ast_hashtab_insert_safe(eh->peer_table, tmp);
06916       
06917       if (tmp->label) {
06918          ast_hashtab_insert_safe(eh->peer_label_table, tmp);
06919       }
06920       ep->peer = tmp;
06921       return 0;   /* success */
06922    }
06923    if (e->priority == tmp->priority) {
06924       /* Can't have something exactly the same.  Is this a
06925          replacement?  If so, replace, otherwise, bonk. */
06926       if (!replace) {
06927          ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
06928          if (tmp->datad) {
06929             tmp->datad(tmp->data);
06930             /* if you free this, null it out */
06931             tmp->data = NULL;
06932          }
06933          
06934          ast_free(tmp);
06935          return -1;
06936       }
06937       /* we are replacing e, so copy the link fields and then update
06938        * whoever pointed to e to point to us
06939        */
06940       tmp->next = e->next; /* not meaningful if we are not first in the peer list */
06941       tmp->peer = e->peer; /* always meaningful */
06942       if (ep)  {     /* We're in the peer list, just insert ourselves */
06943          ast_hashtab_remove_object_via_lookup(eh->peer_table,e);
06944 
06945          if (e->label) {
06946             ast_hashtab_remove_object_via_lookup(eh->peer_label_table,e);
06947          }
06948          
06949          ast_hashtab_insert_safe(eh->peer_table,tmp);
06950          if (tmp->label) {
06951             ast_hashtab_insert_safe(eh->peer_label_table,tmp);
06952          }
06953          
06954          ep->peer = tmp;
06955       } else if (el) {     /* We're the first extension. Take over e's functions */
06956          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
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          el->next = 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, don't sweat this */
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       } else {       /* We're the very first extension.  */
06981          struct match_char *x = add_exten_to_pattern_tree(con, e, 1);
06982          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06983          ast_hashtab_insert_safe(con->root_table, tmp);
06984          tmp->peer_table = e->peer_table;
06985          tmp->peer_label_table = e->peer_label_table;
06986          ast_hashtab_remove_object_via_lookup(tmp->peer_table, e);
06987          ast_hashtab_insert_safe(tmp->peer_table, tmp);
06988          if (e->label) {
06989             ast_hashtab_remove_object_via_lookup(tmp->peer_label_table, e);
06990          }
06991          if (tmp->label) {
06992             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
06993          }
06994          
06995          ast_hashtab_remove_object_via_lookup(con->root_table, e);
06996          ast_hashtab_insert_safe(con->root_table, tmp);
06997          con->root = tmp;
06998          /* The pattern trie points to this exten; replace the pointer,
06999             and all will be well */
07000          if (x) { /* if the trie isn't formed yet; no problem */
07001             if (x->exten) { /* this test for safety purposes */
07002                x->exten = tmp; /* replace what would become a bad pointer */
07003             } else {
07004                ast_log(LOG_ERROR,"Trying to delete an exten from a context, but the pattern tree node returned isn't an extension\n");
07005             }
07006          }
07007       }
07008       if (tmp->priority == PRIORITY_HINT)
07009          ast_change_hint(e,tmp);
07010       /* Destroy the old one */
07011       if (e->datad)
07012          e->datad(e->data);
07013       ast_free(e);
07014    } else { /* Slip ourselves in just before e */
07015       tmp->peer = e;
07016       tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
07017       if (ep) {         /* Easy enough, we're just in the peer list */
07018          if (tmp->label) {
07019             ast_hashtab_insert_safe(eh->peer_label_table, tmp);
07020          }
07021          ast_hashtab_insert_safe(eh->peer_table, tmp);
07022          ep->peer = tmp;
07023       } else {       /* we are the first in some peer list, so link in the ext list */
07024          tmp->peer_table = e->peer_table;
07025          tmp->peer_label_table = e->peer_label_table;
07026          e->peer_table = 0;
07027          e->peer_label_table = 0;
07028          ast_hashtab_insert_safe(tmp->peer_table, tmp);
07029          if (tmp->label) {
07030             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07031          }
07032          ast_hashtab_remove_object_via_lookup(con->root_table, e);
07033          ast_hashtab_insert_safe(con->root_table, tmp);
07034          if (el)
07035             el->next = tmp;   /* in the middle... */
07036          else
07037             con->root = tmp; /* ... or at the head */
07038          e->next = NULL;   /* e is no more at the head, so e->next must be reset */
07039       }
07040       /* And immediately return success. */
07041       if (tmp->priority == PRIORITY_HINT) {
07042          if (lockhints) {
07043             ast_add_hint(tmp);
07044          } else {
07045             ast_add_hint_nolock(tmp);
07046          }
07047       }
07048    }
07049    return 0;
07050 }
07051 
07052 /*! \brief
07053  * Main interface to add extensions to the list for out context.
07054  *
07055  * We sort extensions in order of matching preference, so that we can
07056  * stop the search as soon as we find a suitable match.
07057  * This ordering also takes care of wildcards such as '.' (meaning
07058  * "one or more of any character") and '!' (which is 'earlymatch',
07059  * meaning "zero or more of any character" but also impacts the
07060  * return value from CANMATCH and EARLYMATCH.
07061  *
07062  * The extension match rules defined in the devmeeting 2006.05.05 are
07063  * quite simple: WE SELECT THE LONGEST MATCH.
07064  * In detail, "longest" means the number of matched characters in
07065  * the extension. In case of ties (e.g. _XXX and 333) in the length
07066  * of a pattern, we give priority to entries with the smallest cardinality
07067  * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
07068  * while the latter has 7, etc.
07069  * In case of same cardinality, the first element in the range counts.
07070  * If we still have a tie, any final '!' will make this as a possibly
07071  * less specific pattern.
07072  *
07073  * EBUSY - can't lock
07074  * EEXIST - extension with the same priority exist and no replace is set
07075  *
07076  */
07077 int ast_add_extension2(struct ast_context *con,
07078    int replace, const char *extension, int priority, const char *label, const char *callerid,
07079    const char *application, void *data, void (*datad)(void *),
07080    const char *registrar)
07081 {
07082    return ast_add_extension2_lockopt(con, replace, extension, priority, label, callerid, application, data, datad, registrar, 1, 1);
07083 }
07084 
07085 /*! \brief
07086  * Does all the work of ast_add_extension2, but adds two args, to determine if 
07087  * context and hint locking should be done. In merge_and_delete, we need to do
07088  * this without locking, as the locks are already held.
07089  */
07090 static int ast_add_extension2_lockopt(struct ast_context *con,
07091    int replace, const char *extension, int priority, const char *label, const char *callerid,
07092    const char *application, void *data, void (*datad)(void *),
07093    const char *registrar, int lockconts, int lockhints)
07094 {
07095    /*
07096     * Sort extensions (or patterns) according to the rules indicated above.
07097     * These are implemented by the function ext_cmp()).
07098     * All priorities for the same ext/pattern/cid are kept in a list,
07099     * using the 'peer' field  as a link field..
07100     */
07101    struct ast_exten *tmp, *tmp2, *e, *el = NULL;
07102    int res;
07103    int length;
07104    char *p;
07105    char expand_buf[VAR_BUF_SIZE];
07106    struct ast_exten dummy_exten = {0};
07107    char dummy_name[1024];
07108 
07109    if (ast_strlen_zero(extension)) {
07110       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",
07111             con->name);
07112       return -1;
07113    }
07114    
07115    /* If we are adding a hint evalulate in variables and global variables */
07116    if (priority == PRIORITY_HINT && strstr(application, "${") && !strstr(extension, "_")) {
07117       struct ast_channel c = {0, };
07118 
07119       ast_copy_string(c.exten, extension, sizeof(c.exten));
07120       ast_copy_string(c.context, con->name, sizeof(c.context));
07121       pbx_substitute_variables_helper(&c, application, expand_buf, sizeof(expand_buf));
07122       application = expand_buf;
07123    }
07124 
07125    length = sizeof(struct ast_exten);
07126    length += strlen(extension) + 1;
07127    length += strlen(application) + 1;
07128    if (label)
07129       length += strlen(label) + 1;
07130    if (callerid)
07131       length += strlen(callerid) + 1;
07132    else
07133       length ++;  /* just the '\0' */
07134 
07135    /* Be optimistic:  Build the extension structure first */
07136    if (!(tmp = ast_calloc(1, length)))
07137       return -1;
07138 
07139    if (ast_strlen_zero(label)) /* let's turn empty labels to a null ptr */
07140       label = 0;
07141 
07142    /* use p as dst in assignments, as the fields are const char * */
07143    p = tmp->stuff;
07144    if (label) {
07145       tmp->label = p;
07146       strcpy(p, label);
07147       p += strlen(label) + 1;
07148    }
07149    tmp->exten = p;
07150    p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
07151    tmp->priority = priority;
07152    tmp->cidmatch = p;   /* but use p for assignments below */
07153 
07154    /* Blank callerid and NULL callerid are two SEPARATE things.  Do NOT confuse the two!!! */
07155    if (callerid) {
07156       p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
07157       tmp->matchcid = 1;
07158    } else {
07159       *p++ = '\0';
07160       tmp->matchcid = 0;
07161    }
07162    tmp->app = p;
07163    strcpy(p, application);
07164    tmp->parent = con;
07165    tmp->data = data;
07166    tmp->datad = datad;
07167    tmp->registrar = registrar;
07168 
07169    if (lockconts) {
07170       ast_wrlock_context(con);
07171    }
07172    
07173    if (con->pattern_tree) { /* usually, on initial load, the pattern_tree isn't formed until the first find_exten; so if we are adding
07174                         an extension, and the trie exists, then we need to incrementally add this pattern to it. */
07175       ast_copy_string(dummy_name, extension, sizeof(dummy_name));
07176       dummy_exten.exten = dummy_name;
07177       dummy_exten.matchcid = 0;
07178       dummy_exten.cidmatch = 0;
07179       tmp2 = ast_hashtab_lookup(con->root_table, &dummy_exten);
07180       if (!tmp2) {
07181          /* hmmm, not in the trie; */
07182          add_exten_to_pattern_tree(con, tmp, 0);
07183          ast_hashtab_insert_safe(con->root_table, tmp); /* for the sake of completeness */
07184       }
07185    }
07186    res = 0; /* some compilers will think it is uninitialized otherwise */
07187    for (e = con->root; e; el = e, e = e->next) {   /* scan the extension list */
07188       res = ext_cmp(e->exten, tmp->exten);
07189       if (res == 0) { /* extension match, now look at cidmatch */
07190          if (!e->matchcid && !tmp->matchcid)
07191             res = 0;
07192          else if (tmp->matchcid && !e->matchcid)
07193             res = 1;
07194          else if (e->matchcid && !tmp->matchcid)
07195             res = -1;
07196          else
07197             res = ext_cmp(e->cidmatch, tmp->cidmatch);
07198       }
07199       if (res >= 0)
07200          break;
07201    }
07202    if (e && res == 0) { /* exact match, insert in the pri chain */
07203       res = add_pri(con, tmp, el, e, replace);
07204       if (lockconts) {
07205          ast_unlock_context(con);
07206       }
07207       if (res < 0) {
07208          errno = EEXIST;   /* XXX do we care ? */
07209          return 0; /* XXX should we return -1 maybe ? */
07210       }
07211    } else {
07212       /*
07213        * not an exact match, this is the first entry with this pattern,
07214        * so insert in the main list right before 'e' (if any)
07215        */
07216       tmp->next = e;
07217       if (el) {  /* there is another exten already in this context */
07218          el->next = tmp;
07219          tmp->peer_table = ast_hashtab_create(13,
07220                      hashtab_compare_exten_numbers,
07221                      ast_hashtab_resize_java,
07222                      ast_hashtab_newsize_java,
07223                      hashtab_hash_priority,
07224                      0);
07225          tmp->peer_label_table = ast_hashtab_create(7,
07226                         hashtab_compare_exten_labels,
07227                         ast_hashtab_resize_java,
07228                         ast_hashtab_newsize_java,
07229                         hashtab_hash_labels,
07230                         0);
07231          if (label) {
07232             ast_hashtab_insert_safe(tmp->peer_label_table, tmp);
07233          }
07234          ast_hashtab_insert_safe(tmp->peer_table, tmp);
07235       } else {  /* this is the first exten in this context */
07236          if (!con->root_table)
07237             con->root_table = ast_hashtab_create(27,
07238                                        hashtab_compare_extens,
07239                                        ast_hashtab_resize_java,
07240                                        ast_hashtab_newsize_java,
07241                                        hashtab_hash_extens,
07242                                        0);
07243          con->root = tmp;
07244          con->root->peer_table = ast_hashtab_create(13,
07245                         hashtab_compare_exten_numbers,
07246                         ast_hashtab_resize_java,
07247                         ast_hashtab_newsize_java,
07248                         hashtab_hash_priority,
07249                         0);
07250          con->root->peer_label_table = ast_hashtab_create(7,
07251                            hashtab_compare_exten_labels,
07252                            ast_hashtab_resize_java,
07253                            ast_hashtab_newsize_java,
07254                            hashtab_hash_labels,
07255                            0);
07256          if (label) {
07257             ast_hashtab_insert_safe(con->root->peer_label_table, tmp);
07258          }
07259          ast_hashtab_insert_safe(con->root->peer_table, tmp);
07260             
07261       }
07262       ast_hashtab_insert_safe(con->root_table, tmp);
07263       if (lockconts) {
07264          ast_unlock_context(con);
07265       }
07266       if (tmp->priority == PRIORITY_HINT) {
07267          if (lockhints) {
07268             ast_add_hint(tmp);
07269          } else {
07270             ast_add_hint_nolock(tmp);
07271          }
07272       }
07273    }
07274    if (option_debug) {
07275       if (tmp->matchcid) {
07276          ast_debug(1, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
07277                  tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
07278       } else {
07279          ast_debug(1, "Added extension '%s' priority %d to %s (%p)\n",
07280                  tmp->exten, tmp->priority, con->name, con);
07281       }
07282    }
07283 
07284    if (tmp->matchcid) {
07285       ast_verb(3, "Added extension '%s' priority %d (CID match '%s') to %s (%p)\n",
07286              tmp->exten, tmp->priority, tmp->cidmatch, con->name, con);
07287    } else {
07288       ast_verb(3, "Added extension '%s' priority %d to %s (%p)\n",
07289              tmp->exten, tmp->priority, con->name, con);
07290    }
07291    
07292    return 0;
07293 }
07294 
07295 struct async_stat {
07296    pthread_t p;
07297    struct ast_channel *chan;
07298    char context[AST_MAX_CONTEXT];
07299    char exten[AST_MAX_EXTENSION];
07300    int priority;
07301    int timeout;
07302    char app[AST_MAX_EXTENSION];
07303    char appdata[1024];
07304 };
07305 
07306 static void *async_wait(void *data)
07307 {
07308    struct async_stat *as = data;
07309    struct ast_channel *chan = as->chan;
07310    int timeout = as->timeout;
07311    int res;
07312    struct ast_frame *f;
07313    struct ast_app *app;
07314 
07315    while (timeout && (chan->_state != AST_STATE_UP)) {
07316       res = ast_waitfor(chan, timeout);
07317       if (res < 1)
07318          break;
07319       if (timeout > -1)
07320          timeout = res;
07321       f = ast_read(chan);
07322       if (!f)
07323          break;
07324       if (f->frametype == AST_FRAME_CONTROL) {
07325          if ((f->subclass == AST_CONTROL_BUSY)  ||
07326              (f->subclass == AST_CONTROL_CONGESTION) ) {
07327             ast_frfree(f);
07328             break;
07329          }
07330       }
07331       ast_frfree(f);
07332    }
07333    if (chan->_state == AST_STATE_UP) {
07334       if (!ast_strlen_zero(as->app)) {
07335          app = pbx_findapp(as->app);
07336          if (app) {
07337             ast_verb(3, "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
07338             pbx_exec(chan, app, as->appdata);
07339          } else
07340             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
07341       } else {
07342          if (!ast_strlen_zero(as->context))
07343             ast_copy_string(chan->context, as->context, sizeof(chan->context));
07344          if (!ast_strlen_zero(as->exten))
07345             ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
07346          if (as->priority > 0)
07347             chan->priority = as->priority;
07348          /* Run the PBX */
07349          if (ast_pbx_run(chan)) {
07350             ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
07351          } else {
07352             /* PBX will have taken care of this */
07353             chan = NULL;
07354          }
07355       }
07356    }
07357    ast_free(as);
07358    if (chan)
07359       ast_hangup(chan);
07360    return NULL;
07361 }
07362 
07363 /*! 
07364  * \brief Function to post an empty cdr after a spool call fails.
07365  * \note This function posts an empty cdr for a failed spool call
07366 */
07367 static int ast_pbx_outgoing_cdr_failed(void)
07368 {
07369    /* allocate a channel */
07370    struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", "");
07371 
07372    if (!chan)
07373       return -1;  /* failure */
07374 
07375    if (!chan->cdr) {
07376       /* allocation of the cdr failed */
07377       ast_channel_free(chan);   /* free the channel */
07378       return -1;                /* return failure */
07379    }
07380 
07381    /* allocation of the cdr was successful */
07382    ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
07383    ast_cdr_start(chan->cdr);       /* record the start and stop time */
07384    ast_cdr_end(chan->cdr);
07385    ast_cdr_failed(chan->cdr);      /* set the status to failed */
07386    ast_cdr_detach(chan->cdr);      /* post and free the record */
07387    chan->cdr = NULL;
07388    ast_channel_free(chan);         /* free the channel */
07389 
07390    return 0;  /* success */
07391 }
07392 
07393 int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
07394 {
07395    struct ast_channel *chan;
07396    struct async_stat *as;
07397    int res = -1, cdr_res = -1;
07398    struct outgoing_helper oh;
07399 
07400    if (synchronous) {
07401       oh.context = context;
07402       oh.exten = exten;
07403       oh.priority = priority;
07404       oh.cid_num = cid_num;
07405       oh.cid_name = cid_name;
07406       oh.account = account;
07407       oh.vars = vars;
07408       oh.parent_channel = NULL;
07409 
07410       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07411       if (channel) {
07412          *channel = chan;
07413          if (chan)
07414             ast_channel_lock(chan);
07415       }
07416       if (chan) {
07417          if (chan->_state == AST_STATE_UP) {
07418                res = 0;
07419             ast_verb(4, "Channel %s was answered.\n", chan->name);
07420 
07421             if (synchronous > 1) {
07422                if (channel)
07423                   ast_channel_unlock(chan);
07424                if (ast_pbx_run(chan)) {
07425                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
07426                   if (channel)
07427                      *channel = NULL;
07428                   ast_hangup(chan);
07429                   chan = NULL;
07430                   res = -1;
07431                }
07432             } else {
07433                if (ast_pbx_start(chan)) {
07434                   ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
07435                   if (channel) {
07436                      *channel = NULL;
07437                      ast_channel_unlock(chan);
07438                   }
07439                   ast_hangup(chan);
07440                   res = -1;
07441                }
07442                chan = NULL;
07443             }
07444          } else {
07445             ast_verb(4, "Channel %s was never answered.\n", chan->name);
07446 
07447             if (chan->cdr) { /* update the cdr */
07448                /* here we update the status of the call, which sould be busy.
07449                 * if that fails then we set the status to failed */
07450                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
07451                   ast_cdr_failed(chan->cdr);
07452             }
07453 
07454             if (channel) {
07455                *channel = NULL;
07456                ast_channel_unlock(chan);
07457             }
07458             ast_hangup(chan);
07459             chan = NULL;
07460          }
07461       }
07462 
07463       if (res < 0) { /* the call failed for some reason */
07464          if (*reason == 0) { /* if the call failed (not busy or no answer)
07465                         * update the cdr with the failed message */
07466             cdr_res = ast_pbx_outgoing_cdr_failed();
07467             if (cdr_res != 0) {
07468                res = cdr_res;
07469                goto outgoing_exten_cleanup;
07470             }
07471          }
07472 
07473          /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
07474          /* check if "failed" exists */
07475          if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
07476             chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
07477             if (chan) {
07478                char failed_reason[4] = "";
07479                if (!ast_strlen_zero(context))
07480                   ast_copy_string(chan->context, context, sizeof(chan->context));
07481                set_ext_pri(chan, "failed", 1);
07482                ast_set_variables(chan, vars);
07483                snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
07484                pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
07485                if (account)
07486                   ast_cdr_setaccount(chan, account);
07487                if (ast_pbx_run(chan)) {
07488                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
07489                   ast_hangup(chan);
07490                }
07491                chan = NULL;
07492             }
07493          }
07494       }
07495    } else {
07496       if (!(as = ast_calloc(1, sizeof(*as)))) {
07497          res = -1;
07498          goto outgoing_exten_cleanup;
07499       }
07500       chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
07501       if (channel) {
07502          *channel = chan;
07503          if (chan)
07504             ast_channel_lock(chan);
07505       }
07506       if (!chan) {
07507          ast_free(as);
07508          res = -1;
07509          goto outgoing_exten_cleanup;
07510       }
07511       as->chan = chan;
07512       ast_copy_string(as->context, context, sizeof(as->context));
07513       set_ext_pri(as->chan,  exten, priority);
07514       as->timeout = timeout;
07515       ast_set_variables(chan, vars);
07516       if (account)
07517          ast_cdr_setaccount(chan, account);
07518       if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
07519          ast_log(LOG_WARNING, "Failed to start async wait\n");
07520          ast_free(as);
07521          if (channel) {
07522             *channel = NULL;
07523             ast_channel_unlock(chan);
07524          }
07525          ast_hangup(chan);
07526          res = -1;
07527          goto outgoing_exten_cleanup;
07528       }
07529       res = 0;
07530    }
07531 outgoing_exten_cleanup:
07532    ast_variables_destroy(vars);
07533    return res;
07534 }
07535 
07536 struct app_tmp {
07537    char app[256];
07538    char data[256];
07539    struct ast_channel *chan;
07540    pthread_t t;
07541 };
07542 
07543 /*! \brief run the application and free the descriptor once done */
07544 static void *ast_pbx_run_app(void *data)
07545 {
07546    struct app_tmp *tmp = data;
07547    struct ast_app *app;
07548    app = pbx_findapp(tmp->app);
07549    if (app) {
07550       ast_verb(4, "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
07551       pbx_exec(tmp->chan, app, tmp->data);
07552    } else
07553       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
07554    ast_hangup(tmp->chan);
07555    ast_free(tmp);
07556    return NULL;
07557 }
07558 
07559 int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int synchronous, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
07560 {
07561    struct ast_channel *chan;
07562    struct app_tmp *tmp;
07563    int res = -1, cdr_res = -1;
07564    struct outgoing_helper oh;
07565 
07566    memset(&oh, 0, sizeof(oh));
07567    oh.vars = vars;
07568    oh.account = account;
07569 
07570    if (locked_channel)
07571       *locked_channel = NULL;
07572    if (ast_strlen_zero(app)) {
07573       res = -1;
07574       goto outgoing_app_cleanup;
07575    }
07576    if (synchronous) {
07577       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07578       if (chan) {
07579          ast_set_variables(chan, vars);
07580          if (account)
07581             ast_cdr_setaccount(chan, account);
07582          if (chan->_state == AST_STATE_UP) {
07583             res = 0;
07584             ast_verb(4, "Channel %s was answered.\n", chan->name);
07585             tmp = ast_calloc(1, sizeof(*tmp));
07586             if (!tmp)
07587                res = -1;
07588             else {
07589                ast_copy_string(tmp->app, app, sizeof(tmp->app));
07590                if (appdata)
07591                   ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
07592                tmp->chan = chan;
07593                if (synchronous > 1) {
07594                   if (locked_channel)
07595                      ast_channel_unlock(chan);
07596                   ast_pbx_run_app(tmp);
07597                } else {
07598                   if (locked_channel)
07599                      ast_channel_lock(chan);
07600                   if (ast_pthread_create_detached(&tmp->t, NULL, ast_pbx_run_app, tmp)) {
07601                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
07602                      ast_free(tmp);
07603                      if (locked_channel)
07604                         ast_channel_unlock(chan);
07605                      ast_hangup(chan);
07606                      res = -1;
07607                   } else {
07608                      if (locked_channel)
07609                         *locked_channel = chan;
07610                   }
07611                }
07612             }
07613          } else {
07614             ast_verb(4, "Channel %s was never answered.\n", chan->name);
07615             if (chan->cdr) { /* update the cdr */
07616                /* here we update the status of the call, which sould be busy.
07617                 * if that fails then we set the status to failed */
07618                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
07619                   ast_cdr_failed(chan->cdr);
07620             }
07621             ast_hangup(chan);
07622          }
07623       }
07624 
07625       if (res < 0) { /* the call failed for some reason */
07626          if (*reason == 0) { /* if the call failed (not busy or no answer)
07627                         * update the cdr with the failed message */
07628             cdr_res = ast_pbx_outgoing_cdr_failed();
07629             if (cdr_res != 0) {
07630                res = cdr_res;
07631                goto outgoing_app_cleanup;
07632             }
07633          }
07634       }
07635 
07636    } else {
07637       struct async_stat *as;
07638       if (!(as = ast_calloc(1, sizeof(*as)))) {
07639          res = -1;
07640          goto outgoing_app_cleanup;
07641       }
07642       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
07643       if (!chan) {
07644          ast_free(as);
07645          res = -1;
07646          goto outgoing_app_cleanup;
07647       }
07648       as->chan = chan;
07649       ast_copy_string(as->app, app, sizeof(as->app));
07650       if (appdata)
07651          ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
07652       as->timeout = timeout;
07653       ast_set_variables(chan, vars);
07654       if (account)
07655          ast_cdr_setaccount(chan, account);
07656       /* Start a new thread, and get something handling this channel. */
07657       if (locked_channel)
07658          ast_channel_lock(chan);
07659       if (ast_pthread_create_detached(&as->p, NULL, async_wait, as)) {
07660          ast_log(LOG_WARNING, "Failed to start async wait\n");
07661          ast_free(as);
07662          if (locked_channel)
07663             ast_channel_unlock(chan);
07664          ast_hangup(chan);
07665          res = -1;
07666          goto outgoing_app_cleanup;
07667       } else {
07668          if (locked_channel)
07669             *locked_channel = chan;
07670       }
07671       res = 0;
07672    }
07673 outgoing_app_cleanup:
07674    ast_variables_destroy(vars);
07675    return res;
07676 }
07677 
07678 /* this is the guts of destroying a context --
07679    freeing up the structure, traversing and destroying the
07680    extensions, switches, ignorepats, includes, etc. etc. */
07681 
07682 static void __ast_internal_context_destroy( struct ast_context *con)
07683 {
07684    struct ast_include *tmpi;
07685    struct ast_sw *sw;
07686    struct ast_exten *e, *el, *en;
07687    struct ast_ignorepat *ipi;
07688    struct ast_context *tmp = con;
07689    
07690    for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
07691       struct ast_include *tmpil = tmpi;
07692       tmpi = tmpi->next;
07693       ast_free(tmpil);
07694    }
07695    for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
07696       struct ast_ignorepat *ipl = ipi;
07697       ipi = ipi->next;
07698       ast_free(ipl);
07699    }
07700    if (tmp->registrar)
07701       ast_free(tmp->registrar);
07702    
07703    /* destroy the hash tabs */
07704    if (tmp->root_table) {
07705       ast_hashtab_destroy(tmp->root_table, 0);
07706    }
07707    /* and destroy the pattern tree */
07708    if (tmp->pattern_tree)
07709       destroy_pattern_tree(tmp->pattern_tree);
07710    
07711    while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
07712       ast_free(sw);
07713    for (e = tmp->root; e;) {
07714       for (en = e->peer; en;) {
07715          el = en;
07716          en = en->peer;
07717          destroy_exten(el);
07718       }
07719       el = e;
07720       e = e->next;
07721       destroy_exten(el);
07722    }
07723    tmp->root = NULL;
07724    ast_rwlock_destroy(&tmp->lock);
07725    ast_free(tmp);
07726 }
07727 
07728 
07729 void __ast_context_destroy(struct ast_context *list, struct ast_hashtab *contexttab, struct ast_context *con, const char *registrar)
07730 {
07731    struct ast_context *tmp, *tmpl=NULL;
07732    struct ast_exten *exten_item, *prio_item;
07733 
07734    for (tmp = list; tmp; ) {
07735       struct ast_context *next = NULL; /* next starting point */
07736          /* The following code used to skip forward to the next
07737             context with matching registrar, but this didn't
07738             make sense; individual priorities registrar'd to 
07739             the matching registrar could occur in any context! */
07740       ast_debug(1, "Investigate ctx %s %s\n", tmp->name, tmp->registrar);
07741       if (con) {
07742          for (; tmp; tmpl = tmp, tmp = tmp->next) { /* skip to the matching context */
07743             ast_debug(1, "check ctx %s %s\n", tmp->name, tmp->registrar);
07744             if ( !strcasecmp(tmp->name, con->name) ) {
07745                break;   /* found it */
07746             }
07747          }
07748       }
07749       
07750       if (!tmp)   /* not found, we are done */
07751          break;
07752       ast_wrlock_context(tmp);
07753 
07754       if (registrar) {
07755          /* then search thru and remove any extens that match registrar. */
07756          struct ast_hashtab_iter *exten_iter;
07757          struct ast_hashtab_iter *prio_iter;
07758          struct ast_ignorepat *ip, *ipl = NULL, *ipn = NULL;
07759          struct ast_include *i, *pi = NULL, *ni = NULL;
07760          struct ast_sw *sw = NULL;
07761 
07762          /* remove any ignorepats whose registrar matches */
07763          for (ip = tmp->ignorepats; ip; ip = ipn) {
07764             ipn = ip->next;
07765             if (!strcmp(ip->registrar, registrar)) {
07766                if (ipl) {
07767                   ipl->next = ip->next;
07768                   ast_free(ip);
07769                   continue; /* don't change ipl */
07770                } else {
07771                   tmp->ignorepats = ip->next;
07772                   ast_free(ip);
07773                   continue; /* don't change ipl */
07774                }
07775             }
07776             ipl = ip;
07777          }
07778          /* remove any includes whose registrar matches */
07779          for (i = tmp->includes; i; i = ni) {
07780             ni = i->next;
07781             if (strcmp(i->registrar, registrar) == 0) {
07782                /* remove from list */
07783                if (pi) {
07784                   pi->next = i->next;
07785                   /* free include */
07786                   ast_free(i);
07787                   continue; /* don't change pi */
07788                } else {
07789                   tmp->includes = i->next;
07790                   /* free include */
07791                   ast_free(i);
07792                   continue; /* don't change pi */
07793                }
07794             }
07795             pi = i;
07796          }
07797          /* remove any switches whose registrar matches */
07798          AST_LIST_TRAVERSE_SAFE_BEGIN(&tmp->alts, sw, list) {
07799             if (strcmp(sw->registrar,registrar) == 0) {
07800                AST_LIST_REMOVE_CURRENT(list);
07801                ast_free(sw);
07802             }
07803          }
07804          AST_LIST_TRAVERSE_SAFE_END;
07805 
07806          if (tmp->root_table) { /* it is entirely possible that the context is EMPTY */
07807             exten_iter = ast_hashtab_start_traversal(tmp->root_table);
07808             while ((exten_item=ast_hashtab_next(exten_iter))) {
07809                prio_iter = ast_hashtab_start_traversal(exten_item->peer_table);
07810                while ((prio_item=ast_hashtab_next(prio_iter))) {
07811                   if (!prio_item->registrar || strcmp(prio_item->registrar, registrar) != 0) {
07812                      continue;
07813                   }
07814                   ast_verb(3, "Remove %s/%s/%d, registrar=%s; con=%s(%p); con->root=%p\n",
07815                          tmp->name, prio_item->exten, prio_item->priority, registrar, con? con->name : "<nil>", con, con? con->root_table: NULL);
07816                   /* set matchcid to 1 to insure we get a direct match, and NULL registrar to make sure no wildcarding is done */
07817                   ast_context_remove_extension_callerid2(tmp, prio_item->exten, prio_item->priority, prio_item->cidmatch, 1, NULL, 1);
07818                }
07819                ast_hashtab_end_traversal(prio_iter);
07820             }
07821             ast_hashtab_end_traversal(exten_iter);
07822          }
07823    
07824          /* delete the context if it's registrar matches, is empty, has refcount of 1, */
07825          /* it's not empty, if it has includes, ignorepats, or switches that are registered from
07826             another registrar. It's not empty if there are any extensions */
07827          if (strcmp(tmp->registrar, registrar) == 0 && tmp->refcount < 2 && !tmp->root && !tmp->ignorepats && !tmp->includes && AST_LIST_EMPTY(&tmp->alts)) {
07828             ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
07829             ast_hashtab_remove_this_object(contexttab, tmp);
07830             
07831             next = tmp->next;
07832             if (tmpl)
07833                tmpl->next = next;
07834             else
07835                contexts = next;
07836             /* Okay, now we're safe to let it go -- in a sense, we were
07837                ready to let it go as soon as we locked it. */
07838             ast_unlock_context(tmp);
07839             __ast_internal_context_destroy(tmp);
07840          } else {
07841             ast_debug(1,"Couldn't delete ctx %s/%s; refc=%d; tmp.root=%p\n", tmp->name, tmp->registrar,
07842                     tmp->refcount, tmp->root);
07843             ast_unlock_context(tmp);
07844             next = tmp->next;
07845             tmpl = tmp;
07846          }
07847       } else if (con) {
07848          ast_verb(3, "Deleting context %s registrar=%s\n", tmp->name, tmp->registrar);
07849          ast_debug(1, "delete ctx %s %s\n", tmp->name, tmp->registrar);
07850          ast_hashtab_remove_this_object(contexttab, tmp);
07851          
07852          next = tmp->next;
07853          if (tmpl)
07854             tmpl->next = next;
07855          else
07856             contexts = next;
07857          /* Okay, now we're safe to let it go -- in a sense, we were
07858             ready to let it go as soon as we locked it. */
07859          ast_unlock_context(tmp);
07860          __ast_internal_context_destroy(tmp);
07861       }
07862 
07863       /* if we have a specific match, we are done, otherwise continue */
07864       tmp = con ? NULL : next;
07865    }
07866 }
07867 
07868 void ast_context_destroy(struct ast_context *con, const char *registrar)
07869 {
07870    ast_wrlock_contexts();
07871    __ast_context_destroy(contexts, contexts_table, con,registrar);
07872    ast_unlock_contexts();
07873 }
07874 
07875 static void wait_for_hangup(struct ast_channel *chan, void *data)
07876 {
07877    int res;
07878    struct ast_frame *f;
07879    double waitsec;
07880    int waittime;
07881 
07882    if (ast_strlen_zero(data) || (sscanf(data, "%30lg", &waitsec) != 1) || (waitsec < 0))
07883       waitsec = -1;
07884    if (waitsec > -1) {
07885       waittime = waitsec * 1000.0;
07886       ast_safe_sleep(chan, waittime);
07887    } else do {
07888       res = ast_waitfor(chan, -1);
07889       if (res < 0)
07890          return;
07891       f = ast_read(chan);
07892       if (f)
07893          ast_frfree(f);
07894    } while(f);
07895 }
07896 
07897 /*!
07898  * \ingroup applications
07899  */
07900 static int pbx_builtin_proceeding(struct ast_channel *chan, void *data)
07901 {
07902    ast_indicate(chan, AST_CONTROL_PROCEEDING);
07903    return 0;
07904 }
07905 
07906 /*!
07907  * \ingroup applications
07908  */
07909 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
07910 {
07911    ast_indicate(chan, AST_CONTROL_PROGRESS);
07912    return 0;
07913 }
07914 
07915 /*!
07916  * \ingroup applications
07917  */
07918 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
07919 {
07920    ast_indicate(chan, AST_CONTROL_RINGING);
07921    return 0;
07922 }
07923 
07924 /*!
07925  * \ingroup applications
07926  */
07927 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
07928 {
07929    ast_indicate(chan, AST_CONTROL_BUSY);
07930    /* Don't change state of an UP channel, just indicate
07931       busy in audio */
07932    if (chan->_state != AST_STATE_UP) {
07933       ast_setstate(chan, AST_STATE_BUSY);
07934       ast_cdr_busy(chan->cdr);
07935    }
07936    wait_for_hangup(chan, data);
07937    return -1;
07938 }
07939 
07940 /*!
07941  * \ingroup applications
07942  */
07943 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
07944 {
07945    ast_indicate(chan, AST_CONTROL_CONGESTION);
07946    /* Don't change state of an UP channel, just indicate
07947       congestion in audio */
07948    if (chan->_state != AST_STATE_UP)
07949       ast_setstate(chan, AST_STATE_BUSY);
07950    wait_for_hangup(chan, data);
07951    return -1;
07952 }
07953 
07954 /*!
07955  * \ingroup applications
07956  */
07957 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
07958 {
07959    int delay = 0;
07960 
07961    if ((chan->_state != AST_STATE_UP) && !ast_strlen_zero(data))
07962       delay = atoi(data);
07963 
07964    if (delay < 0) {
07965       delay = 0;
07966    }
07967 
07968    return __ast_answer(chan, delay, 1);
07969 }
07970 
07971 static int pbx_builtin_incomplete(struct ast_channel *chan, void *data)
07972 {
07973    char *options = data;
07974    int answer = 1;
07975 
07976    /* Some channels can receive DTMF in unanswered state; some cannot */
07977    if (!ast_strlen_zero(options) && strchr(options, 'n')) {
07978       answer = 0;
07979    }
07980 
07981    /* If the channel is hungup, stop waiting */
07982    if (ast_check_hangup(chan)) {
07983       return -1;
07984    } else if (chan->_state != AST_STATE_UP && answer) {
07985       __ast_answer(chan, 0, 1);
07986    }
07987 
07988    return AST_PBX_INCOMPLETE;
07989 }
07990 
07991 AST_APP_OPTIONS(resetcdr_opts, {
07992    AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
07993    AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
07994    AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
07995    AST_APP_OPTION('e', AST_CDR_FLAG_POST_ENABLE),
07996 });
07997 
07998 /*!
07999  * \ingroup applications
08000  */
08001 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
08002 {
08003    char *args;
08004    struct ast_flags flags = { 0 };
08005 
08006    if (!ast_strlen_zero(data)) {
08007       args = ast_strdupa(data);
08008       ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
08009    }
08010 
08011    ast_cdr_reset(chan->cdr, &flags);
08012 
08013    return 0;
08014 }
08015 
08016 /*!
08017  * \ingroup applications
08018  */
08019 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
08020 {
08021    /* Copy the AMA Flags as specified */
08022    ast_cdr_setamaflags(chan, data ? data : "");
08023    return 0;
08024 }
08025 
08026 /*!
08027  * \ingroup applications
08028  */
08029 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
08030 {
08031    if (!ast_strlen_zero(data)) {
08032       int cause;
08033       char *endptr;
08034 
08035       if ((cause = ast_str2cause(data)) > -1) {
08036          chan->hangupcause = cause;
08037          return -1;
08038       }
08039       
08040       cause = strtol((const char *) data, &endptr, 10);
08041       if (cause != 0 || (data != endptr)) {
08042          chan->hangupcause = cause;
08043          return -1;
08044       }
08045          
08046       ast_log(LOG_WARNING, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
08047    }
08048 
08049    if (!chan->hangupcause) {
08050       chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
08051    }
08052 
08053    return -1;
08054 }
08055 
08056 /*!
08057  * \ingroup applications
08058  */
08059 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
08060 {
08061    char *s, *ts, *branch1, *branch2, *branch;
08062    struct ast_timing timing;
08063 
08064    if (ast_strlen_zero(data)) {
08065       ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>,<days of week>,<days of month>,<months>?'labeliftrue':'labeliffalse'\n");
08066       return -1;
08067    }
08068 
08069    ts = s = ast_strdupa(data);
08070 
08071    /* Separate the Goto path */
08072    strsep(&ts, "?");
08073    branch1 = strsep(&ts,":");
08074    branch2 = strsep(&ts,"");
08075 
08076    /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
08077    if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
08078       branch = branch1;
08079    else
08080       branch = branch2;
08081 
08082    if (ast_strlen_zero(branch)) {
08083       ast_debug(1, "Not taking any branch\n");
08084       return 0;
08085    }
08086 
08087    return pbx_builtin_goto(chan, branch);
08088 }
08089 
08090 /*!
08091  * \ingroup applications
08092  */
08093 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
08094 {
08095    char *s, *appname;
08096    struct ast_timing timing;
08097    struct ast_app *app;
08098    static const char *usage = "ExecIfTime requires an argument:\n  <time range>,<days of week>,<days of month>,<months>?<appname>[(<appargs>)]";
08099 
08100    if (ast_strlen_zero(data)) {
08101       ast_log(LOG_WARNING, "%s\n", usage);
08102       return -1;
08103    }
08104 
08105    appname = ast_strdupa(data);
08106 
08107    s = strsep(&appname, "?"); /* Separate the timerange and application name/data */
08108    if (!appname) {   /* missing application */
08109       ast_log(LOG_WARNING, "%s\n", usage);
08110       return -1;
08111    }
08112 
08113    if (!ast_build_timing(&timing, s)) {
08114       ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
08115       return -1;
08116    }
08117 
08118    if (!ast_check_timing(&timing))  /* outside the valid time window, just return */
08119       return 0;
08120 
08121    /* now split appname(appargs) */
08122    if ((s = strchr(appname, '('))) {
08123       char *e;
08124       *s++ = '\0';
08125       if ((e = strrchr(s, ')')))
08126          *e = '\0';
08127       else
08128          ast_log(LOG_WARNING, "Failed to find closing parenthesis\n");
08129    }
08130       
08131 
08132    if ((app = pbx_findapp(appname))) {
08133       return pbx_exec(chan, app, S_OR(s, ""));
08134    } else {
08135       ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
08136       return -1;
08137    }
08138 }
08139 
08140 /*!
08141  * \ingroup applications
08142  */
08143 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
08144 {
08145    double s;
08146    int ms;
08147 
08148    /* Wait for "n" seconds */
08149    if (data && (s = atof(data)) > 0.0) {
08150       ms = s * 1000.0;
08151       return ast_safe_sleep(chan, ms);
08152    }
08153    return 0;
08154 }
08155 
08156 /*!
08157  * \ingroup applications
08158  */
08159 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
08160 {
08161    int ms, res;
08162    double s;
08163    struct ast_flags flags = {0};
08164    char *opts[1] = { NULL };
08165    char *parse;
08166    AST_DECLARE_APP_ARGS(args,
08167       AST_APP_ARG(timeout);
08168       AST_APP_ARG(options);
08169    );
08170 
08171    if (!ast_strlen_zero(data)) {
08172       parse = ast_strdupa(data);
08173       AST_STANDARD_APP_ARGS(args, parse);
08174    } else
08175       memset(&args, 0, sizeof(args));
08176 
08177    if (args.options)
08178       ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
08179    
08180    if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
08181       ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n"); 
08182    } else if (ast_test_flag(&flags, WAITEXTEN_MOH)) {
08183       ast_indicate_data(chan, AST_CONTROL_HOLD, S_OR(opts[0], NULL), strlen(opts[0]));
08184    } else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE)) {
08185       const struct tone_zone_sound *ts = ast_get_indication_tone(chan->zone, "dial");
08186       if (ts)
08187          ast_playtones_start(chan, 0, ts->data, 0);
08188       else
08189          ast_tonepair_start(chan, 350, 440, 0, 0);
08190    }
08191    /* Wait for "n" seconds */
08192    if (args.timeout && (s = atof(args.timeout)) > 0)
08193        ms = s * 1000.0;
08194    else if (chan->pbx)
08195       ms = chan->pbx->rtimeoutms;
08196    else
08197       ms = 10000;
08198 
08199    res = ast_waitfordigit(chan, ms);
08200    if (!res) {
08201       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
08202          ast_verb(3, "Timeout on %s, continuing...\n", chan->name);
08203       } else if (chan->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
08204          ast_verb(3, "Call timeout on %s, checking for 'T'\n", chan->name);
08205          res = -1;
08206       } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
08207          ast_verb(3, "Timeout on %s, going to 't'\n", chan->name);
08208          set_ext_pri(chan, "t", 0); /* 0 will become 1, next time through the loop */
08209       } else {
08210          ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
08211          res = -1;
08212       }
08213    }
08214 
08215    if (ast_test_flag(&flags, WAITEXTEN_MOH))
08216       ast_indicate(chan, AST_CONTROL_UNHOLD);
08217    else if (ast_test_flag(&flags, WAITEXTEN_DIALTONE))
08218       ast_playtones_stop(chan);
08219 
08220    return res;
08221 }
08222 
08223 /*!
08224  * \ingroup applications
08225  */
08226 static int pbx_builtin_background(struct ast_channel *chan, void *data)
08227 {
08228    int res = 0;
08229    int mres = 0;
08230    struct ast_flags flags = {0};
08231    char *parse, exten[2] = "";
08232    AST_DECLARE_APP_ARGS(args,
08233       AST_APP_ARG(filename);
08234       AST_APP_ARG(options);
08235       AST_APP_ARG(lang);
08236       AST_APP_ARG(context);
08237    );
08238 
08239    if (ast_strlen_zero(data)) {
08240       ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
08241       return -1;
08242    }
08243 
08244    parse = ast_strdupa(data);
08245 
08246    AST_STANDARD_APP_ARGS(args, parse);
08247 
08248    if (ast_strlen_zero(args.lang))
08249       args.lang = (char *)chan->language; /* XXX this is const */
08250 
08251    if (ast_strlen_zero(args.context)) {
08252       const char *context;
08253       ast_channel_lock(chan);
08254       if ((context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"))) {
08255          args.context = ast_strdupa(context);
08256       } else {
08257          args.context = chan->context;
08258       }
08259       ast_channel_unlock(chan);
08260    }
08261 
08262    if (args.options) {
08263       if (!strcasecmp(args.options, "skip"))
08264          flags.flags = BACKGROUND_SKIP;
08265       else if (!strcasecmp(args.options, "noanswer"))
08266          flags.flags = BACKGROUND_NOANSWER;
08267       else
08268          ast_app_parse_options(background_opts, &flags, NULL, args.options);
08269    }
08270 
08271    /* Answer if need be */
08272    if (chan->_state != AST_STATE_UP) {
08273       if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
08274          goto done;
08275       } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
08276          res = ast_answer(chan);
08277       }
08278    }
08279 
08280    if (!res) {
08281       char *back = args.filename;
08282       char *front;
08283 
08284       ast_stopstream(chan);      /* Stop anything playing */
08285       /* Stream the list of files */
08286       while (!res && (front = strsep(&back, "&")) ) {
08287          if ( (res = ast_streamfile(chan, front, args.lang)) ) {
08288             ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
08289             res = 0;
08290             mres = 1;
08291             break;
08292          }
08293          if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
08294             res = ast_waitstream(chan, "");
08295          } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
08296             res = ast_waitstream_exten(chan, args.context);
08297          } else {
08298             res = ast_waitstream(chan, AST_DIGIT_ANY);
08299          }
08300          ast_stopstream(chan);
08301       }
08302    }
08303 
08304    /*
08305     * If the single digit DTMF is an extension in the specified context, then
08306     * go there and signal no DTMF.  Otherwise, we should exit with that DTMF.
08307     * If we're in Macro, we'll exit and seek that DTMF as the beginning of an
08308     * extension in the Macro's calling context.  If we're not in Macro, then
08309     * we'll simply seek that extension in the calling context.  Previously,
08310     * someone complained about the behavior as it related to the interior of a
08311     * Gosub routine, and the fix (#14011) inadvertently broke FreePBX
08312     * (#14940).  This change should fix both of these situations, but with the
08313     * possible incompatibility that if a single digit extension does not exist
08314     * (but a longer extension COULD have matched), it would have previously
08315     * gone immediately to the "i" extension, but will now need to wait for a
08316     * timeout.
08317     *
08318     * Later, we had to add a flag to disable this workaround, because AGI
08319     * users can EXEC Background and reasonably expect that the DTMF code will
08320     * be returned (see #16434).
08321     */
08322    if (!ast_test_flag(chan, AST_FLAG_DISABLE_WORKAROUNDS) &&
08323          (exten[0] = res) &&
08324          ast_canmatch_extension(chan, args.context, exten, 1, chan->cid.cid_num) &&
08325          !ast_matchmore_extension(chan, args.context, exten, 1, chan->cid.cid_num)) {
08326       snprintf(chan->exten, sizeof(chan->exten), "%c", res);
08327       ast_copy_string(chan->context, args.context, sizeof(chan->context));
08328       chan->priority = 0;
08329       res = 0;
08330    }
08331 done:
08332    pbx_builtin_setvar_helper(chan, "BACKGROUNDSTATUS", mres ? "FAILED" : "SUCCESS");
08333    return res;
08334 }
08335 
08336 /*! Goto
08337  * \ingroup applications
08338  */
08339 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
08340 {
08341    int res = ast_parseable_goto(chan, data);
08342    if (!res)
08343       ast_verb(3, "Goto (%s,%s,%d)\n", chan->context, chan->exten, chan->priority + 1);
08344    return res;
08345 }
08346 
08347 
08348 int pbx_builtin_serialize_variables(struct ast_channel *chan, struct ast_str **buf)
08349 {
08350    struct ast_var_t *variables;
08351    const char *var, *val;
08352    int total = 0;
08353 
08354    if (!chan)
08355       return 0;
08356 
08357    (*buf)->used = 0;
08358    (*buf)->str[0] = '\0';
08359 
08360    ast_channel_lock(chan);
08361 
08362    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
08363       if ((var = ast_var_name(variables)) && (val = ast_var_value(variables))
08364          /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
08365          ) {
08366          if (ast_str_append(buf, 0, "%s=%s\n", var, val) < 0) {
08367             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
08368             break;
08369          } else
08370             total++;
08371       } else
08372          break;
08373    }
08374 
08375    ast_channel_unlock(chan);
08376 
08377    return total;
08378 }
08379 
08380 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
08381 {
08382    struct ast_var_t *variables;
08383    const char *ret = NULL;
08384    int i;
08385    struct varshead *places[2] = { NULL, &globals };
08386 
08387    if (!name)
08388       return NULL;
08389 
08390    if (chan) {
08391       ast_channel_lock(chan);
08392       places[0] = &chan->varshead;
08393    }
08394 
08395    for (i = 0; i < 2; i++) {
08396       if (!places[i])
08397          continue;
08398       if (places[i] == &globals)
08399          ast_rwlock_rdlock(&globalslock);
08400       AST_LIST_TRAVERSE(places[i], variables, entries) {
08401          if (!strcmp(name, ast_var_name(variables))) {
08402             ret = ast_var_value(variables);
08403             break;
08404          }
08405       }
08406       if (places[i] == &globals)
08407          ast_rwlock_unlock(&globalslock);
08408       if (ret)
08409          break;
08410    }
08411 
08412    if (chan)
08413       ast_channel_unlock(chan);
08414 
08415    return ret;
08416 }
08417 
08418 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
08419 {
08420    struct ast_var_t *newvariable;
08421    struct varshead *headp;
08422 
08423    if (name[strlen(name)-1] == ')') {
08424       char *function = ast_strdupa(name);
08425 
08426       ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
08427       ast_func_write(chan, function, value);
08428       return;
08429    }
08430 
08431    if (chan) {
08432       ast_channel_lock(chan);
08433       headp = &chan->varshead;
08434    } else {
08435       ast_rwlock_wrlock(&globalslock);
08436       headp = &globals;
08437    }
08438 
08439    if (value) {
08440       if (headp == &globals)
08441          ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
08442       newvariable = ast_var_assign(name, value);
08443       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
08444    }
08445 
08446    if (chan)
08447       ast_channel_unlock(chan);
08448    else
08449       ast_rwlock_unlock(&globalslock);
08450 }
08451 
08452 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
08453 {
08454    struct ast_var_t *newvariable;
08455    struct varshead *headp;
08456    const char *nametail = name;
08457 
08458    if (name[strlen(name) - 1] == ')') {
08459       char *function = ast_strdupa(name);
08460 
08461       ast_func_write(chan, function, value);
08462       return;
08463    }
08464 
08465    if (chan) {
08466       ast_channel_lock(chan);
08467       headp = &chan->varshead;
08468    } else {
08469       ast_rwlock_wrlock(&globalslock);
08470       headp = &globals;
08471    }
08472 
08473    /* For comparison purposes, we have to strip leading underscores */
08474    if (*nametail == '_') {
08475       nametail++;
08476       if (*nametail == '_')
08477          nametail++;
08478    }
08479 
08480    AST_LIST_TRAVERSE_SAFE_BEGIN(headp, newvariable, entries) {
08481       if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
08482          /* there is already such a variable, delete it */
08483          AST_LIST_REMOVE_CURRENT(entries);
08484          ast_var_delete(newvariable);
08485          break;
08486       }
08487    }
08488    AST_LIST_TRAVERSE_SAFE_END;
08489 
08490    if (value) {
08491       if (headp == &globals)
08492          ast_verb(2, "Setting global variable '%s' to '%s'\n", name, value);
08493       newvariable = ast_var_assign(name, value);
08494       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
08495       manager_event(EVENT_FLAG_DIALPLAN, "VarSet", 
08496          "Channel: %s\r\n"
08497          "Variable: %s\r\n"
08498          "Value: %s\r\n"
08499          "Uniqueid: %s\r\n", 
08500          chan ? chan->name : "none", name, value, 
08501          chan ? chan->uniqueid : "none");
08502    }
08503 
08504    if (chan)
08505       ast_channel_unlock(chan);
08506    else
08507       ast_rwlock_unlock(&globalslock);
08508 }
08509 
08510 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
08511 {
08512    char *name, *value, *mydata;
08513 
08514    if (ast_compat_app_set) {
08515       return pbx_builtin_setvar_multiple(chan, data);
08516    }
08517 
08518    if (ast_strlen_zero(data)) {
08519       ast_log(LOG_WARNING, "Set requires one variable name/value pair.\n");
08520       return 0;
08521    }
08522 
08523    mydata = ast_strdupa(data);
08524    name = strsep(&mydata, "=");
08525    value = mydata;
08526    if (strchr(name, ' '))
08527       ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", name, mydata);
08528 
08529    pbx_builtin_setvar_helper(chan, name, value);
08530    return(0);
08531 }
08532 
08533 int pbx_builtin_setvar_multiple(struct ast_channel *chan, void *vdata)
08534 {
08535    char *data;
08536    int x;
08537    AST_DECLARE_APP_ARGS(args,
08538       AST_APP_ARG(pair)[24];
08539    );
08540    AST_DECLARE_APP_ARGS(pair,
08541       AST_APP_ARG(name);
08542       AST_APP_ARG(value);
08543    );
08544 
08545    if (ast_strlen_zero(vdata)) {
08546       ast_log(LOG_WARNING, "MSet requires at least one variable name/value pair.\n");
08547       return 0;
08548    }
08549 
08550    data = ast_strdupa(vdata);
08551    AST_STANDARD_APP_ARGS(args, data);
08552 
08553    for (x = 0; x < args.argc; x++) {
08554       AST_NONSTANDARD_APP_ARGS(pair, args.pair[x], '=');
08555       if (pair.argc == 2) {
08556          pbx_builtin_setvar_helper(chan, pair.name, pair.value);
08557          if (strchr(pair.name, ' '))
08558             ast_log(LOG_WARNING, "Please avoid unnecessary spaces on variables as it may lead to unexpected results ('%s' set to '%s').\n", pair.name, pair.value);
08559       } else if (!chan) {
08560          ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '='\n", pair.name);
08561       } else {
08562          ast_log(LOG_WARNING, "MSet: ignoring entry '%s' with no '=' (in %s@%s:%d\n", pair.name, chan->exten, chan->context, chan->priority);
08563       }
08564    }
08565 
08566    return 0;
08567 }
08568 
08569 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
08570 {
08571    char *name;
08572    char *value;
08573    char *channel;
08574    char tmp[VAR_BUF_SIZE];
08575    static int deprecation_warning = 0;
08576 
08577    if (ast_strlen_zero(data)) {
08578       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
08579       return 0;
08580    }
08581    tmp[0] = 0;
08582    if (!deprecation_warning) {
08583       ast_log(LOG_WARNING, "ImportVar is deprecated.  Please use Set(varname=${IMPORT(channel,variable)}) instead.\n");
08584       deprecation_warning = 1;
08585    }
08586 
08587    value = ast_strdupa(data);
08588    name = strsep(&value,"=");
08589    channel = strsep(&value,",");
08590    if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
08591       struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
08592       if (chan2) {
08593          char *s = alloca(strlen(value) + 4);
08594          if (s) {
08595             sprintf(s, "${%s}", value);
08596             pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
08597          }
08598          ast_channel_unlock(chan2);
08599       }
08600       pbx_builtin_setvar_helper(chan, name, tmp);
08601    }
08602 
08603    return(0);
08604 }
08605 
08606 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
08607 {
08608    return 0;
08609 }
08610 
08611 void pbx_builtin_clear_globals(void)
08612 {
08613    struct ast_var_t *vardata;
08614 
08615    ast_rwlock_wrlock(&globalslock);
08616    while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
08617       ast_var_delete(vardata);
08618    ast_rwlock_unlock(&globalslock);
08619 }
08620 
08621 int pbx_checkcondition(const char *condition)
08622 {
08623    int res;
08624    if (ast_strlen_zero(condition)) {                /* NULL or empty strings are false */
08625       return 0;
08626    } else if (sscanf(condition, "%30d", &res) == 1) { /* Numbers are evaluated for truth */
08627       return res;
08628    } else {                                         /* Strings are true */
08629       return 1;
08630    }
08631 }
08632 
08633 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
08634 {
08635    char *condition, *branch1, *branch2, *branch;
08636    char *stringp;
08637 
08638    if (ast_strlen_zero(data)) {
08639       ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
08640       return 0;
08641    }
08642 
08643    stringp = ast_strdupa(data);
08644    condition = strsep(&stringp,"?");
08645    branch1 = strsep(&stringp,":");
08646    branch2 = strsep(&stringp,"");
08647    branch = pbx_checkcondition(condition) ? branch1 : branch2;
08648 
08649    if (ast_strlen_zero(branch)) {
08650       ast_debug(1, "Not taking any branch\n");
08651       return 0;
08652    }
08653 
08654    return pbx_builtin_goto(chan, branch);
08655 }
08656 
08657 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
08658 {
08659    char tmp[256];
08660    char *number = tmp;
08661    char *options;
08662 
08663    if (ast_strlen_zero(data)) {
08664       ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
08665       return -1;
08666    }
08667    ast_copy_string(tmp, data, sizeof(tmp));
08668    strsep(&number, ",");
08669    options = strsep(&number, ",");
08670    if (options) {
08671       if ( strcasecmp(options, "f") && strcasecmp(options, "m") &&
08672          strcasecmp(options, "c") && strcasecmp(options, "n") ) {
08673          ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
08674          return -1;
08675       }
08676    }
08677 
08678    if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
08679       ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
08680    }
08681 
08682    return 0;
08683 }
08684 
08685 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
08686 {
08687    int res = 0;
08688 
08689    if (data)
08690       res = ast_say_digit_str(chan, data, "", chan->language);
08691    return res;
08692 }
08693 
08694 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
08695 {
08696    int res = 0;
08697 
08698    if (data)
08699       res = ast_say_character_str(chan, data, "", chan->language);
08700    return res;
08701 }
08702 
08703 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
08704 {
08705    int res = 0;
08706 
08707    if (data)
08708       res = ast_say_phonetic_str(chan, data, "", chan->language);
08709    return res;
08710 }
08711 
08712 static void device_state_cb(const struct ast_event *event, void *unused)
08713 {
08714    const char *device;
08715    struct statechange *sc;
08716 
08717    device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
08718    if (ast_strlen_zero(device)) {
08719       ast_log(LOG_ERROR, "Received invalid event that had no device IE\n");
08720       return;
08721    }
08722 
08723    if (!(sc = ast_calloc(1, sizeof(*sc) + strlen(device) + 1)))
08724       return;
08725    strcpy(sc->dev, device);
08726    if (ast_taskprocessor_push(device_state_tps, handle_statechange, sc) < 0) {
08727       ast_free(sc);
08728    }
08729 }
08730 
08731 int load_pbx(void)
08732 {
08733    int x;
08734 
08735    /* Initialize the PBX */
08736    ast_verb(1, "Asterisk PBX Core Initializing\n");
08737    if (!(device_state_tps = ast_taskprocessor_get("pbx-core", 0))) {
08738       ast_log(LOG_WARNING, "failed to create pbx-core taskprocessor\n");
08739    }
08740 
08741    ast_verb(1, "Registering builtin applications:\n");
08742    ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
08743    __ast_custom_function_register(&exception_function, NULL);
08744 
08745    /* Register builtin applications */
08746    for (x = 0; x < sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
08747       ast_verb(1, "[%s]\n", builtins[x].name);
08748       if (ast_register_application2(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description, NULL)) {
08749          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
08750          return -1;
08751       }
08752    }
08753    
08754    /* Register manager application */
08755    ast_manager_register2("ShowDialPlan", EVENT_FLAG_CONFIG | EVENT_FLAG_REPORTING, manager_show_dialplan, "List dialplan", mandescr_show_dialplan);
08756 
08757    if (!(device_state_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE, device_state_cb, NULL,
08758          AST_EVENT_IE_END))) {
08759       return -1;
08760    }
08761 
08762    return 0;
08763 }
08764 static int conlock_wrlock_version = 0;
08765 
08766 int ast_wrlock_contexts_version(void)
08767 {
08768    return conlock_wrlock_version;
08769 }
08770 
08771 /*
08772  * Lock context list functions ...
08773  */
08774 int ast_wrlock_contexts()
08775 {
08776    int res = ast_rwlock_wrlock(&conlock);
08777    if (!res)
08778       ast_atomic_fetchadd_int(&conlock_wrlock_version, 1);
08779    return res;
08780 }
08781 
08782 int ast_rdlock_contexts()
08783 {
08784    return ast_rwlock_rdlock(&conlock);
08785 }
08786 
08787 int ast_unlock_contexts()
08788 {
08789    return ast_rwlock_unlock(&conlock);
08790 }
08791 
08792 /*
08793  * Lock context ...
08794  */
08795 int ast_wrlock_context(struct ast_context *con)
08796 {
08797    return ast_rwlock_wrlock(&con->lock);
08798 }
08799 
08800 int ast_rdlock_context(struct ast_context *con)
08801 {
08802    return ast_rwlock_rdlock(&con->lock);
08803 }
08804 
08805 int ast_unlock_context(struct ast_context *con)
08806 {
08807    return ast_rwlock_unlock(&con->lock);
08808 }
08809 
08810 /*
08811  * Name functions ...
08812  */
08813 const char *ast_get_context_name(struct ast_context *con)
08814 {
08815    return con ? con->name : NULL;
08816 }
08817 
08818 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
08819 {
08820    return exten ? exten->parent : NULL;
08821 }
08822 
08823 const char *ast_get_extension_name(struct ast_exten *exten)
08824 {
08825    return exten ? exten->exten : NULL;
08826 }
08827 
08828 const char *ast_get_extension_label(struct ast_exten *exten)
08829 {
08830    return exten ? exten->label : NULL;
08831 }
08832 
08833 const char *ast_get_include_name(struct ast_include *inc)
08834 {
08835    return inc ? inc->name : NULL;
08836 }
08837 
08838 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
08839 {
08840    return ip ? ip->pattern : NULL;
08841 }
08842 
08843 int ast_get_extension_priority(struct ast_exten *exten)
08844 {
08845    return exten ? exten->priority : -1;
08846 }
08847 
08848 /*
08849  * Registrar info functions ...
08850  */
08851 const char *ast_get_context_registrar(struct ast_context *c)
08852 {
08853    return c ? c->registrar : NULL;
08854 }
08855 
08856 const char *ast_get_extension_registrar(struct ast_exten *e)
08857 {
08858    return e ? e->registrar : NULL;
08859 }
08860 
08861 const char *ast_get_include_registrar(struct ast_include *i)
08862 {
08863    return i ? i->registrar : NULL;
08864 }
08865 
08866 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
08867 {
08868    return ip ? ip->registrar : NULL;
08869 }
08870 
08871 int ast_get_extension_matchcid(struct ast_exten *e)
08872 {
08873    return e ? e->matchcid : 0;
08874 }
08875 
08876 const char *ast_get_extension_cidmatch(struct ast_exten *e)
08877 {
08878    return e ? e->cidmatch : NULL;
08879 }
08880 
08881 const char *ast_get_extension_app(struct ast_exten *e)
08882 {
08883    return e ? e->app : NULL;
08884 }
08885 
08886 void *ast_get_extension_app_data(struct ast_exten *e)
08887 {
08888    return e ? e->data : NULL;
08889 }
08890 
08891 const char *ast_get_switch_name(struct ast_sw *sw)
08892 {
08893    return sw ? sw->name : NULL;
08894 }
08895 
08896 const char *ast_get_switch_data(struct ast_sw *sw)
08897 {
08898    return sw ? sw->data : NULL;
08899 }
08900 
08901 int ast_get_switch_eval(struct ast_sw *sw)
08902 {
08903    return sw->eval;
08904 }
08905 
08906 const char *ast_get_switch_registrar(struct ast_sw *sw)
08907 {
08908    return sw ? sw->registrar : NULL;
08909 }
08910 
08911 /*
08912  * Walking functions ...
08913  */
08914 struct ast_context *ast_walk_contexts(struct ast_context *con)
08915 {
08916    return con ? con->next : contexts;
08917 }
08918 
08919 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
08920    struct ast_exten *exten)
08921 {
08922    if (!exten)
08923       return con ? con->root : NULL;
08924    else
08925       return exten->next;
08926 }
08927 
08928 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
08929    struct ast_sw *sw)
08930 {
08931    if (!sw)
08932       return con ? AST_LIST_FIRST(&con->alts) : NULL;
08933    else
08934       return AST_LIST_NEXT(sw, list);
08935 }
08936 
08937 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
08938    struct ast_exten *priority)
08939 {
08940    return priority ? priority->peer : exten;
08941 }
08942 
08943 struct ast_include *ast_walk_context_includes(struct ast_context *con,
08944    struct ast_include *inc)
08945 {
08946    if (!inc)
08947       return con ? con->includes : NULL;
08948    else
08949       return inc->next;
08950 }
08951 
08952 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
08953    struct ast_ignorepat *ip)
08954 {
08955    if (!ip)
08956       return con ? con->ignorepats : NULL;
08957    else
08958       return ip->next;
08959 }
08960 
08961 int ast_context_verify_includes(struct ast_context *con)
08962 {
08963    struct ast_include *inc = NULL;
08964    int res = 0;
08965 
08966    while ( (inc = ast_walk_context_includes(con, inc)) ) {
08967       if (ast_context_find(inc->rname))
08968          continue;
08969 
08970       res = -1;
08971       ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
08972          ast_get_context_name(con), inc->rname);
08973       break;
08974    }
08975 
08976    return res;
08977 }
08978 
08979 
08980 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
08981 {
08982    int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
08983 
08984    if (!chan)
08985       return -2;
08986 
08987    if (context == NULL)
08988       context = chan->context;
08989    if (exten == NULL)
08990       exten = chan->exten;
08991 
08992    goto_func = (async) ? ast_async_goto : ast_explicit_goto;
08993    if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
08994       return goto_func(chan, context, exten, priority);
08995    else
08996       return -3;
08997 }
08998 
08999 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
09000 {
09001    return __ast_goto_if_exists(chan, context, exten, priority, 0);
09002 }
09003 
09004 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
09005 {
09006    return __ast_goto_if_exists(chan, context, exten, priority, 1);
09007 }
09008 
09009 static int pbx_parseable_goto(struct ast_channel *chan, const char *goto_string, int async)
09010 {
09011    char *exten, *pri, *context;
09012    char *stringp;
09013    int ipri;
09014    int mode = 0;
09015 
09016    if (ast_strlen_zero(goto_string)) {
09017       ast_log(LOG_WARNING, "Goto requires an argument ([[context,]extension,]priority)\n");
09018       return -1;
09019    }
09020    stringp = ast_strdupa(goto_string);
09021    context = strsep(&stringp, ","); /* guaranteed non-null */
09022    exten = strsep(&stringp, ",");
09023    pri = strsep(&stringp, ",");
09024    if (!exten) {  /* Only a priority in this one */
09025       pri = context;
09026       exten = NULL;
09027       context = NULL;
09028    } else if (!pri) {   /* Only an extension and priority in this one */
09029       pri = exten;
09030       exten = context;
09031       context = NULL;
09032    }
09033    if (*pri == '+') {
09034       mode = 1;
09035       pri++;
09036    } else if (*pri == '-') {
09037       mode = -1;
09038       pri++;
09039    }
09040    if (sscanf(pri, "%30d", &ipri) != 1) {
09041       if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
09042          pri, chan->cid.cid_num)) < 1) {
09043          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
09044          return -1;
09045       } else
09046          mode = 0;
09047    }
09048    /* At this point we have a priority and maybe an extension and a context */
09049 
09050    if (mode)
09051       ipri = chan->priority + (ipri * mode);
09052 
09053    if (async)
09054       ast_async_goto(chan, context, exten, ipri);
09055    else
09056       ast_explicit_goto(chan, context, exten, ipri);
09057    
09058    return 0;
09059 
09060 }
09061 
09062 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
09063 {
09064    return pbx_parseable_goto(chan, goto_string, 0);
09065 }
09066 
09067 int ast_async_parseable_goto(struct ast_channel *chan, const char *goto_string)
09068 {
09069    return pbx_parseable_goto(chan, goto_string, 1);
09070 }

Generated on Wed Aug 18 22:33:54 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7