Thu Feb 5 16:25:48 2009

Asterisk developer's documentation


pbx.c

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

Generated on Thu Feb 5 16:25:48 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7