Sat Nov 25 00:45:40 2006

Asterisk developer's documentation


pbx.c

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

Generated on Sat Nov 25 00:45:40 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6