Thu Jul 9 13:40:37 2009

Asterisk developer's documentation


pbx.c

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

Generated on Thu Jul 9 13:40:38 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7