Mon May 14 04:42:56 2007

Asterisk developer's documentation


pbx.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 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$")
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 
00108 /*!
00109    \brief ast_exten: An extension
00110    The dialplan is saved as a linked list with each context
00111    having it's own linked list of extensions - one item per
00112    priority.
00113 */
00114 struct ast_exten {
00115    char *exten;         /*!< Extension name */
00116    int matchcid;        /*!< Match caller id ? */
00117    const char *cidmatch;      /*!< Caller id to match for this extension */
00118    int priority;        /*!< Priority */
00119    const char *label;      /*!< Label */
00120    struct ast_context *parent;   /*!< The context this extension belongs to  */
00121    const char *app;     /*!< Application to execute */
00122    void *data;       /*!< Data to use (arguments) */
00123    void (*datad)(void *);     /*!< Data destructor */
00124    struct ast_exten *peer;    /*!< Next higher priority with our extension */
00125    const char *registrar;     /*!< Registrar */
00126    struct ast_exten *next;    /*!< Extension with a greater ID */
00127    char stuff[0];
00128 };
00129 
00130 /*! \brief ast_include: include= support in extensions.conf */
00131 struct ast_include {
00132    const char *name;
00133    const char *rname;         /*!< Context to include */
00134    const char *registrar;        /*!< Registrar */
00135    int hastime;            /*!< If time construct exists */
00136    struct ast_timing timing;               /*!< time construct */
00137    struct ast_include *next;     /*!< Link them together */
00138    char stuff[0];
00139 };
00140 
00141 /*! \brief ast_sw: Switch statement in extensions.conf */
00142 struct ast_sw {
00143    char *name;
00144    const char *registrar;        /*!< Registrar */
00145    char *data;          /*!< Data load */
00146    int eval;
00147    AST_LIST_ENTRY(ast_sw) list;
00148    char *tmpdata;
00149    char stuff[0];
00150 };
00151 
00152 /*! \brief ast_ignorepat: Ignore patterns in dial plan */
00153 struct ast_ignorepat {
00154    const char *registrar;
00155    struct ast_ignorepat *next;
00156    const char pattern[0];
00157 };
00158 
00159 /*! \brief ast_context: An extension context */
00160 struct ast_context {
00161    ast_mutex_t lock;          /*!< A lock to prevent multiple threads from clobbering the context */
00162    struct ast_exten *root;       /*!< The root of the list of extensions */
00163    struct ast_context *next;     /*!< Link them together */
00164    struct ast_include *includes;    /*!< Include other contexts */
00165    struct ast_ignorepat *ignorepats;   /*!< Patterns for which to continue playing dialtone */
00166    const char *registrar;        /*!< Registrar */
00167    AST_LIST_HEAD_NOLOCK(, ast_sw) alts;   /*!< Alternative switches */
00168    ast_mutex_t macrolock;        /*!< A lock to implement "exclusive" macros - held whilst a call is executing in the macro */
00169    char name[0];           /*!< Name of the context */
00170 };
00171 
00172 
00173 /*! \brief ast_app: A registered application */
00174 struct ast_app {
00175    int (*execute)(struct ast_channel *chan, void *data);
00176    const char *synopsis;         /*!< Synopsis text for 'show applications' */
00177    const char *description;      /*!< Description (help text) for 'show application &lt;name&gt;' */
00178    AST_LIST_ENTRY(ast_app) list;    /*!< Next app in list */
00179    struct module *module;        /*!< Module this app belongs to */
00180    char name[0];           /*!< Name of the application */
00181 };
00182 
00183 /*! \brief ast_state_cb: An extension state notify register item */
00184 struct ast_state_cb {
00185    int id;
00186    void *data;
00187    ast_state_cb_type callback;
00188    struct ast_state_cb *next;
00189 };
00190 
00191 /*! \brief Structure for dial plan hints
00192 
00193   \note Hints are pointers from an extension in the dialplan to one or
00194   more devices (tech/name) 
00195    - See \ref AstExtState
00196 */
00197 struct ast_hint {
00198    struct ast_exten *exten;   /*!< Extension */
00199    int laststate;          /*!< Last known state */
00200    struct ast_state_cb *callbacks;  /*!< Callback list for this extension */
00201    AST_LIST_ENTRY(ast_hint) list;   /*!< Pointer to next hint in list */
00202 };
00203 
00204 static const struct cfextension_states {
00205    int extension_state;
00206    const char * const text;
00207 } extension_states[] = {
00208    { AST_EXTENSION_NOT_INUSE,                     "Idle" },
00209    { AST_EXTENSION_INUSE,                         "InUse" },
00210    { AST_EXTENSION_BUSY,                          "Busy" },
00211    { AST_EXTENSION_UNAVAILABLE,                   "Unavailable" },
00212    { AST_EXTENSION_RINGING,                       "Ringing" },
00213    { AST_EXTENSION_INUSE | AST_EXTENSION_RINGING, "InUse&Ringing" },
00214    { AST_EXTENSION_ONHOLD,                        "Hold" },
00215    { AST_EXTENSION_INUSE | AST_EXTENSION_ONHOLD,  "InUse&Hold" }
00216 };
00217 
00218 static int pbx_builtin_answer(struct ast_channel *, void *);
00219 static int pbx_builtin_goto(struct ast_channel *, void *);
00220 static int pbx_builtin_hangup(struct ast_channel *, void *);
00221 static int pbx_builtin_background(struct ast_channel *, void *);
00222 static int pbx_builtin_wait(struct ast_channel *, void *);
00223 static int pbx_builtin_waitexten(struct ast_channel *, void *);
00224 static int pbx_builtin_resetcdr(struct ast_channel *, void *);
00225 static int pbx_builtin_setamaflags(struct ast_channel *, void *);
00226 static int pbx_builtin_ringing(struct ast_channel *, void *);
00227 static int pbx_builtin_progress(struct ast_channel *, void *);
00228 static int pbx_builtin_congestion(struct ast_channel *, void *);
00229 static int pbx_builtin_busy(struct ast_channel *, void *);
00230 static int pbx_builtin_setglobalvar(struct ast_channel *, void *);
00231 static int pbx_builtin_noop(struct ast_channel *, void *);
00232 static int pbx_builtin_gotoif(struct ast_channel *, void *);
00233 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
00234 static int pbx_builtin_execiftime(struct ast_channel *, void *);
00235 static int pbx_builtin_saynumber(struct ast_channel *, void *);
00236 static int pbx_builtin_saydigits(struct ast_channel *, void *);
00237 static int pbx_builtin_saycharacters(struct ast_channel *, void *);
00238 static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
00239 int pbx_builtin_setvar(struct ast_channel *, void *);
00240 static int pbx_builtin_importvar(struct ast_channel *, void *);
00241 
00242 AST_MUTEX_DEFINE_STATIC(globalslock);
00243 static struct varshead globals = AST_LIST_HEAD_NOLOCK_INIT_VALUE;
00244 
00245 static int autofallthrough = 1;
00246 
00247 AST_MUTEX_DEFINE_STATIC(maxcalllock);
00248 static int countcalls;
00249 
00250 static AST_LIST_HEAD_STATIC(acf_root, ast_custom_function);
00251 
00252 /*! \brief Declaration of builtin applications */
00253 static struct pbx_builtin {
00254    char name[AST_MAX_APP];
00255    int (*execute)(struct ast_channel *chan, void *data);
00256    char *synopsis;
00257    char *description;
00258 } builtins[] =
00259 {
00260    /* These applications are built into the PBX core and do not
00261       need separate modules */
00262 
00263    { "Answer", pbx_builtin_answer,
00264    "Answer a channel if ringing",
00265    "  Answer([delay]): If the call has not been answered, this application will\n"
00266    "answer it. Otherwise, it has no effect on the call. If a delay is specified,\n"
00267    "Asterisk will wait this number of milliseconds before returning to\n"
00268    "the dialplan after answering the call.\n"
00269    },
00270 
00271    { "BackGround", pbx_builtin_background,
00272    "Play an audio file while waiting for digits of an extension to go to.",
00273    "  Background(filename1[&filename2...][|options[|langoverride][|context]]):\n"
00274    "This application will play the given list of files while waiting for an\n"
00275    "extension to be dialed by the calling channel. To continue waiting for digits\n"
00276    "after this application has finished playing files, the WaitExten application\n"
00277    "should be used. The 'langoverride' option explicitly specifies which language\n"
00278    "to attempt to use for the requested sound files. If a 'context' is specified,\n"
00279    "this is the dialplan context that this application will use when exiting to a\n"
00280    "dialed extension."
00281    "  If one of the requested sound files does not exist, call processing will be\n"
00282    "terminated.\n"
00283    "  Options:\n"
00284    "    s - Causes the playback of the message to be skipped\n"
00285    "          if the channel is not in the 'up' state (i.e. it\n"
00286    "          hasn't been answered yet). If this happens, the\n"
00287    "          application will return immediately.\n"
00288    "    n - Don't answer the channel before playing the files.\n"
00289    "    m - Only break if a digit hit matches a one digit\n"
00290    "          extension in the destination context.\n"
00291    },
00292 
00293    { "Busy", pbx_builtin_busy,
00294    "Indicate the Busy condition",
00295    "  Busy([timeout]): This application will indicate the busy condition to\n"
00296    "the calling channel. If the optional timeout is specified, the calling channel\n"
00297    "will be hung up after the specified number of seconds. Otherwise, this\n"
00298    "application will wait until the calling channel hangs up.\n"
00299    },
00300 
00301    { "Congestion", pbx_builtin_congestion,
00302    "Indicate the Congestion condition",
00303    "  Congestion([timeout]): This application will indicate the congestion\n"
00304    "condition to the calling channel. If the optional timeout is specified, the\n"
00305    "calling channel will be hung up after the specified number of seconds.\n"
00306    "Otherwise, this application will wait until the calling channel hangs up.\n"
00307    },
00308 
00309    { "Goto", pbx_builtin_goto,
00310    "Jump to a particular priority, extension, or context",
00311    "  Goto([[context|]extension|]priority): This application will set the current\n"
00312    "context, extension, and priority in the channel structure. After it completes, the\n"
00313    "pbx engine will continue dialplan execution at the specified location.\n"
00314    "If no specific extension, or extension and context, are specified, then this\n"
00315    "application will just set the specified priority of the current extension.\n"
00316    "  At least a priority is required as an argument, or the goto will return a -1,\n"
00317    "and the channel and call will be terminated.\n"
00318    "  If the location that is put into the channel information is bogus, and asterisk cannot\n"
00319         "find that location in the dialplan,\n"
00320    "then the execution engine will try to find and execute the code in the 'i' (invalid)\n"
00321    "extension in the current context. If that does not exist, it will try to execute the\n"
00322    "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
00323    "channel is hung up, and the execution of instructions on the channel is terminated.\n"
00324    "What this means is that, for example, you specify a context that does not exist, then\n"
00325    "it will not be possible to find the 'h' or 'i' extensions, and the call will terminate!\n"
00326    },
00327 
00328    { "GotoIf", pbx_builtin_gotoif,
00329    "Conditional goto",
00330    "  GotoIf(condition?[labeliftrue]:[labeliffalse]): This application will set the current\n"
00331    "context, extension, and priority in the channel structure based on the evaluation of\n"
00332    "the given condition. After this application completes, the\n"
00333    "pbx engine will continue dialplan execution at the specified location in the dialplan.\n"
00334    "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, and the execution passes to the next instruction.\n"
00339    "If the target location is bogus, and does not exist, the execution engine will try \n"
00340    "to find and execute the code in the 'i' (invalid)\n"
00341    "extension in the current context. If that does not exist, it will try to execute the\n"
00342    "'h' extension. If either or neither the 'h' or 'i' extensions have been defined, the\n"
00343    "channel is hung up, and the execution of instructions on the channel is terminated.\n"
00344    "Remember that this command can set the current context, and if the context specified\n"
00345    "does not exist, then it will not be able to find any 'h' or 'i' extensions there, and\n"
00346    "the channel and call will both be terminated!\n"
00347    },
00348 
00349    { "GotoIfTime", pbx_builtin_gotoiftime,
00350    "Conditional Goto based on the current time",
00351    "  GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]exten|]priority):\n"
00352    "This application will set the context, extension, and priority in the channel structure\n"
00353    "if the current time matches the given time specification. Otherwise, nothing is done.\n"
00354         "Further information on the time specification can be found in examples\n"
00355         "illustrating how to do time-based context includes in the dialplan.\n" 
00356    "If the target jump location is bogus, the same actions would be taken as for Goto.\n"
00357    },
00358 
00359    { "ExecIfTime", pbx_builtin_execiftime,
00360    "Conditional application execution based on the current time",
00361    "  ExecIfTime(<times>|<weekdays>|<mdays>|<months>?appname[|appargs]):\n"
00362    "This application will execute the specified dialplan application, with optional\n"
00363    "arguments, if the current time matches the given time specification.\n"
00364    },
00365 
00366    { "Hangup", pbx_builtin_hangup,
00367    "Hang up the calling channel",
00368    "  Hangup([causecode]): This application will hang up the calling channel.\n"
00369    "If a causecode is given the channel's hangup cause will be set to the given\n"
00370    "value.\n"
00371    },
00372 
00373    { "NoOp", pbx_builtin_noop,
00374    "Do Nothing",
00375    "  NoOp(): This applicatiion does nothing. However, it is useful for debugging\n"
00376    "purposes. Any text that is provided as arguments to this application can be\n"
00377    "viewed at the Asterisk CLI. This method can be used to see the evaluations of\n"
00378    "variables or functions without having any effect."
00379    },
00380 
00381    { "Progress", pbx_builtin_progress,
00382    "Indicate progress",
00383    "  Progress(): This application will request that in-band progress information\n"
00384    "be provided to the calling channel.\n"
00385    },
00386 
00387    { "ResetCDR", pbx_builtin_resetcdr,
00388    "Resets the Call Data Record",
00389    "  ResetCDR([options]):  This application causes the Call Data Record to be\n"
00390    "reset.\n"
00391    "  Options:\n"
00392    "    w -- Store the current CDR record before resetting it.\n"
00393    "    a -- Store any stacked records.\n"
00394    "    v -- Save CDR variables.\n"
00395    },
00396 
00397    { "Ringing", pbx_builtin_ringing,
00398    "Indicate ringing tone",
00399    "  Ringing(): This application will request that the channel indicate a ringing\n"
00400    "tone to the user.\n"
00401    },
00402 
00403    { "SayNumber", pbx_builtin_saynumber,
00404    "Say Number",
00405    "  SayNumber(digits[,gender]): This application will play the sounds that\n"
00406    "correspond to the given number. Optionally, a gender may be specified.\n"
00407    "This will use the language that is currently set for the channel. See the\n"
00408    "LANGUAGE function for more information on setting the language for the channel.\n"
00409    },
00410 
00411    { "SayDigits", pbx_builtin_saydigits,
00412    "Say Digits",
00413    "  SayDigits(digits): This application will play the sounds that correspond\n"
00414    "to the digits of the given number. This will use the language that is currently\n"
00415    "set for the channel. See the LANGUAGE function for more information on setting\n"
00416    "the language for the channel.\n"
00417    },
00418 
00419    { "SayAlpha", pbx_builtin_saycharacters,
00420    "Say Alpha",
00421    "  SayAlpha(string): This application will play the sounds that correspond to\n"
00422    "the letters of the given string.\n"
00423    },
00424 
00425    { "SayPhonetic", pbx_builtin_sayphonetic,
00426    "Say Phonetic",
00427    "  SayPhonetic(string): This application will play the sounds from the phonetic\n"
00428    "alphabet that correspond to the letters in the given string.\n"
00429    },
00430 
00431    { "SetAMAFlags", pbx_builtin_setamaflags,
00432    "Set the AMA Flags",
00433    "  SetAMAFlags([flag]): This application will set the channel's AMA Flags for\n"
00434    "  billing purposes.\n"
00435    },
00436 
00437    { "SetGlobalVar", pbx_builtin_setglobalvar,
00438    "Set a global variable to a given value",
00439    "  SetGlobalVar(variable=value): This application sets a given global variable to\n"
00440    "the specified value.\n"
00441    "\n\nThis application is deprecated in favor of Set(GLOBAL(var)=value)\n"
00442    },
00443 
00444    { "Set", pbx_builtin_setvar,
00445    "Set channel variable(s) or function value(s)",
00446    "  Set(name1=value1|name2=value2|..[|options])\n"
00447    "This function can be used to set the value of channel variables or dialplan\n"
00448    "functions. It will accept up to 24 name/value pairs. When setting variables,\n"
00449    "if the variable name is prefixed with _, the variable will be inherited into\n"
00450    "channels created from the current channel. If the variable name is prefixed\n"
00451    "with __, the variable will be inherited into channels created from the current\n"
00452    "channel and all children channels.\n"
00453    "  Options:\n"
00454    "    g - Set variable globally instead of on the channel\n"
00455    "        (applies only to variables, not functions)\n"
00456    "\n\nThe use of Set to set multiple variables at once and the g flag have both\n"
00457    "been deprecated.  Please use multiple Set calls and the GLOBAL() dialplan\n"
00458    "function instead.\n"
00459    },
00460 
00461    { "ImportVar", pbx_builtin_importvar,
00462    "Import a variable from a channel into a new variable",
00463    "  ImportVar(newvar=channelname|variable): This application imports a variable\n"
00464    "from the specified channel (as opposed to the current one) and stores it as\n"
00465    "a variable in the current channel (the channel that is calling this\n"
00466    "application). Variables created by this application have the same inheritance\n"
00467    "properties as those created with the Set application. See the documentation for\n"
00468    "Set for more information.\n"
00469    },
00470 
00471    { "Wait", pbx_builtin_wait,
00472    "Waits for some time",
00473    "  Wait(seconds): This application waits for a specified number of seconds.\n"
00474    "Then, dialplan execution will continue at the next priority.\n"
00475    "  Note that the seconds can be passed with fractions of a second. For example,\n"
00476    "'1.5' will ask the application to wait for 1.5 seconds.\n"
00477    },
00478 
00479    { "WaitExten", pbx_builtin_waitexten,
00480    "Waits for an extension to be entered",
00481    "  WaitExten([seconds][|options]): This application waits for the user to enter\n"
00482    "a new extension for a specified number of seconds.\n"
00483    "  Note that the seconds can be passed with fractions of a second. For example,\n"
00484    "'1.5' will ask the application to wait for 1.5 seconds.\n"
00485    "  Options:\n"
00486    "    m[(x)] - Provide music on hold to the caller while waiting for an extension.\n"
00487    "               Optionally, specify the class for music on hold within parenthesis.\n"
00488    },
00489 
00490 };
00491 
00492 static struct ast_context *contexts;
00493 AST_MUTEX_DEFINE_STATIC(conlock);      /*!< Lock for the ast_context list */
00494 
00495 static AST_LIST_HEAD_STATIC(apps, ast_app);
00496 
00497 static AST_LIST_HEAD_STATIC(switches, ast_switch);
00498 
00499 static int stateid = 1;
00500 /* WARNING:
00501    When holding this list's lock, do _not_ do anything that will cause conlock
00502    to be taken, unless you _already_ hold it. The ast_merge_contexts_and_delete
00503    function will take the locks in conlock/hints order, so any other
00504    paths that require both locks must also take them in that order.
00505 */
00506 static AST_LIST_HEAD_STATIC(hints, ast_hint);
00507 struct ast_state_cb *statecbs;
00508 
00509 /*
00510    \note This function is special. It saves the stack so that no matter
00511    how many times it is called, it returns to the same place */
00512 int pbx_exec(struct ast_channel *c,       /*!< Channel */
00513         struct ast_app *app,     /*!< Application */
00514         void *data)        /*!< Data for execution */
00515 {
00516    int res;
00517 
00518    const char *saved_c_appl;
00519    const char *saved_c_data;
00520 
00521    if (c->cdr &&  !ast_check_hangup(c))
00522       ast_cdr_setapp(c->cdr, app->name, data);
00523 
00524    /* save channel values */
00525    saved_c_appl= c->appl;
00526    saved_c_data= c->data;
00527 
00528    c->appl = app->name;
00529    c->data = data;
00530    /* XXX remember what to to when we have linked apps to modules */
00531    if (app->module) {
00532       /* XXX LOCAL_USER_ADD(app->module) */
00533    }
00534    res = app->execute(c, data);
00535    if (app->module) {
00536       /* XXX LOCAL_USER_REMOVE(app->module) */
00537    }
00538    /* restore channel values */
00539    c->appl = saved_c_appl;
00540    c->data = saved_c_data;
00541    return res;
00542 }
00543 
00544 
00545 /*! Go no deeper than this through includes (not counting loops) */
00546 #define AST_PBX_MAX_STACK  128
00547 
00548 /*! \brief Find application handle in linked list
00549  */
00550 struct ast_app *pbx_findapp(const char *app)
00551 {
00552    struct ast_app *tmp;
00553 
00554    AST_LIST_LOCK(&apps);
00555    AST_LIST_TRAVERSE(&apps, tmp, list) {
00556       if (!strcasecmp(tmp->name, app))
00557          break;
00558    }
00559    AST_LIST_UNLOCK(&apps);
00560 
00561    return tmp;
00562 }
00563 
00564 static struct ast_switch *pbx_findswitch(const char *sw)
00565 {
00566    struct ast_switch *asw;
00567 
00568    AST_LIST_LOCK(&switches);
00569    AST_LIST_TRAVERSE(&switches, asw, list) {
00570       if (!strcasecmp(asw->name, sw))
00571          break;
00572    }
00573    AST_LIST_UNLOCK(&switches);
00574 
00575    return asw;
00576 }
00577 
00578 static inline int include_valid(struct ast_include *i)
00579 {
00580    if (!i->hastime)
00581       return 1;
00582 
00583    return ast_check_timing(&(i->timing));
00584 }
00585 
00586 static void pbx_destroy(struct ast_pbx *p)
00587 {
00588    free(p);
00589 }
00590 
00591 /*
00592  * Special characters used in patterns:
00593  * '_'   underscore is the leading character of a pattern.
00594  *    In other position it is treated as a regular char.
00595  * ' ' '-'  space and '-' are separator and ignored.
00596  * .  one or more of any character. Only allowed at the end of
00597  *    a pattern.
00598  * !  zero or more of anything. Also impacts the result of CANMATCH
00599  *    and MATCHMORE. Only allowed at the end of a pattern.
00600  *    In the core routine, ! causes a match with a return code of 2.
00601  *    In turn, depending on the search mode: (XXX check if it is implemented)
00602  *    - E_MATCH retuns 1 (does match)
00603  *    - E_MATCHMORE returns 0 (no match)
00604  *    - E_CANMATCH returns 1 (does match)
00605  *
00606  * /  should not appear as it is considered the separator of the CID info.
00607  *    XXX at the moment we may stop on this char.
00608  *
00609  * X Z N match ranges 0-9, 1-9, 2-9 respectively.
00610  * [  denotes the start of a set of character. Everything inside
00611  *    is considered literally. We can have ranges a-d and individual
00612  *    characters. A '[' and '-' can be considered literally if they
00613  *    are just before ']'.
00614  *    XXX currently there is no way to specify ']' in a range, nor \ is
00615  *    considered specially.
00616  *
00617  * When we compare a pattern with a specific extension, all characters in the extension
00618  * itself are considered literally with the only exception of '-' which is considered
00619  * as a separator and thus ignored.
00620  * XXX do we want to consider space as a separator as well ?
00621  * XXX do we want to consider the separators in non-patterns as well ?
00622  */
00623 
00624 /*!
00625  * \brief helper functions to sort extensions and patterns in the desired way,
00626  * so that more specific patterns appear first.
00627  *
00628  * ext_cmp1 compares individual characters (or sets of), returning
00629  * an int where bits 0-7 are the ASCII code of the first char in the set,
00630  * while bit 8-15 are the cardinality of the set minus 1.
00631  * This way more specific patterns (smaller cardinality) appear first.
00632  * Wildcards have a special value, so that we can directly compare them to
00633  * sets by subtracting the two values. In particular:
00634  *    0x000xx     one character, xx
00635  *    0x0yyxx     yy character set starting with xx
00636  *    0x10000     '.' (one or more of anything)
00637  *    0x20000     '!' (zero or more of anything)
00638  *    0x30000     NUL (end of string)
00639  *    0x40000     error in set.
00640  * The pointer to the string is advanced according to needs.
00641  * NOTES:
00642  * 1. the empty set is equivalent to NUL.
00643  * 2. given that a full set has always 0 as the first element,
00644  *    we could encode the special cases as 0xffXX where XX
00645  *    is 1, 2, 3, 4 as used above.
00646  */
00647 static int ext_cmp1(const char **p)
00648 {
00649    uint32_t chars[8];
00650    int c, cmin = 0xff, count = 0;
00651    const char *end;
00652 
00653    /* load, sign extend and advance pointer until we find
00654     * a valid character.
00655     */
00656    while ( (c = *(*p)++) && (c == ' ' || c == '-') )
00657       ;  /* ignore some characters */
00658 
00659    /* always return unless we have a set of chars */
00660    switch (c) {
00661    default: /* ordinary character */
00662       return 0x0000 | (c & 0xff);
00663 
00664    case 'N':   /* 2..9 */
00665       return 0x0700 | '2' ;
00666 
00667    case 'X':   /* 0..9 */
00668       return 0x0900 | '0';
00669 
00670    case 'Z':   /* 1..9 */
00671       return 0x0800 | '1';
00672 
00673    case '.':   /* wildcard */
00674       return 0x10000;
00675 
00676    case '!':   /* earlymatch */
00677       return 0x20000;   /* less specific than NULL */
00678 
00679    case '\0':  /* empty string */
00680       *p = NULL;
00681       return 0x30000;
00682 
00683    case '[':   /* pattern */
00684       break;
00685    }
00686    /* locate end of set */
00687    end = strchr(*p, ']');  
00688 
00689    if (end == NULL) {
00690       ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
00691       return 0x40000;   /* XXX make this entry go last... */
00692    }
00693 
00694    bzero(chars, sizeof(chars));  /* clear all chars in the set */
00695    for (; *p < end  ; (*p)++) {
00696       unsigned char c1, c2;   /* first-last char in range */
00697       c1 = (unsigned char)((*p)[0]);
00698       if (*p + 2 < end && (*p)[1] == '-') { /* this is a range */
00699          c2 = (unsigned char)((*p)[2]);
00700          *p += 2; /* skip a total of 3 chars */
00701       } else         /* individual character */
00702          c2 = c1;
00703       if (c1 < cmin)
00704          cmin = c1;
00705       for (; c1 <= c2; c1++) {
00706          uint32_t mask = 1 << (c1 % 32);
00707          if ( (chars[ c1 / 32 ] & mask) == 0)
00708             count += 0x100;
00709          chars[ c1 / 32 ] |= mask;
00710       }
00711    }
00712    (*p)++;
00713    return count == 0 ? 0x30000 : (count | cmin);
00714 }
00715 
00716 /*!
00717  * \brief the full routine to compare extensions in rules.
00718  */
00719 static int ext_cmp(const char *a, const char *b)
00720 {
00721    /* make sure non-patterns come first.
00722     * If a is not a pattern, it either comes first or
00723     * we use strcmp to compare the strings.
00724     */
00725    int ret = 0;
00726 
00727    if (a[0] != '_')
00728       return (b[0] == '_') ? -1 : strcmp(a, b);
00729 
00730    /* Now we know a is a pattern; if b is not, a comes first */
00731    if (b[0] != '_')
00732       return 1;
00733 #if 0 /* old mode for ext matching */
00734    return strcmp(a, b);
00735 #endif
00736    /* ok we need full pattern sorting routine */
00737    while (!ret && a && b)
00738       ret = ext_cmp1(&a) - ext_cmp1(&b);
00739    if (ret == 0)
00740       return 0;
00741    else
00742       return (ret > 0) ? 1 : -1;
00743 }
00744 
00745 /*!
00746  * When looking up extensions, we can have different requests
00747  * identified by the 'action' argument, as follows.
00748  * Note that the coding is such that the low 4 bits are the
00749  * third argument to extension_match_core.
00750  */
00751 enum ext_match_t {
00752    E_MATCHMORE =  0x00, /* extension can match but only with more 'digits' */
00753    E_CANMATCH =   0x01, /* extension can match with or without more 'digits' */
00754    E_MATCH =   0x02, /* extension is an exact match */
00755    E_MATCH_MASK = 0x03, /* mask for the argument to extension_match_core() */
00756    E_SPAWN =   0x12, /* want to spawn an extension. Requires exact match */
00757    E_FINDLABEL =  0x22  /* returns the priority for a given label. Requires exact match */
00758 };
00759 
00760 /*
00761  * Internal function for ast_extension_{match|close}
00762  * return 0 on no-match, 1 on match, 2 on early match.
00763  * mode is as follows:
00764  * E_MATCH     success only on exact match
00765  * E_MATCHMORE success only on partial match (i.e. leftover digits in pattern)
00766  * E_CANMATCH  either of the above.
00767  */
00768 
00769 static int _extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
00770 {
00771    mode &= E_MATCH_MASK;   /* only consider the relevant bits */
00772 
00773    if ( (mode == E_MATCH) && (pattern[0] == '_') && (strcasecmp(pattern,data)==0) ) /* note: if this test is left out, then _x. will not match _x. !!! */
00774       return 1;
00775 
00776    if (pattern[0] != '_') { /* not a pattern, try exact or partial match */
00777       int ld = strlen(data), lp = strlen(pattern);
00778 
00779       if (lp < ld)      /* pattern too short, cannot match */
00780          return 0;
00781       /* depending on the mode, accept full or partial match or both */
00782       if (mode == E_MATCH)
00783          return !strcmp(pattern, data); /* 1 on match, 0 on fail */
00784       if (ld == 0 || !strncasecmp(pattern, data, ld)) /* partial or full match */
00785          return (mode == E_MATCHMORE) ? lp > ld : 1; /* XXX should consider '!' and '/' ? */
00786       else
00787          return 0;
00788    }
00789    pattern++; /* skip leading _ */
00790    /*
00791     * XXX below we stop at '/' which is a separator for the CID info. However we should
00792     * not store '/' in the pattern at all. When we insure it, we can remove the checks.
00793     */
00794    while (*data && *pattern && *pattern != '/') {
00795       const char *end;
00796 
00797       if (*data == '-') { /* skip '-' in data (just a separator) */
00798          data++;
00799          continue;
00800       }
00801       switch (toupper(*pattern)) {
00802       case '[':   /* a range */
00803          end = strchr(pattern+1, ']'); /* XXX should deal with escapes ? */
00804          if (end == NULL) {
00805             ast_log(LOG_WARNING, "Wrong usage of [] in the extension\n");
00806             return 0;   /* unconditional failure */
00807          }
00808          for (pattern++; pattern != end; pattern++) {
00809             if (pattern+2 < end && pattern[1] == '-') { /* this is a range */
00810                if (*data >= pattern[0] && *data <= pattern[2])
00811                   break;   /* match found */
00812                else {
00813                   pattern += 2; /* skip a total of 3 chars */
00814                   continue;
00815                }
00816             } else if (*data == pattern[0])
00817                break;   /* match found */
00818          }
00819          if (pattern == end)
00820             return 0;
00821          pattern = end; /* skip and continue */
00822          break;
00823       case 'N':
00824          if (*data < '2' || *data > '9')
00825             return 0;
00826          break;
00827       case 'X':
00828          if (*data < '0' || *data > '9')
00829             return 0;
00830          break;
00831       case 'Z':
00832          if (*data < '1' || *data > '9')
00833             return 0;
00834          break;
00835       case '.':   /* Must match, even with more digits */
00836          return 1;
00837       case '!':   /* Early match */
00838          return 2;
00839       case ' ':
00840       case '-':   /* Ignore these in patterns */
00841          data--; /* compensate the final data++ */
00842          break;
00843       default:
00844          if (*data != *pattern)
00845             return 0;
00846       }
00847       data++;
00848       pattern++;
00849    }
00850    if (*data)        /* data longer than pattern, no match */
00851       return 0;
00852    /*
00853     * match so far, but ran off the end of the data.
00854     * Depending on what is next, determine match or not.
00855     */
00856    if (*pattern == '\0' || *pattern == '/')  /* exact match */
00857       return (mode == E_MATCHMORE) ? 0 : 1;  /* this is a failure for E_MATCHMORE */
00858    else if (*pattern == '!')        /* early match */
00859       return 2;
00860    else                 /* partial match */
00861       return (mode == E_MATCH) ? 0 : 1;   /* this is a failure for E_MATCH */
00862 }
00863 
00864 /*
00865  * Wrapper around _extension_match_core() to do performance measurement
00866  * using the profiling code.
00867  */
00868 static int extension_match_core(const char *pattern, const char *data, enum ext_match_t mode)
00869 {
00870    int i;
00871    static int prof_id = -2;   /* marker for 'unallocated' id */
00872    if (prof_id == -2)
00873       prof_id = ast_add_profile("ext_match", 0);
00874    ast_mark(prof_id, 1);
00875    i = _extension_match_core(pattern, data, mode);
00876    ast_mark(prof_id, 0);
00877    return i;
00878 }
00879 
00880 int ast_extension_match(const char *pattern, const char *data)
00881 {
00882    return extension_match_core(pattern, data, E_MATCH);
00883 }
00884 
00885 int ast_extension_close(const char *pattern, const char *data, int needmore)
00886 {
00887    if (needmore != E_MATCHMORE && needmore != E_CANMATCH)
00888       ast_log(LOG_WARNING, "invalid argument %d\n", needmore);
00889    return extension_match_core(pattern, data, needmore);
00890 }
00891 
00892 struct ast_context *ast_context_find(const char *name)
00893 {
00894    struct ast_context *tmp = NULL;
00895    ast_mutex_lock(&conlock);
00896    while ( (tmp = ast_walk_contexts(tmp)) ) {
00897       if (!name || !strcasecmp(name, tmp->name))
00898          break;
00899    }
00900    ast_mutex_unlock(&conlock);
00901    return tmp;
00902 }
00903 
00904 #define STATUS_NO_CONTEXT  1
00905 #define STATUS_NO_EXTENSION   2
00906 #define STATUS_NO_PRIORITY 3
00907 #define STATUS_NO_LABEL    4
00908 #define STATUS_SUCCESS     5
00909 
00910 static int matchcid(const char *cidpattern, const char *callerid)
00911 {
00912    /* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
00913       failing to get a number should count as a match, otherwise not */
00914 
00915    if (ast_strlen_zero(callerid))
00916       return ast_strlen_zero(cidpattern) ? 1 : 0;
00917 
00918    return ast_extension_match(cidpattern, callerid);
00919 }
00920 
00921 /* request and result for pbx_find_extension */
00922 struct pbx_find_info {
00923 #if 0
00924    const char *context;
00925    const char *exten;
00926    int priority;
00927 #endif
00928 
00929    char *incstack[AST_PBX_MAX_STACK];      /* filled during the search */
00930    int stacklen;                   /* modified during the search */
00931    int status;                     /* set on return */
00932    struct ast_switch *swo;         /* set on return */
00933    const char *data;               /* set on return */
00934    const char *foundcontext;       /* set on return */
00935 };
00936 
00937 static struct ast_exten *pbx_find_extension(struct ast_channel *chan,
00938    struct ast_context *bypass, struct pbx_find_info *q,
00939    const char *context, const char *exten, int priority,
00940    const char *label, const char *callerid, enum ext_match_t action)
00941 {
00942    int x, res;
00943    struct ast_context *tmp;
00944    struct ast_exten *e, *eroot;
00945    struct ast_include *i;
00946    struct ast_sw *sw;
00947 
00948    /* Initialize status if appropriate */
00949    if (q->stacklen == 0) {
00950       q->status = STATUS_NO_CONTEXT;
00951       q->swo = NULL;
00952       q->data = NULL;
00953       q->foundcontext = NULL;
00954    }
00955    /* Check for stack overflow */
00956    if (q->stacklen >= AST_PBX_MAX_STACK) {
00957       ast_log(LOG_WARNING, "Maximum PBX stack exceeded\n");
00958       return NULL;
00959    }
00960    /* Check first to see if we've already been checked */
00961    for (x = 0; x < q->stacklen; x++) {
00962       if (!strcasecmp(q->incstack[x], context))
00963          return NULL;
00964    }
00965    if (bypass) /* bypass means we only look there */
00966       tmp = bypass;
00967    else {   /* look in contexts */
00968       tmp = NULL;
00969       while ((tmp = ast_walk_contexts(tmp)) ) {
00970          if (!strcmp(tmp->name, context))
00971             break;
00972       }
00973       if (!tmp)
00974          return NULL;
00975    }
00976    if (q->status < STATUS_NO_EXTENSION)
00977       q->status = STATUS_NO_EXTENSION;
00978 
00979    /* scan the list trying to match extension and CID */
00980    eroot = NULL;
00981    while ( (eroot = ast_walk_context_extensions(tmp, eroot)) ) {
00982       int match = extension_match_core(eroot->exten, exten, action);
00983       /* 0 on fail, 1 on match, 2 on earlymatch */
00984 
00985       if (!match || (eroot->matchcid && !matchcid(eroot->cidmatch, callerid)))
00986          continue;   /* keep trying */
00987       if (match == 2 && action == E_MATCHMORE) {
00988          /* We match an extension ending in '!'.
00989           * The decision in this case is final and is NULL (no match).
00990           */
00991          return NULL;
00992       }
00993       /* found entry, now look for the right priority */
00994       if (q->status < STATUS_NO_PRIORITY)
00995          q->status = STATUS_NO_PRIORITY;
00996       e = NULL;
00997       while ( (e = ast_walk_extension_priorities(eroot, e)) ) {
00998          /* Match label or priority */
00999          if (action == E_FINDLABEL) {
01000             if (q->status < STATUS_NO_LABEL)
01001                q->status = STATUS_NO_LABEL;
01002             if (label && e->label && !strcmp(label, e->label))
01003                break;   /* found it */
01004          } else if (e->priority == priority) {
01005             break;   /* found it */
01006          } /* else keep searching */
01007       }
01008       if (e) { /* found a valid match */
01009          q->status = STATUS_SUCCESS;
01010          q->foundcontext = context;
01011          return e;
01012       }
01013    }
01014    /* Check alternative switches */
01015    AST_LIST_TRAVERSE(&tmp->alts, sw, list) {
01016       struct ast_switch *asw = pbx_findswitch(sw->name);
01017       ast_switch_f *aswf = NULL;
01018       char *datap;
01019 
01020       if (!asw) {
01021          ast_log(LOG_WARNING, "No such switch '%s'\n", sw->name);
01022          continue;
01023       }
01024       /* Substitute variables now */
01025       if (sw->eval)
01026          pbx_substitute_variables_helper(chan, sw->data, sw->tmpdata, SWITCH_DATA_LENGTH - 1);
01027 
01028       /* equivalent of extension_match_core() at the switch level */
01029       if (action == E_CANMATCH)
01030          aswf = asw->canmatch;
01031       else if (action == E_MATCHMORE)
01032          aswf = asw->matchmore;
01033       else /* action == E_MATCH */
01034          aswf = asw->exists;
01035       datap = sw->eval ? sw->tmpdata : sw->data;
01036       res = !aswf ? 0 : aswf(chan, context, exten, priority, callerid, datap);
01037       if (res) {  /* Got a match */
01038          q->swo = asw;
01039          q->data = datap;
01040          q->foundcontext = context;
01041          /* XXX keep status = STATUS_NO_CONTEXT ? */
01042          return NULL;
01043       }
01044    }
01045    q->incstack[q->stacklen++] = tmp->name;   /* Setup the stack */
01046    /* Now try any includes we have in this context */
01047    for (i = tmp->includes; i; i = i->next) {
01048       if (include_valid(i)) {
01049          if ((e = pbx_find_extension(chan, bypass, q, i->rname, exten, priority, label, callerid, action)))
01050             return e;
01051          if (q->swo)
01052             return NULL;
01053       }
01054    }
01055    return NULL;
01056 }
01057 
01058 /*! \brief extract offset:length from variable name.
01059  * Returns 1 if there is a offset:length part, which is
01060  * trimmed off (values go into variables)
01061  */
01062 static int parse_variable_name(char *var, int *offset, int *length, int *isfunc)
01063 {
01064    int parens=0;
01065 
01066    *offset = 0;
01067    *length = INT_MAX;
01068    *isfunc = 0;
01069    for (; *var; var++) {
01070       if (*var == '(') {
01071          (*isfunc)++;
01072          parens++;
01073       } else if (*var == ')') {
01074          parens--;
01075       } else if (*var == ':' && parens == 0) {
01076          *var++ = '\0';
01077          sscanf(var, "%d:%d", offset, length);
01078          return 1; /* offset:length valid */
01079       }
01080    }
01081    return 0;
01082 }
01083 
01084 /*! \brief takes a substring. It is ok to call with value == workspace.
01085  *
01086  * offset < 0 means start from the end of the string and set the beginning
01087  *   to be that many characters back.
01088  * length is the length of the substring.  A value less than 0 means to leave
01089  * that many off the end.
01090  * Always return a copy in workspace.
01091  */
01092 static char *substring(const char *value, int offset, int length, char *workspace, size_t workspace_len)
01093 {
01094    char *ret = workspace;
01095    int lr;  /* length of the input string after the copy */
01096 
01097    ast_copy_string(workspace, value, workspace_len); /* always make a copy */
01098 
01099    lr = strlen(ret); /* compute length after copy, so we never go out of the workspace */
01100 
01101    /* Quick check if no need to do anything */
01102    if (offset == 0 && length >= lr) /* take the whole string */
01103       return ret;
01104 
01105    if (offset < 0)   {  /* translate negative offset into positive ones */
01106       offset = lr + offset;
01107       if (offset < 0) /* If the negative offset was greater than the length of the string, just start at the beginning */
01108          offset = 0;
01109    }
01110 
01111    /* too large offset result in empty string so we know what to return */
01112    if (offset >= lr)
01113       return ret + lr;  /* the final '\0' */
01114 
01115    ret += offset;    /* move to the start position */
01116    if (length >= 0 && length < lr - offset)  /* truncate if necessary */
01117       ret[length] = '\0';
01118    else if (length < 0) {
01119       if (lr > offset - length) /* After we remove from the front and from the rear, is there anything left? */
01120          ret[lr + length - offset] = '\0';
01121       else
01122          ret[0] = '\0';
01123    }
01124 
01125    return ret;
01126 }
01127 
01128 /*! \brief  Support for Asterisk built-in variables and functions in the dialplan
01129 
01130 \note See also
01131    - \ref AstVar  Channel variables
01132    - \ref AstCauses The HANGUPCAUSE variable
01133  */
01134 void pbx_retrieve_variable(struct ast_channel *c, const char *var, char **ret, char *workspace, int workspacelen, struct varshead *headp)
01135 {
01136    const char not_found = '\0';
01137    char *tmpvar;
01138    const char *s; /* the result */
01139    int offset, length;
01140    int i, need_substring;
01141    struct varshead *places[2] = { headp, &globals };  /* list of places where we may look */
01142 
01143    if (c) {
01144       places[0] = &c->varshead;
01145    }
01146    /*
01147     * Make a copy of var because parse_variable_name() modifies the string.
01148     * Then if called directly, we might need to run substring() on the result;
01149     * remember this for later in 'need_substring', 'offset' and 'length'
01150     */
01151    tmpvar = ast_strdupa(var); /* parse_variable_name modifies the string */
01152    need_substring = parse_variable_name(tmpvar, &offset, &length, &i /* ignored */);
01153 
01154    /*
01155     * Look first into predefined variables, then into variable lists.
01156     * Variable 's' points to the result, according to the following rules:
01157     * s == &not_found (set at the beginning) means that we did not find a
01158     * matching variable and need to look into more places.
01159     * If s != &not_found, s is a valid result string as follows:
01160     * s = NULL if the variable does not have a value;
01161     * you typically do this when looking for an unset predefined variable.
01162     * s = workspace if the result has been assembled there;
01163     * typically done when the result is built e.g. with an snprintf(),
01164     * so we don't need to do an additional copy.
01165     * s != workspace in case we have a string, that needs to be copied
01166     * (the ast_copy_string is done once for all at the end).
01167     * Typically done when the result is already available in some string.
01168     */
01169    s = &not_found;   /* default value */
01170    if (c) { /* This group requires a valid channel */
01171       /* Names with common parts are looked up a piece at a time using strncmp. */
01172       if (!strncmp(var, "CALL", 4)) {
01173          if (!strncmp(var + 4, "ING", 3)) {
01174             if (!strcmp(var + 7, "PRES")) {        /* CALLINGPRES */
01175                snprintf(workspace, workspacelen, "%d", c->cid.cid_pres);
01176                s = workspace;
01177             } else if (!strcmp(var + 7, "ANI2")) {    /* CALLINGANI2 */
01178                snprintf(workspace, workspacelen, "%d", c->cid.cid_ani2);
01179                s = workspace;
01180             } else if (!strcmp(var + 7, "TON")) {     /* CALLINGTON */
01181                snprintf(workspace, workspacelen, "%d", c->cid.cid_ton);
01182                s = workspace;
01183             } else if (!strcmp(var + 7, "TNS")) {     /* CALLINGTNS */
01184                snprintf(workspace, workspacelen, "%d", c->cid.cid_tns);
01185                s = workspace;
01186             }
01187          }
01188       } else if (!strcmp(var, "HINT")) {
01189          s = ast_get_hint(workspace, workspacelen, NULL, 0, c, c->context, c->exten) ? workspace : NULL;
01190       } else if (!strcmp(var, "HINTNAME")) {
01191          s = ast_get_hint(NULL, 0, workspace, workspacelen, c, c->context, c->exten) ? workspace : NULL;
01192       } else if (!strcmp(var, "EXTEN")) {
01193          s = c->exten;
01194       } else if (!strcmp(var, "CONTEXT")) {
01195          s = c->context;
01196       } else if (!strcmp(var, "PRIORITY")) {
01197          snprintf(workspace, workspacelen, "%d", c->priority);
01198          s = workspace;
01199       } else if (!strcmp(var, "CHANNEL")) {
01200          s = c->name;
01201       } else if (!strcmp(var, "UNIQUEID")) {
01202          s = c->uniqueid;
01203       } else if (!strcmp(var, "HANGUPCAUSE")) {
01204          snprintf(workspace, workspacelen, "%d", c->hangupcause);
01205          s = workspace;
01206       }
01207    }
01208    if (s == &not_found) { /* look for more */
01209       if (!strcmp(var, "EPOCH")) {
01210          snprintf(workspace, workspacelen, "%u",(int)time(NULL));
01211          s = workspace;
01212       } else if (!strcmp(var, "SYSTEMNAME")) {
01213          s = ast_config_AST_SYSTEM_NAME;
01214       }
01215    }
01216    /* if not found, look into chanvars or global vars */
01217    for (i = 0; s == &not_found && i < (sizeof(places) / sizeof(places[0])); i++) {
01218       struct ast_var_t *variables;
01219       if (!places[i])
01220          continue;
01221       if (places[i] == &globals)
01222          ast_mutex_lock(&globalslock);
01223       AST_LIST_TRAVERSE(places[i], variables, entries) {
01224          if (strcasecmp(ast_var_name(variables), var)==0) {
01225             s = ast_var_value(variables);
01226             break;
01227          }
01228       }
01229       if (places[i] == &globals)
01230          ast_mutex_unlock(&globalslock);
01231    }
01232    if (s == &not_found || s == NULL)
01233       *ret = NULL;
01234    else {
01235       if (s != workspace)
01236          ast_copy_string(workspace, s, workspacelen);
01237       *ret = workspace;
01238       if (need_substring)
01239          *ret = substring(*ret, offset, length, workspace, workspacelen);
01240    }
01241 }
01242 
01243 /*! \brief CLI function to show installed custom functions
01244     \addtogroup CLI_functions
01245  */
01246 static int handle_show_functions_deprecated(int fd, int argc, char *argv[])
01247 {
01248    struct ast_custom_function *acf;
01249    int count_acf = 0;
01250    int like = 0;
01251 
01252    if (argc == 4 && (!strcmp(argv[2], "like")) ) {
01253       like = 1;
01254    } else if (argc != 2) {
01255       return RESULT_SHOWUSAGE;
01256    }
01257 
01258    ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
01259 
01260    AST_LIST_LOCK(&acf_root);
01261    AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
01262       if (!like || strstr(acf->name, argv[3])) {
01263          count_acf++;
01264          ast_cli(fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
01265       }
01266    }
01267    AST_LIST_UNLOCK(&acf_root);
01268 
01269    ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
01270 
01271    return RESULT_SUCCESS;
01272 }
01273 static int handle_show_functions(int fd, int argc, char *argv[])
01274 {
01275    struct ast_custom_function *acf;
01276    int count_acf = 0;
01277    int like = 0;
01278 
01279    if (argc == 5 && (!strcmp(argv[3], "like")) ) {
01280       like = 1;
01281    } else if (argc != 3) {
01282       return RESULT_SHOWUSAGE;
01283    }
01284 
01285    ast_cli(fd, "%s Custom Functions:\n--------------------------------------------------------------------------------\n", like ? "Matching" : "Installed");
01286 
01287    AST_LIST_LOCK(&acf_root);
01288    AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
01289       if (!like || strstr(acf->name, argv[4])) {
01290          count_acf++;
01291          ast_cli(fd, "%-20.20s  %-35.35s  %s\n", acf->name, acf->syntax, acf->synopsis);
01292       }
01293    }
01294    AST_LIST_UNLOCK(&acf_root);
01295 
01296    ast_cli(fd, "%d %scustom functions installed.\n", count_acf, like ? "matching " : "");
01297 
01298    return RESULT_SUCCESS;
01299 }
01300 
01301 static int handle_show_function_deprecated(int fd, int argc, char *argv[])
01302 {
01303    struct ast_custom_function *acf;
01304    /* Maximum number of characters added by terminal coloring is 22 */
01305    char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
01306    char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
01307    char stxtitle[40], *syntax = NULL;
01308    int synopsis_size, description_size, syntax_size;
01309 
01310    if (argc < 3)
01311       return RESULT_SHOWUSAGE;
01312 
01313    if (!(acf = ast_custom_function_find(argv[2]))) {
01314       ast_cli(fd, "No function by that name registered.\n");
01315       return RESULT_FAILURE;
01316 
01317    }
01318 
01319    if (acf->synopsis)
01320       synopsis_size = strlen(acf->synopsis) + 23;
01321    else
01322       synopsis_size = strlen("Not available") + 23;
01323    synopsis = alloca(synopsis_size);
01324 
01325    if (acf->desc)
01326       description_size = strlen(acf->desc) + 23;
01327    else
01328       description_size = strlen("Not available") + 23;
01329    description = alloca(description_size);
01330 
01331    if (acf->syntax)
01332       syntax_size = strlen(acf->syntax) + 23;
01333    else
01334       syntax_size = strlen("Not available") + 23;
01335    syntax = alloca(syntax_size);
01336 
01337    snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
01338    term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
01339    term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
01340    term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
01341    term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
01342    term_color(syntax,
01343          acf->syntax ? acf->syntax : "Not available",
01344          COLOR_CYAN, 0, syntax_size);
01345    term_color(synopsis,
01346          acf->synopsis ? acf->synopsis : "Not available",
01347          COLOR_CYAN, 0, synopsis_size);
01348    term_color(description,
01349          acf->desc ? acf->desc : "Not available",
01350          COLOR_CYAN, 0, description_size);
01351 
01352    ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
01353 
01354    return RESULT_SUCCESS;
01355 }
01356 
01357 static int handle_show_function(int fd, int argc, char *argv[])
01358 {
01359    struct ast_custom_function *acf;
01360    /* Maximum number of characters added by terminal coloring is 22 */
01361    char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
01362    char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
01363    char stxtitle[40], *syntax = NULL;
01364    int synopsis_size, description_size, syntax_size;
01365 
01366    if (argc < 4)
01367       return RESULT_SHOWUSAGE;
01368 
01369    if (!(acf = ast_custom_function_find(argv[3]))) {
01370       ast_cli(fd, "No function by that name registered.\n");
01371       return RESULT_FAILURE;
01372 
01373    }
01374 
01375    if (acf->synopsis)
01376       synopsis_size = strlen(acf->synopsis) + 23;
01377    else
01378       synopsis_size = strlen("Not available") + 23;
01379    synopsis = alloca(synopsis_size);
01380 
01381    if (acf->desc)
01382       description_size = strlen(acf->desc) + 23;
01383    else
01384       description_size = strlen("Not available") + 23;
01385    description = alloca(description_size);
01386 
01387    if (acf->syntax)
01388       syntax_size = strlen(acf->syntax) + 23;
01389    else
01390       syntax_size = strlen("Not available") + 23;
01391    syntax = alloca(syntax_size);
01392 
01393    snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about function '%s' =- \n\n", acf->name);
01394    term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
01395    term_color(stxtitle, "[Syntax]\n", COLOR_MAGENTA, 0, 40);
01396    term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
01397    term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
01398    term_color(syntax,
01399          acf->syntax ? acf->syntax : "Not available",
01400          COLOR_CYAN, 0, syntax_size);
01401    term_color(synopsis,
01402          acf->synopsis ? acf->synopsis : "Not available",
01403          COLOR_CYAN, 0, synopsis_size);
01404    term_color(description,
01405          acf->desc ? acf->desc : "Not available",
01406          COLOR_CYAN, 0, description_size);
01407 
01408    ast_cli(fd,"%s%s%s\n\n%s%s\n\n%s%s\n", infotitle, stxtitle, syntax, syntitle, synopsis, destitle, description);
01409 
01410    return RESULT_SUCCESS;
01411 }
01412 
01413 static char *complete_show_function(const char *line, const char *word, int pos, int state)
01414 {
01415    struct ast_custom_function *acf;
01416    char *ret = NULL;
01417    int which = 0;
01418    int wordlen = strlen(word);
01419 
01420    /* case-insensitive for convenience in this 'complete' function */
01421    AST_LIST_LOCK(&acf_root);
01422    AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
01423       if (!strncasecmp(word, acf->name, wordlen) && ++which > state) {
01424          ret = strdup(acf->name);
01425          break;
01426       }
01427    }
01428    AST_LIST_UNLOCK(&acf_root);
01429 
01430    return ret;
01431 }
01432 
01433 struct ast_custom_function *ast_custom_function_find(const char *name)
01434 {
01435    struct ast_custom_function *acf = NULL;
01436 
01437    AST_LIST_LOCK(&acf_root);
01438    AST_LIST_TRAVERSE(&acf_root, acf, acflist) {
01439       if (!strcmp(name, acf->name))
01440          break;
01441    }
01442    AST_LIST_UNLOCK(&acf_root);
01443 
01444    return acf;
01445 }
01446 
01447 int ast_custom_function_unregister(struct ast_custom_function *acf)
01448 {
01449    struct ast_custom_function *cur;
01450 
01451    if (!acf)
01452       return -1;
01453 
01454    AST_LIST_LOCK(&acf_root);
01455    AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
01456       if (cur == acf) {
01457          AST_LIST_REMOVE_CURRENT(&acf_root, acflist);
01458          if (option_verbose > 1)
01459             ast_verbose(VERBOSE_PREFIX_2 "Unregistered custom function %s\n", acf->name);
01460          break;
01461       }
01462    }
01463    AST_LIST_TRAVERSE_SAFE_END
01464    AST_LIST_UNLOCK(&acf_root);
01465 
01466    return acf ? 0 : -1;
01467 }
01468 
01469 int ast_custom_function_register(struct ast_custom_function *acf)
01470 {
01471    struct ast_custom_function *cur;
01472 
01473    if (!acf)
01474       return -1;
01475 
01476    AST_LIST_LOCK(&acf_root);
01477 
01478    if (ast_custom_function_find(acf->name)) {
01479       ast_log(LOG_ERROR, "Function %s already registered.\n", acf->name);
01480       AST_LIST_UNLOCK(&acf_root);
01481       return -1;
01482    }
01483 
01484    /* Store in alphabetical order */
01485    AST_LIST_TRAVERSE_SAFE_BEGIN(&acf_root, cur, acflist) {
01486       if (strcasecmp(acf->name, cur->name) < 0) {
01487          AST_LIST_INSERT_BEFORE_CURRENT(&acf_root, acf, acflist);
01488          break;
01489       }
01490    }
01491    AST_LIST_TRAVERSE_SAFE_END
01492    if (!cur)
01493       AST_LIST_INSERT_TAIL(&acf_root, acf, acflist);
01494 
01495    AST_LIST_UNLOCK(&acf_root);
01496 
01497    if (option_verbose > 1)
01498       ast_verbose(VERBOSE_PREFIX_2 "Registered custom function %s\n", acf->name);
01499 
01500    return 0;
01501 }
01502 
01503 /*! \brief return a pointer to the arguments of the function,
01504  * and terminates the function name with '\\0'
01505  */
01506 static char *func_args(char *function)
01507 {
01508    char *args = strchr(function, '(');
01509 
01510    if (!args)
01511       ast_log(LOG_WARNING, "Function doesn't contain parentheses.  Assuming null argument.\n");
01512    else {
01513       char *p;
01514       *args++ = '\0';
01515       if ((p = strrchr(args, ')')) )
01516          *p = '\0';
01517       else
01518          ast_log(LOG_WARNING, "Can't find trailing parenthesis?\n");
01519    }
01520    return args;
01521 }
01522 
01523 int ast_func_read(struct ast_channel *chan, char *function, char *workspace, size_t len)
01524 {
01525    char *args = func_args(function);
01526    struct ast_custom_function *acfptr = ast_custom_function_find(function);
01527 
01528    if (acfptr == NULL)
01529       ast_log(LOG_ERROR, "Function %s not registered\n", function);
01530    else if (!acfptr->read)
01531       ast_log(LOG_ERROR, "Function %s cannot be read\n", function);
01532    else
01533       return acfptr->read(chan, function, args, workspace, len);
01534    return -1;
01535 }
01536 
01537 int ast_func_write(struct ast_channel *chan, char *function, const char *value)
01538 {
01539    char *args = func_args(function);
01540    struct ast_custom_function *acfptr = ast_custom_function_find(function);
01541 
01542    if (acfptr == NULL)
01543       ast_log(LOG_ERROR, "Function %s not registered\n", function);
01544    else if (!acfptr->write)
01545       ast_log(LOG_ERROR, "Function %s cannot be written to\n", function);
01546    else
01547       return acfptr->write(chan, function, args, value);
01548 
01549    return -1;
01550 }
01551 
01552 static void pbx_substitute_variables_helper_full(struct ast_channel *c, struct varshead *headp, const char *cp1, char *cp2, int count)
01553 {
01554    /* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
01555       zero-filled */
01556    char *cp4;
01557    const char *tmp, *whereweare;
01558    int length, offset, offset2, isfunction;
01559    char *workspace = NULL;
01560    char *ltmp = NULL, *var = NULL;
01561    char *nextvar, *nextexp, *nextthing;
01562    char *vars, *vare;
01563    int pos, brackets, needsub, len;
01564 
01565    whereweare=tmp=cp1;
01566    while (!ast_strlen_zero(whereweare) && count) {
01567       /* Assume we're copying the whole remaining string */
01568       pos = strlen(whereweare);
01569       nextvar = NULL;
01570       nextexp = NULL;
01571       nextthing = strchr(whereweare, '$');
01572       if (nextthing) {
01573          switch(nextthing[1]) {
01574          case '{':
01575             nextvar = nextthing;
01576             pos = nextvar - whereweare;
01577             break;
01578          case '[':
01579             nextexp = nextthing;
01580             pos = nextexp - whereweare;
01581             break;
01582          }
01583       }
01584 
01585       if (pos) {
01586          /* Can't copy more than 'count' bytes */
01587          if (pos > count)
01588             pos = count;
01589 
01590          /* Copy that many bytes */
01591          memcpy(cp2, whereweare, pos);
01592 
01593          count -= pos;
01594          cp2 += pos;
01595          whereweare += pos;
01596       }
01597 
01598       if (nextvar) {
01599          /* We have a variable.  Find the start and end, and determine
01600             if we are going to have to recursively call ourselves on the
01601             contents */
01602          vars = vare = nextvar + 2;
01603          brackets = 1;
01604          needsub = 0;
01605 
01606          /* Find the end of it */
01607          while (brackets && *vare) {
01608             if ((vare[0] == '$') && (vare[1] == '{')) {
01609                needsub++;
01610             } else if (vare[0] == '{') {
01611                brackets++;
01612             } else if (vare[0] == '}') {
01613                brackets--;
01614             } else if ((vare[0] == '$') && (vare[1] == '['))
01615                needsub++;
01616             vare++;
01617          }
01618          if (brackets)
01619             ast_log(LOG_NOTICE, "Error in extension logic (missing '}')\n");
01620          len = vare - vars - 1;
01621 
01622          /* Skip totally over variable string */
01623          whereweare += (len + 3);
01624 
01625          if (!var)
01626             var = alloca(VAR_BUF_SIZE);
01627 
01628          /* Store variable name (and truncate) */
01629          ast_copy_string(var, vars, len + 1);
01630 
01631          /* Substitute if necessary */
01632          if (needsub) {
01633             if (!ltmp)
01634                ltmp = alloca(VAR_BUF_SIZE);
01635 
01636             memset(ltmp, 0, VAR_BUF_SIZE);
01637             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
01638             vars = ltmp;
01639          } else {
01640             vars = var;
01641          }
01642 
01643          if (!workspace)
01644             workspace = alloca(VAR_BUF_SIZE);
01645 
01646          workspace[0] = '\0';
01647 
01648          parse_variable_name(vars, &offset, &offset2, &isfunction);
01649          if (isfunction) {
01650             /* Evaluate function */
01651             if (c || !headp)
01652                cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
01653             else {
01654                struct varshead old;
01655                struct ast_channel *c = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/%p", vars);
01656                if (c) {
01657                   memcpy(&old, &c->varshead, sizeof(old));
01658                   memcpy(&c->varshead, headp, sizeof(c->varshead));
01659                   cp4 = ast_func_read(c, vars, workspace, VAR_BUF_SIZE) ? NULL : workspace;
01660                   /* Don't deallocate the varshead that was passed in */
01661                   memcpy(&c->varshead, &old, sizeof(c->varshead));
01662                   ast_channel_free(c);
01663                } else
01664                   ast_log(LOG_ERROR, "Unable to allocate bogus channel for variable substitution.  Function results may be blank.\n");
01665             }
01666 
01667             if (option_debug)
01668                ast_log(LOG_DEBUG, "Function result is '%s'\n", cp4 ? cp4 : "(null)");
01669          } else {
01670             /* Retrieve variable value */
01671             pbx_retrieve_variable(c, vars, &cp4, workspace, VAR_BUF_SIZE, headp);
01672          }
01673          if (cp4) {
01674             cp4 = substring(cp4, offset, offset2, workspace, VAR_BUF_SIZE);
01675 
01676             length = strlen(cp4);
01677             if (length > count)
01678                length = count;
01679             memcpy(cp2, cp4, length);
01680             count -= length;
01681             cp2 += length;
01682          }
01683       } else if (nextexp) {
01684          /* We have an expression.  Find the start and end, and determine
01685             if we are going to have to recursively call ourselves on the
01686             contents */
01687          vars = vare = nextexp + 2;
01688          brackets = 1;
01689          needsub = 0;
01690 
01691          /* Find the end of it */
01692          while(brackets && *vare) {
01693             if ((vare[0] == '$') && (vare[1] == '[')) {
01694                needsub++;
01695                brackets++;
01696                vare++;
01697             } else if (vare[0] == '[') {
01698                brackets++;
01699             } else if (vare[0] == ']') {
01700                brackets--;
01701             } else if ((vare[0] == '$') && (vare[1] == '{')) {
01702                needsub++;
01703                vare++;
01704             }
01705             vare++;
01706          }
01707          if (brackets)
01708             ast_log(LOG_NOTICE, "Error in extension logic (missing ']')\n");
01709          len = vare - vars - 1;
01710 
01711          /* Skip totally over expression */
01712          whereweare += (len + 3);
01713 
01714          if (!var)
01715             var = alloca(VAR_BUF_SIZE);
01716 
01717          /* Store variable name (and truncate) */
01718          ast_copy_string(var, vars, len + 1);
01719 
01720          /* Substitute if necessary */
01721          if (needsub) {
01722             if (!ltmp)
01723                ltmp = alloca(VAR_BUF_SIZE);
01724 
01725             memset(ltmp, 0, VAR_BUF_SIZE);
01726             pbx_substitute_variables_helper_full(c, headp, var, ltmp, VAR_BUF_SIZE - 1);
01727             vars = ltmp;
01728          } else {
01729             vars = var;
01730          }
01731 
01732          length = ast_expr(vars, cp2, count);
01733 
01734          if (length) {
01735             if (option_debug)
01736                ast_log(LOG_DEBUG, "Expression result is '%s'\n", cp2);
01737             count -= length;
01738             cp2 += length;
01739          }
01740       } else
01741          break;
01742    }
01743 }
01744 
01745 void pbx_substitute_variables_helper(struct ast_channel *c, const char *cp1, char *cp2, int count)
01746 {
01747    pbx_substitute_variables_helper_full(c, (c) ? &c->varshead : NULL, cp1, cp2, count);
01748 }
01749 
01750 void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count)
01751 {
01752    pbx_substitute_variables_helper_full(NULL, headp, cp1, cp2, count);
01753 }
01754 
01755 static void pbx_substitute_variables(char *passdata, int datalen, struct ast_channel *c, struct ast_exten *e)
01756 {
01757    memset(passdata, 0, datalen);
01758 
01759    /* No variables or expressions in e->data, so why scan it? */
01760    if (e->data && !strchr(e->data, '$') && !strstr(e->data,"${") && !strstr(e->data,"$[") && !strstr(e->data,"$(")) {
01761       ast_copy_string(passdata, e->data, datalen);
01762       return;
01763    }
01764 
01765    pbx_substitute_variables_helper(c, e->data, passdata, datalen - 1);
01766 }
01767 
01768 /*! \brief The return value depends on the action:
01769  *
01770  * E_MATCH, E_CANMATCH, E_MATCHMORE require a real match,
01771  * and return 0 on failure, -1 on match;
01772  * E_FINDLABEL maps the label to a priority, and returns
01773  * the priority on success, ... XXX
01774  * E_SPAWN, spawn an application,
01775  * and return 0 on success, -1 on failure.
01776  */
01777 static int pbx_extension_helper(struct ast_channel *c, struct ast_context *con,
01778    const char *context, const char *exten, int priority,
01779    const char *label, const char *callerid, enum ext_match_t action)
01780 {
01781    struct ast_exten *e;
01782    struct ast_app *app;
01783    int res;
01784    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */
01785    char passdata[EXT_DATA_SIZE];
01786 
01787    int matching_action = (action == E_MATCH || action == E_CANMATCH || action == E_MATCHMORE);
01788 
01789    ast_mutex_lock(&conlock);
01790    e = pbx_find_extension(c, con, &q, context, exten, priority, label, callerid, action);
01791    if (e) {
01792       if (matching_action) {
01793          ast_mutex_unlock(&conlock);
01794          return -1;  /* success, we found it */
01795       } else if (action == E_FINDLABEL) { /* map the label to a priority */
01796          res = e->priority;
01797          ast_mutex_unlock(&conlock);
01798          return res; /* the priority we were looking for */
01799       } else { /* spawn */
01800          app = pbx_findapp(e->app);
01801          ast_mutex_unlock(&conlock);
01802          if (!app) {
01803             ast_log(LOG_WARNING, "No application '%s' for extension (%s, %s, %d)\n", e->app, context, exten, priority);
01804             return -1;
01805          }
01806          if (c->context != context)
01807             ast_copy_string(c->context, context, sizeof(c->context));
01808          if (c->exten != exten)
01809             ast_copy_string(c->exten, exten, sizeof(c->exten));
01810          c->priority = priority;
01811          pbx_substitute_variables(passdata, sizeof(passdata), c, e);
01812          if (option_debug) {
01813             char atmp[80];
01814             char atmp2[EXT_DATA_SIZE+100];
01815             ast_log(LOG_DEBUG, "Launching '%s'\n", app->name);
01816             snprintf(atmp, sizeof(atmp), "STACK-%s-%s-%d", context, exten, priority);
01817             snprintf(atmp2, sizeof(atmp2), "%s(\"%s\", \"%s\") %s",
01818                app->name, c->name, passdata, "in new stack");
01819             pbx_builtin_setvar_helper(c, atmp, atmp2);
01820          }
01821          if (option_verbose > 2) {
01822             char tmp[80], tmp2[80], tmp3[EXT_DATA_SIZE];
01823             ast_verbose( VERBOSE_PREFIX_3 "Executing [%s@%s:%d] %s(\"%s\", \"%s\") %s\n",
01824                exten, context, priority,
01825                term_color(tmp, app->name, COLOR_BRCYAN, 0, sizeof(tmp)),
01826                term_color(tmp2, c->name, COLOR_BRMAGENTA, 0, sizeof(tmp2)),
01827                term_color(tmp3, passdata, COLOR_BRMAGENTA, 0, sizeof(tmp3)),
01828                "in new stack");
01829          }
01830          manager_event(EVENT_FLAG_CALL, "Newexten",
01831                "Channel: %s\r\n"
01832                "Context: %s\r\n"
01833                "Extension: %s\r\n"
01834                "Priority: %d\r\n"
01835                "Application: %s\r\n"
01836                "AppData: %s\r\n"
01837                "Uniqueid: %s\r\n",
01838                c->name, c->context, c->exten, c->priority, app->name, passdata, c->uniqueid);
01839          return pbx_exec(c, app, passdata);  /* 0 on success, -1 on failure */
01840       }
01841    } else if (q.swo) {  /* not found here, but in another switch */
01842       ast_mutex_unlock(&conlock);
01843       if (matching_action)
01844          return -1;
01845       else {
01846          if (!q.swo->exec) {
01847             ast_log(LOG_WARNING, "No execution engine for switch %s\n", q.swo->name);
01848             res = -1;
01849          }
01850          return q.swo->exec(c, q.foundcontext ? q.foundcontext : context, exten, priority, callerid, q.data);
01851       }
01852    } else { /* not found anywhere, see what happened */
01853       ast_mutex_unlock(&conlock);
01854       switch (q.status) {
01855       case STATUS_NO_CONTEXT:
01856          if (!matching_action)
01857             ast_log(LOG_NOTICE, "Cannot find extension context '%s'\n", context);
01858          break;
01859       case STATUS_NO_EXTENSION:
01860          if (!matching_action)
01861             ast_log(LOG_NOTICE, "Cannot find extension '%s' in context '%s'\n", exten, context);
01862          break;
01863       case STATUS_NO_PRIORITY:
01864          if (!matching_action)
01865             ast_log(LOG_NOTICE, "No such priority %d in extension '%s' in context '%s'\n", priority, exten, context);
01866          break;
01867       case STATUS_NO_LABEL:
01868          if (context)
01869             ast_log(LOG_NOTICE, "No such label '%s' in extension '%s' in context '%s'\n", label, exten, context);
01870          break;
01871       default:
01872          if (option_debug)
01873             ast_log(LOG_DEBUG, "Shouldn't happen!\n");
01874       }
01875 
01876       return (matching_action) ? 0 : -1;
01877    }
01878 }
01879 
01880 /*! \brief  ast_hint_extension: Find hint for given extension in context */
01881 static struct ast_exten *ast_hint_extension(struct ast_channel *c, const char *context, const char *exten)
01882 {
01883    struct ast_exten *e;
01884    struct pbx_find_info q = { .stacklen = 0 }; /* the rest is set in pbx_find_context */
01885 
01886    ast_mutex_lock(&conlock);
01887    e = pbx_find_extension(c, NULL, &q, context, exten, PRIORITY_HINT, NULL, "", E_MATCH);
01888    ast_mutex_unlock(&conlock);
01889 
01890    return e;
01891 }
01892 
01893 /*! \brief  ast_extensions_state2: Check state of extension by using hints */
01894 static int ast_extension_state2(struct ast_exten *e)
01895 {
01896    char hint[AST_MAX_EXTENSION];
01897    char *cur, *rest;
01898    int allunavailable = 1, allbusy = 1, allfree = 1, allonhold = 1;
01899    int busy = 0, inuse = 0, ring = 0;
01900 
01901    if (!e)
01902       return -1;
01903 
01904    ast_copy_string(hint, ast_get_extension_app(e), sizeof(hint));
01905 
01906    rest = hint;   /* One or more devices separated with a & character */
01907    while ( (cur = strsep(&rest, "&")) ) {
01908       int res = ast_device_state(cur);
01909       switch (res) {
01910       case AST_DEVICE_NOT_INUSE:
01911          allunavailable = 0;
01912          allbusy = 0;
01913          allonhold = 0;
01914          break;
01915       case AST_DEVICE_INUSE:
01916          inuse = 1;
01917          allunavailable = 0;
01918          allfree = 0;
01919          allonhold = 0;
01920          break;
01921       case AST_DEVICE_RINGING:
01922          ring = 1;
01923          allunavailable = 0;
01924          allfree = 0;
01925          allonhold = 0;
01926          break;
01927       case AST_DEVICE_RINGINUSE:
01928          inuse = 1;
01929          ring = 1;
01930          allunavailable = 0;
01931          allfree = 0;
01932          allonhold = 0;
01933          break;
01934       case AST_DEVICE_ONHOLD:
01935          allunavailable = 0;
01936          allfree = 0;
01937          break;
01938       case AST_DEVICE_BUSY:
01939          allunavailable = 0;
01940          allfree = 0;
01941          allonhold = 0;
01942          busy = 1;
01943          break;
01944       case AST_DEVICE_UNAVAILABLE:
01945       case AST_DEVICE_INVALID:
01946          allbusy = 0;
01947          allfree = 0;
01948          allonhold = 0;
01949          break;
01950       default:
01951          allunavailable = 0;
01952          allbusy = 0;
01953          allfree = 0;
01954          allonhold = 0;
01955       }
01956    }
01957 
01958    if (!inuse && ring)
01959       return AST_EXTENSION_RINGING;
01960    if (inuse && ring)
01961       return (AST_EXTENSION_INUSE | AST_EXTENSION_RINGING);
01962    if (inuse)
01963       return AST_EXTENSION_INUSE;
01964    if (allfree)
01965       return AST_EXTENSION_NOT_INUSE;
01966    if (allonhold)
01967       return AST_EXTENSION_ONHOLD;
01968    if (allbusy)
01969       return AST_EXTENSION_BUSY;
01970    if (allunavailable)
01971       return AST_EXTENSION_UNAVAILABLE;
01972    if (busy)
01973       return AST_EXTENSION_INUSE;
01974 
01975    return AST_EXTENSION_NOT_INUSE;
01976 }
01977 
01978 /*! \brief  ast_extension_state2str: Return extension_state as string */
01979 const char *ast_extension_state2str(int extension_state)
01980 {
01981    int i;
01982 
01983    for (i = 0; (i < (sizeof(extension_states) / sizeof(extension_states[0]))); i++) {
01984       if (extension_states[i].extension_state == extension_state)
01985          return extension_states[i].text;
01986    }
01987    return "Unknown";
01988 }
01989 
01990 /*! \brief  ast_extension_state: Check extension state for an extension by using hint */
01991 int ast_extension_state(struct ast_channel *c, const char *context, const char *exten)
01992 {
01993    struct ast_exten *e;
01994 
01995    e = ast_hint_extension(c, context, exten);   /* Do we have a hint for this extension ? */
01996    if (!e)
01997       return -1;           /* No hint, return -1 */
01998 
01999    return ast_extension_state2(e);        /* Check all devices in the hint */
02000 }
02001 
02002 void ast_hint_state_changed(const char *device)
02003 {
02004    struct ast_hint *hint;
02005 
02006    AST_LIST_LOCK(&hints);
02007 
02008    AST_LIST_TRAVERSE(&hints, hint, list) {
02009       struct ast_state_cb *cblist;
02010       char buf[AST_MAX_EXTENSION];
02011       char *parse = buf;
02012       char *cur;
02013       int state;
02014 
02015       ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
02016       while ( (cur = strsep(&parse, "&")) ) {
02017          if (!strcasecmp(cur, device))
02018             break;
02019       }
02020       if (!cur)
02021          continue;
02022 
02023       /* Get device state for this hint */
02024       state = ast_extension_state2(hint->exten);
02025 
02026       if ((state == -1) || (state == hint->laststate))
02027          continue;
02028 
02029       /* Device state changed since last check - notify the watchers */
02030 
02031       /* For general callbacks */
02032       for (cblist = statecbs; cblist; cblist = cblist->next)
02033          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
02034 
02035       /* For extension callbacks */
02036       for (cblist = hint->callbacks; cblist; cblist = cblist->next)
02037          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
02038 
02039       hint->laststate = state;   /* record we saw the change */
02040    }
02041 
02042    AST_LIST_UNLOCK(&hints);
02043 }
02044 
02045 /*! \brief  ast_extension_state_add: Add watcher for extension states */
02046 int ast_extension_state_add(const char *context, const char *exten,
02047              ast_state_cb_type callback, void *data)
02048 {
02049    struct ast_hint *hint;
02050    struct ast_state_cb *cblist;
02051    struct ast_exten *e;
02052 
02053    /* If there's no context and extension:  add callback to statecbs list */
02054    if (!context && !exten) {
02055       AST_LIST_LOCK(&hints);
02056 
02057       for (cblist = statecbs; cblist; cblist = cblist->next) {
02058          if (cblist->callback == callback) {
02059             cblist->data = data;
02060             AST_LIST_UNLOCK(&hints);
02061             return 0;
02062          }
02063       }
02064 
02065       /* Now insert the callback */
02066       if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
02067          AST_LIST_UNLOCK(&hints);
02068          return -1;
02069       }
02070       cblist->id = 0;
02071       cblist->callback = callback;
02072       cblist->data = data;
02073 
02074       cblist->next = statecbs;
02075       statecbs = cblist;
02076 
02077       AST_LIST_UNLOCK(&hints);
02078       return 0;
02079    }
02080 
02081    if (!context || !exten)
02082       return -1;
02083 
02084    /* This callback type is for only one hint, so get the hint */
02085    e = ast_hint_extension(NULL, context, exten);
02086    if (!e) {
02087       return -1;
02088    }
02089 
02090    /* Find the hint in the list of hints */
02091    AST_LIST_LOCK(&hints);
02092 
02093    AST_LIST_TRAVERSE(&hints, hint, list) {
02094       if (hint->exten == e)
02095          break;
02096    }
02097 
02098    if (!hint) {
02099       /* We have no hint, sorry */
02100       AST_LIST_UNLOCK(&hints);
02101       return -1;
02102    }
02103 
02104    /* Now insert the callback in the callback list  */
02105    if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
02106       AST_LIST_UNLOCK(&hints);
02107       return -1;
02108    }
02109    cblist->id = stateid++;    /* Unique ID for this callback */
02110    cblist->callback = callback;  /* Pointer to callback routine */
02111    cblist->data = data;    /* Data for the callback */
02112 
02113    cblist->next = hint->callbacks;
02114    hint->callbacks = cblist;
02115 
02116    AST_LIST_UNLOCK(&hints);
02117    return cblist->id;
02118 }
02119 
02120 /*! \brief  ast_extension_state_del: Remove a watcher from the callback list */
02121 int ast_extension_state_del(int id, ast_state_cb_type callback)
02122 {
02123    struct ast_state_cb **p_cur = NULL; /* address of pointer to us */
02124    int ret = -1;
02125 
02126    if (!id && !callback)
02127       return -1;
02128 
02129    AST_LIST_LOCK(&hints);
02130 
02131    if (!id) {  /* id == 0 is a callback without extension */
02132       for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
02133          if ((*p_cur)->callback == callback)
02134             break;
02135       }
02136    } else { /* callback with extension, find the callback based on ID */
02137       struct ast_hint *hint;
02138       AST_LIST_TRAVERSE(&hints, hint, list) {
02139          for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
02140             if ((*p_cur)->id == id)
02141                break;
02142          }
02143          if (*p_cur) /* found in the inner loop */
02144             break;
02145       }
02146    }
02147    if (p_cur && *p_cur) {
02148       struct ast_state_cb *cur = *p_cur;
02149       *p_cur = cur->next;
02150       free(cur);
02151       ret = 0;
02152    }
02153    AST_LIST_UNLOCK(&hints);
02154    return ret;
02155 }
02156 
02157 /*! \brief  ast_add_hint: Add hint to hint list, check initial extension state */
02158 static int ast_add_hint(struct ast_exten *e)
02159 {
02160    struct ast_hint *hint;
02161 
02162    if (!e)
02163       return -1;
02164 
02165    AST_LIST_LOCK(&hints);
02166 
02167    /* Search if hint exists, do nothing */
02168    AST_LIST_TRAVERSE(&hints, hint, list) {
02169       if (hint->exten == e) {
02170          AST_LIST_UNLOCK(&hints);
02171          if (option_debug > 1)
02172             ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
02173          return -1;
02174       }
02175    }
02176 
02177    if (option_debug > 1)
02178       ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
02179 
02180    if (!(hint = ast_calloc(1, sizeof(*hint)))) {
02181       AST_LIST_UNLOCK(&hints);
02182       return -1;
02183    }
02184    /* Initialize and insert new item at the top */
02185    hint->exten = e;
02186    hint->laststate = ast_extension_state2(e);
02187    AST_LIST_INSERT_HEAD(&hints, hint, list);
02188 
02189    AST_LIST_UNLOCK(&hints);
02190    return 0;
02191 }
02192 
02193 /*! \brief  ast_change_hint: Change hint for an extension */
02194 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
02195 {
02196    struct ast_hint *hint;
02197    int res = -1;
02198 
02199    AST_LIST_LOCK(&hints);
02200    AST_LIST_TRAVERSE(&hints, hint, list) {
02201       if (hint->exten == oe) {
02202             hint->exten = ne;
02203          res = 0;
02204          break;
02205       }
02206    }
02207    AST_LIST_UNLOCK(&hints);
02208 
02209    return res;
02210 }
02211 
02212 /*! \brief  ast_remove_hint: Remove hint from extension */
02213 static int ast_remove_hint(struct ast_exten *e)
02214 {
02215    /* Cleanup the Notifys if hint is removed */
02216    struct ast_hint *hint;
02217    struct ast_state_cb *cblist, *cbprev;
02218    int res = -1;
02219 
02220    if (!e)
02221       return -1;
02222 
02223    AST_LIST_LOCK(&hints);
02224    AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
02225       if (hint->exten == e) {
02226          cbprev = NULL;
02227          cblist = hint->callbacks;
02228          while (cblist) {
02229             /* Notify with -1 and remove all callbacks */
02230             cbprev = cblist;
02231             cblist = cblist->next;
02232             cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
02233             free(cbprev);
02234             }
02235             hint->callbacks = NULL;
02236          AST_LIST_REMOVE_CURRENT(&hints, list);
02237             free(hint);
02238             res = 0;
02239          break;
02240       }
02241    }
02242    AST_LIST_TRAVERSE_SAFE_END
02243    AST_LIST_UNLOCK(&hints);
02244 
02245    return res;
02246 }
02247 
02248 
02249 /*! \brief  ast_get_hint: Get hint for channel */
02250 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
02251 {
02252    struct ast_exten *e = ast_hint_extension(c, context, exten);
02253 
02254    if (e) {
02255       if (hint)
02256          ast_copy_string(hint, ast_get_extension_app(e), hintsize);
02257       if (name) {
02258          const char *tmp = ast_get_extension_app_data(e);
02259          if (tmp)
02260             ast_copy_string(name, tmp, namesize);
02261       }
02262       return -1;
02263    }
02264    return 0;
02265 }
02266 
02267 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02268 {
02269    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH);
02270 }
02271 
02272 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
02273 {
02274    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL);
02275 }
02276 
02277 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
02278 {
02279    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
02280 }
02281 
02282 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02283 {
02284    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH);
02285 }
02286 
02287 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02288 {
02289    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE);
02290 }
02291 
02292 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02293 {
02294    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN);
02295 }
02296 
02297 /* helper function to set extension and priority */
02298 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
02299 {
02300    ast_copy_string(c->exten, exten, sizeof(c->exten));
02301    c->priority = pri;
02302 }
02303 
02304 /*!
02305  * \brief collect digits from the channel into the buffer,
02306  * return -1 on error, 0 on timeout or done.
02307  */
02308 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
02309 {
02310    int digit;
02311 
02312    buf[pos] = '\0';  /* make sure it is properly terminated */
02313    while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
02314       /* As long as we're willing to wait, and as long as it's not defined,
02315          keep reading digits until we can't possibly get a right answer anymore.  */
02316       digit = ast_waitfordigit(c, waittime * 1000);
02317       if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02318          c->_softhangup = 0;
02319       } else {
02320          if (!digit) /* No entry */
02321             break;
02322          if (digit < 0) /* Error, maybe a  hangup */
02323             return -1;
02324          if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
02325             buf[pos++] = digit;
02326             buf[pos] = '\0';
02327          }
02328          waittime = c->pbx->dtimeout;
02329       }
02330    }
02331    return 0;
02332 }
02333 
02334 static int __ast_pbx_run(struct ast_channel *c)
02335 {
02336    int found = 0; /* set if we find at least one match */
02337    int res = 0;
02338    int autoloopflag;
02339    int error = 0;    /* set an error conditions */
02340 
02341    /* A little initial setup here */
02342    if (c->pbx) {
02343       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
02344       /* XXX and now what ? */
02345       free(c->pbx);
02346    }
02347    if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
02348       return -1;
02349    if (c->amaflags) {
02350       if (!c->cdr) {
02351          c->cdr = ast_cdr_alloc();
02352          if (!c->cdr) {
02353             ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
02354             free(c->pbx);
02355             return -1;
02356          }
02357          ast_cdr_init(c->cdr, c);
02358       }
02359    }
02360    /* Set reasonable defaults */
02361    c->pbx->rtimeout = 10;
02362    c->pbx->dtimeout = 5;
02363 
02364    autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);   /* save value to restore at the end */
02365    ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
02366 
02367    /* Start by trying whatever the channel is set to */
02368    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02369       /* If not successful fall back to 's' */
02370       if (option_verbose > 1)
02371          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);
02372       /* XXX the original code used the existing priority in the call to
02373        * ast_exists_extension(), and reset it to 1 afterwards.
02374        * I believe the correct thing is to set it to 1 immediately.
02375        */
02376       set_ext_pri(c, "s", 1);
02377       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02378          /* JK02: And finally back to default if everything else failed */
02379          if (option_verbose > 1)
02380             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);
02381          ast_copy_string(c->context, "default", sizeof(c->context));
02382       }
02383    }
02384    if (c->cdr && ast_tvzero(c->cdr->start))
02385       ast_cdr_start(c->cdr);
02386    for (;;) {
02387       char dst_exten[256]; /* buffer to accumulate digits */
02388       int pos = 0;      /* XXX should check bounds */
02389       int digit = 0;
02390 
02391       /* loop on priorities in this context/exten */
02392       while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02393          found = 1;
02394          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02395             /* Something bad happened, or a hangup has been requested. */
02396             if (strchr("0123456789ABCDEF*#", res)) {
02397                if (option_debug)
02398                   ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
02399                pos = 0;
02400                dst_exten[pos++] = digit = res;
02401                dst_exten[pos] = '\0';
02402                break;
02403             }
02404             if (res == AST_PBX_KEEPALIVE) {
02405                if (option_debug)
02406                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
02407                if (option_verbose > 1)
02408                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
02409                error = 1;
02410                break;
02411             }
02412             if (option_debug)
02413                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02414             if (option_verbose > 1)
02415                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02416             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02417                c->_softhangup =0;
02418             } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
02419                /* atimeout, nothing bad */
02420             } else {
02421                if (c->cdr)
02422                   ast_cdr_update(c);
02423                error = 1;
02424                break;
02425             }
02426          }
02427          if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
02428             set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
02429             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
02430             c->whentohangup = 0;
02431             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
02432          } else if (c->_softhangup) {
02433             if (option_debug)
02434                ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
02435                   c->exten, c->priority);
02436             error = 1;
02437             break;
02438          }
02439          c->priority++;
02440       } /* end while  - from here on we can use 'break' to go out */
02441       if (error)
02442          break;
02443 
02444       /* XXX we get here on non-existing extension or a keypress or hangup ? */
02445 
02446       if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
02447          /* If there is no match at priority 1, it is not a valid extension anymore.
02448           * Try to continue at "i", 1 or exit if the latter does not exist.
02449           */
02450          if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
02451             if (option_verbose > 2)
02452                ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
02453             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
02454             set_ext_pri(c, "i", 1);
02455          } else {
02456             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
02457                c->name, c->exten, c->context);
02458             error = 1; /* we know what to do with it */
02459             break;
02460          }
02461       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
02462          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
02463          c->_softhangup = 0;
02464       } else { /* keypress received, get more digits for a full extension */
02465          int waittime = 0;
02466          if (digit)
02467             waittime = c->pbx->dtimeout;
02468          else if (!autofallthrough)
02469             waittime = c->pbx->rtimeout;
02470          if (!waittime) {
02471             const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
02472             if (!status)
02473                status = "UNKNOWN";
02474             if (option_verbose > 2)
02475                ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
02476             if (!strcasecmp(status, "CONGESTION"))
02477                res = pbx_builtin_congestion(c, "10");
02478             else if (!strcasecmp(status, "CHANUNAVAIL"))
02479                res = pbx_builtin_congestion(c, "10");
02480             else if (!strcasecmp(status, "BUSY"))
02481                res = pbx_builtin_busy(c, "10");
02482             error = 1; /* XXX disable message */
02483             break;   /* exit from the 'for' loop */
02484          }
02485 
02486          if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
02487             break;
02488          if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
02489             set_ext_pri(c, dst_exten, 1);
02490          else {
02491             /* No such extension */
02492             if (!ast_strlen_zero(dst_exten)) {
02493                /* An invalid extension */
02494                if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
02495                   if (option_verbose > 2)
02496                      ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
02497                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
02498                   set_ext_pri(c, "i", 1);
02499                } else {
02500                   ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
02501                   found = 1; /* XXX disable message */
02502                   break;
02503                }
02504             } else {
02505                /* A simple timeout */
02506                if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
02507                   if (option_verbose > 2)
02508                      ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
02509                   set_ext_pri(c, "t", 1);
02510                } else {
02511                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
02512                   found = 1; /* XXX disable message */
02513                   break;
02514                }
02515             }
02516          }
02517          if (c->cdr) {
02518             if (option_verbose > 2)
02519                ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
02520             ast_cdr_update(c);
02521          }
02522       }
02523    }
02524    if (!found && !error)
02525       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
02526    if ((res != AST_PBX_KEEPALIVE) && ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num)) {
02527       if (c->cdr && ast_opt_end_cdr_before_h_exten)
02528          ast_cdr_end(c->cdr);
02529       set_ext_pri(c, "h", 1);
02530       while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02531          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02532             /* Something bad happened, or a hangup has been requested. */
02533             if (option_debug)
02534                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02535             if (option_verbose > 1)
02536                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02537             break;
02538          }
02539          c->priority++;
02540       }
02541    }
02542    ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02543 
02544    pbx_destroy(c->pbx);
02545    c->pbx = NULL;
02546    if (res != AST_PBX_KEEPALIVE)
02547       ast_hangup(c);
02548    return 0;
02549 }
02550 
02551 /* Returns 0 on success, non-zero if call limit was reached */
02552 static int increase_call_count(const struct ast_channel *c)
02553 {
02554    int failed = 0;
02555    double curloadavg;
02556    ast_mutex_lock(&maxcalllock);
02557    if (option_maxcalls) {
02558       if (countcalls >= option_maxcalls) {
02559          ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
02560          failed = -1;
02561       }
02562    }
02563    if (option_maxload) {
02564       getloadavg(&curloadavg, 1);
02565       if (curloadavg >= option_maxload) {
02566          ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
02567          failed = -1;
02568       }
02569    }
02570    if (!failed)
02571       countcalls++;
02572    ast_mutex_unlock(&maxcalllock);
02573 
02574    return failed;
02575 }
02576 
02577 static void decrease_call_count(void)
02578 {
02579    ast_mutex_lock(&maxcalllock);
02580    if (countcalls > 0)
02581       countcalls--;
02582    ast_mutex_unlock(&maxcalllock);
02583 }
02584 
02585 static void destroy_exten(struct ast_exten *e)
02586 {
02587    if (e->priority == PRIORITY_HINT)
02588       ast_remove_hint(e);
02589 
02590    if (e->datad)
02591       e->datad(e->data);
02592    free(e);
02593 }
02594 
02595 static void *pbx_thread(void *data)
02596 {
02597    /* Oh joyeous kernel, we're a new thread, with nothing to do but
02598       answer this channel and get it going.
02599    */
02600    /* NOTE:
02601       The launcher of this function _MUST_ increment 'countcalls'
02602       before invoking the function; it will be decremented when the
02603       PBX has finished running on the channel
02604     */
02605    struct ast_channel *c = data;
02606 
02607    __ast_pbx_run(c);
02608    decrease_call_count();
02609 
02610    pthread_exit(NULL);
02611 
02612    return NULL;
02613 }
02614 
02615 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
02616 {
02617    pthread_t t;
02618    pthread_attr_t attr;
02619 
02620    if (!c) {
02621       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
02622       return AST_PBX_FAILED;
02623    }
02624 
02625    if (increase_call_count(c))
02626       return AST_PBX_CALL_LIMIT;
02627 
02628    /* Start a new thread, and get something handling this channel. */
02629    pthread_attr_init(&attr);
02630    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02631    if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
02632       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
02633       pthread_attr_destroy(&attr);
02634       return AST_PBX_FAILED;
02635    }
02636    pthread_attr_destroy(&attr);
02637 
02638    return AST_PBX_SUCCESS;
02639 }
02640 
02641 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
02642 {
02643    enum ast_pbx_result res = AST_PBX_SUCCESS;
02644 
02645    if (increase_call_count(c))
02646       return AST_PBX_CALL_LIMIT;
02647 
02648    res = __ast_pbx_run(c);
02649    decrease_call_count();
02650 
02651    return res;
02652 }
02653 
02654 int ast_active_calls(void)
02655 {
02656    return countcalls;
02657 }
02658 
02659 int pbx_set_autofallthrough(int newval)
02660 {
02661    int oldval = autofallthrough;
02662    autofallthrough = newval;
02663    return oldval;
02664 }
02665 
02666 /* lookup for a context with a given name,
02667  * return with conlock held if found, NULL if not found
02668  */
02669 static struct ast_context *find_context_locked(const char *context)
02670 {
02671    struct ast_context *c = NULL;
02672 
02673    ast_lock_contexts();
02674    while ( (c = ast_walk_contexts(c)) ) {
02675       if (!strcmp(ast_get_context_name(c), context))
02676          return c;
02677    }
02678    ast_unlock_contexts();
02679 
02680    return NULL;
02681 }
02682 
02683 /*
02684  * This function locks contexts list by &conlist, search for the right context
02685  * structure, leave context list locked and call ast_context_remove_include2
02686  * which removes include, unlock contexts list and return ...
02687  */
02688 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
02689 {
02690    int ret = -1;
02691    struct ast_context *c = find_context_locked(context);
02692 
02693    if (c) {
02694       /* found, remove include from this context ... */
02695       ret = ast_context_remove_include2(c, include, registrar);
02696       ast_unlock_contexts();
02697    }
02698    return ret;
02699 }
02700 
02701 /*
02702  * When we call this function, &conlock lock must be locked, because when
02703  * we giving *con argument, some process can remove/change this context
02704  * and after that there can be segfault.
02705  *
02706  * This function locks given context, removes include, unlock context and
02707  * return.
02708  */
02709 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
02710 {
02711    struct ast_include *i, *pi = NULL;
02712    int ret = -1;
02713 
02714    ast_mutex_lock(&con->lock);
02715 
02716    /* find our include */
02717    for (i = con->includes; i; pi = i, i = i->next) {
02718       if (!strcmp(i->name, include) &&
02719             (!registrar || !strcmp(i->registrar, registrar))) {
02720          /* remove from list */
02721          if (pi)
02722             pi->next = i->next;
02723          else
02724             con->includes = i->next;
02725          /* free include and return */
02726          free(i);
02727          ret = 0;
02728          break;
02729       }
02730    }
02731 
02732    ast_mutex_unlock(&con->lock);
02733    return ret;
02734 }
02735 
02736 /*!
02737  * \note This function locks contexts list by &conlist, search for the rigt context
02738  * structure, leave context list locked and call ast_context_remove_switch2
02739  * which removes switch, unlock contexts list and return ...
02740  */
02741 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
02742 {
02743    int ret = -1; /* default error return */
02744    struct ast_context *c = find_context_locked(context);
02745 
02746    if (c) {
02747       /* remove switch from this context ... */
02748       ret = ast_context_remove_switch2(c, sw, data, registrar);
02749       ast_unlock_contexts();
02750    }
02751    return ret;
02752 }
02753 
02754 /*!
02755  * \brief This function locks given context, removes switch, unlock context and
02756  * return.
02757  * \note When we call this function, &conlock lock must be locked, because when
02758  * we giving *con argument, some process can remove/change this context
02759  * and after that there can be segfault.
02760  *
02761  */
02762 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
02763 {
02764    struct ast_sw *i;
02765    int ret = -1;
02766 
02767    ast_mutex_lock(&con->lock);
02768 
02769    /* walk switches */
02770    AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
02771       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
02772          (!registrar || !strcmp(i->registrar, registrar))) {
02773          /* found, remove from list */
02774          AST_LIST_REMOVE_CURRENT(&con->alts, list);
02775          free(i); /* free switch and return */
02776          ret = 0;
02777          break;
02778       }
02779    }
02780    AST_LIST_TRAVERSE_SAFE_END
02781 
02782    ast_mutex_unlock(&con->lock);
02783 
02784    return ret;
02785 }
02786 
02787 /*
02788  * \note This functions lock contexts list, search for the right context,
02789  * call ast_context_remove_extension2, unlock contexts list and return.
02790  * In this function we are using
02791  */
02792 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
02793 {
02794    int ret = -1; /* default error return */
02795    struct ast_context *c = find_context_locked(context);
02796 
02797    if (c) { /* ... remove extension ... */
02798       ret = ast_context_remove_extension2(c, extension, priority, registrar);
02799       ast_unlock_contexts();
02800    }
02801    return ret;
02802 }
02803 
02804 /*!
02805  * \brief This functionc locks given context, search for the right extension and
02806  * fires out all peer in this extensions with given priority. If priority
02807  * is set to 0, all peers are removed. After that, unlock context and
02808  * return.
02809  * \note When do you want to call this function, make sure that &conlock is locked,
02810  * because some process can handle with your *con context before you lock
02811  * it.
02812  *
02813  */
02814 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
02815 {
02816    struct ast_exten *exten, *prev_exten = NULL;
02817    struct ast_exten *peer;
02818 
02819    ast_mutex_lock(&con->lock);
02820 
02821    /* scan the extension list to find matching extension-registrar */
02822    for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
02823       if (!strcmp(exten->exten, extension) &&
02824          (!registrar || !strcmp(exten->registrar, registrar)))
02825          break;
02826    }
02827    if (!exten) {
02828       /* we can't find right extension */
02829       ast_mutex_unlock(&con->lock);
02830       return -1;
02831    }
02832 
02833    /* should we free all peers in this extension? (priority == 0)? */
02834    if (priority == 0) {
02835       /* remove this extension from context list */
02836       if (prev_exten)
02837          prev_exten->next = exten->next;
02838       else
02839          con->root = exten->next;
02840 
02841       /* fire out all peers */
02842       while ( (peer = exten) ) {
02843          exten = peer->peer; /* prepare for next entry */
02844          destroy_exten(peer);
02845       }
02846    } else {
02847       /* scan the priority list to remove extension with exten->priority == priority */
02848       struct ast_exten *previous_peer = NULL;
02849 
02850       for (peer = exten; peer; previous_peer = peer, peer = peer->peer) {
02851          if (peer->priority == priority &&
02852                (!registrar || !strcmp(peer->registrar, registrar) ))
02853             break; /* found our priority */
02854       }
02855       if (!peer) { /* not found */
02856          ast_mutex_unlock(&con->lock);
02857          return -1;
02858       }
02859       /* we are first priority extension? */
02860       if (!previous_peer) {
02861          /*
02862           * We are first in the priority chain, so must update the extension chain.
02863           * The next node is either the next priority or the next extension
02864           */
02865          struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
02866 
02867          if (!prev_exten)  /* change the root... */
02868             con->root = next_node;
02869          else
02870             prev_exten->next = next_node; /* unlink */
02871          if (peer->peer)   /* XXX update the new head of the pri list */
02872             peer->peer->next = peer->next;
02873       } else { /* easy, we are not first priority in extension */
02874          previous_peer->peer = peer->peer;
02875       }
02876 
02877       /* now, free whole priority extension */
02878       destroy_exten(peer);
02879       /* XXX should we return -1 ? */
02880    }
02881    ast_mutex_unlock(&con->lock);
02882    return 0;
02883 }
02884 
02885 
02886 /*!
02887  * \note This function locks contexts list by &conlist, searches for the right context
02888  * structure, and locks the macrolock mutex in that context.
02889  * macrolock is used to limit a macro to be executed by one call at a time.
02890  */
02891 int ast_context_lockmacro(const char *context)
02892 {
02893    struct ast_context *c = NULL;
02894    int ret = -1;
02895 
02896    ast_lock_contexts();
02897 
02898    while ((c = ast_walk_contexts(c))) {
02899       if (!strcmp(ast_get_context_name(c), context)) {
02900          ret = 0;
02901          break;
02902       }
02903    }
02904 
02905    ast_unlock_contexts();
02906 
02907    /* if we found context, lock macrolock */
02908    if (ret == 0) 
02909       ret = ast_mutex_lock(&c->macrolock);
02910 
02911    return ret;
02912 }
02913 
02914 /*!
02915  * \note This function locks contexts list by &conlist, searches for the right context
02916  * structure, and unlocks the macrolock mutex in that context.
02917  * macrolock is used to limit a macro to be executed by one call at a time.
02918  */
02919 int ast_context_unlockmacro(const char *context)
02920 {
02921    struct ast_context *c = NULL;
02922    int ret = -1;
02923 
02924    ast_lock_contexts();
02925 
02926    while ((c = ast_walk_contexts(c))) {
02927       if (!strcmp(ast_get_context_name(c), context)) {
02928          ret = 0;
02929          break;
02930       }
02931    }
02932 
02933    ast_unlock_contexts();
02934 
02935    /* if we found context, unlock macrolock */
02936    if (ret == 0) 
02937       ret = ast_mutex_unlock(&c->macrolock);
02938 
02939    return ret;
02940 }
02941 
02942 /*! \brief Dynamically register a new dial plan application */
02943 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
02944 {
02945    struct ast_app *tmp, *cur = NULL;
02946    char tmps[80];
02947    int length;
02948 
02949    AST_LIST_LOCK(&apps);
02950    AST_LIST_TRAVERSE(&apps, tmp, list) {
02951       if (!strcasecmp(app, tmp->name)) {
02952          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
02953          AST_LIST_UNLOCK(&apps);
02954          return -1;
02955       }
02956    }
02957 
02958    length = sizeof(*tmp) + strlen(app) + 1;
02959 
02960    if (!(tmp = ast_calloc(1, length))) {
02961       AST_LIST_UNLOCK(&apps);
02962       return -1;
02963    }
02964 
02965    strcpy(tmp->name, app);
02966    tmp->execute = execute;
02967    tmp->synopsis = synopsis;
02968    tmp->description = description;
02969 
02970    /* Store in alphabetical order */
02971    AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
02972       if (strcasecmp(tmp->name, cur->name) < 0) {
02973          AST_LIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
02974          break;
02975       }
02976    }
02977    AST_LIST_TRAVERSE_SAFE_END
02978    if (!cur)
02979       AST_LIST_INSERT_TAIL(&apps, tmp, list);
02980 
02981    if (option_verbose > 1)
02982       ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
02983 
02984    AST_LIST_UNLOCK(&apps);
02985 
02986    return 0;
02987 }
02988 
02989 /*
02990  * Append to the list. We don't have a tail pointer because we need
02991  * to scan the list anyways to check for duplicates during insertion.
02992  */
02993 int ast_register_switch(struct ast_switch *sw)
02994 {
02995    struct ast_switch *tmp;
02996 
02997    AST_LIST_LOCK(&switches);
02998    AST_LIST_TRAVERSE(&switches, tmp, list) {
02999       if (!strcasecmp(tmp->name, sw->name)) {
03000          AST_LIST_UNLOCK(&switches);
03001          ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
03002          return -1;
03003       }
03004    }
03005    AST_LIST_INSERT_TAIL(&switches, sw, list);
03006    AST_LIST_UNLOCK(&switches);
03007 
03008    return 0;
03009 }
03010 
03011 void ast_unregister_switch(struct ast_switch *sw)
03012 {
03013    AST_LIST_LOCK(&switches);
03014    AST_LIST_REMOVE(&switches, sw, list);
03015    AST_LIST_UNLOCK(&switches);
03016 }
03017 
03018 /*
03019  * Help for CLI commands ...
03020  */
03021 static char show_applications_help[] =
03022 "Usage: core show applications [{like|describing} <text>]\n"
03023 "       List applications which are currently available.\n"
03024 "       If 'like', <text> will be a substring of the app name\n"
03025 "       If 'describing', <text> will be a substring of the description\n";
03026 
03027 static char show_functions_help[] =
03028 "Usage: core show functions [like <text>]\n"
03029 "       List builtin functions, optionally only those matching a given string\n";
03030 
03031 static char show_switches_help[] =
03032 "Usage: core show switches\n"
03033 "       List registered switches\n";
03034 
03035 static char show_hints_help[] =
03036 "Usage: core show hints\n"
03037 "       List registered hints\n";
03038 
03039 static char show_globals_help[] =
03040 "Usage: core show globals\n"
03041 "       List current global dialplan variables and their values\n";
03042 
03043 static char show_application_help[] =
03044 "Usage: core show application <application> [<application> [<application> [...]]]\n"
03045 "       Describes a particular application.\n";
03046 
03047 static char show_function_help[] =
03048 "Usage: core show function <function>\n"
03049 "       Describe a particular dialplan function.\n";
03050 
03051 static char show_dialplan_help[] =
03052 "Usage: core show dialplan [exten@][context]\n"
03053 "       Show dialplan\n";
03054 
03055 static char set_global_help[] =
03056 "Usage: core set global <name> <value>\n"
03057 "       Set global dialplan variable <name> to <value>\n";
03058 
03059 
03060 /*
03061  * \brief 'show application' CLI command implementation functions ...
03062  */
03063 
03064 /*
03065  * There is a possibility to show informations about more than one
03066  * application at one time. You can type 'show application Dial Echo' and
03067  * you will see informations about these two applications ...
03068  */
03069 static char *complete_show_application(const char *line, const char *word, int pos, int state)
03070 {
03071    struct ast_app *a;
03072    char *ret = NULL;
03073    int which = 0;
03074    int wordlen = strlen(word);
03075 
03076    /* return the n-th [partial] matching entry */
03077    AST_LIST_LOCK(&apps);
03078    AST_LIST_TRAVERSE(&apps, a, list) {
03079       if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
03080          ret = strdup(a->name);
03081          break;
03082       }
03083    }
03084    AST_LIST_UNLOCK(&apps);
03085 
03086    return ret;
03087 }
03088 
03089 static int handle_show_application_deprecated(int fd, int argc, char *argv[])
03090 {
03091    struct ast_app *a;
03092    int app, no_registered_app = 1;
03093 
03094    if (argc < 3)
03095       return RESULT_SHOWUSAGE;
03096 
03097    /* ... go through all applications ... */
03098    AST_LIST_LOCK(&apps);
03099    AST_LIST_TRAVERSE(&apps, a, list) {
03100       /* ... compare this application name with all arguments given
03101        * to 'show application' command ... */
03102       for (app = 2; app < argc; app++) {
03103          if (!strcasecmp(a->name, argv[app])) {
03104             /* Maximum number of characters added by terminal coloring is 22 */
03105             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
03106             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
03107             int synopsis_size, description_size;
03108 
03109             no_registered_app = 0;
03110 
03111             if (a->synopsis)
03112                synopsis_size = strlen(a->synopsis) + 23;
03113             else
03114                synopsis_size = strlen("Not available") + 23;
03115             synopsis = alloca(synopsis_size);
03116 
03117             if (a->description)
03118                description_size = strlen(a->description) + 23;
03119             else
03120                description_size = strlen("Not available") + 23;
03121             description = alloca(description_size);
03122 
03123             if (synopsis && description) {
03124                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
03125                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
03126                term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03127                term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03128                term_color(synopsis,
03129                            a->synopsis ? a->synopsis : "Not available",
03130                            COLOR_CYAN, 0, synopsis_size);
03131                term_color(description,
03132                            a->description ? a->description : "Not available",
03133                            COLOR_CYAN, 0, description_size);
03134 
03135                ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
03136             } else {
03137                /* ... one of our applications, show info ...*/
03138                ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
03139                   "[Synopsis]\n  %s\n\n"
03140                   "[Description]\n%s\n",
03141                   a->name,
03142                   a->synopsis ? a->synopsis : "Not available",
03143                   a->description ? a->description : "Not available");
03144             }
03145          }
03146       }
03147    }
03148    AST_LIST_UNLOCK(&apps);
03149 
03150    /* we found at least one app? no? */
03151    if (no_registered_app) {
03152       ast_cli(fd, "Your application(s) is (are) not registered\n");
03153       return RESULT_FAILURE;
03154    }
03155 
03156    return RESULT_SUCCESS;
03157 }
03158 
03159 static int handle_show_application(int fd, int argc, char *argv[])
03160 {
03161    struct ast_app *a;
03162    int app, no_registered_app = 1;
03163 
03164    if (argc < 4)
03165       return RESULT_SHOWUSAGE;
03166 
03167    /* ... go through all applications ... */
03168    AST_LIST_LOCK(&apps);
03169    AST_LIST_TRAVERSE(&apps, a, list) {
03170       /* ... compare this application name with all arguments given
03171        * to 'show application' command ... */
03172       for (app = 3; app < argc; app++) {
03173          if (!strcasecmp(a->name, argv[app])) {
03174             /* Maximum number of characters added by terminal coloring is 22 */
03175             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
03176             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
03177             int synopsis_size, description_size;
03178 
03179             no_registered_app = 0;
03180 
03181             if (a->synopsis)
03182                synopsis_size = strlen(a->synopsis) + 23;
03183             else
03184                synopsis_size = strlen("Not available") + 23;
03185             synopsis = alloca(synopsis_size);
03186 
03187             if (a->description)
03188                description_size = strlen(a->description) + 23;
03189             else
03190                description_size = strlen("Not available") + 23;
03191             description = alloca(description_size);
03192 
03193             if (synopsis && description) {
03194                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
03195                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
03196                term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03197                term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03198                term_color(synopsis,
03199                            a->synopsis ? a->synopsis : "Not available",
03200                            COLOR_CYAN, 0, synopsis_size);
03201                term_color(description,
03202                            a->description ? a->description : "Not available",
03203                            COLOR_CYAN, 0, description_size);
03204 
03205                ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
03206             } else {
03207                /* ... one of our applications, show info ...*/
03208                ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
03209                   "[Synopsis]\n  %s\n\n"
03210                   "[Description]\n%s\n",
03211                   a->name,
03212                   a->synopsis ? a->synopsis : "Not available",
03213                   a->description ? a->description : "Not available");
03214             }
03215          }
03216       }
03217    }
03218    AST_LIST_UNLOCK(&apps);
03219 
03220    /* we found at least one app? no? */
03221    if (no_registered_app) {
03222       ast_cli(fd, "Your application(s) is (are) not registered\n");
03223       return RESULT_FAILURE;
03224    }
03225 
03226    return RESULT_SUCCESS;
03227 }
03228 
03229 /*! \brief  handle_show_hints: CLI support for listing registered dial plan hints */
03230 static int handle_show_hints(int fd, int argc, char *argv[])
03231 {
03232    struct ast_hint *hint;
03233    int num = 0;
03234    int watchers;
03235    struct ast_state_cb *watcher;
03236 
03237    if (AST_LIST_EMPTY(&hints)) {
03238       ast_cli(fd, "There are no registered dialplan hints\n");
03239       return RESULT_SUCCESS;
03240    }
03241    /* ... we have hints ... */
03242    ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
03243    AST_LIST_LOCK(&hints);
03244    AST_LIST_TRAVERSE(&hints, hint, list) {
03245       watchers = 0;
03246       for (watcher = hint->callbacks; watcher; watcher = watcher->next)
03247          watchers++;
03248       ast_cli(fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
03249          ast_get_extension_name(hint->exten),
03250          ast_get_context_name(ast_get_extension_context(hint->exten)),
03251          ast_get_extension_app(hint->exten),
03252          ast_extension_state2str(hint->laststate), watchers);
03253       num++;
03254    }
03255    ast_cli(fd, "----------------\n");
03256    ast_cli(fd, "- %d hints registered\n", num);
03257    AST_LIST_UNLOCK(&hints);
03258    return RESULT_SUCCESS;
03259 }
03260 
03261 /*! \brief  handle_show_switches: CLI support for listing registered dial plan switches */
03262 static int handle_show_switches(int fd, int argc, char *argv[])
03263 {
03264    struct ast_switch *sw;
03265 
03266    AST_LIST_LOCK(&switches);
03267 
03268    if (AST_LIST_EMPTY(&switches)) {
03269       AST_LIST_UNLOCK(&switches);
03270       ast_cli(fd, "There are no registered alternative switches\n");
03271       return RESULT_SUCCESS;
03272    }
03273 
03274    ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
03275    AST_LIST_TRAVERSE(&switches, sw, list)
03276       ast_cli(fd, "%s: %s\n", sw->name, sw->description);
03277 
03278    AST_LIST_UNLOCK(&switches);
03279 
03280    return RESULT_SUCCESS;
03281 }
03282 
03283 /*
03284  * 'show applications' CLI command implementation functions ...
03285  */
03286 static int handle_show_applications_deprecated(int fd, int argc, char *argv[])
03287 {
03288    struct ast_app *a;
03289    int like = 0, describing = 0;
03290    int total_match = 0;    /* Number of matches in like clause */
03291    int total_apps = 0;  /* Number of apps registered */
03292 
03293    AST_LIST_LOCK(&apps);
03294 
03295    if (AST_LIST_EMPTY(&apps)) {
03296       ast_cli(fd, "There are no registered applications\n");
03297       AST_LIST_UNLOCK(&apps);
03298       return -1;
03299    }
03300 
03301    /* show applications like <keyword> */
03302    if ((argc == 4) && (!strcmp(argv[2], "like"))) {
03303       like = 1;
03304    } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
03305       describing = 1;
03306    }
03307 
03308    /* show applications describing <keyword1> [<keyword2>] [...] */
03309    if ((!like) && (!describing)) {
03310       ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
03311    } else {
03312       ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
03313    }
03314 
03315    AST_LIST_TRAVERSE(&apps, a, list) {
03316       int printapp = 0;
03317       total_apps++;
03318       if (like) {
03319          if (strcasestr(a->name, argv[3])) {
03320             printapp = 1;
03321             total_match++;
03322          }
03323       } else if (describing) {
03324          if (a->description) {
03325             /* Match all words on command line */
03326             int i;
03327             printapp = 1;
03328             for (i = 3; i < argc; i++) {
03329                if (!strcasestr(a->description, argv[i])) {
03330                   printapp = 0;
03331                } else {
03332                   total_match++;
03333                }
03334             }
03335          }
03336       } else {
03337          printapp = 1;
03338       }
03339 
03340       if (printapp) {
03341          ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
03342       }
03343    }
03344    if ((!like) && (!describing)) {
03345       ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
03346    } else {
03347       ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
03348    }
03349 
03350    AST_LIST_UNLOCK(&apps);
03351 
03352    return RESULT_SUCCESS;
03353 }
03354 static int handle_show_applications(int fd, int argc, char *argv[])
03355 {
03356    struct ast_app *a;
03357    int like = 0, describing = 0;
03358    int total_match = 0;    /* Number of matches in like clause */
03359    int total_apps = 0;  /* Number of apps registered */
03360 
03361    AST_LIST_LOCK(&apps);
03362 
03363    if (AST_LIST_EMPTY(&apps)) {
03364       ast_cli(fd, "There are no registered applications\n");
03365       AST_LIST_UNLOCK(&apps);
03366       return -1;
03367    }
03368 
03369    /* core list applications like <keyword> */
03370    if ((argc == 5) && (!strcmp(argv[3], "like"))) {
03371       like = 1;
03372    } else if ((argc > 4) && (!strcmp(argv[3], "describing"))) {
03373       describing = 1;
03374    }
03375 
03376    /* core list applications describing <keyword1> [<keyword2>] [...] */
03377    if ((!like) && (!describing)) {
03378       ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
03379    } else {
03380       ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
03381    }
03382 
03383    AST_LIST_TRAVERSE(&apps, a, list) {
03384       int printapp = 0;
03385       total_apps++;
03386       if (like) {
03387          if (strcasestr(a->name, argv[4])) {
03388             printapp = 1;
03389             total_match++;
03390          }
03391       } else if (describing) {
03392          if (a->description) {
03393             /* Match all words on command line */
03394             int i;
03395             printapp = 1;
03396             for (i = 4; i < argc; i++) {
03397                if (!strcasestr(a->description, argv[i])) {
03398                   printapp = 0;
03399                } else {
03400                   total_match++;
03401                }
03402             }
03403          }
03404       } else {
03405          printapp = 1;
03406       }
03407 
03408       if (printapp) {
03409          ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
03410       }
03411    }
03412    if ((!like) && (!describing)) {
03413       ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
03414    } else {
03415       ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
03416    }
03417 
03418    AST_LIST_UNLOCK(&apps);
03419 
03420    return RESULT_SUCCESS;
03421 }
03422 
03423 static char *complete_show_applications_deprecated(const char *line, const char *word, int pos, int state)
03424 {
03425    static char* choices[] = { "like", "describing", NULL };
03426 
03427    return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
03428 }
03429 
03430 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
03431 {
03432    static char* choices[] = { "like", "describing", NULL };
03433 
03434    return (pos != 3) ? NULL : ast_cli_complete(word, choices, state);
03435 }
03436 
03437 /*
03438  * 'show dialplan' CLI command implementation functions ...
03439  */
03440 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
03441    int state)
03442 {
03443    struct ast_context *c = NULL;
03444    char *ret = NULL;
03445    int which = 0;
03446    int wordlen;
03447 
03448    /* we are do completion of [exten@]context on second position only */
03449    if (pos != 2)
03450       return NULL;
03451 
03452    ast_lock_contexts();
03453 
03454    wordlen = strlen(word);
03455 
03456    /* walk through all contexts and return the n-th match */
03457    while ( (c = ast_walk_contexts(c)) ) {
03458       if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
03459          ret = ast_strdup(ast_get_context_name(c));
03460          break;
03461       }
03462    }
03463 
03464    ast_unlock_contexts();
03465 
03466    return ret;
03467 }
03468 
03469 struct dialplan_counters {
03470    int total_context;
03471    int total_exten;
03472    int total_prio;
03473    int context_existence;
03474    int extension_existence;
03475 };
03476 
03477 /*! \brief helper function to print an extension */
03478 static void print_ext(struct ast_exten *e, char * buf, int buflen)
03479 {
03480    int prio = ast_get_extension_priority(e);
03481    if (prio == PRIORITY_HINT) {
03482       snprintf(buf, buflen, "hint: %s",
03483          ast_get_extension_app(e));
03484    } else {
03485       snprintf(buf, buflen, "%d. %s(%s)",
03486          prio, ast_get_extension_app(e),
03487          (char *)ast_get_extension_app_data(e));
03488    }
03489 }
03490 
03491 /* XXX not verified */
03492 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[])
03493 {
03494    struct ast_context *c = NULL;
03495    int res = 0, old_total_exten = dpc->total_exten;
03496 
03497    ast_lock_contexts();
03498 
03499    /* walk all contexts ... */
03500    while ( (c = ast_walk_contexts(c)) ) {
03501       struct ast_exten *e;
03502       struct ast_include *i;
03503       struct ast_ignorepat *ip;
03504       char buf[256], buf2[256];
03505       int context_info_printed = 0;
03506 
03507       if (context && strcmp(ast_get_context_name(c), context))
03508          continue;   /* skip this one, name doesn't match */
03509 
03510       dpc->context_existence = 1;
03511 
03512       ast_lock_context(c);
03513 
03514       /* are we looking for exten too? if yes, we print context
03515        * only if we find our extension.
03516        * Otherwise print context even if empty ?
03517        * XXX i am not sure how the rinclude is handled.
03518        * I think it ought to go inside.
03519        */
03520       if (!exten) {
03521          dpc->total_context++;
03522          ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03523             ast_get_context_name(c), ast_get_context_registrar(c));
03524          context_info_printed = 1;
03525       }
03526 
03527       /* walk extensions ... */
03528       e = NULL;
03529       while ( (e = ast_walk_context_extensions(c, e)) ) {
03530          struct ast_exten *p;
03531 
03532          if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
03533             continue;   /* skip, extension match failed */
03534 
03535          dpc->extension_existence = 1;
03536 
03537          /* may we print context info? */
03538          if (!context_info_printed) {
03539             dpc->total_context++;
03540             if (rinclude) { /* TODO Print more info about rinclude */
03541                ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
03542                   ast_get_context_name(c), ast_get_context_registrar(c));
03543             } else {
03544                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03545                   ast_get_context_name(c), ast_get_context_registrar(c));
03546             }
03547             context_info_printed = 1;
03548          }
03549          dpc->total_prio++;
03550 
03551          /* write extension name and first peer */
03552          snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
03553 
03554          print_ext(e, buf2, sizeof(buf2));
03555 
03556          ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
03557             ast_get_extension_registrar(e));
03558 
03559          dpc->total_exten++;
03560          /* walk next extension peers */
03561          p = e;   /* skip the first one, we already got it */
03562          while ( (p = ast_walk_extension_priorities(e, p)) ) {
03563             const char *el = ast_get_extension_label(p);
03564             dpc->total_prio++;
03565             if (el)
03566                snprintf(buf, sizeof(buf), "   [%s]", el);
03567             else
03568                buf[0] = '\0';
03569             print_ext(p, buf2, sizeof(buf2));
03570 
03571             ast_cli(fd,"  %-17s %-45s [%s]\n", buf, buf2,
03572                ast_get_extension_registrar(p));
03573          }
03574       }
03575 
03576       /* walk included and write info ... */
03577       i = NULL;
03578       while ( (i = ast_walk_context_includes(c, i)) ) {
03579          snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
03580          if (exten) {
03581             /* Check all includes for the requested extension */
03582             if (includecount >= AST_PBX_MAX_STACK) {
03583                ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
03584             } else {
03585                int dupe=0;
03586                int x;
03587                for (x=0;x<includecount;x++) {
03588                   if (!strcasecmp(includes[x], ast_get_include_name(i))) {
03589                      dupe++;
03590                      break;
03591                   }
03592                }
03593                if (!dupe) {
03594                   includes[includecount] = ast_get_include_name(i);
03595                   show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
03596                } else {
03597                   ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
03598                }
03599             }
03600          } else {
03601             ast_cli(fd, "  Include =>        %-45s [%s]\n",
03602                buf, ast_get_include_registrar(i));
03603          }
03604       }
03605 
03606       /* walk ignore patterns and write info ... */
03607       ip = NULL;
03608       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
03609          const char *ipname = ast_get_ignorepat_name(ip);
03610          char ignorepat[AST_MAX_EXTENSION];
03611          snprintf(buf, sizeof(buf), "'%s'", ipname);
03612          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
03613          if (!exten || ast_extension_match(ignorepat, exten)) {
03614             ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
03615                buf, ast_get_ignorepat_registrar(ip));
03616          }
03617       }
03618       if (!rinclude) {
03619          struct ast_sw *sw = NULL;
03620          while ( (sw = ast_walk_context_switches(c, sw)) ) {
03621             snprintf(buf, sizeof(buf), "'%s/%s'",
03622                ast_get_switch_name(sw),
03623                ast_get_switch_data(sw));
03624             ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
03625                buf, ast_get_switch_registrar(sw));
03626          }
03627       }
03628 
03629       ast_unlock_context(c);
03630 
03631       /* if we print something in context, make an empty line */
03632       if (context_info_printed)
03633          ast_cli(fd, "\r\n");
03634    }
03635    ast_unlock_contexts();
03636 
03637    return (dpc->total_exten == old_total_exten) ? -1 : res;
03638 }
03639 
03640 static int handle_show_dialplan(int fd, int argc, char *argv[])
03641 {
03642    char *exten = NULL, *context = NULL;
03643    /* Variables used for different counters */
03644    struct dialplan_counters counters;
03645 
03646    const char *incstack[AST_PBX_MAX_STACK];
03647    memset(&counters, 0, sizeof(counters));
03648 
03649    if (argc != 2 && argc != 3)
03650       return RESULT_SHOWUSAGE;
03651 
03652    /* we obtain [exten@]context? if yes, split them ... */
03653    if (argc == 3) {
03654       if (strchr(argv[2], '@')) {   /* split into exten & context */
03655          context = ast_strdupa(argv[2]);
03656          exten = strsep(&context, "@");
03657          /* change empty strings to NULL */
03658          if (ast_strlen_zero(exten))
03659             exten = NULL;
03660       } else { /* no '@' char, only context given */
03661          context = argv[2];
03662       }
03663       if (ast_strlen_zero(context))
03664          context = NULL;
03665    }
03666    /* else Show complete dial plan, context and exten are NULL */
03667    show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
03668 
03669    /* check for input failure and throw some error messages */
03670    if (context && !counters.context_existence) {
03671       ast_cli(fd, "There is no existence of '%s' context\n", context);
03672       return RESULT_FAILURE;
03673    }
03674 
03675    if (exten && !counters.extension_existence) {
03676       if (context)
03677          ast_cli(fd, "There is no existence of %s@%s extension\n",
03678             exten, context);
03679       else
03680          ast_cli(fd,
03681             "There is no existence of '%s' extension in all contexts\n",
03682             exten);
03683       return RESULT_FAILURE;
03684    }
03685 
03686    ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
03687             counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
03688             counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
03689             counters.total_context, counters.total_context == 1 ? "context" : "contexts");
03690 
03691    /* everything ok */
03692    return RESULT_SUCCESS;
03693 }
03694 
03695 /*! \brief CLI support for listing global variables in a parseable way */
03696 static int handle_show_globals(int fd, int argc, char *argv[])
03697 {
03698    int i = 0;
03699    struct ast_var_t *newvariable;
03700 
03701    ast_mutex_lock(&globalslock);
03702    AST_LIST_TRAVERSE (&globals, newvariable, entries) {
03703       i++;
03704       ast_cli(fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
03705    }
03706    ast_mutex_unlock(&globalslock);
03707    ast_cli(fd, "\n    -- %d variables\n", i);
03708 
03709    return RESULT_SUCCESS;
03710 }
03711 
03712 /*! \brief  CLI support for setting global variables */
03713 static int handle_set_global_deprecated(int fd, int argc, char *argv[])
03714 {
03715    if (argc != 4)
03716       return RESULT_SHOWUSAGE;
03717 
03718    pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
03719    ast_cli(fd, "\n    -- Global variable %s set to %s\n", argv[2], argv[3]);
03720 
03721    return RESULT_SUCCESS;
03722 }
03723 
03724 
03725 static int handle_set_global(int fd, int argc, char *argv[])
03726 {
03727    if (argc != 5)
03728       return RESULT_SHOWUSAGE;
03729 
03730    pbx_builtin_setvar_helper(NULL, argv[3], argv[4]);
03731    ast_cli(fd, "\n    -- Global variable %s set to %s\n", argv[3], argv[4]);
03732 
03733    return RESULT_SUCCESS;
03734 }
03735 
03736 
03737 
03738 /*
03739  * CLI entries for upper commands ...
03740  */
03741 static struct ast_cli_entry cli_show_applications_deprecated = {
03742    { "show", "applications", NULL },
03743    handle_show_applications_deprecated, NULL,
03744    NULL, complete_show_applications_deprecated };
03745 
03746 static struct ast_cli_entry cli_show_functions_deprecated = {
03747    { "show", "functions", NULL },
03748    handle_show_functions_deprecated, NULL,
03749         NULL };
03750 
03751 static struct ast_cli_entry cli_show_switches_deprecated = {
03752    { "show", "switches", NULL },
03753    handle_show_switches, NULL,
03754         NULL };
03755 
03756 static struct ast_cli_entry cli_show_hints_deprecated = {
03757    { "show", "hints", NULL },
03758    handle_show_hints, NULL,
03759         NULL };
03760 
03761 static struct ast_cli_entry cli_show_globals_deprecated = {
03762    { "show", "globals", NULL },
03763    handle_show_globals, NULL,
03764         NULL };
03765 
03766 static struct ast_cli_entry cli_show_function_deprecated = {
03767    { "show" , "function", NULL },
03768    handle_show_function_deprecated, NULL,
03769         NULL, complete_show_function };
03770 
03771 static struct ast_cli_entry cli_show_application_deprecated = {
03772    { "show", "application", NULL },
03773    handle_show_application_deprecated, NULL,
03774         NULL, complete_show_application };
03775 
03776 static struct ast_cli_entry cli_show_dialplan_deprecated = {
03777    { "show", "dialplan", NULL },
03778    handle_show_dialplan, NULL,
03779         NULL, complete_show_dialplan_context };
03780 
03781 static struct ast_cli_entry cli_set_global_deprecated = {
03782    { "set", "global", NULL },
03783    handle_set_global_deprecated, NULL,
03784         NULL };
03785 
03786 static struct ast_cli_entry pbx_cli[] = {
03787    { { "core", "show", "applications", NULL },
03788    handle_show_applications, "Shows registered dialplan applications",
03789    show_applications_help, complete_show_applications, &cli_show_applications_deprecated },
03790 
03791    { { "core", "show", "functions", NULL },
03792    handle_show_functions, "Shows registered dialplan functions",
03793    show_functions_help, NULL, &cli_show_functions_deprecated },
03794 
03795    { { "core", "show", "switches", NULL },
03796    handle_show_switches, "Show alternative switches",
03797    show_switches_help, NULL, &cli_show_switches_deprecated },
03798 
03799    { { "core", "show", "hints", NULL },
03800    handle_show_hints, "Show dialplan hints",
03801    show_hints_help, NULL, &cli_show_hints_deprecated },
03802 
03803    { { "core", "show", "globals", NULL },
03804    handle_show_globals, "Show global dialplan variables",
03805    show_globals_help, NULL, &cli_show_globals_deprecated },
03806 
03807    { { "core", "show" , "function", NULL },
03808    handle_show_function, "Describe a specific dialplan function",
03809    show_function_help, complete_show_function, &cli_show_function_deprecated },
03810 
03811    { { "core", "show", "application", NULL },
03812    handle_show_application, "Describe a specific dialplan application",
03813    show_application_help, complete_show_application, &cli_show_application_deprecated },
03814 
03815    { { "core", "set", "global", NULL },
03816    handle_set_global, "Set global dialplan variable",
03817    set_global_help, NULL, &cli_set_global_deprecated },
03818 
03819    { { "dialplan", "show", NULL },
03820    handle_show_dialplan, "Show dialplan",
03821    show_dialplan_help, complete_show_dialplan_context, &cli_show_dialplan_deprecated },
03822 };
03823 
03824 int ast_unregister_application(const char *app)
03825 {
03826    struct ast_app *tmp;
03827 
03828    AST_LIST_LOCK(&apps);
03829    AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
03830       if (!strcasecmp(app, tmp->name)) {
03831          AST_LIST_REMOVE_CURRENT(&apps, list);
03832          if (option_verbose > 1)
03833             ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
03834          free(tmp);
03835          break;
03836       }
03837    }
03838    AST_LIST_TRAVERSE_SAFE_END
03839    AST_LIST_UNLOCK(&apps);
03840 
03841    return tmp ? 0 : -1;
03842 }
03843 
03844 static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
03845 {
03846    struct ast_context *tmp, **local_contexts;
03847    int length = sizeof(struct ast_context) + strlen(name) + 1;
03848 
03849    if (!extcontexts) {
03850       ast_mutex_lock(&conlock);
03851       local_contexts = &contexts;
03852    } else
03853       local_contexts = extcontexts;
03854 
03855    for (tmp = *local_contexts; tmp; tmp = tmp->next) {
03856       if (!strcasecmp(tmp->name, name)) {
03857          if (!existsokay) {
03858             ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
03859             tmp = NULL;
03860          }
03861          if (!extcontexts)
03862             ast_mutex_unlock(&conlock);
03863          return tmp;
03864       }
03865    }
03866    if ((tmp = ast_calloc(1, length))) {
03867       ast_mutex_init(&tmp->lock);
03868       ast_mutex_init(&tmp->macrolock);
03869       strcpy(tmp->name, name);
03870       tmp->root = NULL;
03871       tmp->registrar = registrar;
03872       tmp->next = *local_contexts;
03873       tmp->includes = NULL;
03874       tmp->ignorepats = NULL;
03875       *local_contexts = tmp;
03876       if (option_debug)
03877          ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
03878       if (option_verbose > 2)
03879          ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
03880    }
03881 
03882    if (!extcontexts)
03883       ast_mutex_unlock(&conlock);
03884    return tmp;
03885 }
03886 
03887 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03888 {
03889    return __ast_context_create(extcontexts, name, registrar, 0);
03890 }
03891 
03892 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03893 {
03894    return __ast_context_create(extcontexts, name, registrar, 1);
03895 }
03896 void __ast_context_destroy(struct ast_context *con, const char *registrar);
03897 
03898 struct store_hint {
03899    char *context;
03900    char *exten;
03901    struct ast_state_cb *callbacks;
03902    int laststate;
03903    AST_LIST_ENTRY(store_hint) list;
03904    char data[1];
03905 };
03906 
03907 AST_LIST_HEAD(store_hints, store_hint);
03908 
03909 /* XXX this does not check that multiple contexts are merged */
03910 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
03911 {
03912    struct ast_context *tmp, *lasttmp = NULL;
03913    struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
03914    struct store_hint *this;
03915    struct ast_hint *hint;
03916    struct ast_exten *exten;
03917    int length;
03918    struct ast_state_cb *thiscb, *prevcb;
03919 
03920    /* it is very important that this function hold the hint list lock _and_ the conlock
03921       during its operation; not only do we need to ensure that the list of contexts
03922       and extensions does not change, but also that no hint callbacks (watchers) are
03923       added or removed during the merge/delete process
03924 
03925       in addition, the locks _must_ be taken in this order, because there are already
03926       other code paths that use this order
03927    */
03928    ast_mutex_lock(&conlock);
03929    AST_LIST_LOCK(&hints);
03930 
03931    /* preserve all watchers for hints associated with this registrar */
03932    AST_LIST_TRAVERSE(&hints, hint, list) {
03933       if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
03934          length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
03935          if (!(this = ast_calloc(1, length)))
03936             continue;
03937          this->callbacks = hint->callbacks;
03938          hint->callbacks = NULL;
03939          this->laststate = hint->laststate;
03940          this->context = this->data;
03941          strcpy(this->data, hint->exten->parent->name);
03942          this->exten = this->data + strlen(this->context) + 1;
03943          strcpy(this->exten, hint->exten->exten);
03944          AST_LIST_INSERT_HEAD(&store, this, list);
03945       }
03946    }
03947 
03948    tmp = *extcontexts;
03949    if (registrar) {
03950       /* XXX remove previous contexts from same registrar */
03951       if (option_debug)
03952          ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
03953       __ast_context_destroy(NULL,registrar);
03954       while (tmp) {
03955          lasttmp = tmp;
03956          tmp = tmp->next;
03957       }
03958    } else {
03959       /* XXX remove contexts with the same name */
03960       while (tmp) {
03961          ast_log(LOG_WARNING, "must remove %s  reg %s\n", tmp->name, tmp->registrar);
03962          __ast_context_destroy(tmp,tmp->registrar);
03963          lasttmp = tmp;
03964          tmp = tmp->next;
03965       }
03966    }
03967    if (lasttmp) {
03968       lasttmp->next = contexts;
03969       contexts = *extcontexts;
03970       *extcontexts = NULL;
03971    } else
03972       ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
03973 
03974    /* restore the watchers for hints that can be found; notify those that
03975       cannot be restored
03976    */
03977    while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
03978       exten = ast_hint_extension(NULL, this->context, this->exten);
03979       /* Find the hint in the list of hints */
03980       AST_LIST_TRAVERSE(&hints, hint, list) {
03981          if (hint->exten == exten)
03982             break;
03983       }
03984       if (!exten || !hint) {
03985          /* this hint has been removed, notify the watchers */
03986          prevcb = NULL;
03987          thiscb = this->callbacks;
03988          while (thiscb) {
03989             prevcb = thiscb;
03990             thiscb = thiscb->next;
03991             prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
03992             free(prevcb);
03993             }
03994       } else {
03995          thiscb = this->callbacks;
03996          while (thiscb->next)
03997             thiscb = thiscb->next;
03998          thiscb->next = hint->callbacks;
03999          hint->callbacks = this->callbacks;
04000          hint->laststate = this->laststate;
04001       }
04002       free(this);
04003    }
04004 
04005    AST_LIST_UNLOCK(&hints);
04006    ast_mutex_unlock(&conlock);
04007 
04008    return;
04009 }
04010 
04011 /*
04012  * errno values
04013  *  EBUSY  - can't lock
04014  *  ENOENT - no existence of context
04015  */
04016 int ast_context_add_include(const char *context, const char *include, const char *registrar)
04017 {
04018    int ret = -1;
04019    struct ast_context *c = find_context_locked(context);
04020 
04021    if (c) {
04022       ret = ast_context_add_include2(c, include, registrar);
04023       ast_unlock_contexts();
04024    }
04025    return ret;
04026 }
04027 
04028 /*! \brief Helper for get_range.
04029  * return the index of the matching entry, starting from 1.
04030  * If names is not supplied, try numeric values.
04031  */
04032 static int lookup_name(const char *s, char *const names[], int max)
04033 {
04034    int i;
04035 
04036    if (names) {
04037       for (i = 0; names[i]; i++) {
04038          if (!strcasecmp(s, names[i]))
04039             return i+1;
04040       }
04041    } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
04042       return i;
04043    }
04044    return 0; /* error return */
04045 }
04046 
04047 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
04048  * names, if supplied, is an array of names that should be mapped to numbers.
04049  */
04050 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
04051 {
04052    int s, e; /* start and ending position */
04053    unsigned int mask = 0;
04054 
04055    /* Check for whole range */
04056    if (ast_strlen_zero(src) || !strcmp(src, "*")) {
04057       s = 0;
04058       e = max - 1;
04059    } else {
04060       /* Get start and ending position */
04061       char *c = strchr(src, '-');
04062       if (c)
04063          *c++ = '\0';
04064       /* Find the start */
04065       s = lookup_name(src, names, max);
04066       if (!s) {
04067          ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
04068          return 0;
04069       }
04070       s--;
04071       if (c) { /* find end of range */
04072          e = lookup_name(c, names, max);
04073          if (!e) {
04074             ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
04075             return 0;
04076          }
04077          e--;
04078       } else
04079          e = s;
04080    }
04081    /* Fill the mask. Remember that ranges are cyclic */
04082    mask = 1 << e; /* initialize with last element */
04083    while (s != e) {
04084       if (s >= max) {
04085          s = 0;
04086          mask |= (1 << s);
04087       } else {
04088          mask |= (1 << s);
04089          s++;
04090       }
04091    }
04092    return mask;
04093 }
04094 
04095 /*! \brief store a bitmask of valid times, one bit each 2 minute */
04096 static void get_timerange(struct ast_timing *i, char *times)
04097 {
04098    char *e;
04099    int x;
04100    int s1, s2;
04101    int e1, e2;
04102    /* int cth, ctm; */
04103 
04104    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
04105    memset(i->minmask, 0, sizeof(i->minmask));
04106 
04107    /* 2-minutes per bit, since the mask has only 32 bits :( */
04108    /* Star is all times */
04109    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
04110       for (x=0; x<24; x++)
04111          i->minmask[x] = 0x3fffffff; /* 30 bits */
04112       return;
04113    }
04114    /* Otherwise expect a range */
04115    e = strchr(times, '-');
04116    if (!e) {
04117       ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
04118       return;
04119    }
04120    *e++ = '\0';
04121    /* XXX why skip non digits ? */
04122    while (*e && !isdigit(*e))
04123       e++;
04124    if (!*e) {
04125       ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
04126       return;
04127    }
04128    if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
04129       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
04130       return;
04131    }
04132    if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
04133       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
04134       return;
04135    }
04136    /* XXX this needs to be optimized */
04137 #if 1
04138    s1 = s1 * 30 + s2/2;
04139    if ((s1 < 0) || (s1 >= 24*30)) {
04140       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
04141       return;
04142    }
04143    e1 = e1 * 30 + e2/2;
04144    if ((e1 < 0) || (e1 >= 24*30)) {
04145       ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
04146       return;
04147    }
04148    /* Go through the time and enable each appropriate bit */
04149    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
04150       i->minmask[x/30] |= (1 << (x % 30));
04151    }
04152    /* Do the last one */
04153    i->minmask[x/30] |= (1 << (x % 30));
04154 #else
04155    for (cth=0; cth<24; cth++) {
04156       /* Initialize masks to blank */
04157       i->minmask[cth] = 0;
04158       for (ctm=0; ctm<30; ctm++) {
04159          if (
04160          /* First hour with more than one hour */
04161                (((cth == s1) && (ctm >= s2)) &&
04162                 ((cth < e1)))
04163          /* Only one hour */
04164          ||    (((cth == s1) && (ctm >= s2)) &&
04165                 ((cth == e1) && (ctm <= e2)))
04166          /* In between first and last hours (more than 2 hours) */
04167          ||    ((cth > s1) &&
04168                 (cth < e1))
04169          /* Last hour with more than one hour */
04170          ||    ((cth > s1) &&
04171                 ((cth == e1) && (ctm <= e2)))
04172          )
04173             i->minmask[cth] |= (1 << (ctm / 2));
04174       }
04175    }
04176 #endif
04177    /* All done */
04178    return;
04179 }
04180 
04181 static char *days[] =
04182 {
04183    "sun",
04184    "mon",
04185    "tue",
04186    "wed",
04187    "thu",
04188    "fri",
04189    "sat",
04190    NULL,
04191 };
04192 
04193 static char *months[] =
04194 {
04195    "jan",
04196    "feb",
04197    "mar",
04198    "apr",
04199    "may",
04200    "jun",
04201    "jul",
04202    "aug",
04203    "sep",
04204    "oct",
04205    "nov",
04206    "dec",
04207    NULL,
04208 };
04209 
04210 int ast_build_timing(struct ast_timing *i, const char *info_in)
04211 {
04212    char info_save[256];
04213    char *info;
04214 
04215    /* Check for empty just in case */
04216    if (ast_strlen_zero(info_in))
04217       return 0;
04218    /* make a copy just in case we were passed a static string */
04219    ast_copy_string(info_save, info_in, sizeof(info_save));
04220    info = info_save;
04221    /* Assume everything except time */
04222    i->monthmask = 0xfff;   /* 12 bits */
04223    i->daymask = 0x7fffffffU; /* 31 bits */
04224    i->dowmask = 0x7f; /* 7 bits */
04225    /* on each call, use strsep() to move info to the next argument */
04226    get_timerange(i, strsep(&info, "|"));
04227    if (info)
04228       i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
04229    if (info)
04230       i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
04231    if (info)
04232       i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
04233    return 1;
04234 }
04235 
04236 int ast_check_timing(const struct ast_timing *i)
04237 {
04238    struct tm tm;
04239    time_t t = time(NULL);
04240 
04241    localtime_r(&t,&tm);
04242 
04243    /* If it's not the right month, return */
04244    if (!(i->monthmask & (1 << tm.tm_mon)))
04245       return 0;
04246 
04247    /* If it's not that time of the month.... */
04248    /* Warning, tm_mday has range 1..31! */
04249    if (!(i->daymask & (1 << (tm.tm_mday-1))))
04250       return 0;
04251 
04252    /* If it's not the right day of the week */
04253    if (!(i->dowmask & (1 << tm.tm_wday)))
04254       return 0;
04255 
04256    /* Sanity check the hour just to be safe */
04257    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
04258       ast_log(LOG_WARNING, "Insane time...\n");
04259       return 0;
04260    }
04261 
04262    /* Now the tough part, we calculate if it fits
04263       in the right time based on min/hour */
04264    if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
04265       return 0;
04266 
04267    /* If we got this far, then we're good */
04268    return 1;
04269 }
04270 
04271 /*
04272  * errno values
04273  *  ENOMEM - out of memory
04274  *  EBUSY  - can't lock
04275  *  EEXIST - already included
04276  *  EINVAL - there is no existence of context for inclusion
04277  */
04278 int ast_context_add_include2(struct ast_context *con, const char *value,
04279    const char *registrar)
04280 {
04281    struct ast_include *new_include;
04282    char *c;
04283    struct ast_include *i, *il = NULL; /* include, include_last */
04284    int length;
04285    char *p;
04286 
04287    length = sizeof(struct ast_include);
04288    length += 2 * (strlen(value) + 1);
04289 
04290    /* allocate new include structure ... */
04291    if (!(new_include = ast_calloc(1, length)))
04292       return -1;
04293    /* Fill in this structure. Use 'p' for assignments, as the fields
04294     * in the structure are 'const char *'
04295     */
04296    p = new_include->stuff;
04297    new_include->name = p;
04298    strcpy(p, value);
04299    p += strlen(value) + 1;
04300    new_include->rname = p;
04301    strcpy(p, value);
04302    /* Strip off timing info, and process if it is there */
04303    if ( (c = strchr(p, '|')) ) {
04304       *c++ = '\0';
04305            new_include->hastime = ast_build_timing(&(new_include->timing), c);
04306    }
04307    new_include->next      = NULL;
04308    new_include->registrar = registrar;
04309 
04310    ast_mutex_lock(&con->lock);
04311 
04312    /* ... go to last include and check if context is already included too... */
04313    for (i = con->includes; i; i = i->next) {
04314       if (!strcasecmp(i->name, new_include->name)) {
04315          free(new_include);
04316          ast_mutex_unlock(&con->lock);
04317          errno = EEXIST;
04318          return -1;
04319       }
04320       il = i;
04321    }
04322 
04323    /* ... include new context into context list, unlock, return */
04324    if (il)
04325       il->next = new_include;
04326    else
04327       con->includes = new_include;
04328    if (option_verbose > 2)
04329       ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
04330    ast_mutex_unlock(&con->lock);
04331 
04332    return 0;
04333 }
04334 
04335 /*
04336  * errno values
04337  *  EBUSY  - can't lock
04338  *  ENOENT - no existence of context
04339  */
04340 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
04341 {
04342    int ret = -1;
04343    struct ast_context *c = find_context_locked(context);
04344 
04345    if (c) { /* found, add switch to this context */
04346       ret = ast_context_add_switch2(c, sw, data, eval, registrar);
04347       ast_unlock_contexts();
04348    }
04349    return ret;
04350 }
04351 
04352 /*
04353  * errno values
04354  *  ENOMEM - out of memory
04355  *  EBUSY  - can't lock
04356  *  EEXIST - already included
04357  *  EINVAL - there is no existence of context for inclusion
04358  */
04359 int ast_context_add_switch2(struct ast_context *con, const char *value,
04360    const char *data, int eval, const char *registrar)
04361 {
04362    struct ast_sw *new_sw;
04363    struct ast_sw *i;
04364    int length;
04365    char *p;
04366 
04367    length = sizeof(struct ast_sw);
04368    length += strlen(value) + 1;
04369    if (data)
04370       length += strlen(data);
04371    length++;
04372    if (eval) {
04373       /* Create buffer for evaluation of variables */
04374       length += SWITCH_DATA_LENGTH;
04375       length++;
04376    }
04377 
04378    /* allocate new sw structure ... */
04379    if (!(new_sw = ast_calloc(1, length)))
04380       return -1;
04381    /* ... fill in this structure ... */
04382    p = new_sw->stuff;
04383    new_sw->name = p;
04384    strcpy(new_sw->name, value);
04385    p += strlen(value) + 1;
04386    new_sw->data = p;
04387    if (data) {
04388       strcpy(new_sw->data, data);
04389       p += strlen(data) + 1;
04390    } else {
04391       strcpy(new_sw->data, "");
04392       p++;
04393    }
04394    if (eval)
04395       new_sw->tmpdata = p;
04396    new_sw->eval     = eval;
04397    new_sw->registrar = registrar;
04398 
04399    /* ... try to lock this context ... */
04400    ast_mutex_lock(&con->lock);
04401 
04402    /* ... go to last sw and check if context is already swd too... */
04403    AST_LIST_TRAVERSE(&con->alts, i, list) {
04404       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
04405          free(new_sw);
04406          ast_mutex_unlock(&con->lock);
04407          errno = EEXIST;
04408          return -1;
04409       }
04410    }
04411 
04412    /* ... sw new context into context list, unlock, return */
04413    AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
04414 
04415    if (option_verbose > 2)
04416       ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
04417 
04418    ast_mutex_unlock(&con->lock);
04419 
04420    return 0;
04421 }
04422 
04423 /*
04424  * EBUSY  - can't lock
04425  * ENOENT - there is not context existence
04426  */
04427 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
04428 {
04429    int ret = -1;
04430    struct ast_context *c = find_context_locked(context);
04431 
04432    if (c) {
04433       ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
04434       ast_unlock_contexts();
04435    }
04436    return ret;
04437 }
04438 
04439 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
04440 {
04441    struct ast_ignorepat *ip, *ipl = NULL;
04442 
04443    ast_mutex_lock(&con->lock);
04444 
04445    for (ip = con->ignorepats; ip; ip = ip->next) {
04446       if (!strcmp(ip->pattern, ignorepat) &&
04447          (!registrar || (registrar == ip->registrar))) {
04448          if (ipl) {
04449             ipl->next = ip->next;
04450             free(ip);
04451          } else {
04452             con->ignorepats = ip->next;
04453             free(ip);
04454          }
04455          ast_mutex_unlock(&con->lock);
04456          return 0;
04457       }
04458       ipl = ip;
04459    }
04460 
04461    ast_mutex_unlock(&con->lock);
04462    errno = EINVAL;
04463    return -1;
04464 }
04465 
04466 /*
04467  * EBUSY - can't lock
04468  * ENOENT - there is no existence of context
04469  */
04470 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
04471 {
04472    int ret = -1;
04473    struct ast_context *c = find_context_locked(context);
04474 
04475    if (c) {
04476       ret = ast_context_add_ignorepat2(c, value, registrar);
04477       ast_unlock_contexts();
04478    }
04479    return ret;
04480 }
04481 
04482 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
04483 {
04484    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
04485    int length;
04486    length = sizeof(struct ast_ignorepat);
04487    length += strlen(value) + 1;
04488    if (!(ignorepat = ast_calloc(1, length)))
04489       return -1;
04490    /* The cast to char * is because we need to write the initial value.
04491     * The field is not supposed to be modified otherwise
04492     */
04493    strcpy((char *)ignorepat->pattern, value);
04494    ignorepat->next = NULL;
04495    ignorepat->registrar = registrar;
04496    ast_mutex_lock(&con->lock);
04497    for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
04498       ignorepatl = ignorepatc;
04499       if (!strcasecmp(ignorepatc->pattern, value)) {
04500          /* Already there */
04501          ast_mutex_unlock(&con->lock);
04502          errno = EEXIST;
04503          return -1;
04504       }
04505    }
04506    if (ignorepatl)
04507       ignorepatl->next = ignorepat;
04508    else
04509       con->ignorepats = ignorepat;
04510    ast_mutex_unlock(&con->lock);
04511    return 0;
04512 
04513 }
04514 
04515 int ast_ignore_pattern(const char *context, const char *pattern)
04516 {
04517    struct ast_context *con = ast_context_find(context);
04518    if (con) {
04519       struct ast_ignorepat *pat;
04520       for (pat = con->ignorepats; pat; pat = pat->next) {
04521          if (ast_extension_match(pat->pattern, pattern))
04522             return 1;
04523       }
04524    }
04525 
04526    return 0;
04527 }
04528 
04529 /*
04530  * EBUSY   - can't lock
04531  * ENOENT  - no existence of context
04532  *
04533  */
04534 int ast_add_extension(const char *context, int replace, const char *extension,
04535    int priority, const char *label, const char *callerid,
04536    const char *application, void *data, void (*datad)(void *), const char *registrar)
04537 {
04538    int ret = -1;
04539    struct ast_context *c = find_context_locked(context);
04540 
04541    if (c) {
04542       ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
04543          application, data, datad, registrar);
04544       ast_unlock_contexts();
04545    }
04546    return ret;
04547 }
04548 
04549 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04550 {
04551    if (!chan)
04552       return -1;
04553 
04554    if (!ast_strlen_zero(context))
04555       ast_copy_string(chan->context, context, sizeof(chan->context));
04556    if (!ast_strlen_zero(exten))
04557       ast_copy_string(chan->exten, exten, sizeof(chan->exten));
04558    if (priority > -1) {
04559       chan->priority = priority;
04560       /* see flag description in channel.h for explanation */
04561       if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
04562          chan->priority--;
04563    }
04564 
04565    return 0;
04566 }
04567 
04568 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04569 {
04570    int res = 0;
04571 
04572    ast_channel_lock(chan);
04573 
04574    if (chan->pbx) { /* This channel is currently in the PBX */
04575       ast_explicit_goto(chan, context, exten, priority);
04576       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
04577    } else {
04578       /* In order to do it when the channel doesn't really exist within
04579          the PBX, we have to make a new channel, masquerade, and start the PBX
04580          at the new location */
04581       struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
04582       if (chan->cdr) {
04583          tmpchan->cdr = ast_cdr_dup(chan->cdr);
04584       }
04585       if (!tmpchan)
04586          res = -1;
04587       else {
04588          /* Make formats okay */
04589          tmpchan->readformat = chan->readformat;
04590          tmpchan->writeformat = chan->writeformat;
04591          /* Setup proper location */
04592          ast_explicit_goto(tmpchan,
04593             S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
04594 
04595          /* Masquerade into temp channel */
04596          ast_channel_masquerade(tmpchan, chan);
04597 
04598          /* Grab the locks and get going */
04599          ast_channel_lock(tmpchan);
04600          ast_do_masquerade(tmpchan);
04601          ast_channel_unlock(tmpchan);
04602          /* Start the PBX going on our stolen channel */
04603          if (ast_pbx_start(tmpchan)) {
04604             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
04605             ast_hangup(tmpchan);
04606             res = -1;
04607          }
04608       }
04609    }
04610    ast_channel_unlock(chan);
04611    return res;
04612 }
04613 
04614 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
04615 {
04616    struct ast_channel *chan;
04617    int res = -1;
04618 
04619    chan = ast_get_channel_by_name_locked(channame);
04620    if (chan) {
04621       res = ast_async_goto(chan, context, exten, priority);
04622       ast_channel_unlock(chan);
04623    }
04624    return res;
04625 }
04626 
04627 /*! \brief copy a string skipping whitespace */
04628 static int ext_strncpy(char *dst, const char *src, int len)
04629 {
04630    int count=0;
04631 
04632    while (*src && (count < len - 1)) {
04633       switch(*src) {
04634       case ' ':
04635          /* otherwise exten => [a-b],1,... doesn't work */
04636          /*    case '-': */
04637          /* Ignore */
04638          break;
04639       default:
04640          *dst = *src;
04641          dst++;
04642       }
04643       src++;
04644       count++;
04645    }
04646    *dst = '\0';
04647 
04648    return count;
04649 }
04650 
04651 /*! \brief add the extension in the priority chain.
04652  * returns 0 on success, -1 on failure
04653  */
04654 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
04655    struct ast_exten *el, struct ast_exten *e, int replace)
04656 {
04657    struct ast_exten *ep;
04658 
04659    for (ep = NULL; e ; ep = e, e = e->peer) {
04660       if (e->priority >= tmp->priority)
04661          break;
04662    }
04663    if (!e) {   /* go at the end, and ep is surely set because the list is not empty */
04664       ep->peer = tmp;
04665       return 0;   /* success */
04666    }
04667    if (e->priority == tmp->priority) {
04668       /* Can't have something exactly the same.  Is this a
04669          replacement?  If so, replace, otherwise, bonk. */
04670       if (!replace) {
04671          ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
04672          if (tmp->datad)
04673             tmp->datad(tmp->data);
04674          free(tmp);
04675          return -1;
04676       }
04677       /* we are replacing e, so copy the link fields and then update
04678        * whoever pointed to e to point to us
04679        */
04680       tmp->next = e->next; /* not meaningful if we are not first in the peer list */
04681       tmp->peer = e->peer; /* always meaningful */
04682       if (ep)        /* We're in the peer list, just insert ourselves */
04683          ep->peer = tmp;
04684       else if (el)      /* We're the first extension. Take over e's functions */
04685          el->next = tmp;
04686       else        /* We're the very first extension.  */
04687          con->root = tmp;
04688       if (tmp->priority == PRIORITY_HINT)
04689          ast_change_hint(e,tmp);
04690       /* Destroy the old one */
04691       if (e->datad)
04692          e->datad(e->data);
04693       free(e);
04694    } else { /* Slip ourselves in just before e */
04695       tmp->peer = e;
04696       tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
04697       if (ep)        /* Easy enough, we're just in the peer list */
04698          ep->peer = tmp;
04699       else {         /* we are the first in some peer list, so link in the ext list */
04700          if (el)
04701             el->next = tmp;   /* in the middle... */
04702          else
04703             con->root = tmp; /* ... or at the head */
04704          e->next = NULL;   /* e is no more at the head, so e->next must be reset */
04705       }
04706       /* And immediately return success. */
04707       if (tmp->priority == PRIORITY_HINT)
04708           ast_add_hint(tmp);
04709    }
04710    return 0;
04711 }
04712 
04713 /*! \brief
04714  * Main interface to add extensions to the list for out context.
04715  *
04716  * We sort extensions in order of matching preference, so that we can
04717  * stop the search as soon as we find a suitable match.
04718  * This ordering also takes care of wildcards such as '.' (meaning
04719  * "one or more of any character") and '!' (which is 'earlymatch',
04720  * meaning "zero or more of any character" but also impacts the
04721  * return value from CANMATCH and EARLYMATCH.
04722  *
04723  * The extension match rules defined in the devmeeting 2006.05.05 are
04724  * quite simple: WE SELECT THE LONGEST MATCH.
04725  * In detail, "longest" means the number of matched characters in
04726  * the extension. In case of ties (e.g. _XXX and 333) in the length
04727  * of a pattern, we give priority to entries with the smallest cardinality
04728  * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
04729  * while the latter has 7, etc.
04730  * In case of same cardinality, the first element in the range counts.
04731  * If we still have a tie, any final '!' will make this as a possibly
04732  * less specific pattern.
04733  *
04734  * EBUSY - can't lock
04735  * EEXIST - extension with the same priority exist and no replace is set
04736  *
04737  */
04738 int ast_add_extension2(struct ast_context *con,
04739    int replace, const char *extension, int priority, const char *label, const char *callerid,
04740    const char *application, void *data, void (*datad)(void *),
04741    const char *registrar)
04742 {
04743    /*
04744     * Sort extensions (or patterns) according to the rules indicated above.
04745     * These are implemented by the function ext_cmp()).
04746     * All priorities for the same ext/pattern/cid are kept in a list,
04747     * using the 'peer' field  as a link field..
04748     */
04749    struct ast_exten *tmp, *e, *el = NULL;
04750    int res;
04751    int length;
04752    char *p;
04753    char expand_buf[VAR_BUF_SIZE] = { 0, };
04754 
04755    /* if we are adding a hint, and there are global variables, and the hint
04756       contains variable references, then expand them
04757    */
04758    ast_mutex_lock(&globalslock);
04759    if (priority == PRIORITY_HINT && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
04760       pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
04761       application = expand_buf;
04762    }
04763    ast_mutex_unlock(&globalslock);
04764 
04765    length = sizeof(struct ast_exten);
04766    length += strlen(extension) + 1;
04767    length += strlen(application) + 1;
04768    if (label)
04769       length += strlen(label) + 1;
04770    if (callerid)
04771       length += strlen(callerid) + 1;
04772    else
04773       length ++;  /* just the '\0' */
04774 
04775    /* Be optimistic:  Build the extension structure first */
04776    if (!(tmp = ast_calloc(1, length)))
04777       return -1;
04778 
04779    /* use p as dst in assignments, as the fields are const char * */
04780    p = tmp->stuff;
04781    if (label) {
04782       tmp->label = p;
04783       strcpy(p, label);
04784       p += strlen(label) + 1;
04785    }
04786    tmp->exten = p;
04787    p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
04788    tmp->priority = priority;
04789    tmp->cidmatch = p;   /* but use p for assignments below */
04790    if (callerid) {
04791       p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
04792       tmp->matchcid = 1;
04793    } else {
04794       *p++ = '\0';
04795       tmp->matchcid = 0;
04796    }
04797    tmp->app = p;
04798    strcpy(p, application);
04799    tmp->parent = con;
04800    tmp->data = data;
04801    tmp->datad = datad;
04802    tmp->registrar = registrar;
04803 
04804    ast_mutex_lock(&con->lock);
04805    res = 0; /* some compilers will think it is uninitialized otherwise */
04806    for (e = con->root; e; el = e, e = e->next) {   /* scan the extension list */
04807       res = ext_cmp(e->exten, extension);
04808       if (res == 0) { /* extension match, now look at cidmatch */
04809          if (!e->matchcid && !tmp->matchcid)
04810             res = 0;
04811          else if (tmp->matchcid && !e->matchcid)
04812             res = 1;
04813          else if (e->matchcid && !tmp->matchcid)
04814             res = -1;
04815          else
04816             res = strcasecmp(e->cidmatch, tmp->cidmatch);
04817       }
04818       if (res >= 0)
04819          break;
04820    }
04821    if (e && res == 0) { /* exact match, insert in the pri chain */
04822       res = add_pri(con, tmp, el, e, replace);
04823       ast_mutex_unlock(&con->lock);
04824       if (res < 0) {
04825          errno = EEXIST;   /* XXX do we care ? */
04826          return 0; /* XXX should we return -1 maybe ? */
04827       }
04828    } else {
04829       /*
04830        * not an exact match, this is the first entry with this pattern,
04831        * so insert in the main list right before 'e' (if any)
04832        */
04833       tmp->next = e;
04834       if (el)
04835          el->next = tmp;
04836       else
04837          con->root = tmp;
04838       ast_mutex_unlock(&con->lock);
04839       if (tmp->priority == PRIORITY_HINT)
04840          ast_add_hint(tmp);
04841    }
04842    if (option_debug) {
04843       if (tmp->matchcid) {
04844          if (option_debug)
04845             ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
04846                tmp->exten, tmp->priority, tmp->cidmatch, con->name);
04847       } else {
04848          if (option_debug)
04849             ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
04850                tmp->exten, tmp->priority, con->name);
04851       }
04852    }
04853    if (option_verbose > 2) {
04854       if (tmp->matchcid) {
04855          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
04856             tmp->exten, tmp->priority, tmp->cidmatch, con->name);
04857       } else {
04858          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
04859             tmp->exten, tmp->priority, con->name);
04860       }
04861    }
04862    return 0;
04863 }
04864 
04865 struct async_stat {
04866    pthread_t p;
04867    struct ast_channel *chan;
04868    char context[AST_MAX_CONTEXT];
04869    char exten[AST_MAX_EXTENSION];
04870    int priority;
04871    int timeout;
04872    char app[AST_MAX_EXTENSION];
04873    char appdata[1024];
04874 };
04875 
04876 static void *async_wait(void *data)
04877 {
04878    struct async_stat *as = data;
04879    struct ast_channel *chan = as->chan;
04880    int timeout = as->timeout;
04881    int res;
04882    struct ast_frame *f;
04883    struct ast_app *app;
04884 
04885    while (timeout && (chan->_state != AST_STATE_UP)) {
04886       res = ast_waitfor(chan, timeout);
04887       if (res < 1)
04888          break;
04889       if (timeout > -1)
04890          timeout = res;
04891       f = ast_read(chan);
04892       if (!f)
04893          break;
04894       if (f->frametype == AST_FRAME_CONTROL) {
04895          if ((f->subclass == AST_CONTROL_BUSY)  ||
04896              (f->subclass == AST_CONTROL_CONGESTION) ) {
04897             ast_frfree(f);
04898             break;
04899          }
04900       }
04901       ast_frfree(f);
04902    }
04903    if (chan->_state == AST_STATE_UP) {
04904       if (!ast_strlen_zero(as->app)) {
04905          app = pbx_findapp(as->app);
04906          if (app) {
04907             if (option_verbose > 2)
04908                ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
04909             pbx_exec(chan, app, as->appdata);
04910          } else
04911             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
04912       } else {
04913          if (!ast_strlen_zero(as->context))
04914             ast_copy_string(chan->context, as->context, sizeof(chan->context));
04915          if (!ast_strlen_zero(as->exten))
04916             ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
04917          if (as->priority > 0)
04918             chan->priority = as->priority;
04919          /* Run the PBX */
04920          if (ast_pbx_run(chan)) {
04921             ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
04922          } else {
04923             /* PBX will have taken care of this */
04924             chan = NULL;
04925          }
04926       }
04927    }
04928    free(as);
04929    if (chan)
04930       ast_hangup(chan);
04931    return NULL;
04932 }
04933 
04934 /*! Function to post an empty cdr after a spool call fails.
04935  *
04936  *  This function posts an empty cdr for a failed spool call
04937  *
04938  */
04939 static int ast_pbx_outgoing_cdr_failed(void)
04940 {
04941    /* allocate a channel */
04942    struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0);
04943 
04944    if (!chan)
04945       return -1;  /* failure */
04946 
04947    if (!chan->cdr) {
04948       /* allocation of the cdr failed */
04949       ast_channel_free(chan);   /* free the channel */
04950       return -1;                /* return failure */
04951    }
04952 
04953    /* allocation of the cdr was successful */
04954    ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
04955    ast_cdr_start(chan->cdr);       /* record the start and stop time */
04956    ast_cdr_end(chan->cdr);
04957    ast_cdr_failed(chan->cdr);      /* set the status to failed */
04958    ast_cdr_detach(chan->cdr);      /* post and free the record */
04959    ast_channel_free(chan);         /* free the channel */
04960 
04961    return 0;  /* success */
04962 }
04963 
04964 int ast_pbx_outgoing_exten(const char *type, int format, void *data, int timeout, const char *context, const char *exten, int priority, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **channel)
04965 {
04966    struct ast_channel *chan;
04967    struct async_stat *as;
04968    int res = -1, cdr_res = -1;
04969    struct outgoing_helper oh;
04970    pthread_attr_t attr;
04971 
04972    if (sync) {
04973       LOAD_OH(oh);
04974       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
04975       if (channel) {
04976          *channel = chan;
04977          if (chan)
04978             ast_channel_lock(chan);
04979       }
04980       if (chan) {
04981          if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
04982             ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
04983          } else {
04984             chan->cdr = ast_cdr_alloc();   /* allocate a cdr for the channel */
04985             if (!chan->cdr) {
04986                /* allocation of the cdr failed */
04987                free(chan->pbx);
04988                res = -1;
04989                goto outgoing_exten_cleanup;
04990             }
04991             /* allocation of the cdr was successful */
04992             ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
04993             ast_cdr_start(chan->cdr);
04994          }
04995          if (chan->_state == AST_STATE_UP) {
04996                res = 0;
04997             if (option_verbose > 3)
04998                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
04999 
05000             if (sync > 1) {
05001                if (channel)
05002                   ast_channel_unlock(chan);
05003                if (ast_pbx_run(chan)) {
05004                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
05005                   if (channel)
05006                      *channel = NULL;
05007                   ast_hangup(chan);
05008                   res = -1;
05009                }
05010             } else {
05011                if (ast_pbx_start(chan)) {
05012                   ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
05013                   if (channel) {
05014                      *channel = NULL;
05015                      ast_channel_unlock(chan);
05016                   }
05017                   ast_hangup(chan);
05018                   res = -1;
05019                }
05020             }
05021          } else {
05022             if (option_verbose > 3)
05023                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05024 
05025             if(chan->cdr) { /* update the cdr */
05026                /* here we update the status of the call, which sould be busy.
05027                 * if that fails then we set the status to failed */
05028                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05029                   ast_cdr_failed(chan->cdr);
05030             }
05031 
05032             if (channel) {
05033                *channel = NULL;
05034                ast_channel_unlock(chan);
05035             }
05036             ast_hangup(chan);
05037          }
05038       }
05039 
05040       if (res < 0) { /* the call failed for some reason */
05041          if (*reason == 0) { /* if the call failed (not busy or no answer)
05042                         * update the cdr with the failed message */
05043             cdr_res = ast_pbx_outgoing_cdr_failed();
05044             if (cdr_res != 0) {
05045                res = cdr_res;
05046                goto outgoing_exten_cleanup;
05047             }
05048          }
05049 
05050          /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
05051          /* check if "failed" exists */
05052          if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
05053             chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
05054             if (chan) {
05055                if (!ast_strlen_zero(context))
05056                   ast_copy_string(chan->context, context, sizeof(chan->context));
05057                set_ext_pri(chan, "failed", 1);
05058                ast_set_variables(chan, vars);
05059                if (account)
05060                   ast_cdr_setaccount(chan, account);
05061                ast_pbx_run(chan);
05062             }
05063          }
05064       }
05065    } else {
05066       if (!(as = ast_calloc(1, sizeof(*as)))) {
05067          res = -1;
05068          goto outgoing_exten_cleanup;
05069       }
05070       chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
05071       if (channel) {
05072          *channel = chan;
05073          if (chan)
05074             ast_channel_lock(chan);
05075       }
05076       if (!chan) {
05077          free(as);
05078          res = -1;
05079          goto outgoing_exten_cleanup;
05080       }
05081       as->chan = chan;
05082       ast_copy_string(as->context, context, sizeof(as->context));
05083       set_ext_pri(as->chan,  exten, priority);
05084       as->timeout = timeout;
05085       ast_set_variables(chan, vars);
05086       if (account)
05087          ast_cdr_setaccount(chan, account);
05088       pthread_attr_init(&attr);
05089       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05090       if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05091          ast_log(LOG_WARNING, "Failed to start async wait\n");
05092          free(as);
05093          if (channel) {
05094             *channel = NULL;
05095             ast_channel_unlock(chan);
05096          }
05097          ast_hangup(chan);
05098          res = -1;
05099          pthread_attr_destroy(&attr);
05100          goto outgoing_exten_cleanup;
05101       }
05102       pthread_attr_destroy(&attr);
05103       res = 0;
05104    }
05105 outgoing_exten_cleanup:
05106    ast_variables_destroy(vars);
05107    return res;
05108 }
05109 
05110 struct app_tmp {
05111    char app[256];
05112    char data[256];
05113    struct ast_channel *chan;
05114    pthread_t t;
05115 };
05116 
05117 /*! \brief run the application and free the descriptor once done */
05118 static void *ast_pbx_run_app(void *data)
05119 {
05120    struct app_tmp *tmp = data;
05121    struct ast_app *app;
05122    app = pbx_findapp(tmp->app);
05123    if (app) {
05124       if (option_verbose > 3)
05125          ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
05126       pbx_exec(tmp->chan, app, tmp->data);
05127    } else
05128       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
05129    ast_hangup(tmp->chan);
05130    free(tmp);
05131    return NULL;
05132 }
05133 
05134 int ast_pbx_outgoing_app(const char *type, int format, void *data, int timeout, const char *app, const char *appdata, int *reason, int sync, const char *cid_num, const char *cid_name, struct ast_variable *vars, const char *account, struct ast_channel **locked_channel)
05135 {
05136    struct ast_channel *chan;
05137    struct app_tmp *tmp;
05138    int res = -1, cdr_res = -1;
05139    struct outgoing_helper oh;
05140    pthread_attr_t attr;
05141 
05142    memset(&oh, 0, sizeof(oh));
05143    oh.vars = vars;
05144    oh.account = account;
05145 
05146    if (locked_channel)
05147       *locked_channel = NULL;
05148    if (ast_strlen_zero(app)) {
05149       res = -1;
05150       goto outgoing_app_cleanup;
05151    }
05152    if (sync) {
05153       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05154       if (chan) {
05155          if (chan->cdr) { /* check if the channel already has a cdr record, if not give it one */
05156             ast_log(LOG_WARNING, "%s already has a call record??\n", chan->name);
05157          } else {
05158             chan->cdr = ast_cdr_alloc();   /* allocate a cdr for the channel */
05159             if(!chan->cdr) {
05160                /* allocation of the cdr failed */
05161                free(chan->pbx);
05162                res = -1;
05163                goto outgoing_app_cleanup;
05164             }
05165             /* allocation of the cdr was successful */
05166             ast_cdr_init(chan->cdr, chan);  /* initialize our channel's cdr */
05167             ast_cdr_start(chan->cdr);
05168          }
05169          ast_set_variables(chan, vars);
05170          if (account)
05171             ast_cdr_setaccount(chan, account);
05172          if (chan->_state == AST_STATE_UP) {
05173             res = 0;
05174             if (option_verbose > 3)
05175                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05176             tmp = ast_calloc(1, sizeof(*tmp));
05177             if (!tmp)
05178                res = -1;
05179             else {
05180                ast_copy_string(tmp->app, app, sizeof(tmp->app));
05181                if (appdata)
05182                   ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
05183                tmp->chan = chan;
05184                if (sync > 1) {
05185                   if (locked_channel)
05186                      ast_channel_unlock(chan);
05187                   ast_pbx_run_app(tmp);
05188                } else {
05189                   pthread_attr_init(&attr);
05190                   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05191                   if (locked_channel)
05192                      ast_channel_lock(chan);
05193                   if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
05194                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
05195                      free(tmp);
05196                      if (locked_channel)
05197                         ast_channel_unlock(chan);
05198                      ast_hangup(chan);
05199                      res = -1;
05200                   } else {
05201                      if (locked_channel)
05202                         *locked_channel = chan;
05203                   }
05204                   pthread_attr_destroy(&attr);
05205                }
05206             }
05207          } else {
05208             if (option_verbose > 3)
05209                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05210             if (chan->cdr) { /* update the cdr */
05211                /* here we update the status of the call, which sould be busy.
05212                 * if that fails then we set the status to failed */
05213                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05214                   ast_cdr_failed(chan->cdr);
05215             }
05216             ast_hangup(chan);
05217          }
05218       }
05219 
05220       if (res < 0) { /* the call failed for some reason */
05221          if (*reason == 0) { /* if the call failed (not busy or no answer)
05222                         * update the cdr with the failed message */
05223             cdr_res = ast_pbx_outgoing_cdr_failed();
05224             if (cdr_res != 0) {
05225                res = cdr_res;
05226                goto outgoing_app_cleanup;
05227             }
05228          }
05229       }
05230 
05231    } else {
05232       struct async_stat *as;
05233       if (!(as = ast_calloc(1, sizeof(*as)))) {
05234          res = -1;
05235          goto outgoing_app_cleanup;
05236       }
05237       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05238       if (!chan) {
05239          free(as);
05240          res = -1;
05241          goto outgoing_app_cleanup;
05242       }
05243       as->chan = chan;
05244       ast_copy_string(as->app, app, sizeof(as->app));
05245       if (appdata)
05246          ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
05247       as->timeout = timeout;
05248       ast_set_variables(chan, vars);
05249       if (account)
05250          ast_cdr_setaccount(chan, account);
05251       /* Start a new thread, and get something handling this channel. */
05252       pthread_attr_init(&attr);
05253       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05254       if (locked_channel)
05255          ast_channel_lock(chan);
05256       if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05257          ast_log(LOG_WARNING, "Failed to start async wait\n");
05258          free(as);
05259          if (locked_channel)
05260             ast_channel_unlock(chan);
05261          ast_hangup(chan);
05262          res = -1;
05263          pthread_attr_destroy(&attr);
05264          goto outgoing_app_cleanup;
05265       } else {
05266          if (locked_channel)
05267             *locked_channel = chan;
05268       }
05269       pthread_attr_destroy(&attr);
05270       res = 0;
05271    }
05272 outgoing_app_cleanup:
05273    ast_variables_destroy(vars);
05274    return res;
05275 }
05276 
05277 void __ast_context_destroy(struct ast_context *con, const char *registrar)
05278 {
05279    struct ast_context *tmp, *tmpl=NULL;
05280    struct ast_include *tmpi;
05281    struct ast_sw *sw;
05282    struct ast_exten *e, *el, *en;
05283    struct ast_ignorepat *ipi;
05284 
05285    ast_mutex_lock(&conlock);
05286    for (tmp = contexts; tmp; ) {
05287       struct ast_context *next;  /* next starting point */
05288       for (; tmp; tmpl = tmp, tmp = tmp->next) {
05289          if (option_debug)
05290             ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
05291          if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
05292               (!con || !strcasecmp(tmp->name, con->name)) )
05293             break;   /* found it */
05294       }
05295       if (!tmp)   /* not found, we are done */
05296          break;
05297       ast_mutex_lock(&tmp->lock);
05298       if (option_debug)
05299          ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
05300       next = tmp->next;
05301       if (tmpl)
05302          tmpl->next = next;
05303       else
05304          contexts = next;
05305       /* Okay, now we're safe to let it go -- in a sense, we were
05306          ready to let it go as soon as we locked it. */
05307       ast_mutex_unlock(&tmp->lock);
05308       for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
05309          struct ast_include *tmpil = tmpi;
05310          tmpi = tmpi->next;
05311          free(tmpil);
05312       }
05313       for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
05314          struct ast_ignorepat *ipl = ipi;
05315          ipi = ipi->next;
05316          free(ipl);
05317       }
05318       while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
05319          free(sw);
05320       for (e = tmp->root; e;) {
05321          for (en = e->peer; en;) {
05322             el = en;
05323             en = en->peer;
05324             destroy_exten(el);
05325          }
05326          el = e;
05327          e = e->next;
05328          destroy_exten(el);
05329       }
05330       ast_mutex_destroy(&tmp->lock);
05331       free(tmp);
05332       /* if we have a specific match, we are done, otherwise continue */
05333       tmp = con ? NULL : next;
05334    }
05335    ast_mutex_unlock(&conlock);
05336 }
05337 
05338 void ast_context_destroy(struct ast_context *con, const char *registrar)
05339 {
05340    __ast_context_destroy(con,registrar);
05341 }
05342 
05343 static void wait_for_hangup(struct ast_channel *chan, void *data)
05344 {
05345    int res;
05346    struct ast_frame *f;
05347    int waittime;
05348 
05349    if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
05350       waittime = -1;
05351    if (waittime > -1) {
05352       ast_safe_sleep(chan, waittime * 1000);
05353    } else do {
05354       res = ast_waitfor(chan, -1);
05355       if (res < 0)
05356          return;
05357       f = ast_read(chan);
05358       if (f)
05359          ast_frfree(f);
05360    } while(f);
05361 }
05362 
05363 /*!
05364  * \ingroup applications
05365  */
05366 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
05367 {
05368    ast_indicate(chan, AST_CONTROL_PROGRESS);
05369    return 0;
05370 }
05371 
05372 /*!
05373  * \ingroup applications
05374  */
05375 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
05376 {
05377    ast_indicate(chan, AST_CONTROL_RINGING);
05378    return 0;
05379 }
05380 
05381 /*!
05382  * \ingroup applications
05383  */
05384 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
05385 {
05386    ast_indicate(chan, AST_CONTROL_BUSY);
05387    /* Don't change state of an UP channel, just indicate
05388       busy in audio */
05389    if (chan->_state != AST_STATE_UP)
05390       ast_setstate(chan, AST_STATE_BUSY);
05391    if( ast_strlen_zero(data) )
05392       wait_for_hangup(chan, "10");
05393    else
05394       wait_for_hangup(chan, data);
05395    return -1;
05396 }
05397 
05398 /*!
05399  * \ingroup applications
05400  */
05401 static int pbx_builtin_congestion(struct ast_channel *chan, void *data)
05402 {
05403    ast_indicate(chan, AST_CONTROL_CONGESTION);
05404    /* Don't change state of an UP channel, just indicate
05405       congestion in audio */
05406    if (chan->_state != AST_STATE_UP)
05407       ast_setstate(chan, AST_STATE_BUSY);
05408    if( ast_strlen_zero(data) )
05409       wait_for_hangup(chan, "10");
05410    else
05411       wait_for_hangup(chan, data);
05412    return -1;
05413 }
05414 
05415 /*!
05416  * \ingroup applications
05417  */
05418 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
05419 {
05420    int delay = 0;
05421    int res;
05422 
05423    if (chan->_state == AST_STATE_UP)
05424       delay = 0;
05425    else if (!ast_strlen_zero(data))
05426       delay = atoi(data);
05427 
05428    res = ast_answer(chan);
05429    if (res)
05430       return res;
05431 
05432    if (delay)
05433       res = ast_safe_sleep(chan, delay);
05434 
05435    return res;
05436 }
05437 
05438 AST_APP_OPTIONS(resetcdr_opts, {
05439    AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
05440    AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
05441    AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
05442 });
05443 
05444 /*!
05445  * \ingroup applications
05446  */
05447 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
05448 {
05449    char *args;
05450    struct ast_flags flags = { 0 };
05451 
05452    if (!ast_strlen_zero(data)) {
05453       args = ast_strdupa(data);
05454       ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
05455    }
05456 
05457    ast_cdr_reset(chan->cdr, &flags);
05458 
05459    return 0;
05460 }
05461 
05462 /*!
05463  * \ingroup applications
05464  */
05465 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
05466 {
05467    /* Copy the AMA Flags as specified */
05468    ast_cdr_setamaflags(chan, data ? data : "");
05469    return 0;
05470 }
05471 
05472 /*!
05473  * \ingroup applications
05474  */
05475 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
05476 {
05477    if (!ast_strlen_zero(data)) {
05478       int cause;
05479       char *endptr;
05480 
05481       if ((cause = ast_str2cause(data)) > -1) {
05482          chan->hangupcause = cause;
05483          return -1;
05484       }
05485       
05486       cause = strtol((const char *) data, &endptr, 10);
05487       if (cause != 0 || (data != endptr)) {
05488          chan->hangupcause = cause;
05489          return -1;
05490       }
05491          
05492       ast_log(LOG_NOTICE, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
05493    }
05494 
05495    if (!chan->hangupcause) {
05496       chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
05497    }
05498 
05499    return -1;
05500 }
05501 
05502 /*!
05503  * \ingroup applications
05504  */
05505 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
05506 {
05507    int res=0;
05508    char *s, *ts;
05509    struct ast_timing timing;
05510 
05511    if (ast_strlen_zero(data)) {
05512       ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
05513       return -1;
05514    }
05515 
05516    ts = s = ast_strdupa(data);
05517 
05518    /* Separate the Goto path */
05519    strsep(&ts,"?");
05520 
05521    /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
05522    if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
05523       res = pbx_builtin_goto(chan, ts);
05524    
05525    return res;
05526 }
05527 
05528 /*!
05529  * \ingroup applications
05530  */
05531 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
05532 {
05533    char *s, *appname;
05534    struct ast_timing timing;
05535    struct ast_app *app;
05536    static const char *usage = "ExecIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
05537 
05538    if (ast_strlen_zero(data)) {
05539       ast_log(LOG_WARNING, "%s\n", usage);
05540       return -1;
05541    }
05542 
05543    appname = ast_strdupa(data);
05544 
05545    s = strsep(&appname,"?");  /* Separate the timerange and application name/data */
05546    if (!appname) {   /* missing application */
05547       ast_log(LOG_WARNING, "%s\n", usage);
05548       return -1;
05549    }
05550 
05551    if (!ast_build_timing(&timing, s)) {
05552       ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
05553       return -1;
05554    }
05555 
05556    if (!ast_check_timing(&timing))  /* outside the valid time window, just return */
05557       return 0;
05558 
05559    /* now split appname|appargs */
05560    if ((s = strchr(appname, '|')))
05561       *s++ = '\0';
05562 
05563    if ((app = pbx_findapp(appname))) {
05564       return pbx_exec(chan, app, S_OR(s, ""));
05565    } else {
05566       ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
05567       return -1;
05568    }
05569 }
05570 
05571 /*!
05572  * \ingroup applications
05573  */
05574 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
05575 {
05576    double s;
05577    int ms;
05578 
05579    /* Wait for "n" seconds */
05580    if (data && (s = atof(data)) > 0) {
05581       ms = s * 1000.0;
05582       return ast_safe_sleep(chan, ms);
05583    }
05584    return 0;
05585 }
05586 
05587 /*!
05588  * \ingroup applications
05589  */
05590 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
05591 {
05592    int ms, res;
05593    double sec;
05594    struct ast_flags flags = {0};
05595    char *opts[1] = { NULL };
05596    char *parse;
05597    AST_DECLARE_APP_ARGS(args,
05598       AST_APP_ARG(timeout);
05599       AST_APP_ARG(options);
05600    );
05601 
05602    if (!ast_strlen_zero(data)) {
05603       parse = ast_strdupa(data);
05604       AST_STANDARD_APP_ARGS(args, parse);
05605    } else
05606       memset(&args, 0, sizeof(args));
05607 
05608    if (args.options)
05609       ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
05610    
05611    if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
05612       ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n"); 
05613    } else if (ast_test_flag(&flags, WAITEXTEN_MOH))
05614       ast_indicate_data(chan, AST_CONTROL_HOLD, opts[0], strlen(opts[0]));
05615 
05616    /* Wait for "n" seconds */
05617    if (args.timeout && (sec = atof(args.timeout)) > 0.0)
05618       ms = 1000 * sec;
05619    else if (chan->pbx)
05620       ms = chan->pbx->rtimeout * 1000;
05621    else
05622       ms = 10000;
05623    res = ast_waitfordigit(chan, ms);
05624    if (!res) {
05625       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
05626          if (option_verbose > 2)
05627             ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
05628       } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
05629          if (option_verbose > 2)
05630             ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
05631          set_ext_pri(chan, "t", 0); /* XXX is the 0 correct ? */
05632       } else {
05633          ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
05634          res = -1;
05635       }
05636    }
05637 
05638    if (ast_test_flag(&flags, WAITEXTEN_MOH))
05639       ast_indicate(chan, AST_CONTROL_UNHOLD);
05640 
05641    return res;
05642 }
05643 
05644 /*!
05645  * \ingroup applications
05646  */
05647 static int pbx_builtin_background(struct ast_channel *chan, void *data)
05648 {
05649    int res = 0;
05650    struct ast_flags flags = {0};
05651    char *parse;
05652    AST_DECLARE_APP_ARGS(args,
05653       AST_APP_ARG(filename);
05654       AST_APP_ARG(options);
05655       AST_APP_ARG(lang);
05656       AST_APP_ARG(context);
05657    );
05658 
05659    if (ast_strlen_zero(data)) {
05660       ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
05661       return -1;
05662    }
05663 
05664    parse = ast_strdupa(data);
05665 
05666    AST_STANDARD_APP_ARGS(args, parse);
05667 
05668    if (ast_strlen_zero(args.lang))
05669       args.lang = (char *)chan->language; /* XXX this is const */
05670 
05671    if (ast_strlen_zero(args.context))
05672       args.context = chan->context;
05673 
05674    if (args.options) {
05675       if (!strcasecmp(args.options, "skip"))
05676          flags.flags = BACKGROUND_SKIP;
05677       else if (!strcasecmp(args.options, "noanswer"))
05678          flags.flags = BACKGROUND_NOANSWER;
05679       else
05680          ast_app_parse_options(background_opts, &flags, NULL, args.options);
05681    }
05682 
05683    /* Answer if need be */
05684    if (chan->_state != AST_STATE_UP) {
05685       if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
05686          return 0;
05687       } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
05688          res = ast_answer(chan);
05689       }
05690    }
05691 
05692    if (!res) {
05693       char *back = args.filename;
05694       char *front;
05695       ast_stopstream(chan);      /* Stop anything playing */
05696       /* Stream the list of files */
05697       while (!res && (front = strsep(&back, "&")) ) {
05698          if ( (res = ast_streamfile(chan, front, args.lang)) ) {
05699             ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
05700             res = 0;
05701             break;
05702          }
05703          if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
05704             res = ast_waitstream(chan, "");
05705          } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
05706             res = ast_waitstream_exten(chan, args.context);
05707          } else {
05708             res = ast_waitstream(chan, AST_DIGIT_ANY);
05709          }
05710          ast_stopstream(chan);
05711       }
05712    }
05713    if (args.context != chan->context && res) {
05714       snprintf(chan->exten, sizeof(chan->exten), "%c", res);
05715       ast_copy_string(chan->context, args.context, sizeof(chan->context));
05716       chan->priority = 0;
05717       res = 0;
05718    }
05719    return res;
05720 }
05721 
05722 /*! Goto
05723  * \ingroup applications
05724  */
05725 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
05726 {
05727    int res = ast_parseable_goto(chan, data);
05728    if (!res && (option_verbose > 2))
05729       ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
05730    return res;
05731 }
05732 
05733 
05734 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
05735 {
05736    struct ast_var_t *variables;
05737    const char *var, *val;
05738    int total = 0;
05739 
05740    if (!chan)
05741       return 0;
05742 
05743    memset(buf, 0, size);
05744 
05745    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
05746       if ((var=ast_var_name(variables)) && (val=ast_var_value(variables))
05747          /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
05748          ) {
05749          if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
05750             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
05751             break;
05752          } else
05753             total++;
05754       } else
05755          break;
05756    }
05757 
05758    return total;
05759 }
05760 
05761 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
05762 {
05763    struct ast_var_t *variables;
05764    const char *ret = NULL;
05765    int i;
05766    struct varshead *places[2] = { NULL, &globals };
05767 
05768    if (!name)
05769       return NULL;
05770    if (chan)
05771       places[0] = &chan->varshead;
05772 
05773    for (i = 0; i < 2; i++) {
05774       if (!places[i])
05775          continue;
05776       if (places[i] == &globals)
05777          ast_mutex_lock(&globalslock);
05778       AST_LIST_TRAVERSE(places[i], variables, entries) {
05779          if (!strcmp(name, ast_var_name(variables))) {
05780             ret = ast_var_value(variables);
05781             break;
05782          }
05783       }
05784       if (places[i] == &globals)
05785          ast_mutex_unlock(&globalslock);
05786       if (ret)
05787          break;
05788    }
05789 
05790    return ret;
05791 }
05792 
05793 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
05794 {
05795    struct ast_var_t *newvariable;
05796    struct varshead *headp;
05797 
05798    if (name[strlen(name)-1] == ')') {
05799       char *function = ast_strdupa(name);
05800 
05801       ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
05802       ast_func_write(chan, function, value);
05803       return;
05804    }
05805 
05806    headp = (chan) ? &chan->varshead : &globals;
05807 
05808    if (value) {
05809       if ((option_verbose > 1) && (headp == &globals))
05810          ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
05811       newvariable = ast_var_assign(name, value);
05812       if (headp == &globals)
05813          ast_mutex_lock(&globalslock);
05814       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
05815       if (headp == &globals)
05816          ast_mutex_unlock(&globalslock);
05817    }
05818 }
05819 
05820 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
05821 {
05822    struct ast_var_t *newvariable;
05823    struct varshead *headp;
05824    const char *nametail = name;
05825 
05826    /* XXX may need locking on the channel ? */
05827    if (name[strlen(name)-1] == ')') {
05828       char *function = ast_strdupa(name);
05829 
05830       ast_func_write(chan, function, value);
05831       return;
05832    }
05833 
05834    headp = (chan) ? &chan->varshead : &globals;
05835 
05836    /* For comparison purposes, we have to strip leading underscores */
05837    if (*nametail == '_') {
05838       nametail++;
05839       if (*nametail == '_')
05840          nametail++;
05841    }
05842 
05843    if (headp == &globals)
05844       ast_mutex_lock(&globalslock);
05845    AST_LIST_TRAVERSE (headp, newvariable, entries) {
05846       if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
05847          /* there is already such a variable, delete it */
05848          AST_LIST_REMOVE(headp, newvariable, entries);
05849          ast_var_delete(newvariable);
05850          break;
05851       }
05852    }
05853 
05854    if (value) {
05855       if ((option_verbose > 1) && (headp == &globals))
05856          ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
05857       newvariable = ast_var_assign(name, value);
05858       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
05859    }
05860 
05861    if (headp == &globals)
05862       ast_mutex_unlock(&globalslock);
05863 }
05864 
05865 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
05866 {
05867    char *name, *value, *mydata;
05868    int argc;
05869    char *argv[24];      /* this will only support a maximum of 24 variables being set in a single operation */
05870    int global = 0;
05871    int x;
05872 
05873    if (ast_strlen_zero(data)) {
05874       ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
05875       return 0;
05876    }
05877 
05878    mydata = ast_strdupa(data);
05879    argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
05880 
05881    /* check for a trailing flags argument */
05882    if ((argc > 1) && !strchr(argv[argc-1], '=')) {
05883       argc--;
05884       if (strchr(argv[argc], 'g'))
05885          global = 1;
05886    }
05887 
05888    for (x = 0; x < argc; x++) {
05889       name = argv[x];
05890       if ((value = strchr(name, '='))) {
05891          *value++ = '\0';
05892          pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
05893       } else
05894          ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
05895    }
05896 
05897    return(0);
05898 }
05899 
05900 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
05901 {
05902    char *name;
05903    char *value;
05904    char *channel;
05905    char tmp[VAR_BUF_SIZE]="";
05906 
05907    if (ast_strlen_zero(data)) {
05908       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
05909       return 0;
05910    }
05911 
05912    value = ast_strdupa(data);
05913    name = strsep(&value,"=");
05914    channel = strsep(&value,"|");
05915    if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
05916       struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
05917       if (chan2) {
05918          char *s = alloca(strlen(value) + 4);
05919          if (s) {
05920             sprintf(s, "${%s}", value);
05921             pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
05922          }
05923          ast_channel_unlock(chan2);
05924       }
05925       pbx_builtin_setvar_helper(chan, name, tmp);
05926    }
05927 
05928    return(0);
05929 }
05930 
05931 /*! \todo XXX overwrites data ? */
05932 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
05933 {
05934    char *name;
05935    char *stringp = data;
05936    static int dep_warning = 0;
05937 
05938    if (ast_strlen_zero(data)) {
05939       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
05940       return 0;
05941    }
05942 
05943    name = strsep(&stringp, "=");
05944 
05945    if (!dep_warning) {
05946       dep_warning = 1;
05947       ast_log(LOG_WARNING, "SetGlobalVar is deprecated.  Please use Set(GLOBAL(%s)=%s) instead.\n", name, stringp);
05948    }
05949 
05950    /*! \todo XXX watch out, leading whitespace ? */
05951    pbx_builtin_setvar_helper(NULL, name, stringp);
05952 
05953    return(0);
05954 }
05955 
05956 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
05957 {
05958    return 0;
05959 }
05960 
05961 void pbx_builtin_clear_globals(void)
05962 {
05963    struct ast_var_t *vardata;
05964 
05965    ast_mutex_lock(&globalslock);
05966    while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
05967       ast_var_delete(vardata);
05968    ast_mutex_unlock(&globalslock);
05969 }
05970 
05971 int pbx_checkcondition(const char *condition)
05972 {
05973    if (ast_strlen_zero(condition))  /* NULL or empty strings are false */
05974       return 0;
05975    else if (*condition >= '0' && *condition <= '9')   /* Numbers are evaluated for truth */
05976       return atoi(condition);
05977    else  /* Strings are true */
05978       return 1;
05979 }
05980 
05981 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
05982 {
05983    char *condition, *branch1, *branch2, *branch;
05984    int rc;
05985    char *stringp;
05986 
05987    if (ast_strlen_zero(data)) {
05988       ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
05989       return 0;
05990    }
05991 
05992    stringp = ast_strdupa(data);
05993    condition = strsep(&stringp,"?");
05994    branch1 = strsep(&stringp,":");
05995    branch2 = strsep(&stringp,"");
05996    branch = pbx_checkcondition(condition) ? branch1 : branch2;
05997 
05998    if (ast_strlen_zero(branch)) {
05999       if (option_debug)
06000          ast_log(LOG_DEBUG, "Not taking any branch\n");
06001       return 0;
06002    }
06003 
06004    rc = pbx_builtin_goto(chan, branch);
06005 
06006    return rc;
06007 }
06008 
06009 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
06010 {
06011    char tmp[256];
06012    char *number = tmp;
06013    char *options;
06014 
06015    if (ast_strlen_zero(data)) {
06016       ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
06017       return -1;
06018    }
06019    ast_copy_string(tmp, data, sizeof(tmp));
06020    strsep(&number, "|");
06021    options = strsep(&number, "|");
06022    if (options) {
06023       if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
06024          strcasecmp(options, "c") && strcasecmp(options, "n") ) {
06025          ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
06026          return -1;
06027       }
06028    }
06029    return ast_say_number(chan, atoi(tmp), "", chan->language, options);
06030 }
06031 
06032 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
06033 {
06034    int res = 0;
06035 
06036    if (data)
06037       res = ast_say_digit_str(chan, data, "", chan->language);
06038    return res;
06039 }
06040 
06041 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
06042 {
06043    int res = 0;
06044 
06045    if (data)
06046       res = ast_say_character_str(chan, data, "", chan->language);
06047    return res;
06048 }
06049 
06050 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
06051 {
06052    int res = 0;
06053 
06054    if (data)
06055       res = ast_say_phonetic_str(chan, data, "", chan->language);
06056    return res;
06057 }
06058 
06059 int load_pbx(void)
06060 {
06061    int x;
06062 
06063    /* Initialize the PBX */
06064    if (option_verbose) {
06065       ast_verbose( "Asterisk PBX Core Initializing\n");
06066       ast_verbose( "Registering builtin applications:\n");
06067    }
06068    ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
06069 
06070    /* Register builtin applications */
06071    for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
06072       if (option_verbose)
06073          ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
06074       if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
06075          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
06076          return -1;
06077       }
06078    }
06079    return 0;
06080 }
06081 
06082 /*
06083  * Lock context list functions ...
06084  */
06085 int ast_lock_contexts()
06086 {
06087    return ast_mutex_lock(&conlock);
06088 }
06089 
06090 int ast_unlock_contexts()
06091 {
06092    return ast_mutex_unlock(&conlock);
06093 }
06094 
06095 /*
06096  * Lock context ...
06097  */
06098 int ast_lock_context(struct ast_context *con)
06099 {
06100    return ast_mutex_lock(&con->lock);
06101 }
06102 
06103 int ast_unlock_context(struct ast_context *con)
06104 {
06105    return ast_mutex_unlock(&con->lock);
06106 }
06107 
06108 /*
06109  * Name functions ...
06110  */
06111 const char *ast_get_context_name(struct ast_context *con)
06112 {
06113    return con ? con->name : NULL;
06114 }
06115 
06116 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
06117 {
06118    return exten ? exten->parent : NULL;
06119 }
06120 
06121 const char *ast_get_extension_name(struct ast_exten *exten)
06122 {
06123    return exten ? exten->exten : NULL;
06124 }
06125 
06126 const char *ast_get_extension_label(struct ast_exten *exten)
06127 {
06128    return exten ? exten->label : NULL;
06129 }
06130 
06131 const char *ast_get_include_name(struct ast_include *inc)
06132 {
06133    return inc ? inc->name : NULL;
06134 }
06135 
06136 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
06137 {
06138    return ip ? ip->pattern : NULL;
06139 }
06140 
06141 int ast_get_extension_priority(struct ast_exten *exten)
06142 {
06143    return exten ? exten->priority : -1;
06144 }
06145 
06146 /*
06147  * Registrar info functions ...
06148  */
06149 const char *ast_get_context_registrar(struct ast_context *c)
06150 {
06151    return c ? c->registrar : NULL;
06152 }
06153 
06154 const char *ast_get_extension_registrar(struct ast_exten *e)
06155 {
06156    return e ? e->registrar : NULL;
06157 }
06158 
06159 const char *ast_get_include_registrar(struct ast_include *i)
06160 {
06161    return i ? i->registrar : NULL;
06162 }
06163 
06164 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
06165 {
06166    return ip ? ip->registrar : NULL;
06167 }
06168 
06169 int ast_get_extension_matchcid(struct ast_exten *e)
06170 {
06171    return e ? e->matchcid : 0;
06172 }
06173 
06174 const char *ast_get_extension_cidmatch(struct ast_exten *e)
06175 {
06176    return e ? e->cidmatch : NULL;
06177 }
06178 
06179 const char *ast_get_extension_app(struct ast_exten *e)
06180 {
06181    return e ? e->app : NULL;
06182 }
06183 
06184 void *ast_get_extension_app_data(struct ast_exten *e)
06185 {
06186    return e ? e->data : NULL;
06187 }
06188 
06189 const char *ast_get_switch_name(struct ast_sw *sw)
06190 {
06191    return sw ? sw->name : NULL;
06192 }
06193 
06194 const char *ast_get_switch_data(struct ast_sw *sw)
06195 {
06196    return sw ? sw->data : NULL;
06197 }
06198 
06199 const char *ast_get_switch_registrar(struct ast_sw *sw)
06200 {
06201    return sw ? sw->registrar : NULL;
06202 }
06203 
06204 /*
06205  * Walking functions ...
06206  */
06207 struct ast_context *ast_walk_contexts(struct ast_context *con)
06208 {
06209    return con ? con->next : contexts;
06210 }
06211 
06212 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
06213    struct ast_exten *exten)
06214 {
06215    if (!exten)
06216       return con ? con->root : NULL;
06217    else
06218       return exten->next;
06219 }
06220 
06221 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
06222    struct ast_sw *sw)
06223 {
06224    if (!sw)
06225       return con ? AST_LIST_FIRST(&con->alts) : NULL;
06226    else
06227       return AST_LIST_NEXT(sw, list);
06228 }
06229 
06230 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
06231    struct ast_exten *priority)
06232 {
06233    return priority ? priority->peer : exten;
06234 }
06235 
06236 struct ast_include *ast_walk_context_includes(struct ast_context *con,
06237    struct ast_include *inc)
06238 {
06239    if (!inc)
06240       return con ? con->includes : NULL;
06241    else
06242       return inc->next;
06243 }
06244 
06245 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
06246    struct ast_ignorepat *ip)
06247 {
06248    if (!ip)
06249       return con ? con->ignorepats : NULL;
06250    else
06251       return ip->next;
06252 }
06253 
06254 int ast_context_verify_includes(struct ast_context *con)
06255 {
06256    struct ast_include *inc = NULL;
06257    int res = 0;
06258 
06259    while ( (inc = ast_walk_context_includes(con, inc)) )
06260       if (!ast_context_find(inc->rname)) {
06261          res = -1;
06262          ast_log(LOG_WARNING, "Context '%s' tries includes nonexistent context '%s'\n",
06263                ast_get_context_name(con), inc->rname);
06264       }
06265    return res;
06266 }
06267 
06268 
06269 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
06270 {
06271    int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
06272 
06273    if (!chan)
06274       return -2;
06275 
06276    if (context == NULL)
06277       context = chan->context;
06278    if (exten == NULL)
06279       exten = chan->exten;
06280 
06281    goto_func = (async) ? ast_async_goto : ast_explicit_goto;
06282    if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
06283       return goto_func(chan, context, exten, priority);
06284    else
06285       return -3;
06286 }
06287 
06288 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
06289 {
06290    return __ast_goto_if_exists(chan, context, exten, priority, 0);
06291 }
06292 
06293 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
06294 {
06295    return __ast_goto_if_exists(chan, context, exten, priority, 1);
06296 }
06297 
06298 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
06299 {
06300    char *exten, *pri, *context;
06301    char *stringp;
06302    int ipri;
06303    int mode = 0;
06304 
06305    if (ast_strlen_zero(goto_string)) {
06306       ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
06307       return -1;
06308    }
06309    stringp = ast_strdupa(goto_string);
06310    context = strsep(&stringp, "|"); /* guaranteed non-null */
06311    exten = strsep(&stringp, "|");
06312    pri = strsep(&stringp, "|");
06313    if (!exten) {  /* Only a priority in this one */
06314       pri = context;
06315       exten = NULL;
06316       context = NULL;
06317    } else if (!pri) {   /* Only an extension and priority in this one */
06318       pri = exten;
06319       exten = context;
06320       context = NULL;
06321    }
06322    if (*pri == '+') {
06323       mode = 1;
06324       pri++;
06325    } else if (*pri == '-') {
06326       mode = -1;
06327       pri++;
06328    }
06329    if (sscanf(pri, "%d", &ipri) != 1) {
06330       if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
06331          pri, chan->cid.cid_num)) < 1) {
06332          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
06333          return -1;
06334       } else
06335          mode = 0;
06336    }
06337    /* At this point we have a priority and maybe an extension and a context */
06338 
06339    if (mode)
06340       ipri = chan->priority + (ipri * mode);
06341 
06342    ast_explicit_goto(chan, context, exten, ipri);
06343    ast_cdr_update(chan);
06344    return 0;
06345 
06346 }

Generated on Mon May 14 04:42:57 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1