Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:50 2007

Asterisk developer's documentation :: Codename Pineapple


pbx.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Core PBX routines.
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  */
00025 
00026 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 53128 $")
00029 
00030 #include <sys/types.h>
00031 #include <string.h>
00032 #include <unistd.h>
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 #include <ctype.h>
00036 #include <errno.h>
00037 #include <time.h>
00038 #include <sys/time.h>
00039 #include <limits.h>
00040 
00041 #include "asterisk/lock.h"
00042 #include "asterisk/cli.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/channel.h"
00045 #include "asterisk/options.h"
00046 #include "asterisk/logger.h"
00047 #include "asterisk/file.h"
00048 #include "asterisk/callerid.h"
00049 #include "asterisk/cdr.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/term.h"
00052 #include "asterisk/manager.h"
00053 #include "asterisk/ast_expr.h"
00054 #include "asterisk/linkedlists.h"
00055 #define  SAY_STUBS   /* generate declarations and stubs for say methods */
00056 #include "asterisk/say.h"
00057 #include "asterisk/utils.h"
00058 #include "asterisk/causes.h"
00059 #include "asterisk/musiconhold.h"
00060 #include "asterisk/app.h"
00061 #include "asterisk/devicestate.h"
00062 #include "asterisk/stringfields.h"
00063 
00064 /*!
00065  * \note I M P O R T A N T :
00066  *
00067  *    The speed of extension handling will likely be among the most important
00068  * aspects of this PBX.  The switching scheme as it exists right now isn't
00069  * terribly bad (it's O(N+M), where N is the # of extensions and M is the avg #
00070  * of priorities, but a constant search time here would be great ;-)
00071  *
00072  */
00073 
00074 #ifdef LOW_MEMORY
00075 #define EXT_DATA_SIZE 256
00076 #else
00077 #define EXT_DATA_SIZE 8192
00078 #endif
00079 
00080 #define SWITCH_DATA_LENGTH 256
00081 
00082 #define VAR_BUF_SIZE 4096
00083 
00084 #define  VAR_NORMAL     1
00085 #define  VAR_SOFTTRAN   2
00086 #define  VAR_HARDTRAN   3
00087 
00088 #define BACKGROUND_SKIP    (1 << 0)
00089 #define BACKGROUND_NOANSWER   (1 << 1)
00090 #define BACKGROUND_MATCHEXTEN (1 << 2)
00091 #define BACKGROUND_PLAYBACK   (1 << 3)
00092 
00093 AST_APP_OPTIONS(background_opts, {
00094    AST_APP_OPTION('s', BACKGROUND_SKIP),
00095    AST_APP_OPTION('n', BACKGROUND_NOANSWER),
00096    AST_APP_OPTION('m', BACKGROUND_MATCHEXTEN),
00097    AST_APP_OPTION('p', BACKGROUND_PLAYBACK),
00098 });
00099 
00100 #define WAITEXTEN_MOH      (1 << 0)
00101 
00102 AST_APP_OPTIONS(waitexten_opts, {
00103    AST_APP_OPTION_ARG('m', WAITEXTEN_MOH, 0),
00104 });
00105 
00106 struct ast_context;
00107 struct ast_app;
00108 
00109 /*!
00110    \brief ast_exten: An extension
00111    The dialplan is saved as a linked list with each context
00112    having it's own linked list of extensions - one item per
00113    priority.
00114 */
00115 struct ast_exten {
00116    char *exten;         /*!< Extension name */
00117    int matchcid;        /*!< Match caller id ? */
00118    const char *cidmatch;      /*!< Caller id to match for this extension */
00119    int priority;        /*!< Priority */
00120    const char *label;      /*!< Label */
00121    struct ast_context *parent;   /*!< The context this extension belongs to  */
00122    const char *app;     /*!< Application to execute */
00123    struct ast_app *cached_app;     /*!< Cached location of application */
00124    void *data;       /*!< Data to use (arguments) */
00125    void (*datad)(void *);     /*!< Data destructor */
00126    struct ast_exten *peer;    /*!< Next higher priority with our extension */
00127    const char *registrar;     /*!< Registrar */
00128    struct ast_exten *next;    /*!< Extension with a greater ID */
00129    char stuff[0];
00130 };
00131 
00132 /*! \brief ast_include: include= support in extensions.conf */
00133 struct ast_include {
00134    const char *name;
00135    const char *rname;         /*!< Context to include */
00136    const char *registrar;        /*!< Registrar */
00137    int hastime;            /*!< If time construct exists */
00138    struct ast_timing timing;               /*!< time construct */
00139    struct ast_include *next;     /*!< Link them together */
00140    char stuff[0];
00141 };
00142 
00143 /*! \brief ast_sw: Switch statement in extensions.conf */
00144 struct ast_sw {
00145    char *name;
00146    const char *registrar;        /*!< Registrar */
00147    char *data;          /*!< Data load */
00148    int eval;
00149    AST_LIST_ENTRY(ast_sw) list;
00150    char *tmpdata;
00151    char stuff[0];
00152 };
00153 
00154 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
00155 struct ast_ignorepat {
00156    const char *registrar;
00157    struct ast_ignorepat *next;
00158    const char pattern[0];
00159 };
00160 
00161 /*! \brief ast_context: An extension context */
00162 struct ast_context {
00163    ast_mutex_t lock;          /*!< A lock to prevent multiple threads from clobbering the context */
00164    struct ast_exten *root;       /*!< The root of the list of extensions */
00165    struct ast_context *next;     /*!< Link them together */
00166    struct ast_include *includes;    /*!< Include other contexts */
00167    struct ast_ignorepat *ignorepats;   /*!< Patterns for which to continue playing dialtone */
00168    const char *registrar;        /*!< Registrar */
00169    AST_LIST_HEAD_NOLOCK(, ast_sw) alts;   /*!< Alternative switches */
00170    ast_mutex_t macrolock;        /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
00171    char name[0];           /*!< Name of the context */
00172 };
00173 
00174 
00175 /*! \brief ast_app: A registered application */
00176 struct ast_app {
00177    int (*execute)(struct ast_channel *chan, void *data);
00178    const char *synopsis;         /*!< Synopsis text for 'show applications' */
00179    const char *description;      /*!< Description (help text) for 'show application &lt;name&gt;' */
00180    AST_RWLIST_ENTRY(ast_app) list;     /*!< Next app in list */
00181    struct module *module;        /*!< Module this app belongs to */
00182    char name[0];           /*!< Name of the application */
00183 };
00184 
00185 /*! \brief ast_state_cb: An extension state notify register item */
00186 struct ast_state_cb {
00187    int id;
00188    void *data;
00189    ast_state_cb_type callback;
00190    struct ast_state_cb *next;
00191 };
00192 
00193 /*! \brief Structure for dial plan hints
00194 
00195   \note Hints are pointers from an extension in the dialplan to one or
00196   more devices (tech/name) 
00197    - See \ref AstExtState
00198 */
00199 struct ast_hint {
00200    struct ast_exten *exten;   /*!< Extension */
00201    int laststate;          /*!< Last known state */
00202    struct ast_state_cb *callbacks;  /*!< Callback list for this extension */
00203    AST_RWLIST_ENTRY(ast_hint) list;/*!< Pointer to next hint in list */
00204 };
00205 
00206 static const struct cfextension_states {
00207    int extension_state;
00208    const char * const text;
00209 } extension_states[] = {
00210    { AST_EXTENSION_NOT_INUSE,                     "Idle" },
00211    { AST_EXTENSION_INUSE,                         "InUse" },
00212    { AST_EXTENSION_BUSY,                          "Busy" },
00213    { AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
00214    { AST_EXTENSION_RINGING,                       "Ringing" },
00215    { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
00216    { AST_EXTENSION_ONHOLD,                        "Hold" },
00217    { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
00218 };
00219 
00220 static int pbx_builtin_answer(struct ast_channel *, void *);
00221 static int pbx_builtin_goto(struct ast_channel *, void *);
00222 static int pbx_builtin_hangup(struct ast_channel *, void *);
00223 static int pbx_builtin_background(struct ast_channel *, void *);
00224 static int pbx_builtin_wait(struct ast_channel *, void *);
00225 static int pbx_builtin_waitexten(struct ast_channel *, void *);
00226 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
00227 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
00228 static int pbx_builtin_ringing(struct ast_channel *, void *);
00229 static int pbx_builtin_progress(struct ast_channel *, void *);
00230 static int pbx_builtin_congestion(struct ast_channel *, void *);
00231 static int pbx_builtin_busy(struct ast_channel *, void *);
00232 static int pbx_builtin_noop(struct ast_channel *, void *);
00233 static int pbx_builtin_gotoif(struct ast_channel *, void *);
00234 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
00235 static int pbx_builtin_execiftime(struct ast_channel *, void *);
00236 static int pbx_builtin_saynumber(struct ast_channel *, void *);
00237 static int pbx_builtin_saydigits(struct ast_channel *, void *);
00238 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
00239 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
00240 int pbx_builtin_setvar(struct ast_channel *, void *);
00241 static int pbx_builtin_importvar(struct ast_channel *, void *);
00242 
00243 AST_RWLOCK_DEFINE_STATIC(globalslock);
00244 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00245 
00246 static int autofallthrough = 1;
00247 
00248 AST_MUTEX_DEFINE_STATIC(maxcalllock);
00249 static int countcalls;
00250 
00251 static AST_RWLIST_HEAD_STATIC(acf_root, ast_custom_function);
00252 
00253 /*! \brief Declaration of builtin applications */
00254 static struct pbx_builtin {
00255    char name[AST_MAX_APP];
00256    int (*execute)(struct ast_channel *chan, void *data);
00257    char *synopsis;
00258    char *description;
00259 } builtins[] =
00260 {
00261    /* These applications are built into the PBX core and do not
00262       need separate modules */
00263 
00264    { "Answer", pbx_builtin_answer,
00265    "Answer a channel if ringing",
00266    "  Answer([delay]): If the call has not been answered, this application will\n"
00267    "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
00268    "Asterisk will wait this number of milliseconds before returning to\n"
00269    "the dialplan after answering the call.\n"
00270    },
00271 
00272    { "BackGround", pbx_builtin_background,
00273    "Play an audio file while waiting for digits of an extension to go to.",
00274    "  Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
00275    "This application will play the given list of files while waiting for an\n"
00276    "extension to be dialed by the calling channel. To continue waiting for digits\n"
00277    "after this application has finished playing files, the WaitExten application\n"
00278    "should be used. The 'langoverride' option explicitly specifies which language\n"
00279    "to attempt to use for the requested sound files. If a 'context' is specified,\n"
00280    "this is the dialplan context that this application will use when exiting to a\n"
00281    "dialed extension."
00282    "  If one of the requested sound files does not exist, call processing will be\n"
00283    "terminated.\n"
00284    "  Options:\n"
00285    "    s - Causes the playback of the message to be skipped\n"
00286    "          if the channel is not in the 'up' state (i.e. it\n"
00287    "          hasn't been answered yet). If this happens, the\n"
00288    "          application will return immediately.\n"
00289    "    n - Don't answer the channel before playing the files.\n"
00290    "    m - Only break if a digit hit matches a one digit\n"
00291    "          extension in the destination context.\n"
00292    "This application sets the following channel variable upon completion:\n"
00293    " BACKGROUNDSTATUS    The status of the background attempt as a text string, one of\n"
00294    "               SUCCESS | FAILED\n"
00295    },
00296 
00297    { "Busy", pbx_builtin_busy,
00298    "Indicate the Busy condition",
00299    "  Busy([timeout]): This application will indicate the busy condition to\n"
00300    "the calling channel. If the optional timeout is specified, the calling channel\n"
00301    "will be hung up after the specified number of seconds. Otherwise, this\n"
00302    "application will wait until the calling channel hangs up.\n"
00303    },
00304 
00305    { "Congestion", pbx_builtin_congestion,
00306    "Indicate the Congestion condition",
00307    "  Congestion([timeout]): This application will indicate the congestion\n"
00308    "condition to the calling channel. If the optional timeout is specified, the\n"
00309    "calling channel will be hung up after the specified number of seconds.\n"
00310    "Otherwise, this application will wait until the calling channel hangs up.\n"
00311    },
00312 
00313    { "ExecIfTime", pbx_builtin_execiftime,
00314    "Conditional application execution based on the current time",
00315    "  ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
00316    "This application will execute the specified dialplan application, with optional\n"
00317    "arguments, if the current time matches the given time specification.\n"
00318    },
00319 
00320    { "Goto", pbx_builtin_goto,
00321    "Jump to a particular priority, extension, or context",
00322    "  Goto([[context|]extension|]priority): This application will cause the\n"
00323    "calling channel to continue dialplan execution at the specified priority.\n"
00324    "If no specific extension, or extension and context, are specified, then this\n"
00325    "application will jump to the specified priority of the current extension.\n"
00326    "  If the attempt to jump to another location in the dialplan is not successful,\n"
00327    "then the channel will continue at the next priority of the current extension.\n"
00328    },
00329 
00330    { "GotoIf", pbx_builtin_gotoif,
00331    "Conditional goto",
00332    "  GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will cause\n"
00333    "the calling channel to jump to the specified location in the dialplan based on\n"
00334    "the evaluation of the given condition. The channel will continue at\n"
00335    "'labeliftrue' if the condition is true, or 'labeliffalse' if the condition is\n"
00336    "false. The labels are specified with the same syntax as used within the Goto\n"
00337    "application.  If the label chosen by the condition is omitted, no jump is\n"
00338    "performed, but execution continues with the next priority in the dialplan.\n"
00339    },
00340 
00341    { "GotoIfTime", pbx_builtin_gotoiftime,
00342    "Conditional Goto based on the current time",
00343    "  GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
00344    "This application will have the calling channel jump to the specified location\n"
00345    "in the dialplan if the current time matches the given time specification.\n"
00346    },
00347 
00348    { "ImportVar", pbx_builtin_importvar,
00349    "Import a variable from a channel into a new variable",
00350    "  ImportVar(newvar=channelname|variable): This application imports a variable\n"
00351    "from the specified channel (as opposed to the current one) and stores it as\n"
00352    "a variable in the current channel (the channel that is calling this\n"
00353    "application). Variables created by this application have the same inheritance\n"
00354    "properties as those created with the Set application. See the documentation for\n"
00355    "Set for more information.\n"
00356    },
00357 
00358    { "Hangup", pbx_builtin_hangup,
00359    "Hang up the calling channel",
00360    "  Hangup([causecode]): This application will hang up the calling channel.\n"
00361    "If a causecode is given the channel's hangup cause will be set to the given\n"
00362    "value.\n"
00363    },
00364 
00365    { "NoOp", pbx_builtin_noop,
00366    "Do Nothing",
00367    "  NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
00368    "purposes. Any text that is provided as arguments to this application can be\n"
00369    "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
00370    "variables or functions without having any effect."
00371    },
00372 
00373    { "Progress", pbx_builtin_progress,
00374    "Indicate progress",
00375    "  Progress(): This application will request that in-band progress information\n"
00376    "be provided to the calling channel.\n"
00377    },
00378 
00379    { "ResetCDR", pbx_builtin_resetcdr,
00380    "Resets the Call Data Record",
00381    "  ResetCDR([options]):  This application causes the Call Data Record to be\n"
00382    "reset.\n"
00383    "  Options:\n"
00384    "    w -- Store the current CDR record before resetting it.\n"
00385    "    a -- Store any stacked records.\n"
00386    "    v -- Save CDR variables.\n"
00387    },
00388 
00389    { "Ringing", pbx_builtin_ringing,
00390    "Indicate ringing tone",
00391    "  Ringing(): This application will request that the channel indicate a ringing\n"
00392    "tone to the user.\n"
00393    },
00394 
00395    { "SayAlpha", pbx_builtin_saycharacters,
00396    "Say Alpha",
00397    "  SayAlpha(string): This application will play the sounds that correspond to\n"
00398    "the letters of the given string.\n"
00399    },
00400 
00401    { "SayDigits", pbx_builtin_saydigits,
00402    "Say Digits",
00403    "  SayDigits(digits): This application will play the sounds that correspond\n"
00404    "to the digits of the given number. This will use the language that is currently\n"
00405    "set for the channel. See the LANGUAGE function for more information on setting\n"
00406    "the language for the channel.\n"
00407    },
00408 
00409    { "SayNumber", pbx_builtin_saynumber,
00410    "Say Number",
00411    "  SayNumber(digits[,gender]): This application will play the sounds that\n"
00412    "correspond to the given number. Optionally, a gender may be specified.\n"
00413    "This will use the language that is currently set for the channel. See the\n"
00414    "LANGUAGE function for more information on setting the language for the channel.\n"
00415    },
00416 
00417    { "SayPhonetic", pbx_builtin_sayphonetic,
00418    "Say Phonetic",
00419    "  SayPhonetic(string): This application will play the sounds from the phonetic\n"
00420    "alphabet that correspond to the letters in the given string.\n"
00421    },
00422 
00423    { "Set", pbx_builtin_setvar,
00424    "Set channel variable(s) or function value(s)",
00425    "  Set(name1=value1|name2=value2|..[|options])\n"
00426    "This function can be used to set the value of channel variables or dialplan\n"
00427    "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
00428    "if the variable name is prefixed with _, the variable will be inherited into\n"
00429    "channels created from the current channel. If the variable name is prefixed\n"
00430    "with __, the variable will be inherited into channels created from the current\n"
00431    "channel and all children channels.\n"
00432    "  Options:\n"
00433    "    g - Set variable globally instead of on the channel\n"
00434    "        (applies only to variables, not functions)\n"
00435    },
00436 
00437    { "SetAMAFlags", pbx_builtin_setamaflags,
00438    "Set the AMA Flags",
00439    "  SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
00440    "  billing purposes.\n"
00441    },
00442 
00443    { "Wait", pbx_builtin_wait,
00444    "Waits for some time",
00445    "  Wait(seconds): This application waits for a specified number of seconds.\n"
00446    "Then, dialplan execution will continue at the next priority.\n"
00447    "  Note that the seconds can be passed with fractions of a second. For example,\n"
00448    "'1.5' will ask the application to wait for 1.5 seconds.\n"
00449    },
00450 
00451    { "WaitExten", pbx_builtin_waitexten,
00452    "Waits for an extension to be entered",
00453    "  WaitExten([seconds][|options]): This application waits for the user to enter\n"
00454    "a new extension for a specified number of seconds.\n"
00455    "  Note that the seconds can be passed with fractions of a second. For example,\n"
00456    "'1.5' will ask the application to wait for 1.5 seconds.\n"
00457    "  Options:\n"
00458    "    m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
00459    "               Optionally, specify the class for music on hold within parenthesis.\n"
00460    },
00461 
00462 };
00463 
00464 static struct ast_context *contexts;
00465 AST_MUTEX_DEFINE_STATIC(conlock);      /*!< Lock for the ast_context list */
00466 
00467 static AST_RWLIST_HEAD_STATIC(apps, ast_app);
00468 
00469 static AST_RWLIST_HEAD_STATIC(switches, ast_switch);
00470 
00471 static int stateid = 1;
00472 /* WARNING:
00473    When holding this list's lock, do _not_ do anything that will cause conlock
00474    to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
00475    function will take the locks in conlock/hints order, so any other
00476    paths that require both locks must also take them in that order.
00477 */
00478 static AST_RWLIST_HEAD_STATIC(hints, ast_hint);
00479 struct ast_state_cb *statecbs;
00480 
00481 /*
00482    \note This function is special. It saves the stack so that no matter
00483    how many times it is called, it returns to the same place */
00484 int pbx_exec(struct ast_channel *c,       /*!< Channel */
00485         struct ast_app *app,     /*!< Application */
00486         void *data)        /*!< Data for execution */
00487 {
00488    int res;
00489 
00490    const char *saved_c_appl;
00491    const char *saved_c_data;
00492 
00493    if (c->cdr)
00494       ast_cdr_setapp(c->cdr, app->name, data);
00495 
00496    /* save channel values */
00497    saved_c_appl= c->appl;
00498    saved_c_data= c->data;
00499 
00500    c->appl = app->name;
00501    c->data = data;
00502    /* XXX remember what to to when we have linked apps to modules */
00503    if (app->module) {
00504       /* XXX LOCAL_USER_ADD(app->module) */
00505    }
00506    res = app->execute(c, data);
00507    if (app->module) {
00508       /* XXX LOCAL_USER_REMOVE(app->module) */
00509    }
00510    /* restore channel values */
00511    c->appl = saved_c_appl;
00512    c->data = saved_c_data;
00513    return res;
00514 }
00515 
00516 
00517 /*! Go no deeper than this through includes (not counting loops) */
00518 #define AST_PBX_MAX_STACK  128
00519 
00520 /*! \brief Find application handle in linked list
00521  */
00522 struct ast_app *pbx_findapp(const char *app)
00523 {
00524    struct ast_app *tmp;
00525 
00526    AST_RWLIST_RDLOCK(&apps);
00527    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
00528       if (!strcasecmp(tmp->name, app))
00529          break;
00530    }
00531    AST_RWLIST_UNLOCK(&apps);
00532 
00533    return tmp;
00534 }
00535 
00536 static struct ast_switch *pbx_findswitch(const char *sw)
00537 {
00538    struct ast_switch *asw;
00539 
00540    AST_RWLIST_RDLOCK(&switches);
00541    AST_RWLIST_TRAVERSE(&switches, asw, list) {
00542       if (!strcasecmp(asw->name, sw))
00543          break;
00544    }
00545    AST_RWLIST_UNLOCK(&switches);
00546 
00547    return asw;
00548 }
00549 
00550 static inline int include_valid(struct ast_include *i)
00551 {
00552    if (!i->hastime)
00553       return 1;
00554 
00555    return ast_check_timing(&(i->timing));
00556 }
00557 
00558 static void pbx_destroy(struct ast_pbx *p)
00559 {
00560    free(p);
00561 }
00562 
00563 /*
00564  * Special characters used in patterns:
00565  * '_'   underscore is the leading character of a pattern.
00566  *    In other position it is treated as a regular char.
00567  * ' ' '-'  space and '-' are separator and ignored.
00568  * .  one or more of any character. Only allowed at the end of
00569  *    a pattern.
00570  * !  zero or more of anything. Also impacts the result of CANMATCH
00571  *    and MATCHMORE. Only allowed at the end of a pattern.
00572  *    In the core routine, ! causes a match with a return code of 2.
00573  *    In turn, depending on the search mode: (XXX check if it is implemented)
00574  *    - E_MATCH retuns 1 (does match)
00575  *    - E_MATCHMORE returns 0 (no match)
00576  *    - E_CANMATCH returns 1 (does match)
00577  *
00578  * /  should not appear as it is considered the separator of the CID info.
00579  *    XXX at the moment we may stop on this char.
00580  *
00581  * X Z N match ranges 0-9, 1-9, 2-9 respectively.
00582  * [  denotes the start of a set of character. Everything inside
00583  *    is considered literally. We can have ranges a-d and individual
00584  *    characters. A '[' and '-' can be considered literally if they
00585  *    are just before ']'.
00586  *    XXX currently there is no way to specify ']' in a range, nor \ is
00587  *    considered specially.
00588  *
00589  * When we compare a pattern with a specific extension, all characters in the extension
00590  * itself are considered literally with the only exception of '-' which is considered
00591  * as a separator and thus ignored.
00592  * XXX do we want to consider space as a separator as well ?
00593  * XXX do we want to consider the separators in non-patterns as well ?
00594  */
00595 
00596 /*!
00597  * \brief helper functions to sort extensions and patterns in the desired way,
00598  * so that more specific patterns appear first.
00599  *
00600  * ext_cmp1 compares individual characters (or sets of), returning
00601  * an int where bits 0-7 are the ASCII code of the first char in the set,
00602  * while bit 8-15 are the cardinality of the set minus 1.
00603  * This way more specific patterns (smaller cardinality) appear first.
00604  * Wildcards have a special value, so that we can directly compare them to
00605  * sets by subtracting the two values. In particular:
00606  *    0x000xx     one character, xx
00607  *    0x0yyxx     yy character set starting with xx
00608  *    0x10000     '.' (one or more of anything)
00609  *    0x20000     '!' (zero or more of anything)
00610  *    0x30000     NUL (end of string)
00611  *    0x40000     error in set.
00612  * The pointer to the string is advanced according to needs.
00613  * NOTES:
00614  * 1. the empty set is equivalent to NUL.
00615  * 2. given that a full set has always 0 as the first element,
00616  *    we could encode the special cases as 0xffXX where XX
00617  *    is 1, 2, 3, 4 as used above.
00618  */
00619 static int ext_cmp1(const char **p)
00620 {
00621    uint32_t chars[8];
00622    int c, cmin = 0xff, count = 0;
00623    const char *end;
00624 
00625    /* load, sign extend and advance pointer until we find
00626     * a valid character.
00627     */
00628    while ( (c = *(*p)++) && (c == ' ' || c == '-') )
00629       ;  /* ignore some characters */
00630 
00631    /* always return unless we have a set of chars */
00632    switch (c) {
00633    default: /* ordinary character */
00634       return 0x0000 | (c & 0xff);
00635 
00636    case 'N':   /* 2..9 */
00637       return 0x0700 | '2' ;
00638 
00639    case 'X':   /* 0..9 */
00640       return 0x0900 | '0';
00641 
00642    case 'Z':   /* 1..9 */
00643       return 0x0800 | '1';
00644 
00645    case '.':   /* wildcard */
00646       return 0x10000;
00647 
00648    case '!':   /* earlymatch */
00649       return 0x20000;   /* less specific than NULL */
00650 
00651    case '\0':  /* empty string */
00652       *p = NULL;
00653       return 0x30000;
00654 
00655    case '[':   /* pattern */
00656       break;
00657    }
00658    /* locate end of set */
00659    end = strchr(*p, ']');  
00660 
00661    if (end == NULL) {
00662       ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
00663       return 0x40000;   /* XXX make this entry go last... */
00664    }
00665 
00666    bzero(chars, sizeof(chars));  /* clear all chars in the set */
00667    for (; *p < end  ; (*p)++) {
00668       unsigned char c1, c2;   /* first-last char in range */
00669       c1 = (unsigned char)((*p)[0]);
00670       if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
00671          c2 = (unsigned char)((*p)[2]);
00672          *p += 2; /* skip a total of 3 chars */
00673       } else         /* individual character */
00674          c2 = c1;
00675       if (c1 < cmin)
00676          cmin = c1;
00677       for (; c1 <= c2; c1++) {
00678          uint32_t mask = 1 << (c1 % 32);
00679          if ( (chars[ c1 / 32 ] & mask) == 0)
00680             count += 0x100;
00681          chars[ c1 / 32 ] |= mask;
00682       }
00683    }
00684    (*p)++;
00685    return count == 0 ? 0x30000 : (count | cmin);
00686 }
00687 
00688 /*!
00689  * \brief the full routine to compare extensions in rules.
00690  */
00691 static int ext_cmp(const char *a, const char *b)
00692 {
00693    /* make sure non-patterns come first.
00694     * If a is not a pattern, it either comes first or
00695     * we use strcmp to compare the strings.
00696     */
00697    int ret = 0;
00698 
00699    if (a[0] != '_')
00700       return (b[0] == '_') ? -1 : strcmp(a, b);
00701 
00702    /* Now we know a is a pattern; if b is not, a comes first */
00703    if (b[0] != '_')
00704       return 1;
00705 #if 0 /* old mode for ext matching */
00706    return strcmp(a, b);
00707 #endif
00708    /* ok we need full pattern sorting routine */
00709    while (!ret && a && b)
00710       ret = ext_cmp1(&a) - ext_cmp1(&b);
00711    if (ret == 0)
00712       return 0;
00713    else
00714       return (ret > 0) ? 1 : -1;
00715 }
00716 
00717 /*!
00718  * When looking up extensions, we can have different requests
00719  * identified by the 'action' argument, as follows.
00720  * Note that the coding is such that the low 4 bits are the
00721  * third argument to extension_match_core.
00722  */
00723 enum ext_match_t {
00724    E_MATCHMORE =  0x00, /* extension can match but only with more 'digits' */
00725    E_CANMATCH =   0x01, /* extension can match with or without more 'digits' */
00726    E_MATCH =   0x02, /* extension is an exact match */
00727    E_MATCH_MASK = 0x03, /* mask for the argument to extension_match_core() */
00728    E_SPAWN =   0x12, /* want to spawn an extension. Requires exact match */
00729    E_FINDLABEL =  0x22  /* returns the priority for a given label. Requires exact match */
00730 };
00731 
00732 /*
00733  * Internal function for ast_extension_{match|close}
00734  * return 0 on no-match, 1 on match, 2 on early match.
00735  * mode is as follows:
00736  * E_MATCH     success only on exact match
00737  * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
00738  * E_CANMATCH  either of the above.
00739  */
00740 
00741 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
00742 {
00743    mode &= E_MATCH_MASK;   /* only consider the relevant bits */
00744 
00745    if ( (mode == E_MATCH) && (pattern[0] == '_') && (strcasecmp(pattern,data)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
00746       return 1;
00747 
00748    if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
00749       int ld = strlen(data), lp = strlen(pattern);
00750 
00751       if (lp < ld)      /* pattern too short, cannot match */
00752          return 0;
00753       /* depending on the mode, accept full or partial match or both */
00754       if (mode == E_MATCH)
00755          return !strcmp(pattern, data); /* 1 on match, 0 on fail */
00756       if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
00757          return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
00758       else
00759          return 0;
00760    }
00761    pattern++; /* skip leading _ */
00762    /*
00763     * XXX below we stop at '/' which is a separator for the CID info. However we should
00764     * not store '/' in the pattern at all. When we insure it, we can remove the checks.
00765     */
00766    while (*data && *pattern && *pattern != '/') {
00767       const char *end;
00768 
00769       if (*data == '-') { /* skip '-' in data (just a separator) */
00770          data++;
00771          continue;
00772       }
00773       switch (toupper(*pattern)) {
00774       case '[':   /* a range */
00775          end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
00776          if (end == NULL) {
00777             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
00778             return 0;   /* unconditional failure */
00779          }
00780          for (pattern++; pattern != end; pattern++) {
00781             if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
00782                if (*data >= pattern[0] && *data <= pattern[2])
00783                   break;   /* match found */
00784                else {
00785                   pattern += 2; /* skip a total of 3 chars */
00786                   continue;
00787                }
00788             } else if (*data == pattern[0])
00789                break;   /* match found */
00790          }
00791          if (pattern == end)
00792             return 0;
00793          pattern = end; /* skip and continue */
00794          break;
00795       case 'N':
00796          if (*data < '2' || *data > '9')
00797             return 0;
00798          break;
00799       case 'X':
00800          if (*data < '0' || *data > '9')
00801             return 0;
00802          break;
00803       case 'Z':
00804          if (*data < '1' || *data > '9')
00805             return 0;
00806          break;
00807       case '.':   /* Must match, even with more digits */
00808          return 1;
00809       case '!':   /* Early match */
00810          return 2;
00811       case ' ':
00812       case '-':   /* Ignore these in patterns */
00813          data--; /* compensate the final data++ */
00814          break;
00815       default:
00816          if (*data != *pattern)
00817             return 0;
00818       }
00819       data++;
00820       pattern++;
00821    }
00822    if (*data)        /* data longer than pattern, no match */
00823       return 0;
00824    /*
00825     * match so far, but ran off the end of the data.
00826     * Depending on what is next, determine match or not.
00827     */
00828    if (*pattern == '\0' || *pattern == '/')  /* exact match */
00829       return (mode == E_MATCHMORE) ? 0 : 1;  /* this is a failure for E_MATCHMORE */
00830    else if (*pattern == '!')        /* early match */
00831       return 2;
00832    else                 /* partial match */
00833       return (mode == E_MATCH) ? 0 : 1;   /* this is a failure for E_MATCH */
00834 }
00835 
00836 /*
00837  * Wrapper around _extension_match_core() to do performance measurement
00838  * using the profiling code.
00839  */
00840 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
00841 {
00842    int i;
00843    static int prof_id = -2;   /* marker for 'unallocated' id */
00844    if (prof_id == -2)
00845       prof_id = ast_add_profile("ext_match", 0);
00846    ast_mark(prof_id, 1);
00847    i = _extension_match_core(pattern, data, mode);
00848    ast_mark(prof_id, 0);
00849    return i;
00850 }
00851 
00852 int ast_extension_match(const char *pattern, const char *data)
00853 {
00854    return extension_match_core(pattern, data, E_MATCH);
00855 }
00856 
00857 int ast_extension_close(const char *pattern, const char *data, int needmore)
00858 {
00859    if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
00860       ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
00861    return extension_match_core(pattern, data, needmore);
00862 }
00863 
00864 struct ast_context *ast_context_find(const char *name)
00865 {
00866    struct ast_context *tmp = NULL;
00867    ast_mutex_lock(&conlock);
00868    while ( (tmp = ast_walk_contexts(tmp)) ) {
00869       if (!name || !strcasecmp(name, tmp->name))
00870          break;
00871    }
00872    ast_mutex_unlock(&conlock);
00873    return tmp;
00874 }
00875 
00876 #define STATUS_NO_CONTEXT  1
00877 #define STATUS_NO_EXTENSION   2
00878 #define STATUS_NO_PRIORITY 3
00879 #define STATUS_NO_LABEL    4
00880 #define STATUS_SUCCESS     5
00881 
00882 static int matchcid(const char *cidpattern, const char *callerid)
00883 {
00884    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
00885       failing to get a number should count as a match, otherwise not */
00886 
00887    if (ast_strlen_zero(callerid))
00888       return ast_strlen_zero(cidpattern) ? 1 : 0;
00889 
00890    return ast_extension_match(cidpattern, callerid);
00891 }
00892 
00893 /* request and result for pbx_find_extension */
00894 struct pbx_find_info {
00895 #if 0
00896    const char *context;
00897    const char *exten;
00898    int priority;
00899 #endif
00900 
00901    char *incstack[AST_PBX_MAX_STACK];      /* filled during the search */
00902    int stacklen;                   /* modified during the search */
00903    int status;                     /* set on return */
00904    struct ast_switch *swo;         /* set on return */
00905    const char *data;               /* set on return */
00906    const char *foundcontext;       /* set on return */
00907 };
00908 
00909 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
00910    struct ast_context *bypass, struct pbx_find_info *q,
00911    const char *context, const char *exten, int priority,
00912    const char *label, const char *callerid, enum ext_match_t action)
00913 {
00914    int x, res;
00915    struct ast_context *tmp;
00916    struct ast_exten *e, *eroot;
00917    struct ast_include *i;
00918    struct ast_sw *sw;
00919 
00920    /* Initialize status if appropriate */
00921    if (q->stacklen == 0) {
00922       q->status = STATUS_NO_CONTEXT;
00923       q->swo = NULL;
00924       q->data = NULL;
00925       q->foundcontext = NULL;
00926    }
00927    /* Check for stack overflow */
00928    if (q->stacklen >= AST_PBX_MAX_STACK) {
00929       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
00930       return NULL;
00931    }
00932    /* Check first to see if we've already been checked */
00933    for (x = 0; x < q->stacklen; x++) {
00934       if (!strcasecmp(q->incstack[x], context))
00935          return NULL;
00936    }
00937    if (bypass) /* bypass means we only look there */
00938       tmp = bypass;
00939    else {   /* look in contexts */
00940       tmp = NULL;
00941       while ((tmp = ast_walk_contexts(tmp)) ) {
00942          if (!strcmp(tmp->name, context))
00943             break;
00944       }
00945       if (!tmp)
00946          return NULL;
00947    }
00948    if (q->status < STATUS_NO_EXTENSION)
00949       q->status = STATUS_NO_EXTENSION;
00950 
00951    /* scan the list trying to match extension and CID */
00952    eroot = NULL;
00953    while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
00954       int match = extension_match_core(eroot->exten, exten, action);
00955       /* 0 on fail, 1 on match, 2 on earlymatch */
00956 
00957       if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
00958          continue;   /* keep trying */
00959       if (match == 2 && action == E_MATCHMORE) {
00960          /* We match an extension ending in '!'.
00961           * The decision in this case is final and is NULL (no match).
00962           */
00963          return NULL;
00964       }
00965       /* found entry, now look for the right priority */
00966       if (q->status < STATUS_NO_PRIORITY)
00967          q->status = STATUS_NO_PRIORITY;
00968       e = NULL;
00969       while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
00970          /* Match label or priority */
00971          if (action == E_FINDLABEL) {
00972             if (q->status < STATUS_NO_LABEL)
00973                q->status = STATUS_NO_LABEL;
00974             if (label && e->label && !strcmp(label, e->label))
00975                break;   /* found it */
00976          } else if (e->priority == priority) {
00977             break;   /* found it */
00978          } /* else keep searching */
00979       }
00980       if (e) { /* found a valid match */
00981          q->status = STATUS_SUCCESS;
00982          q->foundcontext = context;
00983          return e;
00984       }
00985    }
00986    /* Check alternative switches */
00987    AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
00988       struct ast_switch *asw = pbx_findswitch(sw->name);
00989       ast_switch_f *aswf = NULL;
00990       char *datap;
00991 
00992       if (!asw) {
00993          ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
00994          continue;
00995       }
00996       /* Substitute variables now */
00997       if (sw->eval)
00998          pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
00999 
01000       /* equivalent of extension_match_core() at the switch level */
01001       if (action == E_CANMATCH)
01002          aswf = asw->canmatch;
01003       else if (action == E_MATCHMORE)
01004          aswf = asw->matchmore;
01005       else /* action == E_MATCH */
01006          aswf = asw->exists;
01007       datap = sw->eval ? sw->tmpdata : sw->data;
01008       res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
01009       if (res) {  /* Got a match */
01010          q->swo = asw;
01011          q->data = datap;
01012          q->foundcontext = context;
01013          /* XXX keep status = STATUS_NO_CONTEXT ? */
01014          return NULL;
01015       }
01016    }
01017    q->incstack[q->stacklen++] = tmp->name;   /* Setup the stack */
01018    /* Now try any includes we have in this context */
01019    for (i = tmp->includes; i; i = i->next) {
01020       if (include_valid(i)) {
01021          if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
01022             return e;
01023          if (q->swo)
01024             return NULL;
01025       }
01026    }
01027    return NULL;
01028 }
01029 
01030 /*! \brief extract offset:length from variable name.
01031  * Returns 1 if there is a offset:length part, which is
01032  * trimmed off (values go into variables)
01033  */
01034 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
01035 {
01036    int parens=0;
01037 
01038    *offset = 0;
01039    *length = INT_MAX;
01040    *isfunc = 0;
01041    for (; *var; var++) {
01042       if (*var == '(') {
01043          (*isfunc)++;
01044          parens++;
01045       } else if (*var == ')') {
01046          parens--;
01047       } else if (*var == ':' && parens == 0) {
01048          *var++ = '\0';
01049          sscanf(var, "%d:%d", offset, length);
01050          return 1; /* offset:length valid */
01051       }
01052    }
01053    return 0;
01054 }
01055 
01056 /*! \brief takes a substring. It is ok to call with value == workspace.
01057  *
01058  * offset < 0 means start from the end of the string and set the beginning
01059  *   to be that many characters back.
01060  * length is the length of the substring.  A value less than 0 means to leave
01061  * that many off the end.
01062  * Always return a copy in workspace.
01063  */
01064 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
01065 {
01066    char *ret = workspace;
01067    int lr;  /* length of the input string after the copy */
01068 
01069    ast_copy_string(workspace, value, workspace_len); /* always make a copy */
01070 
01071    lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
01072 
01073    /* Quick check if no need to do anything */
01074    if (offset == 0 && length >= lr) /* take the whole string */
01075       return ret;
01076 
01077    if (offset < 0)   {  /* translate negative offset into positive ones */
01078       offset = lr + offset;
01079       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
01080          offset = 0;
01081    }
01082 
01083    /* too large offset result in empty string so we know what to return */
01084    if (offset >= lr)
01085       return ret + lr;  /* the final '\0' */
01086 
01087    ret += offset;    /* move to the start position */
01088    if (length >= 0 && length < lr - offset)  /* truncate if necessary */
01089       ret[length] = '\0';
01090    else if (length < 0) {
01091       if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
01092          ret[lr + length - offset] = '\0';
01093       else
01094          ret[0] = '\0';
01095    }
01096 
01097    return ret;
01098 }
01099 
01100 /*! \brief  Support for Asterisk built-in variables in the dialplan
01101 
01102 \note See also
01103    - \ref AstVar  Channel variables
01104    - \ref AstCauses The HANGUPCAUSE variable
01105  */
01106 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
01107 {
01108    const char not_found = '\0';
01109    char *tmpvar;
01110    const char *s; /* the result */
01111    int offset, length;
01112    int i, need_substring;
01113    struct varshead *places[2] = { headp, &globals };  /* list of places where we may look */
01114 
01115    if (c) {
01116       places[0] = &c->varshead;
01117    }
01118    /*
01119     * Make a copy of var because parse_variable_name() modifies the string.
01120     * Then if called directly, we might need to run substring() on the result;
01121     * remember this for later in 'need_substring', 'offset' and 'length'
01122     */
01123    tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
01124    need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
01125 
01126    /*
01127     * Look first into predefined variables, then into variable lists.
01128     * Variable 's' points to the result, according to the following rules:
01129     * s == &not_found (set at the beginning) means that we did not find a
01130     * matching variable and need to look into more places.
01131     * If s != &not_found, s is a valid result string as follows:
01132     * s = NULL if the variable does not have a value;
01133     * you typically do this when looking for an unset predefined variable.
01134     * s = workspace if the result has been assembled there;
01135     * typically done when the result is built e.g. with an snprintf(),
01136     * so we don't need to do an additional copy.
01137     * s != workspace in case we have a string, that needs to be copied
01138     * (the ast_copy_string is done once for all at the end).
01139     * Typically done when the result is already available in some string.
01140     */
01141    s = &not_found;   /* default value */
01142    if (c) { /* This group requires a valid channel */
01143       /* Names with common parts are looked up a piece at a time using strncmp. */
01144       if (!strncmp(var, "CALL", 4)) {
01145          if (!strncmp(var + 4, "ING", 3)) {
01146             if (!strcmp(var + 7, "PRES")) {        /* CALLINGPRES */
01147                snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
01148                s = workspace;
01149             } else if (!strcmp(var + 7, "ANI2")) {    /* CALLINGANI2 */
01150                snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
01151                s = workspace;
01152             } else if (!strcmp(var + 7, "TON")) {     /* CALLINGTON */
01153                snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
01154                s = workspace;
01155             } else if (!strcmp(var + 7, "TNS")) {     /* CALLINGTNS */
01156                snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
01157                s = workspace;
01158             }
01159          }
01160       } else if (!strcmp(var, "HINT")) {
01161          s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
01162       } else if (!strcmp(var, "HINTNAME")) {
01163          s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
01164       } else if (!strcmp(var, "EXTEN")) {
01165          s = c->exten;
01166       } else if (!strcmp(var, "CONTEXT")) {
01167          s = c->context;
01168       } else if (!strcmp(var, "PRIORITY")) {
01169          snprintf(workspace, workspacelen, "%d", c->priority);
01170          s = workspace;
01171       } else if (!strcmp(var, "CHANNEL")) {
01172          s = c->name;
01173       } else if (!strcmp(var, "UNIQUEID")) {
01174          s = c->uniqueid;
01175       } else if (!strcmp(var, "HANGUPCAUSE")) {
01176          snprintf(workspace, workspacelen, "%d", c->hangupcause);
01177          s = workspace;
01178       }
01179    }
01180    if (s == &not_found) { /* look for more */
01181       if (!strcmp(var, "EPOCH")) {
01182          snprintf(workspace, workspacelen, "%u",(int)time(NULL));
01183          s = workspace;
01184       } else if (!strcmp(var, "SYSTEMNAME")) {
01185          s = ast_config_AST_SYSTEM_NAME;
01186       }
01187    }
01188    /* if not found, look into chanvars or global vars */
01189    for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
01190       struct ast_var_t *variables;
01191       if (!places[i])
01192          continue;
01193       if (places[i] == &globals)
01194          ast_rwlock_rdlock(&globalslock);
01195       AST_LIST_TRAVERSE(places[i], variables, entries) {
01196          if (strcasecmp(ast_var_name(variables), var)==0) {
01197             s = ast_var_value(variables);
01198             break;
01199          }
01200       }
01201       if (places[i] == &globals)
01202          ast_rwlock_unlock(&globalslock);
01203    }
01204    if (s == &not_found || s == NULL)
01205       *ret = NULL;
01206    else {
01207       if (s != workspace)
01208          ast_copy_string(workspace, s, workspacelen);
01209       *ret = workspace;
01210       if (need_substring)
01211          *ret = substring(*ret, offset, length, workspace, workspacelen);
01212    }
01213 }
01214 
01215 static int handle_show_functions(int fd, int argc, char *argv[])
01216 {
01217    struct ast_custom_function *acf;
01218    int count_acf = 0;
01219    int like = 0;
01220 
01221    if (argc == 5 && (!strcmp(argv[3], "like")) ) {
01222       like = 1;
01223    } else if (argc != 3) {
01224       return RESULT_SHOWUSAGE;
01225    }
01226 
01227    ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
01228 
01229    AST_RWLIST_RDLOCK(&acf_root);
01230    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
01231       if (!like || strstr(acf->name, argv[4])) {
01232          count_acf++;
01233          ast_cli(fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
01234       }
01235    }
01236    AST_RWLIST_UNLOCK(&acf_root);
01237 
01238    ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
01239 
01240    return RESULT_SUCCESS;
01241 }
01242 
01243 static int handle_show_function(int fd, int argc, char *argv[])
01244 {
01245    struct ast_custom_function *acf;
01246    /* Maximum number of characters added by terminal coloring is 22 */
01247    char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
01248    char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
01249    char stxtitle[40], *syntax = NULL;
01250    int synopsis_size, description_size, syntax_size;
01251 
01252    if (argc < 4)
01253       return RESULT_SHOWUSAGE;
01254 
01255    if (!(acf = ast_custom_function_find(argv[3]))) {
01256       ast_cli(fd, "No function by that name registered.\n");
01257       return RESULT_FAILURE;
01258 
01259    }
01260 
01261    if (acf->synopsis)
01262       synopsis_size = strlen(acf->synopsis) + 23;
01263    else
01264       synopsis_size = strlen("Not available") + 23;
01265    synopsis = alloca(synopsis_size);
01266 
01267    if (acf->desc)
01268       description_size = strlen(acf->desc) + 23;
01269    else
01270       description_size = strlen("Not available") + 23;
01271    description = alloca(description_size);
01272 
01273    if (acf->syntax)
01274       syntax_size = strlen(acf->syntax) + 23;
01275    else
01276       syntax_size = strlen("Not available") + 23;
01277    syntax = alloca(syntax_size);
01278 
01279    snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
01280    term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
01281    term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
01282    term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
01283    term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
01284    term_color(syntax,
01285          acf->syntax ? acf->syntax : "Not available",
01286          COLOR_CYAN, 0, syntax_size);
01287    term_color(synopsis,
01288          acf->synopsis ? acf->synopsis : "Not available",
01289          COLOR_CYAN, 0, synopsis_size);
01290    term_color(description,
01291          acf->desc ? acf->desc : "Not available",
01292          COLOR_CYAN, 0, description_size);
01293 
01294    ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
01295 
01296    return RESULT_SUCCESS;
01297 }
01298 
01299 static char *complete_show_function(const char *line, const char *word, int pos, int state)
01300 {
01301    struct ast_custom_function *acf;
01302    char *ret = NULL;
01303    int which = 0;
01304    int wordlen = strlen(word);
01305 
01306    /* case-insensitive for convenience in this 'complete' function */
01307    AST_RWLIST_RDLOCK(&acf_root);
01308    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
01309       if (!strncasecmp(word, acf->name, wordlen) && ++which > state) {
01310          ret = strdup(acf->name);
01311          break;
01312       }
01313    }
01314    AST_RWLIST_UNLOCK(&acf_root);
01315 
01316    return ret;
01317 }
01318 
01319 struct ast_custom_function *ast_custom_function_find(const char *name)
01320 {
01321    struct ast_custom_function *acf = NULL;
01322 
01323    AST_RWLIST_RDLOCK(&acf_root);
01324    AST_RWLIST_TRAVERSE(&acf_root, acf, acflist) {
01325       if (!strcmp(name, acf->name))
01326          break;
01327    }
01328    AST_RWLIST_UNLOCK(&acf_root);
01329 
01330    return acf;
01331 }
01332 
01333 int ast_custom_function_unregister(struct ast_custom_function *acf)
01334 {
01335    struct ast_custom_function *cur;
01336 
01337    if (!acf)
01338       return -1;
01339 
01340    AST_RWLIST_WRLOCK(&acf_root);
01341    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
01342       if (cur == acf) {
01343          AST_RWLIST_REMOVE_CURRENT(&acf_root, acflist);
01344          if (option_verbose > 1)
01345             ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
01346          break;
01347       }
01348    }
01349    AST_RWLIST_TRAVERSE_SAFE_END
01350    AST_RWLIST_UNLOCK(&acf_root);
01351 
01352    return acf ? 0 : -1;
01353 }
01354 
01355 int ast_custom_function_register(struct ast_custom_function *acf)
01356 {
01357    struct ast_custom_function *cur;
01358 
01359    if (!acf)
01360       return -1;
01361 
01362    AST_RWLIST_WRLOCK(&acf_root);
01363 
01364    AST_RWLIST_TRAVERSE(&acf_root, cur, acflist) {
01365       if (!strcmp(acf->name, cur->name)) {
01366          ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
01367          AST_RWLIST_UNLOCK(&acf_root);
01368          return -1;
01369       }
01370    }
01371 
01372    /* Store in alphabetical order */
01373    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
01374       if (strcasecmp(acf->name, cur->name) < 0) {
01375          AST_RWLIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
01376          break;
01377       }
01378    }
01379    AST_RWLIST_TRAVERSE_SAFE_END
01380    if (!cur)
01381       AST_RWLIST_INSERT_TAIL(&acf_root, acf, acflist);
01382 
01383    AST_RWLIST_UNLOCK(&acf_root);
01384 
01385    if (option_verbose > 1)
01386       ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
01387 
01388    return 0;
01389 }
01390 
01391 /*! \brief return a pointer to the arguments of the function,
01392  * and terminates the function name with '\\0'
01393  */
01394 static char *func_args(char *function)
01395 {
01396    char *args = strchr(function, '(');
01397 
01398    if (!args)
01399       ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
01400    else {
01401       char *p;
01402       *args++ = '\0';
01403       if ((p = strrchr(args, ')')) )
01404          *p = '\0';
01405       else
01406          ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
01407    }
01408    return args;
01409 }
01410 
01411 int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
01412 {
01413    char *copy = ast_strdupa(function);
01414    char *args = func_args(copy);
01415    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
01416 
01417    if (acfptr == NULL)
01418       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
01419    else if (!acfptr->read)
01420       ast_log(LOG_ERROR, "Function %s cannot be read\n", copy);
01421    else
01422       return acfptr->read(chan, copy, args, workspace, len);
01423    return -1;
01424 }
01425 
01426 int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
01427 {
01428    char *copy = ast_strdupa(function);
01429    char *args = func_args(copy);
01430    struct ast_custom_function *acfptr = ast_custom_function_find(copy);
01431 
01432    if (acfptr == NULL)
01433       ast_log(LOG_ERROR, "Function %s not registered\n", copy);
01434    else if (!acfptr->write)
01435       ast_log(LOG_ERROR, "Function %s cannot be written to\n", copy);
01436    else
01437       return acfptr->write(chan, copy, args, value);
01438 
01439    return -1;
01440 }
01441 
01442 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
01443 {
01444    /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
01445       zero-filled */
01446    char *cp4;
01447    const char *tmp, *whereweare;
01448    int length, offset, offset2, isfunction;
01449    char *workspace = NULL;
01450    char *ltmp = NULL, *var = NULL;
01451    char *nextvar, *nextexp, *nextthing;
01452    char *vars, *vare;
01453    int pos, brackets, needsub, len;
01454 
01455    whereweare=tmp=cp1;
01456    while (!ast_strlen_zero(whereweare) && count) {
01457       /* Assume we're copying the whole remaining string */
01458       pos = strlen(whereweare);
01459       nextvar = NULL;
01460       nextexp = NULL;
01461       nextthing = strchr(whereweare, '$');
01462       if (nextthing) {
01463          switch (nextthing[1]) {
01464          case '{':
01465             nextvar = nextthing;
01466             pos = nextvar - whereweare;
01467             break;
01468          case '[':
01469             nextexp = nextthing;
01470             pos = nextexp - whereweare;
01471             break;
01472          }
01473       }
01474 
01475       if (pos) {
01476          /* Can't copy more than 'count' bytes */
01477          if (pos > count)
01478             pos = count;
01479 
01480          /* Copy that many bytes */
01481          memcpy(cp2, whereweare, pos);
01482 
01483          count -= pos;
01484          cp2 += pos;
01485          whereweare += pos;
01486       }
01487 
01488       if (nextvar) {
01489          /* We have a variable.  Find the start and end, and determine
01490             if we are going to have to recursively call ourselves on the
01491             contents */
01492          vars = vare = nextvar + 2;
01493          brackets = 1;
01494          needsub = 0;
01495 
01496          /* Find the end of it */
01497          while (brackets && *vare) {
01498             if ((vare[0] == '$') && (vare[1] == '{')) {
01499                needsub++;
01500             } else if (vare[0] == '{') {
01501                brackets++;
01502             } else if (vare[0] == '}') {
01503                brackets--;
01504             } else if ((vare[0] == '$') && (vare[1] == '['))
01505                needsub++;
01506             vare++;
01507          }
01508          if (brackets)
01509             ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
01510          len = vare - vars - 1;
01511 
01512          /* Skip totally over variable string */
01513          whereweare += (len + 3);
01514 
01515          if (!var)
01516             var = alloca(VAR_BUF_SIZE);
01517 
01518          /* Store variable name (and truncate) */
01519          ast_copy_string(var, vars, len + 1);
01520 
01521          /* Substitute if necessary */
01522          if (needsub) {
01523             if (!ltmp)
01524                ltmp = alloca(VAR_BUF_SIZE);
01525 
01526             memset(ltmp, 0, VAR_BUF_SIZE);
01527             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
01528             vars = ltmp;
01529          } else {
01530             vars = var;
01531          }
01532 
01533          if (!workspace)
01534             workspace = alloca(VAR_BUF_SIZE);
01535 
01536          workspace[0] = '\0';
01537 
01538          parse_variable_name(vars, &offset, &offset2, &isfunction);
01539          if (isfunction) {
01540             /* Evaluate function */
01541             cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
01542             if (option_debug)
01543                ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
01544          } else {
01545             /* Retrieve variable value */
01546             pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
01547          }
01548          if (cp4) {
01549             cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
01550 
01551             length = strlen(cp4);
01552             if (length > count)
01553                length = count;
01554             memcpy(cp2, cp4, length);
01555             count -= length;
01556             cp2 += length;
01557          }
01558       } else if (nextexp) {
01559          /* We have an expression.  Find the start and end, and determine
01560             if we are going to have to recursively call ourselves on the
01561             contents */
01562          vars = vare = nextexp + 2;
01563          brackets = 1;
01564          needsub = 0;
01565 
01566          /* Find the end of it */
01567          while (brackets && *vare) {
01568             if ((vare[0] == '$') && (vare[1] == '[')) {
01569                needsub++;
01570                brackets++;
01571                vare++;
01572             } else if (vare[0] == '[') {
01573                brackets++;
01574             } else if (vare[0] == ']') {
01575                brackets--;
01576             } else if ((vare[0] == '$') && (vare[1] == '{')) {
01577                needsub++;
01578                vare++;
01579             }
01580             vare++;
01581          }
01582          if (brackets)
01583             ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
01584          len = vare - vars - 1;
01585 
01586          /* Skip totally over expression */
01587          whereweare += (len + 3);
01588 
01589          if (!var)
01590             var = alloca(VAR_BUF_SIZE);
01591 
01592          /* Store variable name (and truncate) */
01593          ast_copy_string(var, vars, len + 1);
01594 
01595          /* Substitute if necessary */
01596          if (needsub) {
01597             if (!ltmp)
01598                ltmp = alloca(VAR_BUF_SIZE);
01599 
01600             memset(ltmp, 0, VAR_BUF_SIZE);
01601             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
01602             vars = ltmp;
01603          } else {
01604             vars = var;
01605          }
01606 
01607          length = ast_expr(vars, cp2, count);
01608 
01609          if (length) {
01610             if (option_debug)
01611                ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
01612             count -= length;
01613             cp2 += length;
01614          }
01615       } else
01616          break;
01617    }
01618 }
01619 
01620 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
01621 {
01622    pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
01623 }
01624 
01625 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
01626 {
01627    pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
01628 }
01629 
01630 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
01631 {
01632    memset(passdata, 0, datalen);
01633 
01634    /* No variables or expressions in e->data, so why scan it? */
01635    if (e->data && !strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
01636       ast_copy_string(passdata, e->data, datalen);
01637       return;
01638    }
01639 
01640    pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
01641 }
01642 
01643 /*! \brief The return value depends on the action:
01644  *
01645  * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
01646  * and return 0 on failure, -1 on match;
01647  * E_FINDLABEL maps the label to a priority, and returns
01648  * the priority on success, ... XXX
01649  * E_SPAWN, spawn an application,
01650  * and return 0 on success, -1 on failure.
01651  */
01652 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
01653    const char *context, const char *exten, int priority,
01654    const char *label, const char *callerid, enum ext_match_t action)
01655 {
01656    struct ast_exten *e;
01657    struct ast_app *app;
01658    int res;
01659    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
01660    char passdata[EXT_DATA_SIZE];
01661 
01662    int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
01663 
01664    ast_mutex_lock(&conlock);
01665    e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
01666    if (e) {
01667       if (matching_action) {
01668          ast_mutex_unlock(&conlock);
01669          return -1;  /* success, we found it */
01670       } else if (action == E_FINDLABEL) { /* map the label to a priority */
01671          res = e->priority;
01672          ast_mutex_unlock(&conlock);
01673          return res; /* the priority we were looking for */
01674       } else { /* spawn */
01675          if (!e->cached_app)
01676             e->cached_app = pbx_findapp(e->app);
01677          app = e->cached_app;
01678          ast_mutex_unlock(&conlock);
01679          if (!app) {
01680             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
01681             return -1;
01682          }
01683          if (c->context != context)
01684             ast_copy_string(c->context, context, sizeof(c->context));
01685          if (c->exten != exten)
01686             ast_copy_string(c->exten, exten, sizeof(c->exten));
01687          c->priority = priority;
01688          pbx_substitute_variables(passdata, sizeof(passdata), c, e);
01689          if (option_debug) {
01690             char atmp[80];
01691             char atmp2[EXT_DATA_SIZE+100];
01692             if (option_debug)
01693                ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
01694             snprintf(atmp, sizeof(atmp), "STACK-%s-%s-%d", context, exten, priority);
01695             snprintf(atmp2, sizeof(atmp2), "%s(\"%s\", \"%s\") %s",
01696                app->name, c->name, passdata, "in new stack");
01697             pbx_builtin_setvar_helper(c, atmp, atmp2);
01698          }
01699          if (option_verbose > 2) {
01700             char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
01701             ast_verbose( VERBOSE_PREFIX_3 "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
01702                exten, context, priority,
01703                term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
01704                term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
01705                term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
01706                "in new stack");
01707          }
01708          manager_event(EVENT_FLAG_CALL, "Newexten",
01709                "Channel: %s\r\n"
01710                "Context: %s\r\n"
01711                "Extension: %s\r\n"
01712                "Priority: %d\r\n"
01713                "Application: %s\r\n"
01714                "AppData: %s\r\n"
01715                "Uniqueid: %s\r\n",
01716                c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
01717          return pbx_exec(c, app, passdata);  /* 0 on success, -1 on failure */
01718       }
01719    } else if (q.swo) {  /* not found here, but in another switch */
01720       ast_mutex_unlock(&conlock);
01721       if (matching_action)
01722          return -1;
01723       else {
01724          if (!q.swo->exec) {
01725             ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
01726             res = -1;
01727          }
01728          return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
01729       }
01730    } else { /* not found anywhere, see what happened */
01731       ast_mutex_unlock(&conlock);
01732       switch (q.status) {
01733       case STATUS_NO_CONTEXT:
01734          if (!matching_action)
01735             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
01736          break;
01737       case STATUS_NO_EXTENSION:
01738          if (!matching_action)
01739             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
01740          break;
01741       case STATUS_NO_PRIORITY:
01742          if (!matching_action)
01743             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
01744          break;
01745       case STATUS_NO_LABEL:
01746          if (context)
01747             ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
01748          break;
01749       default:
01750          if (option_debug)
01751             ast_log(LOG_DEBUG, "Shouldn't happen!\n");
01752       }
01753 
01754       return (matching_action) ? 0 : -1;
01755    }
01756 }
01757 
01758 /*! \brief  ast_hint_extension: Find hint for given extension in context */
01759 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
01760 {
01761    struct ast_exten *e;
01762    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
01763 
01764    ast_mutex_lock(&conlock);
01765    e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
01766    ast_mutex_unlock(&conlock);
01767 
01768    return e;
01769 }
01770 
01771 /*! \brief  ast_extensions_state2: Check state of extension by using hints */
01772 static int ast_extension_state2(struct ast_exten *e)
01773 {
01774    char hint[AST_MAX_EXTENSION];
01775    char *cur, *rest;
01776    int allunavailable = 1, allbusy = 1, allfree = 1, allonhold = 1;
01777    int busy = 0, inuse = 0, ring = 0;
01778 
01779    if (!e)
01780       return -1;
01781 
01782    ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
01783 
01784    rest = hint;   /* One or more devices separated with a & character */
01785    while ( (cur = strsep(&rest, "&")) ) {
01786       int res = ast_device_state(cur);
01787       switch (res) {
01788       case AST_DEVICE_NOT_INUSE:
01789          allunavailable = 0;
01790          allbusy = 0;
01791          allonhold = 0;
01792          break;
01793       case AST_DEVICE_INUSE:
01794          inuse = 1;
01795          allunavailable = 0;
01796          allfree = 0;
01797          allonhold = 0;
01798          break;
01799       case AST_DEVICE_RINGING:
01800          ring = 1;
01801          allunavailable = 0;
01802          allfree = 0;
01803          allonhold = 0;
01804          break;
01805       case AST_DEVICE_RINGINUSE:
01806          inuse = 1;
01807          ring = 1;
01808          allunavailable = 0;
01809          allfree = 0;
01810          allonhold = 0;
01811          break;
01812       case AST_DEVICE_ONHOLD:
01813          allunavailable = 0;
01814          allfree = 0;
01815          break;
01816       case AST_DEVICE_BUSY:
01817          allunavailable = 0;
01818          allfree = 0;
01819          allonhold = 0;
01820          busy = 1;
01821          break;
01822       case AST_DEVICE_UNAVAILABLE:
01823       case AST_DEVICE_INVALID:
01824          allbusy = 0;
01825          allfree = 0;
01826          allonhold = 0;
01827          break;
01828       default:
01829          allunavailable = 0;
01830          allbusy = 0;
01831          allfree = 0;
01832          allonhold = 0;
01833       }
01834    }
01835 
01836    if (!inuse && ring)
01837       return AST_EXTENSION_RINGING;
01838    if (inuse && ring)
01839       return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
01840    if (inuse)
01841       return AST_EXTENSION_INUSE;
01842    if (allfree)
01843       return AST_EXTENSION_NOT_INUSE;
01844    if (allonhold)
01845       return AST_EXTENSION_ONHOLD;
01846    if (allbusy)
01847       return AST_EXTENSION_BUSY;
01848    if (allunavailable)
01849       return AST_EXTENSION_UNAVAILABLE;
01850    if (busy)
01851       return AST_EXTENSION_INUSE;
01852 
01853    return AST_EXTENSION_NOT_INUSE;
01854 }
01855 
01856 /*! \brief  ast_extension_state2str: Return extension_state as string */
01857 const char *ast_extension_state2str(int extension_state)
01858 {
01859    int i;
01860 
01861    for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
01862       if (extension_states[i].extension_state == extension_state)
01863          return extension_states[i].text;
01864    }
01865    return "Unknown";
01866 }
01867 
01868 /*! \brief  ast_extension_state: Check extension state for an extension by using hint */
01869 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
01870 {
01871    struct ast_exten *e;
01872 
01873    e = ast_hint_extension(c, context, exten);   /* Do we have a hint for this extension ? */
01874    if (!e)
01875       return -1;           /* No hint, return -1 */
01876 
01877    return ast_extension_state2(e);        /* Check all devices in the hint */
01878 }
01879 
01880 void ast_hint_state_changed(const char *device)
01881 {
01882    struct ast_hint *hint;
01883 
01884    AST_RWLIST_RDLOCK(&hints);
01885 
01886    AST_RWLIST_TRAVERSE(&hints, hint, list) {
01887       struct ast_state_cb *cblist;
01888       char buf[AST_MAX_EXTENSION];
01889       char *parse = buf;
01890       char *cur;
01891       int state;
01892 
01893       ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
01894       while ( (cur = strsep(&parse, "&")) ) {
01895          if (!strcasecmp(cur, device))
01896             break;
01897       }
01898       if (!cur)
01899          continue;
01900 
01901       /* Get device state for this hint */
01902       state = ast_extension_state2(hint->exten);
01903 
01904       if ((state == -1) || (state == hint->laststate))
01905          continue;
01906 
01907       /* Device state changed since last check - notify the watchers */
01908 
01909       /* For general callbacks */
01910       for (cblist = statecbs; cblist; cblist = cblist->next)
01911          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
01912 
01913       /* For extension callbacks */
01914       for (cblist = hint->callbacks; cblist; cblist = cblist->next)
01915          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
01916 
01917       hint->laststate = state;   /* record we saw the change */
01918    }
01919 
01920    AST_RWLIST_UNLOCK(&hints);
01921 }
01922 
01923 /*! \brief  ast_extension_state_add: Add watcher for extension states */
01924 int ast_extension_state_add(const char *context, const char *exten,
01925              ast_state_cb_type callback, void *data)
01926 {
01927    struct ast_hint *hint;
01928    struct ast_state_cb *cblist;
01929    struct ast_exten *e;
01930 
01931    /* If there's no context and extension:  add callback to statecbs list */
01932    if (!context && !exten) {
01933       AST_RWLIST_WRLOCK(&hints);
01934 
01935       for (cblist = statecbs; cblist; cblist = cblist->next) {
01936          if (cblist->callback == callback) {
01937             cblist->data = data;
01938             AST_RWLIST_UNLOCK(&hints);
01939             return 0;
01940          }
01941       }
01942 
01943       /* Now insert the callback */
01944       if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
01945          AST_RWLIST_UNLOCK(&hints);
01946          return -1;
01947       }
01948       cblist->id = 0;
01949       cblist->callback = callback;
01950       cblist->data = data;
01951 
01952       cblist->next = statecbs;
01953       statecbs = cblist;
01954 
01955       AST_RWLIST_UNLOCK(&hints);
01956       return 0;
01957    }
01958 
01959    if (!context || !exten)
01960       return -1;
01961 
01962    /* This callback type is for only one hint, so get the hint */
01963    e = ast_hint_extension(NULL, context, exten);
01964    if (!e) {
01965       return -1;
01966    }
01967 
01968    /* Find the hint in the list of hints */
01969    AST_RWLIST_WRLOCK(&hints);
01970 
01971    AST_RWLIST_TRAVERSE(&hints, hint, list) {
01972       if (hint->exten == e)
01973          break;
01974    }
01975 
01976    if (!hint) {
01977       /* We have no hint, sorry */
01978       AST_RWLIST_UNLOCK(&hints);
01979       return -1;
01980    }
01981 
01982    /* Now insert the callback in the callback list  */
01983    if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
01984       AST_RWLIST_UNLOCK(&hints);
01985       return -1;
01986    }
01987    cblist->id = stateid++;    /* Unique ID for this callback */
01988    cblist->callback = callback;  /* Pointer to callback routine */
01989    cblist->data = data;    /* Data for the callback */
01990 
01991    cblist->next = hint->callbacks;
01992    hint->callbacks = cblist;
01993 
01994    AST_RWLIST_UNLOCK(&hints);
01995    return cblist->id;
01996 }
01997 
01998 /*! \brief  ast_extension_state_del: Remove a watcher from the callback list */
01999 int ast_extension_state_del(int id, ast_state_cb_type callback)
02000 {
02001    struct ast_state_cb **p_cur = NULL; /* address of pointer to us */
02002    int ret = -1;
02003 
02004    if (!id && !callback)
02005       return -1;
02006 
02007    AST_RWLIST_WRLOCK(&hints);
02008 
02009    if (!id) {  /* id == 0 is a callback without extension */
02010       for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
02011          if ((*p_cur)->callback == callback)
02012             break;
02013       }
02014    } else { /* callback with extension, find the callback based on ID */
02015       struct ast_hint *hint;
02016       AST_RWLIST_TRAVERSE(&hints, hint, list) {
02017          for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
02018             if ((*p_cur)->id == id)
02019                break;
02020          }
02021          if (*p_cur) /* found in the inner loop */
02022             break;
02023       }
02024    }
02025    if (p_cur && *p_cur) {
02026       struct ast_state_cb *cur = *p_cur;
02027       *p_cur = cur->next;
02028       free(cur);
02029       ret = 0;
02030    }
02031    AST_RWLIST_UNLOCK(&hints);
02032    return ret;
02033 }
02034 
02035 /*! \brief  ast_add_hint: Add hint to hint list, check initial extension state */
02036 static int ast_add_hint(struct ast_exten *e)
02037 {
02038    struct ast_hint *hint;
02039 
02040    if (!e)
02041       return -1;
02042 
02043    AST_RWLIST_WRLOCK(&hints);
02044 
02045    /* Search if hint exists, do nothing */
02046    AST_RWLIST_TRAVERSE(&hints, hint, list) {
02047       if (hint->exten == e) {
02048          AST_RWLIST_UNLOCK(&hints);
02049          if (option_debug > 1)
02050             ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
02051          return -1;
02052       }
02053    }
02054 
02055    if (option_debug > 1)
02056       ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
02057 
02058    if (!(hint = ast_calloc(1, sizeof(*hint)))) {
02059       AST_RWLIST_UNLOCK(&hints);
02060       return -1;
02061    }
02062    /* Initialize and insert new item at the top */
02063    hint->exten = e;
02064    hint->laststate = ast_extension_state2(e);
02065    AST_RWLIST_INSERT_HEAD(&hints, hint, list);
02066 
02067    AST_RWLIST_UNLOCK(&hints);
02068    return 0;
02069 }
02070 
02071 /*! \brief  ast_change_hint: Change hint for an extension */
02072 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
02073 {
02074    struct ast_hint *hint;
02075    int res = -1;
02076 
02077    AST_RWLIST_WRLOCK(&hints);
02078    AST_RWLIST_TRAVERSE(&hints, hint, list) {
02079       if (hint->exten == oe) {
02080             hint->exten = ne;
02081          res = 0;
02082          break;
02083       }
02084    }
02085    AST_RWLIST_UNLOCK(&hints);
02086 
02087    return res;
02088 }
02089 
02090 /*! \brief  ast_remove_hint: Remove hint from extension */
02091 static int ast_remove_hint(struct ast_exten *e)
02092 {
02093    /* Cleanup the Notifys if hint is removed */
02094    struct ast_hint *hint;
02095    struct ast_state_cb *cblist, *cbprev;
02096    int res = -1;
02097 
02098    if (!e)
02099       return -1;
02100 
02101    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
02102       if (hint->exten == e) {
02103          cbprev = NULL;
02104          cblist = hint->callbacks;
02105          while (cblist) {
02106             /* Notify with -1 and remove all callbacks */
02107             cbprev = cblist;
02108             cblist = cblist->next;
02109             cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
02110             free(cbprev);
02111             }
02112             hint->callbacks = NULL;
02113          AST_RWLIST_REMOVE_CURRENT(&hints, list);
02114             free(hint);
02115             res = 0;
02116          break;
02117       }
02118    }
02119    AST_RWLIST_TRAVERSE_SAFE_END
02120 
02121    return res;
02122 }
02123 
02124 
02125 /*! \brief  ast_get_hint: Get hint for channel */
02126 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
02127 {
02128    struct ast_exten *e = ast_hint_extension(c, context, exten);
02129 
02130    if (e) {
02131       if (hint)
02132          ast_copy_string(hint, ast_get_extension_app(e), hintsize);
02133       if (name) {
02134          const char *tmp = ast_get_extension_app_data(e);
02135          if (tmp)
02136             ast_copy_string(name, tmp, namesize);
02137       }
02138       return -1;
02139    }
02140    return 0;
02141 }
02142 
02143 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02144 {
02145    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH);
02146 }
02147 
02148 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
02149 {
02150    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL);
02151 }
02152 
02153 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
02154 {
02155    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
02156 }
02157 
02158 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02159 {
02160    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH);
02161 }
02162 
02163 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02164 {
02165    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE);
02166 }
02167 
02168 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02169 {
02170    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN);
02171 }
02172 
02173 /* helper function to set extension and priority */
02174 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
02175 {
02176    ast_copy_string(c->exten, exten, sizeof(c->exten));
02177    c->priority = pri;
02178 }
02179 
02180 /*!
02181  * \brief collect digits from the channel into the buffer,
02182  * return -1 on error, 0 on timeout or done.
02183  */
02184 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
02185 {
02186    int digit;
02187 
02188    buf[pos] = '\0';  /* make sure it is properly terminated */
02189    while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
02190       /* As long as we're willing to wait, and as long as it's not defined,
02191          keep reading digits until we can't possibly get a right answer anymore.  */
02192       digit = ast_waitfordigit(c, waittime * 1000);
02193       if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02194          c->_softhangup = 0;
02195       } else {
02196          if (!digit) /* No entry */
02197             break;
02198          if (digit < 0) /* Error, maybe a  hangup */
02199             return -1;
02200          if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
02201             buf[pos++] = digit;
02202             buf[pos] = '\0';
02203          }
02204          waittime = c->pbx->dtimeout;
02205       }
02206    }
02207    return 0;
02208 }
02209 
02210 static int __ast_pbx_run(struct ast_channel *c)
02211 {
02212    int found = 0; /* set if we find at least one match */
02213    int res = 0;
02214    int autoloopflag;
02215    int error = 0;    /* set an error conditions */
02216 
02217    /* A little initial setup here */
02218    if (c->pbx) {
02219       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
02220       /* XXX and now what ? */
02221       free(c->pbx);
02222    }
02223    if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
02224       return -1;
02225    if (c->amaflags) {
02226       if (!c->cdr) {
02227          c->cdr = ast_cdr_alloc();
02228          if (!c->cdr) {
02229             ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
02230             free(c->pbx);
02231             return -1;
02232          }
02233          ast_cdr_init(c->cdr, c);
02234       }
02235    }
02236    /* Set reasonable defaults */
02237    c->pbx->rtimeout = 10;
02238    c->pbx->dtimeout = 5;
02239 
02240    autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);   /* save value to restore at the end */
02241    ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
02242 
02243    /* Start by trying whatever the channel is set to */
02244    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02245       /* If not successful fall back to 's' */
02246       if (option_verbose > 1)
02247          ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d failed so falling back to exten 's'\n", c->name, c->context, c->exten, c->priority);
02248       /* XXX the original code used the existing priority in the call to
02249        * ast_exists_extension(), and reset it to 1 afterwards.
02250        * I believe the correct thing is to set it to 1 immediately.
02251        */
02252       set_ext_pri(c, "s", 1);
02253       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02254          /* JK02: And finally back to default if everything else failed */
02255          if (option_verbose > 1)
02256             ast_verbose( VERBOSE_PREFIX_2 "Starting %s at %s,%s,%d still failed so falling back to context 'default'\n", c->name, c->context, c->exten, c->priority);
02257          ast_copy_string(c->context, "default", sizeof(c->context));
02258       }
02259    }
02260    if (c->cdr && ast_tvzero(c->cdr->start))
02261       ast_cdr_start(c->cdr);
02262    for (;;) {
02263       char dst_exten[256]; /* buffer to accumulate digits */
02264       int pos = 0;      /* XXX should check bounds */
02265       int digit = 0;
02266 
02267       /* loop on priorities in this context/exten */
02268       while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02269          found = 1;
02270          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02271             /* Something bad happened, or a hangup has been requested. */
02272             if (strchr("0123456789ABCDEF*#", res)) {
02273                if (option_debug)
02274                   ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
02275                pos = 0;
02276                dst_exten[pos++] = digit = res;
02277                dst_exten[pos] = '\0';
02278                break;
02279             }
02280             if (res == AST_PBX_KEEPALIVE) {
02281                if (option_debug)
02282                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
02283                if (option_verbose > 1)
02284                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
02285                error = 1;
02286                break;
02287             }
02288             if (option_debug)
02289                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02290             if (option_verbose > 1)
02291                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02292             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02293                c->_softhangup =0;
02294             } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
02295                /* atimeout, nothing bad */
02296             } else {
02297                if (c->cdr)
02298                   ast_cdr_update(c);
02299                error = 1;
02300                break;
02301             }
02302          }
02303          if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
02304             set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
02305             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
02306             c->whentohangup = 0;
02307             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
02308          } else if (c->_softhangup) {
02309             if (option_debug)
02310                ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
02311                   c->exten, c->priority);
02312             error = 1;
02313             break;
02314          }
02315          c->priority++;
02316       } /* end while  - from here on we can use 'break' to go out */
02317       if (error)
02318          break;
02319 
02320       /* XXX we get here on non-existing extension or a keypress or hangup ? */
02321 
02322       if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
02323          /* If there is no match at priority 1, it is not a valid extension anymore.
02324           * Try to continue at "i", 1 or exit if the latter does not exist.
02325           */
02326          if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
02327             if (option_verbose > 2)
02328                ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
02329             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
02330             set_ext_pri(c, "i", 1);
02331          } else {
02332             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
02333                c->name, c->exten, c->context);
02334             error = 1; /* we know what to do with it */
02335             break;
02336          }
02337       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
02338          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
02339          c->_softhangup = 0;
02340       } else { /* keypress received, get more digits for a full extension */
02341          int waittime = 0;
02342          if (digit)
02343             waittime = c->pbx->dtimeout;
02344          else if (!autofallthrough)
02345             waittime = c->pbx->rtimeout;
02346          if (!waittime) {
02347             const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
02348             if (!status)
02349                status = "UNKNOWN";
02350             if (option_verbose > 2)
02351                ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
02352             if (!strcasecmp(status, "CONGESTION"))
02353                res = pbx_builtin_congestion(c, "10");
02354             else if (!strcasecmp(status, "CHANUNAVAIL"))
02355                res = pbx_builtin_congestion(c, "10");
02356             else if (!strcasecmp(status, "BUSY"))
02357                res = pbx_builtin_busy(c, "10");
02358             error = 1; /* XXX disable message */
02359             break;   /* exit from the 'for' loop */
02360          }
02361 
02362          if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
02363             break;
02364          if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
02365             set_ext_pri(c, dst_exten, 1);
02366          else {
02367             /* No such extension */
02368             if (!ast_strlen_zero(dst_exten)) {
02369                /* An invalid extension */
02370                if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
02371                   if (option_verbose > 2)
02372                      ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
02373                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
02374                   set_ext_pri(c, "i", 1);
02375                } else {
02376                   ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
02377                   found = 1; /* XXX disable message */
02378                   break;
02379                }
02380             } else {
02381                /* A simple timeout */
02382                if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
02383                   if (option_verbose > 2)
02384                      ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
02385                   set_ext_pri(c, "t", 1);
02386                } else {
02387                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
02388                   found = 1; /* XXX disable message */
02389                   break;
02390                }
02391             }
02392          }
02393          if (c->cdr) {
02394             if (option_verbose > 2)
02395                ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
02396             ast_cdr_update(c);
02397          }
02398       }
02399    }
02400    if (!found && !error)
02401       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
02402    if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
02403       if (c->cdr && ast_opt_end_cdr_before_h_exten)
02404          ast_cdr_end(c->cdr);
02405       set_ext_pri(c, "h", 1);
02406       while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02407          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02408             /* Something bad happened, or a hangup has been requested. */
02409             if (option_debug)
02410                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02411             if (option_verbose > 1)
02412                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02413             break;
02414          }
02415          c->priority++;
02416       }
02417    }
02418    ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02419 
02420    pbx_destroy(c->pbx);
02421    c->pbx = NULL;
02422    if (res != AST_PBX_KEEPALIVE)
02423       ast_hangup(c);
02424    return 0;
02425 }
02426 
02427 /* Returns 0 on success, non-zero if call limit was reached */
02428 static int increase_call_count(const struct ast_channel *c)
02429 {
02430    int failed = 0;
02431    double curloadavg;
02432    ast_mutex_lock(&maxcalllock);
02433    if (option_maxcalls) {
02434       if (countcalls >= option_maxcalls) {
02435          ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
02436          failed = -1;
02437       }
02438    }
02439    if (option_maxload) {
02440       getloadavg(&curloadavg, 1);
02441       if (curloadavg >= option_maxload) {
02442          ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
02443          failed = -1;
02444       }
02445    }
02446    if (!failed)
02447       countcalls++;
02448    ast_mutex_unlock(&maxcalllock);
02449 
02450    return failed;
02451 }
02452 
02453 static void decrease_call_count(void)
02454 {
02455    ast_mutex_lock(&maxcalllock);
02456    if (countcalls > 0)
02457       countcalls--;
02458    ast_mutex_unlock(&maxcalllock);
02459 }
02460 
02461 static void destroy_exten(struct ast_exten *e)
02462 {
02463    if (e->priority == PRIORITY_HINT)
02464       ast_remove_hint(e);
02465 
02466    if (e->datad)
02467       e->datad(e->data);
02468    free(e);
02469 }
02470 
02471 static void *pbx_thread(void *data)
02472 {
02473    /* Oh joyeous kernel, we're a new thread, with nothing to do but
02474       answer this channel and get it going.
02475    */
02476    /* NOTE:
02477       The launcher of this function _MUST_ increment 'countcalls'
02478       before invoking the function; it will be decremented when the
02479       PBX has finished running on the channel
02480     */
02481    struct ast_channel *c = data;
02482 
02483    __ast_pbx_run(c);
02484    decrease_call_count();
02485 
02486    pthread_exit(NULL);
02487 
02488    return NULL;
02489 }
02490 
02491 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
02492 {
02493    pthread_t t;
02494    pthread_attr_t attr;
02495 
02496    if (!c) {
02497       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
02498       return AST_PBX_FAILED;
02499    }
02500 
02501    if (increase_call_count(c))
02502       return AST_PBX_CALL_LIMIT;
02503 
02504    /* Start a new thread, and get something handling this channel. */
02505    pthread_attr_init(&attr);
02506    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02507    if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
02508       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
02509       pthread_attr_destroy(&attr);
02510       return AST_PBX_FAILED;
02511    }
02512    pthread_attr_destroy(&attr);
02513 
02514    return AST_PBX_SUCCESS;
02515 }
02516 
02517 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
02518 {
02519    enum ast_pbx_result res = AST_PBX_SUCCESS;
02520 
02521    if (increase_call_count(c))
02522       return AST_PBX_CALL_LIMIT;
02523 
02524    res = __ast_pbx_run(c);
02525    decrease_call_count();
02526 
02527    return res;
02528 }
02529 
02530 int ast_active_calls(void)
02531 {
02532    return countcalls;
02533 }
02534 
02535 int pbx_set_autofallthrough(int newval)
02536 {
02537    int oldval = autofallthrough;
02538    autofallthrough = newval;
02539    return oldval;
02540 }
02541 
02542 /* lookup for a context with a given name,
02543  * return with conlock held if found, NULL if not found
02544  */
02545 static struct ast_context *find_context_locked(const char *context)
02546 {
02547    struct ast_context *c = NULL;
02548 
02549    ast_lock_contexts();
02550    while ( (c = ast_walk_contexts(c)) ) {
02551       if (!strcmp(ast_get_context_name(c), context))
02552          return c;
02553    }
02554    ast_unlock_contexts();
02555 
02556    return NULL;
02557 }
02558 
02559 /*
02560  * This function locks contexts list by &conlist, search for the right context
02561  * structure, leave context list locked and call ast_context_remove_include2
02562  * which removes include, unlock contexts list and return ...
02563  */
02564 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
02565 {
02566    int ret = -1;
02567    struct ast_context *c = find_context_locked(context);
02568 
02569    if (c) {
02570       /* found, remove include from this context ... */
02571       ret = ast_context_remove_include2(c, include, registrar);
02572       ast_unlock_contexts();
02573    }
02574    return ret;
02575 }
02576 
02577 /*
02578  * When we call this function, &conlock lock must be locked, because when
02579  * we giving *con argument, some process can remove/change this context
02580  * and after that there can be segfault.
02581  *
02582  * This function locks given context, removes include, unlock context and
02583  * return.
02584  */
02585 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
02586 {
02587    struct ast_include *i, *pi = NULL;
02588    int ret = -1;
02589 
02590    ast_mutex_lock(&con->lock);
02591 
02592    /* find our include */
02593    for (i = con->includes; i; pi = i, i = i->next) {
02594       if (!strcmp(i->name, include) &&
02595             (!registrar || !strcmp(i->registrar, registrar))) {
02596          /* remove from list */
02597          if (pi)
02598             pi->next = i->next;
02599          else
02600             con->includes = i->next;
02601          /* free include and return */
02602          free(i);
02603          ret = 0;
02604          break;
02605       }
02606    }
02607 
02608    ast_mutex_unlock(&con->lock);
02609    return ret;
02610 }
02611 
02612 /*!
02613  * \note This function locks contexts list by &conlist, search for the rigt context
02614  * structure, leave context list locked and call ast_context_remove_switch2
02615  * which removes switch, unlock contexts list and return ...
02616  */
02617 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
02618 {
02619    int ret = -1; /* default error return */
02620    struct ast_context *c = find_context_locked(context);
02621 
02622    if (c) {
02623       /* remove switch from this context ... */
02624       ret = ast_context_remove_switch2(c, sw, data, registrar);
02625       ast_unlock_contexts();
02626    }
02627    return ret;
02628 }
02629 
02630 /*!
02631  * \brief This function locks given context, removes switch, unlock context and
02632  * return.
02633  * \note When we call this function, &conlock lock must be locked, because when
02634  * we giving *con argument, some process can remove/change this context
02635  * and after that there can be segfault.
02636  *
02637  */
02638 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
02639 {
02640    struct ast_sw *i;
02641    int ret = -1;
02642 
02643    ast_mutex_lock(&con->lock);
02644 
02645    /* walk switches */
02646    AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
02647       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
02648          (!registrar || !strcmp(i->registrar, registrar))) {
02649          /* found, remove from list */
02650          AST_LIST_REMOVE_CURRENT(&con->alts, list);
02651          free(i); /* free switch and return */
02652          ret = 0;
02653          break;
02654       }
02655    }
02656    AST_LIST_TRAVERSE_SAFE_END
02657 
02658    ast_mutex_unlock(&con->lock);
02659 
02660    return ret;
02661 }
02662 
02663 /*
02664  * \note This functions lock contexts list, search for the right context,
02665  * call ast_context_remove_extension2, unlock contexts list and return.
02666  * In this function we are using
02667  */
02668 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
02669 {
02670    int ret = -1; /* default error return */
02671    struct ast_context *c = find_context_locked(context);
02672 
02673    if (c) { /* ... remove extension ... */
02674       ret = ast_context_remove_extension2(c, extension, priority, registrar);
02675       ast_unlock_contexts();
02676    }
02677    return ret;
02678 }
02679 
02680 /*!
02681  * \brief This functionc locks given context, search for the right extension and
02682  * fires out all peer in this extensions with given priority. If priority
02683  * is set to 0, all peers are removed. After that, unlock context and
02684  * return.
02685  * \note When do you want to call this function, make sure that &conlock is locked,
02686  * because some process can handle with your *con context before you lock
02687  * it.
02688  *
02689  */
02690 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
02691 {
02692    struct ast_exten *exten, *prev_exten = NULL;
02693    struct ast_exten *peer;
02694 
02695    ast_mutex_lock(&con->lock);
02696 
02697    /* scan the extension list to find matching extension-registrar */
02698    for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
02699       if (!strcmp(exten->exten, extension) &&
02700          (!registrar || !strcmp(exten->registrar, registrar)))
02701          break;
02702    }
02703    if (!exten) {
02704       /* we can't find right extension */
02705       ast_mutex_unlock(&con->lock);
02706       return -1;
02707    }
02708 
02709    /* should we free all peers in this extension? (priority == 0)? */
02710    if (priority == 0) {
02711       /* remove this extension from context list */
02712       if (prev_exten)
02713          prev_exten->next = exten->next;
02714       else
02715          con->root = exten->next;
02716 
02717       /* fire out all peers */
02718       while ( (peer = exten) ) {
02719          exten = peer->peer; /* prepare for next entry */
02720          destroy_exten(peer);
02721       }
02722    } else {
02723       /* scan the priority list to remove extension with exten->priority == priority */
02724       struct ast_exten *previous_peer = NULL;
02725 
02726       for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
02727          if (peer->priority == priority &&
02728                (!registrar || !strcmp(peer->registrar, registrar) ))
02729             break; /* found our priority */
02730       }
02731       if (!peer) { /* not found */
02732          ast_mutex_unlock(&con->lock);
02733          return -1;
02734       }
02735       /* we are first priority extension? */
02736       if (!previous_peer) {
02737          /*
02738           * We are first in the priority chain, so must update the extension chain.
02739           * The next node is either the next priority or the next extension
02740           */
02741          struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
02742 
02743          if (!prev_exten)  /* change the root... */
02744             con->root = next_node;
02745          else
02746             prev_exten->next = next_node; /* unlink */
02747          if (peer->peer)   /* XXX update the new head of the pri list */
02748             peer->peer->next = peer->next;
02749       } else { /* easy, we are not first priority in extension */
02750          previous_peer->peer = peer->peer;
02751       }
02752 
02753       /* now, free whole priority extension */
02754       destroy_exten(peer);
02755       /* XXX should we return -1 ? */
02756    }
02757    ast_mutex_unlock(&con->lock);
02758    return 0;
02759 }
02760 
02761 
02762 /*!
02763  * \note This function locks contexts list by &conlist, searches for the right context
02764  * structure, and locks the macrolock mutex in that context.
02765  * macrolock is used to limit a macro to be executed by one call at a time.
02766  */
02767 int ast_context_lockmacro(const char *context)
02768 {
02769    struct ast_context *c = NULL;
02770    int ret = -1;
02771 
02772    ast_lock_contexts();
02773 
02774    while ((c = ast_walk_contexts(c))) {
02775       if (!strcmp(ast_get_context_name(c), context)) {
02776          ret = 0;
02777          break;
02778       }
02779    }
02780 
02781    ast_unlock_contexts();
02782 
02783    /* if we found context, lock macrolock */
02784    if (ret == 0) 
02785       ret = ast_mutex_lock(&c->macrolock);
02786 
02787    return ret;
02788 }
02789 
02790 /*!
02791  * \note This function locks contexts list by &conlist, searches for the right context
02792  * structure, and unlocks the macrolock mutex in that context.
02793  * macrolock is used to limit a macro to be executed by one call at a time.
02794  */
02795 int ast_context_unlockmacro(const char *context)
02796 {
02797    struct ast_context *c = NULL;
02798    int ret = -1;
02799 
02800    ast_lock_contexts();
02801 
02802    while ((c = ast_walk_contexts(c))) {
02803       if (!strcmp(ast_get_context_name(c), context)) {
02804          ret = 0;
02805          break;
02806       }
02807    }
02808 
02809    ast_unlock_contexts();
02810 
02811    /* if we found context, unlock macrolock */
02812    if (ret == 0) 
02813       ret = ast_mutex_unlock(&c->macrolock);
02814 
02815    return ret;
02816 }
02817 
02818 /*! \brief Dynamically register a new dial plan application */
02819 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
02820 {
02821    struct ast_app *tmp, *cur = NULL;
02822    char tmps[80];
02823    int length;
02824 
02825    AST_RWLIST_WRLOCK(&apps);
02826    AST_RWLIST_TRAVERSE(&apps, tmp, list) {
02827       if (!strcasecmp(app, tmp->name)) {
02828          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
02829          AST_RWLIST_UNLOCK(&apps);
02830          return -1;
02831       }
02832    }
02833 
02834    length = sizeof(*tmp) + strlen(app) + 1;
02835 
02836    if (!(tmp = ast_calloc(1, length))) {
02837       AST_RWLIST_UNLOCK(&apps);
02838       return -1;
02839    }
02840 
02841    strcpy(tmp->name, app);
02842    tmp->execute = execute;
02843    tmp->synopsis = synopsis;
02844    tmp->description = description;
02845 
02846    /* Store in alphabetical order */
02847    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
02848       if (strcasecmp(tmp->name, cur->name) < 0) {
02849          AST_RWLIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
02850          break;
02851       }
02852    }
02853    AST_RWLIST_TRAVERSE_SAFE_END
02854    if (!cur)
02855       AST_RWLIST_INSERT_TAIL(&apps, tmp, list);
02856 
02857    if (option_verbose > 1)
02858       ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02859 
02860    AST_RWLIST_UNLOCK(&apps);
02861 
02862    return 0;
02863 }
02864 
02865 /*
02866  * Append to the list. We don't have a tail pointer because we need
02867  * to scan the list anyways to check for duplicates during insertion.
02868  */
02869 int ast_register_switch(struct ast_switch *sw)
02870 {
02871    struct ast_switch *tmp;
02872 
02873    AST_RWLIST_WRLOCK(&switches);
02874    AST_RWLIST_TRAVERSE(&switches, tmp, list) {
02875       if (!strcasecmp(tmp->name, sw->name)) {
02876          AST_RWLIST_UNLOCK(&switches);
02877          ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
02878          return -1;
02879       }
02880    }
02881    AST_RWLIST_INSERT_TAIL(&switches, sw, list);
02882    AST_RWLIST_UNLOCK(&switches);
02883 
02884    return 0;
02885 }
02886 
02887 void ast_unregister_switch(struct ast_switch *sw)
02888 {
02889    AST_RWLIST_WRLOCK(&switches);
02890    AST_RWLIST_REMOVE(&switches, sw, list);
02891    AST_RWLIST_UNLOCK(&switches);
02892 }
02893 
02894 /*
02895  * Help for CLI commands ...
02896  */
02897 static char show_applications_help[] =
02898 "Usage: core show applications [{like|describing} <text>]\n"
02899 "       List applications which are currently available.\n"
02900 "       If 'like', <text> will be a substring of the app name\n"
02901 "       If 'describing', <text> will be a substring of the description\n";
02902 
02903 static char show_functions_help[] =
02904 "Usage: core show functions [like <text>]\n"
02905 "       List builtin functions, optionally only those matching a given string\n";
02906 
02907 static char show_switches_help[] =
02908 "Usage: core show switches\n"
02909 "       List registered switches\n";
02910 
02911 static char show_hints_help[] =
02912 "Usage: core show hints\n"
02913 "       List registered hints\n";
02914 
02915 static char show_globals_help[] =
02916 "Usage: core show globals\n"
02917 "       List current global dialplan variables and their values\n";
02918 
02919 static char show_application_help[] =
02920 "Usage: core show application <application> [<application> [<application> [...]]]\n"
02921 "       Describes a particular application.\n";
02922 
02923 static char show_function_help[] =
02924 "Usage: core show function <function>\n"
02925 "       Describe a particular dialplan function.\n";
02926 
02927 static char show_dialplan_help[] =
02928 "Usage: core show dialplan [exten@][context]\n"
02929 "       Show dialplan\n";
02930 
02931 static char set_global_help[] =
02932 "Usage: core set global <name> <value>\n"
02933 "       Set global dialplan variable <name> to <value>\n";
02934 
02935 
02936 /*
02937  * \brief 'show application' CLI command implementation functions ...
02938  */
02939 
02940 /*
02941  * There is a possibility to show informations about more than one
02942  * application at one time. You can type 'show application Dial Echo' and
02943  * you will see informations about these two applications ...
02944  */
02945 static char *complete_show_application(const char *line, const char *word, int pos, int state)
02946 {
02947    struct ast_app *a;
02948    char *ret = NULL;
02949    int which = 0;
02950    int wordlen = strlen(word);
02951 
02952    /* return the n-th [partial] matching entry */
02953    AST_RWLIST_RDLOCK(&apps);
02954    AST_RWLIST_TRAVERSE(&apps, a, list) {
02955       if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
02956          ret = strdup(a->name);
02957          break;
02958       }
02959    }
02960    AST_RWLIST_UNLOCK(&apps);
02961 
02962    return ret;
02963 }
02964 
02965 static int handle_show_application(int fd, int argc, char *argv[])
02966 {
02967    struct ast_app *a;
02968    int app, no_registered_app = 1;
02969 
02970    if (argc < 4)
02971       return RESULT_SHOWUSAGE;
02972 
02973    /* ... go through all applications ... */
02974    AST_RWLIST_RDLOCK(&apps);
02975    AST_RWLIST_TRAVERSE(&apps, a, list) {
02976       /* ... compare this application name with all arguments given
02977        * to 'show application' command ... */
02978       for (app = 3; app < argc; app++) {
02979          if (!strcasecmp(a->name, argv[app])) {
02980             /* Maximum number of characters added by terminal coloring is 22 */
02981             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
02982             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
02983             int synopsis_size, description_size;
02984 
02985             no_registered_app = 0;
02986 
02987             if (a->synopsis)
02988                synopsis_size = strlen(a->synopsis) + 23;
02989             else
02990                synopsis_size = strlen("Not available") + 23;
02991             synopsis = alloca(synopsis_size);
02992 
02993             if (a->description)
02994                description_size = strlen(a->description) + 23;
02995             else
02996                description_size = strlen("Not available") + 23;
02997             description = alloca(description_size);
02998 
02999             if (synopsis && description) {
03000                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
03001                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
03002                term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03003                term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03004                term_color(synopsis,
03005                            a->synopsis ? a->synopsis : "Not available",
03006                            COLOR_CYAN, 0, synopsis_size);
03007                term_color(description,
03008                            a->description ? a->description : "Not available",
03009                            COLOR_CYAN, 0, description_size);
03010 
03011                ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
03012             } else {
03013                /* ... one of our applications, show info ...*/
03014                ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
03015                   "[Synopsis]\n  %s\n\n"
03016                   "[Description]\n%s\n",
03017                   a->name,
03018                   a->synopsis ? a->synopsis : "Not available",
03019                   a->description ? a->description : "Not available");
03020             }
03021          }
03022       }
03023    }
03024    AST_RWLIST_UNLOCK(&apps);
03025 
03026    /* we found at least one app? no? */
03027    if (no_registered_app) {
03028       ast_cli(fd, "Your application(s) is (are) not registered\n");
03029       return RESULT_FAILURE;
03030    }
03031 
03032    return RESULT_SUCCESS;
03033 }
03034 
03035 /*! \brief  handle_show_hints: CLI support for listing registered dial plan hints */
03036 static int handle_show_hints(int fd, int argc, char *argv[])
03037 {
03038    struct ast_hint *hint;
03039    int num = 0;
03040    int watchers;
03041    struct ast_state_cb *watcher;
03042 
03043    AST_RWLIST_RDLOCK(&hints);
03044    if (AST_RWLIST_EMPTY(&hints)) {
03045       ast_cli(fd, "There are no registered dialplan hints\n");
03046       AST_RWLIST_UNLOCK(&hints);
03047       return RESULT_SUCCESS;
03048    }
03049    /* ... we have hints ... */
03050    ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
03051    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03052       watchers = 0;
03053       for (watcher = hint->callbacks; watcher; watcher = watcher->next)
03054          watchers++;
03055       ast_cli(fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
03056          ast_get_extension_name(hint->exten),
03057          ast_get_context_name(ast_get_extension_context(hint->exten)),
03058          ast_get_extension_app(hint->exten),
03059          ast_extension_state2str(hint->laststate), watchers);
03060       num++;
03061    }
03062    ast_cli(fd, "----------------\n");
03063    ast_cli(fd, "- %d hints registered\n", num);
03064    AST_RWLIST_UNLOCK(&hints);
03065    return RESULT_SUCCESS;
03066 }
03067 
03068 /*! \brief  handle_show_switches: CLI support for listing registered dial plan switches */
03069 static int handle_show_switches(int fd, int argc, char *argv[])
03070 {
03071    struct ast_switch *sw;
03072 
03073    AST_RWLIST_RDLOCK(&switches);
03074 
03075    if (AST_RWLIST_EMPTY(&switches)) {
03076       AST_RWLIST_UNLOCK(&switches);
03077       ast_cli(fd, "There are no registered alternative switches\n");
03078       return RESULT_SUCCESS;
03079    }
03080 
03081    ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
03082    AST_RWLIST_TRAVERSE(&switches, sw, list)
03083       ast_cli(fd, "%s: %s\n", sw->name, sw->description);
03084 
03085    AST_RWLIST_UNLOCK(&switches);
03086 
03087    return RESULT_SUCCESS;
03088 }
03089 
03090 static int handle_show_applications(int fd, int argc, char *argv[])
03091 {
03092    struct ast_app *a;
03093    int like = 0, describing = 0;
03094    int total_match = 0;    /* Number of matches in like clause */
03095    int total_apps = 0;  /* Number of apps registered */
03096 
03097    AST_RWLIST_RDLOCK(&apps);
03098 
03099    if (AST_RWLIST_EMPTY(&apps)) {
03100       ast_cli(fd, "There are no registered applications\n");
03101       AST_RWLIST_UNLOCK(&apps);
03102       return -1;
03103    }
03104 
03105    /* core list applications like <keyword> */
03106    if ((argc == 5) && (!strcmp(argv[3], "like"))) {
03107       like = 1;
03108    } else if ((argc > 4) && (!strcmp(argv[3], "describing"))) {
03109       describing = 1;
03110    }
03111 
03112    /* core list applications describing <keyword1> [<keyword2>] [...] */
03113    if ((!like) && (!describing)) {
03114       ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
03115    } else {
03116       ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
03117    }
03118 
03119    AST_RWLIST_TRAVERSE(&apps, a, list) {
03120       int printapp = 0;
03121       total_apps++;
03122       if (like) {
03123          if (strcasestr(a->name, argv[4])) {
03124             printapp = 1;
03125             total_match++;
03126          }
03127       } else if (describing) {
03128          if (a->description) {
03129             /* Match all words on command line */
03130             int i;
03131             printapp = 1;
03132             for (i = 4; i < argc; i++) {
03133                if (!strcasestr(a->description, argv[i])) {
03134                   printapp = 0;
03135                } else {
03136                   total_match++;
03137                }
03138             }
03139          }
03140       } else {
03141          printapp = 1;
03142       }
03143 
03144       if (printapp) {
03145          ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
03146       }
03147    }
03148    if ((!like) && (!describing)) {
03149       ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
03150    } else {
03151       ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
03152    }
03153 
03154    AST_RWLIST_UNLOCK(&apps);
03155 
03156    return RESULT_SUCCESS;
03157 }
03158 
03159 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
03160 {
03161    static char* choices[] = { "like", "describing", NULL };
03162 
03163    return (pos != 3) ? NULL : ast_cli_complete(word, choices, state);
03164 }
03165 
03166 /*
03167  * 'show dialplan' CLI command implementation functions ...
03168  */
03169 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
03170    int state)
03171 {
03172    struct ast_context *c = NULL;
03173    char *ret = NULL;
03174    int which = 0;
03175    int wordlen;
03176 
03177    /* we are do completion of [exten@]context on second position only */
03178    if (pos != 2)
03179       return NULL;
03180 
03181    ast_lock_contexts();
03182 
03183    wordlen = strlen(word);
03184 
03185    /* walk through all contexts and return the n-th match */
03186    while ( (c = ast_walk_contexts(c)) ) {
03187       if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
03188          ret = ast_strdup(ast_get_context_name(c));
03189          break;
03190       }
03191    }
03192 
03193    ast_unlock_contexts();
03194 
03195    return ret;
03196 }
03197 
03198 /*! \brief Counters for the show dialplan manager command */
03199 struct dialplan_counters {
03200    int total_items;
03201    int total_context;
03202    int total_exten;
03203    int total_prio;
03204    int context_existence;
03205    int extension_existence;
03206 };
03207 
03208 /*! \brief helper function to print an extension */
03209 static void print_ext(struct ast_exten *e, char * buf, int buflen)
03210 {
03211    int prio = ast_get_extension_priority(e);
03212    if (prio == PRIORITY_HINT) {
03213       snprintf(buf, buflen, "hint: %s",
03214          ast_get_extension_app(e));
03215    } else {
03216       snprintf(buf, buflen, "%d. %s(%s)",
03217          prio, ast_get_extension_app(e),
03218          (char *)ast_get_extension_app_data(e));
03219    }
03220 }
03221 
03222 /* XXX not verified */
03223 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[])
03224 {
03225    struct ast_context *c = NULL;
03226    int res = 0, old_total_exten = dpc->total_exten;
03227 
03228    ast_lock_contexts();
03229 
03230    /* walk all contexts ... */
03231    while ( (c = ast_walk_contexts(c)) ) {
03232       struct ast_exten *e;
03233       struct ast_include *i;
03234       struct ast_ignorepat *ip;
03235       char buf[256], buf2[256];
03236       int context_info_printed = 0;
03237 
03238       if (context && strcmp(ast_get_context_name(c), context))
03239          continue;   /* skip this one, name doesn't match */
03240 
03241       dpc->context_existence = 1;
03242 
03243       ast_lock_context(c);
03244 
03245       /* are we looking for exten too? if yes, we print context
03246        * only if we find our extension.
03247        * Otherwise print context even if empty ?
03248        * XXX i am not sure how the rinclude is handled.
03249        * I think it ought to go inside.
03250        */
03251       if (!exten) {
03252          dpc->total_context++;
03253          ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03254             ast_get_context_name(c), ast_get_context_registrar(c));
03255          context_info_printed = 1;
03256       }
03257 
03258       /* walk extensions ... */
03259       e = NULL;
03260       while ( (e = ast_walk_context_extensions(c, e)) ) {
03261          struct ast_exten *p;
03262 
03263          if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
03264             continue;   /* skip, extension match failed */
03265 
03266          dpc->extension_existence = 1;
03267 
03268          /* may we print context info? */
03269          if (!context_info_printed) {
03270             dpc->total_context++;
03271             if (rinclude) { /* TODO Print more info about rinclude */
03272                ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
03273                   ast_get_context_name(c), ast_get_context_registrar(c));
03274             } else {
03275                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03276                   ast_get_context_name(c), ast_get_context_registrar(c));
03277             }
03278             context_info_printed = 1;
03279          }
03280          dpc->total_prio++;
03281 
03282          /* write extension name and first peer */
03283          if (e->matchcid)
03284             snprintf(buf, sizeof(buf), "'%s' (CID match '%s') => ", ast_get_extension_name(e), e->cidmatch);
03285          else
03286             snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
03287 
03288          print_ext(e, buf2, sizeof(buf2));
03289 
03290          ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
03291             ast_get_extension_registrar(e));
03292 
03293          dpc->total_exten++;
03294          /* walk next extension peers */
03295          p = e;   /* skip the first one, we already got it */
03296          while ( (p = ast_walk_extension_priorities(e, p)) ) {
03297             const char *el = ast_get_extension_label(p);
03298             dpc->total_prio++;
03299             if (el)
03300                snprintf(buf, sizeof(buf), "   [%s]", el);
03301             else
03302                buf[0] = '\0';
03303             print_ext(p, buf2, sizeof(buf2));
03304 
03305             ast_cli(fd,"  %-17s %-45s [%s]\n", buf, buf2,
03306                ast_get_extension_registrar(p));
03307          }
03308       }
03309 
03310       /* walk included and write info ... */
03311       i = NULL;
03312       while ( (i = ast_walk_context_includes(c, i)) ) {
03313          snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
03314          if (exten) {
03315             /* Check all includes for the requested extension */
03316             if (includecount >= AST_PBX_MAX_STACK) {
03317                ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
03318             } else {
03319                int dupe=0;
03320                int x;
03321                for (x=0;x<includecount;x++) {
03322                   if (!strcasecmp(includes[x], ast_get_include_name(i))) {
03323                      dupe++;
03324                      break;
03325                   }
03326                }
03327                if (!dupe) {
03328                   includes[includecount] = ast_get_include_name(i);
03329                   show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
03330                } else {
03331                   ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
03332                }
03333             }
03334          } else {
03335             ast_cli(fd, "  Include =>        %-45s [%s]\n",
03336                buf, ast_get_include_registrar(i));
03337          }
03338       }
03339 
03340       /* walk ignore patterns and write info ... */
03341       ip = NULL;
03342       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
03343          const char *ipname = ast_get_ignorepat_name(ip);
03344          char ignorepat[AST_MAX_EXTENSION];
03345          snprintf(buf, sizeof(buf), "'%s'", ipname);
03346          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
03347          if (!exten || ast_extension_match(ignorepat, exten)) {
03348             ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
03349                buf, ast_get_ignorepat_registrar(ip));
03350          }
03351       }
03352       if (!rinclude) {
03353          struct ast_sw *sw = NULL;
03354          while ( (sw = ast_walk_context_switches(c, sw)) ) {
03355             snprintf(buf, sizeof(buf), "'%s/%s'",
03356                ast_get_switch_name(sw),
03357                ast_get_switch_data(sw));
03358             ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
03359                buf, ast_get_switch_registrar(sw));
03360          }
03361       }
03362 
03363       ast_unlock_context(c);
03364 
03365       /* if we print something in context, make an empty line */
03366       if (context_info_printed)
03367          ast_cli(fd, "\r\n");
03368    }
03369    ast_unlock_contexts();
03370 
03371    return (dpc->total_exten == old_total_exten) ? -1 : res;
03372 }
03373 
03374 static int handle_show_dialplan(int fd, int argc, char *argv[])
03375 {
03376    char *exten = NULL, *context = NULL;
03377    /* Variables used for different counters */
03378    struct dialplan_counters counters;
03379 
03380    const char *incstack[AST_PBX_MAX_STACK];
03381    memset(&counters, 0, sizeof(counters));
03382 
03383    if (argc != 2 && argc != 3)
03384       return RESULT_SHOWUSAGE;
03385 
03386    /* we obtain [exten@]context? if yes, split them ... */
03387    if (argc == 3) {
03388       if (strchr(argv[2], '@')) {   /* split into exten & context */
03389          context = ast_strdupa(argv[2]);
03390          exten = strsep(&context, "@");
03391          /* change empty strings to NULL */
03392          if (ast_strlen_zero(exten))
03393             exten = NULL;
03394       } else { /* no '@' char, only context given */
03395          context = argv[2];
03396       }
03397       if (ast_strlen_zero(context))
03398          context = NULL;
03399    }
03400    /* else Show complete dial plan, context and exten are NULL */
03401    show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
03402 
03403    /* check for input failure and throw some error messages */
03404    if (context && !counters.context_existence) {
03405       ast_cli(fd, "There is no existence of '%s' context\n", context);
03406       return RESULT_FAILURE;
03407    }
03408 
03409    if (exten && !counters.extension_existence) {
03410       if (context)
03411          ast_cli(fd, "There is no existence of %s@%s extension\n",
03412             exten, context);
03413       else
03414          ast_cli(fd,
03415             "There is no existence of '%s' extension in all contexts\n",
03416             exten);
03417       return RESULT_FAILURE;
03418    }
03419 
03420    ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
03421             counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
03422             counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
03423             counters.total_context, counters.total_context == 1 ? "context" : "contexts");
03424 
03425    /* everything ok */
03426    return RESULT_SUCCESS;
03427 }
03428 
03429 /*! \brief Send ack once */
03430 static void manager_dpsendack(struct mansession *s, const struct message *m)
03431 {
03432    astman_send_listack(s, m, "DialPlan list will follow", "start");
03433 }
03434 
03435 /*! \brief Show dialplan extensions
03436  * XXX this function is similar but not exactly the same as the CLI's
03437  * show dialplan. Must check whether the difference is intentional or not.
03438  */
03439 static int manager_show_dialplan_helper(struct mansession *s, const struct message *m,
03440                const char *actionidtext, const char *context,
03441                const char *exten, struct dialplan_counters *dpc,
03442                struct ast_include *rinclude)
03443 {
03444    struct ast_context *c;
03445    int res=0, old_total_exten = dpc->total_exten;
03446 
03447    if (ast_strlen_zero(exten))
03448       exten = NULL;
03449    if (ast_strlen_zero(context))
03450       context = NULL;
03451 
03452    if (option_debug > 2)
03453       ast_log(LOG_DEBUG, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten);
03454 
03455    /* try to lock contexts */
03456    if (ast_lock_contexts()) {
03457       astman_send_error(s, m, "Failed to lock contexts\r\n");
03458       ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n");
03459       return -1;
03460    }
03461 
03462    c = NULL;      /* walk all contexts ... */
03463    while ( (c = ast_walk_contexts(c)) ) {
03464       struct ast_exten *e;
03465       struct ast_include *i;
03466       struct ast_ignorepat *ip;
03467 
03468       if (context && strcmp(ast_get_context_name(c), context) != 0)
03469          continue;   /* not the name we want */
03470 
03471       dpc->context_existence = 1;
03472 
03473       if (option_debug > 2)
03474          ast_log(LOG_DEBUG, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c));
03475 
03476       if (ast_lock_context(c)) { /* failed to lock */
03477          if (option_debug > 2)
03478             ast_log(LOG_DEBUG, "manager_show_dialplan: Failed to lock context\n");
03479          continue;
03480       }
03481 
03482       /* XXX note- an empty context is not printed */
03483       e = NULL;      /* walk extensions in context  */
03484       while ( (e = ast_walk_context_extensions(c, e)) ) {
03485          struct ast_exten *p;
03486 
03487          /* looking for extension? is this our extension? */
03488          if (exten && !ast_extension_match(ast_get_extension_name(e), exten)) {
03489             /* not the one we are looking for, continue */
03490             if (option_debug > 2)
03491                ast_log(LOG_DEBUG, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e));
03492             continue;
03493          }
03494          if (option_debug > 2)
03495             ast_log(LOG_DEBUG, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e));
03496 
03497          dpc->extension_existence = 1;
03498 
03499          /* may we print context info? */ 
03500          dpc->total_context++;
03501          dpc->total_exten++;
03502 
03503          p = NULL;      /* walk next extension peers */
03504          while ( (p = ast_walk_extension_priorities(e, p)) ) {
03505             int prio = ast_get_extension_priority(p);
03506 
03507             dpc->total_prio++;
03508             if (!dpc->total_items++)
03509                manager_dpsendack(s, m);
03510             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
03511             astman_append(s, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) );
03512 
03513             /* XXX maybe make this conditional, if p != e ? */
03514             if (ast_get_extension_label(p))
03515                astman_append(s, "ExtensionLabel: %s\r\n", ast_get_extension_label(p));
03516 
03517             if (prio == PRIORITY_HINT) {
03518                astman_append(s, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p));
03519             } else {
03520                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));
03521             }
03522             astman_append(s, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e));
03523          }
03524       }
03525 
03526       i = NULL;      /* walk included and write info ... */
03527       while ( (i = ast_walk_context_includes(c, i)) ) {
03528          if (exten) {
03529             /* Check all includes for the requested extension */
03530             manager_show_dialplan_helper(s, m, actionidtext, ast_get_include_name(i), exten, dpc, i);
03531          } else {
03532             if (!dpc->total_items++)
03533                manager_dpsendack(s, m);
03534             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
03535             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));
03536             astman_append(s, "\r\n");
03537             if (option_debug > 2)
03538                ast_log(LOG_DEBUG, "manager_show_dialplan: Found Included context: %s \n", ast_get_include_name(i));
03539          }
03540       }
03541 
03542       ip = NULL;  /* walk ignore patterns and write info ... */
03543       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
03544          const char *ipname = ast_get_ignorepat_name(ip);
03545          char ignorepat[AST_MAX_EXTENSION];
03546 
03547          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
03548          if (!exten || ast_extension_match(ignorepat, exten)) {
03549             if (!dpc->total_items++)
03550                manager_dpsendack(s, m);
03551             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
03552             astman_append(s, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip));
03553             astman_append(s, "\r\n");
03554          }
03555       }
03556       if (!rinclude) {
03557          struct ast_sw *sw = NULL;
03558          while ( (sw = ast_walk_context_switches(c, sw)) ) {
03559             if (!dpc->total_items++)
03560                manager_dpsendack(s, m);
03561             astman_append(s, "Event: ListDialplan\r\n%s", actionidtext);
03562             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));  
03563             astman_append(s, "\r\n");
03564             if (option_debug > 2)
03565                ast_log(LOG_DEBUG, "manager_show_dialplan: Found Switch : %s \n", ast_get_switch_name(sw));
03566          }
03567       }
03568 
03569       ast_unlock_context(c);
03570    }
03571    ast_unlock_contexts();
03572 
03573    if (dpc->total_exten == old_total_exten) {
03574       if (option_debug > 2)
03575          ast_log(LOG_DEBUG, "manager_show_dialplan: Found nothing new\n");
03576       /* Nothing new under the sun */
03577       return -1;
03578    } else {
03579       return res;
03580    }
03581 }
03582 
03583 /*! \brief  Manager listing of dial plan */
03584 static int manager_show_dialplan(struct mansession *s, const struct message *m)
03585 {
03586    const char *exten, *context;
03587    const char *id = astman_get_header(m, "ActionID");
03588    char idtext[256];
03589    int res;
03590 
03591    /* Variables used for different counters */
03592    struct dialplan_counters counters;
03593 
03594    if (id && !ast_strlen_zero(id))
03595       snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id);
03596    else
03597       idtext[0] = '\0';
03598 
03599    memset(&counters, 0, sizeof(counters));
03600 
03601    exten = astman_get_header(m, "Extension");
03602    context = astman_get_header(m, "Context");
03603    
03604    res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL);
03605 
03606    if (context && !counters.context_existence) {
03607       char errorbuf[BUFSIZ];
03608    
03609       snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s\r\n", context);
03610       astman_send_error(s, m, errorbuf);
03611       return 0;
03612    }
03613    if (exten && !counters.extension_existence) {
03614       char errorbuf[BUFSIZ];
03615 
03616       if (context)
03617          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s\r\n", exten, context);
03618       else
03619          snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context\r\n", exten);
03620       astman_send_error(s, m, errorbuf);
03621       return 0;
03622    }
03623 
03624    manager_event(EVENT_FLAG_CONFIG, "ShowDialPlanComplete",
03625       "EventList: Complete\r\n"
03626       "ListItems: %d\r\n"
03627       "ListExtensions: %d\r\n"
03628       "ListPriorities: %d\r\n"   
03629       "ListContexts: %d\r\n"  
03630       "%s"
03631       "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext);
03632 
03633    /* everything ok */
03634    return 0;
03635 }
03636 
03637 static char mandescr_show_dialplan[] =
03638 "Description: Show dialplan contexts and extensions.\n"
03639 "Be aware that showing the full dialplan may take a lot of capacity\n"
03640 "Variables: \n"
03641 " ActionID: <id>     Action ID for this AMI transaction (optional)\n"
03642 " Extension: <extension>   Extension (Optional)\n"
03643 " Context: <context>    Context (Optional)\n"
03644 "\n";
03645 
03646 
03647 /*! \brief CLI support for listing global variables in a parseable way */
03648 static int handle_show_globals(int fd, int argc, char *argv[])
03649 {
03650    int i = 0;
03651    struct ast_var_t *newvariable;
03652 
03653    ast_rwlock_rdlock(&globalslock);
03654    AST_LIST_TRAVERSE (&globals, newvariable, entries) {
03655       i++;
03656       ast_cli(fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
03657    }
03658    ast_rwlock_unlock(&globalslock);
03659    ast_cli(fd, "\n    -- %d variables\n", i);
03660 
03661    return RESULT_SUCCESS;
03662 }
03663 
03664 static int handle_set_global(int fd, int argc, char *argv[])
03665 {
03666    if (argc != 5)
03667       return RESULT_SHOWUSAGE;
03668 
03669    pbx_builtin_setvar_helper(NULL, argv[3], argv[4]);
03670    ast_cli(fd, "\n    -- Global variable %s set to %s\n", argv[3], argv[4]);
03671 
03672    return RESULT_SUCCESS;
03673 }
03674 
03675 
03676 
03677 /*
03678  * CLI entries for upper commands ...
03679  */
03680 static struct ast_cli_entry pbx_cli[] = {
03681    { { "core", "show", "applications", NULL },
03682    handle_show_applications, "Shows registered dialplan applications",
03683    show_applications_help, complete_show_applications },
03684 
03685    { { "core", "show", "functions", NULL },
03686    handle_show_functions, "Shows registered dialplan functions",
03687    show_functions_help },
03688 
03689    { { "core", "show", "switches", NULL },
03690    handle_show_switches, "Show alternative switches",
03691    show_switches_help },
03692 
03693    { { "core", "show", "hints", NULL },
03694    handle_show_hints, "Show dialplan hints",
03695    show_hints_help },
03696 
03697    { { "core", "show", "globals", NULL },
03698    handle_show_globals, "Show global dialplan variables",
03699    show_globals_help },
03700 
03701    { { "core", "show" , "function", NULL },
03702    handle_show_function, "Describe a specific dialplan function",
03703    show_function_help, complete_show_function },
03704 
03705    { { "core", "show", "application", NULL },
03706    handle_show_application, "Describe a specific dialplan application",
03707    show_application_help, complete_show_application },
03708 
03709    { { "core", "set", "global", NULL },
03710    handle_set_global, "Set global dialplan variable",
03711    set_global_help },
03712 
03713    { { "dialplan", "show", NULL },
03714    handle_show_dialplan, "Show dialplan",
03715    show_dialplan_help, complete_show_dialplan_context },
03716 };
03717 
03718 static void unreference_cached_app(struct ast_app *app)
03719 {
03720    struct ast_context *context = NULL;
03721    struct ast_exten *eroot = NULL, *e = NULL;
03722 
03723    ast_lock_contexts();
03724    while ((context = ast_walk_contexts(context))) {
03725       while ((eroot = ast_walk_context_extensions(context, eroot))) {
03726          while ((e = ast_walk_extension_priorities(eroot, e))) {
03727             if (e->cached_app == app)
03728                e->cached_app = NULL;
03729          }
03730       }
03731    }
03732    ast_unlock_contexts();
03733 
03734    return;
03735 }
03736 
03737 int ast_unregister_application(const char *app)
03738 {
03739    struct ast_app *tmp;
03740 
03741    AST_RWLIST_WRLOCK(&apps);
03742    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
03743       if (!strcasecmp(app, tmp->name)) {
03744          unreference_cached_app(tmp);
03745          AST_RWLIST_REMOVE_CURRENT(&apps, list);
03746          if (option_verbose > 1)
03747             ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
03748          free(tmp);
03749          break;
03750       }
03751    }
03752    AST_RWLIST_TRAVERSE_SAFE_END
03753    AST_RWLIST_UNLOCK(&apps);
03754 
03755    return tmp ? 0 : -1;
03756 }
03757 
03758 static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
03759 {
03760    struct ast_context *tmp, **local_contexts;
03761    int length = sizeof(struct ast_context) + strlen(name) + 1;
03762 
03763    if (!extcontexts) {
03764       ast_mutex_lock(&conlock);
03765       local_contexts = &contexts;
03766    } else
03767       local_contexts = extcontexts;
03768 
03769    for (tmp = *local_contexts; tmp; tmp = tmp->next) {
03770       if (!strcasecmp(tmp->name, name)) {
03771          if (!existsokay) {
03772             ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
03773             tmp = NULL;
03774          }
03775          if (!extcontexts)
03776             ast_mutex_unlock(&conlock);
03777          return tmp;
03778       }
03779    }
03780    if ((tmp = ast_calloc(1, length))) {
03781       ast_mutex_init(&tmp->lock);
03782       ast_mutex_init(&tmp->macrolock);
03783       strcpy(tmp->name, name);
03784       tmp->root = NULL;
03785       tmp->registrar = registrar;
03786       tmp->next = *local_contexts;
03787       tmp->includes = NULL;
03788       tmp->ignorepats = NULL;
03789       *local_contexts = tmp;
03790       if (option_debug)
03791          ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
03792       if (option_verbose > 2)
03793          ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
03794    }
03795 
03796    if (!extcontexts)
03797       ast_mutex_unlock(&conlock);
03798    return tmp;
03799 }
03800 
03801 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03802 {
03803    return __ast_context_create(extcontexts, name, registrar, 0);
03804 }
03805 
03806 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03807 {
03808    return __ast_context_create(extcontexts, name, registrar, 1);
03809 }
03810 void __ast_context_destroy(struct ast_context *con, const char *registrar);
03811 
03812 struct store_hint {
03813    char *context;
03814    char *exten;
03815    struct ast_state_cb *callbacks;
03816    int laststate;
03817    AST_LIST_ENTRY(store_hint) list;
03818    char data[1];
03819 };
03820 
03821 AST_LIST_HEAD(store_hints, store_hint);
03822 
03823 /* XXX this does not check that multiple contexts are merged */
03824 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
03825 {
03826    struct ast_context *tmp, *lasttmp = NULL;
03827    struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
03828    struct store_hint *this;
03829    struct ast_hint *hint;
03830    struct ast_exten *exten;
03831    int length;
03832    struct ast_state_cb *thiscb, *prevcb;
03833 
03834    /* it is very important that this function hold the hint list lock _and_ the conlock
03835       during its operation; not only do we need to ensure that the list of contexts
03836       and extensions does not change, but also that no hint callbacks (watchers) are
03837       added or removed during the merge/delete process
03838 
03839       in addition, the locks _must_ be taken in this order, because there are already
03840       other code paths that use this order
03841    */
03842    ast_mutex_lock(&conlock);
03843    AST_RWLIST_WRLOCK(&hints);
03844 
03845    /* preserve all watchers for hints associated with this registrar */
03846    AST_RWLIST_TRAVERSE(&hints, hint, list) {
03847       if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
03848          length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
03849          if (!(this = ast_calloc(1, length)))
03850             continue;
03851          this->callbacks = hint->callbacks;
03852          hint->callbacks = NULL;
03853          this->laststate = hint->laststate;
03854          this->context = this->data;
03855          strcpy(this->data, hint->exten->parent->name);
03856          this->exten = this->data + strlen(this->context) + 1;
03857          strcpy(this->exten, hint->exten->exten);
03858          AST_LIST_INSERT_HEAD(&store, this, list);
03859       }
03860    }
03861 
03862    tmp = *extcontexts;
03863    if (registrar) {
03864       /* XXX remove previous contexts from same registrar */
03865       if (option_debug)
03866          ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
03867       __ast_context_destroy(NULL,registrar);
03868       while (tmp) {
03869          lasttmp = tmp;
03870          tmp = tmp->next;
03871       }
03872    } else {
03873       /* XXX remove contexts with the same name */
03874       while (tmp) {
03875          ast_log(LOG_WARNING, "must remove %s  reg %s\n", tmp->name, tmp->registrar);
03876          __ast_context_destroy(tmp,tmp->registrar);
03877          lasttmp = tmp;
03878          tmp = tmp->next;
03879       }
03880    }
03881    if (lasttmp) {
03882       lasttmp->next = contexts;
03883       contexts = *extcontexts;
03884       *extcontexts = NULL;
03885    } else
03886       ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
03887 
03888    /* restore the watchers for hints that can be found; notify those that
03889       cannot be restored
03890    */
03891    while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
03892       exten = ast_hint_extension(NULL, this->context, this->exten);
03893       /* Find the hint in the list of hints */
03894       AST_RWLIST_TRAVERSE(&hints, hint, list) {
03895          if (hint->exten == exten)
03896             break;
03897       }
03898       if (!exten || !hint) {
03899          /* this hint has been removed, notify the watchers */
03900          prevcb = NULL;
03901          thiscb = this->callbacks;
03902          while (thiscb) {
03903             prevcb = thiscb;
03904             thiscb = thiscb->next;
03905             prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
03906             free(prevcb);
03907             }
03908       } else {
03909          thiscb = this->callbacks;
03910          while (thiscb->next)
03911             thiscb = thiscb->next;
03912          thiscb->next = hint->callbacks;
03913          hint->callbacks = this->callbacks;
03914          hint->laststate = this->laststate;
03915       }
03916       free(this);
03917    }
03918 
03919    AST_RWLIST_UNLOCK(&hints);
03920    ast_mutex_unlock(&conlock);
03921 
03922    return;
03923 }
03924 
03925 /*
03926  * errno values
03927  *  EBUSY  - can't lock
03928  *  ENOENT - no existence of context
03929  */
03930 int ast_context_add_include(const char *context, const char *include, const char *registrar)
03931 {
03932    int ret = -1;
03933    struct ast_context *c = find_context_locked(context);
03934 
03935    if (c) {
03936       ret = ast_context_add_include2(c, include, registrar);
03937       ast_unlock_contexts();
03938    }
03939    return ret;
03940 }
03941 
03942 /*! \brief Helper for get_range.
03943  * return the index of the matching entry, starting from 1.
03944  * If names is not supplied, try numeric values.
03945  */
03946 static int lookup_name(const char *s, char *const names[], int max)
03947 {
03948    int i;
03949 
03950    if (names) {
03951       for (i = 0; names[i]; i++) {
03952          if (!strcasecmp(s, names[i]))
03953             return i+1;
03954       }
03955    } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
03956       return i;
03957    }
03958    return 0; /* error return */
03959 }
03960 
03961 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
03962  * names, if supplied, is an array of names that should be mapped to numbers.
03963  */
03964 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
03965 {
03966    int s, e; /* start and ending position */
03967    unsigned int mask = 0;
03968 
03969    /* Check for whole range */
03970    if (ast_strlen_zero(src) || !strcmp(src, "*")) {
03971       s = 0;
03972       e = max - 1;
03973    } else {
03974       /* Get start and ending position */
03975       char *c = strchr(src, '-');
03976       if (c)
03977          *c++ = '\0';
03978       /* Find the start */
03979       s = lookup_name(src, names, max);
03980       if (!s) {
03981          ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
03982          return 0;
03983       }
03984       s--;
03985       if (c) { /* find end of range */
03986          e = lookup_name(c, names, max);
03987          if (!e) {
03988             ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
03989             return 0;
03990          }
03991          e--;
03992       } else
03993          e = s;
03994    }
03995    /* Fill the mask. Remember that ranges are cyclic */
03996    mask = 1 << e; /* initialize with last element */
03997    while (s != e) {
03998       if (s >= max) {
03999          s = 0;
04000          mask |= (1 << s);
04001       } else {
04002          mask |= (1 << s);
04003          s++;
04004       }
04005    }
04006    return mask;
04007 }
04008 
04009 /*! \brief store a bitmask of valid times, one bit each 2 minute */
04010 static void get_timerange(struct ast_timing *i, char *times)
04011 {
04012    char *e;
04013    int x;
04014    int s1, s2;
04015    int e1, e2;
04016    /* int cth, ctm; */
04017 
04018    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
04019    memset(i->minmask, 0, sizeof(i->minmask));
04020 
04021    /* 2-minutes per bit, since the mask has only 32 bits :( */
04022    /* Star is all times */
04023    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
04024       for (x=0; x<24; x++)
04025          i->minmask[x] = 0x3fffffff; /* 30 bits */
04026       return;
04027    }
04028    /* Otherwise expect a range */
04029    e = strchr(times, '-');
04030    if (!e) {
04031       ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
04032       return;
04033    }
04034    *e++ = '\0';
04035    /* XXX why skip non digits ? */
04036    while (*e && !isdigit(*e))
04037       e++;
04038    if (!*e) {
04039       ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
04040       return;
04041    }
04042    if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
04043       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
04044       return;
04045    }
04046    if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
04047       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
04048       return;
04049    }
04050    /* XXX this needs to be optimized */
04051 #if 1
04052    s1 = s1 * 30 + s2/2;
04053    if ((s1 < 0) || (s1 >= 24*30)) {
04054       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
04055       return;
04056    }
04057    e1 = e1 * 30 + e2/2;
04058    if ((e1 < 0) || (e1 >= 24*30)) {
04059       ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
04060       return;
04061    }
04062    /* Go through the time and enable each appropriate bit */
04063    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
04064       i->minmask[x/30] |= (1 << (x % 30));
04065    }
04066    /* Do the last one */
04067    i->minmask[x/30] |= (1 << (x % 30));
04068 #else
04069    for (cth=0; cth<24; cth++) {
04070       /* Initialize masks to blank */
04071       i->minmask[cth] = 0;
04072       for (ctm=0; ctm<30; ctm++) {
04073          if (
04074          /* First hour with more than one hour */
04075                (((cth == s1) && (ctm >= s2)) &&
04076                 ((cth < e1)))
04077          /* Only one hour */
04078          ||    (((cth == s1) && (ctm >= s2)) &&
04079                 ((cth == e1) && (ctm <= e2)))
04080          /* In between first and last hours (more than 2