Sat Aug 6 00:39:30 2011

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

Generated on Sat Aug 6 00:39:30 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7