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

Generated on Mon Nov 24 15:34:19 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7