Tue Nov 4 13:20:20 2008

Asterisk developer's documentation


pbx.c

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

Generated on Tue Nov 4 13:20:20 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7