Tue Apr 6 15:45:33 2010

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

Generated on Tue Apr 6 15:45:33 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7