2004-08-03 06:31:20 +00:00
/*
1999-12-04 20:45:45 +00:00
* Asterisk - - A telephony toolkit for Linux .
*
* Core PBX routines .
*
2004-10-02 00:58:31 +00:00
* Copyright ( C ) 1999 - 2004 , Digium , Inc .
1999-12-04 20:45:45 +00:00
*
2004-07-17 02:25:53 +00:00
* Mark Spencer < markster @ digium . com >
1999-12-04 20:45:45 +00:00
*
* This program is free software , distributed under the terms of
* the GNU General Public License
*/
2002-06-21 01:40:13 +00:00
# include <asterisk/lock.h>
2001-04-27 15:07:56 +00:00
# include <asterisk/cli.h>
1999-12-04 20:45:45 +00:00
# include <asterisk/pbx.h>
# include <asterisk/channel.h>
# include <asterisk/options.h>
# include <asterisk/logger.h>
# include <asterisk/file.h>
2001-09-28 21:20:52 +00:00
# include <asterisk/callerid.h>
2001-11-24 15:15:01 +00:00
# include <asterisk/cdr.h>
2003-09-08 21:52:45 +00:00
# include <asterisk/config.h>
2002-06-21 01:40:13 +00:00
# include <asterisk/term.h>
2002-09-11 17:09:48 +00:00
# include <asterisk/manager.h>
# include <asterisk/ast_expr.h>
# include <asterisk/channel_pvt.h>
# include <asterisk/linkedlists.h>
2003-04-16 13:43:11 +00:00
# include <asterisk/say.h>
2004-05-04 06:34:34 +00:00
# include <asterisk/utils.h>
2004-10-15 17:51:37 +00:00
# include <asterisk/causes.h>
1999-12-04 20:45:45 +00:00
# include <string.h>
# include <unistd.h>
# include <stdlib.h>
# include <stdio.h>
# include <setjmp.h>
# include <ctype.h>
2001-09-28 21:20:52 +00:00
# include <errno.h>
2003-03-07 06:00:13 +00:00
# include <time.h>
# include <sys/time.h>
1999-12-18 07:01:48 +00:00
# include "asterisk.h"
1999-12-04 20:45:45 +00:00
/*
* I M P O R T A N T :
*
* The speed of extension handling will likely be among the most important
* aspects of this PBX . The switching scheme as it exists right now isn ' t
* terribly bad ( it ' s O ( N + M ) , where N is the # of extensions and M is the avg #
* of priorities , but a constant search time here would be great ; - )
*
*/
2004-06-12 14:34:15 +00:00
# ifdef LOW_MEMORY
# define EXT_DATA_SIZE 256
# else
# define EXT_DATA_SIZE 8192
# endif
1999-12-04 20:45:45 +00:00
2004-11-01 02:23:28 +00:00
# define VAR_NORMAL 1
# define VAR_SOFTTRAN 2
# define VAR_HARDTRAN 3
1999-12-04 20:45:45 +00:00
struct ast_context ;
2004-07-17 02:25:53 +00:00
/* ast_exten: An extension */
1999-12-04 20:45:45 +00:00
struct ast_exten {
2004-12-18 22:04:07 +00:00
char * exten ; /* Extension name */
int matchcid ; /* Match caller id ? */
char * cidmatch ; /* Caller id to match for this extension */
int priority ; /* Priority */
char * label ; /* Label */
struct ast_context * parent ; /* The context this extension belongs to */
char * app ; /* Application to execute */
void * data ; /* Data to use (arguments) */
void ( * datad ) ( void * ) ; /* Data destructor */
struct ast_exten * peer ; /* Next higher priority with our extension */
const char * registrar ; /* Registrar */
struct ast_exten * next ; /* Extension with a greater ID */
2004-10-03 04:19:59 +00:00
char stuff [ 0 ] ;
1999-12-04 20:45:45 +00:00
} ;
2004-07-17 02:25:53 +00:00
/* ast_include: include= support in extensions.conf */
2001-03-30 18:47:35 +00:00
struct ast_include {
2004-10-03 04:19:59 +00:00
char * name ;
char * rname ; /* Context to include */
const char * registrar ; /* Registrar */
2004-07-17 02:25:53 +00:00
int hastime ; /* If time construct exists */
2004-11-11 21:23:45 +00:00
struct ast_timing timing ; /* time construct */
2004-07-17 02:25:53 +00:00
struct ast_include * next ; /* Link them together */
2004-10-03 04:19:59 +00:00
char stuff [ 0 ] ;
2001-03-30 18:47:35 +00:00
} ;
2004-07-17 02:25:53 +00:00
/* ast_sw: Switch statement in extensions.conf */
2001-09-28 21:20:52 +00:00
struct ast_sw {
2004-10-03 04:19:59 +00:00
char * name ;
const char * registrar ; /* Registrar */
char * data ; /* Data load */
2004-07-17 02:25:53 +00:00
struct ast_sw * next ; /* Link them together */
2004-10-03 04:19:59 +00:00
char stuff [ 0 ] ;
2001-09-28 21:20:52 +00:00
} ;
struct ast_ignorepat {
2004-10-03 04:19:59 +00:00
const char * registrar ;
2001-09-28 21:20:52 +00:00
struct ast_ignorepat * next ;
2004-10-03 04:19:59 +00:00
char pattern [ 0 ] ;
2001-09-28 21:20:52 +00:00
} ;
2004-07-17 02:25:53 +00:00
/* ast_context: An extension context */
1999-12-04 20:45:45 +00:00
struct ast_context {
2004-07-17 02:25:53 +00:00
ast_mutex_t lock ; /* A lock to prevent multiple threads from clobbering the context */
struct ast_exten * root ; /* The root of the list of extensions */
struct ast_context * next ; /* Link them together */
struct ast_include * includes ; /* Include other contexts */
struct ast_ignorepat * ignorepats ; /* Patterns for which to continue playing dialtone */
2004-10-03 04:19:59 +00:00
const char * registrar ; /* Registrar */
2004-07-17 02:25:53 +00:00
struct ast_sw * alts ; /* Alternative switches */
2004-10-03 04:19:59 +00:00
char name [ 0 ] ; /* Name of the context */
1999-12-04 20:45:45 +00:00
} ;
2004-07-17 02:25:53 +00:00
/* ast_app: An application */
1999-12-04 20:45:45 +00:00
struct ast_app {
int ( * execute ) ( struct ast_channel * chan , void * data ) ;
2004-10-03 04:19:59 +00:00
const char * synopsis ; /* Synopsis text for 'show applications' */
const char * description ; /* Description (help text) for 'show application <name>' */
2004-07-17 02:25:53 +00:00
struct ast_app * next ; /* Next app in list */
2004-10-03 04:19:59 +00:00
char name [ 0 ] ; /* Name of the application */
1999-12-04 20:45:45 +00:00
} ;
2004-07-17 02:25:53 +00:00
/* ast_state_cb: An extension state notify */
2003-04-06 18:19:51 +00:00
struct ast_state_cb {
2003-03-30 22:55:42 +00:00
int id ;
void * data ;
2003-04-06 18:19:51 +00:00
ast_state_cb_type callback ;
struct ast_state_cb * next ;
2003-03-30 22:55:42 +00:00
} ;
2004-11-13 22:44:33 +00:00
/* ast_state_cb: An extension state notify */
struct ast_devstate_cb {
void * data ;
ast_devstate_cb_type callback ;
struct ast_devstate_cb * next ;
} ;
static struct ast_devstate_cb * devcbs ;
2003-04-06 18:19:51 +00:00
struct ast_hint {
2003-03-30 22:55:42 +00:00
struct ast_exten * exten ;
int laststate ;
2003-04-06 18:19:51 +00:00
struct ast_state_cb * callbacks ;
struct ast_hint * next ;
2003-03-30 22:55:42 +00:00
} ;
2004-10-15 17:51:37 +00:00
int ast_pbx_outgoing_cdr_failed ( void ) ;
2003-09-14 00:32:51 +00:00
2000-01-07 10:54:40 +00:00
static int pbx_builtin_prefix ( struct ast_channel * , void * ) ;
2003-04-28 04:18:47 +00:00
static int pbx_builtin_suffix ( struct ast_channel * , void * ) ;
2000-01-07 10:54:40 +00:00
static int pbx_builtin_stripmsd ( struct ast_channel * , void * ) ;
1999-12-04 20:45:45 +00:00
static int pbx_builtin_answer ( struct ast_channel * , void * ) ;
static int pbx_builtin_goto ( struct ast_channel * , void * ) ;
static int pbx_builtin_hangup ( struct ast_channel * , void * ) ;
static int pbx_builtin_background ( struct ast_channel * , void * ) ;
static int pbx_builtin_dtimeout ( struct ast_channel * , void * ) ;
static int pbx_builtin_rtimeout ( struct ast_channel * , void * ) ;
2001-11-24 15:15:01 +00:00
static int pbx_builtin_atimeout ( struct ast_channel * , void * ) ;
1999-12-04 20:45:45 +00:00
static int pbx_builtin_wait ( struct ast_channel * , void * ) ;
2004-04-06 04:14:19 +00:00
static int pbx_builtin_waitexten ( struct ast_channel * , void * ) ;
2000-01-24 07:14:18 +00:00
static int pbx_builtin_setlanguage ( struct ast_channel * , void * ) ;
2003-09-08 21:52:45 +00:00
static int pbx_builtin_resetcdr ( struct ast_channel * , void * ) ;
2003-04-27 19:35:06 +00:00
static int pbx_builtin_setaccount ( struct ast_channel * , void * ) ;
2004-06-28 03:48:53 +00:00
static int pbx_builtin_setamaflags ( struct ast_channel * , void * ) ;
2001-04-27 15:07:56 +00:00
static int pbx_builtin_ringing ( struct ast_channel * , void * ) ;
2004-06-22 03:51:34 +00:00
static int pbx_builtin_progress ( struct ast_channel * , void * ) ;
2001-04-27 15:07:56 +00:00
static int pbx_builtin_congestion ( struct ast_channel * , void * ) ;
static int pbx_builtin_busy ( struct ast_channel * , void * ) ;
2003-02-13 06:00:14 +00:00
static int pbx_builtin_setglobalvar ( struct ast_channel * , void * ) ;
2003-02-12 13:59:15 +00:00
static int pbx_builtin_noop ( struct ast_channel * , void * ) ;
2002-09-11 17:09:48 +00:00
static int pbx_builtin_gotoif ( struct ast_channel * , void * ) ;
2003-04-28 04:18:47 +00:00
static int pbx_builtin_gotoiftime ( struct ast_channel * , void * ) ;
2003-04-16 13:43:11 +00:00
static int pbx_builtin_saynumber ( struct ast_channel * , void * ) ;
static int pbx_builtin_saydigits ( struct ast_channel * , void * ) ;
2004-05-03 00:54:16 +00:00
static int pbx_builtin_saycharacters ( struct ast_channel * , void * ) ;
static int pbx_builtin_sayphonetic ( struct ast_channel * , void * ) ;
2003-09-22 15:27:09 +00:00
int pbx_builtin_setvar ( struct ast_channel * , void * ) ;
2004-11-17 04:48:58 +00:00
static int pbx_builtin_importvar ( struct ast_channel * , void * ) ;
2002-09-11 17:09:48 +00:00
void pbx_builtin_setvar_helper ( struct ast_channel * chan , char * name , char * value ) ;
2003-02-02 19:04:14 +00:00
char * pbx_builtin_getvar_helper ( struct ast_channel * chan , char * name ) ;
2002-09-11 17:09:48 +00:00
2004-06-09 01:45:08 +00:00
static struct varshead globals ;
1999-12-04 20:45:45 +00:00
2004-10-16 19:46:02 +00:00
static int autofallthrough = 0 ;
1999-12-04 20:45:45 +00:00
static struct pbx_builtin {
char name [ AST_MAX_APP ] ;
int ( * execute ) ( struct ast_channel * chan , void * data ) ;
2001-04-27 15:07:56 +00:00
char * synopsis ;
char * description ;
1999-12-04 20:45:45 +00:00
} builtins [ ] =
{
/* These applications are built into the PBX core and do not
2003-04-27 19:35:06 +00:00
need separate modules
*/
{ " AbsoluteTimeout " , pbx_builtin_atimeout ,
2004-07-17 02:25:53 +00:00
" Set absolute maximum time of call " ,
" AbsoluteTimeout(seconds): Set the absolute maximum amount of time permitted \n "
" for a call. A setting of 0 disables the timeout. Always returns 0. \n "
} ,
2003-04-27 19:35:06 +00:00
2001-04-27 15:07:56 +00:00
{ " Answer " , pbx_builtin_answer ,
2004-07-17 02:25:53 +00:00
" Answer a channel if ringing " ,
2004-12-29 12:49:35 +00:00
" Answer([delay]): If the channel is ringing, answer it, otherwise do nothing. \n "
" If delay is specified, asterisk will pause execution for the specified amount \n "
" of milliseconds if an answer is required, in order to give audio a chance to \n "
" become ready. Returns 0 unless it tries to answer the channel and fails. \n "
2004-07-17 02:25:53 +00:00
} ,
2001-09-28 21:20:52 +00:00
2003-04-27 19:35:06 +00:00
{ " BackGround " , pbx_builtin_background ,
2004-07-17 02:25:53 +00:00
" Play a file while awaiting extension " ,
2004-11-25 02:57:34 +00:00
" Background(filename1[&filename2...][|options[|langoverride]]): Plays \n "
" given files, while simultaneously waiting for the user to begin typing \n "
" an extension. The timeouts do not count until the last BackGround \n "
" application has ended. Options may also be included following a pipe \n "
" symbol. The 'skip' option causes the playback of the message to be \n "
" skipped if the channel is not in the 'up' state (i.e. it hasn't been \n "
" answered yet. If 'skip' is specified, the application will return \n "
" immediately should the channel not be off hook. Otherwise, unless \n "
" 'noanswer' is specified, the channel channel will be answered before the \n "
" sound is played. Not all channels support playing messages while still \n "
" hook. The 'langoverride' may be a language to use for playing the prompt \n "
" which differs from the current language of the channel. Returns -1 if \n "
" the channel was hung up, or if the file does not exist. Returns 0 otherwise. \n "
2004-07-17 02:25:53 +00:00
} ,
2001-09-28 21:20:52 +00:00
2003-04-27 19:35:06 +00:00
{ " Busy " , pbx_builtin_busy ,
2004-07-17 02:25:53 +00:00
" Indicate busy condition and stop " ,
" Busy([timeout]): Requests that the channel indicate busy condition and \n "
" then waits for the user to hang up or the optional timeout to expire. \n "
" Always returns -1. "
} ,
2003-04-27 19:35:06 +00:00
{ " Congestion " , pbx_builtin_congestion ,
2004-07-17 02:25:53 +00:00
" Indicate congestion and stop " ,
" Congestion([timeout]): Requests that the channel indicate congestion \n "
" and then waits for the user to hang up or for the optional timeout to \n "
" expire. Always returns -1. "
} ,
2001-09-28 21:20:52 +00:00
2001-04-27 15:07:56 +00:00
{ " DigitTimeout " , pbx_builtin_dtimeout ,
2004-07-17 02:25:53 +00:00
" Set maximum timeout between digits " ,
" DigitTimeout(seconds): Set the maximum amount of time permitted between \n "
" digits when the user is typing in an extension. When this timeout expires, \n "
" after the user has started to type in an extension, the extension will be \n "
" considered complete, and will be interpreted. Note that if an extension \n "
" typed in is valid, it will not have to timeout to be tested, so typically \n "
" at the expiry of this timeout, the extension will be considered invalid \n "
" (and thus control would be passed to the 'i' extension, or if it doesn't \n "
" exist the call would be terminated). Always returns 0. \n "
} ,
2001-09-28 21:20:52 +00:00
2003-04-27 19:35:06 +00:00
{ " Goto " , pbx_builtin_goto ,
2004-07-17 02:25:53 +00:00
" Goto a particular priority, extension, or context " ,
" Goto([[context|]extension|]priority): Set the priority to the specified \n "
" value, optionally setting the extension and optionally the context as well. \n "
" The extension BYEXTENSION is special in that it uses the current extension, \n "
" thus permitting you to go to a different context, without specifying a \n "
" specific extension. Always returns 0, even if the given context, extension, \n "
" or priority is invalid. \n "
} ,
2001-11-24 15:15:01 +00:00
2003-04-27 19:35:06 +00:00
{ " GotoIf " , pbx_builtin_gotoif ,
2004-07-17 02:25:53 +00:00
" Conditional goto " ,
" GotoIf(Condition?label1:label2): Go to label 1 if condition is \n "
" true, to label2 if condition is false. Either label1 or label2 may be \n "
" omitted (in that case, we just don't take the particular branch) but not \n "
" both. Look for the condition syntax in examples or documentation. "
} ,
2001-09-28 21:20:52 +00:00
2003-04-28 04:18:47 +00:00
{ " GotoIfTime " , pbx_builtin_gotoiftime ,
2004-07-17 02:25:53 +00:00
" Conditional goto on current time " ,
" GotoIfTime(<times>|<weekdays>|<mdays>|<months>?[[context|]extension|]pri): \n "
" If the current time matches the specified time, then branch to the specified \n "
" extension. Each of the elements may be specified either as '*' (for always) \n "
" or as a range. See the 'include' syntax for details. "
} ,
2003-04-27 19:35:06 +00:00
{ " Hangup " , pbx_builtin_hangup ,
2004-07-17 02:25:53 +00:00
" Unconditional hangup " ,
" Hangup(): Unconditionally hangs up a given channel by returning -1 always. \n "
} ,
2001-09-28 21:20:52 +00:00
2003-04-27 19:35:06 +00:00
{ " NoOp " , pbx_builtin_noop ,
2004-07-17 02:25:53 +00:00
" No operation " ,
" NoOp(): No-operation; Does nothing. "
} ,
2001-09-28 21:20:52 +00:00
{ " Prefix " , pbx_builtin_prefix ,
2004-07-17 02:25:53 +00:00
" Prepend leading digits " ,
" Prefix(digits): Prepends the digit string specified by digits to the \n "
" channel's associated extension. For example, the number 1212 when prefixed \n "
" with '555' will become 5551212. This app always returns 0, and the PBX will \n "
" continue processing at the next priority for the *new* extension. \n "
" So, for example, if priority 3 of 1212 is Prefix 555, the next step \n "
" executed will be priority 4 of 5551212. If you switch into an extension \n "
" which has no first step, the PBX will treat it as though the user dialed an \n "
" invalid extension. \n "
} ,
2001-09-28 21:20:52 +00:00
2004-06-22 03:51:34 +00:00
{ " Progress " , pbx_builtin_progress ,
2004-07-17 02:25:53 +00:00
" Indicate progress " ,
" Progress(): Request that the channel indicate in-band progress is \n "
" available to the user. \n Always returns 0. \n "
} ,
2004-06-22 03:51:34 +00:00
2003-09-08 21:52:45 +00:00
{ " ResetCDR " , pbx_builtin_resetcdr ,
2004-07-17 02:25:53 +00:00
" Resets the Call Data Record " ,
" ResetCDR([options]): Causes the Call Data Record to be reset, optionally \n "
" storing the current CDR before zeroing it out (if 'w' option is specifed). \n "
" record WILL be stored. \n Always returns 0. \n "
} ,
2003-09-08 21:52:45 +00:00
2003-04-27 19:35:06 +00:00
{ " ResponseTimeout " , pbx_builtin_rtimeout ,
2004-07-17 02:25:53 +00:00
" Set maximum timeout awaiting response " ,
" ResponseTimeout(seconds): Set the maximum amount of time permitted after \n "
" falling through a series of priorities for a channel in which the user may \n "
" begin typing an extension. If the user does not type an extension in this \n "
" amount of time, control will pass to the 't' extension if it exists, and \n "
" if not the call would be terminated. \n Always returns 0. \n "
} ,
2001-09-28 21:20:52 +00:00
{ " Ringing " , pbx_builtin_ringing ,
2004-07-17 02:25:53 +00:00
" Indicate ringing tone " ,
" Ringing(): Request that the channel indicate ringing tone to the user. \n "
" Always returns 0. \n "
} ,
2001-09-28 21:20:52 +00:00
2003-04-27 19:35:06 +00:00
{ " SayNumber " , pbx_builtin_saynumber ,
2004-07-17 02:25:53 +00:00
" Say Number " ,
" SayNumber(digits[,gender]): Says the passed number. SayNumber is using \n "
" the current language setting for the channel. (See app SetLanguage). \n "
} ,
2001-09-28 21:20:52 +00:00
2003-04-27 19:35:06 +00:00
{ " SayDigits " , pbx_builtin_saydigits ,
2004-07-17 02:25:53 +00:00
" Say Digits " ,
" SayDigits(digits): Says the passed digits. SayDigits is using the \n "
" current language setting for the channel. (See app setLanguage) \n "
} ,
2001-09-28 21:20:52 +00:00
2004-05-03 00:54:16 +00:00
{ " SayAlpha " , pbx_builtin_saycharacters ,
2004-07-17 02:25:53 +00:00
" Say Alpha " ,
" SayAlpha(string): Spells the passed string \n "
} ,
2004-05-03 00:54:16 +00:00
{ " SayPhonetic " , pbx_builtin_sayphonetic ,
2004-07-17 02:25:53 +00:00
" Say Phonetic " ,
" SayPhonetic(string): Spells the passed string with phonetic alphabet \n "
} ,
2004-05-03 00:54:16 +00:00
2003-04-27 19:35:06 +00:00
{ " SetAccount " , pbx_builtin_setaccount ,
2004-07-17 02:25:53 +00:00
" Sets account code " ,
" SetAccount([account]): Set the channel account code for billing \n "
" purposes. Always returns 0. \n "
} ,
2004-06-28 03:48:53 +00:00
{ " SetAMAFlags " , pbx_builtin_setamaflags ,
2004-07-17 02:25:53 +00:00
" Sets AMA Flags " ,
" SetAMAFlags([flag]): Set the channel AMA Flags for billing \n "
" purposes. Always returns 0. \n "
} ,
2002-09-11 17:09:48 +00:00
2003-02-13 06:00:14 +00:00
{ " SetGlobalVar " , pbx_builtin_setglobalvar ,
2004-07-17 02:25:53 +00:00
" Set global variable to value " ,
" SetGlobalVar(#n=value): Sets global variable n to value. Global \n "
" variable are available across channels. \n "
} ,
2003-02-13 06:00:14 +00:00
2003-04-27 19:35:06 +00:00
{ " SetLanguage " , pbx_builtin_setlanguage ,
2004-07-17 02:25:53 +00:00
" Sets user language " ,
" SetLanguage(language): Set the channel language to 'language'. This \n "
" information is used for the syntax in generation of numbers, and to choose \n "
" a natural language file when available. \n "
" For example, if language is set to 'fr' and the file 'demo-congrats' is \n "
" requested to be played, if the file 'fr/demo-congrats' exists, then \n "
" it will play that file, and if not will play the normal 'demo-congrats'. \n "
" Always returns 0. \n "
} ,
2003-02-12 13:59:15 +00:00
2003-04-27 19:35:06 +00:00
{ " SetVar " , pbx_builtin_setvar ,
2004-07-17 02:25:53 +00:00
" Set variable to value " ,
2004-11-01 02:23:28 +00:00
" SetVar(#n=value): Sets variable n to value. If prefixed with _, single \n "
" inheritance assumed. If prefixed with __, infinite inheritance is assumed. \n " } ,
2002-09-11 17:09:48 +00:00
2004-11-17 04:48:58 +00:00
{ " ImportVar " , pbx_builtin_importvar ,
" Set variable to value " ,
" ImportVar(#n=channel|variable): Sets variable n to variable as evaluated on \n "
" the specified channel (instead of current). If prefixed with _, single \n "
" inheritance assumed. If prefixed with __, infinite inheritance is assumed. \n " } ,
2003-04-27 19:35:06 +00:00
{ " StripMSD " , pbx_builtin_stripmsd ,
2004-07-17 02:25:53 +00:00
" Strip leading digits " ,
" StripMSD(count): Strips the leading 'count' digits from the channel's \n "
" associated extension. For example, the number 5551212 when stripped with a \n "
" count of 3 would be changed to 1212. This app always returns 0, and the PBX \n "
" will continue processing at the next priority for the *new* extension. \n "
" So, for example, if priority 3 of 5551212 is StripMSD 3, the next step \n "
" executed will be priority 4 of 1212. If you switch into an extension which \n "
" has no first step, the PBX will treat it as though the user dialed an \n "
" invalid extension. \n "
} ,
2003-04-28 04:18:47 +00:00
{ " Suffix " , pbx_builtin_suffix ,
2004-07-17 02:25:53 +00:00
" Append trailing digits " ,
" Suffix(digits): Appends the digit string specified by digits to the \n "
" channel's associated extension. For example, the number 555 when suffixed \n "
" with '1212' will become 5551212. This app always returns 0, and the PBX will \n "
" continue processing at the next priority for the *new* extension. \n "
" So, for example, if priority 3 of 555 is Suffix 1212, the next step \n "
" executed will be priority 4 of 5551212. If you switch into an extension \n "
" which has no first step, the PBX will treat it as though the user dialed an \n "
" invalid extension. \n "
} ,
2003-04-16 13:43:11 +00:00
2003-04-27 19:35:06 +00:00
{ " Wait " , pbx_builtin_wait ,
2004-07-17 02:25:53 +00:00
" Waits for some time " ,
" Wait(seconds): Waits for a specified number of seconds, then returns 0. \n "
" seconds can be passed with fractions of a second. (eg: 1.5 = 1.5 seconds) \n "
} ,
2004-04-06 04:14:19 +00:00
{ " WaitExten " , pbx_builtin_waitexten ,
2004-11-16 03:13:05 +00:00
" Waits for an extension to be entered " ,
" WaitExten([seconds]): Waits for the user to enter a new extension for the \n "
2004-07-17 02:25:53 +00:00
" specified number of seconds, then returns 0. Seconds can be passed with \n "
2004-10-16 19:46:02 +00:00
" fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the \n "
" default extension timeout will be used. \n "
2004-07-17 02:25:53 +00:00
} ,
2004-04-06 04:14:19 +00:00
1999-12-04 20:45:45 +00:00
} ;
2004-07-17 02:25:53 +00:00
AST_MUTEX_DEFINE_STATIC ( applock ) ; /* Lock for the application list */
1999-12-04 20:45:45 +00:00
static struct ast_context * contexts = NULL ;
2004-07-17 02:25:53 +00:00
AST_MUTEX_DEFINE_STATIC ( conlock ) ; /* Lock for the ast_context list */
1999-12-04 20:45:45 +00:00
static struct ast_app * apps = NULL ;
2004-07-17 02:25:53 +00:00
AST_MUTEX_DEFINE_STATIC ( switchlock ) ; /* Lock for switches */
2001-09-28 21:20:52 +00:00
struct ast_switch * switches = NULL ;
2004-07-17 02:25:53 +00:00
AST_MUTEX_DEFINE_STATIC ( hintlock ) ; /* Lock for extension state notifys */
2003-04-06 18:19:51 +00:00
static int stateid = 1 ;
struct ast_hint * hints = NULL ;
struct ast_state_cb * statecbs = NULL ;
2003-03-30 22:55:42 +00:00
2004-07-17 02:25:53 +00:00
int pbx_exec ( struct ast_channel * c , /* Channel */
struct ast_app * app , /* Application */
void * data , /* Data for execution */
int newstack ) /* Force stack increment */
1999-12-04 20:45:45 +00:00
{
/* This function is special. It saves the stack so that no matter
how many times it is called , it returns to the same place */
int res ;
2004-04-04 21:30:24 +00:00
char * saved_c_appl ;
char * saved_c_data ;
2001-09-28 21:20:52 +00:00
int ( * execute ) ( struct ast_channel * chan , void * data ) = app - > execute ;
2004-07-17 02:25:53 +00:00
2004-12-07 20:38:43 +00:00
if ( newstack ) {
2001-11-24 15:15:01 +00:00
if ( c - > cdr )
ast_cdr_setapp ( c - > cdr , app - > name , data ) ;
2004-04-04 21:30:24 +00:00
2004-07-17 02:25:53 +00:00
/* save channel values */
2004-04-04 21:30:24 +00:00
saved_c_appl = c - > appl ;
saved_c_data = c - > data ;
2001-09-28 21:20:52 +00:00
c - > appl = app - > name ;
c - > data = data ;
1999-12-04 20:45:45 +00:00
res = execute ( c , data ) ;
2004-07-17 02:25:53 +00:00
/* restore channel values */
2004-04-04 21:30:24 +00:00
c - > appl = saved_c_appl ;
c - > data = saved_c_data ;
2004-12-07 20:38:43 +00:00
return res ;
} else
ast_log ( LOG_WARNING , " You really didn't want to call this function with newstack set to 0 \n " ) ;
return - 1 ;
1999-12-04 20:45:45 +00:00
}
2001-03-30 18:47:35 +00:00
/* Go no deeper than this through includes (not counting loops) */
2004-12-31 00:37:55 +00:00
# define AST_PBX_MAX_STACK 128
2001-03-30 18:47:35 +00:00
1999-12-04 20:45:45 +00:00
# define HELPER_EXISTS 0
# define HELPER_SPAWN 1
# define HELPER_EXEC 2
2000-01-07 10:54:40 +00:00
# define HELPER_CANMATCH 3
2003-02-02 19:04:14 +00:00
# define HELPER_MATCHMORE 4
2004-10-03 04:19:59 +00:00
# define HELPER_FINDLABEL 5
1999-12-04 20:45:45 +00:00
2004-10-03 04:19:59 +00:00
struct ast_app * pbx_findapp ( const char * app )
1999-12-04 20:45:45 +00:00
{
struct ast_app * tmp ;
2004-07-17 02:25:53 +00:00
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & applock ) ) {
1999-12-04 20:45:45 +00:00
ast_log ( LOG_WARNING , " Unable to obtain application lock \n " ) ;
return NULL ;
}
tmp = apps ;
while ( tmp ) {
if ( ! strcasecmp ( tmp - > name , app ) )
break ;
tmp = tmp - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
1999-12-04 20:45:45 +00:00
return tmp ;
}
2004-10-03 04:19:59 +00:00
static struct ast_switch * pbx_findswitch ( const char * sw )
2001-09-28 21:20:52 +00:00
{
struct ast_switch * asw ;
2004-07-17 02:25:53 +00:00
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & switchlock ) ) {
2001-09-28 21:20:52 +00:00
ast_log ( LOG_WARNING , " Unable to obtain application lock \n " ) ;
return NULL ;
}
asw = switches ;
while ( asw ) {
if ( ! strcasecmp ( asw - > name , sw ) )
break ;
asw = asw - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & switchlock ) ;
2001-09-28 21:20:52 +00:00
return asw ;
}
2002-06-21 01:40:13 +00:00
static inline int include_valid ( struct ast_include * i )
{
if ( ! i - > hastime )
return 1 ;
2004-11-11 21:23:45 +00:00
return ast_check_timing ( & ( i - > timing ) ) ;
2002-06-21 01:40:13 +00:00
}
1999-12-04 20:45:45 +00:00
static void pbx_destroy ( struct ast_pbx * p )
{
free ( p ) ;
}
2003-09-14 00:32:51 +00:00
# define EXTENSION_MATCH_CORE(data,pattern,match) {\
/* All patterns begin with _ */ \
if ( pattern [ 0 ] ! = ' _ ' ) \
return 0 ; \
/* Start optimistic */ \
match = 1 ; \
pattern + + ; \
while ( match & & * data & & * pattern & & ( * pattern ! = ' / ' ) ) { \
2004-11-12 02:54:17 +00:00
while ( * data = = ' - ' & & ( * ( data + 1 ) ! = ' \0 ' ) ) data + + ; \
2003-09-14 00:32:51 +00:00
switch ( toupper ( * pattern ) ) { \
case ' [ ' : \
{ \
int i , border = 0 ; \
char * where ; \
match = 0 ; \
pattern + + ; \
where = strchr ( pattern , ' ] ' ) ; \
if ( where ) \
border = ( int ) ( where - pattern ) ; \
if ( ! where | | border > strlen ( pattern ) ) { \
ast_log ( LOG_WARNING , " Wrong usage of [] in the extension \n " ) ; \
return match ; \
} \
for ( i = 0 ; i < border ; i + + ) { \
int res = 0 ; \
if ( i + 2 < border ) \
if ( pattern [ i + 1 ] = = ' - ' ) { \
if ( * data > = pattern [ i ] & & * data < = pattern [ i + 2 ] ) { \
res = 1 ; \
} else { \
i + = 2 ; \
continue ; \
} \
} \
if ( res = = 1 | | * data = = pattern [ i ] ) { \
match = 1 ; \
break ; \
} \
} \
pattern + = border ; \
break ; \
} \
case ' N ' : \
if ( ( * data < ' 2 ' ) | | ( * data > ' 9 ' ) ) \
match = 0 ; \
break ; \
case ' X ' : \
if ( ( * data < ' 0 ' ) | | ( * data > ' 9 ' ) ) \
match = 0 ; \
break ; \
case ' Z ' : \
if ( ( * data < ' 1 ' ) | | ( * data > ' 9 ' ) ) \
match = 0 ; \
break ; \
case ' . ' : \
/* Must match */ \
return 1 ; \
case ' ' : \
case ' - ' : \
/* Ignore these characters */ \
data - - ; \
break ; \
default : \
if ( * data ! = * pattern ) \
match = 0 ; \
} \
data + + ; \
pattern + + ; \
} \
2003-02-12 13:59:15 +00:00
}
2004-10-03 04:19:59 +00:00
int ast_extension_match ( const char * pattern , const char * data )
1999-12-04 20:45:45 +00:00
{
int match ;
2003-09-14 00:32:51 +00:00
/* If they're the same return */
if ( ! strcmp ( pattern , data ) )
return 1 ;
EXTENSION_MATCH_CORE ( data , pattern , match ) ;
/* Must be at the end of both */
if ( * data | | ( * pattern & & ( * pattern ! = ' / ' ) ) )
match = 0 ;
1999-12-04 20:45:45 +00:00
return match ;
}
2004-11-24 03:07:08 +00:00
int ast_extension_close ( const char * pattern , const char * data , int needmore )
2000-01-07 10:54:40 +00:00
{
2003-09-14 00:32:51 +00:00
int match ;
2003-02-02 19:04:14 +00:00
/* If "data" is longer, it can'be a subset of pattern unless
pattern is a pattern match */
if ( ( strlen ( pattern ) < strlen ( data ) ) & & ( pattern [ 0 ] ! = ' _ ' ) )
2000-01-07 10:54:40 +00:00
return 0 ;
2004-05-04 06:34:34 +00:00
if ( ( ast_strlen_zero ( ( char * ) data ) | | ! strncasecmp ( pattern , data , strlen ( data ) ) ) & &
2003-02-02 19:04:14 +00:00
( ! needmore | | ( strlen ( pattern ) > strlen ( data ) ) ) ) {
2000-01-07 10:54:40 +00:00
return 1 ;
}
2003-09-14 00:32:51 +00:00
EXTENSION_MATCH_CORE ( data , pattern , match ) ;
2003-02-02 19:04:14 +00:00
/* If there's more or we don't care about more, return non-zero, otlherwise it's a miss */
if ( ! needmore | | * pattern ) {
return match ;
} else
return 0 ;
2000-01-07 10:54:40 +00:00
}
2004-10-03 04:19:59 +00:00
struct ast_context * ast_context_find ( const char * name )
2000-01-24 07:14:18 +00:00
{
struct ast_context * tmp ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & conlock ) ;
2001-04-27 15:07:56 +00:00
if ( name ) {
tmp = contexts ;
while ( tmp ) {
if ( ! strcasecmp ( name , tmp - > name ) )
break ;
tmp = tmp - > next ;
}
} else
tmp = contexts ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2000-01-24 07:14:18 +00:00
return tmp ;
}
2001-03-30 18:47:35 +00:00
# define STATUS_NO_CONTEXT 1
# define STATUS_NO_EXTENSION 2
# define STATUS_NO_PRIORITY 3
2004-10-03 04:19:59 +00:00
# define STATUS_NO_LABEL 4
# define STATUS_SUCCESS 5
2001-03-30 18:47:35 +00:00
2004-10-03 04:19:59 +00:00
static int matchcid ( const char * cidpattern , const char * callerid )
1999-12-04 20:45:45 +00:00
{
2001-09-28 21:20:52 +00:00
int failresult ;
/* If the Caller*ID pattern is empty, then we're matching NO Caller*ID, so
failing to get a number should count as a match , otherwise not */
2004-05-04 06:34:34 +00:00
if ( ! ast_strlen_zero ( cidpattern ) )
2001-09-28 21:20:52 +00:00
failresult = 0 ;
else
failresult = 1 ;
if ( ! callerid )
return failresult ;
2004-10-02 00:58:31 +00:00
return ast_extension_match ( cidpattern , callerid ) ;
2001-09-28 21:20:52 +00:00
}
2004-12-11 03:50:19 +00:00
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 )
2001-09-28 21:20:52 +00:00
{
int x , res ;
1999-12-04 20:45:45 +00:00
struct ast_context * tmp ;
2001-03-30 18:47:35 +00:00
struct ast_exten * e , * eroot ;
struct ast_include * i ;
2001-09-28 21:20:52 +00:00
struct ast_sw * sw ;
struct ast_switch * asw ;
2004-07-17 02:25:53 +00:00
2001-03-30 18:47:35 +00:00
/* Initialize status if appropriate */
2001-09-28 21:20:52 +00:00
if ( ! * stacklen ) {
2001-03-30 18:47:35 +00:00
* status = STATUS_NO_CONTEXT ;
2001-09-28 21:20:52 +00:00
* swo = NULL ;
* data = NULL ;
}
2001-03-30 18:47:35 +00:00
/* Check for stack overflow */
if ( * stacklen > = AST_PBX_MAX_STACK ) {
ast_log ( LOG_WARNING , " Maximum PBX stack exceeded \n " ) ;
return NULL ;
}
/* Check first to see if we've already been checked */
for ( x = 0 ; x < * stacklen ; x + + ) {
if ( ! strcasecmp ( incstack [ x ] , context ) )
return NULL ;
}
2004-10-03 16:15:44 +00:00
if ( bypass )
tmp = bypass ;
else
tmp = contexts ;
2001-03-30 18:47:35 +00:00
while ( tmp ) {
/* Match context */
2004-10-03 16:15:44 +00:00
if ( bypass | | ! strcmp ( tmp - > name , context ) ) {
2001-03-30 18:47:35 +00:00
if ( * status < STATUS_NO_EXTENSION )
* status = STATUS_NO_EXTENSION ;
eroot = tmp - > root ;
while ( eroot ) {
/* Match extension */
2003-02-02 19:04:14 +00:00
if ( ( ( ( action ! = HELPER_MATCHMORE ) & & ast_extension_match ( eroot - > exten , exten ) ) | |
2004-11-24 03:07:08 +00:00
( ( action = = HELPER_CANMATCH ) & & ( ast_extension_close ( eroot - > exten , exten , 0 ) ) ) | |
( ( action = = HELPER_MATCHMORE ) & & ( ast_extension_close ( eroot - > exten , exten , 1 ) ) ) ) & &
2001-09-28 21:20:52 +00:00
( ! eroot - > matchcid | | matchcid ( eroot - > cidmatch , callerid ) ) ) {
2001-03-30 18:47:35 +00:00
e = eroot ;
if ( * status < STATUS_NO_PRIORITY )
* status = STATUS_NO_PRIORITY ;
while ( e ) {
/* Match priority */
2004-10-03 04:19:59 +00:00
if ( action = = HELPER_FINDLABEL ) {
if ( * status < STATUS_NO_LABEL )
* status = STATUS_NO_LABEL ;
if ( label & & e - > label & & ! strcmp ( label , e - > label ) ) {
* status = STATUS_SUCCESS ;
2004-12-11 03:50:19 +00:00
* foundcontext = context ;
2004-10-03 04:19:59 +00:00
return e ;
}
} else if ( e - > priority = = priority ) {
2001-03-30 18:47:35 +00:00
* status = STATUS_SUCCESS ;
2004-12-11 03:50:19 +00:00
* foundcontext = context ;
2001-03-30 18:47:35 +00:00
return e ;
}
e = e - > peer ;
}
}
eroot = eroot - > next ;
}
2001-09-28 21:20:52 +00:00
/* Check alternative switches */
sw = tmp - > alts ;
while ( sw ) {
if ( ( asw = pbx_findswitch ( sw - > name ) ) ) {
if ( action = = HELPER_CANMATCH )
res = asw - > canmatch ? asw - > canmatch ( chan , context , exten , priority , callerid , sw - > data ) : 0 ;
2003-02-02 19:04:14 +00:00
else if ( action = = HELPER_MATCHMORE )
res = asw - > matchmore ? asw - > matchmore ( chan , context , exten , priority , callerid , sw - > data ) : 0 ;
2001-09-28 21:20:52 +00:00
else
res = asw - > exists ? asw - > exists ( chan , context , exten , priority , callerid , sw - > data ) : 0 ;
if ( res ) {
/* Got a match */
* swo = asw ;
* data = sw - > data ;
2004-12-11 03:50:19 +00:00
* foundcontext = context ;
2001-09-28 21:20:52 +00:00
return NULL ;
}
} else {
ast_log ( LOG_WARNING , " No such switch '%s' \n " , sw - > name ) ;
}
sw = sw - > next ;
}
2001-03-30 18:47:35 +00:00
/* Setup the stack */
incstack [ * stacklen ] = tmp - > name ;
( * stacklen ) + + ;
/* Now try any includes we have in this context */
i = tmp - > includes ;
while ( i ) {
2002-06-21 01:40:13 +00:00
if ( include_valid ( i ) ) {
2004-12-11 03:50:19 +00:00
if ( ( e = pbx_find_extension ( chan , bypass , i - > rname , exten , priority , label , callerid , action , incstack , stacklen , status , swo , data , foundcontext ) ) )
2002-06-21 01:40:13 +00:00
return e ;
if ( * swo )
return NULL ;
}
2001-03-30 18:47:35 +00:00
i = i - > next ;
}
2004-10-03 16:15:44 +00:00
break ;
2001-03-30 18:47:35 +00:00
}
tmp = tmp - > next ;
}
return NULL ;
}
2004-12-23 02:47:01 +00:00
void pbx_retrieve_variable ( struct ast_channel * c , const char * var , char * * ret , char * workspace , int workspacelen , struct varshead * headp )
2003-02-21 06:00:08 +00:00
{
2003-03-18 06:00:18 +00:00
char * first , * second ;
2003-04-18 15:34:25 +00:00
char tmpvar [ 80 ] = " " ;
2003-04-21 03:02:22 +00:00
time_t thistime ;
struct tm brokentime ;
2003-03-18 06:00:18 +00:00
int offset , offset2 ;
2002-09-11 17:09:48 +00:00
struct ast_var_t * variables ;
2004-05-09 07:19:00 +00:00
if ( c )
2003-08-03 18:33:50 +00:00
headp = & c - > varshead ;
2004-05-09 07:19:00 +00:00
* ret = NULL ;
/* Now we have the variable name on cp3 */
2004-03-19 06:36:25 +00:00
if ( ! strncasecmp ( var , " LEN( " , 4 ) ) {
int len = strlen ( var ) ;
int len_len = 4 ;
if ( strrchr ( var , ' ) ' ) ) {
char cp3 [ 80 ] ;
strncpy ( cp3 , var , sizeof ( cp3 ) - 1 ) ;
cp3 [ len - len_len - 1 ] = ' \0 ' ;
2004-06-13 21:25:10 +00:00
sprintf ( workspace , " %d " , ( int ) strlen ( cp3 ) ) ;
2004-03-19 06:36:25 +00:00
* ret = workspace ;
} else {
/* length is zero */
* ret = " 0 " ;
}
} else if ( ( first = strchr ( var , ' : ' ) ) ) {
2003-04-18 15:34:25 +00:00
strncpy ( tmpvar , var , sizeof ( tmpvar ) - 1 ) ;
first = strchr ( tmpvar , ' : ' ) ;
if ( ! first )
first = tmpvar + strlen ( tmpvar ) ;
2003-03-18 06:00:18 +00:00
* first = ' \0 ' ;
2004-12-23 02:47:01 +00:00
pbx_retrieve_variable ( c , tmpvar , ret , workspace , workspacelen - 1 , headp ) ;
2003-04-18 15:34:25 +00:00
if ( ! ( * ret ) ) return ;
2003-03-18 06:00:18 +00:00
offset = atoi ( first + 1 ) ;
if ( ( second = strchr ( first + 1 , ' : ' ) ) ) {
* second = ' \0 ' ;
offset2 = atoi ( second + 1 ) ;
2003-03-18 19:55:35 +00:00
} else
2003-04-18 15:34:25 +00:00
offset2 = strlen ( * ret ) - offset ;
if ( abs ( offset ) > strlen ( * ret ) ) {
if ( offset > = 0 )
offset = strlen ( * ret ) ;
else
offset = - strlen ( * ret ) ;
2003-03-18 06:00:18 +00:00
}
2003-04-18 15:34:25 +00:00
if ( ( offset < 0 & & offset2 > - offset ) | | ( offset > = 0 & & offset + offset2 > strlen ( * ret ) ) ) {
if ( offset > = 0 )
offset2 = strlen ( * ret ) - offset ;
else
offset2 = strlen ( * ret ) + offset ;
2003-03-18 06:00:18 +00:00
}
if ( offset > = 0 )
2003-04-18 15:34:25 +00:00
* ret + = offset ;
2003-03-18 06:00:18 +00:00
else
2003-04-18 15:34:25 +00:00
* ret + = strlen ( * ret ) + offset ;
( * ret ) [ offset2 ] = ' \0 ' ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " CALLERIDNUM " ) ) {
2004-10-02 00:58:31 +00:00
if ( c - > cid . cid_num ) {
strncpy ( workspace , c - > cid . cid_num , workspacelen - 1 ) ;
* ret = workspace ;
2003-03-18 06:00:18 +00:00
} else
2004-10-02 00:58:31 +00:00
* ret = NULL ;
} else if ( c & & ! strcmp ( var , " CALLERANI " ) ) {
if ( c - > cid . cid_ani ) {
strncpy ( workspace , c - > cid . cid_ani , workspacelen - 1 ) ;
2003-05-06 00:00:20 +00:00
* ret = workspace ;
2004-10-02 00:58:31 +00:00
} else
* ret = NULL ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " CALLERIDNAME " ) ) {
2004-10-02 00:58:31 +00:00
if ( c - > cid . cid_name ) {
strncpy ( workspace , c - > cid . cid_name , workspacelen - 1 ) ;
2003-05-06 00:00:20 +00:00
* ret = workspace ;
2004-10-02 00:58:31 +00:00
} else
* ret = NULL ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " CALLERID " ) ) {
2004-10-02 00:58:31 +00:00
if ( c - > cid . cid_num ) {
if ( c - > cid . cid_name ) {
snprintf ( workspace , workspacelen , " \" %s \" <%s> " , c - > cid . cid_name , c - > cid . cid_num ) ;
} else {
strncpy ( workspace , c - > cid . cid_num , workspacelen - 1 ) ;
}
* ret = workspace ;
} else if ( c - > cid . cid_name ) {
strncpy ( workspace , c - > cid . cid_name , workspacelen - 1 ) ;
2003-04-18 15:34:25 +00:00
* ret = workspace ;
2004-10-02 00:58:31 +00:00
} else
2003-04-18 15:34:25 +00:00
* ret = NULL ;
2003-09-04 22:46:06 +00:00
} else if ( c & & ! strcmp ( var , " DNID " ) ) {
2004-10-02 00:58:31 +00:00
if ( c - > cid . cid_dnid ) {
strncpy ( workspace , c - > cid . cid_dnid , workspacelen - 1 ) ;
2003-09-04 22:46:06 +00:00
* ret = workspace ;
} else
* ret = NULL ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " HINT " ) ) {
2004-07-14 07:44:19 +00:00
if ( ! ast_get_hint ( workspace , workspacelen , c , c - > context , c - > exten ) )
2003-04-18 15:34:25 +00:00
* ret = NULL ;
2003-03-30 22:55:42 +00:00
else
2003-04-18 15:34:25 +00:00
* ret = workspace ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " EXTEN " ) ) {
2003-04-18 15:34:25 +00:00
strncpy ( workspace , c - > exten , workspacelen - 1 ) ;
* ret = workspace ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " RDNIS " ) ) {
2004-10-02 00:58:31 +00:00
if ( c - > cid . cid_rdnis ) {
strncpy ( workspace , c - > cid . cid_rdnis , workspacelen - 1 ) ;
2003-04-18 15:34:25 +00:00
* ret = workspace ;
} else
* ret = NULL ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " CONTEXT " ) ) {
2003-04-18 15:34:25 +00:00
strncpy ( workspace , c - > context , workspacelen - 1 ) ;
* ret = workspace ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " PRIORITY " ) ) {
2003-03-30 22:55:42 +00:00
snprintf ( workspace , workspacelen , " %d " , c - > priority ) ;
2003-04-18 15:34:25 +00:00
* ret = workspace ;
2004-09-09 20:05:57 +00:00
} else if ( c & & ! strcmp ( var , " CALLINGPRES " ) ) {
2004-10-02 00:58:31 +00:00
snprintf ( workspace , workspacelen , " %d " , c - > cid . cid_pres ) ;
* ret = workspace ;
} else if ( c & & ! strcmp ( var , " CALLINGANI2 " ) ) {
snprintf ( workspace , workspacelen , " %d " , c - > cid . cid_ani2 ) ;
* ret = workspace ;
} else if ( c & & ! strcmp ( var , " CALLINGTON " ) ) {
snprintf ( workspace , workspacelen , " %d " , c - > cid . cid_ton ) ;
* ret = workspace ;
} else if ( c & & ! strcmp ( var , " CALLINGTNS " ) ) {
snprintf ( workspace , workspacelen , " %d " , c - > cid . cid_tns ) ;
2004-09-09 20:05:57 +00:00
* ret = workspace ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " CHANNEL " ) ) {
2003-04-18 15:34:25 +00:00
strncpy ( workspace , c - > name , workspacelen - 1 ) ;
* ret = workspace ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " EPOCH " ) ) {
2004-07-14 07:44:19 +00:00
snprintf ( workspace , workspacelen , " %u " , ( int ) time ( NULL ) ) ;
2004-05-09 07:19:00 +00:00
* ret = workspace ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " DATETIME " ) ) {
2004-05-09 07:19:00 +00:00
thistime = time ( NULL ) ;
localtime_r ( & thistime , & brokentime ) ;
2004-07-14 07:44:19 +00:00
snprintf ( workspace , workspacelen , " %02d%02d%04d-%02d:%02d:%02d " ,
2004-05-09 07:19:00 +00:00
brokentime . tm_mday ,
brokentime . tm_mon + 1 ,
brokentime . tm_year + 1900 ,
brokentime . tm_hour ,
brokentime . tm_min ,
brokentime . tm_sec
) ;
* ret = workspace ;
2003-12-01 02:47:19 +00:00
} else if ( c & & ! strcmp ( var , " TIMESTAMP " ) ) {
2004-05-09 07:19:00 +00:00
thistime = time ( NULL ) ;
localtime_r ( & thistime , & brokentime ) ;
2003-12-01 02:47:19 +00:00
/* 20031130-150612 */
2004-07-14 07:44:19 +00:00
snprintf ( workspace , workspacelen , " %04d%02d%02d-%02d%02d%02d " ,
2004-05-09 07:19:00 +00:00
brokentime . tm_year + 1900 ,
brokentime . tm_mon + 1 ,
brokentime . tm_mday ,
brokentime . tm_hour ,
brokentime . tm_min ,
brokentime . tm_sec
) ;
* ret = workspace ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " UNIQUEID " ) ) {
2004-07-14 07:44:19 +00:00
snprintf ( workspace , workspacelen , " %s " , c - > uniqueid ) ;
2004-05-09 07:19:00 +00:00
* ret = workspace ;
} else if ( c & & ! strcmp ( var , " HANGUPCAUSE " ) ) {
2004-07-14 07:44:19 +00:00
snprintf ( workspace , workspacelen , " %i " , c - > hangupcause ) ;
2004-05-09 07:19:00 +00:00
* ret = workspace ;
} else if ( c & & ! strcmp ( var , " ACCOUNTCODE " ) ) {
strncpy ( workspace , c - > accountcode , workspacelen - 1 ) ;
* ret = workspace ;
} else if ( c & & ! strcmp ( var , " LANGUAGE " ) ) {
strncpy ( workspace , c - > language , workspacelen - 1 ) ;
* ret = workspace ;
2003-03-18 06:00:18 +00:00
} else {
2004-10-24 02:53:24 +00:00
if ( headp ) {
2003-08-03 18:33:50 +00:00
AST_LIST_TRAVERSE ( headp , variables , entries ) {
2003-02-23 06:00:11 +00:00
#if 0
2003-08-03 18:33:50 +00:00
ast_log ( LOG_WARNING , " Comparing variable '%s' with '%s' \n " , var , ast_var_name ( variables ) ) ;
2003-02-23 06:00:11 +00:00
# endif
2003-08-03 18:33:50 +00:00
if ( strcasecmp ( ast_var_name ( variables ) , var ) = = 0 ) {
* ret = ast_var_value ( variables ) ;
if ( * ret ) {
strncpy ( workspace , * ret , workspacelen - 1 ) ;
* ret = workspace ;
}
2004-01-31 17:00:24 +00:00
break ;
2003-04-18 15:34:25 +00:00
}
}
2003-03-18 06:00:18 +00:00
}
2003-04-18 15:34:25 +00:00
if ( ! ( * ret ) ) {
2003-03-18 06:00:18 +00:00
/* Try globals */
AST_LIST_TRAVERSE ( & globals , variables , entries ) {
#if 0
2003-04-18 15:34:25 +00:00
ast_log ( LOG_WARNING , " Comparing variable '%s' with '%s' \n " , var , ast_var_name ( variables ) ) ;
2003-03-18 06:00:18 +00:00
# endif
2003-04-18 15:34:25 +00:00
if ( strcasecmp ( ast_var_name ( variables ) , var ) = = 0 ) {
* ret = ast_var_value ( variables ) ;
if ( * ret ) {
strncpy ( workspace , * ret , workspacelen - 1 ) ;
* ret = workspace ;
}
}
2003-03-18 06:00:18 +00:00
}
}
2003-04-18 15:34:25 +00:00
if ( ! ( * ret ) ) {
int len = strlen ( var ) ;
2003-03-18 06:00:18 +00:00
int len_env = strlen ( " ENV( " ) ;
2003-04-18 15:34:25 +00:00
if ( len > ( len_env + 1 ) & & ! strncasecmp ( var , " ENV( " , len_env ) & & ! strcmp ( var + len - 1 , " ) " ) ) {
char cp3 [ 80 ] = " " ;
strncpy ( cp3 , var , sizeof ( cp3 ) - 1 ) ;
2003-03-18 06:00:18 +00:00
cp3 [ len - 1 ] = ' \0 ' ;
2003-04-18 15:34:25 +00:00
* ret = getenv ( cp3 + len_env ) ;
if ( * ret ) {
strncpy ( workspace , * ret , workspacelen - 1 ) ;
* ret = workspace ;
}
2003-03-18 06:00:18 +00:00
}
}
}
2003-02-21 06:00:08 +00:00
}
2004-10-24 02:53:24 +00:00
static void pbx_substitute_variables_helper_full ( struct ast_channel * c , const char * cp1 , char * cp2 , int count , struct varshead * headp )
2003-02-21 06:00:08 +00:00
{
2003-04-18 15:34:25 +00:00
char * cp4 ;
const char * tmp , * whereweare ;
int length ;
2004-06-25 04:07:52 +00:00
char workspace [ 4096 ] ;
char ltmp [ 4096 ] , var [ 4096 ] ;
2003-04-18 16:57:48 +00:00
char * nextvar , * nextexp ;
2003-04-18 15:34:25 +00:00
char * vars , * vare ;
int pos , brackets , needsub , len ;
2004-07-17 02:25:53 +00:00
2003-04-18 15:34:25 +00:00
/* Substitutes variables into cp2, based on string cp1, and assuming cp2 to be
zero - filled */
whereweare = tmp = cp1 ;
2004-05-04 06:34:34 +00:00
while ( ! ast_strlen_zero ( whereweare ) & & count ) {
2003-04-18 15:34:25 +00:00
/* Assume we're copying the whole remaining string */
pos = strlen ( whereweare ) ;
/* Look for a variable */
2003-04-18 16:57:48 +00:00
nextvar = strstr ( whereweare , " ${ " ) ;
2004-07-17 02:25:53 +00:00
/* Look for an expression */
2003-04-18 16:57:48 +00:00
nextexp = strstr ( whereweare , " $[ " ) ;
2004-07-17 02:25:53 +00:00
/* Pick the first one only */
2003-04-18 16:57:48 +00:00
if ( nextvar & & nextexp ) {
if ( nextvar < nextexp )
nextexp = NULL ;
else
nextvar = NULL ;
}
2003-04-18 15:34:25 +00:00
/* If there is one, we only go that far */
2003-04-18 16:57:48 +00:00
if ( nextvar )
pos = nextvar - whereweare ;
else if ( nextexp )
pos = nextexp - whereweare ;
2003-04-18 15:34:25 +00:00
/* Can't copy more than 'count' bytes */
if ( pos > count )
pos = count ;
/* Copy that many bytes */
memcpy ( cp2 , whereweare , pos ) ;
count - = pos ;
cp2 + = pos ;
whereweare + = pos ;
2003-04-18 16:57:48 +00:00
if ( nextvar ) {
2003-04-18 15:34:25 +00:00
/* We have a variable. Find the start and end, and determine
if we are going to have to recursively call ourselves on the
contents */
2003-04-18 16:57:48 +00:00
vars = vare = nextvar + 2 ;
2003-04-18 15:34:25 +00:00
brackets = 1 ;
needsub = 0 ;
2003-02-23 06:00:11 +00:00
2003-04-18 15:34:25 +00:00
/* Find the end of it */
while ( brackets & & * vare ) {
if ( ( vare [ 0 ] = = ' $ ' ) & & ( vare [ 1 ] = = ' { ' ) ) {
needsub + + ;
brackets + + ;
} else if ( vare [ 0 ] = = ' } ' ) {
brackets - - ;
2003-04-18 16:57:48 +00:00
} else if ( ( vare [ 0 ] = = ' $ ' ) & & ( vare [ 1 ] = = ' [ ' ) )
2003-04-18 15:34:25 +00:00
needsub + + ;
vare + + ;
2003-02-21 06:00:08 +00:00
}
2003-04-18 15:34:25 +00:00
if ( brackets )
ast_log ( LOG_NOTICE , " Error in extension logic (missing '}') \n " ) ;
len = vare - vars - 1 ;
/* Skip totally over variable name */
whereweare + = ( len + 3 ) ;
/* Store variable name (and truncate) */
memset ( var , 0 , sizeof ( var ) ) ;
strncpy ( var , vars , sizeof ( var ) - 1 ) ;
var [ len ] = ' \0 ' ;
/* Substitute if necessary */
if ( needsub ) {
memset ( ltmp , 0 , sizeof ( ltmp ) ) ;
pbx_substitute_variables_helper ( c , var , ltmp , sizeof ( ltmp ) - 1 ) ;
vars = ltmp ;
} else {
vars = var ;
2003-02-23 06:00:11 +00:00
}
2003-04-18 15:34:25 +00:00
/* Retrieve variable value */
2004-07-14 07:44:19 +00:00
workspace [ 0 ] = ' \0 ' ;
2004-12-23 02:47:01 +00:00
pbx_retrieve_variable ( c , vars , & cp4 , workspace , sizeof ( workspace ) , headp ) ;
2003-04-18 15:34:25 +00:00
if ( cp4 ) {
length = strlen ( cp4 ) ;
if ( length > count )
length = count ;
memcpy ( cp2 , cp4 , length ) ;
count - = length ;
cp2 + = length ;
2003-02-21 06:00:08 +00:00
}
2003-04-18 15:34:25 +00:00
2003-04-18 16:57:48 +00:00
} else if ( nextexp ) {
/* We have an expression. Find the start and end, and determine
if we are going to have to recursively call ourselves on the
contents */
vars = vare = nextexp + 2 ;
brackets = 1 ;
needsub = 0 ;
/* Find the end of it */
while ( brackets & & * vare ) {
if ( ( vare [ 0 ] = = ' $ ' ) & & ( vare [ 1 ] = = ' [ ' ) ) {
needsub + + ;
brackets + + ;
2004-06-25 18:23:26 +00:00
vare + + ;
} else if ( vare [ 0 ] = = ' [ ' ) {
brackets + + ;
2003-04-18 16:57:48 +00:00
} else if ( vare [ 0 ] = = ' ] ' ) {
brackets - - ;
2004-06-25 18:23:26 +00:00
} else if ( ( vare [ 0 ] = = ' $ ' ) & & ( vare [ 1 ] = = ' { ' ) ) {
2003-04-18 16:57:48 +00:00
needsub + + ;
2004-06-25 19:33:27 +00:00
vare + + ;
2004-06-25 18:23:26 +00:00
}
2003-04-18 16:57:48 +00:00
vare + + ;
}
if ( brackets )
ast_log ( LOG_NOTICE , " Error in extension logic (missing ']') \n " ) ;
len = vare - vars - 1 ;
/* Skip totally over variable name */
whereweare + = ( len + 3 ) ;
/* Store variable name (and truncate) */
memset ( var , 0 , sizeof ( var ) ) ;
strncpy ( var , vars , sizeof ( var ) - 1 ) ;
var [ len ] = ' \0 ' ;
/* Substitute if necessary */
if ( needsub ) {
memset ( ltmp , 0 , sizeof ( ltmp ) ) ;
pbx_substitute_variables_helper ( c , var , ltmp , sizeof ( ltmp ) - 1 ) ;
vars = ltmp ;
} else {
vars = var ;
}
/* Evaluate expression */
cp4 = ast_expr ( vars ) ;
2003-09-08 16:08:07 +00:00
ast_log ( LOG_DEBUG , " Expression is '%s' \n " , cp4 ) ;
2003-04-18 16:57:48 +00:00
if ( cp4 ) {
length = strlen ( cp4 ) ;
if ( length > count )
length = count ;
memcpy ( cp2 , cp4 , length ) ;
count - = length ;
cp2 + = length ;
free ( cp4 ) ;
}
2003-04-18 15:34:25 +00:00
} else
2003-02-21 06:00:08 +00:00
break ;
2003-04-18 15:34:25 +00:00
}
2003-02-21 06:00:08 +00:00
}
2004-10-24 02:53:24 +00:00
void pbx_substitute_variables_helper ( struct ast_channel * c , const char * cp1 , char * cp2 , int count )
{
pbx_substitute_variables_helper_full ( c , cp1 , cp2 , count , NULL ) ;
}
void pbx_substitute_variables_varshead ( struct varshead * headp , const char * cp1 , char * cp2 , int count )
{
pbx_substitute_variables_helper_full ( NULL , cp1 , cp2 , count , headp ) ;
}
2003-04-18 15:34:25 +00:00
static void pbx_substitute_variables ( char * passdata , int datalen , struct ast_channel * c , struct ast_exten * e ) {
2003-04-18 16:57:48 +00:00
memset ( passdata , 0 , datalen ) ;
2003-04-18 15:34:25 +00:00
/* No variables or expressions in e->data, so why scan it? */
if ( ! strstr ( e - > data , " ${ " ) & & ! strstr ( e - > data , " $[ " ) ) {
strncpy ( passdata , e - > data , datalen - 1 ) ;
passdata [ datalen - 1 ] = ' \0 ' ;
return ;
}
2004-07-17 02:25:53 +00:00
pbx_substitute_variables_helper ( c , e - > data , passdata , datalen - 1 ) ;
2003-04-18 16:57:48 +00:00
}
2002-09-11 17:09:48 +00:00
2004-10-03 16:15:44 +00:00
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 )
2001-03-30 18:47:35 +00:00
{
struct ast_exten * e ;
1999-12-04 20:45:45 +00:00
struct ast_app * app ;
2001-09-28 21:20:52 +00:00
struct ast_switch * sw ;
char * data ;
2004-12-11 03:50:19 +00:00
const char * foundcontext = NULL ;
1999-12-04 20:45:45 +00:00
int newstack = 0 ;
1999-12-18 07:01:48 +00:00
int res ;
2001-03-30 18:47:35 +00:00
int status = 0 ;
char * incstack [ AST_PBX_MAX_STACK ] ;
2004-06-12 14:34:15 +00:00
char passdata [ EXT_DATA_SIZE ] ;
2001-03-30 18:47:35 +00:00
int stacklen = 0 ;
2002-06-21 01:40:13 +00:00
char tmp [ 80 ] ;
char tmp2 [ 80 ] ;
2004-06-12 14:34:15 +00:00
char tmp3 [ EXT_DATA_SIZE ] ;
2004-12-29 23:40:54 +00:00
char atmp [ 80 ] ;
char atmp2 [ EXT_DATA_SIZE + 100 ] ;
2004-07-17 02:25:53 +00:00
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & conlock ) ) {
1999-12-04 20:45:45 +00:00
ast_log ( LOG_WARNING , " Unable to obtain lock \n " ) ;
2003-02-02 19:04:14 +00:00
if ( ( action = = HELPER_EXISTS ) | | ( action = = HELPER_CANMATCH ) | | ( action = = HELPER_MATCHMORE ) )
1999-12-04 20:45:45 +00:00
return 0 ;
else
return - 1 ;
}
2004-12-11 03:50:19 +00:00
e = pbx_find_extension ( c , con , context , exten , priority , label , callerid , action , incstack , & stacklen , & status , & sw , & data , & foundcontext ) ;
2001-03-30 18:47:35 +00:00
if ( e ) {
switch ( action ) {
case HELPER_CANMATCH :
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2001-03-30 18:47:35 +00:00
return - 1 ;
case HELPER_EXISTS :
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2001-03-30 18:47:35 +00:00
return - 1 ;
2004-10-03 04:19:59 +00:00
case HELPER_FINDLABEL :
res = e - > priority ;
ast_mutex_unlock ( & conlock ) ;
return res ;
2003-02-02 19:04:14 +00:00
case HELPER_MATCHMORE :
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2003-02-02 19:04:14 +00:00
return - 1 ;
2001-03-30 18:47:35 +00:00
case HELPER_SPAWN :
newstack + + ;
/* Fall through */
case HELPER_EXEC :
app = pbx_findapp ( e - > app ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2001-03-30 18:47:35 +00:00
if ( app ) {
2003-07-29 15:38:02 +00:00
if ( c - > context ! = context )
2003-09-10 05:24:49 +00:00
strncpy ( c - > context , context , sizeof ( c - > context ) - 1 ) ;
2003-07-29 15:38:02 +00:00
if ( c - > exten ! = exten )
strncpy ( c - > exten , exten , sizeof ( c - > exten ) - 1 ) ;
2001-03-30 18:47:35 +00:00
c - > priority = priority ;
2003-04-18 15:34:25 +00:00
pbx_substitute_variables ( passdata , sizeof ( passdata ) , c , e ) ;
2004-12-29 23:40:54 +00:00
if ( option_debug ) {
2001-03-30 18:47:35 +00:00
ast_log ( LOG_DEBUG , " Launching '%s' \n " , app - > name ) ;
2004-12-29 23:40:54 +00:00
snprintf ( atmp , 80 , " STACK-%s-%s-%d " , context , exten , priority ) ;
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 " ) ) ;
pbx_builtin_setvar_helper ( c , atmp , atmp2 ) ;
}
2004-10-08 04:23:22 +00:00
if ( option_verbose > 2 )
2001-03-30 18:47:35 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Executing %s( \" %s \" , \" %s \" ) %s \n " ,
2002-06-21 01:40:13 +00:00
term_color ( tmp , app - > name , COLOR_BRCYAN , 0 , sizeof ( tmp ) ) ,
term_color ( tmp2 , c - > name , COLOR_BRMAGENTA , 0 , sizeof ( tmp2 ) ) ,
2004-05-04 06:34:34 +00:00
term_color ( tmp3 , ( ! ast_strlen_zero ( passdata ) ? ( char * ) passdata : " " ) , COLOR_BRMAGENTA , 0 , sizeof ( tmp3 ) ) ,
2002-06-21 01:40:13 +00:00
( newstack ? " in new stack " : " in same stack " ) ) ;
2004-07-24 02:26:07 +00:00
manager_event ( EVENT_FLAG_CALL , " Newexten " ,
" Channel: %s \r \n "
" Context: %s \r \n "
" Extension: %s \r \n "
" Priority: %d \r \n "
" Application: %s \r \n "
" AppData: %s \r \n "
" Uniqueid: %s \r \n " ,
c - > name , c - > context , c - > exten , c - > priority , app - > name , passdata ? passdata : " (NULL) " , c - > uniqueid ) ;
2003-04-18 15:34:25 +00:00
res = pbx_exec ( c , app , passdata , newstack ) ;
2001-03-30 18:47:35 +00:00
return res ;
} else {
ast_log ( LOG_WARNING , " No application '%s' for extension (%s, %s, %d) \n " , e - > app , context , exten , priority ) ;
return - 1 ;
}
default :
2002-09-11 17:09:48 +00:00
ast_log ( LOG_WARNING , " Huh (%d)? \n " , action ) ; return - 1 ;
2001-03-30 18:47:35 +00:00
}
2001-09-28 21:20:52 +00:00
} else if ( sw ) {
switch ( action ) {
case HELPER_CANMATCH :
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2001-09-28 21:20:52 +00:00
return - 1 ;
case HELPER_EXISTS :
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2001-09-28 21:20:52 +00:00
return - 1 ;
2003-02-02 19:04:14 +00:00
case HELPER_MATCHMORE :
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2003-02-02 19:04:14 +00:00
return - 1 ;
2004-10-03 04:19:59 +00:00
case HELPER_FINDLABEL :
ast_mutex_unlock ( & conlock ) ;
return - 1 ;
2001-09-28 21:20:52 +00:00
case HELPER_SPAWN :
newstack + + ;
/* Fall through */
case HELPER_EXEC :
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2001-09-28 21:20:52 +00:00
if ( sw - > exec )
2004-12-11 03:50:19 +00:00
res = sw - > exec ( c , foundcontext ? foundcontext : context , exten , priority , callerid , newstack , data ) ;
2001-09-28 21:20:52 +00:00
else {
ast_log ( LOG_WARNING , " No execution engine for switch %s \n " , sw - > name ) ;
res = - 1 ;
}
return res ;
default :
ast_log ( LOG_WARNING , " Huh (%d)? \n " , action ) ;
return - 1 ;
}
2001-03-30 18:47:35 +00:00
} else {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2001-03-30 18:47:35 +00:00
switch ( status ) {
case STATUS_NO_CONTEXT :
2003-02-02 19:04:14 +00:00
if ( ( action ! = HELPER_EXISTS ) & & ( action ! = HELPER_MATCHMORE ) )
2001-03-30 18:47:35 +00:00
ast_log ( LOG_NOTICE , " Cannot find extension context '%s' \n " , context ) ;
break ;
case STATUS_NO_EXTENSION :
2003-02-02 19:04:14 +00:00
if ( ( action ! = HELPER_EXISTS ) & & ( action ! = HELPER_CANMATCH ) & & ( action ! = HELPER_MATCHMORE ) )
2001-03-30 18:47:35 +00:00
ast_log ( LOG_NOTICE , " Cannot find extension '%s' in context '%s' \n " , exten , context ) ;
break ;
case STATUS_NO_PRIORITY :
2003-02-02 19:04:14 +00:00
if ( ( action ! = HELPER_EXISTS ) & & ( action ! = HELPER_CANMATCH ) & & ( action ! = HELPER_MATCHMORE ) )
2001-03-30 18:47:35 +00:00
ast_log ( LOG_NOTICE , " No such priority %d in extension '%s' in context '%s' \n " , priority , exten , context ) ;
break ;
2004-10-03 04:19:59 +00:00
case STATUS_NO_LABEL :
2004-10-03 16:15:44 +00:00
if ( context )
ast_log ( LOG_NOTICE , " No such label '%s' in extension '%s' in context '%s' \n " , label , exten , context ) ;
2004-10-03 04:19:59 +00:00
break ;
2001-03-30 18:47:35 +00:00
default :
ast_log ( LOG_DEBUG , " Shouldn't happen! \n " ) ;
}
2004-07-17 02:25:53 +00:00
2003-02-02 19:04:14 +00:00
if ( ( action ! = HELPER_EXISTS ) & & ( action ! = HELPER_CANMATCH ) & & ( action ! = HELPER_MATCHMORE ) )
2001-03-30 18:47:35 +00:00
return - 1 ;
else
return 0 ;
}
1999-12-04 20:45:45 +00:00
}
2001-03-30 18:47:35 +00:00
2004-10-03 04:19:59 +00:00
static struct ast_exten * ast_hint_extension ( struct ast_channel * c , const char * context , const char * exten )
2003-03-30 22:55:42 +00:00
{
struct ast_exten * e ;
struct ast_switch * sw ;
char * data ;
2004-12-11 03:50:19 +00:00
const char * foundcontext = NULL ;
2003-03-30 22:55:42 +00:00
int status = 0 ;
char * incstack [ AST_PBX_MAX_STACK ] ;
int stacklen = 0 ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & conlock ) ) {
2003-03-30 22:55:42 +00:00
ast_log ( LOG_WARNING , " Unable to obtain lock \n " ) ;
return NULL ;
}
2004-12-11 03:50:19 +00:00
e = pbx_find_extension ( c , NULL , context , exten , PRIORITY_HINT , NULL , " " , HELPER_EXISTS , incstack , & stacklen , & status , & sw , & data , & foundcontext ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2003-03-30 22:55:42 +00:00
return e ;
}
static int ast_extension_state2 ( struct ast_exten * e )
{
2004-07-17 02:25:53 +00:00
char hint [ AST_MAX_EXTENSION ] = " " ;
char * cur , * rest ;
int res = - 1 ;
int allunavailable = 1 , allbusy = 1 , allfree = 1 ;
int busy = 0 ;
2003-03-30 22:55:42 +00:00
2004-07-17 02:25:53 +00:00
strncpy ( hint , ast_get_extension_app ( e ) , sizeof ( hint ) - 1 ) ;
2003-03-30 22:55:42 +00:00
2004-07-17 02:25:53 +00:00
cur = hint ;
do {
rest = strchr ( cur , ' & ' ) ;
if ( rest ) {
* rest = 0 ;
rest + + ;
}
2003-03-30 22:55:42 +00:00
2004-07-17 02:25:53 +00:00
res = ast_device_state ( cur ) ;
switch ( res ) {
case AST_DEVICE_NOT_INUSE :
allunavailable = 0 ;
allbusy = 0 ;
break ;
case AST_DEVICE_INUSE :
return AST_EXTENSION_INUSE ;
case AST_DEVICE_BUSY :
allunavailable = 0 ;
allfree = 0 ;
busy = 1 ;
break ;
case AST_DEVICE_UNAVAILABLE :
case AST_DEVICE_INVALID :
allbusy = 0 ;
allfree = 0 ;
break ;
default :
allunavailable = 0 ;
allbusy = 0 ;
allfree = 0 ;
}
cur = rest ;
} while ( cur ) ;
if ( allfree )
2003-04-06 19:10:24 +00:00
return AST_EXTENSION_NOT_INUSE ;
2004-07-17 02:25:53 +00:00
if ( allbusy )
2003-04-06 19:10:24 +00:00
return AST_EXTENSION_BUSY ;
2004-07-17 02:25:53 +00:00
if ( allunavailable )
2003-04-06 19:10:24 +00:00
return AST_EXTENSION_UNAVAILABLE ;
2004-07-17 02:25:53 +00:00
if ( busy )
2003-04-06 19:10:24 +00:00
return AST_EXTENSION_INUSE ;
2004-07-17 02:25:53 +00:00
return AST_EXTENSION_NOT_INUSE ;
2003-03-30 22:55:42 +00:00
}
int ast_extension_state ( struct ast_channel * c , char * context , char * exten )
{
2004-05-09 07:19:00 +00:00
struct ast_exten * e ;
2003-03-30 22:55:42 +00:00
2004-05-09 07:19:00 +00:00
e = ast_hint_extension ( c , context , exten ) ;
if ( ! e )
return - 1 ;
2003-03-30 22:55:42 +00:00
2004-05-09 07:19:00 +00:00
return ast_extension_state2 ( e ) ;
2003-03-30 22:55:42 +00:00
}
2003-04-06 18:19:51 +00:00
int ast_device_state_changed ( const char * fmt , . . . )
2003-03-30 22:55:42 +00:00
{
2004-07-14 07:44:19 +00:00
struct ast_hint * list ;
struct ast_state_cb * cblist ;
2004-11-13 22:44:33 +00:00
struct ast_devstate_cb * devcb ;
2004-07-14 07:44:19 +00:00
char hint [ AST_MAX_EXTENSION ] = " " ;
char device [ AST_MAX_EXTENSION ] ;
char * cur , * rest ;
int state ;
2003-04-06 18:19:51 +00:00
2004-07-14 07:44:19 +00:00
va_list ap ;
2003-04-06 19:10:24 +00:00
2004-07-14 07:44:19 +00:00
va_start ( ap , fmt ) ;
vsnprintf ( device , sizeof ( device ) , fmt , ap ) ;
va_end ( ap ) ;
2003-03-30 22:55:42 +00:00
2004-07-14 07:44:19 +00:00
rest = strchr ( device , ' - ' ) ;
if ( rest ) {
2003-03-30 22:55:42 +00:00
* rest = 0 ;
2004-07-14 07:44:19 +00:00
}
2003-03-30 22:55:42 +00:00
2004-11-13 22:44:33 +00:00
state = ast_device_state ( device ) ;
2004-07-14 07:44:19 +00:00
ast_mutex_lock ( & hintlock ) ;
2004-11-13 22:44:33 +00:00
devcb = devcbs ;
while ( devcb ) {
if ( devcb - > callback )
devcb - > callback ( device , state , devcb - > data ) ;
devcb = devcb - > next ;
}
2004-07-14 07:44:19 +00:00
list = hints ;
while ( list ) {
strncpy ( hint , ast_get_extension_app ( list - > exten ) , sizeof ( hint ) - 1 ) ;
cur = hint ;
do {
rest = strchr ( cur , ' & ' ) ;
if ( rest ) {
* rest = 0 ;
rest + + ;
}
if ( ! strcmp ( cur , device ) ) {
2004-07-17 02:25:53 +00:00
/* Found extension execute callbacks */
2004-07-14 07:44:19 +00:00
state = ast_extension_state2 ( list - > exten ) ;
if ( ( state ! = - 1 ) & & ( state ! = list - > laststate ) ) {
2004-07-17 02:25:53 +00:00
/* For general callbacks */
2004-07-14 07:44:19 +00:00
cblist = statecbs ;
while ( cblist ) {
cblist - > callback ( list - > exten - > parent - > name , list - > exten - > exten , state , cblist - > data ) ;
cblist = cblist - > next ;
}
2004-07-17 02:25:53 +00:00
/* For extension callbacks */
2004-07-14 07:44:19 +00:00
cblist = list - > callbacks ;
while ( cblist ) {
cblist - > callback ( list - > exten - > parent - > name , list - > exten - > exten , state , cblist - > data ) ;
cblist = cblist - > next ;
}
list - > laststate = state ;
}
break ;
}
cur = rest ;
} while ( cur ) ;
list = list - > next ;
}
ast_mutex_unlock ( & hintlock ) ;
return 1 ;
2003-03-30 22:55:42 +00:00
}
2004-11-13 22:44:33 +00:00
int ast_devstate_add ( ast_devstate_cb_type callback , void * data )
{
struct ast_devstate_cb * devcb ;
devcb = malloc ( sizeof ( struct ast_devstate_cb ) ) ;
if ( devcb ) {
memset ( devcb , 0 , sizeof ( struct ast_devstate_cb ) ) ;
ast_mutex_lock ( & hintlock ) ;
devcb - > data = data ;
devcb - > callback = callback ;
devcb - > next = devcbs ;
devcbs = devcb ;
ast_mutex_unlock ( & hintlock ) ;
}
return 0 ;
}
void ast_devstate_del ( ast_devstate_cb_type callback , void * data )
{
struct ast_devstate_cb * devcb , * prev = NULL , * next ;
ast_mutex_lock ( & hintlock ) ;
devcb = devcbs ;
while ( devcb ) {
next = devcb - > next ;
if ( ( devcb - > data = = data ) & & ( devcb - > callback = = callback ) ) {
if ( prev )
prev - > next = next ;
else
devcbs = next ;
free ( devcb ) ;
} else
prev = devcb ;
devcb = next ;
}
ast_mutex_unlock ( & hintlock ) ;
}
2004-10-03 04:19:59 +00:00
int ast_extension_state_add ( const char * context , const char * exten ,
2003-04-06 18:19:51 +00:00
ast_state_cb_type callback , void * data )
2003-03-30 22:55:42 +00:00
{
2004-07-17 02:25:53 +00:00
struct ast_hint * list ;
struct ast_state_cb * cblist ;
struct ast_exten * e ;
2003-03-30 22:55:42 +00:00
2004-07-17 02:25:53 +00:00
/* No context and extension add callback to statecbs list */
if ( ! context & & ! exten ) {
ast_mutex_lock ( & hintlock ) ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
cblist = statecbs ;
while ( cblist ) {
if ( cblist - > callback = = callback ) {
cblist - > data = data ;
ast_mutex_unlock ( & hintlock ) ;
}
cblist = cblist - > next ;
}
/* Now inserts the callback */
cblist = malloc ( sizeof ( struct ast_state_cb ) ) ;
if ( ! cblist ) {
ast_mutex_unlock ( & hintlock ) ;
return - 1 ;
}
memset ( cblist , 0 , sizeof ( struct ast_state_cb ) ) ;
cblist - > id = 0 ;
cblist - > callback = callback ;
2003-04-06 18:19:51 +00:00
cblist - > data = data ;
2004-07-17 02:25:53 +00:00
cblist - > next = statecbs ;
statecbs = cblist ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & hintlock ) ;
2004-07-17 02:25:53 +00:00
return 0 ;
}
if ( ! context | | ! exten )
return - 1 ;
/* This callback type is for only one hint */
e = ast_hint_extension ( NULL , context , exten ) ;
if ( ! e ) {
return - 1 ;
2003-04-06 18:19:51 +00:00
}
2004-07-17 02:25:53 +00:00
ast_mutex_lock ( & hintlock ) ;
list = hints ;
while ( list ) {
if ( list - > exten = = e )
break ;
list = list - > next ;
}
if ( ! list ) {
ast_mutex_unlock ( & hintlock ) ;
return - 1 ;
}
2003-04-06 18:19:51 +00:00
/* Now inserts the callback */
cblist = malloc ( sizeof ( struct ast_state_cb ) ) ;
if ( ! cblist ) {
2004-07-17 02:25:53 +00:00
ast_mutex_unlock ( & hintlock ) ;
return - 1 ;
2003-04-06 18:19:51 +00:00
}
memset ( cblist , 0 , sizeof ( struct ast_state_cb ) ) ;
2004-07-17 02:25:53 +00:00
cblist - > id = stateid + + ;
2003-04-06 18:19:51 +00:00
cblist - > callback = callback ;
cblist - > data = data ;
2004-07-17 02:25:53 +00:00
cblist - > next = list - > callbacks ;
list - > callbacks = cblist ;
2003-04-06 18:19:51 +00:00
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & hintlock ) ;
2004-07-17 02:25:53 +00:00
return cblist - > id ;
2003-03-30 22:55:42 +00:00
}
2003-04-06 18:19:51 +00:00
int ast_extension_state_del ( int id , ast_state_cb_type callback )
{
2004-07-17 02:25:53 +00:00
struct ast_hint * list ;
struct ast_state_cb * cblist , * cbprev ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
if ( ! id & & ! callback )
return - 1 ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
ast_mutex_lock ( & hintlock ) ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
/* id is zero is a callback without extension */
if ( ! id ) {
cbprev = NULL ;
cblist = statecbs ;
while ( cblist ) {
if ( cblist - > callback = = callback ) {
if ( ! cbprev )
statecbs = cblist - > next ;
else
cbprev - > next = cblist - > next ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
free ( cblist ) ;
ast_mutex_unlock ( & hintlock ) ;
return 0 ;
}
cbprev = cblist ;
cblist = cblist - > next ;
}
ast_mutex_lock ( & hintlock ) ;
return - 1 ;
2003-04-06 18:19:51 +00:00
}
2004-07-17 02:25:53 +00:00
/* id greater than zero is a callback with extension */
list = hints ;
while ( list ) {
cblist = list - > callbacks ;
cbprev = NULL ;
while ( cblist ) {
if ( cblist - > id = = id ) {
if ( ! cbprev )
list - > callbacks = cblist - > next ;
else
cbprev - > next = cblist - > next ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
free ( cblist ) ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
ast_mutex_unlock ( & hintlock ) ;
return 0 ;
}
cbprev = cblist ;
cblist = cblist - > next ;
}
list = list - > next ;
2003-04-06 18:19:51 +00:00
}
2004-07-17 02:25:53 +00:00
ast_mutex_unlock ( & hintlock ) ;
return - 1 ;
2003-04-06 18:19:51 +00:00
}
static int ast_add_hint ( struct ast_exten * e )
{
2004-07-17 02:25:53 +00:00
struct ast_hint * list ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
if ( ! e )
return - 1 ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
ast_mutex_lock ( & hintlock ) ;
list = hints ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
/* Search if hint exists, do nothing */
while ( list ) {
if ( list - > exten = = e ) {
ast_mutex_unlock ( & hintlock ) ;
return - 1 ;
}
list = list - > next ;
}
list = malloc ( sizeof ( struct ast_hint ) ) ;
if ( ! list ) {
ast_mutex_unlock ( & hintlock ) ;
return - 1 ;
2003-04-06 18:19:51 +00:00
}
2004-07-17 02:25:53 +00:00
/* Initialize and insert new item */
memset ( list , 0 , sizeof ( struct ast_hint ) ) ;
list - > exten = e ;
list - > laststate = ast_extension_state2 ( e ) ;
list - > next = hints ;
hints = list ;
2003-04-06 18:19:51 +00:00
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & hintlock ) ;
2004-07-17 02:25:53 +00:00
return 0 ;
2003-04-06 18:19:51 +00:00
}
static int ast_change_hint ( struct ast_exten * oe , struct ast_exten * ne )
{
2004-07-17 02:25:53 +00:00
struct ast_hint * list ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
ast_mutex_lock ( & hintlock ) ;
list = hints ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
while ( list ) {
if ( list - > exten = = oe ) {
list - > exten = ne ;
ast_mutex_unlock ( & hintlock ) ;
return 0 ;
}
list = list - > next ;
2003-04-06 18:19:51 +00:00
}
2004-07-17 02:25:53 +00:00
ast_mutex_unlock ( & hintlock ) ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
return - 1 ;
2003-04-06 18:19:51 +00:00
}
static int ast_remove_hint ( struct ast_exten * e )
2003-03-30 22:55:42 +00:00
{
2004-07-17 02:25:53 +00:00
/* Cleanup the Notifys if hint is removed */
struct ast_hint * list , * prev = NULL ;
struct ast_state_cb * cblist , * cbprev ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
if ( ! e )
return - 1 ;
2003-03-30 22:55:42 +00:00
2004-07-17 02:25:53 +00:00
ast_mutex_lock ( & hintlock ) ;
list = hints ;
while ( list ) {
if ( list - > exten = = e ) {
cbprev = NULL ;
cblist = list - > callbacks ;
while ( cblist ) {
/* Notify with -1 and remove all callbacks */
cbprev = cblist ;
cblist = cblist - > next ;
cbprev - > callback ( list - > exten - > parent - > name , list - > exten - > exten , - 1 , cbprev - > data ) ;
free ( cbprev ) ;
}
list - > callbacks = NULL ;
if ( ! prev )
hints = list - > next ;
else
prev - > next = list - > next ;
free ( list ) ;
2003-04-06 18:19:51 +00:00
2004-07-17 02:25:53 +00:00
ast_mutex_unlock ( & hintlock ) ;
return 0 ;
} else {
prev = list ;
list = list - > next ;
}
}
2003-03-30 22:55:42 +00:00
2004-07-17 02:25:53 +00:00
ast_mutex_unlock ( & hintlock ) ;
return - 1 ;
2003-03-30 22:55:42 +00:00
}
2004-10-03 04:19:59 +00:00
int ast_get_hint ( char * hint , int hintsize , struct ast_channel * c , const char * context , const char * exten )
2003-03-30 22:55:42 +00:00
{
struct ast_exten * e ;
e = ast_hint_extension ( c , context , exten ) ;
if ( e ) {
2004-07-14 07:44:19 +00:00
strncpy ( hint , ast_get_extension_app ( e ) , hintsize - 1 ) ;
2003-03-30 22:55:42 +00:00
return - 1 ;
}
return 0 ;
}
2004-10-03 04:19:59 +00:00
int ast_exists_extension ( struct ast_channel * c , const char * context , const char * exten , int priority , const char * callerid )
1999-12-04 20:45:45 +00:00
{
2004-10-03 16:15:44 +00:00
return pbx_extension_helper ( c , NULL , context , exten , priority , NULL , callerid , HELPER_EXISTS ) ;
1999-12-04 20:45:45 +00:00
}
2004-10-03 04:19:59 +00:00
int ast_findlabel_extension ( struct ast_channel * c , const char * context , const char * exten , const char * label , const char * callerid )
2000-01-07 10:54:40 +00:00
{
2004-10-03 16:15:44 +00:00
return pbx_extension_helper ( c , NULL , context , exten , 0 , label , callerid , HELPER_FINDLABEL ) ;
}
int ast_findlabel_extension2 ( struct ast_channel * c , struct ast_context * con , const char * exten , const char * label , const char * callerid )
{
return pbx_extension_helper ( c , con , NULL , exten , 0 , label , callerid , HELPER_FINDLABEL ) ;
2000-01-07 10:54:40 +00:00
}
2004-10-03 04:19:59 +00:00
int ast_canmatch_extension ( struct ast_channel * c , const char * context , const char * exten , int priority , const char * callerid )
2003-02-02 19:04:14 +00:00
{
2004-10-03 16:15:44 +00:00
return pbx_extension_helper ( c , NULL , context , exten , priority , NULL , callerid , HELPER_CANMATCH ) ;
2003-02-02 19:04:14 +00:00
}
2004-10-03 04:19:59 +00:00
int ast_matchmore_extension ( struct ast_channel * c , const char * context , const char * exten , int priority , const char * callerid )
1999-12-04 20:45:45 +00:00
{
2004-10-03 16:15:44 +00:00
return pbx_extension_helper ( c , NULL , context , exten , priority , NULL , callerid , HELPER_MATCHMORE ) ;
2004-10-03 04:19:59 +00:00
}
int ast_spawn_extension ( struct ast_channel * c , const char * context , const char * exten , int priority , const char * callerid )
{
2004-10-03 16:15:44 +00:00
return pbx_extension_helper ( c , NULL , context , exten , priority , NULL , callerid , HELPER_SPAWN ) ;
1999-12-04 20:45:45 +00:00
}
2004-10-24 02:53:24 +00:00
int ast_exec_extension ( struct ast_channel * c , const char * context , const char * exten , int priority , const char * callerid )
{
return pbx_extension_helper ( c , NULL , context , exten , priority , NULL , callerid , HELPER_EXEC ) ;
}
2001-03-30 18:47:35 +00:00
int ast_pbx_run ( struct ast_channel * c )
1999-12-04 20:45:45 +00:00
{
int firstpass = 1 ;
char digit ;
char exten [ 256 ] ;
int pos ;
int waittime ;
2000-01-24 07:14:18 +00:00
int res = 0 ;
2001-03-30 18:47:35 +00:00
/* A little initial setup here */
if ( c - > pbx )
2002-06-21 01:40:13 +00:00
ast_log ( LOG_WARNING , " %s already has PBX structure?? \n " , c - > name ) ;
2001-03-30 18:47:35 +00:00
c - > pbx = malloc ( sizeof ( struct ast_pbx ) ) ;
if ( ! c - > pbx ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
2001-03-30 18:47:35 +00:00
return - 1 ;
}
2001-11-24 15:15:01 +00:00
if ( c - > amaflags ) {
2004-10-15 17:51:37 +00:00
if ( ! c - > cdr ) {
2001-11-24 15:15:01 +00:00
c - > cdr = ast_cdr_alloc ( ) ;
if ( ! c - > cdr ) {
ast_log ( LOG_WARNING , " Unable to create Call Detail Record \n " ) ;
free ( c - > pbx ) ;
return - 1 ;
}
ast_cdr_init ( c - > cdr , c ) ;
}
}
2001-03-30 18:47:35 +00:00
memset ( c - > pbx , 0 , sizeof ( struct ast_pbx ) ) ;
/* Set reasonable defaults */
c - > pbx - > rtimeout = 10 ;
c - > pbx - > dtimeout = 5 ;
1999-12-04 20:45:45 +00:00
/* Start by trying whatever the channel is set to */
2004-10-02 00:58:31 +00:00
if ( ! ast_exists_extension ( c , c - > context , c - > exten , c - > priority , c - > cid . cid_num ) ) {
2003-02-02 19:04:14 +00:00
/* JK02: If not successfull fall back to 's' */
2004-09-01 18:29:43 +00:00
if ( option_verbose > 1 )
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 ) ;
2001-11-24 15:15:01 +00:00
strncpy ( c - > exten , " s " , sizeof ( c - > exten ) - 1 ) ;
2004-10-02 00:58:31 +00:00
if ( ! ast_exists_extension ( c , c - > context , c - > exten , c - > priority , c - > cid . cid_num ) ) {
2003-02-02 19:04:14 +00:00
/* JK02: And finally back to default if everything else failed */
2004-09-01 18:29:43 +00:00
if ( option_verbose > 1 )
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 ) ;
2003-02-02 19:04:14 +00:00
strncpy ( c - > context , " default " , sizeof ( c - > context ) - 1 ) ;
}
1999-12-04 20:45:45 +00:00
c - > priority = 1 ;
}
2004-10-15 17:51:37 +00:00
if ( c - > cdr & & ! c - > cdr - > start . tv_sec & & ! c - > cdr - > start . tv_usec )
2001-11-24 15:15:01 +00:00
ast_cdr_start ( c - > cdr ) ;
1999-12-04 20:45:45 +00:00
for ( ; ; ) {
pos = 0 ;
digit = 0 ;
2004-10-02 00:58:31 +00:00
while ( ast_exists_extension ( c , c - > context , c - > exten , c - > priority , c - > cid . cid_num ) ) {
2000-01-24 07:14:18 +00:00
memset ( exten , 0 , sizeof ( exten ) ) ;
2004-10-02 00:58:31 +00:00
if ( ( res = ast_spawn_extension ( c , c - > context , c - > exten , c - > priority , c - > cid . cid_num ) ) ) {
1999-12-04 20:45:45 +00:00
/* Something bad happened, or a hangup has been requested. */
2003-03-02 19:52:23 +00:00
if ( ( ( res > = ' 0 ' ) & & ( res < = ' 9 ' ) ) | | ( ( res > = ' A ' ) & & ( res < = ' F ' ) ) | |
( res = = ' * ' ) | | ( res = = ' # ' ) ) {
2003-02-02 19:04:14 +00:00
ast_log ( LOG_DEBUG , " Oooh, got something to jump out with ('%c')! \n " , res ) ;
2003-03-27 02:57:17 +00:00
memset ( exten , 0 , sizeof ( exten ) ) ;
pos = 0 ;
2003-02-14 06:00:11 +00:00
exten [ pos + + ] = digit = res ;
2003-02-02 19:04:14 +00:00
break ;
}
2000-01-24 07:14:18 +00:00
switch ( res ) {
case AST_PBX_KEEPALIVE :
if ( option_debug )
ast_log ( LOG_DEBUG , " Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s' \n " , c - > context , c - > exten , c - > priority , c - > name ) ;
else if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s' \n " , c - > context , c - > exten , c - > priority , c - > name ) ;
2002-09-11 17:09:48 +00:00
goto out ;
break ;
2000-01-24 07:14:18 +00:00
default :
if ( option_debug )
ast_log ( LOG_DEBUG , " Spawn extension (%s,%s,%d) exited non-zero on '%s' \n " , c - > context , c - > exten , c - > priority , c - > name ) ;
else if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Spawn extension (%s, %s, %d) exited non-zero on '%s' \n " , c - > context , c - > exten , c - > priority , c - > name ) ;
2002-09-11 17:09:48 +00:00
if ( c - > _softhangup = = AST_SOFTHANGUP_ASYNCGOTO ) {
c - > _softhangup = 0 ;
break ;
}
2003-03-07 06:00:13 +00:00
/* atimeout */
if ( c - > _softhangup = = AST_SOFTHANGUP_TIMEOUT ) {
break ;
}
2004-02-02 01:13:00 +00:00
if ( c - > cdr ) {
ast_cdr_update ( c ) ;
}
2002-09-11 17:09:48 +00:00
goto out ;
2000-01-24 07:14:18 +00:00
}
1999-12-04 20:45:45 +00:00
}
2004-10-02 00:58:31 +00:00
if ( ( c - > _softhangup = = AST_SOFTHANGUP_TIMEOUT ) & & ( ast_exists_extension ( c , c - > context , " T " , 1 , c - > cid . cid_num ) ) ) {
2003-03-07 06:00:13 +00:00
strncpy ( c - > exten , " T " , sizeof ( c - > exten ) - 1 ) ;
/* If the AbsoluteTimeout is not reset to 0, we'll get an infinite loop */
c - > whentohangup = 0 ;
2003-05-22 04:38:46 +00:00
c - > priority = 0 ;
c - > _softhangup & = ~ AST_SOFTHANGUP_TIMEOUT ;
2003-03-07 06:00:13 +00:00
} else if ( c - > _softhangup ) {
2002-09-11 17:09:48 +00:00
ast_log ( LOG_DEBUG , " Extension %s, priority %d returned normally even though call was hung up \n " ,
2001-04-27 15:07:56 +00:00
c - > exten , c - > priority ) ;
goto out ;
}
1999-12-04 20:45:45 +00:00
firstpass = 0 ;
c - > priority + + ;
}
2004-10-02 00:58:31 +00:00
if ( ! ast_exists_extension ( c , c - > context , c - > exten , 1 , c - > cid . cid_num ) ) {
2001-04-27 15:07:56 +00:00
/* It's not a valid extension anymore */
2004-10-02 00:58:31 +00:00
if ( ast_exists_extension ( c , c - > context , " i " , 1 , c - > cid . cid_num ) ) {
2001-04-27 15:07:56 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Sent into invalid extension '%s' in context '%s' on %s \n " , c - > exten , c - > context , c - > name ) ;
2003-06-24 22:25:01 +00:00
pbx_builtin_setvar_helper ( c , " INVALID_EXTEN " , c - > exten ) ;
2001-11-24 15:15:01 +00:00
strncpy ( c - > exten , " i " , sizeof ( c - > exten ) - 1 ) ;
2001-04-27 15:07:56 +00:00
c - > priority = 1 ;
} else {
ast_log ( LOG_WARNING , " Channel '%s' sent into invalid extension '%s' in context '%s', but no invalid handler \n " ,
c - > name , c - > exten , c - > context ) ;
1999-12-04 20:45:45 +00:00
goto out ;
2001-04-27 15:07:56 +00:00
}
2003-03-07 06:00:13 +00:00
} else if ( c - > _softhangup = = AST_SOFTHANGUP_TIMEOUT ) {
/* If we get this far with AST_SOFTHANGUP_TIMEOUT, then we know that the "T" extension is next. */
c - > _softhangup = 0 ;
1999-12-04 20:45:45 +00:00
} else {
2001-04-27 15:07:56 +00:00
/* Done, wait for an extension */
2004-10-16 19:46:02 +00:00
waittime = 0 ;
2001-04-27 15:07:56 +00:00
if ( digit )
waittime = c - > pbx - > dtimeout ;
2004-10-16 19:46:02 +00:00
else if ( ! autofallthrough )
2001-04-27 15:07:56 +00:00
waittime = c - > pbx - > rtimeout ;
2004-10-16 19:46:02 +00:00
if ( waittime ) {
while ( ast_matchmore_extension ( c , c - > context , exten , 1 , c - > cid . cid_num ) ) {
/* As long as we're willing to wait, and as long as it's not defined,
keep reading digits until we can ' t possibly get a right answer anymore . */
digit = ast_waitfordigit ( c , waittime * 1000 ) ;
if ( c - > _softhangup = = AST_SOFTHANGUP_ASYNCGOTO ) {
c - > _softhangup = 0 ;
2001-04-27 15:07:56 +00:00
} else {
2004-10-16 19:46:02 +00:00
if ( ! digit )
/* No entry */
break ;
if ( digit < 0 )
/* Error, maybe a hangup */
goto out ;
exten [ pos + + ] = digit ;
waittime = c - > pbx - > dtimeout ;
2001-04-27 15:07:56 +00:00
}
2004-10-16 19:46:02 +00:00
}
if ( ast_exists_extension ( c , c - > context , exten , 1 , c - > cid . cid_num ) ) {
/* Prepare the next cycle */
strncpy ( c - > exten , exten , sizeof ( c - > exten ) - 1 ) ;
c - > priority = 1 ;
1999-12-04 20:45:45 +00:00
} else {
2004-10-16 19:46:02 +00:00
/* No such extension */
if ( ! ast_strlen_zero ( exten ) ) {
/* An invalid extension */
if ( ast_exists_extension ( c , c - > context , " i " , 1 , c - > cid . cid_num ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Invalid extension '%s' in context '%s' on %s \n " , exten , c - > context , c - > name ) ;
pbx_builtin_setvar_helper ( c , " INVALID_EXTEN " , exten ) ;
strncpy ( c - > exten , " i " , sizeof ( c - > exten ) - 1 ) ;
c - > priority = 1 ;
} else {
ast_log ( LOG_WARNING , " Invalid extension '%s', but no rule 'i' in context '%s' \n " , exten , c - > context ) ;
goto out ;
}
2001-04-27 15:07:56 +00:00
} else {
2004-10-16 19:46:02 +00:00
/* A simple timeout */
if ( ast_exists_extension ( c , c - > context , " t " , 1 , c - > cid . cid_num ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Timeout on %s \n " , c - > name ) ;
strncpy ( c - > exten , " t " , sizeof ( c - > exten ) - 1 ) ;
c - > priority = 1 ;
} else {
ast_log ( LOG_WARNING , " Timeout, but no rule 't' in context '%s' \n " , c - > context ) ;
goto out ;
}
}
}
if ( c - > cdr ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_2 " CDR updated on %s \n " , c - > name ) ;
ast_cdr_update ( c ) ;
}
} else {
if ( option_verbose > 0 ) {
char * status ;
status = pbx_builtin_getvar_helper ( c , " DIALSTATUS " ) ;
if ( ! status )
status = " UNKNOWN " ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_2 " Auto fallthrough, channel '%s' status is '%s' \n " , c - > name , status ) ;
if ( ! strcasecmp ( status , " CONGESTION " ) )
res = pbx_builtin_congestion ( c , " 10 " ) ;
else if ( ! strcasecmp ( status , " CHANUNAVAIL " ) )
res = pbx_builtin_congestion ( c , " 10 " ) ;
else if ( ! strcasecmp ( status , " BUSY " ) )
res = pbx_builtin_busy ( c , " 10 " ) ;
goto out ;
}
2001-04-27 15:07:56 +00:00
}
1999-12-04 20:45:45 +00:00
}
}
if ( firstpass )
ast_log ( LOG_WARNING , " Don't know what to do with '%s' \n " , c - > name ) ;
out :
2004-10-02 00:58:31 +00:00
if ( ( res ! = AST_PBX_KEEPALIVE ) & & ast_exists_extension ( c , c - > context , " h " , 1 , c - > cid . cid_num ) ) {
2004-07-14 07:44:19 +00:00
c - > exten [ 0 ] = ' h ' ;
c - > exten [ 1 ] = ' \0 ' ;
2002-06-21 01:40:13 +00:00
c - > priority = 1 ;
2004-10-02 00:58:31 +00:00
while ( ast_exists_extension ( c , c - > context , c - > exten , c - > priority , c - > cid . cid_num ) ) {
if ( ( res = ast_spawn_extension ( c , c - > context , c - > exten , c - > priority , c - > cid . cid_num ) ) ) {
2002-06-21 01:40:13 +00:00
/* Something bad happened, or a hangup has been requested. */
if ( option_debug )
ast_log ( LOG_DEBUG , " Spawn extension (%s,%s,%d) exited non-zero on '%s' \n " , c - > context , c - > exten , c - > priority , c - > name ) ;
else if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Spawn extension (%s, %s, %d) exited non-zero on '%s' \n " , c - > context , c - > exten , c - > priority , c - > name ) ;
break ;
}
c - > priority + + ;
}
}
1999-12-04 20:45:45 +00:00
pbx_destroy ( c - > pbx ) ;
c - > pbx = NULL ;
2000-01-24 07:14:18 +00:00
if ( res ! = AST_PBX_KEEPALIVE )
ast_hangup ( c ) ;
2001-03-30 18:47:35 +00:00
return 0 ;
}
static void * pbx_thread ( void * data )
{
/* Oh joyeous kernel, we're a new thread, with nothing to do but
answer this channel and get it going . The setjmp stuff is fairly
confusing , but necessary to get smooth transitions between
the execution of different applications ( without the use of
additional threads ) */
struct ast_channel * c = data ;
ast_pbx_run ( c ) ;
1999-12-04 20:45:45 +00:00
pthread_exit ( NULL ) ;
2001-03-30 18:47:35 +00:00
return NULL ;
1999-12-04 20:45:45 +00:00
}
int ast_pbx_start ( struct ast_channel * c )
{
pthread_t t ;
2001-04-27 15:07:56 +00:00
pthread_attr_t attr ;
1999-12-04 20:45:45 +00:00
if ( ! c ) {
ast_log ( LOG_WARNING , " Asked to start thread on NULL channel? \n " ) ;
return - 1 ;
}
2002-09-11 17:09:48 +00:00
1999-12-04 20:45:45 +00:00
/* Start a new thread, and get something handling this channel. */
2001-04-27 15:07:56 +00:00
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2004-08-08 17:15:02 +00:00
if ( ast_pthread_create ( & t , & attr , pbx_thread , c ) ) {
1999-12-04 20:45:45 +00:00
ast_log ( LOG_WARNING , " Failed to create new channel thread \n " ) ;
return - 1 ;
}
return 0 ;
}
2001-09-28 21:20:52 +00:00
2004-10-16 19:46:02 +00:00
int pbx_set_autofallthrough ( int newval )
{
int oldval ;
oldval = autofallthrough ;
if ( oldval ! = newval )
autofallthrough = newval ;
return oldval ;
}
2001-09-28 21:20:52 +00:00
/*
2004-07-17 02:25:53 +00:00
* This function locks contexts list by & conlist , search for the right context
2001-09-28 21:20:52 +00:00
* structure , leave context list locked and call ast_context_remove_include2
* which removes include , unlock contexts list and return . . .
*/
2004-10-03 04:19:59 +00:00
int ast_context_remove_include ( const char * context , const char * include , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_context * c ;
if ( ast_lock_contexts ( ) ) return - 1 ;
/* walk contexts and search for the right one ...*/
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
/* we found one ... */
if ( ! strcmp ( ast_get_context_name ( c ) , context ) ) {
int ret ;
/* remove include from this context ... */
ret = ast_context_remove_include2 ( c , include , registrar ) ;
ast_unlock_contexts ( ) ;
/* ... return results */
return ret ;
}
c = ast_walk_contexts ( c ) ;
}
/* we can't find the right one context */
ast_unlock_contexts ( ) ;
return - 1 ;
}
/*
* When we call this function , & conlock lock must be locked , because when
* we giving * con argument , some process can remove / change this context
* and after that there can be segfault .
*
* This function locks given context , removes include , unlock context and
* return .
*/
2004-10-03 04:19:59 +00:00
int ast_context_remove_include2 ( struct ast_context * con , const char * include , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_include * i , * pi = NULL ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & con - > lock ) ) return - 1 ;
2001-09-28 21:20:52 +00:00
/* walk includes */
i = con - > includes ;
while ( i ) {
/* find our include */
if ( ! strcmp ( i - > name , include ) & &
2004-08-03 06:31:20 +00:00
( ! registrar | | ! strcmp ( i - > registrar , registrar ) ) ) {
2001-09-28 21:20:52 +00:00
/* remove from list */
if ( pi )
pi - > next = i - > next ;
else
con - > includes = i - > next ;
/* free include and return */
free ( i ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return 0 ;
}
pi = i ;
i = i - > next ;
}
/* we can't find the right include */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return - 1 ;
}
/*
* This function locks contexts list by & conlist , search for the rigt context
* structure , leave context list locked and call ast_context_remove_switch2
* which removes switch , unlock contexts list and return . . .
*/
2004-10-03 04:19:59 +00:00
int ast_context_remove_switch ( const char * context , const char * sw , const char * data , const char * registrar )
1999-12-04 20:45:45 +00:00
{
2001-09-28 21:20:52 +00:00
struct ast_context * c ;
if ( ast_lock_contexts ( ) ) return - 1 ;
/* walk contexts and search for the right one ...*/
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
/* we found one ... */
if ( ! strcmp ( ast_get_context_name ( c ) , context ) ) {
int ret ;
/* remove switch from this context ... */
ret = ast_context_remove_switch2 ( c , sw , data , registrar ) ;
ast_unlock_contexts ( ) ;
/* ... return results */
return ret ;
}
c = ast_walk_contexts ( c ) ;
}
/* we can't find the right one context */
ast_unlock_contexts ( ) ;
1999-12-04 20:45:45 +00:00
return - 1 ;
}
2001-09-28 21:20:52 +00:00
/*
* When we call this function , & conlock lock must be locked , because when
* we giving * con argument , some process can remove / change this context
* and after that there can be segfault .
*
* This function locks given context , removes switch , unlock context and
* return .
*/
2004-10-03 04:19:59 +00:00
int ast_context_remove_switch2 ( struct ast_context * con , const char * sw , const char * data , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_sw * i , * pi = NULL ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & con - > lock ) ) return - 1 ;
2001-09-28 21:20:52 +00:00
/* walk switchs */
i = con - > alts ;
while ( i ) {
/* find our switch */
if ( ! strcmp ( i - > name , sw ) & & ! strcmp ( i - > data , data ) & &
2004-08-03 06:31:20 +00:00
( ! registrar | | ! strcmp ( i - > registrar , registrar ) ) ) {
2001-09-28 21:20:52 +00:00
/* remove from list */
if ( pi )
pi - > next = i - > next ;
else
con - > alts = i - > next ;
/* free switch and return */
free ( i ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return 0 ;
}
pi = i ;
i = i - > next ;
}
/* we can't find the right switch */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return - 1 ;
}
/*
* This functions lock contexts list , search for the right context ,
* call ast_context_remove_extension2 , unlock contexts list and return .
* In this function we are using
*/
2004-10-03 04:19:59 +00:00
int ast_context_remove_extension ( const char * context , const char * extension , int priority , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_context * c ;
if ( ast_lock_contexts ( ) ) return - 1 ;
/* walk contexts ... */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
/* ... search for the right one ... */
if ( ! strcmp ( ast_get_context_name ( c ) , context ) ) {
/* ... remove extension ... */
int ret = ast_context_remove_extension2 ( c , extension , priority ,
registrar ) ;
/* ... unlock contexts list and return */
ast_unlock_contexts ( ) ;
return ret ;
}
c = ast_walk_contexts ( c ) ;
}
/* we can't find the right context */
ast_unlock_contexts ( ) ;
return - 1 ;
}
/*
* When do you want to call this function , make sure that & conlock is locked ,
* because some process can handle with your * con context before you lock
* it .
*
* This functionc locks given context , search for the right extension and
* fires out all peer in this extensions with given priority . If priority
* is set to 0 , all peers are removed . After that , unlock context and
* return .
*/
2004-10-03 04:19:59 +00:00
int ast_context_remove_extension2 ( struct ast_context * con , const char * extension , int priority , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_exten * exten , * prev_exten = NULL ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & con - > lock ) ) return - 1 ;
2001-09-28 21:20:52 +00:00
/* go through all extensions in context and search the right one ... */
exten = con - > root ;
while ( exten ) {
/* look for right extension */
if ( ! strcmp ( exten - > exten , extension ) & &
2004-08-03 06:31:20 +00:00
( ! registrar | | ! strcmp ( exten - > registrar , registrar ) ) ) {
2001-09-28 21:20:52 +00:00
struct ast_exten * peer ;
/* should we free all peers in this extension? (priority == 0)? */
if ( priority = = 0 ) {
/* remove this extension from context list */
if ( prev_exten )
prev_exten - > next = exten - > next ;
else
con - > root = exten - > next ;
/* fire out all peers */
peer = exten ;
while ( peer ) {
exten = peer - > peer ;
2003-03-30 22:55:42 +00:00
if ( ! peer - > priority = = PRIORITY_HINT )
2003-04-06 18:19:51 +00:00
ast_remove_hint ( peer ) ;
2001-09-28 21:20:52 +00:00
peer - > datad ( peer - > data ) ;
free ( peer ) ;
peer = exten ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return 0 ;
} else {
/* remove only extension with exten->priority == priority */
struct ast_exten * previous_peer = NULL ;
peer = exten ;
while ( peer ) {
/* is this our extension? */
if ( peer - > priority = = priority & &
2004-08-03 06:31:20 +00:00
( ! registrar | | ! strcmp ( peer - > registrar , registrar ) ) ) {
2001-09-28 21:20:52 +00:00
/* we are first priority extension? */
if ( ! previous_peer ) {
/* exists previous extension here? */
if ( prev_exten ) {
/* yes, so we must change next pointer in
* previous connection to next peer
*/
if ( peer - > peer ) {
prev_exten - > next = peer - > peer ;
peer - > peer - > next = exten - > next ;
} else
prev_exten - > next = exten - > next ;
} else {
/* no previous extension, we are first
* extension , so change con - > root . . .
*/
if ( peer - > peer )
con - > root = peer - > peer ;
else
con - > root = exten - > next ;
}
} else {
/* we are not first priority in extension */
previous_peer - > peer = peer - > peer ;
}
/* now, free whole priority extension */
2003-03-30 22:55:42 +00:00
if ( peer - > priority = = PRIORITY_HINT )
2003-04-06 18:19:51 +00:00
ast_remove_hint ( peer ) ;
2001-09-28 21:20:52 +00:00
peer - > datad ( peer - > data ) ;
free ( peer ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return 0 ;
} else {
/* this is not right extension, skip to next peer */
previous_peer = peer ;
peer = peer - > peer ;
}
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return - 1 ;
}
}
prev_exten = exten ;
exten = exten - > next ;
}
/* we can't find right extension */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return - 1 ;
}
2004-10-03 04:19:59 +00:00
int ast_register_application ( const char * app , int ( * execute ) ( struct ast_channel * , void * ) , const char * synopsis , const char * description )
1999-12-04 20:45:45 +00:00
{
2003-04-27 19:35:06 +00:00
struct ast_app * tmp , * prev , * cur ;
2002-06-21 01:40:13 +00:00
char tmps [ 80 ] ;
2004-10-03 04:19:59 +00:00
int length ;
length = sizeof ( struct ast_app ) ;
length + = strlen ( app ) + 1 ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & applock ) ) {
1999-12-04 20:45:45 +00:00
ast_log ( LOG_ERROR , " Unable to lock application list \n " ) ;
return - 1 ;
}
tmp = apps ;
while ( tmp ) {
if ( ! strcasecmp ( app , tmp - > name ) ) {
ast_log ( LOG_WARNING , " Already have an application '%s' \n " , app ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
1999-12-04 20:45:45 +00:00
return - 1 ;
}
tmp = tmp - > next ;
}
2004-10-03 04:19:59 +00:00
tmp = malloc ( length ) ;
1999-12-04 20:45:45 +00:00
if ( tmp ) {
2004-10-03 04:19:59 +00:00
memset ( tmp , 0 , length ) ;
strcpy ( tmp - > name , app ) ;
1999-12-04 20:45:45 +00:00
tmp - > execute = execute ;
2001-04-27 15:07:56 +00:00
tmp - > synopsis = synopsis ;
tmp - > description = description ;
2003-04-27 19:35:06 +00:00
/* Store in alphabetical order */
cur = apps ;
prev = NULL ;
while ( cur ) {
if ( strcasecmp ( tmp - > name , cur - > name ) < 0 )
break ;
prev = cur ;
cur = cur - > next ;
}
if ( prev ) {
tmp - > next = prev - > next ;
prev - > next = tmp ;
} else {
tmp - > next = apps ;
apps = tmp ;
}
1999-12-04 20:45:45 +00:00
} else {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
1999-12-04 20:45:45 +00:00
return - 1 ;
}
if ( option_verbose > 1 )
2002-06-21 01:40:13 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Registered application '%s' \n " , term_color ( tmps , tmp - > name , COLOR_BRCYAN , 0 , sizeof ( tmps ) ) ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
1999-12-04 20:45:45 +00:00
return 0 ;
}
2001-09-28 21:20:52 +00:00
int ast_register_switch ( struct ast_switch * sw )
2001-04-27 15:07:56 +00:00
{
2001-09-28 21:20:52 +00:00
struct ast_switch * tmp , * prev = NULL ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & switchlock ) ) {
2001-09-28 21:20:52 +00:00
ast_log ( LOG_ERROR , " Unable to lock switch lock \n " ) ;
2001-04-27 15:07:56 +00:00
return - 1 ;
}
2001-09-28 21:20:52 +00:00
tmp = switches ;
2001-04-27 15:07:56 +00:00
while ( tmp ) {
2001-09-28 21:20:52 +00:00
if ( ! strcasecmp ( tmp - > name , sw - > name ) )
break ;
prev = tmp ;
2001-04-27 15:07:56 +00:00
tmp = tmp - > next ;
}
2001-09-28 21:20:52 +00:00
if ( tmp ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & switchlock ) ;
2001-09-28 21:20:52 +00:00
ast_log ( LOG_WARNING , " Switch '%s' already found \n " , sw - > name ) ;
return - 1 ;
}
sw - > next = NULL ;
if ( prev )
prev - > next = sw ;
else
switches = sw ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & switchlock ) ;
2001-09-28 21:20:52 +00:00
return 0 ;
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
void ast_unregister_switch ( struct ast_switch * sw )
2001-04-27 15:07:56 +00:00
{
2001-09-28 21:20:52 +00:00
struct ast_switch * tmp , * prev = NULL ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & switchlock ) ) {
2001-09-28 21:20:52 +00:00
ast_log ( LOG_ERROR , " Unable to lock switch lock \n " ) ;
return ;
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
tmp = switches ;
2001-04-27 15:07:56 +00:00
while ( tmp ) {
2001-09-28 21:20:52 +00:00
if ( tmp = = sw ) {
if ( prev )
prev - > next = tmp - > next ;
else
switches = tmp - > next ;
tmp - > next = NULL ;
break ;
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
prev = tmp ;
2001-04-27 15:07:56 +00:00
tmp = tmp - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & switchlock ) ;
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
/*
* Help for CLI commands . . .
*/
static char show_application_help [ ] =
" Usage: show application <application> [<application> [<application> [...]]] \n "
" Describes a particular application. \n " ;
static char show_applications_help [ ] =
2004-08-27 04:21:09 +00:00
" Usage: show applications [{like|describing} <text>] \n "
" List applications which are currently available. \n "
" If 'like', <text> will be a substring of the app name \n "
" If 'describing', <text> will be a substring of the description \n " ;
2001-09-28 21:20:52 +00:00
static char show_dialplan_help [ ] =
" Usage: show dialplan [exten@][context] \n "
" Show dialplan \n " ;
static char show_switches_help [ ] =
" Usage: show switches \n "
" Show registered switches \n " ;
/*
* IMPLEMENTATION OF CLI FUNCTIONS IS IN THE SAME ORDER AS COMMANDS HELPS
*
*/
/*
* ' show application ' CLI command implementation functions . . .
*/
/*
* There is a possibility to show informations about more than one
* application at one time . You can type ' show application Dial Echo ' and
* you will see informations about these two applications . . .
*/
static char * complete_show_application ( char * line , char * word ,
int pos , int state )
2001-04-27 15:07:56 +00:00
{
2001-09-28 21:20:52 +00:00
struct ast_app * a ;
2001-04-27 15:07:56 +00:00
int which = 0 ;
2001-09-28 21:20:52 +00:00
/* try to lock applications list ... */
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & applock ) ) {
2001-09-28 21:20:52 +00:00
ast_log ( LOG_ERROR , " Unable to lock application list \n " ) ;
2001-04-27 15:07:56 +00:00
return NULL ;
}
2001-09-28 21:20:52 +00:00
/* ... walk all applications ... */
a = apps ;
while ( a ) {
/* ... check if word matches this application ... */
if ( ! strncasecmp ( word , a - > name , strlen ( word ) ) ) {
/* ... if this is right app serve it ... */
if ( + + which > state ) {
char * ret = strdup ( a - > name ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
2001-09-28 21:20:52 +00:00
return ret ;
}
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
a = a - > next ;
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
/* no application match */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
2001-09-28 21:20:52 +00:00
return NULL ;
2001-04-27 15:07:56 +00:00
}
static int handle_show_application ( int fd , int argc , char * argv [ ] )
{
2001-09-28 21:20:52 +00:00
struct ast_app * a ;
2003-11-21 18:38:42 +00:00
int app , no_registered_app = 1 ;
2001-09-28 21:20:52 +00:00
if ( argc < 3 ) return RESULT_SHOWUSAGE ;
/* try to lock applications list ... */
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & applock ) ) {
2001-04-27 15:07:56 +00:00
ast_log ( LOG_ERROR , " Unable to lock application list \n " ) ;
return - 1 ;
}
2001-09-28 21:20:52 +00:00
/* ... go through all applications ... */
a = apps ;
while ( a ) {
/* ... compare this application name with all arguments given
* to ' show application ' command . . . */
for ( app = 2 ; app < argc ; app + + ) {
if ( ! strcasecmp ( a - > name , argv [ app ] ) ) {
2003-11-21 18:38:42 +00:00
/* Maximum number of characters added by terminal coloring is 22 */
char infotitle [ 64 + AST_MAX_APP + 22 ] , syntitle [ 40 ] , destitle [ 40 ] ;
char info [ 64 + AST_MAX_APP ] , * synopsis = NULL , * description = NULL ;
int synopsis_size , description_size ;
2001-09-28 21:20:52 +00:00
no_registered_app = 0 ;
2003-11-21 18:38:42 +00:00
if ( a - > synopsis )
synopsis_size = strlen ( a - > synopsis ) + 23 ;
else
synopsis_size = strlen ( " Not available " ) + 23 ;
synopsis = alloca ( synopsis_size ) ;
if ( a - > description )
description_size = strlen ( a - > description ) + 23 ;
else
description_size = strlen ( " Not available " ) + 23 ;
description = alloca ( description_size ) ;
if ( synopsis & & description ) {
snprintf ( info , 64 + AST_MAX_APP , " \n -= Info about application '%s' =- \n \n " , a - > name ) ;
term_color ( infotitle , info , COLOR_MAGENTA , 0 , 64 + AST_MAX_APP + 22 ) ;
term_color ( syntitle , " [Synopsis]: \n " , COLOR_MAGENTA , 0 , 40 ) ;
term_color ( destitle , " [Description]: \n " , COLOR_MAGENTA , 0 , 40 ) ;
term_color ( synopsis ,
a - > synopsis ? a - > synopsis : " Not available " ,
COLOR_CYAN , 0 , synopsis_size ) ;
term_color ( description ,
a - > description ? a - > description : " Not available " ,
COLOR_CYAN , 0 , description_size ) ;
ast_cli ( fd , " %s%s%s \n \n %s%s \n " , infotitle , syntitle , synopsis , destitle , description ) ;
} else {
/* ... one of our applications, show info ...*/
ast_cli ( fd , " \n -= Info about application '%s' =- \n \n "
" [Synopsis]: \n %s \n \n "
" [Description]: \n %s \n " ,
a - > name ,
a - > synopsis ? a - > synopsis : " Not available " ,
a - > description ? a - > description : " Not available " ) ;
2003-09-27 02:22:18 +00:00
}
2001-09-28 21:20:52 +00:00
}
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
a = a - > next ;
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
2001-09-28 21:20:52 +00:00
/* we found at least one app? no? */
if ( no_registered_app ) {
ast_cli ( fd , " Your application(s) is (are) not registered \n " ) ;
return RESULT_FAILURE ;
}
2001-04-27 15:07:56 +00:00
return RESULT_SUCCESS ;
}
2001-09-28 21:20:52 +00:00
static int handle_show_switches ( int fd , int argc , char * argv [ ] )
2001-04-27 15:07:56 +00:00
{
2001-09-28 21:20:52 +00:00
struct ast_switch * sw ;
if ( ! switches ) {
ast_cli ( fd , " There are no registered alternative switches \n " ) ;
return RESULT_SUCCESS ;
}
/* ... we have applications ... */
ast_cli ( fd , " \n -= Registered Asterisk Alternative Switches =- \n " ) ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & switchlock ) ) {
2001-09-28 21:20:52 +00:00
ast_log ( LOG_ERROR , " Unable to lock switches \n " ) ;
return - 1 ;
}
sw = switches ;
while ( sw ) {
ast_cli ( fd , " %s: %s \n " , sw - > name , sw - > description ) ;
sw = sw - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & switchlock ) ;
2001-09-28 21:20:52 +00:00
return RESULT_SUCCESS ;
}
/*
* ' show applications ' CLI command implementation functions . . .
*/
static int handle_show_applications ( int fd , int argc , char * argv [ ] )
{
struct ast_app * a ;
2004-08-27 04:21:09 +00:00
int like = 0 , describing = 0 ;
2004-12-01 01:28:07 +00:00
int total_match = 0 ; /* Number of matches in like clause */
int total_apps = 0 ; /* Number of apps registered */
2001-09-28 21:20:52 +00:00
/* try to lock applications list ... */
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & applock ) ) {
2001-09-28 21:20:52 +00:00
ast_log ( LOG_ERROR , " Unable to lock application list \n " ) ;
return - 1 ;
}
/* ... have we got at least one application (first)? no? */
2004-08-27 04:21:09 +00:00
if ( ! apps ) {
ast_cli ( fd , " There are no registered applications \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
2001-09-28 21:20:52 +00:00
return - 1 ;
}
2004-08-27 04:21:09 +00:00
/* show applications like <keyword> */
if ( ( argc = = 4 ) & & ( ! strcmp ( argv [ 2 ] , " like " ) ) ) {
like = 1 ;
} else if ( ( argc > 3 ) & & ( ! strcmp ( argv [ 2 ] , " describing " ) ) ) {
describing = 1 ;
}
/* show applications describing <keyword1> [<keyword2>] [...] */
if ( ( ! like ) & & ( ! describing ) ) {
ast_cli ( fd , " -= Registered Asterisk Applications =- \n " ) ;
} else {
ast_cli ( fd , " -= Matching Asterisk Applications =- \n " ) ;
}
2001-09-28 21:20:52 +00:00
/* ... go through all applications ... */
2004-08-27 04:21:09 +00:00
for ( a = apps ; a ; a = a - > next ) {
2001-09-28 21:20:52 +00:00
/* ... show informations about applications ... */
2004-08-27 04:21:09 +00:00
int printapp = 0 ;
2004-12-01 01:28:07 +00:00
total_apps + + ;
2004-08-27 04:21:09 +00:00
if ( like ) {
if ( ast_strcasestr ( a - > name , argv [ 3 ] ) ) {
printapp = 1 ;
2004-12-01 01:28:07 +00:00
total_match + + ;
2004-08-27 04:21:09 +00:00
}
} else if ( describing ) {
if ( a - > description ) {
/* Match all words on command line */
int i ;
printapp = 1 ;
for ( i = 3 ; i < argc ; i + + ) {
if ( ! ast_strcasestr ( a - > description , argv [ i ] ) ) {
printapp = 0 ;
2004-12-01 01:28:07 +00:00
} else {
total_match + + ;
2004-08-27 04:21:09 +00:00
}
}
}
} else {
printapp = 1 ;
}
if ( printapp ) {
ast_cli ( fd , " %20s: %s \n " , a - > name , a - > synopsis ? a - > synopsis : " <Synopsis not available> " ) ;
}
2001-09-28 21:20:52 +00:00
}
2004-12-01 01:28:07 +00:00
if ( ( ! like ) & & ( ! describing ) ) {
ast_cli ( fd , " -= %d Applications Registered =- \n " , total_apps ) ;
} else {
ast_cli ( fd , " -= %d Applications Matching =- \n " , total_match ) ;
}
2001-09-28 21:20:52 +00:00
/* ... unlock and return */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
2001-09-28 21:20:52 +00:00
return RESULT_SUCCESS ;
}
2004-08-27 04:21:09 +00:00
static char * complete_show_applications ( char * line , char * word , int pos , int state )
{
if ( pos = = 2 ) {
if ( ast_strlen_zero ( word ) ) {
switch ( state ) {
case 0 :
return strdup ( " like " ) ;
case 1 :
return strdup ( " describing " ) ;
default :
return NULL ;
}
} else if ( ! strncasecmp ( word , " like " , strlen ( word ) ) ) {
if ( state = = 0 ) {
return strdup ( " like " ) ;
} else {
return NULL ;
}
} else if ( ! strncasecmp ( word , " describing " , strlen ( word ) ) ) {
if ( state = = 0 ) {
return strdup ( " describing " ) ;
} else {
return NULL ;
}
}
}
return NULL ;
}
2001-09-28 21:20:52 +00:00
/*
* ' show dialplan ' CLI command implementation functions . . .
*/
static char * complete_show_dialplan_context ( char * line , char * word , int pos ,
int state )
{
struct ast_context * c ;
int which = 0 ;
2003-04-28 04:18:47 +00:00
/* we are do completion of [exten@]context on second position only */
2001-09-28 21:20:52 +00:00
if ( pos ! = 2 ) return NULL ;
/* try to lock contexts list ... */
if ( ast_lock_contexts ( ) ) {
ast_log ( LOG_ERROR , " Unable to lock context list \n " ) ;
return NULL ;
}
/* ... walk through all contexts ... */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
/* ... word matches context name? yes? ... */
if ( ! strncasecmp ( word , ast_get_context_name ( c ) , strlen ( word ) ) ) {
/* ... for serve? ... */
if ( + + which > state ) {
/* ... yes, serve this context name ... */
char * ret = strdup ( ast_get_context_name ( c ) ) ;
ast_unlock_contexts ( ) ;
return ret ;
}
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
c = ast_walk_contexts ( c ) ;
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
/* ... unlock and return */
ast_unlock_contexts ( ) ;
return NULL ;
}
static int handle_show_dialplan ( int fd , int argc , char * argv [ ] )
{
struct ast_context * c ;
char * exten = NULL , * context = NULL ;
int context_existence = 0 , extension_existence = 0 ;
2004-12-11 03:08:12 +00:00
/* Variables used for different counters */
int total_context = 0 , total_exten = 0 , total_prio = 0 ;
2001-09-28 21:20:52 +00:00
if ( argc ! = 3 & & argc ! = 2 ) return - 1 ;
/* we obtain [exten@]context? if yes, split them ... */
if ( argc = = 3 ) {
char * splitter = argv [ 2 ] ;
/* is there a '@' character? */
if ( strchr ( argv [ 2 ] , ' @ ' ) ) {
/* yes, split into exten & context ... */
exten = strsep ( & splitter , " @ " ) ;
context = splitter ;
2004-05-26 19:24:47 +00:00
/* check for length and change to NULL if ast_strlen_zero() */
2004-05-04 06:34:34 +00:00
if ( ast_strlen_zero ( exten ) ) exten = NULL ;
if ( ast_strlen_zero ( context ) ) context = NULL ;
2001-09-28 21:20:52 +00:00
} else
{
/* no '@' char, only context given */
context = argv [ 2 ] ;
2004-05-04 06:34:34 +00:00
if ( ast_strlen_zero ( context ) ) context = NULL ;
2001-09-28 21:20:52 +00:00
}
}
/* try to lock contexts */
if ( ast_lock_contexts ( ) ) {
2003-09-10 05:24:49 +00:00
ast_log ( LOG_WARNING , " Failed to lock contexts list \n " ) ;
2001-09-28 21:20:52 +00:00
return RESULT_FAILURE ;
}
/* walk all contexts ... */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
/* show this context? */
if ( ! context | |
! strcmp ( ast_get_context_name ( c ) , context ) ) {
context_existence = 1 ;
/* try to lock context before walking in ... */
if ( ! ast_lock_context ( c ) ) {
struct ast_exten * e ;
struct ast_include * i ;
struct ast_ignorepat * ip ;
struct ast_sw * sw ;
char buf [ 256 ] , buf2 [ 256 ] ;
int context_info_printed = 0 ;
/* are we looking for exten too? if yes, we print context
* if we our extension only
*/
if ( ! exten ) {
2004-12-11 03:08:12 +00:00
total_context + + ;
2001-09-28 21:20:52 +00:00
ast_cli ( fd , " [ Context '%s' created by '%s' ] \n " ,
ast_get_context_name ( c ) , ast_get_context_registrar ( c ) ) ;
context_info_printed = 1 ;
}
/* walk extensions ... */
e = ast_walk_context_extensions ( c , NULL ) ;
while ( e ) {
struct ast_exten * p ;
2004-12-28 22:52:40 +00:00
int prio ;
2001-09-28 21:20:52 +00:00
/* looking for extension? is this our extension? */
if ( exten & &
strcmp ( ast_get_extension_name ( e ) , exten ) )
{
/* we are looking for extension and it's not our
* extension , so skip to next extension */
e = ast_walk_context_extensions ( c , e ) ;
continue ;
}
extension_existence = 1 ;
/* may we print context info? */
if ( ! context_info_printed ) {
2004-12-11 03:08:12 +00:00
total_context + + ;
2001-09-28 21:20:52 +00:00
ast_cli ( fd , " [ Context '%s' created by '%s' ] \n " ,
ast_get_context_name ( c ) ,
ast_get_context_registrar ( c ) ) ;
context_info_printed = 1 ;
}
2004-12-11 03:08:12 +00:00
total_prio + + ;
2001-09-28 21:20:52 +00:00
/* write extension name and first peer */
bzero ( buf , sizeof ( buf ) ) ;
snprintf ( buf , sizeof ( buf ) , " '%s' => " ,
ast_get_extension_name ( e ) ) ;
2004-12-28 22:52:40 +00:00
prio = ast_get_extension_priority ( e ) ;
if ( prio = = PRIORITY_HINT ) {
snprintf ( buf2 , sizeof ( buf2 ) ,
" hint: %s " ,
ast_get_extension_app ( e ) ) ;
} else {
snprintf ( buf2 , sizeof ( buf2 ) ,
" %d. %s(%s) " ,
prio ,
ast_get_extension_app ( e ) ,
( char * ) ast_get_extension_app_data ( e ) ) ;
}
2001-09-28 21:20:52 +00:00
ast_cli ( fd , " %-17s %-45s [%s] \n " , buf , buf2 ,
ast_get_extension_registrar ( e ) ) ;
2004-12-11 03:08:12 +00:00
total_exten + + ;
2001-09-28 21:20:52 +00:00
/* walk next extension peers */
p = ast_walk_extension_priorities ( e , e ) ;
while ( p ) {
2004-12-11 03:08:12 +00:00
total_prio + + ;
2001-09-28 21:20:52 +00:00
bzero ( ( void * ) buf2 , sizeof ( buf2 ) ) ;
2004-10-03 04:19:59 +00:00
bzero ( ( void * ) buf , sizeof ( buf ) ) ;
if ( ast_get_extension_label ( p ) )
snprintf ( buf , sizeof ( buf ) , " [%s] " , ast_get_extension_label ( p ) ) ;
2004-12-28 22:52:40 +00:00
prio = ast_get_extension_priority ( p ) ;
if ( prio = = PRIORITY_HINT ) {
snprintf ( buf2 , sizeof ( buf2 ) ,
" hint: %s " ,
ast_get_extension_app ( p ) ) ;
} else {
snprintf ( buf2 , sizeof ( buf2 ) ,
" %d. %s(%s) " ,
prio ,
ast_get_extension_app ( p ) ,
( char * ) ast_get_extension_app_data ( p ) ) ;
}
2001-09-28 21:20:52 +00:00
ast_cli ( fd , " %-17s %-45s [%s] \n " ,
2004-10-03 04:19:59 +00:00
buf , buf2 ,
2001-09-28 21:20:52 +00:00
ast_get_extension_registrar ( p ) ) ;
p = ast_walk_extension_priorities ( e , p ) ;
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
e = ast_walk_context_extensions ( c , e ) ;
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
/* include & ignorepat we all printing if we are not
* looking for exact extension
*/
if ( ! exten ) {
if ( ast_walk_context_extensions ( c , NULL ) )
ast_cli ( fd , " \n " ) ;
/* walk included and write info ... */
i = ast_walk_context_includes ( c , NULL ) ;
while ( i ) {
bzero ( buf , sizeof ( buf ) ) ;
snprintf ( buf , sizeof ( buf ) , " '%s' " ,
ast_get_include_name ( i ) ) ;
ast_cli ( fd , " Include => %-45s [%s] \n " ,
buf , ast_get_include_registrar ( i ) ) ;
i = ast_walk_context_includes ( c , i ) ;
}
/* walk ignore patterns and write info ... */
ip = ast_walk_context_ignorepats ( c , NULL ) ;
while ( ip ) {
bzero ( buf , sizeof ( buf ) ) ;
snprintf ( buf , sizeof ( buf ) , " '%s' " ,
ast_get_ignorepat_name ( ip ) ) ;
ast_cli ( fd , " Ignore pattern => %-45s [%s] \n " ,
buf , ast_get_ignorepat_registrar ( ip ) ) ;
ip = ast_walk_context_ignorepats ( c , ip ) ;
}
sw = ast_walk_context_switches ( c , NULL ) ;
while ( sw ) {
bzero ( buf , sizeof ( buf ) ) ;
snprintf ( buf , sizeof ( buf ) , " '%s/%s' " ,
ast_get_switch_name ( sw ) ,
ast_get_switch_data ( sw ) ) ;
ast_cli ( fd , " Alt. Switch => %-45s [%s] \n " ,
buf , ast_get_switch_registrar ( sw ) ) ;
sw = ast_walk_context_switches ( c , sw ) ;
}
}
ast_unlock_context ( c ) ;
/* if we print something in context, make an empty line */
if ( context_info_printed ) ast_cli ( fd , " \n " ) ;
2001-04-27 15:07:56 +00:00
}
}
2001-09-28 21:20:52 +00:00
c = ast_walk_contexts ( c ) ;
2001-04-27 15:07:56 +00:00
}
2001-09-28 21:20:52 +00:00
ast_unlock_contexts ( ) ;
/* check for input failure and throw some error messages */
if ( context & & ! context_existence ) {
ast_cli ( fd , " There is no existence of '%s' context \n " ,
context ) ;
return RESULT_FAILURE ;
}
if ( exten & & ! extension_existence ) {
if ( context )
ast_cli ( fd , " There is no existence of %s@%s extension \n " ,
exten , context ) ;
else
ast_cli ( fd ,
" There is no existence of '%s' extension in all contexts \n " ,
exten ) ;
return RESULT_FAILURE ;
}
2004-12-11 03:08:12 +00:00
ast_cli ( fd , " -= %d extensions (%d priorities) in %d contexts. =- \n " , total_exten , total_prio , total_context ) ;
2001-09-28 21:20:52 +00:00
/* everything ok */
2001-04-27 15:07:56 +00:00
return RESULT_SUCCESS ;
}
2001-09-28 21:20:52 +00:00
/*
* CLI entries for upper commands . . .
*/
static struct ast_cli_entry show_applications_cli =
{ { " show " , " applications " , NULL } ,
handle_show_applications , " Shows registered applications " ,
2004-08-27 04:21:09 +00:00
show_applications_help , complete_show_applications } ;
2001-09-28 21:20:52 +00:00
static struct ast_cli_entry show_application_cli =
{ { " show " , " application " , NULL } ,
handle_show_application , " Describe a specific application " ,
show_application_help , complete_show_application } ;
static struct ast_cli_entry show_dialplan_cli =
{ { " show " , " dialplan " , NULL } ,
handle_show_dialplan , " Show dialplan " ,
show_dialplan_help , complete_show_dialplan_context } ;
static struct ast_cli_entry show_switches_cli =
{ { " show " , " switches " , NULL } ,
handle_show_switches , " Show alternative switches " ,
show_switches_help , NULL } ;
2001-04-27 15:07:56 +00:00
2004-10-03 04:19:59 +00:00
int ast_unregister_application ( const char * app ) {
1999-12-04 20:45:45 +00:00
struct ast_app * tmp , * tmpl = NULL ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & applock ) ) {
1999-12-04 20:45:45 +00:00
ast_log ( LOG_ERROR , " Unable to lock application list \n " ) ;
return - 1 ;
}
tmp = apps ;
while ( tmp ) {
if ( ! strcasecmp ( app , tmp - > name ) ) {
if ( tmpl )
tmpl - > next = tmp - > next ;
else
apps = tmp - > next ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Unregistered application '%s' \n " , tmp - > name ) ;
2004-08-21 18:49:52 +00:00
free ( tmp ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
1999-12-04 20:45:45 +00:00
return 0 ;
}
tmpl = tmp ;
tmp = tmp - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & applock ) ;
1999-12-04 20:45:45 +00:00
return - 1 ;
}
2004-10-03 04:19:59 +00:00
struct ast_context * ast_context_create ( struct ast_context * * extcontexts , const char * name , const char * registrar )
1999-12-04 20:45:45 +00:00
{
2003-07-14 15:35:21 +00:00
struct ast_context * tmp , * * local_contexts ;
2004-10-03 04:19:59 +00:00
int length ;
length = sizeof ( struct ast_context ) ;
length + = strlen ( name ) + 1 ;
2003-07-14 15:35:21 +00:00
if ( ! extcontexts ) {
local_contexts = & contexts ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & conlock ) ;
2003-07-14 15:35:21 +00:00
} else
local_contexts = extcontexts ;
tmp = * local_contexts ;
1999-12-04 20:45:45 +00:00
while ( tmp ) {
if ( ! strcasecmp ( tmp - > name , name ) ) {
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
1999-12-04 20:45:45 +00:00
ast_log ( LOG_WARNING , " Tried to register context '%s', already in use \n " , name ) ;
2003-07-14 15:35:21 +00:00
if ( ! extcontexts )
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
1999-12-04 20:45:45 +00:00
return NULL ;
}
tmp = tmp - > next ;
}
2004-10-03 04:19:59 +00:00
tmp = malloc ( length ) ;
1999-12-04 20:45:45 +00:00
if ( tmp ) {
2004-10-03 04:19:59 +00:00
memset ( tmp , 0 , length ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_init ( & tmp - > lock ) ;
2004-10-03 04:19:59 +00:00
strcpy ( tmp - > name , name ) ;
1999-12-04 20:45:45 +00:00
tmp - > root = NULL ;
2001-04-27 15:07:56 +00:00
tmp - > registrar = registrar ;
2003-07-14 15:35:21 +00:00
tmp - > next = * local_contexts ;
2001-03-30 18:47:35 +00:00
tmp - > includes = NULL ;
2001-09-28 21:20:52 +00:00
tmp - > ignorepats = NULL ;
2003-07-14 15:35:21 +00:00
* local_contexts = tmp ;
1999-12-04 20:45:45 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Registered context '%s' \n " , tmp - > name ) ;
else if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Registered extension context '%s' \n " , tmp - > name ) ;
} else
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
1999-12-04 20:45:45 +00:00
2003-07-14 15:35:21 +00:00
if ( ! extcontexts )
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
1999-12-04 20:45:45 +00:00
return tmp ;
}
2004-10-03 04:19:59 +00:00
void __ast_context_destroy ( struct ast_context * con , const char * registrar ) ;
2003-07-14 15:35:21 +00:00
2004-10-03 04:19:59 +00:00
void ast_merge_contexts_and_delete ( struct ast_context * * extcontexts , const char * registrar ) {
2003-07-14 15:35:21 +00:00
struct ast_context * tmp , * lasttmp = NULL ;
tmp = * extcontexts ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & conlock ) ;
2003-07-14 17:17:05 +00:00
if ( registrar ) {
2004-04-06 22:17:32 +00:00
__ast_context_destroy ( NULL , registrar ) ;
2003-07-14 17:17:05 +00:00
while ( tmp ) {
lasttmp = tmp ;
tmp = tmp - > next ;
}
} else {
while ( tmp ) {
2004-04-06 22:17:32 +00:00
__ast_context_destroy ( tmp , tmp - > registrar ) ;
2003-07-14 17:17:05 +00:00
lasttmp = tmp ;
tmp = tmp - > next ;
}
2003-07-14 15:35:21 +00:00
}
if ( lasttmp ) {
lasttmp - > next = contexts ;
contexts = * extcontexts ;
* extcontexts = NULL ;
} else
ast_log ( LOG_WARNING , " Requested contexts didn't get merged \n " ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & conlock ) ;
2003-07-14 15:35:21 +00:00
return ;
}
2001-09-28 21:20:52 +00:00
/*
* errno values
* EBUSY - can ' t lock
2003-04-23 19:13:35 +00:00
* ENOENT - no existence of context
2001-09-28 21:20:52 +00:00
*/
2004-10-03 04:19:59 +00:00
int ast_context_add_include ( const char * context , const char * include , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_context * c ;
if ( ast_lock_contexts ( ) ) {
errno = EBUSY ;
return - 1 ;
}
/* walk contexts ... */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
/* ... search for the right one ... */
if ( ! strcmp ( ast_get_context_name ( c ) , context ) ) {
int ret = ast_context_add_include2 ( c , include , registrar ) ;
/* ... unlock contexts list and return */
ast_unlock_contexts ( ) ;
return ret ;
}
c = ast_walk_contexts ( c ) ;
}
/* we can't find the right context */
ast_unlock_contexts ( ) ;
2003-04-23 19:13:35 +00:00
errno = ENOENT ;
2001-09-28 21:20:52 +00:00
return - 1 ;
}
2002-06-21 01:40:13 +00:00
# define FIND_NEXT \
do { \
c = info ; \
while ( * c & & ( * c ! = ' | ' ) ) c + + ; \
2002-09-11 17:09:48 +00:00
if ( * c ) { * c = ' \0 ' ; c + + ; } else c = NULL ; \
2002-06-21 01:40:13 +00:00
} while ( 0 )
2004-11-11 21:23:45 +00:00
static void get_timerange ( struct ast_timing * i , char * times )
2002-06-21 01:40:13 +00:00
{
char * e ;
int x ;
int s1 , s2 ;
int e1 , e2 ;
2004-07-17 02:25:53 +00:00
/* int cth, ctm; */
2003-07-01 20:28:02 +00:00
2004-07-17 02:25:53 +00:00
/* start disabling all times, fill the fields with 0's, as they may contain garbage */
2003-08-07 17:35:08 +00:00
memset ( i - > minmask , 0 , sizeof ( i - > minmask ) ) ;
2003-07-01 20:28:02 +00:00
2002-06-21 01:40:13 +00:00
/* Star is all times */
2004-05-04 06:34:34 +00:00
if ( ast_strlen_zero ( times ) | | ! strcmp ( times , " * " ) ) {
2002-06-21 01:40:13 +00:00
for ( x = 0 ; x < 24 ; x + + )
i - > minmask [ x ] = ( 1 < < 30 ) - 1 ;
return ;
}
/* Otherwise expect a range */
e = strchr ( times , ' - ' ) ;
if ( ! e ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_WARNING , " Time range is not valid. Assuming no restrictions based on time. \n " ) ;
2002-06-21 01:40:13 +00:00
return ;
}
* e = ' \0 ' ;
e + + ;
while ( * e & & ! isdigit ( * e ) ) e + + ;
if ( ! * e ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_WARNING , " Invalid time range. Assuming no restrictions based on time. \n " ) ;
2002-06-21 01:40:13 +00:00
return ;
}
if ( sscanf ( times , " %d:%d " , & s1 , & s2 ) ! = 2 ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_WARNING , " %s isn't a time. Assuming no restrictions based on time. \n " , times ) ;
2002-06-21 01:40:13 +00:00
return ;
}
if ( sscanf ( e , " %d:%d " , & e1 , & e2 ) ! = 2 ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_WARNING , " %s isn't a time. Assuming no restrictions based on time. \n " , e ) ;
2002-06-21 01:40:13 +00:00
return ;
}
2004-01-11 09:19:16 +00:00
2004-01-13 07:48:39 +00:00
# if 1
2002-06-21 01:40:13 +00:00
s1 = s1 * 30 + s2 / 2 ;
if ( ( s1 < 0 ) | | ( s1 > = 24 * 30 ) ) {
2004-03-04 05:23:50 +00:00
ast_log ( LOG_WARNING , " %s isn't a valid start time. Assuming no time. \n " , times ) ;
2002-06-21 01:40:13 +00:00
return ;
}
e1 = e1 * 30 + e2 / 2 ;
2004-03-04 05:23:50 +00:00
if ( ( e1 < 0 ) | | ( e1 > = 24 * 30 ) ) {
ast_log ( LOG_WARNING , " %s isn't a valid end time. Assuming no time. \n " , e ) ;
2002-06-21 01:40:13 +00:00
return ;
}
/* Go through the time and enable each appropriate bit */
2003-08-07 19:21:56 +00:00
for ( x = s1 ; x ! = e1 ; x = ( x + 1 ) % ( 24 * 30 ) ) {
2002-06-21 01:40:13 +00:00
i - > minmask [ x / 30 ] | = ( 1 < < ( x % 30 ) ) ;
}
/* Do the last one */
i - > minmask [ x / 30 ] | = ( 1 < < ( x % 30 ) ) ;
2004-01-11 09:19:16 +00:00
# else
for ( cth = 0 ; cth < 24 ; cth + + ) {
/* Initialize masks to blank */
i - > minmask [ cth ] = 0 ;
for ( ctm = 0 ; ctm < 30 ; ctm + + ) {
if (
/* First hour with more than one hour */
( ( ( cth = = s1 ) & & ( ctm > = s2 ) ) & &
( ( cth < e1 ) ) )
/* Only one hour */
| | ( ( ( cth = = s1 ) & & ( ctm > = s2 ) ) & &
( ( cth = = e1 ) & & ( ctm < = e2 ) ) )
/* In between first and last hours (more than 2 hours) */
| | ( ( cth > s1 ) & &
( cth < e1 ) )
/* Last hour with more than one hour */
| | ( ( cth > s1 ) & &
( ( cth = = e1 ) & & ( ctm < = e2 ) ) )
)
i - > minmask [ cth ] | = ( 1 < < ( ctm / 2 ) ) ;
}
}
# endif
2002-06-21 01:40:13 +00:00
/* All done */
2003-08-07 19:21:56 +00:00
return ;
2002-06-21 01:40:13 +00:00
}
static char * days [ ] =
{
" sun " ,
" mon " ,
" tue " ,
" wed " ,
" thu " ,
" fri " ,
" sat " ,
} ;
static unsigned int get_dow ( char * dow )
{
char * c ;
/* The following line is coincidence, really! */
int s , e , x ;
2002-09-11 17:09:48 +00:00
unsigned int mask ;
2004-07-17 02:25:53 +00:00
2002-06-21 01:40:13 +00:00
/* Check for all days */
2004-05-04 06:34:34 +00:00
if ( ast_strlen_zero ( dow ) | | ! strcmp ( dow , " * " ) )
2002-06-21 01:40:13 +00:00
return ( 1 < < 7 ) - 1 ;
/* Get start and ending days */
c = strchr ( dow , ' - ' ) ;
if ( c ) {
* c = ' \0 ' ;
c + + ;
2002-09-11 17:09:48 +00:00
} else
c = NULL ;
2002-06-21 01:40:13 +00:00
/* Find the start */
s = 0 ;
while ( ( s < 7 ) & & strcasecmp ( dow , days [ s ] ) ) s + + ;
if ( s > = 7 ) {
ast_log ( LOG_WARNING , " Invalid day '%s', assuming none \n " , dow ) ;
return 0 ;
}
if ( c ) {
e = 0 ;
2002-09-11 17:09:48 +00:00
while ( ( e < 7 ) & & strcasecmp ( c , days [ e ] ) ) e + + ;
2002-06-21 01:40:13 +00:00
if ( e > = 7 ) {
ast_log ( LOG_WARNING , " Invalid day '%s', assuming none \n " , c ) ;
return 0 ;
}
} else
e = s ;
mask = 0 ;
2004-07-17 02:25:53 +00:00
for ( x = s ; x ! = e ; x = ( x + 1 ) % 7 ) {
2002-06-21 01:40:13 +00:00
mask | = ( 1 < < x ) ;
}
/* One last one */
mask | = ( 1 < < x ) ;
return mask ;
}
static unsigned int get_day ( char * day )
{
char * c ;
/* The following line is coincidence, really! */
int s , e , x ;
unsigned int mask ;
2004-07-17 02:25:53 +00:00
2002-06-21 01:40:13 +00:00
/* Check for all days */
2004-05-04 06:34:34 +00:00
if ( ast_strlen_zero ( day ) | | ! strcmp ( day , " * " ) ) {
2002-06-21 01:40:13 +00:00
mask = ( 1 < < 30 ) + ( ( 1 < < 30 ) - 1 ) ;
2002-09-11 17:09:48 +00:00
return mask ;
2002-06-21 01:40:13 +00:00
}
/* Get start and ending days */
c = strchr ( day , ' - ' ) ;
if ( c ) {
* c = ' \0 ' ;
c + + ;
}
/* Find the start */
if ( sscanf ( day , " %d " , & s ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid day '%s', assuming none \n " , day ) ;
return 0 ;
}
if ( ( s < 1 ) | | ( s > 31 ) ) {
ast_log ( LOG_WARNING , " Invalid day '%s', assuming none \n " , day ) ;
return 0 ;
}
s - - ;
if ( c ) {
if ( sscanf ( c , " %d " , & e ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid day '%s', assuming none \n " , c ) ;
return 0 ;
}
if ( ( e < 1 ) | | ( e > 31 ) ) {
ast_log ( LOG_WARNING , " Invalid day '%s', assuming none \n " , c ) ;
return 0 ;
}
e - - ;
} else
e = s ;
mask = 0 ;
for ( x = s ; x ! = e ; x = ( x + 1 ) % 31 ) {
mask | = ( 1 < < x ) ;
}
mask | = ( 1 < < x ) ;
return mask ;
}
static char * months [ ] =
{
" jan " ,
" feb " ,
" mar " ,
" apr " ,
" may " ,
" jun " ,
" jul " ,
" aug " ,
" sep " ,
" oct " ,
" nov " ,
" dec " ,
} ;
static unsigned int get_month ( char * mon )
{
char * c ;
/* The following line is coincidence, really! */
int s , e , x ;
unsigned int mask ;
2004-07-17 02:25:53 +00:00
2002-06-21 01:40:13 +00:00
/* Check for all days */
2004-05-04 06:34:34 +00:00
if ( ast_strlen_zero ( mon ) | | ! strcmp ( mon , " * " ) )
2002-06-21 01:40:13 +00:00
return ( 1 < < 12 ) - 1 ;
/* Get start and ending days */
c = strchr ( mon , ' - ' ) ;
if ( c ) {
* c = ' \0 ' ;
c + + ;
}
/* Find the start */
s = 0 ;
while ( ( s < 12 ) & & strcasecmp ( mon , months [ s ] ) ) s + + ;
if ( s > = 12 ) {
ast_log ( LOG_WARNING , " Invalid month '%s', assuming none \n " , mon ) ;
return 0 ;
}
if ( c ) {
e = 0 ;
while ( ( e < 12 ) & & strcasecmp ( mon , months [ e ] ) ) e + + ;
if ( e > = 12 ) {
ast_log ( LOG_WARNING , " Invalid month '%s', assuming none \n " , c ) ;
return 0 ;
}
} else
e = s ;
mask = 0 ;
2004-07-17 02:25:53 +00:00
for ( x = s ; x ! = e ; x = ( x + 1 ) % 12 ) {
2002-06-21 01:40:13 +00:00
mask | = ( 1 < < x ) ;
}
/* One last one */
mask | = ( 1 < < x ) ;
return mask ;
}
2004-11-11 21:23:45 +00:00
int ast_build_timing ( struct ast_timing * i , char * info_in )
2002-06-21 01:40:13 +00:00
{
2004-11-11 21:23:45 +00:00
char info_save [ 256 ] ;
char * info ;
2002-06-21 01:40:13 +00:00
char * c ;
2004-07-17 02:25:53 +00:00
2002-06-21 01:40:13 +00:00
/* Check for empty just in case */
2004-11-11 21:23:45 +00:00
if ( ast_strlen_zero ( info_in ) )
return 0 ;
/* make a copy just in case we were passed a static string */
strncpy ( info_save , info_in , sizeof ( info_save ) ) ;
info = info_save ;
2002-06-21 01:40:13 +00:00
/* Assume everything except time */
i - > monthmask = ( 1 < < 12 ) - 1 ;
i - > daymask = ( 1 < < 30 ) - 1 + ( 1 < < 30 ) ;
i - > dowmask = ( 1 < < 7 ) - 1 ;
2003-02-02 19:04:14 +00:00
/* Avoid using str tok */
2002-06-21 01:40:13 +00:00
FIND_NEXT ;
/* Info has the time range, start with that */
get_timerange ( i , info ) ;
info = c ;
if ( ! info )
2004-11-11 21:23:45 +00:00
return 1 ;
2002-06-21 01:40:13 +00:00
FIND_NEXT ;
/* Now check for day of week */
i - > dowmask = get_dow ( info ) ;
info = c ;
if ( ! info )
2004-11-11 21:23:45 +00:00
return 1 ;
2002-06-21 01:40:13 +00:00
FIND_NEXT ;
/* Now check for the day of the month */
i - > daymask = get_day ( info ) ;
info = c ;
if ( ! info )
2004-11-11 21:23:45 +00:00
return 1 ;
2002-06-21 01:40:13 +00:00
FIND_NEXT ;
/* And finally go for the month */
i - > monthmask = get_month ( info ) ;
2004-11-11 21:23:45 +00:00
return 1 ;
}
int ast_check_timing ( struct ast_timing * i )
{
struct tm tm ;
time_t t ;
time ( & t ) ;
localtime_r ( & t , & tm ) ;
/* If it's not the right month, return */
if ( ! ( i - > monthmask & ( 1 < < tm . tm_mon ) ) ) {
return 0 ;
}
/* If it's not that time of the month.... */
/* Warning, tm_mday has range 1..31! */
if ( ! ( i - > daymask & ( 1 < < ( tm . tm_mday - 1 ) ) ) )
return 0 ;
/* If it's not the right day of the week */
if ( ! ( i - > dowmask & ( 1 < < tm . tm_wday ) ) )
return 0 ;
/* Sanity check the hour just to be safe */
if ( ( tm . tm_hour < 0 ) | | ( tm . tm_hour > 23 ) ) {
ast_log ( LOG_WARNING , " Insane time... \n " ) ;
return 0 ;
}
/* Now the tough part, we calculate if it fits
in the right time based on min / hour */
if ( ! ( i - > minmask [ tm . tm_hour ] & ( 1 < < ( tm . tm_min / 2 ) ) ) )
return 0 ;
/* If we got this far, then we're good */
return 1 ;
2002-06-21 01:40:13 +00:00
}
2001-09-28 21:20:52 +00:00
/*
* errno values
* ENOMEM - out of memory
* EBUSY - can ' t lock
* EEXIST - already included
* EINVAL - there is no existence of context for inclusion
*/
2004-10-03 04:19:59 +00:00
int ast_context_add_include2 ( struct ast_context * con , const char * value ,
const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_include * new_include ;
2002-06-21 01:40:13 +00:00
char * c ;
2001-09-28 21:20:52 +00:00
struct ast_include * i , * il = NULL ; /* include, include_last */
2004-10-03 04:19:59 +00:00
int length ;
char * p ;
length = sizeof ( struct ast_include ) ;
length + = 2 * ( strlen ( value ) + 1 ) ;
2001-09-28 21:20:52 +00:00
/* allocate new include structure ... */
2004-10-03 04:19:59 +00:00
if ( ! ( new_include = malloc ( length ) ) ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
2001-09-28 21:20:52 +00:00
errno = ENOMEM ;
return - 1 ;
}
/* ... fill in this structure ... */
2004-10-03 04:19:59 +00:00
memset ( new_include , 0 , length ) ;
p = new_include - > stuff ;
new_include - > name = p ;
strcpy ( new_include - > name , value ) ;
p + = strlen ( value ) + 1 ;
new_include - > rname = p ;
strcpy ( new_include - > rname , value ) ;
2002-06-21 01:40:13 +00:00
c = new_include - > rname ;
/* Strip off timing info */
while ( * c & & ( * c ! = ' | ' ) ) c + + ;
/* Process if it's there */
if ( * c ) {
2004-11-11 21:23:45 +00:00
new_include - > hastime = ast_build_timing ( & ( new_include - > timing ) , c + 1 ) ;
2002-06-21 01:40:13 +00:00
* c = ' \0 ' ;
}
2001-09-28 21:20:52 +00:00
new_include - > next = NULL ;
new_include - > registrar = registrar ;
/* ... try to lock this context ... */
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & con - > lock ) ) {
2001-09-28 21:20:52 +00:00
free ( new_include ) ;
errno = EBUSY ;
return - 1 ;
}
/* ... go to last include and check if context is already included too... */
i = con - > includes ;
while ( i ) {
if ( ! strcasecmp ( i - > name , new_include - > name ) ) {
free ( new_include ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
errno = EEXIST ;
return - 1 ;
}
il = i ;
i = i - > next ;
}
/* ... include new context into context list, unlock, return */
if ( il )
il - > next = new_include ;
else
con - > includes = new_include ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Including context '%s' in context '%s' \n " , new_include - > name , ast_get_context_name ( con ) ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return 0 ;
}
/*
* errno values
* EBUSY - can ' t lock
2003-04-23 19:13:35 +00:00
* ENOENT - no existence of context
2001-09-28 21:20:52 +00:00
*/
2004-10-03 04:19:59 +00:00
int ast_context_add_switch ( const char * context , const char * sw , const char * data , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_context * c ;
if ( ast_lock_contexts ( ) ) {
errno = EBUSY ;
return - 1 ;
}
/* walk contexts ... */
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
/* ... search for the right one ... */
if ( ! strcmp ( ast_get_context_name ( c ) , context ) ) {
int ret = ast_context_add_switch2 ( c , sw , data , registrar ) ;
/* ... unlock contexts list and return */
ast_unlock_contexts ( ) ;
return ret ;
}
c = ast_walk_contexts ( c ) ;
}
/* we can't find the right context */
ast_unlock_contexts ( ) ;
2003-04-23 19:13:35 +00:00
errno = ENOENT ;
2001-09-28 21:20:52 +00:00
return - 1 ;
}
/*
* errno values
* ENOMEM - out of memory
* EBUSY - can ' t lock
* EEXIST - already included
* EINVAL - there is no existence of context for inclusion
*/
2004-10-03 04:19:59 +00:00
int ast_context_add_switch2 ( struct ast_context * con , const char * value ,
const char * data , const char * registrar )
2001-03-30 18:47:35 +00:00
{
2001-09-28 21:20:52 +00:00
struct ast_sw * new_sw ;
struct ast_sw * i , * il = NULL ; /* sw, sw_last */
2004-10-03 04:19:59 +00:00
int length ;
char * p ;
length = sizeof ( struct ast_sw ) ;
length + = strlen ( value ) + 1 ;
if ( data )
length + = strlen ( data ) ;
length + + ;
2001-09-28 21:20:52 +00:00
/* allocate new sw structure ... */
2004-10-03 04:19:59 +00:00
if ( ! ( new_sw = malloc ( length ) ) ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
2001-09-28 21:20:52 +00:00
errno = ENOMEM ;
2001-03-30 18:47:35 +00:00
return - 1 ;
}
2001-09-28 21:20:52 +00:00
/* ... fill in this structure ... */
2004-10-03 04:19:59 +00:00
memset ( new_sw , 0 , length ) ;
p = new_sw - > stuff ;
new_sw - > name = p ;
strcpy ( new_sw - > name , value ) ;
p + = strlen ( value ) + 1 ;
new_sw - > data = p ;
2001-09-28 21:20:52 +00:00
if ( data )
2004-10-03 04:19:59 +00:00
strcpy ( new_sw - > data , data ) ;
2001-09-28 21:20:52 +00:00
else
2004-10-03 04:19:59 +00:00
strcpy ( new_sw - > data , " " ) ;
2001-09-28 21:20:52 +00:00
new_sw - > next = NULL ;
new_sw - > registrar = registrar ;
/* ... try to lock this context ... */
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & con - > lock ) ) {
2001-09-28 21:20:52 +00:00
free ( new_sw ) ;
errno = EBUSY ;
return - 1 ;
}
/* ... go to last sw and check if context is already swd too... */
i = con - > alts ;
while ( i ) {
2004-03-06 20:15:08 +00:00
if ( ! strcasecmp ( i - > name , new_sw - > name ) & & ! strcasecmp ( i - > data , new_sw - > data ) ) {
2001-09-28 21:20:52 +00:00
free ( new_sw ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
errno = EEXIST ;
return - 1 ;
}
il = i ;
i = i - > next ;
}
/* ... sw new context into context list, unlock, return */
if ( il )
il - > next = new_sw ;
else
con - > alts = new_sw ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Including switch '%s/%s' in context '%s' \n " , new_sw - > name , new_sw - > data , ast_get_context_name ( con ) ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return 0 ;
}
/*
* EBUSY - can ' t lock
2003-04-23 19:13:35 +00:00
* ENOENT - there is not context existence
2001-09-28 21:20:52 +00:00
*/
2004-10-03 04:19:59 +00:00
int ast_context_remove_ignorepat ( const char * context , const char * ignorepat , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_context * c ;
if ( ast_lock_contexts ( ) ) {
errno = EBUSY ;
return - 1 ;
}
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
if ( ! strcmp ( ast_get_context_name ( c ) , context ) ) {
int ret = ast_context_remove_ignorepat2 ( c , ignorepat , registrar ) ;
ast_unlock_contexts ( ) ;
return ret ;
}
c = ast_walk_contexts ( c ) ;
}
ast_unlock_contexts ( ) ;
2003-04-23 19:13:35 +00:00
errno = ENOENT ;
2001-09-28 21:20:52 +00:00
return - 1 ;
}
2004-10-03 04:19:59 +00:00
int ast_context_remove_ignorepat2 ( struct ast_context * con , const char * ignorepat , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_ignorepat * ip , * ipl = NULL ;
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & con - > lock ) ) {
2001-09-28 21:20:52 +00:00
errno = EBUSY ;
return - 1 ;
}
ip = con - > ignorepats ;
while ( ip ) {
if ( ! strcmp ( ip - > pattern , ignorepat ) & &
2004-08-03 06:31:20 +00:00
( ! registrar | | ( registrar = = ip - > registrar ) ) ) {
2001-09-28 21:20:52 +00:00
if ( ipl ) {
ipl - > next = ip - > next ;
free ( ip ) ;
} else {
con - > ignorepats = ip - > next ;
free ( ip ) ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
return 0 ;
}
ipl = ip ; ip = ip - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
errno = EINVAL ;
return - 1 ;
}
/*
* EBUSY - can ' t lock
2003-04-23 19:13:35 +00:00
* ENOENT - there is no existence of context
2001-09-28 21:20:52 +00:00
*/
2004-10-03 04:19:59 +00:00
int ast_context_add_ignorepat ( const char * con , const char * value , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_context * c ;
if ( ast_lock_contexts ( ) ) {
errno = EBUSY ;
return - 1 ;
}
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
if ( ! strcmp ( ast_get_context_name ( c ) , con ) ) {
int ret = ast_context_add_ignorepat2 ( c , value , registrar ) ;
ast_unlock_contexts ( ) ;
return ret ;
}
c = ast_walk_contexts ( c ) ;
}
ast_unlock_contexts ( ) ;
2003-04-23 19:13:35 +00:00
errno = ENOENT ;
2001-09-28 21:20:52 +00:00
return - 1 ;
}
2004-10-03 04:19:59 +00:00
int ast_context_add_ignorepat2 ( struct ast_context * con , const char * value , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_ignorepat * ignorepat , * ignorepatc , * ignorepatl = NULL ;
2004-10-03 04:19:59 +00:00
int length ;
length = sizeof ( struct ast_ignorepat ) ;
length + = strlen ( value ) + 1 ;
ignorepat = malloc ( length ) ;
2001-09-28 21:20:52 +00:00
if ( ! ignorepat ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
2001-09-28 21:20:52 +00:00
errno = ENOMEM ;
return - 1 ;
}
2004-10-03 04:19:59 +00:00
memset ( ignorepat , 0 , length ) ;
strcpy ( ignorepat - > pattern , value ) ;
2001-09-28 21:20:52 +00:00
ignorepat - > next = NULL ;
ignorepat - > registrar = registrar ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
ignorepatc = con - > ignorepats ;
while ( ignorepatc ) {
ignorepatl = ignorepatc ;
if ( ! strcasecmp ( ignorepatc - > pattern , value ) ) {
2001-03-30 18:47:35 +00:00
/* Already there */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
errno = EEXIST ;
return - 1 ;
2001-03-30 18:47:35 +00:00
}
2001-09-28 21:20:52 +00:00
ignorepatc = ignorepatc - > next ;
2001-03-30 18:47:35 +00:00
}
2001-09-28 21:20:52 +00:00
if ( ignorepatl )
ignorepatl - > next = ignorepat ;
2001-03-30 18:47:35 +00:00
else
2001-09-28 21:20:52 +00:00
con - > ignorepats = ignorepat ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-03-30 18:47:35 +00:00
return 0 ;
}
2004-10-03 04:19:59 +00:00
int ast_ignore_pattern ( const char * context , const char * pattern )
2001-09-28 21:20:52 +00:00
{
struct ast_context * con ;
struct ast_ignorepat * pat ;
2004-07-17 02:25:53 +00:00
2001-09-28 21:20:52 +00:00
con = ast_context_find ( context ) ;
if ( con ) {
pat = con - > ignorepats ;
while ( pat ) {
if ( ast_extension_match ( pat - > pattern , pattern ) )
return 1 ;
pat = pat - > next ;
}
}
return 0 ;
}
/*
* EBUSY - can ' t lock
2003-04-23 19:13:35 +00:00
* ENOENT - no existence of context
2001-09-28 21:20:52 +00:00
*
*/
2004-10-03 04:19:59 +00:00
int ast_add_extension ( const char * context , int replace , const char * extension , int priority , const char * label , const char * callerid ,
const char * application , void * data , void ( * datad ) ( void * ) , const char * registrar )
2001-09-28 21:20:52 +00:00
{
struct ast_context * c ;
if ( ast_lock_contexts ( ) ) {
errno = EBUSY ;
return - 1 ;
}
c = ast_walk_contexts ( NULL ) ;
while ( c ) {
if ( ! strcmp ( context , ast_get_context_name ( c ) ) ) {
2004-10-03 04:19:59 +00:00
int ret = ast_add_extension2 ( c , replace , extension , priority , label , callerid ,
2001-09-28 21:20:52 +00:00
application , data , datad , registrar ) ;
ast_unlock_contexts ( ) ;
return ret ;
}
c = ast_walk_contexts ( c ) ;
}
ast_unlock_contexts ( ) ;
2003-04-23 19:13:35 +00:00
errno = ENOENT ;
2001-09-28 21:20:52 +00:00
return - 1 ;
}
2004-11-23 20:25:02 +00:00
int ast_explicit_goto ( struct ast_channel * chan , const char * context , const char * exten , int priority ) {
2004-12-02 18:08:11 +00:00
if ( chan ) {
2004-11-23 20:25:02 +00:00
if ( context & & ! ast_strlen_zero ( context ) )
strncpy ( chan - > context , context , sizeof ( chan - > context ) - 1 ) ;
if ( exten & & ! ast_strlen_zero ( exten ) )
strncpy ( chan - > exten , exten , sizeof ( chan - > context ) - 1 ) ;
2004-12-08 18:24:04 +00:00
if ( priority > - 1 )
chan - > priority = priority ;
2004-11-23 20:25:02 +00:00
return 0 ;
}
return - 1 ;
}
2004-10-03 04:19:59 +00:00
int ast_async_goto ( struct ast_channel * chan , const char * context , const char * exten , int priority )
2002-09-11 17:09:48 +00:00
{
int res = 0 ;
2004-04-06 22:17:32 +00:00
ast_mutex_lock ( & chan - > lock ) ;
2004-07-17 02:25:53 +00:00
2002-09-11 17:09:48 +00:00
if ( chan - > pbx ) {
/* This channel is currently in the PBX */
2004-12-02 18:08:11 +00:00
ast_explicit_goto ( chan , context , exten , priority - 1 ) ;
2002-09-11 17:09:48 +00:00
ast_softhangup_nolock ( chan , AST_SOFTHANGUP_ASYNCGOTO ) ;
} else {
/* In order to do it when the channel doesn't really exist within
the PBX , we have to make a new channel , masquerade , and start the PBX
at the new location */
struct ast_channel * tmpchan ;
tmpchan = ast_channel_alloc ( 0 ) ;
if ( tmpchan ) {
snprintf ( tmpchan - > name , sizeof ( tmpchan - > name ) , " AsyncGoto/%s " , chan - > name ) ;
2003-02-24 06:00:18 +00:00
ast_setstate ( tmpchan , chan - > _state ) ;
2002-09-11 17:09:48 +00:00
/* Make formats okay */
tmpchan - > readformat = chan - > readformat ;
tmpchan - > writeformat = chan - > writeformat ;
/* Setup proper location */
2004-11-23 20:25:02 +00:00
ast_explicit_goto ( tmpchan ,
( context & & ! ast_strlen_zero ( context ) ) ? context : chan - > context ,
( exten & & ! ast_strlen_zero ( exten ) ) ? exten : chan - > exten ,
2004-12-28 20:31:37 +00:00
priority ) ;
2004-11-23 20:25:02 +00:00
2002-09-11 17:09:48 +00:00
/* Masquerade into temp channel */
ast_channel_masquerade ( tmpchan , chan ) ;
2004-02-26 17:29:49 +00:00
2004-03-24 05:01:44 +00:00
/* Grab the locks and get going */
ast_mutex_lock ( & tmpchan - > lock ) ;
2004-04-06 22:17:32 +00:00
ast_do_masquerade ( tmpchan ) ;
2004-03-24 05:01:44 +00:00
ast_mutex_unlock ( & tmpchan - > lock ) ;
2002-09-11 17:09:48 +00:00
/* Start the PBX going on our stolen channel */
if ( ast_pbx_start ( tmpchan ) ) {
ast_log ( LOG_WARNING , " Unable to start PBX on %s \n " , tmpchan - > name ) ;
ast_hangup ( tmpchan ) ;
res = - 1 ;
}
} else {
res = - 1 ;
}
}
2004-04-19 23:00:50 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
2002-09-11 17:09:48 +00:00
return res ;
}
2004-10-03 04:19:59 +00:00
int ast_async_goto_by_name ( const char * channame , const char * context , const char * exten , int priority )
2002-09-11 17:09:48 +00:00
{
struct ast_channel * chan ;
2004-05-20 16:30:10 +00:00
int res = - 1 ;
chan = ast_channel_walk_locked ( NULL ) ;
2002-09-11 17:09:48 +00:00
while ( chan ) {
if ( ! strcasecmp ( channame , chan - > name ) )
break ;
2004-05-20 16:30:10 +00:00
ast_mutex_unlock ( & chan - > lock ) ;
chan = ast_channel_walk_locked ( chan ) ;
2002-09-11 17:09:48 +00:00
}
2004-05-20 16:30:10 +00:00
if ( chan ) {
res = ast_async_goto ( chan , context , exten , priority ) ;
ast_mutex_unlock ( & chan - > lock ) ;
}
return res ;
2002-09-11 17:09:48 +00:00
}
2004-12-19 17:16:39 +00:00
static int ext_strncpy ( char * dst , const char * src , int len )
2001-09-28 21:20:52 +00:00
{
int count = 0 ;
2004-07-17 02:25:53 +00:00
2001-09-28 21:20:52 +00:00
while ( * src & & ( count < len - 1 ) ) {
switch ( * src ) {
case ' ' :
2004-07-17 02:25:53 +00:00
/* otherwise exten => [a-b],1,... doesn't work */
/* case '-': */
2001-09-28 21:20:52 +00:00
/* Ignore */
break ;
default :
* dst = * src ;
dst + + ;
}
src + + ;
count + + ;
}
* dst = ' \0 ' ;
2004-12-19 17:16:39 +00:00
return count ;
2001-09-28 21:20:52 +00:00
}
/*
* EBUSY - can ' t lock
* EEXIST - extension with the same priority exist and no replace is set
*
*/
1999-12-04 20:45:45 +00:00
int ast_add_extension2 ( struct ast_context * con ,
2004-10-03 04:19:59 +00:00
int replace , const char * extension , int priority , const char * label , const char * callerid ,
const char * application , void * data , void ( * datad ) ( void * ) ,
const char * registrar )
1999-12-04 20:45:45 +00:00
{
2001-09-28 21:20:52 +00:00
# define LOG do { if (option_debug) {\
if ( tmp - > matchcid ) { \
ast_log ( LOG_DEBUG , " Added extension '%s' priority %d (CID match '%s') to %s \n " , tmp - > exten , tmp - > priority , tmp - > cidmatch , con - > name ) ; \
} else { \
ast_log ( LOG_DEBUG , " Added extension '%s' priority %d to %s \n " , tmp - > exten , tmp - > priority , con - > name ) ; \
} \
} else if ( option_verbose > 2 ) { \
if ( tmp - > matchcid ) { \
ast_verbose ( VERBOSE_PREFIX_3 " Added extension '%s' priority %d (CID match '%s')to %s \n " , tmp - > exten , tmp - > priority , tmp - > cidmatch , con - > name ) ; \
} else { \
ast_verbose ( VERBOSE_PREFIX_3 " Added extension '%s' priority %d to %s \n " , tmp - > exten , tmp - > priority , con - > name ) ; \
} \
} } while ( 0 )
1999-12-04 20:45:45 +00:00
/*
* This is a fairly complex routine . Different extensions are kept
* in order by the extension number . Then , extensions of different
* priorities ( same extension ) are kept in a list , according to the
* peer pointer .
*/
struct ast_exten * tmp , * e , * el = NULL , * ep = NULL ;
int res ;
2004-10-03 04:19:59 +00:00
int length ;
char * p ;
length = sizeof ( struct ast_exten ) ;
length + = strlen ( extension ) + 1 ;
length + = strlen ( application ) + 1 ;
if ( label )
length + = strlen ( label ) + 1 ;
if ( callerid )
length + = strlen ( callerid ) + 1 ;
else
length + + ;
2004-07-17 02:25:53 +00:00
1999-12-04 20:45:45 +00:00
/* Be optimistic: Build the extension structure first */
2004-10-03 04:19:59 +00:00
tmp = malloc ( length ) ;
1999-12-04 20:45:45 +00:00
if ( tmp ) {
2004-10-03 04:19:59 +00:00
memset ( tmp , 0 , length ) ;
p = tmp - > stuff ;
if ( label ) {
tmp - > label = p ;
strcpy ( tmp - > label , label ) ;
p + = strlen ( label ) + 1 ;
}
tmp - > exten = p ;
2004-12-19 17:16:39 +00:00
p + = ext_strncpy ( tmp - > exten , extension , strlen ( extension ) + 1 ) + 1 ;
1999-12-04 20:45:45 +00:00
tmp - > priority = priority ;
2004-10-03 04:19:59 +00:00
tmp - > cidmatch = p ;
2001-09-28 21:20:52 +00:00
if ( callerid ) {
2004-12-19 17:16:39 +00:00
p + = ext_strncpy ( tmp - > cidmatch , callerid , strlen ( callerid ) + 1 ) + 1 ;
2001-09-28 21:20:52 +00:00
tmp - > matchcid = 1 ;
} else {
2004-07-14 07:44:19 +00:00
tmp - > cidmatch [ 0 ] = ' \0 ' ;
2001-09-28 21:20:52 +00:00
tmp - > matchcid = 0 ;
2004-10-03 04:19:59 +00:00
p + + ;
2001-09-28 21:20:52 +00:00
}
2004-10-03 04:19:59 +00:00
tmp - > app = p ;
strcpy ( tmp - > app , application ) ;
2003-03-30 22:55:42 +00:00
tmp - > parent = con ;
1999-12-04 20:45:45 +00:00
tmp - > data = data ;
tmp - > datad = datad ;
2001-04-27 15:07:56 +00:00
tmp - > registrar = registrar ;
1999-12-04 20:45:45 +00:00
tmp - > peer = NULL ;
tmp - > next = NULL ;
} else {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
2001-09-28 21:20:52 +00:00
errno = ENOMEM ;
1999-12-04 20:45:45 +00:00
return - 1 ;
}
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & con - > lock ) ) {
1999-12-04 20:45:45 +00:00
free ( tmp ) ;
/* And properly destroy the data */
datad ( data ) ;
ast_log ( LOG_WARNING , " Failed to lock context '%s' \n " , con - > name ) ;
2001-09-28 21:20:52 +00:00
errno = EBUSY ;
1999-12-04 20:45:45 +00:00
return - 1 ;
}
e = con - > root ;
while ( e ) {
2004-09-14 22:35:53 +00:00
/* Make sure patterns are always last! */
if ( ( e - > exten [ 0 ] ! = ' _ ' ) & & ( extension [ 0 ] = = ' _ ' ) )
res = - 1 ;
else if ( ( e - > exten [ 0 ] = = ' _ ' ) & & ( extension [ 0 ] ! = ' _ ' ) )
res = 1 ;
else
res = strcmp ( e - > exten , extension ) ;
2001-09-28 21:20:52 +00:00
if ( ! res ) {
if ( ! e - > matchcid & & ! tmp - > matchcid )
res = 0 ;
else if ( tmp - > matchcid & & ! e - > matchcid )
res = 1 ;
else if ( e - > matchcid & & ! tmp - > matchcid )
res = - 1 ;
else
res = strcasecmp ( e - > cidmatch , tmp - > cidmatch ) ;
}
1999-12-04 20:45:45 +00:00
if ( res = = 0 ) {
/* We have an exact match, now we find where we are
and be sure there ' s no duplicates */
while ( e ) {
if ( e - > priority = = tmp - > priority ) {
/* Can't have something exactly the same. Is this a
replacement ? If so , replace , otherwise , bonk . */
if ( replace ) {
if ( ep ) {
/* We're in the peer list, insert ourselves */
ep - > peer = tmp ;
tmp - > peer = e - > peer ;
} else if ( el ) {
/* We're the first extension. Take over e's functions */
el - > next = tmp ;
tmp - > next = e - > next ;
tmp - > peer = e - > peer ;
} else {
/* We're the very first extension. */
con - > root = tmp ;
tmp - > next = e - > next ;
tmp - > peer = e - > peer ;
}
2003-04-06 18:19:51 +00:00
if ( tmp - > priority = = PRIORITY_HINT )
ast_change_hint ( e , tmp ) ;
1999-12-04 20:45:45 +00:00
/* Destroy the old one */
e - > datad ( e - > data ) ;
free ( e ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2003-04-06 18:19:51 +00:00
if ( tmp - > priority = = PRIORITY_HINT )
ast_change_hint ( e , tmp ) ;
1999-12-04 20:45:45 +00:00
/* And immediately return success. */
LOG ;
return 0 ;
} else {
ast_log ( LOG_WARNING , " Unable to register extension '%s', priority %d in '%s', already in use \n " , tmp - > exten , tmp - > priority , con - > name ) ;
tmp - > datad ( tmp - > data ) ;
free ( tmp ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
errno = EEXIST ;
1999-12-04 20:45:45 +00:00
return - 1 ;
}
} else if ( e - > priority > tmp - > priority ) {
/* Slip ourselves in just before e */
if ( ep ) {
/* Easy enough, we're just in the peer list */
ep - > peer = tmp ;
tmp - > peer = e ;
} else if ( el ) {
/* We're the first extension in this peer list */
el - > next = tmp ;
tmp - > next = e - > next ;
e - > next = NULL ;
tmp - > peer = e ;
} else {
/* We're the very first extension altogether */
2004-02-23 02:47:22 +00:00
tmp - > next = con - > root - > next ;
1999-12-04 20:45:45 +00:00
/* Con->root must always exist or we couldn't get here */
2004-02-23 02:47:22 +00:00
tmp - > peer = con - > root ;
1999-12-04 20:45:45 +00:00
con - > root = tmp ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
1999-12-04 20:45:45 +00:00
/* And immediately return success. */
2003-04-06 18:19:51 +00:00
if ( tmp - > priority = = PRIORITY_HINT )
ast_add_hint ( tmp ) ;
1999-12-04 20:45:45 +00:00
LOG ;
return 0 ;
}
ep = e ;
e = e - > peer ;
}
/* If we make it here, then it's time for us to go at the very end.
ep * must * be defined or we couldn ' t have gotten here . */
ep - > peer = tmp ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2003-04-06 18:19:51 +00:00
if ( tmp - > priority = = PRIORITY_HINT )
2004-07-17 02:25:53 +00:00
ast_add_hint ( tmp ) ;
2003-04-06 18:19:51 +00:00
1999-12-04 20:45:45 +00:00
/* And immediately return success. */
LOG ;
return 0 ;
} else if ( res > 0 ) {
/* Insert ourselves just before 'e'. We're the first extension of
this kind */
tmp - > next = e ;
if ( el ) {
/* We're in the list somewhere */
el - > next = tmp ;
} else {
/* We're at the top of the list */
con - > root = tmp ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2003-04-06 18:19:51 +00:00
if ( tmp - > priority = = PRIORITY_HINT )
2004-07-17 02:25:53 +00:00
ast_add_hint ( tmp ) ;
2003-04-06 18:19:51 +00:00
1999-12-04 20:45:45 +00:00
/* And immediately return success. */
LOG ;
return 0 ;
}
el = e ;
e = e - > next ;
}
/* If we fall all the way through to here, then we need to be on the end. */
if ( el )
el - > next = tmp ;
else
con - > root = tmp ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & con - > lock ) ;
2003-04-06 18:19:51 +00:00
if ( tmp - > priority = = PRIORITY_HINT )
2004-07-17 02:25:53 +00:00
ast_add_hint ( tmp ) ;
1999-12-04 20:45:45 +00:00
LOG ;
return 0 ;
}
2002-09-11 17:09:48 +00:00
struct async_stat {
pthread_t p ;
struct ast_channel * chan ;
char context [ AST_MAX_EXTENSION ] ;
char exten [ AST_MAX_EXTENSION ] ;
int priority ;
int timeout ;
char app [ AST_MAX_EXTENSION ] ;
2003-02-02 19:04:14 +00:00
char appdata [ 1024 ] ;
2002-09-11 17:09:48 +00:00
} ;
static void * async_wait ( void * data )
{
struct async_stat * as = data ;
struct ast_channel * chan = as - > chan ;
int timeout = as - > timeout ;
int res ;
struct ast_frame * f ;
2003-02-02 19:04:14 +00:00
struct ast_app * app ;
2002-09-11 17:09:48 +00:00
while ( timeout & & ( chan - > _state ! = AST_STATE_UP ) ) {
res = ast_waitfor ( chan , timeout ) ;
if ( res < 1 )
break ;
if ( timeout > - 1 )
timeout = res ;
f = ast_read ( chan ) ;
if ( ! f )
break ;
if ( f - > frametype = = AST_FRAME_CONTROL ) {
if ( ( f - > subclass = = AST_CONTROL_BUSY ) | |
( f - > subclass = = AST_CONTROL_CONGESTION ) )
break ;
}
ast_frfree ( f ) ;
}
if ( chan - > _state = = AST_STATE_UP ) {
2004-05-04 06:34:34 +00:00
if ( ! ast_strlen_zero ( as - > app ) ) {
2003-02-02 19:04:14 +00:00
app = pbx_findapp ( as - > app ) ;
if ( app ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Lauching %s(%s) on %s \n " , as - > app , as - > appdata , chan - > name ) ;
pbx_exec ( chan , app , as - > appdata , 1 ) ;
} else
ast_log ( LOG_WARNING , " No such application '%s' \n " , as - > app ) ;
2002-09-11 17:09:48 +00:00
} else {
2004-05-04 06:34:34 +00:00
if ( ! ast_strlen_zero ( as - > context ) )
2003-02-02 19:04:14 +00:00
strncpy ( chan - > context , as - > context , sizeof ( chan - > context ) - 1 ) ;
2004-05-04 06:34:34 +00:00
if ( ! ast_strlen_zero ( as - > exten ) )
2003-02-02 19:04:14 +00:00
strncpy ( chan - > exten , as - > exten , sizeof ( chan - > exten ) - 1 ) ;
if ( as - > priority > 0 )
chan - > priority = as - > priority ;
/* Run the PBX */
if ( ast_pbx_run ( chan ) ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Failed to start PBX on %s \n " , chan - > name ) ;
2003-02-02 19:04:14 +00:00
} else {
/* PBX will have taken care of this */
chan = NULL ;
}
2002-09-11 17:09:48 +00:00
}
}
free ( as ) ;
if ( chan )
ast_hangup ( chan ) ;
return NULL ;
}
2004-10-15 17:51:37 +00:00
/*! Function to update the cdr after a spool call fails.
*
* This function updates the cdr for a failed spool call
* and takes the channel of the failed call as an argument .
*
* \ param chan the channel for the failed call .
*/
int ast_pbx_outgoing_cdr_failed ( void )
{
/* allocate a channel */
struct ast_channel * chan = ast_channel_alloc ( 0 ) ;
if ( ! chan ) {
/* allocation of the channel failed, let some peeps know */
ast_log ( LOG_WARNING , " Unable to allocate channel structure for CDR record \n " ) ;
return - 1 ; /* failure */
}
chan - > cdr = ast_cdr_alloc ( ) ; /* allocate a cdr for the channel */
if ( ! chan - > cdr ) {
/* allocation of the cdr failed */
ast_log ( LOG_WARNING , " Unable to create Call Detail Record \n " ) ;
ast_channel_free ( chan ) ; /* free the channel */
return - 1 ; /* return failure */
}
/* allocation of the cdr was successful */
ast_cdr_init ( chan - > cdr , chan ) ; /* initilize our channel's cdr */
ast_cdr_start ( chan - > cdr ) ; /* record the start and stop time */
ast_cdr_end ( chan - > cdr ) ;
ast_cdr_failed ( chan - > cdr ) ; /* set the status to failed */
ast_cdr_post ( chan - > cdr ) ; /* post the record */
ast_cdr_free ( chan - > cdr ) ; /* free the cdr */
ast_channel_free ( chan ) ; /* free the channel */
return 0 ; /* success */
}
2004-10-03 04:19:59 +00:00
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 , const char * variable , const char * account )
2002-09-11 17:09:48 +00:00
{
struct ast_channel * chan ;
struct async_stat * as ;
2004-10-15 17:51:37 +00:00
int res = - 1 , cdr_res = - 1 ;
2003-02-02 19:04:14 +00:00
char * var , * tmp ;
2003-09-22 15:27:09 +00:00
struct outgoing_helper oh ;
2003-10-23 03:55:58 +00:00
pthread_attr_t attr ;
2002-09-11 17:09:48 +00:00
if ( sync ) {
2003-09-22 15:27:09 +00:00
LOAD_OH ( oh ) ;
2004-10-02 00:58:31 +00:00
chan = __ast_request_and_dial ( type , format , data , timeout , reason , cid_num , cid_name , & oh ) ;
2002-09-11 17:09:48 +00:00
if ( chan ) {
2004-10-15 17:51:37 +00:00
2004-10-03 04:19:59 +00:00
if ( account )
ast_cdr_setaccount ( chan , account ) ;
2004-10-15 17:51:37 +00:00
if ( chan - > cdr ) { /* check if the channel already has a cdr record, if not give it one */
ast_log ( LOG_WARNING , " %s already has a call record?? \n " , chan - > name ) ;
} else {
chan - > cdr = ast_cdr_alloc ( ) ; /* allocate a cdr for the channel */
if ( ! chan - > cdr ) {
/* allocation of the cdr failed */
ast_log ( LOG_WARNING , " Unable to create Call Detail Record \n " ) ;
free ( chan - > pbx ) ;
return - 1 ; /* return failure */
}
/* allocation of the cdr was successful */
ast_cdr_init ( chan - > cdr , chan ) ; /* initilize our channel's cdr */
ast_cdr_start ( chan - > cdr ) ;
}
2002-09-11 17:09:48 +00:00
if ( chan - > _state = = AST_STATE_UP ) {
2003-09-22 15:27:09 +00:00
res = 0 ;
2002-09-11 17:09:48 +00:00
if ( option_verbose > 3 )
ast_verbose ( VERBOSE_PREFIX_4 " Channel %s was answered. \n " , chan - > name ) ;
2003-09-22 15:27:09 +00:00
2003-02-02 19:04:14 +00:00
if ( sync > 1 ) {
if ( ast_pbx_run ( chan ) ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Unable to run PBX on %s \n " , chan - > name ) ;
2003-02-02 19:04:14 +00:00
ast_hangup ( chan ) ;
res = - 1 ;
}
} else {
if ( ast_pbx_start ( chan ) ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Unable to start PBX on %s \n " , chan - > name ) ;
2003-02-02 19:04:14 +00:00
ast_hangup ( chan ) ;
res = - 1 ;
}
}
2002-09-11 17:09:48 +00:00
} else {
if ( option_verbose > 3 )
ast_verbose ( VERBOSE_PREFIX_4 " Channel %s was never answered. \n " , chan - > name ) ;
2004-10-15 17:51:37 +00:00
if ( chan - > cdr ) { /* update the cdr */
/* here we update the status of the call, which sould be busy.
* if that fails then we set the status to failed */
if ( ast_cdr_disposition ( chan - > cdr , chan - > hangupcause ) )
ast_cdr_failed ( chan - > cdr ) ;
}
2002-09-11 17:09:48 +00:00
ast_hangup ( chan ) ;
}
2004-06-23 20:46:58 +00:00
}
if ( res < 0 ) { /* the call failed for some reason */
2004-10-15 17:51:37 +00:00
if ( * reason = = 0 ) { /* if the call failed (not busy or no answer)
* update the cdr with the failed message */
cdr_res = ast_pbx_outgoing_cdr_failed ( ) ;
if ( cdr_res ! = 0 )
return cdr_res ;
}
2003-09-12 16:51:35 +00:00
/* create a fake channel and execute the "failed" extension (if it exists) within the requested context */
/* check if "failed" exists */
if ( ast_exists_extension ( chan , context , " failed " , 1 , NULL ) ) {
chan = ast_channel_alloc ( 0 ) ;
2004-10-15 17:51:37 +00:00
if ( chan ) {
2003-09-12 16:51:35 +00:00
strncpy ( chan - > name , " OutgoingSpoolFailed " , sizeof ( chan - > name ) - 1 ) ;
2004-05-04 06:34:34 +00:00
if ( context & & ! ast_strlen_zero ( context ) )
2003-09-12 16:51:35 +00:00
strncpy ( chan - > context , context , sizeof ( chan - > context ) - 1 ) ;
strncpy ( chan - > exten , " failed " , sizeof ( chan - > exten ) - 1 ) ;
chan - > priority = 1 ;
2003-10-26 23:08:21 +00:00
if ( variable ) {
tmp = ast_strdupa ( variable ) ;
for ( var = strtok_r ( tmp , " | " , & tmp ) ; var ; var = strtok_r ( NULL , " | " , & tmp ) ) {
pbx_builtin_setvar ( chan , var ) ;
}
}
2003-09-12 16:51:35 +00:00
ast_pbx_run ( chan ) ;
2004-10-15 17:51:37 +00:00
} else
2003-09-12 16:51:35 +00:00
ast_log ( LOG_WARNING , " Can't allocate the channel structure, skipping execution of extension 'failed' \n " ) ;
}
2002-09-11 17:09:48 +00:00
}
} else {
as = malloc ( sizeof ( struct async_stat ) ) ;
if ( ! as )
return - 1 ;
memset ( as , 0 , sizeof ( struct async_stat ) ) ;
2004-10-02 00:58:31 +00:00
chan = ast_request_and_dial ( type , format , data , timeout , reason , cid_num , cid_name ) ;
2002-09-11 17:09:48 +00:00
if ( ! chan ) {
free ( as ) ;
return - 1 ;
}
2004-10-03 04:19:59 +00:00
if ( account )
ast_cdr_setaccount ( chan , account ) ;
2002-09-11 17:09:48 +00:00
as - > chan = chan ;
strncpy ( as - > context , context , sizeof ( as - > context ) - 1 ) ;
strncpy ( as - > exten , exten , sizeof ( as - > exten ) - 1 ) ;
as - > priority = priority ;
as - > timeout = timeout ;
2004-05-17 21:10:26 +00:00
if ( variable ) {
tmp = ast_strdupa ( variable ) ;
2004-07-17 02:25:53 +00:00
for ( var = strtok_r ( tmp , " | " , & tmp ) ; var ; var = strtok_r ( NULL , " | " , & tmp ) )
pbx_builtin_setvar ( chan , var ) ;
2004-05-17 21:10:26 +00:00
}
2003-10-23 03:55:58 +00:00
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2004-08-08 17:15:02 +00:00
if ( ast_pthread_create ( & as - > p , & attr , async_wait , as ) ) {
2002-09-11 17:09:48 +00:00
ast_log ( LOG_WARNING , " Failed to start async wait \n " ) ;
free ( as ) ;
ast_hangup ( chan ) ;
return - 1 ;
}
res = 0 ;
}
return res ;
}
2003-02-02 19:04:14 +00:00
struct app_tmp {
char app [ 256 ] ;
char data [ 256 ] ;
struct ast_channel * chan ;
pthread_t t ;
} ;
static void * ast_pbx_run_app ( void * data )
{
struct app_tmp * tmp = data ;
struct ast_app * app ;
app = pbx_findapp ( tmp - > app ) ;
if ( app ) {
if ( option_verbose > 3 )
ast_verbose ( VERBOSE_PREFIX_4 " Lauching %s(%s) on %s \n " , tmp - > app , tmp - > data , tmp - > chan - > name ) ;
pbx_exec ( tmp - > chan , app , tmp - > data , 1 ) ;
} else
ast_log ( LOG_WARNING , " No such application '%s' \n " , tmp - > app ) ;
ast_hangup ( tmp - > chan ) ;
free ( tmp ) ;
return NULL ;
}
2004-10-03 04:19:59 +00:00
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 , const char * variable , const char * account )
2003-02-02 19:04:14 +00:00
{
struct ast_channel * chan ;
struct async_stat * as ;
struct app_tmp * tmp ;
2003-08-25 22:40:14 +00:00
char * var , * vartmp ;
2004-10-15 17:51:37 +00:00
int res = - 1 , cdr_res = - 1 ;
2003-10-23 03:55:58 +00:00
pthread_attr_t attr ;
2004-05-04 06:34:34 +00:00
if ( ! app | | ast_strlen_zero ( app ) )
2003-02-02 19:04:14 +00:00
return - 1 ;
if ( sync ) {
2004-10-02 00:58:31 +00:00
chan = ast_request_and_dial ( type , format , data , timeout , reason , cid_num , cid_name ) ;
2003-02-02 19:04:14 +00:00
if ( chan ) {
2004-10-15 17:51:37 +00:00
2004-10-03 04:19:59 +00:00
if ( account )
ast_cdr_setaccount ( chan , account ) ;
2004-10-15 17:51:37 +00:00
if ( chan - > cdr ) { /* check if the channel already has a cdr record, if not give it one */
ast_log ( LOG_WARNING , " %s already has a call record?? \n " , chan - > name ) ;
} else {
chan - > cdr = ast_cdr_alloc ( ) ; /* allocate a cdr for the channel */
if ( ! chan - > cdr ) {
/* allocation of the cdr failed */
ast_log ( LOG_WARNING , " Unable to create Call Detail Record \n " ) ;
free ( chan - > pbx ) ;
return - 1 ; /* return failure */
}
/* allocation of the cdr was successful */
ast_cdr_init ( chan - > cdr , chan ) ; /* initilize our channel's cdr */
ast_cdr_start ( chan - > cdr ) ;
}
2003-10-26 23:08:21 +00:00
if ( variable ) {
vartmp = ast_strdupa ( variable ) ;
for ( var = strtok_r ( vartmp , " | " , & vartmp ) ; var ; var = strtok_r ( NULL , " | " , & vartmp ) ) {
pbx_builtin_setvar ( chan , var ) ;
}
2003-08-25 22:40:14 +00:00
}
2003-02-02 19:04:14 +00:00
if ( chan - > _state = = AST_STATE_UP ) {
res = 0 ;
if ( option_verbose > 3 )
ast_verbose ( VERBOSE_PREFIX_4 " Channel %s was answered. \n " , chan - > name ) ;
tmp = malloc ( sizeof ( struct app_tmp ) ) ;
if ( tmp ) {
memset ( tmp , 0 , sizeof ( struct app_tmp ) ) ;
strncpy ( tmp - > app , app , sizeof ( tmp - > app ) - 1 ) ;
strncpy ( tmp - > data , appdata , sizeof ( tmp - > data ) - 1 ) ;
tmp - > chan = chan ;
if ( sync > 1 ) {
ast_pbx_run_app ( tmp ) ;
} else {
2003-10-23 03:55:58 +00:00
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2004-08-08 17:15:02 +00:00
if ( ast_pthread_create ( & tmp - > t , & attr , ast_pbx_run_app , tmp ) ) {
2003-02-02 19:04:14 +00:00
ast_log ( LOG_WARNING , " Unable to spawn execute thread on %s: %s \n " , chan - > name , strerror ( errno ) ) ;
free ( tmp ) ;
ast_hangup ( chan ) ;
res = - 1 ;
}
}
} else {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_ERROR , " Out of memory :( \n " ) ;
2003-02-02 19:04:14 +00:00
res = - 1 ;
}
} else {
if ( option_verbose > 3 )
ast_verbose ( VERBOSE_PREFIX_4 " Channel %s was never answered. \n " , chan - > name ) ;
2004-10-15 17:51:37 +00:00
if ( chan - > cdr ) { /* update the cdr */
/* here we update the status of the call, which sould be busy.
* if that fails then we set the status to failed */
if ( ast_cdr_disposition ( chan - > cdr , chan - > hangupcause ) )
ast_cdr_failed ( chan - > cdr ) ;
}
2003-02-02 19:04:14 +00:00
ast_hangup ( chan ) ;
}
}
2004-10-15 17:51:37 +00:00
if ( res < 0 ) { /* the call failed for some reason */
if ( * reason = = 0 ) { /* if the call failed (not busy or no answer)
* update the cdr with the failed message */
cdr_res = ast_pbx_outgoing_cdr_failed ( ) ;
if ( cdr_res ! = 0 )
return cdr_res ;
}
}
2003-02-02 19:04:14 +00:00
} else {
as = malloc ( sizeof ( struct async_stat ) ) ;
if ( ! as )
return - 1 ;
memset ( as , 0 , sizeof ( struct async_stat ) ) ;
2004-10-02 00:58:31 +00:00
chan = ast_request_and_dial ( type , format , data , timeout , reason , cid_num , cid_name ) ;
2003-02-02 19:04:14 +00:00
if ( ! chan ) {
free ( as ) ;
return - 1 ;
}
2004-10-03 04:19:59 +00:00
if ( account )
ast_cdr_setaccount ( chan , account ) ;
2003-02-02 19:04:14 +00:00
as - > chan = chan ;
strncpy ( as - > app , app , sizeof ( as - > app ) - 1 ) ;
if ( appdata )
strncpy ( as - > appdata , appdata , sizeof ( as - > appdata ) - 1 ) ;
as - > timeout = timeout ;
2004-05-17 21:10:26 +00:00
if ( variable ) {
2004-05-17 21:15:37 +00:00
vartmp = ast_strdupa ( variable ) ;
for ( var = strtok_r ( vartmp , " | " , & vartmp ) ; var ; var = strtok_r ( NULL , " | " , & vartmp ) )
pbx_builtin_setvar ( chan , var ) ;
2004-05-17 21:10:26 +00:00
}
2004-04-02 07:24:33 +00:00
/* Start a new thread, and get something handling this channel. */
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2004-08-08 17:15:02 +00:00
if ( ast_pthread_create ( & as - > p , & attr , async_wait , as ) ) {
2003-02-02 19:04:14 +00:00
ast_log ( LOG_WARNING , " Failed to start async wait \n " ) ;
free ( as ) ;
ast_hangup ( chan ) ;
return - 1 ;
}
res = 0 ;
}
return res ;
}
2003-04-06 18:19:51 +00:00
static void destroy_exten ( struct ast_exten * e )
{
2003-04-06 19:10:24 +00:00
if ( e - > priority = = PRIORITY_HINT )
ast_remove_hint ( e ) ;
2003-04-06 18:19:51 +00:00
if ( e - > datad )
e - > datad ( e - > data ) ;
free ( e ) ;
}
2004-10-03 04:19:59 +00:00
void __ast_context_destroy ( struct ast_context * con , const char * registrar )
1999-12-04 20:45:45 +00:00
{
struct ast_context * tmp , * tmpl = NULL ;
2001-03-30 18:47:35 +00:00
struct ast_include * tmpi , * tmpil = NULL ;
2001-09-28 21:20:52 +00:00
struct ast_sw * sw , * swl = NULL ;
2003-04-06 18:19:51 +00:00
struct ast_exten * e , * el , * en ;
2004-02-11 03:54:28 +00:00
struct ast_ignorepat * ipi , * ipl = NULL ;
2004-07-17 02:25:53 +00:00
2004-04-06 22:17:32 +00:00
ast_mutex_lock ( & conlock ) ;
1999-12-04 20:45:45 +00:00
tmp = contexts ;
while ( tmp ) {
2003-07-14 15:35:21 +00:00
if ( ( ( tmp - > name & & con & & con - > name & & ! strcasecmp ( tmp - > name , con - > name ) ) | | ! con ) & &
2001-04-27 15:07:56 +00:00
( ! registrar | | ! strcasecmp ( registrar , tmp - > registrar ) ) ) {
1999-12-04 20:45:45 +00:00
/* Okay, let's lock the structure to be sure nobody else
is searching through it . */
2003-08-13 15:25:16 +00:00
if ( ast_mutex_lock ( & tmp - > lock ) ) {
1999-12-04 20:45:45 +00:00
ast_log ( LOG_WARNING , " Unable to lock context lock \n " ) ;
return ;
}
if ( tmpl )
tmpl - > next = tmp - > next ;
else
contexts = tmp - > next ;
/* Okay, now we're safe to let it go -- in a sense, we were
ready to let it go as soon as we locked it . */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & tmp - > lock ) ;
2001-03-30 18:47:35 +00:00
for ( tmpi = tmp - > includes ; tmpi ; ) {
/* Free includes */
tmpil = tmpi ;
tmpi = tmpi - > next ;
free ( tmpil ) ;
2004-02-11 03:54:28 +00:00
}
for ( ipi = tmp - > ignorepats ; ipi ; ) {
2004-02-23 05:37:24 +00:00
/* Free ignorepats */
2004-02-11 03:54:28 +00:00
ipl = ipi ;
ipi = ipi - > next ;
free ( ipl ) ;
2001-03-30 18:47:35 +00:00
}
2001-09-28 21:20:52 +00:00
for ( sw = tmp - > alts ; sw ; ) {
2004-02-23 05:37:24 +00:00
/* Free switches */
2001-09-28 21:20:52 +00:00
swl = sw ;
sw = sw - > next ;
free ( swl ) ;
swl = sw ;
}
2003-04-06 18:19:51 +00:00
for ( e = tmp - > root ; e ; ) {
for ( en = e - > peer ; en ; ) {
el = en ;
en = en - > peer ;
destroy_exten ( el ) ;
}
el = e ;
e = e - > next ;
destroy_exten ( el ) ;
}
2004-06-22 17:42:14 +00:00
ast_mutex_destroy ( & tmp - > lock ) ;
1999-12-04 20:45:45 +00:00
free ( tmp ) ;
2001-04-27 15:07:56 +00:00
if ( ! con ) {
/* Might need to get another one -- restart */
tmp = contexts ;
tmpl = NULL ;
tmpil = NULL ;
continue ;
}
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & conlock ) ;
1999-12-04 20:45:45 +00:00
return ;
}
tmpl = tmp ;
tmp = tmp - > next ;
}
2004-04-06 22:17:32 +00:00
ast_mutex_unlock ( & conlock ) ;
2003-07-14 15:35:21 +00:00
}
2004-10-03 04:19:59 +00:00
void ast_context_destroy ( struct ast_context * con , const char * registrar )
2003-07-14 15:35:21 +00:00
{
2004-04-06 22:17:32 +00:00
__ast_context_destroy ( con , registrar ) ;
1999-12-04 20:45:45 +00:00
}
2004-07-09 08:32:09 +00:00
static void wait_for_hangup ( struct ast_channel * chan , void * data )
2001-04-27 15:07:56 +00:00
{
int res ;
struct ast_frame * f ;
2004-07-09 08:32:09 +00:00
int waittime ;
if ( ! data | | ! strlen ( data ) | | ( sscanf ( data , " %i " , & waittime ) ! = 1 ) | | ( waittime < 0 ) )
waittime = - 1 ;
if ( waittime > - 1 ) {
ast_safe_sleep ( chan , waittime * 1000 ) ;
} else do {
2001-04-27 15:07:56 +00:00
res = ast_waitfor ( chan , - 1 ) ;
if ( res < 0 )
return ;
f = ast_read ( chan ) ;
if ( f )
ast_frfree ( f ) ;
} while ( f ) ;
}
2004-06-22 03:51:34 +00:00
static int pbx_builtin_progress ( struct ast_channel * chan , void * data )
{
ast_indicate ( chan , AST_CONTROL_PROGRESS ) ;
return 0 ;
}
2001-04-27 15:07:56 +00:00
static int pbx_builtin_ringing ( struct ast_channel * chan , void * data )
{
ast_indicate ( chan , AST_CONTROL_RINGING ) ;
return 0 ;
}
static int pbx_builtin_busy ( struct ast_channel * chan , void * data )
{
ast_indicate ( chan , AST_CONTROL_BUSY ) ;
2004-07-09 08:32:09 +00:00
wait_for_hangup ( chan , data ) ;
2001-04-27 15:07:56 +00:00
return - 1 ;
}
static int pbx_builtin_congestion ( struct ast_channel * chan , void * data )
{
ast_indicate ( chan , AST_CONTROL_CONGESTION ) ;
2004-07-09 08:32:09 +00:00
wait_for_hangup ( chan , data ) ;
2001-04-27 15:07:56 +00:00
return - 1 ;
}
static int pbx_builtin_answer ( struct ast_channel * chan , void * data )
1999-12-04 20:45:45 +00:00
{
2004-12-29 12:49:35 +00:00
int delay = atoi ( data ) ;
int res ;
if ( chan - > _state = = AST_STATE_UP )
delay = 0 ;
res = ast_answer ( chan ) ;
if ( res )
return res ;
if ( delay )
res = ast_safe_sleep ( chan , delay ) ;
return res ;
1999-12-04 20:45:45 +00:00
}
2001-04-27 15:07:56 +00:00
static int pbx_builtin_setlanguage ( struct ast_channel * chan , void * data )
2000-01-24 07:14:18 +00:00
{
/* Copy the language as specified */
2004-10-13 22:47:42 +00:00
if ( data )
strncpy ( chan - > language , ( char * ) data , sizeof ( chan - > language ) - 1 ) ;
2000-01-24 07:14:18 +00:00
return 0 ;
}
2003-09-08 21:52:45 +00:00
static int pbx_builtin_resetcdr ( struct ast_channel * chan , void * data )
{
2004-09-24 21:33:48 +00:00
int flags = 0 ;
2003-09-08 21:52:45 +00:00
/* Reset the CDR as specified */
2004-09-24 21:33:48 +00:00
if ( data ) {
if ( strchr ( ( char * ) data , ' w ' ) )
flags | = AST_CDR_FLAG_POSTED ;
if ( strchr ( ( char * ) data , ' a ' ) )
flags | = AST_CDR_FLAG_LOCKED ;
}
ast_cdr_reset ( chan - > cdr , flags ) ;
2003-09-08 21:52:45 +00:00
return 0 ;
}
2003-04-27 19:35:06 +00:00
static int pbx_builtin_setaccount ( struct ast_channel * chan , void * data )
{
2004-06-28 03:48:53 +00:00
/* Copy the account code as specified */
2003-04-27 19:35:06 +00:00
if ( data )
ast_cdr_setaccount ( chan , ( char * ) data ) ;
else
ast_cdr_setaccount ( chan , " " ) ;
return 0 ;
}
2004-06-28 03:48:53 +00:00
static int pbx_builtin_setamaflags ( struct ast_channel * chan , void * data )
{
/* Copy the AMA Flags as specified */
if ( data )
ast_cdr_setamaflags ( chan , ( char * ) data ) ;
else
ast_cdr_setamaflags ( chan , " " ) ;
return 0 ;
}
2001-04-27 15:07:56 +00:00
static int pbx_builtin_hangup ( struct ast_channel * chan , void * data )
1999-12-04 20:45:45 +00:00
{
/* Just return non-zero and it will hang up */
return - 1 ;
}
2001-04-27 15:07:56 +00:00
static int pbx_builtin_stripmsd ( struct ast_channel * chan , void * data )
2000-01-07 10:54:40 +00:00
{
char newexten [ AST_MAX_EXTENSION ] = " " ;
2004-07-17 02:25:53 +00:00
2000-01-07 10:54:40 +00:00
if ( ! data | | ! atoi ( data ) ) {
ast_log ( LOG_DEBUG , " Ignoring, since number of digits to strip is 0 \n " ) ;
return 0 ;
}
if ( strlen ( chan - > exten ) > atoi ( data ) ) {
2001-11-24 15:15:01 +00:00
strncpy ( newexten , chan - > exten + atoi ( data ) , sizeof ( newexten ) - 1 ) ;
2000-01-07 10:54:40 +00:00
}
2001-11-24 15:15:01 +00:00
strncpy ( chan - > exten , newexten , sizeof ( chan - > exten ) - 1 ) ;
2000-01-07 10:54:40 +00:00
return 0 ;
}
2001-04-27 15:07:56 +00:00
static int pbx_builtin_prefix ( struct ast_channel * chan , void * data )
2000-01-07 10:54:40 +00:00
{
char newexten [ AST_MAX_EXTENSION ] = " " ;
2004-07-17 02:25:53 +00:00
2004-05-04 06:34:34 +00:00
if ( ! data | | ast_strlen_zero ( data ) ) {
2000-01-07 10:54:40 +00:00
ast_log ( LOG_DEBUG , " Ignoring, since there is no prefix to add \n " ) ;
return 0 ;
}
snprintf ( newexten , sizeof ( newexten ) , " %s%s " , ( char * ) data , chan - > exten ) ;
2001-11-24 15:15:01 +00:00
strncpy ( chan - > exten , newexten , sizeof ( chan - > exten ) - 1 ) ;
2001-04-27 15:07:56 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Prepended prefix, new extension is %s \n " , chan - > exten ) ;
2000-01-07 10:54:40 +00:00
return 0 ;
}
2003-04-28 04:18:47 +00:00
static int pbx_builtin_suffix ( struct ast_channel * chan , void * data )
{
char newexten [ AST_MAX_EXTENSION ] = " " ;
2004-07-17 02:25:53 +00:00
2004-05-04 06:34:34 +00:00
if ( ! data | | ast_strlen_zero ( data ) ) {
2003-04-28 04:18:47 +00:00
ast_log ( LOG_DEBUG , " Ignoring, since there is no suffix to add \n " ) ;
return 0 ;
}
snprintf ( newexten , sizeof ( newexten ) , " %s%s " , chan - > exten , ( char * ) data ) ;
strncpy ( chan - > exten , newexten , sizeof ( chan - > exten ) - 1 ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Appended suffix, new extension is %s \n " , chan - > exten ) ;
return 0 ;
}
static int pbx_builtin_gotoiftime ( struct ast_channel * chan , void * data )
{
int res = 0 ;
char * s , * ts ;
2004-11-11 21:23:45 +00:00
struct ast_timing timing ;
2003-04-28 04:18:47 +00:00
if ( ! data ) {
ast_log ( LOG_WARNING , " GotoIfTime requires an argument: \n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority \n " ) ;
return - 1 ;
}
s = strdup ( ( char * ) data ) ;
ts = s ;
/* Separate the Goto path */
strsep ( & ts , " ? " ) ;
2004-07-17 02:25:53 +00:00
/* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
2004-11-11 21:23:45 +00:00
if ( ast_build_timing ( & timing , s ) & & ast_check_timing ( & timing ) )
2003-04-28 04:18:47 +00:00
res = pbx_builtin_goto ( chan , ( void * ) ts ) ;
free ( s ) ;
return res ;
}
2001-04-27 15:07:56 +00:00
static int pbx_builtin_wait ( struct ast_channel * chan , void * data )
1999-12-04 20:45:45 +00:00
{
2001-11-24 15:15:01 +00:00
int ms ;
2004-07-17 02:25:53 +00:00
1999-12-04 20:45:45 +00:00
/* Wait for "n" seconds */
2004-03-04 21:45:21 +00:00
if ( data & & atof ( ( char * ) data ) ) {
ms = atof ( ( char * ) data ) * 1000 ;
2002-06-21 01:40:13 +00:00
return ast_safe_sleep ( chan , ms ) ;
2001-11-24 15:15:01 +00:00
}
1999-12-04 20:45:45 +00:00
return 0 ;
}
2004-04-06 04:14:19 +00:00
static int pbx_builtin_waitexten ( struct ast_channel * chan , void * data )
{
int ms ;
2004-10-16 19:46:02 +00:00
int res ;
2004-04-06 04:14:19 +00:00
/* Wait for "n" seconds */
2004-10-16 19:46:02 +00:00
if ( data & & atof ( ( char * ) data ) )
2004-04-06 04:14:19 +00:00
ms = atof ( ( char * ) data ) * 1000 ;
2004-10-16 19:46:02 +00:00
else if ( chan - > pbx )
ms = chan - > pbx - > rtimeout * 1000 ;
else
ms = 10000 ;
res = ast_waitfordigit ( chan , ms ) ;
if ( ! res ) {
2004-11-22 22:40:06 +00:00
if ( ast_exists_extension ( chan , chan - > context , chan - > exten , chan - > priority + 1 , chan - > cid . cid_num ) ) {
2004-10-16 19:46:02 +00:00
if ( option_verbose > 2 )
2004-11-22 22:40:06 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Timeout on %s, continuing... \n " , chan - > name ) ;
} else if ( ast_exists_extension ( chan , chan - > context , " t " , 1 , chan - > cid . cid_num ) ) {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Timeout on %s, going to 't' \n " , chan - > name ) ;
2004-10-16 19:46:02 +00:00
strncpy ( chan - > exten , " t " , sizeof ( chan - > exten ) ) ;
chan - > priority = 0 ;
} else {
ast_log ( LOG_WARNING , " Timeout but no rule 't' in context '%s' \n " , chan - > context ) ;
res = - 1 ;
}
2004-04-06 04:14:19 +00:00
}
2004-10-16 19:46:02 +00:00
return res ;
2004-04-06 04:14:19 +00:00
}
2001-04-27 15:07:56 +00:00
static int pbx_builtin_background ( struct ast_channel * chan , void * data )
1999-12-04 20:45:45 +00:00
{
2004-09-07 14:51:20 +00:00
int res = 0 ;
int option_skip = 0 ;
int option_noanswer = 0 ;
2004-11-25 02:57:34 +00:00
char * filename = NULL ;
2004-09-07 14:51:20 +00:00
char * stringp ;
char * options ;
char * lang = NULL ;
2004-11-25 02:57:34 +00:00
char * front = NULL , * back = NULL ;
2004-09-07 14:51:20 +00:00
2004-11-25 02:57:34 +00:00
if ( ! data | | ast_strlen_zero ( data ) | | ! ( filename = ast_strdupa ( data ) ) ) {
2004-09-07 14:51:20 +00:00
ast_log ( LOG_WARNING , " Background requires an argument(filename) \n " ) ;
return - 1 ;
}
stringp = filename ;
strsep ( & stringp , " | " ) ;
options = strsep ( & stringp , " | " ) ;
if ( options )
lang = strsep ( & stringp , " | " ) ;
if ( ! lang )
lang = chan - > language ;
if ( options & & ! strcasecmp ( options , " skip " ) )
option_skip = 1 ;
if ( options & & ! strcasecmp ( options , " noanswer " ) )
option_noanswer = 1 ;
/* Answer if need be */
if ( chan - > _state ! = AST_STATE_UP ) {
if ( option_skip ) {
return 0 ;
} else if ( ! option_noanswer ) {
res = ast_answer ( chan ) ;
}
}
if ( ! res ) {
/* Stop anything playing */
ast_stopstream ( chan ) ;
/* Stream a file */
2004-11-25 02:57:34 +00:00
front = filename ;
while ( ! res & & front ) {
if ( ( back = strchr ( front , ' & ' ) ) ) {
* back = ' \0 ' ;
back + + ;
}
res = ast_streamfile ( chan , front , lang ) ;
if ( ! res ) {
res = ast_waitstream ( chan , AST_DIGIT_ANY ) ;
ast_stopstream ( chan ) ;
} else {
ast_log ( LOG_WARNING , " ast_streamfile failed on %s for %s \n " , chan - > name , ( char * ) data ) ;
res = 0 ;
break ;
}
front = back ;
2004-09-07 14:51:20 +00:00
}
}
1999-12-04 20:45:45 +00:00
return res ;
}
2001-11-24 15:15:01 +00:00
static int pbx_builtin_atimeout ( struct ast_channel * chan , void * data )
{
int x = atoi ( ( char * ) data ) ;
2004-07-17 02:25:53 +00:00
2004-03-05 23:42:58 +00:00
/* Set the absolute maximum time how long a call can be connected */
2001-11-24 15:15:01 +00:00
ast_channel_setwhentohangup ( chan , x ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Set Absolute Timeout to %d \n " , x ) ;
return 0 ;
}
2001-04-27 15:07:56 +00:00
static int pbx_builtin_rtimeout ( struct ast_channel * chan , void * data )
1999-12-04 20:45:45 +00:00
{
/* Set the timeout for how long to wait between digits */
chan - > pbx - > rtimeout = atoi ( ( char * ) data ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Set Response Timeout to %d \n " , chan - > pbx - > rtimeout ) ;
return 0 ;
}
2001-04-27 15:07:56 +00:00
static int pbx_builtin_dtimeout ( struct ast_channel * chan , void * data )
1999-12-04 20:45:45 +00:00
{
/* Set the timeout for how long to wait between digits */
chan - > pbx - > dtimeout = atoi ( ( char * ) data ) ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Set Digit Timeout to %d \n " , chan - > pbx - > dtimeout ) ;
return 0 ;
}
2001-04-27 15:07:56 +00:00
static int pbx_builtin_goto ( struct ast_channel * chan , void * data )
1999-12-04 20:45:45 +00:00
{
2004-11-22 22:11:10 +00:00
int res ;
res = ast_parseable_goto ( chan , ( const char * ) data ) ;
if ( ! res & & ( option_verbose > 2 ) )
1999-12-04 20:45:45 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Goto (%s,%s,%d) \n " , chan - > context , chan - > exten , chan - > priority + 1 ) ;
2004-11-22 22:11:10 +00:00
return res ;
1999-12-04 20:45:45 +00:00
}
2001-04-27 15:07:56 +00:00
2004-11-22 22:11:10 +00:00
2004-10-22 20:59:38 +00:00
int pbx_builtin_serialize_variables ( struct ast_channel * chan , char * buf , size_t size )
{
struct ast_var_t * variables ;
struct varshead * headp ;
2004-10-27 01:34:06 +00:00
char * var = NULL , * val = NULL ;
2004-10-22 20:59:38 +00:00
int total = 0 ;
memset ( buf , 0 , size ) ;
if ( chan ) {
headp = & chan - > varshead ;
AST_LIST_TRAVERSE ( headp , variables , entries ) {
2004-10-27 02:26:17 +00:00
if ( chan & & variables & & ( var = ast_var_name ( variables ) ) & & ( val = ast_var_value ( variables ) ) & & ! ast_strlen_zero ( var ) & & ! ast_strlen_zero ( val ) ) {
2004-10-27 01:34:06 +00:00
snprintf ( buf + strlen ( buf ) , size - strlen ( buf ) , " %s=%s \n " , var , val ) ;
if ( strlen ( buf ) > = size ) {
ast_log ( LOG_ERROR , " Data Buffer Size Exceeded! \n " ) ;
break ;
}
total + + ;
2004-10-27 02:26:17 +00:00
} else
break ;
2004-10-22 20:59:38 +00:00
}
}
return total ;
}
2004-05-09 07:19:00 +00:00
char * pbx_builtin_getvar_helper ( struct ast_channel * chan , char * name )
{
2003-02-02 19:04:14 +00:00
struct ast_var_t * variables ;
struct varshead * headp ;
2004-05-09 07:19:00 +00:00
if ( chan )
headp = & chan - > varshead ;
2003-02-12 13:59:15 +00:00
else
headp = & globals ;
2003-02-02 19:04:14 +00:00
2003-02-12 13:59:15 +00:00
if ( name ) {
2003-02-02 19:04:14 +00:00
AST_LIST_TRAVERSE ( headp , variables , entries ) {
if ( ! strcmp ( name , ast_var_name ( variables ) ) )
return ast_var_value ( variables ) ;
}
2003-02-12 13:59:15 +00:00
if ( headp ! = & globals ) {
/* Check global variables if we haven't already */
headp = & globals ;
AST_LIST_TRAVERSE ( headp , variables , entries ) {
if ( ! strcmp ( name , ast_var_name ( variables ) ) )
return ast_var_value ( variables ) ;
}
}
}
2003-02-02 19:04:14 +00:00
return NULL ;
}
2004-11-01 02:23:28 +00:00
void pbx_builtin_setvar_helper ( struct ast_channel * chan , char * name , char * value )
2004-05-09 07:19:00 +00:00
{
2002-09-11 17:09:48 +00:00
struct ast_var_t * newvariable ;
2004-05-09 07:19:00 +00:00
struct varshead * headp ;
2004-11-01 02:23:28 +00:00
2004-05-09 07:19:00 +00:00
if ( chan )
2004-11-01 02:23:28 +00:00
headp = & chan - > varshead ;
2003-02-12 13:59:15 +00:00
else
2004-11-01 02:23:28 +00:00
headp = & globals ;
AST_LIST_TRAVERSE ( headp , newvariable , entries ) {
if ( strcasecmp ( ast_var_name ( newvariable ) , name ) = = 0 ) {
2002-09-11 17:09:48 +00:00
/* there is already such a variable, delete it */
2005-01-01 21:26:37 +00:00
AST_LIST_REMOVE ( headp , newvariable , entries ) ;
2002-09-11 17:09:48 +00:00
ast_var_delete ( newvariable ) ;
break ;
}
}
2004-11-01 02:23:28 +00:00
2003-02-12 13:59:15 +00:00
if ( value ) {
if ( ( option_verbose > 1 ) & & ( headp = = & globals ) )
2004-11-01 02:23:28 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Setting global variable '%s' to '%s' \n " , name , value ) ;
newvariable = ast_var_assign ( name , value ) ;
AST_LIST_INSERT_HEAD ( headp , newvariable , entries ) ;
2003-02-12 13:59:15 +00:00
}
2002-09-11 17:09:48 +00:00
}
2003-09-22 15:27:09 +00:00
int pbx_builtin_setvar ( struct ast_channel * chan , void * data )
2002-09-11 17:09:48 +00:00
{
char * name ;
char * value ;
2003-02-02 19:04:14 +00:00
char * stringp = NULL ;
2004-11-01 02:23:28 +00:00
2004-05-04 06:34:34 +00:00
if ( ! data | | ast_strlen_zero ( data ) ) {
2002-09-11 17:09:48 +00:00
ast_log ( LOG_WARNING , " Ignoring, since there is no variable to set \n " ) ;
return 0 ;
}
2004-11-01 02:23:28 +00:00
2004-11-17 04:48:58 +00:00
stringp = ast_strdupa ( data ) ;
2004-11-01 02:23:28 +00:00
name = strsep ( & stringp , " = " ) ;
value = strsep ( & stringp , " \0 " ) ;
pbx_builtin_setvar_helper ( chan , name , value ) ;
return ( 0 ) ;
2002-09-11 17:09:48 +00:00
}
2004-11-17 04:48:58 +00:00
int pbx_builtin_importvar ( struct ast_channel * chan , void * data )
{
char * name ;
char * value ;
char * stringp = NULL ;
char * channel ;
struct ast_channel * chan2 = NULL ;
char tmp [ 4096 ] = " " ;
char * s ;
if ( ! data | | ast_strlen_zero ( data ) ) {
ast_log ( LOG_WARNING , " Ignoring, since there is no variable to set \n " ) ;
return 0 ;
}
stringp = ast_strdupa ( data ) ;
name = strsep ( & stringp , " = " ) ;
channel = strsep ( & stringp , " | " ) ;
value = strsep ( & stringp , " \0 " ) ;
if ( channel & & value & & name ) {
while ( ( chan2 = ast_channel_walk_locked ( chan2 ) ) ) {
if ( ! strcmp ( chan2 - > name , channel ) )
break ;
ast_mutex_unlock ( & chan2 - > lock ) ;
}
if ( chan2 ) {
s = alloca ( strlen ( value ) + 4 ) ;
if ( s ) {
sprintf ( s , " ${%s} " , value ) ;
pbx_substitute_variables_helper ( chan2 , s , tmp , sizeof ( tmp ) - 1 ) ;
}
ast_mutex_unlock ( & chan2 - > lock ) ;
}
pbx_builtin_setvar_helper ( chan , name , tmp ) ;
}
return ( 0 ) ;
}
2003-02-13 06:00:14 +00:00
static int pbx_builtin_setglobalvar ( struct ast_channel * chan , void * data )
{
char * name ;
char * value ;
2004-11-01 02:23:28 +00:00
char * stringp = NULL ;
2004-05-04 06:34:34 +00:00
if ( ! data | | ast_strlen_zero ( data ) ) {
2003-02-13 06:00:14 +00:00
ast_log ( LOG_WARNING , " Ignoring, since there is no variable to set \n " ) ;
return 0 ;
}
2004-11-01 02:23:28 +00:00
stringp = data ;
name = strsep ( & stringp , " = " ) ;
value = strsep ( & stringp , " \0 " ) ;
pbx_builtin_setvar_helper ( NULL , name , value ) ;
return ( 0 ) ;
}
2003-02-13 06:00:14 +00:00
2003-02-12 13:59:15 +00:00
static int pbx_builtin_noop ( struct ast_channel * chan , void * data )
{
return 0 ;
}
void pbx_builtin_clear_globals ( void )
{
struct ast_var_t * vardata ;
while ( ! AST_LIST_EMPTY ( & globals ) ) {
2005-01-01 21:26:37 +00:00
vardata = AST_LIST_REMOVE_HEAD ( & globals , entries ) ;
2003-02-12 13:59:15 +00:00
ast_var_delete ( vardata ) ;
}
}
2004-05-09 07:19:00 +00:00
static int pbx_checkcondition ( char * condition )
{
2004-07-01 20:42:49 +00:00
return condition ? atoi ( condition ) : 0 ;
2002-09-11 17:09:48 +00:00
}
static int pbx_builtin_gotoif ( struct ast_channel * chan , void * data )
{
char * condition , * branch1 , * branch2 , * branch ;
char * s ;
int rc ;
2003-02-02 19:04:14 +00:00
char * stringp = NULL ;
2002-09-11 17:09:48 +00:00
2004-05-04 06:34:34 +00:00
if ( ! data | | ast_strlen_zero ( data ) ) {
2004-01-11 09:19:16 +00:00
ast_log ( LOG_WARNING , " Ignoring, since there is no variable to check \n " ) ;
2002-09-11 17:09:48 +00:00
return 0 ;
}
2004-07-01 20:42:49 +00:00
s = ast_strdupa ( data ) ;
2003-02-02 19:04:14 +00:00
stringp = s ;
condition = strsep ( & stringp , " ? " ) ;
branch1 = strsep ( & stringp , " : " ) ;
branch2 = strsep ( & stringp , " " ) ;
2004-07-01 20:42:49 +00:00
branch = pbx_checkcondition ( condition ) ? branch1 : branch2 ;
2002-09-11 17:09:48 +00:00
2004-05-04 06:34:34 +00:00
if ( ( branch = = NULL ) | | ast_strlen_zero ( branch ) ) {
2004-09-09 13:00:21 +00:00
ast_log ( LOG_DEBUG , " Not taking any branch \n " ) ;
2002-09-11 17:09:48 +00:00
return ( 0 ) ;
}
rc = pbx_builtin_goto ( chan , branch ) ;
2004-07-01 20:42:49 +00:00
2002-09-11 17:09:48 +00:00
return ( rc ) ;
}
2003-04-16 13:43:11 +00:00
static int pbx_builtin_saynumber ( struct ast_channel * chan , void * data )
{
int res = 0 ;
2004-04-29 02:30:14 +00:00
char tmp [ 256 ] ;
char * number = ( char * ) NULL ;
char * options = ( char * ) NULL ;
2004-05-04 06:34:34 +00:00
if ( ! data | | ast_strlen_zero ( ( char * ) data ) ) {
2004-04-29 02:30:14 +00:00
ast_log ( LOG_WARNING , " SayNumber requires an argument (number) \n " ) ;
return - 1 ;
}
strncpy ( tmp , ( char * ) data , sizeof ( tmp ) - 1 ) ;
number = tmp ;
strsep ( & number , " | " ) ;
options = strsep ( & number , " | " ) ;
if ( options ) {
if ( strcasecmp ( options , " f " ) & & strcasecmp ( options , " m " ) & &
strcasecmp ( options , " c " ) & & strcasecmp ( options , " n " ) ) {
ast_log ( LOG_WARNING , " SayNumber gender option is either 'f', 'm', 'c' or 'n' \n " ) ;
return - 1 ;
}
}
return res = ast_say_number ( chan , atoi ( ( char * ) tmp ) , " " , chan - > language , options ) ;
2003-04-16 13:43:11 +00:00
}
static int pbx_builtin_saydigits ( struct ast_channel * chan , void * data )
{
int res = 0 ;
2004-07-17 02:25:53 +00:00
2003-04-29 20:30:08 +00:00
if ( data )
res = ast_say_digit_str ( chan , ( char * ) data , " " , chan - > language ) ;
2003-04-16 13:43:11 +00:00
return res ;
}
2002-09-11 17:09:48 +00:00
2004-05-03 00:54:16 +00:00
static int pbx_builtin_saycharacters ( struct ast_channel * chan , void * data )
{
int res = 0 ;
2004-07-17 02:25:53 +00:00
2004-05-03 00:54:16 +00:00
if ( data )
res = ast_say_character_str ( chan , ( char * ) data , " " , chan - > language ) ;
return res ;
}
static int pbx_builtin_sayphonetic ( struct ast_channel * chan , void * data )
{
int res = 0 ;
2004-07-17 02:25:53 +00:00
2004-05-03 00:54:16 +00:00
if ( data )
res = ast_say_phonetic_str ( chan , ( char * ) data , " " , chan - > language ) ;
return res ;
}
1999-12-04 20:45:45 +00:00
int load_pbx ( void )
{
int x ;
2004-07-17 02:25:53 +00:00
1999-12-04 20:45:45 +00:00
/* Initialize the PBX */
if ( option_verbose ) {
ast_verbose ( " Asterisk PBX Core Initializing \n " ) ;
ast_verbose ( " Registering builtin applications: \n " ) ;
}
2004-06-09 01:45:08 +00:00
AST_LIST_HEAD_INIT ( & globals ) ;
2001-09-28 21:20:52 +00:00
ast_cli_register ( & show_applications_cli ) ;
ast_cli_register ( & show_application_cli ) ;
ast_cli_register ( & show_dialplan_cli ) ;
ast_cli_register ( & show_switches_cli ) ;
2004-07-17 02:25:53 +00:00
/* Register builtin applications */
for ( x = 0 ; x < sizeof ( builtins ) / sizeof ( struct pbx_builtin ) ; x + + ) {
1999-12-04 20:45:45 +00:00
if ( option_verbose )
ast_verbose ( VERBOSE_PREFIX_1 " [%s] \n " , builtins [ x ] . name ) ;
2001-04-27 15:07:56 +00:00
if ( ast_register_application ( builtins [ x ] . name , builtins [ x ] . execute , builtins [ x ] . synopsis , builtins [ x ] . description ) ) {
1999-12-04 20:45:45 +00:00
ast_log ( LOG_ERROR , " Unable to register builtin application '%s' \n " , builtins [ x ] . name ) ;
return - 1 ;
}
}
return 0 ;
}
2001-09-28 21:20:52 +00:00
/*
* Lock context list functions . . .
*/
int ast_lock_contexts ( )
{
2003-08-13 15:25:16 +00:00
return ast_mutex_lock ( & conlock ) ;
2001-09-28 21:20:52 +00:00
}
int ast_unlock_contexts ( )
{
2003-08-13 15:25:16 +00:00
return ast_mutex_unlock ( & conlock ) ;
2001-09-28 21:20:52 +00:00
}
/*
* Lock context . . .
*/
int ast_lock_context ( struct ast_context * con )
{
2003-08-13 15:25:16 +00:00
return ast_mutex_lock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
}
int ast_unlock_context ( struct ast_context * con )
{
2003-08-13 15:25:16 +00:00
return ast_mutex_unlock ( & con - > lock ) ;
2001-09-28 21:20:52 +00:00
}
/*
* Name functions . . .
*/
2004-10-03 04:19:59 +00:00
const char * ast_get_context_name ( struct ast_context * con )
2001-09-28 21:20:52 +00:00
{
return con ? con - > name : NULL ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_extension_name ( struct ast_exten * exten )
2001-09-28 21:20:52 +00:00
{
return exten ? exten - > exten : NULL ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_extension_label ( struct ast_exten * exten )
{
return exten ? exten - > label : NULL ;
}
const char * ast_get_include_name ( struct ast_include * inc )
2001-09-28 21:20:52 +00:00
{
return inc ? inc - > name : NULL ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_ignorepat_name ( struct ast_ignorepat * ip )
2001-09-28 21:20:52 +00:00
{
return ip ? ip - > pattern : NULL ;
}
int ast_get_extension_priority ( struct ast_exten * exten )
{
return exten ? exten - > priority : - 1 ;
}
/*
* Registrar info functions . . .
*/
2004-10-03 04:19:59 +00:00
const char * ast_get_context_registrar ( struct ast_context * c )
2001-09-28 21:20:52 +00:00
{
return c ? c - > registrar : NULL ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_extension_registrar ( struct ast_exten * e )
2001-09-28 21:20:52 +00:00
{
return e ? e - > registrar : NULL ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_include_registrar ( struct ast_include * i )
2001-09-28 21:20:52 +00:00
{
return i ? i - > registrar : NULL ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_ignorepat_registrar ( struct ast_ignorepat * ip )
2001-09-28 21:20:52 +00:00
{
return ip ? ip - > registrar : NULL ;
}
2004-08-21 18:55:39 +00:00
int ast_get_extension_matchcid ( struct ast_exten * e )
{
return e ? e - > matchcid : 0 ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_extension_cidmatch ( struct ast_exten * e )
2004-08-21 18:55:39 +00:00
{
return e ? e - > cidmatch : NULL ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_extension_app ( struct ast_exten * e )
2001-09-28 21:20:52 +00:00
{
return e ? e - > app : NULL ;
}
void * ast_get_extension_app_data ( struct ast_exten * e )
{
return e ? e - > data : NULL ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_switch_name ( struct ast_sw * sw )
2001-09-28 21:20:52 +00:00
{
return sw ? sw - > name : NULL ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_switch_data ( struct ast_sw * sw )
2001-09-28 21:20:52 +00:00
{
return sw ? sw - > data : NULL ;
}
2004-10-03 04:19:59 +00:00
const char * ast_get_switch_registrar ( struct ast_sw * sw )
2001-09-28 21:20:52 +00:00
{
return sw ? sw - > registrar : NULL ;
}
/*
* Walking functions . . .
*/
struct ast_context * ast_walk_contexts ( struct ast_context * con )
{
if ( ! con )
return contexts ;
else
return con - > next ;
}
struct ast_exten * ast_walk_context_extensions ( struct ast_context * con ,
struct ast_exten * exten )
{
if ( ! exten )
return con ? con - > root : NULL ;
else
return exten - > next ;
}
struct ast_sw * ast_walk_context_switches ( struct ast_context * con ,
struct ast_sw * sw )
{
if ( ! sw )
return con ? con - > alts : NULL ;
else
return sw - > next ;
}
struct ast_exten * ast_walk_extension_priorities ( struct ast_exten * exten ,
struct ast_exten * priority )
{
if ( ! priority )
return exten ;
else
return priority - > peer ;
}
struct ast_include * ast_walk_context_includes ( struct ast_context * con ,
struct ast_include * inc )
{
if ( ! inc )
return con ? con - > includes : NULL ;
else
return inc - > next ;
}
struct ast_ignorepat * ast_walk_context_ignorepats ( struct ast_context * con ,
struct ast_ignorepat * ip )
{
if ( ! ip )
return con ? con - > ignorepats : NULL ;
else
return ip - > next ;
}
2003-10-25 17:50:06 +00:00
int ast_context_verify_includes ( struct ast_context * con )
{
struct ast_include * inc ;
int res = 0 ;
for ( inc = ast_walk_context_includes ( con , NULL ) ; inc ; inc = ast_walk_context_includes ( con , inc ) )
if ( ! ast_context_find ( inc - > rname ) ) {
res = - 1 ;
ast_log ( LOG_WARNING , " Context '%s' tries includes non-existant context '%s' \n " ,
ast_get_context_name ( con ) , inc - > rname ) ;
}
return res ;
}
2004-10-24 02:53:24 +00:00
2004-11-22 22:11:10 +00:00
2004-11-23 20:25:02 +00:00
static int __ast_goto_if_exists ( struct ast_channel * chan , char * context , char * exten , int priority , int async )
2004-11-22 22:11:10 +00:00
{
2004-12-08 18:24:04 +00:00
int ( * goto_func ) ( struct ast_channel * chan , const char * context , const char * exten , int priority ) = NULL ;
2004-11-23 20:25:02 +00:00
2004-11-22 22:11:10 +00:00
if ( chan ) {
2004-12-08 18:24:04 +00:00
if ( async ) {
goto_func = ast_async_goto ;
} else {
goto_func = ast_explicit_goto ;
priority - - ;
if ( priority < 0 )
priority = 0 ;
}
if ( ast_exists_extension ( chan ,
context ? context : chan - > context ,
exten ? exten : chan - > exten ,
priority ,
chan - > cid . cid_num ) ) {
2004-11-23 20:25:02 +00:00
return goto_func ( chan ,
2004-12-08 18:24:04 +00:00
context ? context : chan - > context ,
exten ? exten : chan - > exten ,
priority ) ;
2004-11-22 22:11:10 +00:00
} else
return - 3 ;
}
return - 2 ;
}
2004-11-23 20:25:02 +00:00
int ast_goto_if_exists ( struct ast_channel * chan , char * context , char * exten , int priority ) {
return __ast_goto_if_exists ( chan , context , exten , priority , 0 ) ;
}
int ast_async_goto_if_exists ( struct ast_channel * chan , char * context , char * exten , int priority ) {
return __ast_goto_if_exists ( chan , context , exten , priority , 1 ) ;
}
2004-11-22 22:11:10 +00:00
int ast_parseable_goto ( struct ast_channel * chan , const char * goto_string )
{
char * s ;
char * exten , * pri , * context ;
char * stringp = NULL ;
int ipri ;
int mode = 0 ;
if ( ! goto_string | | ast_strlen_zero ( goto_string ) ) {
ast_log ( LOG_WARNING , " Goto requires an argument (optional context|optional extension|priority) \n " ) ;
return - 1 ;
}
s = ast_strdupa ( goto_string ) ;
stringp = s ;
context = strsep ( & stringp , " | " ) ;
exten = strsep ( & stringp , " | " ) ;
if ( ! exten ) {
/* Only a priority in this one */
pri = context ;
exten = NULL ;
context = NULL ;
} else {
pri = strsep ( & stringp , " | " ) ;
if ( ! pri ) {
/* Only an extension and priority in this one */
pri = exten ;
exten = context ;
context = NULL ;
}
}
if ( * pri = = ' + ' ) {
mode = 1 ;
pri + + ;
} else if ( * pri = = ' - ' ) {
mode = - 1 ;
pri + + ;
}
if ( sscanf ( pri , " %i " , & ipri ) ! = 1 ) {
if ( ( ipri = ast_findlabel_extension ( chan , context ? context : chan - > context , ( exten & & strcasecmp ( exten , " BYEXTENSION " ) ) ? exten : chan - > exten ,
pri , chan - > cid . cid_num ) ) < 1 ) {
ast_log ( LOG_WARNING , " Priority '%s' must be a number > 0, or valid label \n " , pri ) ;
return - 1 ;
} else
mode = 0 ;
}
/* At this point we have a priority and maybe an extension and a context */
if ( exten & & ! strcasecmp ( exten , " BYEXTENSION " ) )
exten = NULL ;
if ( mode )
ipri = chan - > priority + ( ipri * mode ) ;
/* This channel is currently in the PBX */
2004-12-08 18:24:04 +00:00
ast_explicit_goto ( chan , context , exten , ipri - 1 ) ;
2004-11-22 22:11:10 +00:00
ast_cdr_update ( chan ) ;
return 0 ;
}