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

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