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

Generated on Sat Jul 26 06:13:19 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1