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

Generated on Fri Jul 24 00:41:00 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7