Mon Mar 31 07:38:03 2008

Asterisk developer's documentation


pbx.c

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

Generated on Mon Mar 31 07:38:03 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1