Mon Mar 20 08:25:43 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

pbx.c

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

Generated on Mon Mar 20 08:25:43 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1