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

Generated on Wed Aug 15 01:24:23 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3