Fri Sep 25 19:28:13 2009

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

Generated on Fri Sep 25 19:28:13 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.5