Thu Dec 17 23:51:17 2009

Asterisk developer's documentation


pbx.c

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

Generated on Thu Dec 17 23:51:17 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7