Tue Mar 2 17:31:51 2010

Asterisk developer's documentation


pbx.c

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

Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1