Thu May 14 14:49:05 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: 177786 $")
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_rdlock_contexts();
02056    AST_LIST_LOCK(&hints);
02057 
02058    AST_LIST_TRAVERSE(&hints, hint, list) {
02059       struct ast_state_cb *cblist;
02060       char buf[AST_MAX_EXTENSION];
02061       char *parse = buf;
02062       char *cur;
02063       int state;
02064 
02065       ast_copy_string(buf, ast_get_extension_app(hint->exten), sizeof(buf));
02066       while ( (cur = strsep(&parse, "&")) ) {
02067          if (!strcasecmp(cur, device))
02068             break;
02069       }
02070       if (!cur)
02071          continue;
02072 
02073       /* Get device state for this hint */
02074       state = ast_extension_state2(hint->exten);
02075 
02076       if ((state == -1) || (state == hint->laststate))
02077          continue;
02078 
02079       /* Device state changed since last check - notify the watchers */
02080 
02081       /* For general callbacks */
02082       for (cblist = statecbs; cblist; cblist = cblist->next)
02083          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
02084 
02085       /* For extension callbacks */
02086       for (cblist = hint->callbacks; cblist; cblist = cblist->next)
02087          cblist->callback(hint->exten->parent->name, hint->exten->exten, state, cblist->data);
02088 
02089       hint->laststate = state;   /* record we saw the change */
02090    }
02091 
02092    AST_LIST_UNLOCK(&hints);
02093    ast_unlock_contexts();
02094 }
02095 
02096 /*! \brief  ast_extension_state_add: Add watcher for extension states */
02097 int ast_extension_state_add(const char *context, const char *exten,
02098              ast_state_cb_type callback, void *data)
02099 {
02100    struct ast_hint *hint;
02101    struct ast_state_cb *cblist;
02102    struct ast_exten *e;
02103 
02104    /* If there's no context and extension:  add callback to statecbs list */
02105    if (!context && !exten) {
02106       AST_LIST_LOCK(&hints);
02107 
02108       for (cblist = statecbs; cblist; cblist = cblist->next) {
02109          if (cblist->callback == callback) {
02110             cblist->data = data;
02111             AST_LIST_UNLOCK(&hints);
02112             return 0;
02113          }
02114       }
02115 
02116       /* Now insert the callback */
02117       if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
02118          AST_LIST_UNLOCK(&hints);
02119          return -1;
02120       }
02121       cblist->id = 0;
02122       cblist->callback = callback;
02123       cblist->data = data;
02124 
02125       cblist->next = statecbs;
02126       statecbs = cblist;
02127 
02128       AST_LIST_UNLOCK(&hints);
02129       return 0;
02130    }
02131 
02132    if (!context || !exten)
02133       return -1;
02134 
02135    /* This callback type is for only one hint, so get the hint */
02136    e = ast_hint_extension(NULL, context, exten);
02137    if (!e) {
02138       return -1;
02139    }
02140 
02141    /* Find the hint in the list of hints */
02142    AST_LIST_LOCK(&hints);
02143 
02144    AST_LIST_TRAVERSE(&hints, hint, list) {
02145       if (hint->exten == e)
02146          break;
02147    }
02148 
02149    if (!hint) {
02150       /* We have no hint, sorry */
02151       AST_LIST_UNLOCK(&hints);
02152       return -1;
02153    }
02154 
02155    /* Now insert the callback in the callback list  */
02156    if (!(cblist = ast_calloc(1, sizeof(*cblist)))) {
02157       AST_LIST_UNLOCK(&hints);
02158       return -1;
02159    }
02160    cblist->id = stateid++;    /* Unique ID for this callback */
02161    cblist->callback = callback;  /* Pointer to callback routine */
02162    cblist->data = data;    /* Data for the callback */
02163 
02164    cblist->next = hint->callbacks;
02165    hint->callbacks = cblist;
02166 
02167    AST_LIST_UNLOCK(&hints);
02168    return cblist->id;
02169 }
02170 
02171 /*! \brief  ast_extension_state_del: Remove a watcher from the callback list */
02172 int ast_extension_state_del(int id, ast_state_cb_type callback)
02173 {
02174    struct ast_state_cb **p_cur = NULL; /* address of pointer to us */
02175    int ret = -1;
02176 
02177    if (!id && !callback)
02178       return -1;
02179 
02180    AST_LIST_LOCK(&hints);
02181 
02182    if (!id) {  /* id == 0 is a callback without extension */
02183       for (p_cur = &statecbs; *p_cur; p_cur = &(*p_cur)->next) {
02184          if ((*p_cur)->callback == callback)
02185             break;
02186       }
02187    } else { /* callback with extension, find the callback based on ID */
02188       struct ast_hint *hint;
02189       AST_LIST_TRAVERSE(&hints, hint, list) {
02190          for (p_cur = &hint->callbacks; *p_cur; p_cur = &(*p_cur)->next) {
02191             if ((*p_cur)->id == id)
02192                break;
02193          }
02194          if (*p_cur) /* found in the inner loop */
02195             break;
02196       }
02197    }
02198    if (p_cur && *p_cur) {
02199       struct ast_state_cb *cur = *p_cur;
02200       *p_cur = cur->next;
02201       free(cur);
02202       ret = 0;
02203    }
02204    AST_LIST_UNLOCK(&hints);
02205    return ret;
02206 }
02207 
02208 /*! \brief  ast_add_hint: Add hint to hint list, check initial extension state */
02209 static int ast_add_hint(struct ast_exten *e)
02210 {
02211    struct ast_hint *hint;
02212 
02213    if (!e)
02214       return -1;
02215 
02216    AST_LIST_LOCK(&hints);
02217 
02218    /* Search if hint exists, do nothing */
02219    AST_LIST_TRAVERSE(&hints, hint, list) {
02220       if (hint->exten == e) {
02221          AST_LIST_UNLOCK(&hints);
02222          if (option_debug > 1)
02223             ast_log(LOG_DEBUG, "HINTS: Not re-adding existing hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
02224          return -1;
02225       }
02226    }
02227 
02228    if (option_debug > 1)
02229       ast_log(LOG_DEBUG, "HINTS: Adding hint %s: %s\n", ast_get_extension_name(e), ast_get_extension_app(e));
02230 
02231    if (!(hint = ast_calloc(1, sizeof(*hint)))) {
02232       AST_LIST_UNLOCK(&hints);
02233       return -1;
02234    }
02235    /* Initialize and insert new item at the top */
02236    hint->exten = e;
02237    hint->laststate = ast_extension_state2(e);
02238    AST_LIST_INSERT_HEAD(&hints, hint, list);
02239 
02240    AST_LIST_UNLOCK(&hints);
02241    return 0;
02242 }
02243 
02244 /*! \brief  ast_change_hint: Change hint for an extension */
02245 static int ast_change_hint(struct ast_exten *oe, struct ast_exten *ne)
02246 {
02247    struct ast_hint *hint;
02248    int res = -1;
02249 
02250    AST_LIST_LOCK(&hints);
02251    AST_LIST_TRAVERSE(&hints, hint, list) {
02252       if (hint->exten == oe) {
02253             hint->exten = ne;
02254          res = 0;
02255          break;
02256       }
02257    }
02258    AST_LIST_UNLOCK(&hints);
02259 
02260    return res;
02261 }
02262 
02263 /*! \brief  ast_remove_hint: Remove hint from extension */
02264 static int ast_remove_hint(struct ast_exten *e)
02265 {
02266    /* Cleanup the Notifys if hint is removed */
02267    struct ast_hint *hint;
02268    struct ast_state_cb *cblist, *cbprev;
02269    int res = -1;
02270 
02271    if (!e)
02272       return -1;
02273 
02274    AST_LIST_LOCK(&hints);
02275    AST_LIST_TRAVERSE_SAFE_BEGIN(&hints, hint, list) {
02276       if (hint->exten == e) {
02277          cbprev = NULL;
02278          cblist = hint->callbacks;
02279          while (cblist) {
02280             /* Notify with -1 and remove all callbacks */
02281             cbprev = cblist;
02282             cblist = cblist->next;
02283             cbprev->callback(hint->exten->parent->name, hint->exten->exten, AST_EXTENSION_DEACTIVATED, cbprev->data);
02284             free(cbprev);
02285             }
02286             hint->callbacks = NULL;
02287          AST_LIST_REMOVE_CURRENT(&hints, list);
02288             free(hint);
02289             res = 0;
02290          break;
02291       }
02292    }
02293    AST_LIST_TRAVERSE_SAFE_END
02294    AST_LIST_UNLOCK(&hints);
02295 
02296    return res;
02297 }
02298 
02299 
02300 /*! \brief  ast_get_hint: Get hint for channel */
02301 int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
02302 {
02303    struct ast_exten *e = ast_hint_extension(c, context, exten);
02304 
02305    if (e) {
02306       if (hint)
02307          ast_copy_string(hint, ast_get_extension_app(e), hintsize);
02308       if (name) {
02309          const char *tmp = ast_get_extension_app_data(e);
02310          if (tmp)
02311             ast_copy_string(name, tmp, namesize);
02312       }
02313       return -1;
02314    }
02315    return 0;
02316 }
02317 
02318 int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02319 {
02320    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCH);
02321 }
02322 
02323 int ast_findlabel_extension(struct ast_channel *c, const char *context, const char *exten, const char *label, const char *callerid)
02324 {
02325    return pbx_extension_helper(c, NULL, context, exten, 0, label, callerid, E_FINDLABEL);
02326 }
02327 
02328 int ast_findlabel_extension2(struct ast_channel *c, struct ast_context *con, const char *exten, const char *label, const char *callerid)
02329 {
02330    return pbx_extension_helper(c, con, NULL, exten, 0, label, callerid, E_FINDLABEL);
02331 }
02332 
02333 int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02334 {
02335    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_CANMATCH);
02336 }
02337 
02338 int ast_matchmore_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02339 {
02340    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_MATCHMORE);
02341 }
02342 
02343 int ast_spawn_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
02344 {
02345    return pbx_extension_helper(c, NULL, context, exten, priority, NULL, callerid, E_SPAWN);
02346 }
02347 
02348 /* helper function to set extension and priority */
02349 static void set_ext_pri(struct ast_channel *c, const char *exten, int pri)
02350 {
02351    ast_channel_lock(c);
02352    ast_copy_string(c->exten, exten, sizeof(c->exten));
02353    c->priority = pri;
02354    ast_channel_unlock(c);
02355 }
02356 
02357 /*!
02358  * \brief collect digits from the channel into the buffer,
02359  * return -1 on error, 0 on timeout or done.
02360  */
02361 static int collect_digits(struct ast_channel *c, int waittime, char *buf, int buflen, int pos)
02362 {
02363    int digit;
02364 
02365    buf[pos] = '\0';  /* make sure it is properly terminated */
02366    while (ast_matchmore_extension(c, c->context, buf, 1, c->cid.cid_num)) {
02367       /* As long as we're willing to wait, and as long as it's not defined,
02368          keep reading digits until we can't possibly get a right answer anymore.  */
02369       digit = ast_waitfordigit(c, waittime * 1000);
02370       if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02371          c->_softhangup = 0;
02372       } else {
02373          if (!digit) /* No entry */
02374             break;
02375          if (digit < 0) /* Error, maybe a  hangup */
02376             return -1;
02377          if (pos < buflen - 1) { /* XXX maybe error otherwise ? */
02378             buf[pos++] = digit;
02379             buf[pos] = '\0';
02380          }
02381          waittime = c->pbx->dtimeout;
02382       }
02383    }
02384    return 0;
02385 }
02386 
02387 static int __ast_pbx_run(struct ast_channel *c)
02388 {
02389    int found = 0; /* set if we find at least one match */
02390    int res = 0;
02391    int autoloopflag;
02392    int error = 0;    /* set an error conditions */
02393    const char *emc;
02394 
02395    /* A little initial setup here */
02396    if (c->pbx) {
02397       ast_log(LOG_WARNING, "%s already has PBX structure??\n", c->name);
02398       /* XXX and now what ? */
02399       free(c->pbx);
02400    }
02401    if (!(c->pbx = ast_calloc(1, sizeof(*c->pbx))))
02402       return -1;
02403    /* Set reasonable defaults */
02404    c->pbx->rtimeout = 10;
02405    c->pbx->dtimeout = 5;
02406 
02407    autoloopflag = ast_test_flag(c, AST_FLAG_IN_AUTOLOOP);   /* save value to restore at the end */
02408    ast_set_flag(c, AST_FLAG_IN_AUTOLOOP);
02409 
02410    /* Start by trying whatever the channel is set to */
02411    if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02412       /* If not successful fall back to 's' */
02413       if (option_verbose > 1)
02414          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);
02415       /* XXX the original code used the existing priority in the call to
02416        * ast_exists_extension(), and reset it to 1 afterwards.
02417        * I believe the correct thing is to set it to 1 immediately.
02418        */
02419       set_ext_pri(c, "s", 1);
02420       if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02421          /* JK02: And finally back to default if everything else failed */
02422          if (option_verbose > 1)
02423             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);
02424          ast_copy_string(c->context, "default", sizeof(c->context));
02425       }
02426    }
02427    for (;;) {
02428       char dst_exten[256]; /* buffer to accumulate digits */
02429       int pos = 0;      /* XXX should check bounds */
02430       int digit = 0;
02431 
02432       /* loop on priorities in this context/exten */
02433       while (ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02434          found = 1;
02435          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02436             /* Something bad happened, or a hangup has been requested. */
02437             if (strchr("0123456789ABCDEF*#", res)) {
02438                if (option_debug)
02439                   ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
02440                pos = 0;
02441                dst_exten[pos++] = digit = res;
02442                dst_exten[pos] = '\0';
02443                break;
02444             }
02445             if (res == AST_PBX_KEEPALIVE) {
02446                if (option_debug)
02447                   ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
02448                if (option_verbose > 1)
02449                   ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name);
02450                error = 1;
02451                break;
02452             }
02453             if (option_debug)
02454                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02455             if (option_verbose > 1)
02456                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02457             if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02458                c->_softhangup = 0;
02459             } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
02460                /* atimeout, nothing bad */
02461             } else {
02462                if (c->cdr)
02463                   ast_cdr_update(c);
02464                error = 1;
02465                break;
02466             }
02467          }
02468          if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
02469             c->_softhangup = 0;
02470          } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT && ast_exists_extension(c,c->context,"T",1,c->cid.cid_num)) {
02471             set_ext_pri(c, "T", 0); /* 0 will become 1 with the c->priority++; at the end */
02472             /* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
02473             c->whentohangup = 0;
02474             c->_softhangup &= ~AST_SOFTHANGUP_TIMEOUT;
02475          } else if (c->_softhangup) {
02476             if (option_debug)
02477                ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
02478                   c->exten, c->priority);
02479             error = 1;
02480             break;
02481          }
02482          c->priority++;
02483       } /* end while  - from here on we can use 'break' to go out */
02484       if (error)
02485          break;
02486 
02487       /* XXX we get here on non-existing extension or a keypress or hangup ? */
02488 
02489       if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) {
02490          /* If there is no match at priority 1, it is not a valid extension anymore.
02491           * Try to continue at "i", 1 or exit if the latter does not exist.
02492           */
02493          if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
02494             if (option_verbose > 2)
02495                ast_verbose(VERBOSE_PREFIX_3 "Sent into invalid extension '%s' in context '%s' on %s\n", c->exten, c->context, c->name);
02496             pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten);
02497             set_ext_pri(c, "i", 1);
02498          } else {
02499             ast_log(LOG_WARNING, "Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler\n",
02500                c->name, c->exten, c->context);
02501             error = 1; /* we know what to do with it */
02502             break;
02503          }
02504       } else if (c->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
02505          /* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
02506          c->_softhangup = 0;
02507       } else { /* keypress received, get more digits for a full extension */
02508          int waittime = 0;
02509          if (digit)
02510             waittime = c->pbx->dtimeout;
02511          else if (!autofallthrough)
02512             waittime = c->pbx->rtimeout;
02513          if (!waittime) {
02514             const char *status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
02515             if (!status)
02516                status = "UNKNOWN";
02517             if (option_verbose > 2)
02518                ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
02519             if (!strcasecmp(status, "CONGESTION"))
02520                res = pbx_builtin_congestion(c, "10");
02521             else if (!strcasecmp(status, "CHANUNAVAIL"))
02522                res = pbx_builtin_congestion(c, "10");
02523             else if (!strcasecmp(status, "BUSY"))
02524                res = pbx_builtin_busy(c, "10");
02525             error = 1; /* XXX disable message */
02526             break;   /* exit from the 'for' loop */
02527          }
02528 
02529          if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos))
02530             break;
02531          if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */
02532             set_ext_pri(c, dst_exten, 1);
02533          else {
02534             /* No such extension */
02535             if (!ast_strlen_zero(dst_exten)) {
02536                /* An invalid extension */
02537                if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
02538                   if (option_verbose > 2)
02539                      ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name);
02540                   pbx_builtin_setvar_helper(c, "INVALID_EXTEN", dst_exten);
02541                   set_ext_pri(c, "i", 1);
02542                } else {
02543                   ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", dst_exten, c->context);
02544                   found = 1; /* XXX disable message */
02545                   break;
02546                }
02547             } else {
02548                /* A simple timeout */
02549                if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
02550                   if (option_verbose > 2)
02551                      ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
02552                   set_ext_pri(c, "t", 1);
02553                } else {
02554                   ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
02555                   found = 1; /* XXX disable message */
02556                   break;
02557                }
02558             }
02559          }
02560          if (c->cdr) {
02561             if (option_verbose > 2)
02562                ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
02563             ast_cdr_update(c);
02564          }
02565       }
02566    }
02567    if (!found && !error)
02568       ast_log(LOG_WARNING, "Don't know what to do with '%s'\n", c->name);
02569    if (res != AST_PBX_KEEPALIVE)
02570       ast_softhangup(c, c->hangupcause ? c->hangupcause : AST_CAUSE_NORMAL_CLEARING);
02571    ast_channel_lock(c);
02572    if ((emc = pbx_builtin_getvar_helper(c, "EXIT_MACRO_CONTEXT"))) {
02573       emc = ast_strdupa(emc);
02574    }
02575    ast_channel_unlock(c);
02576    if ((res != AST_PBX_KEEPALIVE) && !ast_test_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN) &&
02577          ((emc && ast_exists_extension(c, emc, "h", 1, c->cid.cid_num)) ||
02578           (ast_exists_extension(c, c->context, "h", 1, c->cid.cid_num) && (emc = c->context)))) {
02579       ast_copy_string(c->context, emc, sizeof(c->context));
02580       set_ext_pri(c, "h", 1);
02581       if (c->cdr && ast_opt_end_cdr_before_h_exten) {
02582          ast_cdr_end(c->cdr);
02583       }
02584       while(ast_exists_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) {
02585          if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num))) {
02586             /* Something bad happened, or a hangup has been requested. */
02587             if (option_debug)
02588                ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02589             if (option_verbose > 1)
02590                ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name);
02591             break;
02592          }
02593          c->priority++;
02594       }
02595    }
02596    ast_set2_flag(c, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02597    ast_clear_flag(c, AST_FLAG_BRIDGE_HANGUP_RUN); /* from one round to the next, make sure this gets cleared */
02598    pbx_destroy(c->pbx);
02599    c->pbx = NULL;
02600    if (res != AST_PBX_KEEPALIVE)
02601       ast_hangup(c);
02602    return 0;
02603 }
02604 
02605 /* Returns 0 on success, non-zero if call limit was reached */
02606 static int increase_call_count(const struct ast_channel *c)
02607 {
02608    int failed = 0;
02609    double curloadavg;
02610    ast_mutex_lock(&maxcalllock);
02611    if (option_maxcalls) {
02612       if (countcalls >= option_maxcalls) {
02613          ast_log(LOG_NOTICE, "Maximum call limit of %d calls exceeded by '%s'!\n", option_maxcalls, c->name);
02614          failed = -1;
02615       }
02616    }
02617    if (option_maxload) {
02618       getloadavg(&curloadavg, 1);
02619       if (curloadavg >= option_maxload) {
02620          ast_log(LOG_NOTICE, "Maximum loadavg limit of %f load exceeded by '%s' (currently %f)!\n", option_maxload, c->name, curloadavg);
02621          failed = -1;
02622       }
02623    }
02624    if (!failed)
02625       countcalls++;
02626    ast_mutex_unlock(&maxcalllock);
02627 
02628    return failed;
02629 }
02630 
02631 static void decrease_call_count(void)
02632 {
02633    ast_mutex_lock(&maxcalllock);
02634    if (countcalls > 0)
02635       countcalls--;
02636    ast_mutex_unlock(&maxcalllock);
02637 }
02638 
02639 static void destroy_exten(struct ast_exten *e)
02640 {
02641    if (e->priority == PRIORITY_HINT)
02642       ast_remove_hint(e);
02643 
02644    if (e->datad)
02645       e->datad(e->data);
02646    free(e);
02647 }
02648 
02649 static void *pbx_thread(void *data)
02650 {
02651    /* Oh joyeous kernel, we're a new thread, with nothing to do but
02652       answer this channel and get it going.
02653    */
02654    /* NOTE:
02655       The launcher of this function _MUST_ increment 'countcalls'
02656       before invoking the function; it will be decremented when the
02657       PBX has finished running on the channel
02658     */
02659    struct ast_channel *c = data;
02660 
02661    __ast_pbx_run(c);
02662    decrease_call_count();
02663 
02664    pthread_exit(NULL);
02665 
02666    return NULL;
02667 }
02668 
02669 enum ast_pbx_result ast_pbx_start(struct ast_channel *c)
02670 {
02671    pthread_t t;
02672    pthread_attr_t attr;
02673 
02674    if (!c) {
02675       ast_log(LOG_WARNING, "Asked to start thread on NULL channel?\n");
02676       return AST_PBX_FAILED;
02677    }
02678 
02679    if (increase_call_count(c))
02680       return AST_PBX_CALL_LIMIT;
02681 
02682    /* Start a new thread, and get something handling this channel. */
02683    pthread_attr_init(&attr);
02684    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
02685    if (ast_pthread_create(&t, &attr, pbx_thread, c)) {
02686       ast_log(LOG_WARNING, "Failed to create new channel thread\n");
02687       pthread_attr_destroy(&attr);
02688       decrease_call_count();
02689       return AST_PBX_FAILED;
02690    }
02691    pthread_attr_destroy(&attr);
02692 
02693    return AST_PBX_SUCCESS;
02694 }
02695 
02696 enum ast_pbx_result ast_pbx_run(struct ast_channel *c)
02697 {
02698    enum ast_pbx_result res = AST_PBX_SUCCESS;
02699 
02700    if (increase_call_count(c))
02701       return AST_PBX_CALL_LIMIT;
02702 
02703    res = __ast_pbx_run(c);
02704    decrease_call_count();
02705 
02706    return res;
02707 }
02708 
02709 int ast_active_calls(void)
02710 {
02711    return countcalls;
02712 }
02713 
02714 int pbx_set_autofallthrough(int newval)
02715 {
02716    int oldval = autofallthrough;
02717    autofallthrough = newval;
02718    return oldval;
02719 }
02720 
02721 /* lookup for a context with a given name,
02722  * return with conlock held if found, NULL if not found
02723  */
02724 static struct ast_context *find_context_locked(const char *context)
02725 {
02726    struct ast_context *c = NULL;
02727 
02728    ast_rdlock_contexts();
02729    while ( (c = ast_walk_contexts(c)) ) {
02730       if (!strcmp(ast_get_context_name(c), context))
02731          return c;
02732    }
02733    ast_unlock_contexts();
02734 
02735    return NULL;
02736 }
02737 
02738 /*
02739  * This function locks contexts list by &conlist, search for the right context
02740  * structure, leave context list locked and call ast_context_remove_include2
02741  * which removes include, unlock contexts list and return ...
02742  */
02743 int ast_context_remove_include(const char *context, const char *include, const char *registrar)
02744 {
02745    int ret = -1;
02746    struct ast_context *c = find_context_locked(context);
02747 
02748    if (c) {
02749       /* found, remove include from this context ... */
02750       ret = ast_context_remove_include2(c, include, registrar);
02751       ast_unlock_contexts();
02752    }
02753    return ret;
02754 }
02755 
02756 /*
02757  * When we call this function, &conlock lock must be locked, because when
02758  * we giving *con argument, some process can remove/change this context
02759  * and after that there can be segfault.
02760  *
02761  * This function locks given context, removes include, unlock context and
02762  * return.
02763  */
02764 int ast_context_remove_include2(struct ast_context *con, const char *include, const char *registrar)
02765 {
02766    struct ast_include *i, *pi = NULL;
02767    int ret = -1;
02768 
02769    ast_mutex_lock(&con->lock);
02770 
02771    /* find our include */
02772    for (i = con->includes; i; pi = i, i = i->next) {
02773       if (!strcmp(i->name, include) &&
02774             (!registrar || !strcmp(i->registrar, registrar))) {
02775          /* remove from list */
02776          if (pi)
02777             pi->next = i->next;
02778          else
02779             con->includes = i->next;
02780          /* free include and return */
02781          free(i);
02782          ret = 0;
02783          break;
02784       }
02785    }
02786 
02787    ast_mutex_unlock(&con->lock);
02788    return ret;
02789 }
02790 
02791 /*!
02792  * \note This function locks contexts list by &conlist, search for the rigt context
02793  * structure, leave context list locked and call ast_context_remove_switch2
02794  * which removes switch, unlock contexts list and return ...
02795  */
02796 int ast_context_remove_switch(const char *context, const char *sw, const char *data, const char *registrar)
02797 {
02798    int ret = -1; /* default error return */
02799    struct ast_context *c = find_context_locked(context);
02800 
02801    if (c) {
02802       /* remove switch from this context ... */
02803       ret = ast_context_remove_switch2(c, sw, data, registrar);
02804       ast_unlock_contexts();
02805    }
02806    return ret;
02807 }
02808 
02809 /*!
02810  * \brief This function locks given context, removes switch, unlock context and
02811  * return.
02812  * \note When we call this function, &conlock lock must be locked, because when
02813  * we giving *con argument, some process can remove/change this context
02814  * and after that there can be segfault.
02815  *
02816  */
02817 int ast_context_remove_switch2(struct ast_context *con, const char *sw, const char *data, const char *registrar)
02818 {
02819    struct ast_sw *i;
02820    int ret = -1;
02821 
02822    ast_mutex_lock(&con->lock);
02823 
02824    /* walk switches */
02825    AST_LIST_TRAVERSE_SAFE_BEGIN(&con->alts, i, list) {
02826       if (!strcmp(i->name, sw) && !strcmp(i->data, data) &&
02827          (!registrar || !strcmp(i->registrar, registrar))) {
02828          /* found, remove from list */
02829          AST_LIST_REMOVE_CURRENT(&con->alts, list);
02830          free(i); /* free switch and return */
02831          ret = 0;
02832          break;
02833       }
02834    }
02835    AST_LIST_TRAVERSE_SAFE_END
02836 
02837    ast_mutex_unlock(&con->lock);
02838 
02839    return ret;
02840 }
02841 
02842 /*
02843  * \note This functions lock contexts list, search for the right context,
02844  * call ast_context_remove_extension2, unlock contexts list and return.
02845  * In this function we are using
02846  */
02847 int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
02848 {
02849    return ast_context_remove_extension_callerid(context, extension, priority, NULL, 0, registrar);
02850 }
02851 
02852 int ast_context_remove_extension_callerid(const char *context, const char *extension, int priority, const char *callerid, int matchcid, const char *registrar)
02853 {
02854    int ret = -1; /* default error return */
02855    struct ast_context *c = find_context_locked(context);
02856 
02857    if (c) { /* ... remove extension ... */
02858       ret = ast_context_remove_extension_callerid2(c, extension, priority, callerid, matchcid, registrar);
02859       ast_unlock_contexts();
02860    }
02861    return ret;
02862 }
02863 
02864 /*!
02865  * \brief This functionc locks given context, search for the right extension and
02866  * fires out all peer in this extensions with given priority. If priority
02867  * is set to 0, all peers are removed. After that, unlock context and
02868  * return.
02869  * \note When do you want to call this function, make sure that &conlock is locked,
02870  * because some process can handle with your *con context before you lock
02871  * it.
02872  *
02873  */
02874 int ast_context_remove_extension2(struct ast_context *con, const char *extension, int priority, const char *registrar)
02875 {
02876    return ast_context_remove_extension_callerid2(con, extension, priority, NULL, 0, registrar);
02877 }
02878 
02879 int ast_context_remove_extension_callerid2(struct ast_context *con, const char *extension, int priority, const char *callerid, int matchcid, const char *registrar)
02880 {
02881    struct ast_exten *exten, *prev_exten = NULL;
02882    struct ast_exten *peer;
02883    struct ast_exten *previous_peer = NULL;
02884    struct ast_exten *next_peer = NULL;
02885    int found = 0;
02886 
02887    ast_mutex_lock(&con->lock);
02888 
02889    /* scan the extension list to find first matching extension-registrar */
02890    for (exten = con->root; exten; prev_exten = exten, exten = exten->next) {
02891       if (!strcmp(exten->exten, extension) &&
02892          (!registrar || !strcmp(exten->registrar, registrar)))
02893          break;
02894    }
02895    if (!exten) {
02896       /* we can't find right extension */
02897       ast_mutex_unlock(&con->lock);
02898       return -1;
02899    }
02900 
02901    /* scan the priority list to remove extension with exten->priority == priority */
02902    for (peer = exten, next_peer = exten->peer ? exten->peer : exten->next;
02903          peer && !strcmp(peer->exten, extension);
02904          peer = next_peer, next_peer = next_peer ? (next_peer->peer ? next_peer->peer : next_peer->next) : NULL) {
02905       if ((priority == 0 || peer->priority == priority) &&
02906             (!callerid || !matchcid || (matchcid && !strcmp(peer->cidmatch, callerid))) &&
02907             (!registrar || !strcmp(peer->registrar, registrar) )) {
02908          found = 1;
02909 
02910          /* we are first priority extension? */
02911          if (!previous_peer) {
02912             /*
02913              * We are first in the priority chain, so must update the extension chain.
02914              * The next node is either the next priority or the next extension
02915              */
02916             struct ast_exten *next_node = peer->peer ? peer->peer : peer->next;
02917 
02918             if (!prev_exten) {   /* change the root... */
02919                con->root = next_node;
02920             } else {
02921                prev_exten->next = next_node; /* unlink */
02922             }
02923             if (peer->peer)   { /* update the new head of the pri list */
02924                peer->peer->next = peer->next;
02925             }
02926          } else { /* easy, we are not first priority in extension */
02927             previous_peer->peer = peer->peer;
02928          }
02929 
02930          /* now, free whole priority extension */
02931          destroy_exten(peer);
02932       } else {
02933          previous_peer = peer;
02934       }
02935    }
02936    ast_mutex_unlock(&con->lock);
02937    return found ? 0 : -1;
02938 }
02939 
02940 
02941 /*!
02942  * \note This function locks contexts list by &conlist, searches for the right context
02943  * structure, and locks the macrolock mutex in that context.
02944  * macrolock is used to limit a macro to be executed by one call at a time.
02945  */
02946 int ast_context_lockmacro(const char *context)
02947 {
02948    struct ast_context *c = NULL;
02949    int ret = -1;
02950 
02951    ast_rdlock_contexts();
02952 
02953    while ((c = ast_walk_contexts(c))) {
02954       if (!strcmp(ast_get_context_name(c), context)) {
02955          ret = 0;
02956          break;
02957       }
02958    }
02959 
02960    ast_unlock_contexts();
02961 
02962    /* if we found context, lock macrolock */
02963    if (ret == 0) 
02964       ret = ast_mutex_lock(&c->macrolock);
02965 
02966    return ret;
02967 }
02968 
02969 /*!
02970  * \note This function locks contexts list by &conlist, searches for the right context
02971  * structure, and unlocks the macrolock mutex in that context.
02972  * macrolock is used to limit a macro to be executed by one call at a time.
02973  */
02974 int ast_context_unlockmacro(const char *context)
02975 {
02976    struct ast_context *c = NULL;
02977    int ret = -1;
02978 
02979    ast_rdlock_contexts();
02980 
02981    while ((c = ast_walk_contexts(c))) {
02982       if (!strcmp(ast_get_context_name(c), context)) {
02983          ret = 0;
02984          break;
02985       }
02986    }
02987 
02988    ast_unlock_contexts();
02989 
02990    /* if we found context, unlock macrolock */
02991    if (ret == 0) 
02992       ret = ast_mutex_unlock(&c->macrolock);
02993 
02994    return ret;
02995 }
02996 
02997 /*! \brief Dynamically register a new dial plan application */
02998 int ast_register_application(const char *app, int (*execute)(struct ast_channel *, void *), const char *synopsis, const char *description)
02999 {
03000    struct ast_app *tmp, *cur = NULL;
03001    char tmps[80];
03002    int length;
03003 
03004    AST_LIST_LOCK(&apps);
03005    AST_LIST_TRAVERSE(&apps, tmp, list) {
03006       if (!strcasecmp(app, tmp->name)) {
03007          ast_log(LOG_WARNING, "Already have an application '%s'\n", app);
03008          AST_LIST_UNLOCK(&apps);
03009          return -1;
03010       }
03011    }
03012 
03013    length = sizeof(*tmp) + strlen(app) + 1;
03014 
03015    if (!(tmp = ast_calloc(1, length))) {
03016       AST_LIST_UNLOCK(&apps);
03017       return -1;
03018    }
03019 
03020    strcpy(tmp->name, app);
03021    tmp->execute = execute;
03022    tmp->synopsis = synopsis;
03023    tmp->description = description;
03024 
03025    /* Store in alphabetical order */
03026    AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, cur, list) {
03027       if (strcasecmp(tmp->name, cur->name) < 0) {
03028          AST_LIST_INSERT_BEFORE_CURRENT(&apps, tmp, list);
03029          break;
03030       }
03031    }
03032    AST_LIST_TRAVERSE_SAFE_END
03033    if (!cur)
03034       AST_LIST_INSERT_TAIL(&apps, tmp, list);
03035 
03036    if (option_verbose > 1)
03037       ast_verbose( VERBOSE_PREFIX_2 "Registered application '%s'\n", term_color(tmps, tmp->name, COLOR_BRCYAN, 0, sizeof(tmps)));
03038 
03039    AST_LIST_UNLOCK(&apps);
03040 
03041    return 0;
03042 }
03043 
03044 /*
03045  * Append to the list. We don't have a tail pointer because we need
03046  * to scan the list anyways to check for duplicates during insertion.
03047  */
03048 int ast_register_switch(struct ast_switch *sw)
03049 {
03050    struct ast_switch *tmp;
03051 
03052    AST_LIST_LOCK(&switches);
03053    AST_LIST_TRAVERSE(&switches, tmp, list) {
03054       if (!strcasecmp(tmp->name, sw->name)) {
03055          AST_LIST_UNLOCK(&switches);
03056          ast_log(LOG_WARNING, "Switch '%s' already found\n", sw->name);
03057          return -1;
03058       }
03059    }
03060    AST_LIST_INSERT_TAIL(&switches, sw, list);
03061    AST_LIST_UNLOCK(&switches);
03062 
03063    return 0;
03064 }
03065 
03066 void ast_unregister_switch(struct ast_switch *sw)
03067 {
03068    AST_LIST_LOCK(&switches);
03069    AST_LIST_REMOVE(&switches, sw, list);
03070    AST_LIST_UNLOCK(&switches);
03071 }
03072 
03073 /*
03074  * Help for CLI commands ...
03075  */
03076 static char show_applications_help[] =
03077 "Usage: core show applications [{like|describing} <text>]\n"
03078 "       List applications which are currently available.\n"
03079 "       If 'like', <text> will be a substring of the app name\n"
03080 "       If 'describing', <text> will be a substring of the description\n";
03081 
03082 static char show_functions_help[] =
03083 "Usage: core show functions [like <text>]\n"
03084 "       List builtin functions, optionally only those matching a given string\n";
03085 
03086 static char show_switches_help[] =
03087 "Usage: core show switches\n"
03088 "       List registered switches\n";
03089 
03090 static char show_hints_help[] =
03091 "Usage: core show hints\n"
03092 "       List registered hints\n";
03093 
03094 static char show_globals_help[] =
03095 "Usage: core show globals\n"
03096 "       List current global dialplan variables and their values\n";
03097 
03098 static char show_application_help[] =
03099 "Usage: core show application <application> [<application> [<application> [...]]]\n"
03100 "       Describes a particular application.\n";
03101 
03102 static char show_function_help[] =
03103 "Usage: core show function <function>\n"
03104 "       Describe a particular dialplan function.\n";
03105 
03106 static char show_dialplan_help[] =
03107 "Usage: dialplan show [exten@][context]\n"
03108 "       Show dialplan\n";
03109 
03110 static char set_global_help[] =
03111 "Usage: core set global <name> <value>\n"
03112 "       Set global dialplan variable <name> to <value>\n";
03113 
03114 
03115 /*
03116  * \brief 'show application' CLI command implementation functions ...
03117  */
03118 
03119 /*
03120  * There is a possibility to show informations about more than one
03121  * application at one time. You can type 'show application Dial Echo' and
03122  * you will see informations about these two applications ...
03123  */
03124 static char *complete_show_application(const char *line, const char *word, int pos, int state)
03125 {
03126    struct ast_app *a;
03127    char *ret = NULL;
03128    int which = 0;
03129    int wordlen = strlen(word);
03130 
03131    /* return the n-th [partial] matching entry */
03132    AST_LIST_LOCK(&apps);
03133    AST_LIST_TRAVERSE(&apps, a, list) {
03134       if (!strncasecmp(word, a->name, wordlen) && ++which > state) {
03135          ret = strdup(a->name);
03136          break;
03137       }
03138    }
03139    AST_LIST_UNLOCK(&apps);
03140 
03141    return ret;
03142 }
03143 
03144 static int handle_show_application_deprecated(int fd, int argc, char *argv[])
03145 {
03146    struct ast_app *a;
03147    int app, no_registered_app = 1;
03148 
03149    if (argc < 3)
03150       return RESULT_SHOWUSAGE;
03151 
03152    /* ... go through all applications ... */
03153    AST_LIST_LOCK(&apps);
03154    AST_LIST_TRAVERSE(&apps, a, list) {
03155       /* ... compare this application name with all arguments given
03156        * to 'show application' command ... */
03157       for (app = 2; app < argc; app++) {
03158          if (!strcasecmp(a->name, argv[app])) {
03159             /* Maximum number of characters added by terminal coloring is 22 */
03160             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
03161             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
03162             int synopsis_size, description_size;
03163 
03164             no_registered_app = 0;
03165 
03166             if (a->synopsis)
03167                synopsis_size = strlen(a->synopsis) + 23;
03168             else
03169                synopsis_size = strlen("Not available") + 23;
03170             synopsis = alloca(synopsis_size);
03171 
03172             if (a->description)
03173                description_size = strlen(a->description) + 23;
03174             else
03175                description_size = strlen("Not available") + 23;
03176             description = alloca(description_size);
03177 
03178             if (synopsis && description) {
03179                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
03180                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
03181                term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03182                term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03183                term_color(synopsis,
03184                            a->synopsis ? a->synopsis : "Not available",
03185                            COLOR_CYAN, 0, synopsis_size);
03186                term_color(description,
03187                            a->description ? a->description : "Not available",
03188                            COLOR_CYAN, 0, description_size);
03189 
03190                ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
03191             } else {
03192                /* ... one of our applications, show info ...*/
03193                ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
03194                   "[Synopsis]\n  %s\n\n"
03195                   "[Description]\n%s\n",
03196                   a->name,
03197                   a->synopsis ? a->synopsis : "Not available",
03198                   a->description ? a->description : "Not available");
03199             }
03200          }
03201       }
03202    }
03203    AST_LIST_UNLOCK(&apps);
03204 
03205    /* we found at least one app? no? */
03206    if (no_registered_app) {
03207       ast_cli(fd, "Your application(s) is (are) not registered\n");
03208       return RESULT_FAILURE;
03209    }
03210 
03211    return RESULT_SUCCESS;
03212 }
03213 
03214 static int handle_show_application(int fd, int argc, char *argv[])
03215 {
03216    struct ast_app *a;
03217    int app, no_registered_app = 1;
03218 
03219    if (argc < 4)
03220       return RESULT_SHOWUSAGE;
03221 
03222    /* ... go through all applications ... */
03223    AST_LIST_LOCK(&apps);
03224    AST_LIST_TRAVERSE(&apps, a, list) {
03225       /* ... compare this application name with all arguments given
03226        * to 'show application' command ... */
03227       for (app = 3; app < argc; app++) {
03228          if (!strcasecmp(a->name, argv[app])) {
03229             /* Maximum number of characters added by terminal coloring is 22 */
03230             char infotitle[64 + AST_MAX_APP + 22], syntitle[40], destitle[40];
03231             char info[64 + AST_MAX_APP], *synopsis = NULL, *description = NULL;
03232             int synopsis_size, description_size;
03233 
03234             no_registered_app = 0;
03235 
03236             if (a->synopsis)
03237                synopsis_size = strlen(a->synopsis) + 23;
03238             else
03239                synopsis_size = strlen("Not available") + 23;
03240             synopsis = alloca(synopsis_size);
03241 
03242             if (a->description)
03243                description_size = strlen(a->description) + 23;
03244             else
03245                description_size = strlen("Not available") + 23;
03246             description = alloca(description_size);
03247 
03248             if (synopsis && description) {
03249                snprintf(info, 64 + AST_MAX_APP, "\n  -= Info about application '%s' =- \n\n", a->name);
03250                term_color(infotitle, info, COLOR_MAGENTA, 0, 64 + AST_MAX_APP + 22);
03251                term_color(syntitle, "[Synopsis]\n", COLOR_MAGENTA, 0, 40);
03252                term_color(destitle, "[Description]\n", COLOR_MAGENTA, 0, 40);
03253                term_color(synopsis,
03254                            a->synopsis ? a->synopsis : "Not available",
03255                            COLOR_CYAN, 0, synopsis_size);
03256                term_color(description,
03257                            a->description ? a->description : "Not available",
03258                            COLOR_CYAN, 0, description_size);
03259 
03260                ast_cli(fd,"%s%s%s\n\n%s%s\n", infotitle, syntitle, synopsis, destitle, description);
03261             } else {
03262                /* ... one of our applications, show info ...*/
03263                ast_cli(fd,"\n  -= Info about application '%s' =- \n\n"
03264                   "[Synopsis]\n  %s\n\n"
03265                   "[Description]\n%s\n",
03266                   a->name,
03267                   a->synopsis ? a->synopsis : "Not available",
03268                   a->description ? a->description : "Not available");
03269             }
03270          }
03271       }
03272    }
03273    AST_LIST_UNLOCK(&apps);
03274 
03275    /* we found at least one app? no? */
03276    if (no_registered_app) {
03277       ast_cli(fd, "Your application(s) is (are) not registered\n");
03278       return RESULT_FAILURE;
03279    }
03280 
03281    return RESULT_SUCCESS;
03282 }
03283 
03284 /*! \brief  handle_show_hints: CLI support for listing registered dial plan hints */
03285 static int handle_show_hints(int fd, int argc, char *argv[])
03286 {
03287    struct ast_hint *hint;
03288    int num = 0;
03289    int watchers;
03290    struct ast_state_cb *watcher;
03291 
03292    if (AST_LIST_EMPTY(&hints)) {
03293       ast_cli(fd, "There are no registered dialplan hints\n");
03294       return RESULT_SUCCESS;
03295    }
03296    /* ... we have hints ... */
03297    ast_cli(fd, "\n    -= Registered Asterisk Dial Plan Hints =-\n");
03298    AST_LIST_LOCK(&hints);
03299    AST_LIST_TRAVERSE(&hints, hint, list) {
03300       watchers = 0;
03301       for (watcher = hint->callbacks; watcher; watcher = watcher->next)
03302          watchers++;
03303       ast_cli(fd, "   %20s@%-20.20s: %-20.20s  State:%-15.15s Watchers %2d\n",
03304          ast_get_extension_name(hint->exten),
03305          ast_get_context_name(ast_get_extension_context(hint->exten)),
03306          ast_get_extension_app(hint->exten),
03307          ast_extension_state2str(hint->laststate), watchers);
03308       num++;
03309    }
03310    ast_cli(fd, "----------------\n");
03311    ast_cli(fd, "- %d hints registered\n", num);
03312    AST_LIST_UNLOCK(&hints);
03313    return RESULT_SUCCESS;
03314 }
03315 
03316 /*! \brief  handle_show_switches: CLI support for listing registered dial plan switches */
03317 static int handle_show_switches(int fd, int argc, char *argv[])
03318 {
03319    struct ast_switch *sw;
03320 
03321    AST_LIST_LOCK(&switches);
03322 
03323    if (AST_LIST_EMPTY(&switches)) {
03324       AST_LIST_UNLOCK(&switches);
03325       ast_cli(fd, "There are no registered alternative switches\n");
03326       return RESULT_SUCCESS;
03327    }
03328 
03329    ast_cli(fd, "\n    -= Registered Asterisk Alternative Switches =-\n");
03330    AST_LIST_TRAVERSE(&switches, sw, list)
03331       ast_cli(fd, "%s: %s\n", sw->name, sw->description);
03332 
03333    AST_LIST_UNLOCK(&switches);
03334 
03335    return RESULT_SUCCESS;
03336 }
03337 
03338 /*
03339  * 'show applications' CLI command implementation functions ...
03340  */
03341 static int handle_show_applications_deprecated(int fd, int argc, char *argv[])
03342 {
03343    struct ast_app *a;
03344    int like = 0, describing = 0;
03345    int total_match = 0;    /* Number of matches in like clause */
03346    int total_apps = 0;  /* Number of apps registered */
03347 
03348    AST_LIST_LOCK(&apps);
03349 
03350    if (AST_LIST_EMPTY(&apps)) {
03351       ast_cli(fd, "There are no registered applications\n");
03352       AST_LIST_UNLOCK(&apps);
03353       return -1;
03354    }
03355 
03356    /* show applications like <keyword> */
03357    if ((argc == 4) && (!strcmp(argv[2], "like"))) {
03358       like = 1;
03359    } else if ((argc > 3) && (!strcmp(argv[2], "describing"))) {
03360       describing = 1;
03361    }
03362 
03363    /* show applications describing <keyword1> [<keyword2>] [...] */
03364    if ((!like) && (!describing)) {
03365       ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
03366    } else {
03367       ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
03368    }
03369 
03370    AST_LIST_TRAVERSE(&apps, a, list) {
03371       int printapp = 0;
03372       total_apps++;
03373       if (like) {
03374          if (strcasestr(a->name, argv[3])) {
03375             printapp = 1;
03376             total_match++;
03377          }
03378       } else if (describing) {
03379          if (a->description) {
03380             /* Match all words on command line */
03381             int i;
03382             printapp = 1;
03383             for (i = 3; i < argc; i++) {
03384                if (!strcasestr(a->description, argv[i])) {
03385                   printapp = 0;
03386                } else {
03387                   total_match++;
03388                }
03389             }
03390          }
03391       } else {
03392          printapp = 1;
03393       }
03394 
03395       if (printapp) {
03396          ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
03397       }
03398    }
03399    if ((!like) && (!describing)) {
03400       ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
03401    } else {
03402       ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
03403    }
03404 
03405    AST_LIST_UNLOCK(&apps);
03406 
03407    return RESULT_SUCCESS;
03408 }
03409 static int handle_show_applications(int fd, int argc, char *argv[])
03410 {
03411    struct ast_app *a;
03412    int like = 0, describing = 0;
03413    int total_match = 0;    /* Number of matches in like clause */
03414    int total_apps = 0;  /* Number of apps registered */
03415 
03416    AST_LIST_LOCK(&apps);
03417 
03418    if (AST_LIST_EMPTY(&apps)) {
03419       ast_cli(fd, "There are no registered applications\n");
03420       AST_LIST_UNLOCK(&apps);
03421       return -1;
03422    }
03423 
03424    /* core list applications like <keyword> */
03425    if ((argc == 5) && (!strcmp(argv[3], "like"))) {
03426       like = 1;
03427    } else if ((argc > 4) && (!strcmp(argv[3], "describing"))) {
03428       describing = 1;
03429    }
03430 
03431    /* core list applications describing <keyword1> [<keyword2>] [...] */
03432    if ((!like) && (!describing)) {
03433       ast_cli(fd, "    -= Registered Asterisk Applications =-\n");
03434    } else {
03435       ast_cli(fd, "    -= Matching Asterisk Applications =-\n");
03436    }
03437 
03438    AST_LIST_TRAVERSE(&apps, a, list) {
03439       int printapp = 0;
03440       total_apps++;
03441       if (like) {
03442          if (strcasestr(a->name, argv[4])) {
03443             printapp = 1;
03444             total_match++;
03445          }
03446       } else if (describing) {
03447          if (a->description) {
03448             /* Match all words on command line */
03449             int i;
03450             printapp = 1;
03451             for (i = 4; i < argc; i++) {
03452                if (!strcasestr(a->description, argv[i])) {
03453                   printapp = 0;
03454                } else {
03455                   total_match++;
03456                }
03457             }
03458          }
03459       } else {
03460          printapp = 1;
03461       }
03462 
03463       if (printapp) {
03464          ast_cli(fd,"  %20s: %s\n", a->name, a->synopsis ? a->synopsis : "<Synopsis not available>");
03465       }
03466    }
03467    if ((!like) && (!describing)) {
03468       ast_cli(fd, "    -= %d Applications Registered =-\n",total_apps);
03469    } else {
03470       ast_cli(fd, "    -= %d Applications Matching =-\n",total_match);
03471    }
03472 
03473    AST_LIST_UNLOCK(&apps);
03474 
03475    return RESULT_SUCCESS;
03476 }
03477 
03478 static char *complete_show_applications_deprecated(const char *line, const char *word, int pos, int state)
03479 {
03480    static char* choices[] = { "like", "describing", NULL };
03481 
03482    return (pos != 2) ? NULL : ast_cli_complete(word, choices, state);
03483 }
03484 
03485 static char *complete_show_applications(const char *line, const char *word, int pos, int state)
03486 {
03487    static char* choices[] = { "like", "describing", NULL };
03488 
03489    return (pos != 3) ? NULL : ast_cli_complete(word, choices, state);
03490 }
03491 
03492 /*
03493  * 'show dialplan' CLI command implementation functions ...
03494  */
03495 static char *complete_show_dialplan_context(const char *line, const char *word, int pos,
03496    int state)
03497 {
03498    struct ast_context *c = NULL;
03499    char *ret = NULL;
03500    int which = 0;
03501    int wordlen;
03502 
03503    /* we are do completion of [exten@]context on second position only */
03504    if (pos != 2)
03505       return NULL;
03506 
03507    ast_rdlock_contexts();
03508 
03509    wordlen = strlen(word);
03510 
03511    /* walk through all contexts and return the n-th match */
03512    while ( (c = ast_walk_contexts(c)) ) {
03513       if (!strncasecmp(word, ast_get_context_name(c), wordlen) && ++which > state) {
03514          ret = ast_strdup(ast_get_context_name(c));
03515          break;
03516       }
03517    }
03518 
03519    ast_unlock_contexts();
03520 
03521    return ret;
03522 }
03523 
03524 struct dialplan_counters {
03525    int total_context;
03526    int total_exten;
03527    int total_prio;
03528    int context_existence;
03529    int extension_existence;
03530 };
03531 
03532 /*! \brief helper function to print an extension */
03533 static void print_ext(struct ast_exten *e, char * buf, int buflen)
03534 {
03535    int prio = ast_get_extension_priority(e);
03536    if (prio == PRIORITY_HINT) {
03537       snprintf(buf, buflen, "hint: %s",
03538          ast_get_extension_app(e));
03539    } else {
03540       snprintf(buf, buflen, "%d. %s(%s)",
03541          prio, ast_get_extension_app(e),
03542          (!ast_strlen_zero(ast_get_extension_app_data(e)) ? (char *)ast_get_extension_app_data(e) : ""));
03543    }
03544 }
03545 
03546 /* XXX not verified */
03547 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[])
03548 {
03549    struct ast_context *c = NULL;
03550    int res = 0, old_total_exten = dpc->total_exten;
03551 
03552    ast_rdlock_contexts();
03553 
03554    /* walk all contexts ... */
03555    while ( (c = ast_walk_contexts(c)) ) {
03556       struct ast_exten *e;
03557       struct ast_include *i;
03558       struct ast_ignorepat *ip;
03559       char buf[256], buf2[256];
03560       int context_info_printed = 0;
03561 
03562       if (context && strcmp(ast_get_context_name(c), context))
03563          continue;   /* skip this one, name doesn't match */
03564 
03565       dpc->context_existence = 1;
03566 
03567       ast_lock_context(c);
03568 
03569       /* are we looking for exten too? if yes, we print context
03570        * only if we find our extension.
03571        * Otherwise print context even if empty ?
03572        * XXX i am not sure how the rinclude is handled.
03573        * I think it ought to go inside.
03574        */
03575       if (!exten) {
03576          dpc->total_context++;
03577          ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03578             ast_get_context_name(c), ast_get_context_registrar(c));
03579          context_info_printed = 1;
03580       }
03581 
03582       /* walk extensions ... */
03583       e = NULL;
03584       while ( (e = ast_walk_context_extensions(c, e)) ) {
03585          struct ast_exten *p;
03586 
03587          if (exten && !ast_extension_match(ast_get_extension_name(e), exten))
03588             continue;   /* skip, extension match failed */
03589 
03590          dpc->extension_existence = 1;
03591 
03592          /* may we print context info? */
03593          if (!context_info_printed) {
03594             dpc->total_context++;
03595             if (rinclude) { /* TODO Print more info about rinclude */
03596                ast_cli(fd, "[ Included context '%s' created by '%s' ]\n",
03597                   ast_get_context_name(c), ast_get_context_registrar(c));
03598             } else {
03599                ast_cli(fd, "[ Context '%s' created by '%s' ]\n",
03600                   ast_get_context_name(c), ast_get_context_registrar(c));
03601             }
03602             context_info_printed = 1;
03603          }
03604          dpc->total_prio++;
03605 
03606          /* write extension name and first peer */
03607          snprintf(buf, sizeof(buf), "'%s' =>", ast_get_extension_name(e));
03608 
03609          print_ext(e, buf2, sizeof(buf2));
03610 
03611          ast_cli(fd, "  %-17s %-45s [%s]\n", buf, buf2,
03612             ast_get_extension_registrar(e));
03613 
03614          dpc->total_exten++;
03615          /* walk next extension peers */
03616          p = e;   /* skip the first one, we already got it */
03617          while ( (p = ast_walk_extension_priorities(e, p)) ) {
03618             const char *el = ast_get_extension_label(p);
03619             dpc->total_prio++;
03620             if (el)
03621                snprintf(buf, sizeof(buf), "   [%s]", el);
03622             else
03623                buf[0] = '\0';
03624             print_ext(p, buf2, sizeof(buf2));
03625 
03626             ast_cli(fd,"  %-17s %-45s [%s]\n", buf, buf2,
03627                ast_get_extension_registrar(p));
03628          }
03629       }
03630 
03631       /* walk included and write info ... */
03632       i = NULL;
03633       while ( (i = ast_walk_context_includes(c, i)) ) {
03634          snprintf(buf, sizeof(buf), "'%s'", ast_get_include_name(i));
03635          if (exten) {
03636             /* Check all includes for the requested extension */
03637             if (includecount >= AST_PBX_MAX_STACK) {
03638                ast_log(LOG_NOTICE, "Maximum include depth exceeded!\n");
03639             } else {
03640                int dupe=0;
03641                int x;
03642                for (x=0;x<includecount;x++) {
03643                   if (!strcasecmp(includes[x], ast_get_include_name(i))) {
03644                      dupe++;
03645                      break;
03646                   }
03647                }
03648                if (!dupe) {
03649                   includes[includecount] = ast_get_include_name(i);
03650                   show_dialplan_helper(fd, ast_get_include_name(i), exten, dpc, i, includecount + 1, includes);
03651                } else {
03652                   ast_log(LOG_WARNING, "Avoiding circular include of %s within %s\n", ast_get_include_name(i), context);
03653                }
03654             }
03655          } else {
03656             ast_cli(fd, "  Include =>        %-45s [%s]\n",
03657                buf, ast_get_include_registrar(i));
03658          }
03659       }
03660 
03661       /* walk ignore patterns and write info ... */
03662       ip = NULL;
03663       while ( (ip = ast_walk_context_ignorepats(c, ip)) ) {
03664          const char *ipname = ast_get_ignorepat_name(ip);
03665          char ignorepat[AST_MAX_EXTENSION];
03666          snprintf(buf, sizeof(buf), "'%s'", ipname);
03667          snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname);
03668          if (!exten || ast_extension_match(ignorepat, exten)) {
03669             ast_cli(fd, "  Ignore pattern => %-45s [%s]\n",
03670                buf, ast_get_ignorepat_registrar(ip));
03671          }
03672       }
03673       if (!rinclude) {
03674          struct ast_sw *sw = NULL;
03675          while ( (sw = ast_walk_context_switches(c, sw)) ) {
03676             snprintf(buf, sizeof(buf), "'%s/%s'",
03677                ast_get_switch_name(sw),
03678                ast_get_switch_data(sw));
03679             ast_cli(fd, "  Alt. Switch =>    %-45s [%s]\n",
03680                buf, ast_get_switch_registrar(sw));
03681          }
03682       }
03683 
03684       ast_unlock_context(c);
03685 
03686       /* if we print something in context, make an empty line */
03687       if (context_info_printed)
03688          ast_cli(fd, "\n");
03689    }
03690    ast_unlock_contexts();
03691 
03692    return (dpc->total_exten == old_total_exten) ? -1 : res;
03693 }
03694 
03695 static int handle_show_dialplan(int fd, int argc, char *argv[])
03696 {
03697    char *exten = NULL, *context = NULL;
03698    /* Variables used for different counters */
03699    struct dialplan_counters counters;
03700 
03701    const char *incstack[AST_PBX_MAX_STACK];
03702    memset(&counters, 0, sizeof(counters));
03703 
03704    if (argc != 2 && argc != 3)
03705       return RESULT_SHOWUSAGE;
03706 
03707    /* we obtain [exten@]context? if yes, split them ... */
03708    if (argc == 3) {
03709       if (strchr(argv[2], '@')) {   /* split into exten & context */
03710          context = ast_strdupa(argv[2]);
03711          exten = strsep(&context, "@");
03712          /* change empty strings to NULL */
03713          if (ast_strlen_zero(exten))
03714             exten = NULL;
03715       } else { /* no '@' char, only context given */
03716          context = argv[2];
03717       }
03718       if (ast_strlen_zero(context))
03719          context = NULL;
03720    }
03721    /* else Show complete dial plan, context and exten are NULL */
03722    show_dialplan_helper(fd, context, exten, &counters, NULL, 0, incstack);
03723 
03724    /* check for input failure and throw some error messages */
03725    if (context && !counters.context_existence) {
03726       ast_cli(fd, "There is no existence of '%s' context\n", context);
03727       return RESULT_FAILURE;
03728    }
03729 
03730    if (exten && !counters.extension_existence) {
03731       if (context)
03732          ast_cli(fd, "There is no existence of %s@%s extension\n",
03733             exten, context);
03734       else
03735          ast_cli(fd,
03736             "There is no existence of '%s' extension in all contexts\n",
03737             exten);
03738       return RESULT_FAILURE;
03739    }
03740 
03741    ast_cli(fd,"-= %d %s (%d %s) in %d %s. =-\n",
03742             counters.total_exten, counters.total_exten == 1 ? "extension" : "extensions",
03743             counters.total_prio, counters.total_prio == 1 ? "priority" : "priorities",
03744             counters.total_context, counters.total_context == 1 ? "context" : "contexts");
03745 
03746    /* everything ok */
03747    return RESULT_SUCCESS;
03748 }
03749 
03750 /*! \brief CLI support for listing global variables in a parseable way */
03751 static int handle_show_globals(int fd, int argc, char *argv[])
03752 {
03753    int i = 0;
03754    struct ast_var_t *newvariable;
03755 
03756    ast_mutex_lock(&globalslock);
03757    AST_LIST_TRAVERSE (&globals, newvariable, entries) {
03758       i++;
03759       ast_cli(fd, "   %s=%s\n", ast_var_name(newvariable), ast_var_value(newvariable));
03760    }
03761    ast_mutex_unlock(&globalslock);
03762    ast_cli(fd, "\n    -- %d variables\n", i);
03763 
03764    return RESULT_SUCCESS;
03765 }
03766 
03767 /*! \brief  CLI support for setting global variables */
03768 static int handle_set_global_deprecated(int fd, int argc, char *argv[])
03769 {
03770    if (argc != 4)
03771       return RESULT_SHOWUSAGE;
03772 
03773    pbx_builtin_setvar_helper(NULL, argv[2], argv[3]);
03774    ast_cli(fd, "\n    -- Global variable %s set to %s\n", argv[2], argv[3]);
03775 
03776    return RESULT_SUCCESS;
03777 }
03778 
03779 
03780 static int handle_set_global(int fd, int argc, char *argv[])
03781 {
03782    if (argc != 5)
03783       return RESULT_SHOWUSAGE;
03784 
03785    pbx_builtin_setvar_helper(NULL, argv[3], argv[4]);
03786    ast_cli(fd, "\n    -- Global variable %s set to %s\n", argv[3], argv[4]);
03787 
03788    return RESULT_SUCCESS;
03789 }
03790 
03791 
03792 
03793 /*
03794  * CLI entries for upper commands ...
03795  */
03796 static struct ast_cli_entry cli_show_applications_deprecated = {
03797    { "show", "applications", NULL },
03798    handle_show_applications_deprecated, NULL,
03799    NULL, complete_show_applications_deprecated };
03800 
03801 static struct ast_cli_entry cli_show_functions_deprecated = {
03802    { "show", "functions", NULL },
03803    handle_show_functions_deprecated, NULL,
03804         NULL };
03805 
03806 static struct ast_cli_entry cli_show_switches_deprecated = {
03807    { "show", "switches", NULL },
03808    handle_show_switches, NULL,
03809         NULL };
03810 
03811 static struct ast_cli_entry cli_show_hints_deprecated = {
03812    { "show", "hints", NULL },
03813    handle_show_hints, NULL,
03814         NULL };
03815 
03816 static struct ast_cli_entry cli_show_globals_deprecated = {
03817    { "show", "globals", NULL },
03818    handle_show_globals, NULL,
03819         NULL };
03820 
03821 static struct ast_cli_entry cli_show_function_deprecated = {
03822    { "show" , "function", NULL },
03823    handle_show_function_deprecated, NULL,
03824         NULL, complete_show_function };
03825 
03826 static struct ast_cli_entry cli_show_application_deprecated = {
03827    { "show", "application", NULL },
03828    handle_show_application_deprecated, NULL,
03829         NULL, complete_show_application };
03830 
03831 static struct ast_cli_entry cli_show_dialplan_deprecated = {
03832    { "show", "dialplan", NULL },
03833    handle_show_dialplan, NULL,
03834         NULL, complete_show_dialplan_context };
03835 
03836 static struct ast_cli_entry cli_set_global_deprecated = {
03837    { "set", "global", NULL },
03838    handle_set_global_deprecated, NULL,
03839         NULL };
03840 
03841 static struct ast_cli_entry pbx_cli[] = {
03842    { { "core", "show", "applications", NULL },
03843    handle_show_applications, "Shows registered dialplan applications",
03844    show_applications_help, complete_show_applications, &cli_show_applications_deprecated },
03845 
03846    { { "core", "show", "functions", NULL },
03847    handle_show_functions, "Shows registered dialplan functions",
03848    show_functions_help, NULL, &cli_show_functions_deprecated },
03849 
03850    { { "core", "show", "switches", NULL },
03851    handle_show_switches, "Show alternative switches",
03852    show_switches_help, NULL, &cli_show_switches_deprecated },
03853 
03854    { { "core", "show", "hints", NULL },
03855    handle_show_hints, "Show dialplan hints",
03856    show_hints_help, NULL, &cli_show_hints_deprecated },
03857 
03858    { { "core", "show", "globals", NULL },
03859    handle_show_globals, "Show global dialplan variables",
03860    show_globals_help, NULL, &cli_show_globals_deprecated },
03861 
03862    { { "core", "show" , "function", NULL },
03863    handle_show_function, "Describe a specific dialplan function",
03864    show_function_help, complete_show_function, &cli_show_function_deprecated },
03865 
03866    { { "core", "show", "application", NULL },
03867    handle_show_application, "Describe a specific dialplan application",
03868    show_application_help, complete_show_application, &cli_show_application_deprecated },
03869 
03870    { { "core", "set", "global", NULL },
03871    handle_set_global, "Set global dialplan variable",
03872    set_global_help, NULL, &cli_set_global_deprecated },
03873 
03874    { { "dialplan", "show", NULL },
03875    handle_show_dialplan, "Show dialplan",
03876    show_dialplan_help, complete_show_dialplan_context, &cli_show_dialplan_deprecated },
03877 };
03878 
03879 int ast_unregister_application(const char *app)
03880 {
03881    struct ast_app *tmp;
03882 
03883    AST_LIST_LOCK(&apps);
03884    AST_LIST_TRAVERSE_SAFE_BEGIN(&apps, tmp, list) {
03885       if (!strcasecmp(app, tmp->name)) {
03886          AST_LIST_REMOVE_CURRENT(&apps, list);
03887          if (option_verbose > 1)
03888             ast_verbose( VERBOSE_PREFIX_2 "Unregistered application '%s'\n", tmp->name);
03889          free(tmp);
03890          break;
03891       }
03892    }
03893    AST_LIST_TRAVERSE_SAFE_END
03894    AST_LIST_UNLOCK(&apps);
03895 
03896    return tmp ? 0 : -1;
03897 }
03898 
03899 static struct ast_context *__ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar, int existsokay)
03900 {
03901    struct ast_context *tmp, **local_contexts;
03902    int length = sizeof(struct ast_context) + strlen(name) + 1;
03903 
03904    if (!extcontexts) {
03905       ast_rdlock_contexts();
03906       local_contexts = &contexts;
03907    } else
03908       local_contexts = extcontexts;
03909 
03910    for (tmp = *local_contexts; tmp; tmp = tmp->next) {
03911       if (!strcasecmp(tmp->name, name)) {
03912          if (!existsokay) {
03913             ast_log(LOG_WARNING, "Tried to register context '%s', already in use\n", name);
03914             tmp = NULL;
03915          }
03916          if (!extcontexts)
03917             ast_unlock_contexts();
03918          return tmp;
03919       }
03920    }
03921    
03922    if (!extcontexts)
03923       ast_unlock_contexts();
03924 
03925    if ((tmp = ast_calloc(1, length))) {
03926       ast_mutex_init(&tmp->lock);
03927       ast_mutex_init(&tmp->macrolock);
03928       strcpy(tmp->name, name);
03929       tmp->registrar = registrar;
03930       if (!extcontexts)
03931          ast_wrlock_contexts();
03932       tmp->next = *local_contexts;
03933       *local_contexts = tmp;
03934       if (!extcontexts)
03935          ast_unlock_contexts();
03936       if (option_debug)
03937          ast_log(LOG_DEBUG, "Registered context '%s'\n", tmp->name);
03938       if (option_verbose > 2)
03939          ast_verbose( VERBOSE_PREFIX_3 "Registered extension context '%s'\n", tmp->name);
03940    }
03941 
03942    return tmp;
03943 }
03944 
03945 struct ast_context *ast_context_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03946 {
03947    return __ast_context_create(extcontexts, name, registrar, 0);
03948 }
03949 
03950 struct ast_context *ast_context_find_or_create(struct ast_context **extcontexts, const char *name, const char *registrar)
03951 {
03952    return __ast_context_create(extcontexts, name, registrar, 1);
03953 }
03954 void __ast_context_destroy(struct ast_context *con, const char *registrar);
03955 
03956 struct store_hint {
03957    char *context;
03958    char *exten;
03959    struct ast_state_cb *callbacks;
03960    int laststate;
03961    AST_LIST_ENTRY(store_hint) list;
03962    char data[1];
03963 };
03964 
03965 AST_LIST_HEAD(store_hints, store_hint);
03966 
03967 /* XXX this does not check that multiple contexts are merged */
03968 void ast_merge_contexts_and_delete(struct ast_context **extcontexts, const char *registrar)
03969 {
03970    struct ast_context *tmp, *lasttmp = NULL;
03971    struct store_hints store = AST_LIST_HEAD_INIT_VALUE;
03972    struct store_hint *this;
03973    struct ast_hint *hint;
03974    struct ast_exten *exten;
03975    int length;
03976    struct ast_state_cb *thiscb, *prevcb;
03977 
03978    /* it is very important that this function hold the hint list lock _and_ the conlock
03979       during its operation; not only do we need to ensure that the list of contexts
03980       and extensions does not change, but also that no hint callbacks (watchers) are
03981       added or removed during the merge/delete process
03982 
03983       in addition, the locks _must_ be taken in this order, because there are already
03984       other code paths that use this order
03985    */
03986    ast_wrlock_contexts();
03987    AST_LIST_LOCK(&hints);
03988 
03989    /* preserve all watchers for hints associated with this registrar */
03990    AST_LIST_TRAVERSE(&hints, hint, list) {
03991       if (hint->callbacks && !strcmp(registrar, hint->exten->parent->registrar)) {
03992          length = strlen(hint->exten->exten) + strlen(hint->exten->parent->name) + 2 + sizeof(*this);
03993          if (!(this = ast_calloc(1, length)))
03994             continue;
03995          this->callbacks = hint->callbacks;
03996          hint->callbacks = NULL;
03997          this->laststate = hint->laststate;
03998          this->context = this->data;
03999          strcpy(this->data, hint->exten->parent->name);
04000          this->exten = this->data + strlen(this->context) + 1;
04001          strcpy(this->exten, hint->exten->exten);
04002          AST_LIST_INSERT_HEAD(&store, this, list);
04003       }
04004    }
04005 
04006    tmp = *extcontexts;
04007    if (registrar) {
04008       /* XXX remove previous contexts from same registrar */
04009       if (option_debug)
04010          ast_log(LOG_DEBUG, "must remove any reg %s\n", registrar);
04011       __ast_context_destroy(NULL,registrar);
04012       while (tmp) {
04013          lasttmp = tmp;
04014          tmp = tmp->next;
04015       }
04016    } else {
04017       /* XXX remove contexts with the same name */
04018       while (tmp) {
04019          ast_log(LOG_WARNING, "must remove %s  reg %s\n", tmp->name, tmp->registrar);
04020          __ast_context_destroy(tmp,tmp->registrar);
04021          lasttmp = tmp;
04022          tmp = tmp->next;
04023       }
04024    }
04025    if (lasttmp) {
04026       lasttmp->next = contexts;
04027       contexts = *extcontexts;
04028       *extcontexts = NULL;
04029    } else
04030       ast_log(LOG_WARNING, "Requested contexts didn't get merged\n");
04031 
04032    /* restore the watchers for hints that can be found; notify those that
04033       cannot be restored
04034    */
04035    while ((this = AST_LIST_REMOVE_HEAD(&store, list))) {
04036       struct pbx_find_info q = { .stacklen = 0 };
04037       exten = pbx_find_extension(NULL, NULL, &q, this->context, this->exten, PRIORITY_HINT, NULL, "", E_MATCH);
04038       /* Find the hint in the list of hints */
04039       AST_LIST_TRAVERSE(&hints, hint, list) {
04040          if (hint->exten == exten)
04041             break;
04042       }
04043       if (!exten || !hint) {
04044          /* this hint has been removed, notify the watchers */
04045          prevcb = NULL;
04046          thiscb = this->callbacks;
04047          while (thiscb) {
04048             prevcb = thiscb;
04049             thiscb = thiscb->next;
04050             prevcb->callback(this->context, this->exten, AST_EXTENSION_REMOVED, prevcb->data);
04051             free(prevcb);
04052             }
04053       } else {
04054          thiscb = this->callbacks;
04055          while (thiscb->next)
04056             thiscb = thiscb->next;
04057          thiscb->next = hint->callbacks;
04058          hint->callbacks = this->callbacks;
04059          hint->laststate = this->laststate;
04060       }
04061       free(this);
04062    }
04063 
04064    AST_LIST_UNLOCK(&hints);
04065    ast_unlock_contexts();
04066 
04067    return;
04068 }
04069 
04070 /*
04071  * errno values
04072  *  EBUSY  - can't lock
04073  *  ENOENT - no existence of context
04074  */
04075 int ast_context_add_include(const char *context, const char *include, const char *registrar)
04076 {
04077    int ret = -1;
04078    struct ast_context *c = find_context_locked(context);
04079 
04080    if (c) {
04081       ret = ast_context_add_include2(c, include, registrar);
04082       ast_unlock_contexts();
04083    }
04084    return ret;
04085 }
04086 
04087 /*! \brief Helper for get_range.
04088  * return the index of the matching entry, starting from 1.
04089  * If names is not supplied, try numeric values.
04090  */
04091 static int lookup_name(const char *s, char *const names[], int max)
04092 {
04093    int i;
04094 
04095    if (names) {
04096       for (i = 0; names[i]; i++) {
04097          if (!strcasecmp(s, names[i]))
04098             return i+1;
04099       }
04100    } else if (sscanf(s, "%d", &i) == 1 && i >= 1 && i <= max) {
04101       return i;
04102    }
04103    return 0; /* error return */
04104 }
04105 
04106 /*! \brief helper function to return a range up to max (7, 12, 31 respectively).
04107  * names, if supplied, is an array of names that should be mapped to numbers.
04108  */
04109 static unsigned get_range(char *src, int max, char *const names[], const char *msg)
04110 {
04111    int s, e; /* start and ending position */
04112    unsigned int mask = 0;
04113 
04114    /* Check for whole range */
04115    if (ast_strlen_zero(src) || !strcmp(src, "*")) {
04116       s = 0;
04117       e = max - 1;
04118    } else {
04119       /* Get start and ending position */
04120       char *c = strchr(src, '-');
04121       if (c)
04122          *c++ = '\0';
04123       /* Find the start */
04124       s = lookup_name(src, names, max);
04125       if (!s) {
04126          ast_log(LOG_WARNING, "Invalid %s '%s', assuming none\n", msg, src);
04127          return 0;
04128       }
04129       s--;
04130       if (c) { /* find end of range */
04131          e = lookup_name(c, names, max);
04132          if (!e) {
04133             ast_log(LOG_WARNING, "Invalid end %s '%s', assuming none\n", msg, c);
04134             return 0;
04135          }
04136          e--;
04137       } else
04138          e = s;
04139    }
04140    /* Fill the mask. Remember that ranges are cyclic */
04141    mask = 1 << e; /* initialize with last element */
04142    while (s != e) {
04143       if (s >= max) {
04144          s = 0;
04145          mask |= (1 << s);
04146       } else {
04147          mask |= (1 << s);
04148          s++;
04149       }
04150    }
04151    return mask;
04152 }
04153 
04154 /*! \brief store a bitmask of valid times, one bit each 2 minute */
04155 static void get_timerange(struct ast_timing *i, char *times)
04156 {
04157    char *e;
04158    int x;
04159    int s1, s2;
04160    int e1, e2;
04161    /* int cth, ctm; */
04162 
04163    /* start disabling all times, fill the fields with 0's, as they may contain garbage */
04164    memset(i->minmask, 0, sizeof(i->minmask));
04165 
04166    /* 2-minutes per bit, since the mask has only 32 bits :( */
04167    /* Star is all times */
04168    if (ast_strlen_zero(times) || !strcmp(times, "*")) {
04169       for (x=0; x<24; x++)
04170          i->minmask[x] = 0x3fffffff; /* 30 bits */
04171       return;
04172    }
04173    /* Otherwise expect a range */
04174    e = strchr(times, '-');
04175    if (!e) {
04176       ast_log(LOG_WARNING, "Time range is not valid. Assuming no restrictions based on time.\n");
04177       return;
04178    }
04179    *e++ = '\0';
04180    /* XXX why skip non digits ? */
04181    while (*e && !isdigit(*e))
04182       e++;
04183    if (!*e) {
04184       ast_log(LOG_WARNING, "Invalid time range.  Assuming no restrictions based on time.\n");
04185       return;
04186    }
04187    if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
04188       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", times);
04189       return;
04190    }
04191    if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
04192       ast_log(LOG_WARNING, "%s isn't a time.  Assuming no restrictions based on time.\n", e);
04193       return;
04194    }
04195    /* XXX this needs to be optimized */
04196 #if 1
04197    s1 = s1 * 30 + s2/2;
04198    if ((s1 < 0) || (s1 >= 24*30)) {
04199       ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
04200       return;
04201    }
04202    e1 = e1 * 30 + e2/2;
04203    if ((e1 < 0) || (e1 >= 24*30)) {
04204       ast_log(LOG_WARNING, "%s isn't a valid end time. Assuming no time.\n", e);
04205       return;
04206    }
04207    /* Go through the time and enable each appropriate bit */
04208    for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
04209       i->minmask[x/30] |= (1 << (x % 30));
04210    }
04211    /* Do the last one */
04212    i->minmask[x/30] |= (1 << (x % 30));
04213 #else
04214    for (cth=0; cth<24; cth++) {
04215       /* Initialize masks to blank */
04216       i->minmask[cth] = 0;
04217       for (ctm=0; ctm<30; ctm++) {
04218          if (
04219          /* First hour with more than one hour */
04220                (((cth == s1) && (ctm >= s2)) &&
04221                 ((cth < e1)))
04222          /* Only one hour */
04223          ||    (((cth == s1) && (ctm >= s2)) &&
04224                 ((cth == e1) && (ctm <= e2)))
04225          /* In between first and last hours (more than 2 hours) */
04226          ||    ((cth > s1) &&
04227                 (cth < e1))
04228          /* Last hour with more than one hour */
04229          ||    ((cth > s1) &&
04230                 ((cth == e1) && (ctm <= e2)))
04231          )
04232             i->minmask[cth] |= (1 << (ctm / 2));
04233       }
04234    }
04235 #endif
04236    /* All done */
04237    return;
04238 }
04239 
04240 static char *days[] =
04241 {
04242    "sun",
04243    "mon",
04244    "tue",
04245    "wed",
04246    "thu",
04247    "fri",
04248    "sat",
04249    NULL,
04250 };
04251 
04252 static char *months[] =
04253 {
04254    "jan",
04255    "feb",
04256    "mar",
04257    "apr",
04258    "may",
04259    "jun",
04260    "jul",
04261    "aug",
04262    "sep",
04263    "oct",
04264    "nov",
04265    "dec",
04266    NULL,
04267 };
04268 
04269 int ast_build_timing(struct ast_timing *i, const char *info_in)
04270 {
04271    char info_save[256];
04272    char *info;
04273 
04274    /* Check for empty just in case */
04275    if (ast_strlen_zero(info_in))
04276       return 0;
04277    /* make a copy just in case we were passed a static string */
04278    ast_copy_string(info_save, info_in, sizeof(info_save));
04279    info = info_save;
04280    /* Assume everything except time */
04281    i->monthmask = 0xfff;   /* 12 bits */
04282    i->daymask = 0x7fffffffU; /* 31 bits */
04283    i->dowmask = 0x7f; /* 7 bits */
04284    /* on each call, use strsep() to move info to the next argument */
04285    get_timerange(i, strsep(&info, "|"));
04286    if (info)
04287       i->dowmask = get_range(strsep(&info, "|"), 7, days, "day of week");
04288    if (info)
04289       i->daymask = get_range(strsep(&info, "|"), 31, NULL, "day");
04290    if (info)
04291       i->monthmask = get_range(strsep(&info, "|"), 12, months, "month");
04292    return 1;
04293 }
04294 
04295 int ast_check_timing(const struct ast_timing *i)
04296 {
04297    struct tm tm;
04298    time_t t = time(NULL);
04299 
04300    ast_localtime(&t, &tm, NULL);
04301 
04302    /* If it's not the right month, return */
04303    if (!(i->monthmask & (1 << tm.tm_mon)))
04304       return 0;
04305 
04306    /* If it's not that time of the month.... */
04307    /* Warning, tm_mday has range 1..31! */
04308    if (!(i->daymask & (1 << (tm.tm_mday-1))))
04309       return 0;
04310 
04311    /* If it's not the right day of the week */
04312    if (!(i->dowmask & (1 << tm.tm_wday)))
04313       return 0;
04314 
04315    /* Sanity check the hour just to be safe */
04316    if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
04317       ast_log(LOG_WARNING, "Insane time...\n");
04318       return 0;
04319    }
04320 
04321    /* Now the tough part, we calculate if it fits
04322       in the right time based on min/hour */
04323    if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
04324       return 0;
04325 
04326    /* If we got this far, then we're good */
04327    return 1;
04328 }
04329 
04330 /*
04331  * errno values
04332  *  ENOMEM - out of memory
04333  *  EBUSY  - can't lock
04334  *  EEXIST - already included
04335  *  EINVAL - there is no existence of context for inclusion
04336  */
04337 int ast_context_add_include2(struct ast_context *con, const char *value,
04338    const char *registrar)
04339 {
04340    struct ast_include *new_include;
04341    char *c;
04342    struct ast_include *i, *il = NULL; /* include, include_last */
04343    int length;
04344    char *p;
04345 
04346    length = sizeof(struct ast_include);
04347    length += 2 * (strlen(value) + 1);
04348 
04349    /* allocate new include structure ... */
04350    if (!(new_include = ast_calloc(1, length)))
04351       return -1;
04352    /* Fill in this structure. Use 'p' for assignments, as the fields
04353     * in the structure are 'const char *'
04354     */
04355    p = new_include->stuff;
04356    new_include->name = p;
04357    strcpy(p, value);
04358    p += strlen(value) + 1;
04359    new_include->rname = p;
04360    strcpy(p, value);
04361    /* Strip off timing info, and process if it is there */
04362    if ( (c = strchr(p, '|')) ) {
04363       *c++ = '\0';
04364            new_include->hastime = ast_build_timing(&(new_include->timing), c);
04365    }
04366    new_include->next      = NULL;
04367    new_include->registrar = registrar;
04368 
04369    ast_mutex_lock(&con->lock);
04370 
04371    /* ... go to last include and check if context is already included too... */
04372    for (i = con->includes; i; i = i->next) {
04373       if (!strcasecmp(i->name, new_include->name)) {
04374          free(new_include);
04375          ast_mutex_unlock(&con->lock);
04376          errno = EEXIST;
04377          return -1;
04378       }
04379       il = i;
04380    }
04381 
04382    /* ... include new context into context list, unlock, return */
04383    if (il)
04384       il->next = new_include;
04385    else
04386       con->includes = new_include;
04387    if (option_verbose > 2)
04388       ast_verbose(VERBOSE_PREFIX_3 "Including context '%s' in context '%s'\n", new_include->name, ast_get_context_name(con));
04389    ast_mutex_unlock(&con->lock);
04390 
04391    return 0;
04392 }
04393 
04394 /*
04395  * errno values
04396  *  EBUSY  - can't lock
04397  *  ENOENT - no existence of context
04398  */
04399 int ast_context_add_switch(const char *context, const char *sw, const char *data, int eval, const char *registrar)
04400 {
04401    int ret = -1;
04402    struct ast_context *c = find_context_locked(context);
04403 
04404    if (c) { /* found, add switch to this context */
04405       ret = ast_context_add_switch2(c, sw, data, eval, registrar);
04406       ast_unlock_contexts();
04407    }
04408    return ret;
04409 }
04410 
04411 /*
04412  * errno values
04413  *  ENOMEM - out of memory
04414  *  EBUSY  - can't lock
04415  *  EEXIST - already included
04416  *  EINVAL - there is no existence of context for inclusion
04417  */
04418 int ast_context_add_switch2(struct ast_context *con, const char *value,
04419    const char *data, int eval, const char *registrar)
04420 {
04421    struct ast_sw *new_sw;
04422    struct ast_sw *i;
04423    int length;
04424    char *p;
04425 
04426    length = sizeof(struct ast_sw);
04427    length += strlen(value) + 1;
04428    if (data)
04429       length += strlen(data);
04430    length++;
04431 
04432    /* allocate new sw structure ... */
04433    if (!(new_sw = ast_calloc(1, length)))
04434       return -1;
04435    /* ... fill in this structure ... */
04436    p = new_sw->stuff;
04437    new_sw->name = p;
04438    strcpy(new_sw->name, value);
04439    p += strlen(value) + 1;
04440    new_sw->data = p;
04441    if (data) {
04442       strcpy(new_sw->data, data);
04443       p += strlen(data) + 1;
04444    } else {
04445       strcpy(new_sw->data, "");
04446       p++;
04447    }
04448    new_sw->eval     = eval;
04449    new_sw->registrar = registrar;
04450 
04451    /* ... try to lock this context ... */
04452    ast_mutex_lock(&con->lock);
04453 
04454    /* ... go to last sw and check if context is already swd too... */
04455    AST_LIST_TRAVERSE(&con->alts, i, list) {
04456       if (!strcasecmp(i->name, new_sw->name) && !strcasecmp(i->data, new_sw->data)) {
04457          free(new_sw);
04458          ast_mutex_unlock(&con->lock);
04459          errno = EEXIST;
04460          return -1;
04461       }
04462    }
04463 
04464    /* ... sw new context into context list, unlock, return */
04465    AST_LIST_INSERT_TAIL(&con->alts, new_sw, list);
04466 
04467    if (option_verbose > 2)
04468       ast_verbose(VERBOSE_PREFIX_3 "Including switch '%s/%s' in context '%s'\n", new_sw->name, new_sw->data, ast_get_context_name(con));
04469 
04470    ast_mutex_unlock(&con->lock);
04471 
04472    return 0;
04473 }
04474 
04475 /*
04476  * EBUSY  - can't lock
04477  * ENOENT - there is not context existence
04478  */
04479 int ast_context_remove_ignorepat(const char *context, const char *ignorepat, const char *registrar)
04480 {
04481    int ret = -1;
04482    struct ast_context *c = find_context_locked(context);
04483 
04484    if (c) {
04485       ret = ast_context_remove_ignorepat2(c, ignorepat, registrar);
04486       ast_unlock_contexts();
04487    }
04488    return ret;
04489 }
04490 
04491 int ast_context_remove_ignorepat2(struct ast_context *con, const char *ignorepat, const char *registrar)
04492 {
04493    struct ast_ignorepat *ip, *ipl = NULL;
04494 
04495    ast_mutex_lock(&con->lock);
04496 
04497    for (ip = con->ignorepats; ip; ip = ip->next) {
04498       if (!strcmp(ip->pattern, ignorepat) &&
04499          (!registrar || (registrar == ip->registrar))) {
04500          if (ipl) {
04501             ipl->next = ip->next;
04502             free(ip);
04503          } else {
04504             con->ignorepats = ip->next;
04505             free(ip);
04506          }
04507          ast_mutex_unlock(&con->lock);
04508          return 0;
04509       }
04510       ipl = ip;
04511    }
04512 
04513    ast_mutex_unlock(&con->lock);
04514    errno = EINVAL;
04515    return -1;
04516 }
04517 
04518 /*
04519  * EBUSY - can't lock
04520  * ENOENT - there is no existence of context
04521  */
04522 int ast_context_add_ignorepat(const char *context, const char *value, const char *registrar)
04523 {
04524    int ret = -1;
04525    struct ast_context *c = find_context_locked(context);
04526 
04527    if (c) {
04528       ret = ast_context_add_ignorepat2(c, value, registrar);
04529       ast_unlock_contexts();
04530    }
04531    return ret;
04532 }
04533 
04534 int ast_context_add_ignorepat2(struct ast_context *con, const char *value, const char *registrar)
04535 {
04536    struct ast_ignorepat *ignorepat, *ignorepatc, *ignorepatl = NULL;
04537    int length;
04538    char *pattern;
04539    length = sizeof(struct ast_ignorepat);
04540    length += strlen(value) + 1;
04541    if (!(ignorepat = ast_calloc(1, length)))
04542       return -1;
04543    /* The cast to char * is because we need to write the initial value.
04544     * The field is not supposed to be modified otherwise.  Also, gcc 4.2
04545     * sees the cast as dereferencing a type-punned pointer and warns about
04546     * it.  This is the workaround (we're telling gcc, yes, that's really
04547     * what we wanted to do).
04548     */
04549    pattern = (char *) ignorepat->pattern;
04550    strcpy(pattern, value);
04551    ignorepat->next = NULL;
04552    ignorepat->registrar = registrar;
04553    ast_mutex_lock(&con->lock);
04554    for (ignorepatc = con->ignorepats; ignorepatc; ignorepatc = ignorepatc->next) {
04555       ignorepatl = ignorepatc;
04556       if (!strcasecmp(ignorepatc->pattern, value)) {
04557          /* Already there */
04558          ast_mutex_unlock(&con->lock);
04559          errno = EEXIST;
04560          return -1;
04561       }
04562    }
04563    if (ignorepatl)
04564       ignorepatl->next = ignorepat;
04565    else
04566       con->ignorepats = ignorepat;
04567    ast_mutex_unlock(&con->lock);
04568    return 0;
04569 
04570 }
04571 
04572 int ast_ignore_pattern(const char *context, const char *pattern)
04573 {
04574    struct ast_context *con = ast_context_find(context);
04575    if (con) {
04576       struct ast_ignorepat *pat;
04577       for (pat = con->ignorepats; pat; pat = pat->next) {
04578          if (ast_extension_match(pat->pattern, pattern))
04579             return 1;
04580       }
04581    }
04582 
04583    return 0;
04584 }
04585 
04586 /*
04587  * EBUSY   - can't lock
04588  * ENOENT  - no existence of context
04589  *
04590  */
04591 int ast_add_extension(const char *context, int replace, const char *extension,
04592    int priority, const char *label, const char *callerid,
04593    const char *application, void *data, void (*datad)(void *), const char *registrar)
04594 {
04595    int ret = -1;
04596    struct ast_context *c = find_context_locked(context);
04597 
04598    if (c) {
04599       ret = ast_add_extension2(c, replace, extension, priority, label, callerid,
04600          application, data, datad, registrar);
04601       ast_unlock_contexts();
04602    }
04603    return ret;
04604 }
04605 
04606 int ast_explicit_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04607 {
04608    if (!chan)
04609       return -1;
04610 
04611    ast_channel_lock(chan);
04612 
04613    if (!ast_strlen_zero(context))
04614       ast_copy_string(chan->context, context, sizeof(chan->context));
04615    if (!ast_strlen_zero(exten))
04616       ast_copy_string(chan->exten, exten, sizeof(chan->exten));
04617    if (priority > -1) {
04618       chan->priority = priority;
04619       /* see flag description in channel.h for explanation */
04620       if (ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP))
04621          chan->priority--;
04622    }
04623 
04624    ast_channel_unlock(chan);
04625 
04626    return 0;
04627 }
04628 
04629 int ast_async_goto(struct ast_channel *chan, const char *context, const char *exten, int priority)
04630 {
04631    int res = 0;
04632 
04633    ast_channel_lock(chan);
04634 
04635    if (chan->pbx) { /* This channel is currently in the PBX */
04636       ast_explicit_goto(chan, context, exten, priority);
04637       ast_softhangup_nolock(chan, AST_SOFTHANGUP_ASYNCGOTO);
04638    } else {
04639       /* In order to do it when the channel doesn't really exist within
04640          the PBX, we have to make a new channel, masquerade, and start the PBX
04641          at the new location */
04642       struct ast_channel *tmpchan = ast_channel_alloc(0, chan->_state, 0, 0, chan->accountcode, chan->exten, chan->context, chan->amaflags, "AsyncGoto/%s", chan->name);
04643       if (!tmpchan) {
04644          res = -1;
04645       } else {
04646          if (chan->cdr) {
04647             ast_cdr_discard(tmpchan->cdr);
04648             tmpchan->cdr = ast_cdr_dup(chan->cdr);  /* share the love */
04649          }
04650          /* Make formats okay */
04651          tmpchan->readformat = chan->readformat;
04652          tmpchan->writeformat = chan->writeformat;
04653          /* Setup proper location */
04654          ast_explicit_goto(tmpchan,
04655             S_OR(context, chan->context), S_OR(exten, chan->exten), priority);
04656 
04657          /* Masquerade into temp channel */
04658          if (ast_channel_masquerade(tmpchan, chan)) {
04659             /* Failed to set up the masquerade.  It's probably chan_local
04660              * in the middle of optimizing itself out.  Sad. :( */
04661             ast_hangup(tmpchan);
04662             tmpchan = NULL;
04663             res = -1;
04664          } else {
04665             /* Grab the locks and get going */
04666             ast_channel_lock(tmpchan);
04667             ast_do_masquerade(tmpchan);
04668             ast_channel_unlock(tmpchan);
04669             /* Start the PBX going on our stolen channel */
04670             if (ast_pbx_start(tmpchan)) {
04671                ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmpchan->name);
04672                ast_hangup(tmpchan);
04673                res = -1;
04674             }
04675          }
04676       }
04677    }
04678    ast_channel_unlock(chan);
04679    return res;
04680 }
04681 
04682 int ast_async_goto_by_name(const char *channame, const char *context, const char *exten, int priority)
04683 {
04684    struct ast_channel *chan;
04685    int res = -1;
04686 
04687    chan = ast_get_channel_by_name_locked(channame);
04688    if (chan) {
04689       res = ast_async_goto(chan, context, exten, priority);
04690       ast_channel_unlock(chan);
04691    }
04692    return res;
04693 }
04694 
04695 /*! \brief copy a string skipping whitespace */
04696 static int ext_strncpy(char *dst, const char *src, int len)
04697 {
04698    int count=0;
04699 
04700    while (*src && (count < len - 1)) {
04701       switch(*src) {
04702       case ' ':
04703          /* otherwise exten => [a-b],1,... doesn't work */
04704          /*    case '-': */
04705          /* Ignore */
04706          break;
04707       default:
04708          *dst = *src;
04709          dst++;
04710       }
04711       src++;
04712       count++;
04713    }
04714    *dst = '\0';
04715 
04716    return count;
04717 }
04718 
04719 /*! \brief add the extension in the priority chain.
04720  * returns 0 on success, -1 on failure
04721  */
04722 static int add_pri(struct ast_context *con, struct ast_exten *tmp,
04723    struct ast_exten *el, struct ast_exten *e, int replace)
04724 {
04725    struct ast_exten *ep;
04726 
04727    for (ep = NULL; e ; ep = e, e = e->peer) {
04728       if (e->priority >= tmp->priority)
04729          break;
04730    }
04731    if (!e) {   /* go at the end, and ep is surely set because the list is not empty */
04732       ep->peer = tmp;
04733       return 0;   /* success */
04734    }
04735    if (e->priority == tmp->priority) {
04736       /* Can't have something exactly the same.  Is this a
04737          replacement?  If so, replace, otherwise, bonk. */
04738       if (!replace) {
04739          ast_log(LOG_WARNING, "Unable to register extension '%s', priority %d in '%s', already in use\n", tmp->exten, tmp->priority, con->name);
04740          if (tmp->datad)
04741             tmp->datad(tmp->data);
04742          free(tmp);
04743          return -1;
04744       }
04745       /* we are replacing e, so copy the link fields and then update
04746        * whoever pointed to e to point to us
04747        */
04748       tmp->next = e->next; /* not meaningful if we are not first in the peer list */
04749       tmp->peer = e->peer; /* always meaningful */
04750       if (ep)        /* We're in the peer list, just insert ourselves */
04751          ep->peer = tmp;
04752       else if (el)      /* We're the first extension. Take over e's functions */
04753          el->next = tmp;
04754       else        /* We're the very first extension.  */
04755          con->root = tmp;
04756       if (tmp->priority == PRIORITY_HINT)
04757          ast_change_hint(e,tmp);
04758       /* Destroy the old one */
04759       if (e->datad)
04760          e->datad(e->data);
04761       free(e);
04762    } else { /* Slip ourselves in just before e */
04763       tmp->peer = e;
04764       tmp->next = e->next; /* extension chain, or NULL if e is not the first extension */
04765       if (ep)        /* Easy enough, we're just in the peer list */
04766          ep->peer = tmp;
04767       else {         /* we are the first in some peer list, so link in the ext list */
04768          if (el)
04769             el->next = tmp;   /* in the middle... */
04770          else
04771             con->root = tmp; /* ... or at the head */
04772          e->next = NULL;   /* e is no more at the head, so e->next must be reset */
04773       }
04774       /* And immediately return success. */
04775       if (tmp->priority == PRIORITY_HINT)
04776           ast_add_hint(tmp);
04777    }
04778    return 0;
04779 }
04780 
04781 /*! \brief
04782  * Main interface to add extensions to the list for out context.
04783  *
04784  * We sort extensions in order of matching preference, so that we can
04785  * stop the search as soon as we find a suitable match.
04786  * This ordering also takes care of wildcards such as '.' (meaning
04787  * "one or more of any character") and '!' (which is 'earlymatch',
04788  * meaning "zero or more of any character" but also impacts the
04789  * return value from CANMATCH and EARLYMATCH.
04790  *
04791  * The extension match rules defined in the devmeeting 2006.05.05 are
04792  * quite simple: WE SELECT THE LONGEST MATCH.
04793  * In detail, "longest" means the number of matched characters in
04794  * the extension. In case of ties (e.g. _XXX and 333) in the length
04795  * of a pattern, we give priority to entries with the smallest cardinality
04796  * (e.g, [5-9] comes before [2-8] before the former has only 5 elements,
04797  * while the latter has 7, etc.
04798  * In case of same cardinality, the first element in the range counts.
04799  * If we still have a tie, any final '!' will make this as a possibly
04800  * less specific pattern.
04801  *
04802  * EBUSY - can't lock
04803  * EEXIST - extension with the same priority exist and no replace is set
04804  *
04805  */
04806 int ast_add_extension2(struct ast_context *con,
04807    int replace, const char *extension, int priority, const char *label, const char *callerid,
04808    const char *application, void *data, void (*datad)(void *),
04809    const char *registrar)
04810 {
04811    /*
04812     * Sort extensions (or patterns) according to the rules indicated above.
04813     * These are implemented by the function ext_cmp()).
04814     * All priorities for the same ext/pattern/cid are kept in a list,
04815     * using the 'peer' field  as a link field..
04816     */
04817    struct ast_exten *tmp, *e, *el = NULL;
04818    int res;
04819    int length;
04820    char *p;
04821    char expand_buf[VAR_BUF_SIZE] = { 0, };
04822 
04823    /* if we are adding a hint, and there are global variables, and the hint
04824       contains variable references, then expand them
04825    */
04826    ast_mutex_lock(&globalslock);
04827    if (priority == PRIORITY_HINT && AST_LIST_FIRST(&globals) && strstr(application, "${")) {
04828       pbx_substitute_variables_varshead(&globals, application, expand_buf, sizeof(expand_buf));
04829       application = expand_buf;
04830    }
04831    ast_mutex_unlock(&globalslock);
04832 
04833    length = sizeof(struct ast_exten);
04834    length += strlen(extension) + 1;
04835    length += strlen(application) + 1;
04836    if (label)
04837       length += strlen(label) + 1;
04838    if (callerid)
04839       length += strlen(callerid) + 1;
04840    else
04841       length ++;  /* just the '\0' */
04842 
04843    /* Be optimistic:  Build the extension structure first */
04844    if (!(tmp = ast_calloc(1, length)))
04845       return -1;
04846 
04847    /* use p as dst in assignments, as the fields are const char * */
04848    p = tmp->stuff;
04849    if (label) {
04850       tmp->label = p;
04851       strcpy(p, label);
04852       p += strlen(label) + 1;
04853    }
04854    tmp->exten = p;
04855    p += ext_strncpy(p, extension, strlen(extension) + 1) + 1;
04856    tmp->priority = priority;
04857    tmp->cidmatch = p;   /* but use p for assignments below */
04858    if (callerid) {
04859       p += ext_strncpy(p, callerid, strlen(callerid) + 1) + 1;
04860       tmp->matchcid = 1;
04861    } else {
04862       *p++ = '\0';
04863       tmp->matchcid = 0;
04864    }
04865    tmp->app = p;
04866    strcpy(p, application);
04867    tmp->parent = con;
04868    tmp->data = data;
04869    tmp->datad = datad;
04870    tmp->registrar = registrar;
04871 
04872    ast_mutex_lock(&con->lock);
04873    res = 0; /* some compilers will think it is uninitialized otherwise */
04874    for (e = con->root; e; el = e, e = e->next) {   /* scan the extension list */
04875       res = ext_cmp(e->exten, tmp->exten);
04876       if (res == 0) { /* extension match, now look at cidmatch */
04877          if (!e->matchcid && !tmp->matchcid)
04878             res = 0;
04879          else if (tmp->matchcid && !e->matchcid)
04880             res = 1;
04881          else if (e->matchcid && !tmp->matchcid)
04882             res = -1;
04883          else
04884             res = strcasecmp(e->cidmatch, tmp->cidmatch);
04885       }
04886       if (res >= 0)
04887          break;
04888    }
04889    if (e && res == 0) { /* exact match, insert in the pri chain */
04890       res = add_pri(con, tmp, el, e, replace);
04891       ast_mutex_unlock(&con->lock);
04892       if (res < 0) {
04893          errno = EEXIST;   /* XXX do we care ? */
04894          return 0; /* XXX should we return -1 maybe ? */
04895       }
04896    } else {
04897       /*
04898        * not an exact match, this is the first entry with this pattern,
04899        * so insert in the main list right before 'e' (if any)
04900        */
04901       tmp->next = e;
04902       if (el)
04903          el->next = tmp;
04904       else
04905          con->root = tmp;
04906       ast_mutex_unlock(&con->lock);
04907       if (tmp->priority == PRIORITY_HINT)
04908          ast_add_hint(tmp);
04909    }
04910    if (option_debug) {
04911       if (tmp->matchcid) {
04912          if (option_debug)
04913             ast_log(LOG_DEBUG, "Added extension '%s' priority %d (CID match '%s') to %s\n",
04914                tmp->exten, tmp->priority, tmp->cidmatch, con->name);
04915       } else {
04916          if (option_debug)
04917             ast_log(LOG_DEBUG, "Added extension '%s' priority %d to %s\n",
04918                tmp->exten, tmp->priority, con->name);
04919       }
04920    }
04921    if (option_verbose > 2) {
04922       if (tmp->matchcid) {
04923          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d (CID match '%s')to %s\n",
04924             tmp->exten, tmp->priority, tmp->cidmatch, con->name);
04925       } else {
04926          ast_verbose( VERBOSE_PREFIX_3 "Added extension '%s' priority %d to %s\n",
04927             tmp->exten, tmp->priority, con->name);
04928       }
04929    }
04930    return 0;
04931 }
04932 
04933 struct async_stat {
04934    pthread_t p;
04935    struct ast_channel *chan;
04936    char context[AST_MAX_CONTEXT];
04937    char exten[AST_MAX_EXTENSION];
04938    int priority;
04939    int timeout;
04940    char app[AST_MAX_EXTENSION];
04941    char appdata[1024];
04942 };
04943 
04944 static void *async_wait(void *data)
04945 {
04946    struct async_stat *as = data;
04947    struct ast_channel *chan = as->chan;
04948    int timeout = as->timeout;
04949    int res;
04950    struct ast_frame *f;
04951    struct ast_app *app;
04952 
04953    while (timeout && (chan->_state != AST_STATE_UP)) {
04954       res = ast_waitfor(chan, timeout);
04955       if (res < 1)
04956          break;
04957       if (timeout > -1)
04958          timeout = res;
04959       f = ast_read(chan);
04960       if (!f)
04961          break;
04962       if (f->frametype == AST_FRAME_CONTROL) {
04963          if ((f->subclass == AST_CONTROL_BUSY)  ||
04964              (f->subclass == AST_CONTROL_CONGESTION) ) {
04965             ast_frfree(f);
04966             break;
04967          }
04968       }
04969       ast_frfree(f);
04970    }
04971    if (chan->_state == AST_STATE_UP) {
04972       if (!ast_strlen_zero(as->app)) {
04973          app = pbx_findapp(as->app);
04974          if (app) {
04975             if (option_verbose > 2)
04976                ast_verbose(VERBOSE_PREFIX_3 "Launching %s(%s) on %s\n", as->app, as->appdata, chan->name);
04977             pbx_exec(chan, app, as->appdata);
04978          } else
04979             ast_log(LOG_WARNING, "No such application '%s'\n", as->app);
04980       } else {
04981          if (!ast_strlen_zero(as->context))
04982             ast_copy_string(chan->context, as->context, sizeof(chan->context));
04983          if (!ast_strlen_zero(as->exten))
04984             ast_copy_string(chan->exten, as->exten, sizeof(chan->exten));
04985          if (as->priority > 0)
04986             chan->priority = as->priority;
04987          /* Run the PBX */
04988          if (ast_pbx_run(chan)) {
04989             ast_log(LOG_ERROR, "Failed to start PBX on %s\n", chan->name);
04990          } else {
04991             /* PBX will have taken care of this */
04992             chan = NULL;
04993          }
04994       }
04995    }
04996    free(as);
04997    if (chan)
04998       ast_hangup(chan);
04999    return NULL;
05000 }
05001 
05002 /*! Function to post an empty cdr after a spool call fails.
05003  *
05004  *  This function posts an empty cdr for a failed spool call
05005  *
05006  */
05007 static int ast_pbx_outgoing_cdr_failed(void)
05008 {
05009    /* allocate a channel */
05010    struct ast_channel *chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", "");
05011 
05012    if (!chan)
05013       return -1;  /* failure */
05014 
05015    if (!chan->cdr) {
05016       /* allocation of the cdr failed */
05017       ast_channel_free(chan);   /* free the channel */
05018       return -1;                /* return failure */
05019    }
05020 
05021    /* allocation of the cdr was successful */
05022    ast_cdr_init(chan->cdr, chan);  /* initilize our channel's cdr */
05023    ast_cdr_start(chan->cdr);       /* record the start and stop time */
05024    ast_cdr_end(chan->cdr);
05025    ast_cdr_failed(chan->cdr);      /* set the status to failed */
05026    ast_cdr_detach(chan->cdr);      /* post and free the record */
05027    chan->cdr = NULL;
05028    ast_channel_free(chan);         /* free the channel */
05029 
05030    return 0;  /* success */
05031 }
05032 
05033 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)
05034 {
05035    struct ast_channel *chan;
05036    struct async_stat *as;
05037    int res = -1, cdr_res = -1;
05038    struct outgoing_helper oh;
05039    pthread_attr_t attr;
05040 
05041    if (sync) {
05042       LOAD_OH(oh);
05043       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05044       if (channel) {
05045          *channel = chan;
05046          if (chan)
05047             ast_channel_lock(chan);
05048       }
05049       if (chan) {
05050          if (chan->_state == AST_STATE_UP) {
05051                res = 0;
05052             if (option_verbose > 3)
05053                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05054 
05055             if (sync > 1) {
05056                if (channel)
05057                   ast_channel_unlock(chan);
05058                if (ast_pbx_run(chan)) {
05059                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
05060                   if (channel)
05061                      *channel = NULL;
05062                   ast_hangup(chan);
05063                   chan = NULL;
05064                   res = -1;
05065                }
05066             } else {
05067                if (ast_pbx_start(chan)) {
05068                   ast_log(LOG_ERROR, "Unable to start PBX on %s\n", chan->name);
05069                   if (channel) {
05070                      *channel = NULL;
05071                      ast_channel_unlock(chan);
05072                   }
05073                   ast_hangup(chan);
05074                   res = -1;
05075                }
05076                chan = NULL;
05077             }
05078          } else {
05079             if (option_verbose > 3)
05080                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05081 
05082             if (chan->cdr) { /* update the cdr */
05083                /* here we update the status of the call, which sould be busy.
05084                 * if that fails then we set the status to failed */
05085                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05086                   ast_cdr_failed(chan->cdr);
05087             }
05088 
05089             if (channel) {
05090                *channel = NULL;
05091                ast_channel_unlock(chan);
05092             }
05093             ast_hangup(chan);
05094             chan = NULL;
05095          }
05096       }
05097 
05098       if (res < 0) { /* the call failed for some reason */
05099          if (*reason == 0) { /* if the call failed (not busy or no answer)
05100                         * update the cdr with the failed message */
05101             cdr_res = ast_pbx_outgoing_cdr_failed();
05102             if (cdr_res != 0) {
05103                res = cdr_res;
05104                goto outgoing_exten_cleanup;
05105             }
05106          }
05107 
05108          /* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
05109          /* check if "failed" exists */
05110          if (ast_exists_extension(chan, context, "failed", 1, NULL)) {
05111             chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "OutgoingSpoolFailed");
05112             if (chan) {
05113                char failed_reason[4] = "";
05114                if (!ast_strlen_zero(context))
05115                   ast_copy_string(chan->context, context, sizeof(chan->context));
05116                set_ext_pri(chan, "failed", 1);
05117                ast_set_variables(chan, vars);
05118                snprintf(failed_reason, sizeof(failed_reason), "%d", *reason);
05119                pbx_builtin_setvar_helper(chan, "REASON", failed_reason);
05120                if (account)
05121                   ast_cdr_setaccount(chan, account);
05122                if (ast_pbx_run(chan)) {
05123                   ast_log(LOG_ERROR, "Unable to run PBX on %s\n", chan->name);
05124                   ast_hangup(chan);
05125                }
05126                chan = NULL;
05127             }
05128          }
05129       }
05130    } else {
05131       if (!(as = ast_calloc(1, sizeof(*as)))) {
05132          res = -1;
05133          goto outgoing_exten_cleanup;
05134       }
05135       chan = ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name);
05136       if (channel) {
05137          *channel = chan;
05138          if (chan)
05139             ast_channel_lock(chan);
05140       }
05141       if (!chan) {
05142          free(as);
05143          res = -1;
05144          goto outgoing_exten_cleanup;
05145       }
05146       as->chan = chan;
05147       ast_copy_string(as->context, context, sizeof(as->context));
05148       set_ext_pri(as->chan,  exten, priority);
05149       as->timeout = timeout;
05150       ast_set_variables(chan, vars);
05151       if (account)
05152          ast_cdr_setaccount(chan, account);
05153       pthread_attr_init(&attr);
05154       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05155       if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05156          ast_log(LOG_WARNING, "Failed to start async wait\n");
05157          free(as);
05158          if (channel) {
05159             *channel = NULL;
05160             ast_channel_unlock(chan);
05161          }
05162          ast_hangup(chan);
05163          res = -1;
05164          pthread_attr_destroy(&attr);
05165          goto outgoing_exten_cleanup;
05166       }
05167       pthread_attr_destroy(&attr);
05168       res = 0;
05169    }
05170 outgoing_exten_cleanup:
05171    ast_variables_destroy(vars);
05172    return res;
05173 }
05174 
05175 struct app_tmp {
05176    char app[256];
05177    char data[256];
05178    struct ast_channel *chan;
05179    pthread_t t;
05180 };
05181 
05182 /*! \brief run the application and free the descriptor once done */
05183 static void *ast_pbx_run_app(void *data)
05184 {
05185    struct app_tmp *tmp = data;
05186    struct ast_app *app;
05187    app = pbx_findapp(tmp->app);
05188    if (app) {
05189       if (option_verbose > 3)
05190          ast_verbose(VERBOSE_PREFIX_4 "Launching %s(%s) on %s\n", tmp->app, tmp->data, tmp->chan->name);
05191       pbx_exec(tmp->chan, app, tmp->data);
05192    } else
05193       ast_log(LOG_WARNING, "No such application '%s'\n", tmp->app);
05194    ast_hangup(tmp->chan);
05195    free(tmp);
05196    return NULL;
05197 }
05198 
05199 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)
05200 {
05201    struct ast_channel *chan;
05202    struct app_tmp *tmp;
05203    int res = -1, cdr_res = -1;
05204    struct outgoing_helper oh;
05205    pthread_attr_t attr;
05206 
05207    memset(&oh, 0, sizeof(oh));
05208    oh.vars = vars;
05209    oh.account = account;
05210 
05211    if (locked_channel)
05212       *locked_channel = NULL;
05213    if (ast_strlen_zero(app)) {
05214       res = -1;
05215       goto outgoing_app_cleanup;
05216    }
05217    if (sync) {
05218       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05219       if (chan) {
05220          ast_set_variables(chan, vars);
05221          if (account)
05222             ast_cdr_setaccount(chan, account);
05223          if (chan->_state == AST_STATE_UP) {
05224             res = 0;
05225             if (option_verbose > 3)
05226                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was answered.\n", chan->name);
05227             tmp = ast_calloc(1, sizeof(*tmp));
05228             if (!tmp)
05229                res = -1;
05230             else {
05231                ast_copy_string(tmp->app, app, sizeof(tmp->app));
05232                if (appdata)
05233                   ast_copy_string(tmp->data, appdata, sizeof(tmp->data));
05234                tmp->chan = chan;
05235                if (sync > 1) {
05236                   if (locked_channel)
05237                      ast_channel_unlock(chan);
05238                   ast_pbx_run_app(tmp);
05239                } else {
05240                   pthread_attr_init(&attr);
05241                   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05242                   if (locked_channel)
05243                      ast_channel_lock(chan);
05244                   if (ast_pthread_create(&tmp->t, &attr, ast_pbx_run_app, tmp)) {
05245                      ast_log(LOG_WARNING, "Unable to spawn execute thread on %s: %s\n", chan->name, strerror(errno));
05246                      free(tmp);
05247                      if (locked_channel)
05248                         ast_channel_unlock(chan);
05249                      ast_hangup(chan);
05250                      res = -1;
05251                   } else {
05252                      if (locked_channel)
05253                         *locked_channel = chan;
05254                   }
05255                   pthread_attr_destroy(&attr);
05256                }
05257             }
05258          } else {
05259             if (option_verbose > 3)
05260                ast_verbose(VERBOSE_PREFIX_4 "Channel %s was never answered.\n", chan->name);
05261             if (chan->cdr) { /* update the cdr */
05262                /* here we update the status of the call, which sould be busy.
05263                 * if that fails then we set the status to failed */
05264                if (ast_cdr_disposition(chan->cdr, chan->hangupcause))
05265                   ast_cdr_failed(chan->cdr);
05266             }
05267             ast_hangup(chan);
05268          }
05269       }
05270 
05271       if (res < 0) { /* the call failed for some reason */
05272          if (*reason == 0) { /* if the call failed (not busy or no answer)
05273                         * update the cdr with the failed message */
05274             cdr_res = ast_pbx_outgoing_cdr_failed();
05275             if (cdr_res != 0) {
05276                res = cdr_res;
05277                goto outgoing_app_cleanup;
05278             }
05279          }
05280       }
05281 
05282    } else {
05283       struct async_stat *as;
05284       if (!(as = ast_calloc(1, sizeof(*as)))) {
05285          res = -1;
05286          goto outgoing_app_cleanup;
05287       }
05288       chan = __ast_request_and_dial(type, format, data, timeout, reason, cid_num, cid_name, &oh);
05289       if (!chan) {
05290          free(as);
05291          res = -1;
05292          goto outgoing_app_cleanup;
05293       }
05294       as->chan = chan;
05295       ast_copy_string(as->app, app, sizeof(as->app));
05296       if (appdata)
05297          ast_copy_string(as->appdata,  appdata, sizeof(as->appdata));
05298       as->timeout = timeout;
05299       ast_set_variables(chan, vars);
05300       if (account)
05301          ast_cdr_setaccount(chan, account);
05302       /* Start a new thread, and get something handling this channel. */
05303       pthread_attr_init(&attr);
05304       pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
05305       if (locked_channel)
05306          ast_channel_lock(chan);
05307       if (ast_pthread_create(&as->p, &attr, async_wait, as)) {
05308          ast_log(LOG_WARNING, "Failed to start async wait\n");
05309          free(as);
05310          if (locked_channel)
05311             ast_channel_unlock(chan);
05312          ast_hangup(chan);
05313          res = -1;
05314          pthread_attr_destroy(&attr);
05315          goto outgoing_app_cleanup;
05316       } else {
05317          if (locked_channel)
05318             *locked_channel = chan;
05319       }
05320       pthread_attr_destroy(&attr);
05321       res = 0;
05322    }
05323 outgoing_app_cleanup:
05324    ast_variables_destroy(vars);
05325    return res;
05326 }
05327 
05328 void __ast_context_destroy(struct ast_context *con, const char *registrar)
05329 {
05330    struct ast_context *tmp, *tmpl=NULL;
05331    struct ast_include *tmpi;
05332    struct ast_sw *sw;
05333    struct ast_exten *e, *el, *en;
05334    struct ast_ignorepat *ipi;
05335 
05336    for (tmp = contexts; tmp; ) {
05337       struct ast_context *next;  /* next starting point */
05338       for (; tmp; tmpl = tmp, tmp = tmp->next) {
05339          if (option_debug)
05340             ast_log(LOG_DEBUG, "check ctx %s %s\n", tmp->name, tmp->registrar);
05341          if ( (!registrar || !strcasecmp(registrar, tmp->registrar)) &&
05342               (!con || !strcasecmp(tmp->name, con->name)) )
05343             break;   /* found it */
05344       }
05345       if (!tmp)   /* not found, we are done */
05346          break;
05347       ast_mutex_lock(&tmp->lock);
05348       if (option_debug)
05349          ast_log(LOG_DEBUG, "delete ctx %s %s\n", tmp->name, tmp->registrar);
05350       next = tmp->next;
05351       if (tmpl)
05352          tmpl->next = next;
05353       else
05354          contexts = next;
05355       /* Okay, now we're safe to let it go -- in a sense, we were
05356          ready to let it go as soon as we locked it. */
05357       ast_mutex_unlock(&tmp->lock);
05358       for (tmpi = tmp->includes; tmpi; ) { /* Free includes */
05359          struct ast_include *tmpil = tmpi;
05360          tmpi = tmpi->next;
05361          free(tmpil);
05362       }
05363       for (ipi = tmp->ignorepats; ipi; ) { /* Free ignorepats */
05364          struct ast_ignorepat *ipl = ipi;
05365          ipi = ipi->next;
05366          free(ipl);
05367       }
05368       while ((sw = AST_LIST_REMOVE_HEAD(&tmp->alts, list)))
05369          free(sw);
05370       for (e = tmp->root; e;) {
05371          for (en = e->peer; en;) {
05372             el = en;
05373             en = en->peer;
05374             destroy_exten(el);
05375          }
05376          el = e;
05377          e = e->next;
05378          destroy_exten(el);
05379       }
05380       ast_mutex_destroy(&tmp->lock);
05381       free(tmp);
05382       /* if we have a specific match, we are done, otherwise continue */
05383       tmp = con ? NULL : next;
05384    }
05385 }
05386 
05387 void ast_context_destroy(struct ast_context *con, const char *registrar)
05388 {
05389    ast_wrlock_contexts();
05390    __ast_context_destroy(con,registrar);
05391    ast_unlock_contexts();
05392 }
05393 
05394 static void wait_for_hangup(struct ast_channel *chan, void *data)
05395 {
05396    int res;
05397    struct ast_frame *f;
05398    int waittime;
05399 
05400    if (ast_strlen_zero(data) || (sscanf(data, "%d", &waittime) != 1) || (waittime < 0))
05401       waittime = -1;
05402    if (waittime > -1) {
05403       ast_safe_sleep(chan, waittime * 1000);
05404    } else do {
05405       res = ast_waitfor(chan, -1);
05406       if (res < 0)
05407          return;
05408       f = ast_read(chan);
05409       if (f)
05410          ast_frfree(f);
05411    } while(f);
05412 }
05413 
05414 /*!
05415  * \ingroup applications
05416  */
05417 static int pbx_builtin_progress(struct ast_channel *chan, void *data)
05418 {
05419    ast_indicate(chan, AST_CONTROL_PROGRESS);
05420    return 0;
05421 }
05422 
05423 /*!
05424  * \ingroup applications
05425  */
05426 static int pbx_builtin_ringing(struct ast_channel *chan, void *data)
05427 {
05428    ast_indicate(chan, AST_CONTROL_RINGING);
05429    return 0;
05430 }
05431 
05432 /*!
05433  * \ingroup applications
05434  */
05435 static int pbx_builtin_busy(struct ast_channel *chan, void *data)
05436 {
05437    ast_indicate(chan, AST_CONTROL_BUSY);
05438    /* Don't change state of an UP channel, just indicate
05439       busy 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_congestion(struct ast_channel *chan, void *data)
05450 {
05451    ast_indicate(chan, AST_CONTROL_CONGESTION);
05452    /* Don't change state of an UP channel, just indicate
05453       congestion in audio */
05454    if (chan->_state != AST_STATE_UP)
05455       ast_setstate(chan, AST_STATE_BUSY);
05456    wait_for_hangup(chan, data);
05457    return -1;
05458 }
05459 
05460 /*!
05461  * \ingroup applications
05462  */
05463 static int pbx_builtin_answer(struct ast_channel *chan, void *data)
05464 {
05465    int delay = 0;
05466    int res;
05467 
05468    if (chan->_state == AST_STATE_UP)
05469       delay = 0;
05470    else if (!ast_strlen_zero(data))
05471       delay = atoi(data);
05472 
05473    res = ast_answer(chan);
05474    if (res)
05475       return res;
05476 
05477    if (delay)
05478       res = ast_safe_sleep(chan, delay);
05479 
05480    return res;
05481 }
05482 
05483 AST_APP_OPTIONS(resetcdr_opts, {
05484    AST_APP_OPTION('w', AST_CDR_FLAG_POSTED),
05485    AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED),
05486    AST_APP_OPTION('v', AST_CDR_FLAG_KEEP_VARS),
05487 });
05488 
05489 /*!
05490  * \ingroup applications
05491  */
05492 static int pbx_builtin_resetcdr(struct ast_channel *chan, void *data)
05493 {
05494    char *args;
05495    struct ast_flags flags = { 0 };
05496 
05497    if (!ast_strlen_zero(data)) {
05498       args = ast_strdupa(data);
05499       ast_app_parse_options(resetcdr_opts, &flags, NULL, args);
05500    }
05501 
05502    ast_cdr_reset(chan->cdr, &flags);
05503 
05504    return 0;
05505 }
05506 
05507 /*!
05508  * \ingroup applications
05509  */
05510 static int pbx_builtin_setamaflags(struct ast_channel *chan, void *data)
05511 {
05512    /* Copy the AMA Flags as specified */
05513    ast_cdr_setamaflags(chan, data ? data : "");
05514    return 0;
05515 }
05516 
05517 /*!
05518  * \ingroup applications
05519  */
05520 static int pbx_builtin_hangup(struct ast_channel *chan, void *data)
05521 {
05522    if (!ast_strlen_zero(data)) {
05523       int cause;
05524       char *endptr;
05525 
05526       if ((cause = ast_str2cause(data)) > -1) {
05527          chan->hangupcause = cause;
05528          return -1;
05529       }
05530       
05531       cause = strtol((const char *) data, &endptr, 10);
05532       if (cause != 0 || (data != endptr)) {
05533          chan->hangupcause = cause;
05534          return -1;
05535       }
05536          
05537       ast_log(LOG_NOTICE, "Invalid cause given to Hangup(): \"%s\"\n", (char *) data);
05538    }
05539 
05540    if (!chan->hangupcause) {
05541       chan->hangupcause = AST_CAUSE_NORMAL_CLEARING;
05542    }
05543 
05544    return -1;
05545 }
05546 
05547 /*!
05548  * \ingroup applications
05549  */
05550 static int pbx_builtin_gotoiftime(struct ast_channel *chan, void *data)
05551 {
05552    int res=0;
05553    char *s, *ts;
05554    struct ast_timing timing;
05555 
05556    if (ast_strlen_zero(data)) {
05557       ast_log(LOG_WARNING, "GotoIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority\n");
05558       return -1;
05559    }
05560 
05561    ts = s = ast_strdupa(data);
05562 
05563    /* Separate the Goto path */
05564    strsep(&ts,"?");
05565 
05566    /* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
05567    if (ast_build_timing(&timing, s) && ast_check_timing(&timing))
05568       res = pbx_builtin_goto(chan, ts);
05569    
05570    return res;
05571 }
05572 
05573 /*!
05574  * \ingroup applications
05575  */
05576 static int pbx_builtin_execiftime(struct ast_channel *chan, void *data)
05577 {
05578    char *s, *appname;
05579    struct ast_timing timing;
05580    struct ast_app *app;
05581    static const char *usage = "ExecIfTime requires an argument:\n  <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>]";
05582 
05583    if (ast_strlen_zero(data)) {
05584       ast_log(LOG_WARNING, "%s\n", usage);
05585       return -1;
05586    }
05587 
05588    appname = ast_strdupa(data);
05589 
05590    s = strsep(&appname,"?");  /* Separate the timerange and application name/data */
05591    if (!appname) {   /* missing application */
05592       ast_log(LOG_WARNING, "%s\n", usage);
05593       return -1;
05594    }
05595 
05596    if (!ast_build_timing(&timing, s)) {
05597       ast_log(LOG_WARNING, "Invalid Time Spec: %s\nCorrect usage: %s\n", s, usage);
05598       return -1;
05599    }
05600 
05601    if (!ast_check_timing(&timing))  /* outside the valid time window, just return */
05602       return 0;
05603 
05604    /* now split appname|appargs */
05605    if ((s = strchr(appname, '|')))
05606       *s++ = '\0';
05607 
05608    if ((app = pbx_findapp(appname))) {
05609       return pbx_exec(chan, app, S_OR(s, ""));
05610    } else {
05611       ast_log(LOG_WARNING, "Cannot locate application %s\n", appname);
05612       return -1;
05613    }
05614 }
05615 
05616 /*!
05617  * \ingroup applications
05618  */
05619 static int pbx_builtin_wait(struct ast_channel *chan, void *data)
05620 {
05621    double s;
05622    int ms;
05623 
05624    /* Wait for "n" seconds */
05625    if (data && (s = atof(data)) > 0) {
05626       ms = s * 1000.0;
05627       return ast_safe_sleep(chan, ms);
05628    }
05629    return 0;
05630 }
05631 
05632 /*!
05633  * \ingroup applications
05634  */
05635 static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
05636 {
05637    int ms, res;
05638    double sec;
05639    struct ast_flags flags = {0};
05640    char *opts[1] = { NULL };
05641    char *parse;
05642    AST_DECLARE_APP_ARGS(args,
05643       AST_APP_ARG(timeout);
05644       AST_APP_ARG(options);
05645    );
05646 
05647    if (!ast_strlen_zero(data)) {
05648       parse = ast_strdupa(data);
05649       AST_STANDARD_APP_ARGS(args, parse);
05650    } else
05651       memset(&args, 0, sizeof(args));
05652 
05653    if (args.options)
05654       ast_app_parse_options(waitexten_opts, &flags, opts, args.options);
05655    
05656    if (ast_test_flag(&flags, WAITEXTEN_MOH) && !opts[0] ) {
05657       ast_log(LOG_WARNING, "The 'm' option has been specified for WaitExten without a class.\n"); 
05658    } else if (ast_test_flag(&flags, WAITEXTEN_MOH))
05659       ast_indicate_data(chan, AST_CONTROL_HOLD, opts[0], strlen(opts[0]));
05660 
05661    /* Wait for "n" seconds */
05662    if (args.timeout && (sec = atof(args.timeout)) > 0.0)
05663       ms = 1000 * sec;
05664    else if (chan->pbx)
05665       ms = chan->pbx->rtimeout * 1000;
05666    else
05667       ms = 10000;
05668    res = ast_waitfordigit(chan, ms);
05669    if (!res) {
05670       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
05671          if (option_verbose > 2)
05672             ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, continuing...\n", chan->name);
05673       } else if (chan->_softhangup == AST_SOFTHANGUP_TIMEOUT) {
05674          if (option_verbose > 2)
05675             ast_verbose(VERBOSE_PREFIX_3 "Call timeout on %s, checking for 'T'\n", chan->name);
05676          res = -1;
05677       } else if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
05678          if (option_verbose > 2)
05679             ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s, going to 't'\n", chan->name);
05680          set_ext_pri(chan, "t", 0); /* 0 will become 1, next time through the loop */
05681       } else {
05682          ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
05683          res = -1;
05684       }
05685    }
05686 
05687    if (ast_test_flag(&flags, WAITEXTEN_MOH))
05688       ast_indicate(chan, AST_CONTROL_UNHOLD);
05689 
05690    return res;
05691 }
05692 
05693 /*!
05694  * \ingroup applications
05695  */
05696 static int pbx_builtin_background(struct ast_channel *chan, void *data)
05697 {
05698    int res = 0;
05699    struct ast_flags flags = {0};
05700    char *parse;
05701    AST_DECLARE_APP_ARGS(args,
05702       AST_APP_ARG(filename);
05703       AST_APP_ARG(options);
05704       AST_APP_ARG(lang);
05705       AST_APP_ARG(context);
05706    );
05707 
05708    if (ast_strlen_zero(data)) {
05709       ast_log(LOG_WARNING, "Background requires an argument (filename)\n");
05710       return -1;
05711    }
05712 
05713    parse = ast_strdupa(data);
05714 
05715    AST_STANDARD_APP_ARGS(args, parse);
05716 
05717    if (ast_strlen_zero(args.lang))
05718       args.lang = (char *)chan->language; /* XXX this is const */
05719 
05720    if (ast_strlen_zero(args.context))
05721       args.context = chan->context;
05722 
05723    if (args.options) {
05724       if (!strcasecmp(args.options, "skip"))
05725          flags.flags = BACKGROUND_SKIP;
05726       else if (!strcasecmp(args.options, "noanswer"))
05727          flags.flags = BACKGROUND_NOANSWER;
05728       else
05729          ast_app_parse_options(background_opts, &flags, NULL, args.options);
05730    }
05731 
05732    /* Answer if need be */
05733    if (chan->_state != AST_STATE_UP) {
05734       if (ast_test_flag(&flags, BACKGROUND_SKIP)) {
05735          return 0;
05736       } else if (!ast_test_flag(&flags, BACKGROUND_NOANSWER)) {
05737          res = ast_answer(chan);
05738       }
05739    }
05740 
05741    if (!res) {
05742       char *back = args.filename;
05743       char *front;
05744       ast_stopstream(chan);      /* Stop anything playing */
05745       /* Stream the list of files */
05746       while (!res && (front = strsep(&back, "&")) ) {
05747          if ( (res = ast_streamfile(chan, front, args.lang)) ) {
05748             ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char*)data);
05749             res = 0;
05750             break;
05751          }
05752          if (ast_test_flag(&flags, BACKGROUND_PLAYBACK)) {
05753             res = ast_waitstream(chan, "");
05754          } else if (ast_test_flag(&flags, BACKGROUND_MATCHEXTEN)) {
05755             res = ast_waitstream_exten(chan, args.context);
05756          } else {
05757             res = ast_waitstream(chan, AST_DIGIT_ANY);
05758          }
05759          ast_stopstream(chan);
05760       }
05761    }
05762    if (strcmp(args.context, chan->context) && res) {
05763       snprintf(chan->exten, sizeof(chan->exten), "%c", res);
05764       ast_copy_string(chan->context, args.context, sizeof(chan->context));
05765       chan->priority = 0;
05766       res = 0;
05767    }
05768    return res;
05769 }
05770 
05771 /*! Goto
05772  * \ingroup applications
05773  */
05774 static int pbx_builtin_goto(struct ast_channel *chan, void *data)
05775 {
05776    int res = ast_parseable_goto(chan, data);
05777    if (!res && (option_verbose > 2))
05778       ast_verbose( VERBOSE_PREFIX_3 "Goto (%s,%s,%d)\n", chan->context,chan->exten, chan->priority+1);
05779    return res;
05780 }
05781 
05782 
05783 int pbx_builtin_serialize_variables(struct ast_channel *chan, char *buf, size_t size)
05784 {
05785    struct ast_var_t *variables;
05786    const char *var, *val;
05787    int total = 0;
05788 
05789    if (!chan)
05790       return 0;
05791 
05792    memset(buf, 0, size);
05793 
05794    ast_channel_lock(chan);
05795 
05796    AST_LIST_TRAVERSE(&chan->varshead, variables, entries) {
05797       if ((var=ast_var_name(variables)) && (val=ast_var_value(variables))
05798          /* && !ast_strlen_zero(var) && !ast_strlen_zero(val) */
05799          ) {
05800          if (ast_build_string(&buf, &size, "%s=%s\n", var, val)) {
05801             ast_log(LOG_ERROR, "Data Buffer Size Exceeded!\n");
05802             break;
05803          } else
05804             total++;
05805       } else
05806          break;
05807    }
05808 
05809    ast_channel_unlock(chan);
05810 
05811    return total;
05812 }
05813 
05814 const char *pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
05815 {
05816    struct ast_var_t *variables;
05817    const char *ret = NULL;
05818    int i;
05819    struct varshead *places[2] = { NULL, &globals };
05820 
05821    if (!name)
05822       return NULL;
05823 
05824    if (chan) {
05825       ast_channel_lock(chan);
05826       places[0] = &chan->varshead;
05827    }
05828 
05829    for (i = 0; i < 2; i++) {
05830       if (!places[i])
05831          continue;
05832       if (places[i] == &globals)
05833          ast_mutex_lock(&globalslock);
05834       AST_LIST_TRAVERSE(places[i], variables, entries) {
05835          if (!strcmp(name, ast_var_name(variables))) {
05836             ret = ast_var_value(variables);
05837             break;
05838          }
05839       }
05840       if (places[i] == &globals)
05841          ast_mutex_unlock(&globalslock);
05842       if (ret)
05843          break;
05844    }
05845 
05846    if (chan)
05847       ast_channel_unlock(chan);
05848 
05849    return ret;
05850 }
05851 
05852 void pbx_builtin_pushvar_helper(struct ast_channel *chan, const char *name, const char *value)
05853 {
05854    struct ast_var_t *newvariable;
05855    struct varshead *headp;
05856 
05857    if (name[strlen(name)-1] == ')') {
05858       char *function = ast_strdupa(name);
05859 
05860       ast_log(LOG_WARNING, "Cannot push a value onto a function\n");
05861       ast_func_write(chan, function, value);
05862       return;
05863    }
05864 
05865    if (chan) {
05866       ast_channel_lock(chan);
05867       headp = &chan->varshead;
05868    } else {
05869       ast_mutex_lock(&globalslock);
05870       headp = &globals;
05871    }
05872 
05873    if (value) {
05874       if ((option_verbose > 1) && (headp == &globals))
05875          ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
05876       newvariable = ast_var_assign(name, value);
05877       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
05878    }
05879 
05880    if (chan)
05881       ast_channel_unlock(chan);
05882    else
05883       ast_mutex_unlock(&globalslock);
05884 }
05885 
05886 void pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
05887 {
05888    struct ast_var_t *newvariable;
05889    struct varshead *headp;
05890    const char *nametail = name;
05891 
05892    if (name[strlen(name)-1] == ')') {
05893       char *function = ast_strdupa(name);
05894 
05895       ast_func_write(chan, function, value);
05896       return;
05897    }
05898 
05899    if (chan) {
05900       ast_channel_lock(chan);
05901       headp = &chan->varshead;
05902    } else {
05903       ast_mutex_lock(&globalslock);
05904       headp = &globals;
05905    }
05906 
05907    /* For comparison purposes, we have to strip leading underscores */
05908    if (*nametail == '_') {
05909       nametail++;
05910       if (*nametail == '_')
05911          nametail++;
05912    }
05913 
05914    AST_LIST_TRAVERSE (headp, newvariable, entries) {
05915       if (strcasecmp(ast_var_name(newvariable), nametail) == 0) {
05916          /* there is already such a variable, delete it */
05917          AST_LIST_REMOVE(headp, newvariable, entries);
05918          ast_var_delete(newvariable);
05919          break;
05920       }
05921    }
05922 
05923    if (value) {
05924       if ((option_verbose > 1) && (headp == &globals))
05925          ast_verbose(VERBOSE_PREFIX_2 "Setting global variable '%s' to '%s'\n", name, value);
05926       newvariable = ast_var_assign(name, value);
05927       AST_LIST_INSERT_HEAD(headp, newvariable, entries);
05928    }
05929 
05930    if (chan)
05931       ast_channel_unlock(chan);
05932    else
05933       ast_mutex_unlock(&globalslock);
05934 }
05935 
05936 int pbx_builtin_setvar(struct ast_channel *chan, void *data)
05937 {
05938    char *name, *value, *mydata;
05939    int argc;
05940    char *argv[24];      /* this will only support a maximum of 24 variables being set in a single operation */
05941    int global = 0;
05942    int x;
05943 
05944    if (ast_strlen_zero(data)) {
05945       ast_log(LOG_WARNING, "Set requires at least one variable name/value pair.\n");
05946       return 0;
05947    }
05948 
05949    mydata = ast_strdupa(data);
05950    argc = ast_app_separate_args(mydata, '|', argv, sizeof(argv) / sizeof(argv[0]));
05951 
05952    /* check for a trailing flags argument */
05953    if ((argc > 1) && !strchr(argv[argc-1], '=')) {
05954       argc--;
05955       if (strchr(argv[argc], 'g')) {
05956          ast_log(LOG_WARNING, "The use of the 'g' flag is deprecated.  Please use Set(GLOBAL(foo)=bar) instead\n");
05957          global = 1;
05958       }
05959    }
05960 
05961    if (argc > 1)
05962       ast_log(LOG_WARNING, "Setting multiple variables at once within Set is deprecated.  Please separate each name/value pair into its own line.\n");
05963 
05964    for (x = 0; x < argc; x++) {
05965       name = argv[x];
05966       if ((value = strchr(name, '='))) {
05967          *value++ = '\0';
05968          pbx_builtin_setvar_helper((global) ? NULL : chan, name, value);
05969       } else
05970          ast_log(LOG_WARNING, "Ignoring entry '%s' with no = (and not last 'options' entry)\n", name);
05971    }
05972 
05973    return(0);
05974 }
05975 
05976 int pbx_builtin_importvar(struct ast_channel *chan, void *data)
05977 {
05978    char *name;
05979    char *value;
05980    char *channel;
05981    char tmp[VAR_BUF_SIZE]="";
05982 
05983    if (ast_strlen_zero(data)) {
05984       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
05985       return 0;
05986    }
05987 
05988    value = ast_strdupa(data);
05989    name = strsep(&value,"=");
05990    channel = strsep(&value,"|");
05991    if (channel && value && name) { /*! \todo XXX should do !ast_strlen_zero(..) of the args ? */
05992       struct ast_channel *chan2 = ast_get_channel_by_name_locked(channel);
05993       if (chan2) {
05994          char *s = alloca(strlen(value) + 4);
05995          if (s) {
05996             sprintf(s, "${%s}", value);
05997             pbx_substitute_variables_helper(chan2, s, tmp, sizeof(tmp) - 1);
05998          }
05999          ast_channel_unlock(chan2);
06000       }
06001       pbx_builtin_setvar_helper(chan, name, tmp);
06002    }
06003 
06004    return(0);
06005 }
06006 
06007 /*! \todo XXX overwrites data ? */
06008 static int pbx_builtin_setglobalvar(struct ast_channel *chan, void *data)
06009 {
06010    char *name;
06011    char *stringp = data;
06012    static int dep_warning = 0;
06013 
06014    if (ast_strlen_zero(data)) {
06015       ast_log(LOG_WARNING, "Ignoring, since there is no variable to set\n");
06016       return 0;
06017    }
06018 
06019    name = strsep(&stringp, "=");
06020 
06021    if (!dep_warning) {
06022       dep_warning = 1;
06023       ast_log(LOG_WARNING, "SetGlobalVar is deprecated.  Please use Set(GLOBAL(%s)=%s) instead.\n", name, stringp);
06024    }
06025 
06026    /*! \todo XXX watch out, leading whitespace ? */
06027    pbx_builtin_setvar_helper(NULL, name, stringp);
06028 
06029    return(0);
06030 }
06031 
06032 static int pbx_builtin_noop(struct ast_channel *chan, void *data)
06033 {
06034    return 0;
06035 }
06036 
06037 void pbx_builtin_clear_globals(void)
06038 {
06039    struct ast_var_t *vardata;
06040 
06041    ast_mutex_lock(&globalslock);
06042    while ((vardata = AST_LIST_REMOVE_HEAD(&globals, entries)))
06043       ast_var_delete(vardata);
06044    ast_mutex_unlock(&globalslock);
06045 }
06046 
06047 int pbx_checkcondition(const char *condition)
06048 {
06049    if (ast_strlen_zero(condition))  /* NULL or empty strings are false */
06050       return 0;
06051    else if (*condition >= '0' && *condition <= '9')   /* Numbers are evaluated for truth */
06052       return atoi(condition);
06053    else  /* Strings are true */
06054       return 1;
06055 }
06056 
06057 static int pbx_builtin_gotoif(struct ast_channel *chan, void *data)
06058 {
06059    char *condition, *branch1, *branch2, *branch;
06060    int rc;
06061    char *stringp;
06062 
06063    if (ast_strlen_zero(data)) {
06064       ast_log(LOG_WARNING, "Ignoring, since there is no variable to check\n");
06065       return 0;
06066    }
06067 
06068    stringp = ast_strdupa(data);
06069    condition = strsep(&stringp,"?");
06070    branch1 = strsep(&stringp,":");
06071    branch2 = strsep(&stringp,"");
06072    branch = pbx_checkcondition(condition) ? branch1 : branch2;
06073 
06074    if (ast_strlen_zero(branch)) {
06075       if (option_debug)
06076          ast_log(LOG_DEBUG, "Not taking any branch\n");
06077       return 0;
06078    }
06079 
06080    rc = pbx_builtin_goto(chan, branch);
06081 
06082    return rc;
06083 }
06084 
06085 static int pbx_builtin_saynumber(struct ast_channel *chan, void *data)
06086 {
06087    char tmp[256];
06088    char *number = tmp;
06089    char *options;
06090 
06091    if (ast_strlen_zero(data)) {
06092       ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n");
06093       return -1;
06094    }
06095    ast_copy_string(tmp, data, sizeof(tmp));
06096    strsep(&number, "|");
06097    options = strsep(&number, "|");
06098    if (options) {
06099       if ( strcasecmp(options, "f") && strcasecmp(options,"m") &&
06100          strcasecmp(options, "c") && strcasecmp(options, "n") ) {
06101          ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n");
06102          return -1;
06103       }
06104    }
06105 
06106    if (ast_say_number(chan, atoi(tmp), "", chan->language, options)) {
06107       ast_log(LOG_WARNING, "We were unable to say the number %s, is it too large?\n", tmp);
06108    }
06109 
06110    return 0;
06111 }
06112 
06113 static int pbx_builtin_saydigits(struct ast_channel *chan, void *data)
06114 {
06115    int res = 0;
06116 
06117    if (data)
06118       res = ast_say_digit_str(chan, data, "", chan->language);
06119    return res;
06120 }
06121 
06122 static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
06123 {
06124    int res = 0;
06125 
06126    if (data)
06127       res = ast_say_character_str(chan, data, "", chan->language);
06128    return res;
06129 }
06130 
06131 static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
06132 {
06133    int res = 0;
06134 
06135    if (data)
06136       res = ast_say_phonetic_str(chan, data, "", chan->language);
06137    return res;
06138 }
06139 
06140 static int pbx_builtin_saydate(struct ast_channel *chan, void *data)
06141 {
06142    int res = 0;
06143    char *parse;
06144    int unixdate = 0;
06145    char charascii[2];
06146 
06147    AST_DECLARE_APP_ARGS(args,
06148       AST_APP_ARG(datestr);
06149       AST_APP_ARG(digits);
06150    );
06151 
06152 
06153    if (ast_strlen_zero(data)) {
06154       ast_log(LOG_WARNING, "SayDate requires an argument (date)\n");
06155       return -1;
06156    }
06157 
06158    if (!(parse = ast_strdupa(data))) {
06159       ast_log(LOG_WARNING, "Memory Error!\n");
06160       return -1;
06161    }
06162 
06163    AST_STANDARD_APP_ARGS(args, parse);
06164 
06165    if (!ast_strlen_zero(args.digits) && (strspn(args.digits, "0123456789*#") != strlen(args.digits))) {
06166       ast_log(LOG_WARNING, "SayDate escape digits must be a subset from '0123456789*#'\n");
06167       args.digits = "";
06168    }
06169 
06170    if (sscanf(args.datestr, "%d", &unixdate) != 1) {
06171       ast_log(LOG_WARNING, "Firt argument to SayDate must be numeric (date)\n");
06172       return -1;
06173    }
06174 
06175    res = ast_say_date(chan, (time_t)unixdate, args.digits, chan->language);
06176    if (res > 0) {
06177       if (isdigit(res) || (res == '*') || (res == '#')) {
06178          snprintf(charascii, 2, "%c", res);
06179          pbx_builtin_setvar_helper(chan, "USER_INPUT", charascii);
06180          res = 0;
06181       } else {
06182          ast_log(LOG_WARNING, "SayDate: invalid return value (%d) detected\n", res);
06183       }
06184    }
06185    return res;
06186 }
06187 
06188 static int pbx_builtin_saytime(struct ast_channel *chan, void *data)
06189 {
06190    int res = 0;
06191    char *parse;
06192    int secs = 0;
06193    char charascii[2];
06194 
06195    AST_DECLARE_APP_ARGS(args,
06196       AST_APP_ARG(timestr);
06197       AST_APP_ARG(digits);
06198    );
06199 
06200    if (ast_strlen_zero(data)) {
06201       ast_log(LOG_WARNING, "SayTime requires an argument (time in seconds)\n");
06202       return -1;
06203    }
06204 
06205    if (!(parse = ast_strdupa(data))) {
06206       ast_log(LOG_WARNING, "Memory Error!\n");
06207       return -1;
06208    }
06209 
06210    AST_STANDARD_APP_ARGS(args, parse);
06211 
06212    if (!ast_strlen_zero(args.digits) && (strspn(args.digits, "0123456789*#") != strlen(args.digits))) {
06213       ast_log(LOG_WARNING, "SayTime escape digits must be a subset from '0123456789*#'\n");
06214       args.digits = "";
06215    }
06216 
06217    if (sscanf(args.timestr, "%d", &secs) != 1) {
06218       ast_log(LOG_WARNING, "Firt argument to SayTime must be numeric (time in seconds)\n");
06219       return -1;
06220    }
06221 
06222    res = ast_say_time(chan, (time_t)secs, args.digits, chan->language);
06223    if (res > 0) {
06224       if (isdigit(res) || (res == '*') || (res == '#')) {
06225          snprintf(charascii, 2, "%c", res);
06226          pbx_builtin_setvar_helper(chan, "USER_INPUT", charascii);
06227          res = 0;
06228       } else {
06229          ast_log(LOG_WARNING, "SayTime: invalid return value (%d) detected\n", res);
06230       }
06231    }
06232    return res;
06233 }
06234 
06235 int load_pbx(void)
06236 {
06237    int x;
06238 
06239    /* Initialize the PBX */
06240    if (option_verbose) {
06241       ast_verbose( "Asterisk PBX Core Initializing\n");
06242       ast_verbose( "Registering builtin applications:\n");
06243    }
06244    ast_cli_register_multiple(pbx_cli, sizeof(pbx_cli) / sizeof(struct ast_cli_entry));
06245 
06246    /* Register builtin applications */
06247    for (x=0; x<sizeof(builtins) / sizeof(struct pbx_builtin); x++) {
06248       if (option_verbose)
06249          ast_verbose( VERBOSE_PREFIX_1 "[%s]\n", builtins[x].name);
06250       if (ast_register_application(builtins[x].name, builtins[x].execute, builtins[x].synopsis, builtins[x].description)) {
06251          ast_log(LOG_ERROR, "Unable to register builtin application '%s'\n", builtins[x].name);
06252          return -1;
06253       }
06254    }
06255    return 0;
06256 }
06257 
06258 /*
06259  * Lock context list functions ...
06260  */
06261 int ast_lock_contexts()
06262 {
06263    return ast_rwlock_wrlock(&conlock);
06264 }
06265 
06266 int ast_rdlock_contexts(void)
06267 {
06268    return ast_rwlock_rdlock(&conlock);
06269 }
06270 
06271 int ast_wrlock_contexts(void)
06272 {
06273    return ast_rwlock_wrlock(&conlock);
06274 }
06275 
06276 int ast_unlock_contexts()
06277 {
06278    return ast_rwlock_unlock(&conlock);
06279 }
06280 
06281 /*
06282  * Lock context ...
06283  */
06284 int ast_lock_context(struct ast_context *con)
06285 {
06286    return ast_mutex_lock(&con->lock);
06287 }
06288 
06289 int ast_unlock_context(struct ast_context *con)
06290 {
06291    return ast_mutex_unlock(&con->lock);
06292 }
06293 
06294 /*
06295  * Name functions ...
06296  */
06297 const char *ast_get_context_name(struct ast_context *con)
06298 {
06299    return con ? con->name : NULL;
06300 }
06301 
06302 struct ast_context *ast_get_extension_context(struct ast_exten *exten)
06303 {
06304    return exten ? exten->parent : NULL;
06305 }
06306 
06307 const char *ast_get_extension_name(struct ast_exten *exten)
06308 {
06309    return exten ? exten->exten : NULL;
06310 }
06311 
06312 const char *ast_get_extension_label(struct ast_exten *exten)
06313 {
06314    return exten ? exten->label : NULL;
06315 }
06316 
06317 const char *ast_get_include_name(struct ast_include *inc)
06318 {
06319    return inc ? inc->name : NULL;
06320 }
06321 
06322 const char *ast_get_ignorepat_name(struct ast_ignorepat *ip)
06323 {
06324    return ip ? ip->pattern : NULL;
06325 }
06326 
06327 int ast_get_extension_priority(struct ast_exten *exten)
06328 {
06329    return exten ? exten->priority : -1;
06330 }
06331 
06332 /*
06333  * Registrar info functions ...
06334  */
06335 const char *ast_get_context_registrar(struct ast_context *c)
06336 {
06337    return c ? c->registrar : NULL;
06338 }
06339 
06340 const char *ast_get_extension_registrar(struct ast_exten *e)
06341 {
06342    return e ? e->registrar : NULL;
06343 }
06344 
06345 const char *ast_get_include_registrar(struct ast_include *i)
06346 {
06347    return i ? i->registrar : NULL;
06348 }
06349 
06350 const char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip)
06351 {
06352    return ip ? ip->registrar : NULL;
06353 }
06354 
06355 int ast_get_extension_matchcid(struct ast_exten *e)
06356 {
06357    return e ? e->matchcid : 0;
06358 }
06359 
06360 const char *ast_get_extension_cidmatch(struct ast_exten *e)
06361 {
06362    return e ? e->cidmatch : NULL;
06363 }
06364 
06365 const char *ast_get_extension_app(struct ast_exten *e)
06366 {
06367    return e ? e->app : NULL;
06368 }
06369 
06370 void *ast_get_extension_app_data(struct ast_exten *e)
06371 {
06372    return e ? e->data : NULL;
06373 }
06374 
06375 const char *ast_get_switch_name(struct ast_sw *sw)
06376 {
06377    return sw ? sw->name : NULL;
06378 }
06379 
06380 const char *ast_get_switch_data(struct ast_sw *sw)
06381 {
06382    return sw ? sw->data : NULL;
06383 }
06384 
06385 const char *ast_get_switch_registrar(struct ast_sw *sw)
06386 {
06387    return sw ? sw->registrar : NULL;
06388 }
06389 
06390 /*
06391  * Walking functions ...
06392  */
06393 struct ast_context *ast_walk_contexts(struct ast_context *con)
06394 {
06395    return con ? con->next : contexts;
06396 }
06397 
06398 struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
06399    struct ast_exten *exten)
06400 {
06401    if (!exten)
06402       return con ? con->root : NULL;
06403    else
06404       return exten->next;
06405 }
06406 
06407 struct ast_sw *ast_walk_context_switches(struct ast_context *con,
06408    struct ast_sw *sw)
06409 {
06410    if (!sw)
06411       return con ? AST_LIST_FIRST(&con->alts) : NULL;
06412    else
06413       return AST_LIST_NEXT(sw, list);
06414 }
06415 
06416 struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
06417    struct ast_exten *priority)
06418 {
06419    return priority ? priority->peer : exten;
06420 }
06421 
06422 struct ast_include *ast_walk_context_includes(struct ast_context *con,
06423    struct ast_include *inc)
06424 {
06425    if (!inc)
06426       return con ? con->includes : NULL;
06427    else
06428       return inc->next;
06429 }
06430 
06431 struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
06432    struct ast_ignorepat *ip)
06433 {
06434    if (!ip)
06435       return con ? con->ignorepats : NULL;
06436    else
06437       return ip->next;
06438 }
06439 
06440 int ast_context_verify_includes(struct ast_context *con)
06441 {
06442    struct ast_include *inc = NULL;
06443    int res = 0;
06444 
06445    while ( (inc = ast_walk_context_includes(con, inc)) ) {
06446       if (ast_context_find(inc->rname))
06447          continue;
06448 
06449       res = -1;
06450       ast_log(LOG_WARNING, "Context '%s' tries to include nonexistent context '%s'\n",
06451          ast_get_context_name(con), inc->rname);
06452       break;
06453    }
06454 
06455    return res;
06456 }
06457 
06458 
06459 static int __ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, int async)
06460 {
06461    int (*goto_func)(struct ast_channel *chan, const char *context, const char *exten, int priority);
06462 
06463    if (!chan)
06464       return -2;
06465 
06466    if (context == NULL)
06467       context = chan->context;
06468    if (exten == NULL)
06469       exten = chan->exten;
06470 
06471    goto_func = (async) ? ast_async_goto : ast_explicit_goto;
06472    if (ast_exists_extension(chan, context, exten, priority, chan->cid.cid_num))
06473       return goto_func(chan, context, exten, priority);
06474    else
06475       return -3;
06476 }
06477 
06478 int ast_goto_if_exists(struct ast_channel *chan, const char* context, const char *exten, int priority)
06479 {
06480    return __ast_goto_if_exists(chan, context, exten, priority, 0);
06481 }
06482 
06483 int ast_async_goto_if_exists(struct ast_channel *chan, const char * context, const char *exten, int priority)
06484 {
06485    return __ast_goto_if_exists(chan, context, exten, priority, 1);
06486 }
06487 
06488 int ast_parseable_goto(struct ast_channel *chan, const char *goto_string)
06489 {
06490    char *exten, *pri, *context;
06491    char *stringp;
06492    int ipri;
06493    int mode = 0;
06494 
06495    if (ast_strlen_zero(goto_string)) {
06496       ast_log(LOG_WARNING, "Goto requires an argument (optional context|optional extension|priority)\n");
06497       return -1;
06498    }
06499    stringp = ast_strdupa(goto_string);
06500    context = strsep(&stringp, "|"); /* guaranteed non-null */
06501    exten = strsep(&stringp, "|");
06502    pri = strsep(&stringp, "|");
06503    if (!exten) {  /* Only a priority in this one */
06504       pri = context;
06505       exten = NULL;
06506       context = NULL;
06507    } else if (!pri) {   /* Only an extension and priority in this one */
06508       pri = exten;
06509       exten = context;
06510       context = NULL;
06511    }
06512    if (*pri == '+') {
06513       mode = 1;
06514       pri++;
06515    } else if (*pri == '-') {
06516       mode = -1;
06517       pri++;
06518    }
06519    if (sscanf(pri, "%d", &ipri) != 1) {
06520       if ((ipri = ast_findlabel_extension(chan, context ? context : chan->context, exten ? exten : chan->exten,
06521          pri, chan->cid.cid_num)) < 1) {
06522          ast_log(LOG_WARNING, "Priority '%s' must be a number > 0, or valid label\n", pri);
06523          return -1;
06524       } else
06525          mode = 0;
06526    }
06527    /* At this point we have a priority and maybe an extension and a context */
06528 
06529    if (mode)
06530       ipri = chan->priority + (ipri * mode);
06531 
06532    ast_explicit_goto(chan, context, exten, ipri);
06533    return 0;
06534 
06535 }

Generated on Thu May 14 14:49:06 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7