2005-03-26 21:01:59 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
1999-12-04 20:45:45 +00:00
*
2005-01-21 07:06:25 +00:00
* Copyright ( C ) 1999 - 2005 , 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
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
1999-12-04 20:45:45 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
/*
*
* Core PBX routines .
*
1999-12-04 20:45:45 +00:00
*/
2005-03-04 06:36:18 +00:00
# include <sys/types.h>
2005-04-22 13:11:34 +00:00
# include <string.h>
# include <unistd.h>
# include <stdlib.h>
# include <stdio.h>
# include <ctype.h>
# include <errno.h>
# include <time.h>
# include <sys/time.h>
2005-06-06 20:27:51 +00:00
# include "asterisk.h"
2005-06-06 22:12:19 +00:00
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-06-06 20:27:51 +00:00
2005-04-21 06:02:45 +00:00
# include "asterisk/lock.h"
# include "asterisk/cli.h"
# include "asterisk/pbx.h"
# include "asterisk/channel.h"
# include "asterisk/options.h"
# include "asterisk/logger.h"
# include "asterisk/file.h"
# include "asterisk/callerid.h"
# include "asterisk/cdr.h"
# include "asterisk/config.h"
# include "asterisk/term.h"
# include "asterisk/manager.h"
# include "asterisk/ast_expr.h"
# include "asterisk/linkedlists.h"
# include "asterisk/say.h"
# include "asterisk/utils.h"
# include "asterisk/causes.h"
# include "asterisk/musiconhold.h"
# include "asterisk/app.h"
2005-07-08 21:14:34 +00:00
# include "asterisk/devicestate.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
2005-01-13 05:14:56 +00:00
# define SWITCH_DATA_LENGTH 256
2005-09-26 16:58:40 +00:00
# define VAR_BUF_SIZE 4096
2005-01-13 05:14:56 +00:00
2004-11-01 02:23:28 +00:00
# define VAR_NORMAL 1
# define VAR_SOFTTRAN 2
# define VAR_HARDTRAN 3
2005-04-15 05:47:40 +00:00
# define BACKGROUND_SKIP (1 << 0)
# define BACKGROUND_NOANSWER (1 << 1)
2005-07-12 01:34:06 +00:00
# define BACKGROUND_MATCHEXTEN (1 << 2)
# define BACKGROUND_PLAYBACK (1 << 3)
2005-04-15 05:47:40 +00:00
AST_DECLARE_OPTIONS ( background_opts , {
[ ' s ' ] = { BACKGROUND_SKIP } ,
[ ' n ' ] = { BACKGROUND_NOANSWER } ,
2005-07-12 01:34:06 +00:00
[ ' m ' ] = { BACKGROUND_MATCHEXTEN } ,
[ ' p ' ] = { BACKGROUND_PLAYBACK } ,
2005-04-15 05:47:40 +00:00
} ) ;
# define WAITEXTEN_MOH (1 << 0)
AST_DECLARE_OPTIONS ( waitexten_opts , {
[ ' m ' ] = { WAITEXTEN_MOH , 1 } ,
} ) ;
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 */
2005-03-29 06:16:49 +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 */
2005-04-01 19:56:35 +00:00
char * data ; /* Data load */
2005-01-13 05:14:56 +00:00
int eval ;
2004-07-17 02:25:53 +00:00
struct ast_sw * next ; /* Link them together */
2005-01-13 05:14:56 +00:00
char * tmpdata ;
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 */
2005-03-26 21:01: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 */
2005-03-26 21:01: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 {
2005-03-26 21:01:59 +00:00
int id ;
void * data ;
ast_state_cb_type callback ;
struct ast_state_cb * next ;
2003-03-30 22:55:42 +00:00
} ;
2005-03-17 21:05:10 +00:00
/* Hints are pointers from an extension in the dialplan to one or more devices (tech/name) */
2003-04-06 18:19:51 +00:00
struct ast_hint {
2005-03-26 21:01:59 +00:00
struct ast_exten * exten ; /* Extension */
int laststate ; /* Last known state */
struct ast_state_cb * callbacks ; /* Callback list for this extension */
struct ast_hint * next ; /* Pointer to next hint in list */
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 * ) ;
2005-02-25 00:25:28 +00:00
static int pbx_builtin_execiftime ( 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 * ) ;
2005-05-15 23:32:38 +00:00
static int pbx_builtin_setvar_old ( 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
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 ;
2005-05-18 01:49:13 +00:00
AST_MUTEX_DEFINE_STATIC ( maxcalllock ) ;
static int countcalls = 0 ;
2005-05-05 05:39:33 +00:00
AST_MUTEX_DEFINE_STATIC ( acflock ) ; /* Lock for the custom function list */
static struct ast_custom_function * acf_root = NULL ;
2005-03-04 06:36:18 +00:00
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
2005-07-19 15:54:17 +00:00
need separate modules */
2003-04-27 19:35:06 +00:00
{ " 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 "
2005-05-15 23:32:38 +00:00
" AbsoluteTimeout has been deprecated in favor of Set(TIMEOUT(absolute)=timeout) \n "
2004-07-17 02:25:53 +00:00
} ,
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 " ,
2005-07-12 01:34:06 +00:00
" Background(filename1[&filename2...][|options[|langoverride][|context]]): \n "
" Plays given files, while simultaneously waiting for the user to begin typing \n "
2005-04-15 05:47:40 +00:00
" 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 'langoverride' may be a language to use for playing the prompt \n "
2005-07-12 01:34:06 +00:00
" which differs from the current language of the channel. The optional \n "
" 'context' can be used to specify an optional context to exit into. \n "
" Returns -1 if thhe channel was hung up, or if the file does not exist./n "
" Returns 0 otherwise. \n \n "
2005-04-15 05:47:40 +00:00
" Options: \n "
" 's' - causes the playback of the message to be skipped \n "
" if the channel is not in the 'up' state (i.e. it \n "
" hasn't been answered yet.) If this happens, the \n "
" application will return immediately. \n "
" 'n' - don't answer the channel before playing the files \n "
2005-07-12 01:34:06 +00:00
" 'm' - only break if a digit hit matches a one digit \n "
" extension in the destination context \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 "
2005-04-20 14:40:47 +00:00
" exist the call would be terminated). The default timeout is 5 seconds. \n "
" Always returns 0. \n "
2005-05-15 23:32:38 +00:00
" DigitTimeout has been deprecated in favor of Set(TIMEOUT(digit)=timeout) \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
{ " 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. "
} ,
2005-02-25 00:25:28 +00:00
{ " ExecIfTime " , pbx_builtin_execiftime ,
" Conditional application execution on current time " ,
" ExecIfTime(<times>|<weekdays>|<mdays>|<months>?<appname>[|<appdata>]): \n "
" If the current time matches the specified time, then execute the specified \n "
" application. Each of the elements may be specified either as '*' (for always) \n "
2005-03-29 06:18:58 +00:00
" or as a range. See the 'include' syntax for details. It will return whatever \n "
" <appname> returns, or a non-zero value if the application is not found. \n "
2005-02-25 00:25:28 +00:00
} ,
2004-07-17 02:25:53 +00:00
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 "
2005-02-23 22:48:47 +00:00
" storing the current CDR before zeroing it out \b "
2005-04-01 19:56:35 +00:00
" - if 'w' option is specified record will be stored. \n "
" - if 'a' option is specified any stacked records will be stored. \n "
" - if 'v' option is specified any variables will be saved. \n "
2005-02-23 22:48:47 +00:00
" Always returns 0. \n "
2004-07-17 02:25:53 +00:00
} ,
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 "
2005-04-20 14:40:47 +00:00
" if not the call would be terminated. The default timeout is 10 seconds. \n "
" Always returns 0. \n "
2005-05-15 23:32:38 +00:00
" ResponseTimeout has been deprecated in favor of Set(TIMEOUT(response)=timeout) \n "
2004-07-17 02:25:53 +00:00
} ,
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 " ,
2005-04-01 19:56:35 +00:00
" SetAccount([account]): Set the channel account code for billing \n "
" purposes. Always returns 0. \n "
2004-07-17 02:25:53 +00:00
} ,
2004-06-28 03:48:53 +00:00
{ " SetAMAFlags " , pbx_builtin_setamaflags ,
2004-07-17 02:25:53 +00:00
" Sets AMA Flags " ,
2005-04-01 19:56:35 +00:00
" SetAMAFlags([flag]): Set the channel AMA Flags for billing \n "
" purposes. Always returns 0. \n "
2004-07-17 02:25:53 +00:00
} ,
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 ,
2005-04-01 19:56:35 +00:00
" Sets channel language " ,
" SetLanguage(language): Set the channel language to 'language'. This \n "
2004-07-17 02:25:53 +00:00
" 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 "
2005-04-01 19:56:35 +00:00
" requested to be played, if the file 'fr/demo-congrats' exists, then \n "
2004-07-17 02:25:53 +00:00
" it will play that file, and if not will play the normal 'demo-congrats'. \n "
2005-04-01 19:56:35 +00:00
" For some language codes, SetLanguage also changes the syntax of some \n "
" Asterisk functions, like SayNumber. \n "
" Always returns 0. \n "
2005-05-15 23:32:38 +00:00
" SetLanguage has been deprecated in favor of Set(LANGUAGE()=language) \n "
2004-07-17 02:25:53 +00:00
} ,
2003-02-12 13:59:15 +00:00
2005-05-15 23:32:38 +00:00
{ " Set " , pbx_builtin_setvar ,
" Set channel variable(s) or function value(s) " ,
" Set(name1=value1|name2=value2|..[|options]) \n "
" This function can be used to set the value of channel variables \n "
" or dialplan functions. It will accept up to 24 name/value pairs. \n "
" When setting variables, if the variable name is prefixed with _, \n "
" the variable will be inherited into channels created from the \n "
" current channel. If the variable name is prefixed with __, \n "
" the variable will be inherited into channels created from the \n "
" current channel and all child channels. \n "
" The last argument, if it does not contain '=', is interpreted \n "
" as a string of options. The valid options are: \n "
" g - Set variable globally instead of on the channel \n "
" (applies only to variables, not functions) \n "
} ,
{ " SetVar " , pbx_builtin_setvar_old ,
" Set channel variable(s) " ,
" SetVar(name1=value1|name2=value2|..[|options]) \n "
" SetVar has been deprecated in favor of Set. \n "
2005-04-01 19:56:35 +00:00
} ,
2002-09-11 17:09:48 +00:00
2004-11-17 04:48:58 +00:00
{ " ImportVar " , pbx_builtin_importvar ,
2005-05-14 00:36:55 +00:00
" Import a variable from a channel into a new variable " ,
" ImportVar(newvar=channelname|variable): This application imports a \n "
" variable from the specified channel (as opposed to the current one) \n "
" and stores it as a variable in the current channel (the channel that \n "
" is calling this application). If the new variable name is prefixed by \n "
" a single underscore \" _ \" , then it will be inherited into any channels \n "
" created from this one. If it is prefixed with two underscores,then \n "
" the variable will have infinite inheritance, meaning that it will be \n "
" present in any descendent channel of this one. \n "
} ,
2004-11-17 04:48:58 +00:00
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 " ,
2005-04-01 19:56:35 +00:00
" Suffix(digits): Appends the digit string specified by digits to the \n "
" channel's associated extension. For example, the number 555 when suffixed \n "
2004-07-17 02:25:53 +00:00
" 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 "
2005-04-01 19:56:35 +00:00
" 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 "
2004-07-17 02:25:53 +00:00
" 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 " ,
2005-04-15 05:47:40 +00:00
" WaitExten([seconds][|options]): Waits for the user to enter a new extension for the \n "
2005-04-01 19:56:35 +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 "
2005-04-15 05:47:40 +00:00
" default extension timeout will be used. \n "
" Options: \n "
" 'm[(x)]' - Provide music on hold to the caller while waiting for an extension. \n "
" Optionally, specify the class for music on hold within parenthesis. \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
} ;
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 ;
2005-03-17 21:05:10 +00:00
AST_MUTEX_DEFINE_STATIC ( applock ) ; /* Lock for the application list */
1999-12-04 20:45:45 +00:00
2001-09-28 21:20:52 +00:00
struct ast_switch * switches = NULL ;
2005-03-17 21:05:10 +00:00
AST_MUTEX_DEFINE_STATIC ( switchlock ) ; /* Lock for switches */
2001-09-28 21:20:52 +00:00
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
{
2005-04-01 19:56:35 +00:00
/* This function is special. It saves the stack so that no matter
1999-12-04 20:45:45 +00:00
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 ; \
2005-04-03 22:24:17 +00:00
case ' ! ' : \
2005-04-03 21:32:33 +00:00
/* Early match */ \
return 2 ; \
2003-09-14 00:32:51 +00:00
case ' ' : \
case ' - ' : \
/* Ignore these characters */ \
data - - ; \
break ; \
default : \
if ( * data ! = * pattern ) \
match = 0 ; \
} \
data + + ; \
pattern + + ; \
} \
2005-04-03 22:24:17 +00:00
/* If we ran off the end of the data and the pattern ends in '!', match */ \
if ( match & & ! * data & & ( * pattern = = ' ! ' ) ) \
2005-04-03 21:32:33 +00:00
return 2 ; \
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 ) ;
2005-04-03 21:32:33 +00:00
/* If there's more or we don't care about more, or if it's a possible early match,
return non - zero ; otherwise it ' s a miss */
if ( ! needmore | | * pattern | | match = = 2 ) {
2003-02-02 19:04:14 +00:00
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 ;
}
2005-07-19 15:54:17 +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
2005-07-19 15:54:17 +00:00
# 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 */
2005-04-01 19:56:35 +00:00
for ( x = 0 ; x < * stacklen ; x + + ) {
2001-03-30 18:47:35 +00:00
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 ) ) {
2005-04-03 21:32:33 +00:00
struct ast_exten * earlymatch = NULL ;
2001-03-30 18:47:35 +00:00
if ( * status < STATUS_NO_EXTENSION )
* status = STATUS_NO_EXTENSION ;
2005-04-03 21:32:33 +00:00
for ( eroot = tmp - > root ; eroot ; eroot = eroot - > next ) {
int match = 0 ;
2001-03-30 18:47:35 +00:00
/* Match extension */
2003-02-02 19:04:14 +00:00
if ( ( ( ( action ! = HELPER_MATCHMORE ) & & ast_extension_match ( eroot - > exten , exten ) ) | |
2005-04-03 21:32:33 +00:00
( ( action = = HELPER_CANMATCH ) & & ( ast_extension_close ( eroot - > exten , exten , 0 ) ) ) | |
( ( action = = HELPER_MATCHMORE ) & & ( match = ast_extension_close ( eroot - > exten , exten , 1 ) ) ) ) & &
( ! eroot - > matchcid | | matchcid ( eroot - > cidmatch , callerid ) ) ) {
if ( action = = HELPER_MATCHMORE & & match = = 2 & & ! earlymatch ) {
2005-04-03 22:24:17 +00:00
/* It matched an extension ending in a '!' wildcard
2005-04-03 21:32:33 +00:00
So ignore it for now , unless there ' s a better match */
earlymatch = eroot ;
} else {
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 ;
}
2005-04-03 21:32:33 +00:00
}
2001-03-30 18:47:35 +00:00
}
2005-04-03 21:32:33 +00:00
}
if ( earlymatch ) {
/* Bizarre logic for HELPER_MATCHMORE. We return zero to break out
of the loop waiting for more digits , and _then_ match ( normally )
the extension we ended up with . We got an early - matching wildcard
pattern , so return NULL to break out of the loop . */
return NULL ;
2001-03-30 18:47:35 +00:00
}
2001-09-28 21:20:52 +00:00
/* Check alternative switches */
sw = tmp - > alts ;
while ( sw ) {
if ( ( asw = pbx_findswitch ( sw - > name ) ) ) {
2005-01-13 05:14:56 +00:00
/* Substitute variables now */
if ( sw - > eval )
pbx_substitute_variables_helper ( chan , sw - > data , sw - > tmpdata , SWITCH_DATA_LENGTH - 1 ) ;
2001-09-28 21:20:52 +00:00
if ( action = = HELPER_CANMATCH )
2005-01-13 05:14:56 +00:00
res = asw - > canmatch ? asw - > canmatch ( chan , context , exten , priority , callerid , sw - > eval ? sw - > tmpdata : sw - > data ) : 0 ;
2003-02-02 19:04:14 +00:00
else if ( action = = HELPER_MATCHMORE )
2005-01-13 05:14:56 +00:00
res = asw - > matchmore ? asw - > matchmore ( chan , context , exten , priority , callerid , sw - > eval ? sw - > tmpdata : sw - > data ) : 0 ;
2001-09-28 21:20:52 +00:00
else
2005-01-13 05:14:56 +00:00
res = asw - > exists ? asw - > exists ( chan , context , exten , priority , callerid , sw - > eval ? sw - > tmpdata : sw - > data ) : 0 ;
2001-09-28 21:20:52 +00:00
if ( res ) {
/* Got a match */
* swo = asw ;
2005-01-13 05:14:56 +00:00
* data = sw - > eval ? sw - > tmpdata : 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 ;
}
2005-09-29 04:39:14 +00:00
/* Note that it's negative -- that's important later. */
# define DONT_HAVE_LENGTH 0x80000000
static int parse_variable_name ( char * var , int * offset , int * length , int * isfunc )
{
char * varchar , * offsetchar = NULL ;
int parens = 0 ;
* offset = 0 ;
* length = DONT_HAVE_LENGTH ;
* isfunc = 0 ;
for ( varchar = var ; * varchar ; varchar + + ) {
switch ( * varchar ) {
case ' ( ' :
( * isfunc ) + + ;
parens + + ;
break ;
case ' ) ' :
parens - - ;
break ;
case ' : ' :
if ( parens = = 0 ) {
offsetchar = varchar + 1 ;
* varchar = ' \0 ' ;
goto pvn_endfor ;
}
}
}
pvn_endfor :
if ( offsetchar ) {
sscanf ( offsetchar , " %d:%d " , offset , length ) ;
return 1 ;
} else {
return 0 ;
}
}
static char * substring ( char * value , int offset , int length , char * workspace , size_t workspace_len )
{
char * ret = workspace ;
/* No need to do anything */
if ( offset = = 0 & & length = = - 1 ) {
return value ;
}
ast_copy_string ( workspace , value , workspace_len ) ;
if ( abs ( offset ) > strlen ( ret ) ) { /* Offset beyond string */
if ( offset > = 0 )
offset = strlen ( ret ) ;
else
offset = - strlen ( ret ) ;
}
/* Detect too-long length */
if ( ( offset < 0 & & length > - offset ) | | ( offset > = 0 & & offset + length > strlen ( ret ) ) ) {
if ( offset > = 0 )
length = strlen ( ret ) - offset ;
else
length = strlen ( ret ) + offset ;
}
/* Bounce up to the right offset */
if ( offset > = 0 )
ret + = offset ;
else
ret + = strlen ( ret ) + offset ;
/* Chop off at the requisite length */
if ( length > = 0 )
ret [ length ] = ' \0 ' ;
return ret ;
}
2005-02-13 20:57:52 +00:00
/*--- pbx_retrieve_variable: Support for Asterisk built-in variables and
functions in the dialplan
- - - */
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
{
2005-09-07 21:01:31 +00:00
char tmpvar [ 80 ] ;
2003-04-21 03:02:22 +00:00
time_t thistime ;
struct tm brokentime ;
2005-09-29 04:39:14 +00:00
int offset , offset2 , isfunc ;
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 ;
2005-09-29 04:39:14 +00:00
ast_copy_string ( tmpvar , var , sizeof ( tmpvar ) ) ;
if ( parse_variable_name ( tmpvar , & offset , & offset2 , & isfunc ) ) {
pbx_retrieve_variable ( c , tmpvar , ret , workspace , workspacelen , headp ) ;
2005-02-13 20:57:52 +00:00
if ( ! ( * ret ) )
return ;
2005-09-29 04:39:14 +00:00
* ret = substring ( * ret , offset , offset2 , workspace , workspacelen ) ;
2005-02-09 21:10:41 +00:00
} else if ( c & & ! strncmp ( var , " CALL " , 4 ) ) {
if ( ! strncmp ( var + 4 , " ER " , 2 ) ) {
if ( ! strncmp ( var + 6 , " ID " , 2 ) ) {
2005-02-13 20:57:52 +00:00
if ( ! var [ 8 ] ) { /* CALLERID */
2005-02-09 21:10:41 +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 {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > cid . cid_num , workspacelen ) ;
2005-02-09 21:10:41 +00:00
}
* ret = workspace ;
} else if ( c - > cid . cid_name ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > cid . cid_name , workspacelen ) ;
2005-02-09 21:10:41 +00:00
* ret = workspace ;
} else
* ret = NULL ;
} else if ( ! strcmp ( var + 8 , " NUM " ) ) {
/* CALLERIDNUM */
if ( c - > cid . cid_num ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > cid . cid_num , workspacelen ) ;
2005-02-09 21:10:41 +00:00
* ret = workspace ;
} else
* ret = NULL ;
} else if ( ! strcmp ( var + 8 , " NAME " ) ) {
/* CALLERIDNAME */
if ( c - > cid . cid_name ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > cid . cid_name , workspacelen ) ;
2005-02-09 21:10:41 +00:00
* ret = workspace ;
} else
* ret = NULL ;
}
} else if ( ! strcmp ( var + 6 , " ANI " ) ) {
/* CALLERANI */
if ( c - > cid . cid_ani ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > cid . cid_ani , workspacelen ) ;
2005-02-09 21:10:41 +00:00
* ret = workspace ;
} else
* ret = NULL ;
2005-02-17 19:41:23 +00:00
} else
goto icky ;
2005-02-09 21:10:41 +00:00
} else if ( ! strncmp ( var + 4 , " ING " , 3 ) ) {
if ( ! strcmp ( var + 7 , " PRES " ) ) {
/* CALLINGPRES */
snprintf ( workspace , workspacelen , " %d " , c - > cid . cid_pres ) ;
* ret = workspace ;
} else if ( ! strcmp ( var + 7 , " ANI2 " ) ) {
/* CALLINGANI2 */
snprintf ( workspace , workspacelen , " %d " , c - > cid . cid_ani2 ) ;
* ret = workspace ;
} else if ( ! strcmp ( var + 7 , " TON " ) ) {
/* CALLINGTON */
snprintf ( workspace , workspacelen , " %d " , c - > cid . cid_ton ) ;
* ret = workspace ;
} else if ( ! strcmp ( var + 7 , " TNS " ) ) {
/* CALLINGTNS */
snprintf ( workspace , workspacelen , " %d " , c - > cid . cid_tns ) ;
* ret = workspace ;
2005-02-17 19:41:23 +00:00
} else
goto icky ;
2005-02-10 16:38:39 +00:00
} else
goto icky ;
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 ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > cid . cid_dnid , workspacelen ) ;
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 " ) ) {
2005-02-01 01:53:25 +00:00
if ( ! ast_get_hint ( workspace , workspacelen , NULL , 0 , c , c - > context , c - > exten ) )
* ret = NULL ;
else
* ret = workspace ;
} else if ( c & & ! strcmp ( var , " HINTNAME " ) ) {
if ( ! ast_get_hint ( NULL , 0 , 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 " ) ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > exten , workspacelen ) ;
2003-04-18 15:34:25 +00:00
* 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 ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > cid . cid_rdnis , workspacelen ) ;
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 " ) ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > context , workspacelen ) ;
2003-04-18 15:34:25 +00:00
* 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 ;
2003-08-03 18:33:50 +00:00
} else if ( c & & ! strcmp ( var , " CHANNEL " ) ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > name , workspacelen ) ;
2003-04-18 15:34:25 +00:00
* ret = workspace ;
2005-02-09 21:10:41 +00:00
} else if ( ! 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 ;
2005-02-09 21:10:41 +00:00
} else if ( ! 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 ;
2005-02-09 21:10:41 +00:00
} else if ( ! 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 " ) ) {
2005-04-29 17:00:33 +00:00
snprintf ( workspace , workspacelen , " %d " , c - > hangupcause ) ;
2004-05-09 07:19:00 +00:00
* ret = workspace ;
} else if ( c & & ! strcmp ( var , " ACCOUNTCODE " ) ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > accountcode , workspacelen ) ;
2004-05-09 07:19:00 +00:00
* ret = workspace ;
} else if ( c & & ! strcmp ( var , " LANGUAGE " ) ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , c - > language , workspacelen ) ;
2004-05-09 07:19:00 +00:00
* ret = workspace ;
2003-03-18 06:00:18 +00:00
} else {
2005-02-10 16:38:39 +00:00
icky :
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 ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , * ret , workspacelen ) ;
2003-08-03 18:33:50 +00:00
* 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 ) {
2005-07-19 15:54:17 +00:00
* ret = ast_var_value ( variables ) ;
2003-04-18 15:34:25 +00:00
if ( * ret ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( workspace , * ret , workspacelen ) ;
2003-04-18 15:34:25 +00:00
* ret = workspace ;
}
}
2003-03-18 06:00:18 +00:00
}
}
}
2003-02-21 06:00:08 +00:00
}
2005-03-04 06:36:18 +00:00
static int handle_show_functions ( int fd , int argc , char * argv [ ] )
{
2005-05-05 05:39:33 +00:00
struct ast_custom_function * acf ;
2005-08-22 18:47:19 +00:00
int count_acf = 0 ;
2005-03-04 06:36:18 +00:00
ast_cli ( fd , " Installed Custom Functions: \n -------------------------------------------------------------------------------- \n " ) ;
2005-05-05 05:39:33 +00:00
for ( acf = acf_root ; acf ; acf = acf - > next ) {
2005-05-08 17:10:58 +00:00
ast_cli ( fd , " %-20.20s %-35.35s %s \n " , acf - > name , acf - > syntax , acf - > synopsis ) ;
2005-08-22 18:47:19 +00:00
count_acf + + ;
2005-03-04 06:36:18 +00:00
}
2005-08-22 18:47:19 +00:00
ast_cli ( fd , " %d custom functions installed. \n " , count_acf ) ;
2005-03-04 06:36:18 +00:00
return 0 ;
}
2005-05-05 05:39:33 +00:00
static int handle_show_function ( int fd , int argc , char * argv [ ] )
2005-03-04 06:36:18 +00:00
{
2005-05-05 05:39:33 +00:00
struct ast_custom_function * acf ;
/* 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 ;
char stxtitle [ 40 ] , * syntax = NULL ;
int synopsis_size , description_size , syntax_size ;
2005-03-04 06:36:18 +00:00
2005-05-05 05:39:33 +00:00
if ( argc < 3 ) return RESULT_SHOWUSAGE ;
if ( ! ( acf = ast_custom_function_find ( argv [ 2 ] ) ) ) {
ast_cli ( fd , " No function by that name registered. \n " ) ;
return RESULT_FAILURE ;
}
if ( acf - > synopsis )
synopsis_size = strlen ( acf - > synopsis ) + 23 ;
else
synopsis_size = strlen ( " Not available " ) + 23 ;
synopsis = alloca ( synopsis_size ) ;
if ( acf - > desc )
description_size = strlen ( acf - > desc ) + 23 ;
else
description_size = strlen ( " Not available " ) + 23 ;
description = alloca ( description_size ) ;
if ( acf - > syntax )
syntax_size = strlen ( acf - > syntax ) + 23 ;
else
syntax_size = strlen ( " Not available " ) + 23 ;
syntax = alloca ( syntax_size ) ;
snprintf ( info , 64 + AST_MAX_APP , " \n -= Info about function '%s' =- \n \n " , acf - > name ) ;
term_color ( infotitle , info , COLOR_MAGENTA , 0 , 64 + AST_MAX_APP + 22 ) ;
term_color ( stxtitle , " [Syntax] \n " , COLOR_MAGENTA , 0 , 40 ) ;
term_color ( syntitle , " [Synopsis] \n " , COLOR_MAGENTA , 0 , 40 ) ;
term_color ( destitle , " [Description] \n " , COLOR_MAGENTA , 0 , 40 ) ;
term_color ( syntax ,
acf - > syntax ? acf - > syntax : " Not available " ,
COLOR_CYAN , 0 , syntax_size ) ;
term_color ( synopsis ,
acf - > synopsis ? acf - > synopsis : " Not available " ,
COLOR_CYAN , 0 , synopsis_size ) ;
term_color ( description ,
acf - > desc ? acf - > desc : " Not available " ,
COLOR_CYAN , 0 , description_size ) ;
ast_cli ( fd , " %s%s%s \n \n %s%s \n \n %s%s \n " , infotitle , stxtitle , syntax , syntitle , synopsis , destitle , description ) ;
return RESULT_SUCCESS ;
}
static char * complete_show_function ( char * line , char * word , int pos , int state )
{
struct ast_custom_function * acf ;
int which = 0 ;
/* try to lock functions list ... */
if ( ast_mutex_lock ( & acflock ) ) {
ast_log ( LOG_ERROR , " Unable to lock function list \n " ) ;
return NULL ;
}
acf = acf_root ;
while ( acf ) {
if ( ! strncasecmp ( word , acf - > name , strlen ( word ) ) ) {
if ( + + which > state ) {
char * ret = strdup ( acf - > name ) ;
ast_mutex_unlock ( & acflock ) ;
return ret ;
}
}
acf = acf - > next ;
}
ast_mutex_unlock ( & acflock ) ;
return NULL ;
}
struct ast_custom_function * ast_custom_function_find ( char * name )
{
struct ast_custom_function * acfptr ;
/* try to lock functions list ... */
if ( ast_mutex_lock ( & acflock ) ) {
ast_log ( LOG_ERROR , " Unable to lock function list \n " ) ;
return NULL ;
}
for ( acfptr = acf_root ; acfptr ; acfptr = acfptr - > next ) {
2005-03-04 06:36:18 +00:00
if ( ! strcmp ( name , acfptr - > name ) ) {
break ;
}
2005-05-05 05:39:33 +00:00
}
ast_mutex_unlock ( & acflock ) ;
2005-03-04 06:36:18 +00:00
return acfptr ;
}
2005-05-05 05:39:33 +00:00
int ast_custom_function_unregister ( struct ast_custom_function * acf )
2005-03-04 06:36:18 +00:00
{
2005-05-05 05:39:33 +00:00
struct ast_custom_function * acfptr , * lastacf = NULL ;
int res = - 1 ;
2005-03-04 06:36:18 +00:00
2005-05-05 05:39:33 +00:00
if ( ! acf )
return - 1 ;
/* try to lock functions list ... */
if ( ast_mutex_lock ( & acflock ) ) {
ast_log ( LOG_ERROR , " Unable to lock function list \n " ) ;
return - 1 ;
}
for ( acfptr = acf_root ; acfptr ; acfptr = acfptr - > next ) {
if ( acfptr = = acf ) {
if ( lastacf ) {
lastacf - > next = acf - > next ;
} else {
acf_root = acf - > next ;
2005-03-04 06:36:18 +00:00
}
2005-05-05 05:39:33 +00:00
res = 0 ;
break ;
2005-03-04 06:36:18 +00:00
}
2005-05-05 05:39:33 +00:00
lastacf = acfptr ;
2005-03-04 06:36:18 +00:00
}
2005-05-05 05:39:33 +00:00
ast_mutex_unlock ( & acflock ) ;
if ( ! res & & ( option_verbose > 1 ) )
ast_verbose ( VERBOSE_PREFIX_2 " Unregistered custom function %s \n " , acf - > name ) ;
return res ;
2005-03-04 06:36:18 +00:00
}
2005-05-05 05:39:33 +00:00
int ast_custom_function_register ( struct ast_custom_function * acf )
2005-03-04 06:36:18 +00:00
{
2005-05-05 05:39:33 +00:00
if ( ! acf )
return - 1 ;
2005-03-04 06:36:18 +00:00
2005-05-05 05:39:33 +00:00
/* try to lock functions list ... */
if ( ast_mutex_lock ( & acflock ) ) {
2005-07-19 15:54:17 +00:00
ast_log ( LOG_ERROR , " Unable to lock function list. Failed registering function %s \n " , acf - > name ) ;
2005-05-05 05:39:33 +00:00
return - 1 ;
2005-03-04 06:36:18 +00:00
}
2005-05-05 05:39:33 +00:00
if ( ast_custom_function_find ( acf - > name ) ) {
ast_log ( LOG_ERROR , " Function %s already registered. \n " , acf - > name ) ;
ast_mutex_unlock ( & acflock ) ;
return - 1 ;
}
acf - > next = acf_root ;
acf_root = acf ;
ast_mutex_unlock ( & acflock ) ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Registered custom function %s \n " , acf - > name ) ;
return 0 ;
2005-03-04 06:36:18 +00:00
}
2005-03-29 06:16:49 +00:00
char * ast_func_read ( struct ast_channel * chan , const char * in , char * workspace , size_t len )
{
char * args = NULL , * function , * p ;
char * ret = " 0 " ;
2005-05-05 05:39:33 +00:00
struct ast_custom_function * acfptr ;
2005-03-04 06:36:18 +00:00
2005-03-29 06:16:49 +00:00
function = ast_strdupa ( in ) ;
2005-07-19 15:54:17 +00:00
if ( ! function ) {
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
return ret ;
}
if ( ( args = strchr ( function , ' ( ' ) ) ) {
* args = ' \0 ' ;
args + + ;
if ( ( p = strrchr ( args , ' ) ' ) ) ) {
* p = ' \0 ' ;
2005-03-29 06:16:49 +00:00
} else {
2005-07-19 15:54:17 +00:00
ast_log ( LOG_WARNING , " Can't find trailing parenthesis? \n " ) ;
2005-03-29 06:16:49 +00:00
}
2005-07-19 15:54:17 +00:00
} else {
ast_log ( LOG_WARNING , " Function doesn't contain parentheses. Assuming null argument. \n " ) ;
}
2005-03-04 06:36:18 +00:00
2005-07-19 15:54:17 +00:00
if ( ( acfptr = ast_custom_function_find ( function ) ) ) {
/* run the custom function */
if ( acfptr - > read ) {
return acfptr - > read ( chan , function , args , workspace , len ) ;
2005-03-29 06:16:49 +00:00
} else {
2005-07-19 15:54:17 +00:00
ast_log ( LOG_ERROR , " Function %s cannot be read \n " , function ) ;
2005-03-04 06:36:18 +00:00
}
2005-03-29 06:16:49 +00:00
} else {
2005-07-19 15:54:17 +00:00
ast_log ( LOG_ERROR , " Function %s not registered \n " , function ) ;
2005-03-29 06:16:49 +00:00
}
return ret ;
}
2005-05-05 15:07:49 +00:00
void ast_func_write ( struct ast_channel * chan , const char * in , const char * value )
2005-03-29 06:16:49 +00:00
{
char * args = NULL , * function , * p ;
2005-05-05 05:39:33 +00:00
struct ast_custom_function * acfptr ;
2005-03-29 06:16:49 +00:00
function = ast_strdupa ( in ) ;
2005-07-19 15:54:17 +00:00
if ( ! function ) {
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
return ;
}
if ( ( args = strchr ( function , ' ( ' ) ) ) {
* args = ' \0 ' ;
args + + ;
if ( ( p = strrchr ( args , ' ) ' ) ) ) {
* p = ' \0 ' ;
2005-03-29 06:16:49 +00:00
} else {
2005-07-19 15:54:17 +00:00
ast_log ( LOG_WARNING , " Can't find trailing parenthesis? \n " ) ;
2005-03-29 06:16:49 +00:00
}
2005-07-19 15:54:17 +00:00
} else {
ast_log ( LOG_WARNING , " Function doesn't contain parentheses. Assuming null argument. \n " ) ;
}
2005-03-29 06:16:49 +00:00
2005-07-19 15:54:17 +00:00
if ( ( acfptr = ast_custom_function_find ( function ) ) ) {
/* run the custom function */
if ( acfptr - > write ) {
acfptr - > write ( chan , function , args , value ) ;
2005-03-29 06:16:49 +00:00
} else {
2005-07-19 15:54:17 +00:00
ast_log ( LOG_ERROR , " Function %s is read-only, it cannot be written to \n " , function ) ;
2005-03-29 06:16:49 +00:00
}
} else {
2005-07-19 15:54:17 +00:00
ast_log ( LOG_ERROR , " Function %s not registered \n " , function ) ;
2005-03-04 06:36:18 +00:00
}
}
2005-09-26 16:58:40 +00:00
static void pbx_substitute_variables_helper_full ( struct ast_channel * c , struct varshead * headp , const char * cp1 , char * cp2 , int count )
2003-02-21 06:00:08 +00:00
{
2003-04-18 15:34:25 +00:00
char * cp4 ;
const char * tmp , * whereweare ;
2005-09-29 04:39:14 +00:00
int length , offset , offset2 , isfunction ;
2005-09-26 19:31:03 +00:00
char * workspace = NULL ;
char * ltmp = NULL , * var = NULL ;
2005-03-29 06:16:49 +00:00
char * nextvar , * nextexp , * nextthing ;
2003-04-18 15:34:25 +00:00
char * vars , * vare ;
2005-03-29 06:16:49 +00:00
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 ) ;
2005-03-05 05:21:45 +00:00
nextvar = NULL ;
nextexp = NULL ;
nextthing = strchr ( whereweare , ' $ ' ) ;
if ( nextthing ) {
switch ( nextthing [ 1 ] ) {
case ' { ' :
nextvar = nextthing ;
2005-09-26 16:58:40 +00:00
pos = nextvar - whereweare ;
2005-03-05 05:21:45 +00:00
break ;
case ' [ ' :
nextexp = nextthing ;
2005-09-26 16:58:40 +00:00
pos = nextexp - whereweare ;
2005-03-05 05:21:45 +00:00
break ;
}
2003-04-18 16:57:48 +00:00
}
2005-09-26 16:58:40 +00:00
if ( pos ) {
/* 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 15:34:25 +00:00
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 ;
2005-03-29 06:16:49 +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 ;
2005-03-29 06:16:49 +00:00
2005-09-26 16:58:40 +00:00
/* Skip totally over variable string */
2005-07-19 15:54:17 +00:00
whereweare + = ( len + 3 ) ;
2005-03-29 06:16:49 +00:00
2005-09-26 16:58:40 +00:00
if ( ! var )
var = alloca ( VAR_BUF_SIZE ) ;
2003-04-18 15:34:25 +00:00
/* Store variable name (and truncate) */
2005-09-26 16:58:40 +00:00
ast_copy_string ( var , vars , len + 1 ) ;
2005-03-29 06:16:49 +00:00
2003-04-18 15:34:25 +00:00
/* Substitute if necessary */
if ( needsub ) {
2005-09-26 16:58:40 +00:00
if ( ! ltmp )
ltmp = alloca ( VAR_BUF_SIZE ) ;
memset ( ltmp , 0 , VAR_BUF_SIZE ) ;
pbx_substitute_variables_helper_full ( c , headp , var , ltmp , VAR_BUF_SIZE - 1 ) ;
2003-04-18 15:34:25 +00:00
vars = ltmp ;
} else {
vars = var ;
2003-02-23 06:00:11 +00:00
}
2005-03-29 06:16:49 +00:00
2005-09-26 16:58:40 +00:00
if ( ! workspace )
workspace = alloca ( VAR_BUF_SIZE ) ;
2004-07-14 07:44:19 +00:00
workspace [ 0 ] = ' \0 ' ;
2005-03-29 06:16:49 +00:00
2005-09-29 04:39:14 +00:00
parse_variable_name ( var , & offset , & offset2 , & isfunction ) ;
if ( isfunction ) {
2005-03-29 06:16:49 +00:00
/* Evaluate function */
2005-09-26 16:58:40 +00:00
cp4 = ast_func_read ( c , vars , workspace , VAR_BUF_SIZE ) ;
2005-03-29 06:16:49 +00:00
2005-05-01 18:37:37 +00:00
ast_log ( LOG_DEBUG , " Function result is '%s' \n " , cp4 ? cp4 : " (null) " ) ;
2005-03-29 06:16:49 +00:00
} else {
/* Retrieve variable value */
2005-09-26 16:58:40 +00:00
pbx_retrieve_variable ( c , vars , & cp4 , workspace , VAR_BUF_SIZE , headp ) ;
2005-03-29 06:16:49 +00:00
}
2003-04-18 15:34:25 +00:00
if ( cp4 ) {
2005-09-29 04:39:14 +00:00
cp4 = substring ( cp4 , offset , offset2 , workspace , VAR_BUF_SIZE ) ;
2003-04-18 15:34:25 +00:00
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 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 ;
2005-03-04 06:36:18 +00:00
2003-04-18 16:57:48 +00:00
/* 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 ;
2005-09-26 16:58:40 +00:00
/* Skip totally over expression */
whereweare + = ( len + 3 ) ;
2003-04-18 16:57:48 +00:00
2005-09-26 16:58:40 +00:00
if ( ! var )
var = alloca ( VAR_BUF_SIZE ) ;
2003-04-18 16:57:48 +00:00
/* Store variable name (and truncate) */
2005-09-26 16:58:40 +00:00
ast_copy_string ( var , vars , len + 1 ) ;
2003-04-18 16:57:48 +00:00
/* Substitute if necessary */
2005-03-29 06:16:49 +00:00
if ( needsub ) {
2005-09-26 16:58:40 +00:00
if ( ! ltmp )
ltmp = alloca ( VAR_BUF_SIZE ) ;
memset ( ltmp , 0 , VAR_BUF_SIZE ) ;
pbx_substitute_variables_helper_full ( c , headp , var , ltmp , VAR_BUF_SIZE - 1 ) ;
2003-04-18 16:57:48 +00:00
vars = ltmp ;
} else {
vars = var ;
}
2005-08-29 22:03:37 +00:00
length = ast_expr ( vars , cp2 , count ) ;
if ( length ) {
ast_log ( LOG_DEBUG , " Expression result is '%s' \n " , cp2 ) ;
2005-03-04 06:36:18 +00:00
count - = length ;
cp2 + = length ;
}
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 )
{
2005-09-26 19:51:58 +00:00
pbx_substitute_variables_helper_full ( c , ( c ) ? & c - > varshead : NULL , cp1 , cp2 , count ) ;
2004-10-24 02:53:24 +00:00
}
void pbx_substitute_variables_varshead ( struct varshead * headp , const char * cp1 , char * cp2 , int count )
{
2005-09-26 16:58:40 +00:00
pbx_substitute_variables_helper_full ( NULL , headp , cp1 , cp2 , count ) ;
2004-10-24 02:53:24 +00:00
}
2005-03-29 06:16:49 +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? */
2005-09-26 03:02:06 +00:00
if ( ! strchr ( e - > data , ' $ ' ) & & ! strstr ( e - > data , " ${ " ) & & ! strstr ( e - > data , " $[ " ) & & ! strstr ( e - > data , " $( " ) ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( passdata , e - > data , datalen ) ;
2003-04-18 15:34:25 +00:00
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 )
2005-06-05 16:32:16 +00:00
ast_copy_string ( c - > context , context , sizeof ( c - > context ) ) ;
2003-07-29 15:38:02 +00:00
if ( c - > exten ! = exten )
2005-06-05 16:32:16 +00:00
ast_copy_string ( c - > exten , exten , sizeof ( c - > exten ) ) ;
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
2005-02-21 06:31:01 +00:00
/*--- ast_hint_extension: Find hint for given extension in context */
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 ;
}
2005-03-17 21:05:10 +00:00
/*--- ast_extensions_state2: Check state of extension by using hints */
2003-03-30 22:55:42 +00:00
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 ;
2005-08-29 23:53:29 +00:00
int busy = 0 , inuse = 0 , ring = 0 ;
2003-03-30 22:55:42 +00:00
2005-03-17 21:05:10 +00:00
if ( ! e )
return - 1 ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( hint , ast_get_extension_app ( e ) , sizeof ( hint ) ) ;
2005-03-29 06:16:49 +00:00
2005-03-17 21:05:10 +00:00
cur = hint ; /* On or more devices separated with a & character */
2004-07-17 02:25:53 +00:00
do {
rest = strchr ( cur , ' & ' ) ;
if ( rest ) {
2005-08-29 23:53:29 +00:00
* rest = 0 ;
2004-07-17 02:25:53 +00:00
rest + + ;
}
2003-03-30 22:55:42 +00:00
2004-07-17 02:25:53 +00:00
res = ast_device_state ( cur ) ;
switch ( res ) {
2005-03-29 06:16:49 +00:00
case AST_DEVICE_NOT_INUSE :
2004-07-17 02:25:53 +00:00
allunavailable = 0 ;
allbusy = 0 ;
break ;
2005-03-29 06:16:49 +00:00
case AST_DEVICE_INUSE :
2005-08-29 23:53:29 +00:00
inuse = 1 ;
allunavailable = 0 ;
allfree = 0 ;
break ;
case AST_DEVICE_RINGING :
ring = 1 ;
allunavailable = 0 ;
allfree = 0 ;
break ;
2005-03-29 06:16:49 +00:00
case AST_DEVICE_BUSY :
2004-07-17 02:25:53 +00:00
allunavailable = 0 ;
allfree = 0 ;
busy = 1 ;
break ;
2005-03-29 06:16:49 +00:00
case AST_DEVICE_UNAVAILABLE :
case AST_DEVICE_INVALID :
2004-07-17 02:25:53 +00:00
allbusy = 0 ;
allfree = 0 ;
break ;
2005-03-29 06:16:49 +00:00
default :
2004-07-17 02:25:53 +00:00
allunavailable = 0 ;
allbusy = 0 ;
allfree = 0 ;
}
2005-03-29 06:16:49 +00:00
cur = rest ;
2004-07-17 02:25:53 +00:00
} while ( cur ) ;
2005-08-29 23:53:29 +00:00
if ( ! inuse & & ring )
return AST_EXTENSION_RINGING ;
if ( inuse & & ring )
return ( AST_EXTENSION_INUSE | AST_EXTENSION_RINGING ) ;
if ( inuse )
return AST_EXTENSION_INUSE ;
if ( allfree )
2003-04-06 19:10:24 +00:00
return AST_EXTENSION_NOT_INUSE ;
2005-03-17 21:05:10 +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
}
2005-08-29 23:53:29 +00:00
/*--- ast_extension_state2str: Return extension_state as string */
const char * ast_extension_state2str ( int extension_state )
{
int i ;
for ( i = 0 ; ( i < ( sizeof ( extension_states ) / sizeof ( extension_states [ 0 ] ) ) ) ; i + + ) {
if ( extension_states [ i ] . extension_state = = extension_state ) {
return extension_states [ i ] . text ;
}
}
return " Unknown " ;
}
2003-03-30 22:55:42 +00:00
2005-03-17 21:05:10 +00:00
/*--- ast_extension_state: Check extension state for an extension by using hint */
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
2005-03-17 21:05:10 +00:00
e = ast_hint_extension ( c , context , exten ) ; /* Do we have a hint for this extension ? */
2004-05-09 07:19:00 +00:00
if ( ! e )
2005-03-17 21:05:10 +00:00
return - 1 ; /* No hint, return -1 */
2003-03-30 22:55:42 +00:00
2005-03-17 21:05:10 +00:00
return ast_extension_state2 ( e ) ; /* Check all devices in the hint */
2003-03-30 22:55:42 +00:00
}
2005-07-08 21:14:34 +00:00
void ast_hint_state_changed ( const char * device )
2003-03-30 22:55:42 +00:00
{
2005-07-08 21:14:34 +00:00
struct ast_hint * hint ;
2004-07-14 07:44:19 +00:00
struct ast_state_cb * cblist ;
2005-07-08 21:14:34 +00:00
char buf [ AST_MAX_EXTENSION ] ;
char * parse ;
char * cur ;
2004-07-14 07:44:19 +00:00
int state ;
2003-04-06 18:19:51 +00:00
2004-07-14 07:44:19 +00:00
ast_mutex_lock ( & hintlock ) ;
2005-07-08 21:14:34 +00:00
for ( hint = hints ; hint ; hint = hint - > next ) {
ast_copy_string ( buf , ast_get_extension_app ( hint - > exten ) , sizeof ( buf ) ) ;
parse = buf ;
for ( cur = strsep ( & parse , " & " ) ; cur ; cur = strsep ( & parse , " & " ) ) {
if ( strcmp ( cur , device ) )
continue ;
2004-07-14 07:44:19 +00:00
2005-07-08 21:14:34 +00:00
/* Get device state for this hint */
state = ast_extension_state2 ( hint - > exten ) ;
2004-07-14 07:44:19 +00:00
2005-07-08 21:14:34 +00:00
if ( ( state = = - 1 ) | | ( state = = hint - > laststate ) )
continue ;
2004-07-14 07:44:19 +00:00
2005-07-08 21:14:34 +00:00
/* Device state changed since last check - notify the watchers */
2004-07-14 07:44:19 +00:00
2005-07-08 21:14:34 +00:00
/* For general callbacks */
for ( cblist = statecbs ; cblist ; cblist = cblist - > next )
cblist - > callback ( hint - > exten - > parent - > name , hint - > exten - > exten , state , cblist - > data ) ;
2003-03-30 22:55:42 +00:00
2005-07-08 21:14:34 +00:00
/* For extension callbacks */
for ( cblist = hint - > callbacks ; cblist ; cblist = cblist - > next )
cblist - > callback ( hint - > exten - > parent - > name , hint - > exten - > exten , state , cblist - > data ) ;
hint - > laststate = state ;
break ;
}
2004-11-13 22:44:33 +00:00
}
ast_mutex_unlock ( & hintlock ) ;
}
2005-07-08 21:14:34 +00:00
2005-03-17 21:05:10 +00:00
/*--- ast_extension_state_add: Add watcher for extension states */
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
2005-03-17 21:05:10 +00:00
/* If there's no context and extension: add callback to statecbs list */
2004-07-17 02:25:53 +00:00
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 ) ;
2005-05-08 16:54:53 +00:00
return 0 ;
2004-07-17 02:25:53 +00:00
}
cblist = cblist - > next ;
}
2005-05-08 16:54:53 +00:00
/* Now insert the callback */
2004-07-17 02:25:53 +00:00
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
2005-03-29 06:16:49 +00:00
cblist - > next = statecbs ;
2004-07-17 02:25:53 +00:00
statecbs = cblist ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & hintlock ) ;
2004-07-17 02:25:53 +00:00
return 0 ;
2005-03-29 06:16:49 +00:00
}
2004-07-17 02:25:53 +00:00
if ( ! context | | ! exten )
return - 1 ;
2005-03-17 21:05:10 +00:00
/* This callback type is for only one hint, so get the hint */
2004-07-17 02:25:53 +00:00
e = ast_hint_extension ( NULL , context , exten ) ;
if ( ! e ) {
return - 1 ;
2003-04-06 18:19:51 +00:00
}
2005-03-29 06:16:49 +00:00
2005-03-17 21:05:10 +00:00
/* Find the hint in the list of hints */
2004-07-17 02:25:53 +00:00
ast_mutex_lock ( & hintlock ) ;
list = hints ;
2005-03-29 06:16:49 +00:00
2004-07-17 02:25:53 +00:00
while ( list ) {
if ( list - > exten = = e )
break ;
list = list - > next ;
}
if ( ! list ) {
2005-03-17 21:05:10 +00:00
/* We have no hint, sorry */
2004-07-17 02:25:53 +00:00
ast_mutex_unlock ( & hintlock ) ;
return - 1 ;
}
2005-03-17 21:05:10 +00:00
/* Now insert the callback in the callback list */
2003-04-06 18:19:51 +00:00
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 ) ) ;
2005-03-17 21:05:10 +00:00
cblist - > id = stateid + + ; /* Unique ID for this callback */
cblist - > callback = callback ; /* Pointer to callback routine */
cblist - > data = data ; /* Data for the callback */
2003-04-06 18:19:51 +00:00
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
}
2005-03-17 21:05:10 +00:00
/*--- ast_extension_state_del: Remove a watcher from the callback list */
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 ;
2005-03-29 06:16:49 +00:00
2004-07-17 02:25:53 +00:00
if ( ! id & & ! callback )
return - 1 ;
2005-03-29 06:16:49 +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 ;
}
2005-03-29 06:16:49 +00:00
ast_mutex_lock ( & hintlock ) ;
2004-07-17 02:25:53 +00:00
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 */
2005-03-17 21:05:10 +00:00
/* Find the callback based on ID */
2004-07-17 02:25:53 +00:00
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 ;
}
2005-03-29 06:16:49 +00:00
cbprev = cblist ;
2004-07-17 02:25:53 +00:00
cblist = cblist - > next ;
}
list = list - > next ;
2003-04-06 18:19:51 +00:00
}
2005-03-29 06:16:49 +00:00
2004-07-17 02:25:53 +00:00
ast_mutex_unlock ( & hintlock ) ;
return - 1 ;
2003-04-06 18:19:51 +00:00
}
2005-02-21 06:31:01 +00:00
/*--- ast_add_hint: Add hint to hint list, check initial extension state */
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 ;
2005-03-29 06:16:49 +00:00
2004-07-17 02:25:53 +00:00
ast_mutex_lock ( & hintlock ) ;
list = hints ;
2005-03-29 06:16:49 +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 ) ;
2005-02-21 06:31:01 +00:00
if ( option_debug > 1 )
ast_log ( LOG_DEBUG , " HINTS: Not re-adding existing hint %s: %s \n " , ast_get_extension_name ( e ) , ast_get_extension_app ( e ) ) ;
2004-07-17 02:25:53 +00:00
return - 1 ;
}
list = list - > next ;
2005-03-29 06:16:49 +00:00
}
2004-07-17 02:25:53 +00:00
2005-02-21 06:31:01 +00:00
if ( option_debug > 1 )
ast_log ( LOG_DEBUG , " HINTS: Adding hint %s: %s \n " , ast_get_extension_name ( e ) , ast_get_extension_app ( e ) ) ;
2004-07-17 02:25:53 +00:00
list = malloc ( sizeof ( struct ast_hint ) ) ;
if ( ! list ) {
ast_mutex_unlock ( & hintlock ) ;
2005-02-21 06:31:01 +00:00
if ( option_debug > 1 )
ast_log ( LOG_DEBUG , " HINTS: Out of memory... \n " ) ;
2004-07-17 02:25:53 +00:00
return - 1 ;
2003-04-06 18:19:51 +00:00
}
2005-02-21 06:31:01 +00:00
/* Initialize and insert new item at the top */
2004-07-17 02:25:53 +00:00
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
}
2005-02-21 06:31:01 +00:00
/*--- ast_change_hint: Change hint for an extension */
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 ;
2005-03-29 06:16:49 +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
}
2005-02-21 06:31:01 +00:00
/*--- ast_remove_hint: Remove hint from extension */
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 ;
2005-08-27 23:55:14 +00:00
cbprev - > callback ( list - > exten - > parent - > name , list - > exten - > exten , AST_EXTENSION_DEACTIVATED , cbprev - > data ) ;
2004-07-17 02:25:53 +00:00
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 ;
}
2005-02-01 01:53:25 +00:00
}
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
}
2005-02-21 06:31:01 +00:00
/*--- ast_get_hint: Get hint for channel */
2005-02-01 01:53:25 +00:00
int ast_get_hint ( char * hint , int hintsize , char * name , int namesize , struct ast_channel * c , const char * context , const char * exten )
2003-03-30 22:55:42 +00:00
{
struct ast_exten * e ;
2005-02-01 01:53:25 +00:00
void * tmp ;
2005-06-05 16:32:16 +00:00
2003-03-30 22:55:42 +00:00
e = ast_hint_extension ( c , context , exten ) ;
2005-02-01 01:53:25 +00:00
if ( e ) {
if ( hint )
2005-06-05 16:32:16 +00:00
ast_copy_string ( hint , ast_get_extension_app ( e ) , hintsize ) ;
2005-02-01 01:53:25 +00:00
if ( name ) {
tmp = ast_get_extension_app_data ( e ) ;
if ( tmp )
2005-06-05 16:32:16 +00:00
ast_copy_string ( name , ( char * ) tmp , namesize ) ;
2005-02-01 01:53:25 +00:00
}
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 ) ;
}
2005-05-18 01:49:13 +00:00
static int __ast_pbx_run ( struct ast_channel * c )
1999-12-04 20:45:45 +00:00
{
int firstpass = 1 ;
2005-06-05 15:04:43 +00:00
int digit ;
1999-12-04 20:45:45 +00:00
char exten [ 256 ] ;
int pos ;
int waittime ;
2000-01-24 07:14:18 +00:00
int res = 0 ;
2005-04-29 15:04:26 +00:00
int autoloopflag ;
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 ;
2005-04-29 15:04:26 +00:00
autoloopflag = ast_test_flag ( c , AST_FLAG_IN_AUTOLOOP ) ;
ast_set_flag ( c , AST_FLAG_IN_AUTOLOOP ) ;
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 ) ) {
2005-04-29 15:04:26 +00:00
/* If not successful 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 ) ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( c - > exten , " s " , sizeof ( c - > exten ) ) ;
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 ) ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( c - > context , " default " , sizeof ( c - > context ) ) ;
2003-02-02 19:04:14 +00:00
}
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 ) ) ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( c - > exten , " T " , sizeof ( c - > exten ) ) ;
2003-03-07 06:00:13 +00:00
/* 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 ) ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( c - > exten , " i " , sizeof ( c - > exten ) ) ;
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 */
2005-06-05 16:32:16 +00:00
ast_copy_string ( c - > exten , exten , sizeof ( c - > exten ) ) ;
2004-10-16 19:46:02 +00:00
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 ) ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( c - > exten , " i " , sizeof ( c - > exten ) ) ;
2004-10-16 19:46:02 +00:00
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 ) ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( c - > exten , " t " , sizeof ( c - > exten ) ) ;
2004-10-16 19:46:02 +00:00
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 {
2005-03-14 05:51:20 +00:00
char * status ;
2005-04-29 15:04:26 +00:00
2005-03-14 05:51:20 +00:00
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 + + ;
}
}
2005-04-29 15:04:26 +00:00
ast_set2_flag ( c , autoloopflag , AST_FLAG_IN_AUTOLOOP ) ;
2002-06-21 01:40:13 +00:00
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 ;
}
2005-09-13 21:59:45 +00:00
/* Returns 0 on success, non-zero if call limit was reached */
static int increase_call_count ( const struct ast_channel * c )
{
int failed = 0 ;
ast_mutex_lock ( & maxcalllock ) ;
if ( option_maxcalls ) {
if ( countcalls > = option_maxcalls ) {
ast_log ( LOG_NOTICE , " Maximum call limit of %d calls exceeded by '%s'! \n " , option_maxcalls , c - > name ) ;
failed = - 1 ;
}
}
if ( ! failed )
countcalls + + ;
ast_mutex_unlock ( & maxcalllock ) ;
return failed ;
}
static void decrease_call_count ( void )
{
ast_mutex_lock ( & maxcalllock ) ;
if ( countcalls > 0 )
countcalls - - ;
ast_mutex_unlock ( & maxcalllock ) ;
}
2001-03-30 18:47:35 +00:00
static void * pbx_thread ( void * data )
{
/* Oh joyeous kernel, we're a new thread, with nothing to do but
2005-09-02 18:07:26 +00:00
answer this channel and get it going .
*/
2005-09-13 21:59:45 +00:00
/* NOTE:
The launcher of this function _MUST_ increment ' countcalls '
before invoking the function ; it will be decremented when the
PBX has finished running on the channel
*/
2001-03-30 18:47:35 +00:00
struct ast_channel * c = data ;
2005-09-13 21:59:45 +00:00
__ast_pbx_run ( c ) ;
decrease_call_count ( ) ;
1999-12-04 20:45:45 +00:00
pthread_exit ( NULL ) ;
2005-09-13 21:59:45 +00:00
2001-03-30 18:47:35 +00:00
return NULL ;
1999-12-04 20:45:45 +00:00
}
2005-09-13 21:59:45 +00:00
enum ast_pbx_result ast_pbx_start ( struct ast_channel * c )
1999-12-04 20:45:45 +00:00
{
pthread_t t ;
2001-04-27 15:07:56 +00:00
pthread_attr_t attr ;
2005-09-13 21:59:45 +00:00
1999-12-04 20:45:45 +00:00
if ( ! c ) {
ast_log ( LOG_WARNING , " Asked to start thread on NULL channel? \n " ) ;
2005-09-13 21:59:45 +00:00
return AST_PBX_FAILED ;
1999-12-04 20:45:45 +00:00
}
2002-09-11 17:09:48 +00:00
2005-09-13 21:59:45 +00:00
if ( increase_call_count ( c ) )
return AST_PBX_CALL_LIMIT ;
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 " ) ;
2005-09-13 21:59:45 +00:00
return AST_PBX_FAILED ;
1999-12-04 20:45:45 +00:00
}
2005-09-13 21:59:45 +00:00
return AST_PBX_SUCCESS ;
1999-12-04 20:45:45 +00:00
}
2001-09-28 21:20:52 +00:00
2005-09-13 21:59:45 +00:00
enum ast_pbx_result ast_pbx_run ( struct ast_channel * c )
2005-05-18 01:49:13 +00:00
{
2005-09-13 21:59:45 +00:00
enum ast_pbx_result res = AST_PBX_SUCCESS ;
if ( increase_call_count ( c ) )
return AST_PBX_CALL_LIMIT ;
res = __ast_pbx_run ( c ) ;
decrease_call_count ( ) ;
2005-05-18 01:49:13 +00:00
return res ;
}
int ast_active_calls ( void )
{
return countcalls ;
}
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 " ;
2005-03-04 06:36:18 +00:00
static char show_functions_help [ ] =
" Usage: show functions \n "
2005-05-05 05:39:33 +00:00
" List builtin functions accessable as $(function args) \n " ;
static char show_function_help [ ] =
" Usage: show function <function> \n "
" Describe a particular dialplan function. \n " ;
2005-03-04 06:36:18 +00:00
2001-09-28 21:20:52 +00:00
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 " ;
2005-02-21 06:31:01 +00:00
static char show_hints_help [ ] =
" Usage: show hints \n "
" Show registered hints \n " ;
2001-09-28 21:20:52 +00:00
/*
* 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 ) ;
2005-05-05 05:39:33 +00:00
term_color ( syntitle , " [Synopsis] \n " , COLOR_MAGENTA , 0 , 40 ) ;
term_color ( destitle , " [Description] \n " , COLOR_MAGENTA , 0 , 40 ) ;
2003-11-21 18:38:42 +00:00
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 "
2005-05-05 05:39:33 +00:00
" [Synopsis] \n %s \n \n "
" [Description] \n %s \n " ,
2003-11-21 18:38:42 +00:00
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 ;
}
2005-02-21 06:31:01 +00:00
/*--- handle_show_hints: CLI support for listing registred dial plan hints */
static int handle_show_hints ( int fd , int argc , char * argv [ ] )
{
struct ast_hint * hint ;
int num = 0 ;
2005-08-27 23:55:14 +00:00
int watchers ;
struct ast_state_cb * watcher ;
2005-02-21 06:31:01 +00:00
if ( ! hints ) {
ast_cli ( fd , " There are no registered dialplan hints \n " ) ;
return RESULT_SUCCESS ;
}
/* ... we have hints ... */
ast_cli ( fd , " \n -= Registered Asterisk Dial Plan Hints =- \n " ) ;
if ( ast_mutex_lock ( & hintlock ) ) {
ast_log ( LOG_ERROR , " Unable to lock hints \n " ) ;
return - 1 ;
}
hint = hints ;
while ( hint ) {
2005-08-27 23:55:14 +00:00
watchers = 0 ;
for ( watcher = hint - > callbacks ; watcher ; watcher = watcher - > next )
watchers + + ;
ast_cli ( fd , " %-20.20s: %-20.20s State %2d Watchers %2d \n " ,
ast_get_extension_name ( hint - > exten ) , ast_get_extension_app ( hint - > exten ) ,
hint - > laststate , watchers ) ;
2005-02-21 06:31:01 +00:00
num + + ;
hint = hint - > next ;
}
ast_cli ( fd , " ---------------- \n " ) ;
ast_cli ( fd , " - %d hints registred \n " , num ) ;
ast_mutex_unlock ( & hintlock ) ;
return RESULT_SUCCESS ;
}
/*--- handle_show_switches: CLI support for listing registred dial plan switches */
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 ) {
2005-07-15 22:06:15 +00:00
if ( strcasestr ( a - > name , argv [ 3 ] ) ) {
2004-08-27 04:21:09 +00:00
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 ;
2005-07-19 15:54:17 +00:00
for ( i = 3 ; i < argc ; i + + ) {
2005-07-15 22:06:15 +00:00
if ( ! strcasestr ( a - > description , argv [ i ] ) ) {
2004-08-27 04:21:09 +00:00
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
}
2005-03-29 06:16:49 +00:00
if ( ( ! like ) & & ( ! describing ) ) {
2004-12-01 01:28:07 +00:00
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 ;
}
2005-01-09 20:28:47 +00:00
struct dialplan_counters {
int total_context ;
int total_exten ;
int total_prio ;
int context_existence ;
int extension_existence ;
} ;
2005-09-24 14:19:00 +00:00
static int show_dialplan_helper ( int fd , char * context , char * exten , struct dialplan_counters * dpc , struct ast_include * rinclude , int includecount , char * includes [ ] )
2001-09-28 21:20:52 +00:00
{
struct ast_context * c ;
2005-01-09 20:28:47 +00:00
int res = 0 , old_total_exten = dpc - > total_exten ;
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 " ) ;
2005-01-09 20:28:47 +00:00
return - 1 ;
2001-09-28 21:20:52 +00:00
}
/* walk all contexts ... */
2005-01-09 20:28:47 +00:00
for ( c = ast_walk_contexts ( NULL ) ; c ; c = ast_walk_contexts ( c ) ) {
2001-09-28 21:20:52 +00:00
/* show this context? */
if ( ! context | |
! strcmp ( ast_get_context_name ( c ) , context ) ) {
2005-01-09 20:28:47 +00:00
dpc - > context_existence = 1 ;
2001-09-28 21:20:52 +00:00
/* 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 ) {
2005-01-09 20:28:47 +00:00
dpc - > 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 ... */
2005-01-09 20:28:47 +00:00
for ( e = ast_walk_context_extensions ( c , NULL ) ; e ; e = ast_walk_context_extensions ( c , e ) ) {
2001-09-28 21:20:52 +00:00
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 & &
2005-01-09 20:28:47 +00:00
! ast_extension_match ( ast_get_extension_name ( e ) , exten ) )
2001-09-28 21:20:52 +00:00
{
/* we are looking for extension and it's not our
* extension , so skip to next extension */
continue ;
}
2005-01-09 20:28:47 +00:00
dpc - > extension_existence = 1 ;
2001-09-28 21:20:52 +00:00
/* may we print context info? */
if ( ! context_info_printed ) {
2005-01-09 20:28:47 +00:00
dpc - > total_context + + ;
if ( rinclude ) {
/* TODO Print more info about rinclude */
ast_cli ( fd , " [ Included context '%s' created by '%s' ] \n " ,
ast_get_context_name ( c ) ,
ast_get_context_registrar ( c ) ) ;
} else {
ast_cli ( fd , " [ Context '%s' created by '%s' ] \n " ,
ast_get_context_name ( c ) ,
ast_get_context_registrar ( c ) ) ;
}
2001-09-28 21:20:52 +00:00
context_info_printed = 1 ;
}
2005-01-09 20:28:47 +00:00
dpc - > 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 ) ) ;
2005-01-09 20:28:47 +00:00
dpc - > total_exten + + ;
2001-09-28 21:20:52 +00:00
/* walk next extension peers */
2005-01-09 20:28:47 +00:00
for ( p = ast_walk_extension_priorities ( e , e ) ; p ; p = ast_walk_extension_priorities ( e , p ) ) {
dpc - > 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 ,
2005-01-09 20:28:47 +00:00
ast_get_extension_registrar ( p ) ) ;
2001-04-27 15:07:56 +00:00
}
}
2001-09-28 21:20:52 +00:00
2005-01-09 20:28:47 +00:00
/* walk included and write info ... */
for ( i = ast_walk_context_includes ( c , NULL ) ; i ; i = ast_walk_context_includes ( c , i ) ) {
bzero ( buf , sizeof ( buf ) ) ;
snprintf ( buf , sizeof ( buf ) , " '%s' " ,
ast_get_include_name ( i ) ) ;
if ( exten ) {
/* Check all includes for the requested extension */
2005-09-24 14:19:00 +00:00
if ( includecount > = AST_PBX_MAX_STACK ) {
ast_log ( LOG_NOTICE , " Maximum include depth exceeded! \n " ) ;
} else {
int dupe = 0 ;
int x ;
for ( x = 0 ; x < includecount ; x + + ) {
if ( ! strcasecmp ( includes [ x ] , ast_get_include_name ( i ) ) ) {
dupe + + ;
break ;
}
}
if ( ! dupe ) {
includes [ includecount ] = ( char * ) ast_get_include_name ( i ) ;
show_dialplan_helper ( fd , ( char * ) ast_get_include_name ( i ) , exten , dpc , i , includecount + 1 , includes ) ;
} else {
ast_log ( LOG_WARNING , " Avoiding circular include of %s within %s \n " , ast_get_include_name ( i ) , context ) ;
}
}
2005-01-09 20:28:47 +00:00
} else {
2001-09-28 21:20:52 +00:00
ast_cli ( fd , " Include => %-45s [%s] \n " ,
buf , ast_get_include_registrar ( i ) ) ;
}
2005-01-09 20:28:47 +00:00
}
2001-09-28 21:20:52 +00:00
2005-01-09 20:28:47 +00:00
/* walk ignore patterns and write info ... */
for ( ip = ast_walk_context_ignorepats ( c , NULL ) ; ip ; ip = ast_walk_context_ignorepats ( c , ip ) ) {
const char * ipname = ast_get_ignorepat_name ( ip ) ;
char ignorepat [ AST_MAX_EXTENSION ] ;
snprintf ( buf , sizeof ( buf ) , " '%s' " , ipname ) ;
snprintf ( ignorepat , sizeof ( ignorepat ) , " _%s. " , ipname ) ;
if ( ( ! exten ) | | ast_extension_match ( ignorepat , exten ) ) {
2001-09-28 21:20:52 +00:00
ast_cli ( fd , " Ignore pattern => %-45s [%s] \n " ,
2005-01-09 20:28:47 +00:00
buf , ast_get_ignorepat_registrar ( ip ) ) ;
2001-09-28 21:20:52 +00:00
}
2005-01-09 20:28:47 +00:00
}
if ( ! rinclude ) {
for ( sw = ast_walk_context_switches ( c , NULL ) ; sw ; sw = ast_walk_context_switches ( c , sw ) ) {
2001-09-28 21:20:52 +00:00
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 ) ) ;
}
}
ast_unlock_context ( c ) ;
/* if we print something in context, make an empty line */
2005-01-09 20:28:47 +00:00
if ( context_info_printed ) ast_cli ( fd , " \r \n " ) ;
2001-04-27 15:07:56 +00:00
}
}
}
2001-09-28 21:20:52 +00:00
ast_unlock_contexts ( ) ;
2005-01-09 20:28:47 +00:00
if ( dpc - > total_exten = = old_total_exten ) {
/* Nothing new under the sun */
return - 1 ;
} else {
return res ;
}
}
static int handle_show_dialplan ( int fd , int argc , char * argv [ ] )
{
char * exten = NULL , * context = NULL ;
/* Variables used for different counters */
struct dialplan_counters counters ;
2005-09-24 14:19:00 +00:00
char * incstack [ AST_PBX_MAX_STACK ] ;
2005-01-09 20:28:47 +00:00
memset ( & counters , 0 , sizeof ( counters ) ) ;
2005-04-01 19:56:35 +00:00
if ( argc ! = 2 & & argc ! = 3 )
return RESULT_SHOWUSAGE ;
2005-01-09 20:28:47 +00:00
/* we obtain [exten@]context? if yes, split them ... */
if ( argc = = 3 ) {
char * splitter = ast_strdupa ( argv [ 2 ] ) ;
/* is there a '@' character? */
if ( splitter & & strchr ( argv [ 2 ] , ' @ ' ) ) {
/* yes, split into exten & context ... */
exten = strsep ( & splitter , " @ " ) ;
context = splitter ;
/* check for length and change to NULL if ast_strlen_zero() */
2005-04-01 19:56:35 +00:00
if ( ast_strlen_zero ( exten ) )
exten = NULL ;
if ( ast_strlen_zero ( context ) )
context = NULL ;
2005-09-24 14:19:00 +00:00
show_dialplan_helper ( fd , context , exten , & counters , NULL , 0 , incstack ) ;
2005-01-09 20:28:47 +00:00
} else {
/* no '@' char, only context given */
context = argv [ 2 ] ;
2005-04-01 19:56:35 +00:00
if ( ast_strlen_zero ( context ) )
context = NULL ;
2005-09-24 14:19:00 +00:00
show_dialplan_helper ( fd , context , exten , & counters , NULL , 0 , incstack ) ;
2005-01-09 20:28:47 +00:00
}
} else {
2005-04-01 19:56:35 +00:00
/* Show complete dial plan */
2005-09-24 14:19:00 +00:00
show_dialplan_helper ( fd , NULL , NULL , & counters , NULL , 0 , incstack ) ;
2005-01-09 20:28:47 +00:00
}
2001-09-28 21:20:52 +00:00
/* check for input failure and throw some error messages */
2005-01-09 20:28:47 +00:00
if ( context & & ! counters . context_existence ) {
ast_cli ( fd , " There is no existence of '%s' context \n " , context ) ;
2001-09-28 21:20:52 +00:00
return RESULT_FAILURE ;
}
2005-01-09 20:28:47 +00:00
if ( exten & & ! counters . extension_existence ) {
2001-09-28 21:20:52 +00:00
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 ;
}
2005-01-09 20:28:47 +00:00
2005-09-16 18:11:00 +00:00
ast_cli ( fd , " -= %d %s (%d %s) in %d %s. =- \n " ,
counters . total_exten , counters . total_exten = = 1 ? " extension " : " extensions " ,
counters . total_prio , counters . total_prio = = 1 ? " priority " : " priorities " ,
counters . total_context , counters . total_context = = 1 ? " context " : " contexts " ) ;
2005-01-09 20:28:47 +00:00
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 . . .
*/
2005-06-03 03:09:20 +00:00
static struct ast_cli_entry pbx_cli [ ] = {
{ { " show " , " applications " , NULL } , handle_show_applications ,
" Shows registered dialplan applications " , show_applications_help , complete_show_applications } ,
{ { " show " , " functions " , NULL } , handle_show_functions ,
" Shows registered dialplan functions " , show_functions_help } ,
{ { " show " , " function " , NULL } , handle_show_function ,
" Describe a specific dialplan function " , show_function_help , complete_show_function } ,
{ { " show " , " application " , NULL } , handle_show_application ,
" Describe a specific dialplan application " , show_application_help , complete_show_application } ,
{ { " show " , " dialplan " , NULL } , handle_show_dialplan ,
" Show dialplan " , show_dialplan_help , complete_show_dialplan_context } ,
{ { " show " , " switches " , NULL } , handle_show_switches ,
" Show alternative switches " , show_switches_help } ,
{ { " show " , " hints " , NULL } , handle_show_hints ,
" Show dialplan hints " , show_hints_help } ,
2005-05-05 05:39:33 +00:00
} ;
2005-09-24 14:19:00 +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
2005-08-27 23:55:14 +00:00
struct store_hint {
char * context ;
char * exten ;
struct ast_state_cb * callbacks ;
int laststate ;
AST_LIST_ENTRY ( store_hint ) list ;
char data [ 1 ] ;
} ;
AST_LIST_HEAD ( store_hints , store_hint ) ;
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 ;
2005-08-27 23:55:14 +00:00
struct store_hints store ;
struct store_hint * this ;
struct ast_hint * hint ;
struct ast_exten * exten ;
int length ;
struct ast_state_cb * thiscb , * prevcb ;
/* preserve all watchers for hints associated with this registrar */
AST_LIST_HEAD_INIT ( & store ) ;
ast_mutex_lock ( & hintlock ) ;
for ( hint = hints ; hint ; hint = hint - > next ) {
if ( hint - > callbacks & & ! strcmp ( registrar , hint - > exten - > parent - > registrar ) ) {
length = strlen ( hint - > exten - > exten ) + strlen ( hint - > exten - > parent - > name ) + 2 + sizeof ( * this ) ;
this = calloc ( 1 , length ) ;
if ( ! this ) {
ast_log ( LOG_WARNING , " Could not allocate memory to preserve hint \n " ) ;
continue ;
}
this - > callbacks = hint - > callbacks ;
hint - > callbacks = NULL ;
this - > laststate = hint - > laststate ;
this - > context = this - > data ;
strcpy ( this - > data , hint - > exten - > parent - > name ) ;
this - > exten = this - > data + strlen ( this - > context ) + 1 ;
strcpy ( this - > exten , hint - > exten - > exten ) ;
AST_LIST_INSERT_HEAD ( & store , this , list ) ;
}
}
ast_mutex_unlock ( & hintlock ) ;
2003-07-14 15:35:21 +00:00
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 ) ;
2005-08-27 23:55:14 +00:00
/* restore the watchers for hints that can be found; notify those that
cannot be restored
*/
while ( ( this = AST_LIST_REMOVE_HEAD ( & store , list ) ) ) {
exten = ast_hint_extension ( NULL , this - > context , this - > exten ) ;
/* Find the hint in the list of hints */
ast_mutex_lock ( & hintlock ) ;
for ( hint = hints ; hint ; hint = hint - > next ) {
if ( hint - > exten = = exten )
break ;
}
if ( ! exten | | ! hint ) {
/* this hint has been removed, notify the watchers */
prevcb = NULL ;
thiscb = this - > callbacks ;
while ( thiscb ) {
prevcb = thiscb ;
thiscb = thiscb - > next ;
prevcb - > callback ( this - > context , this - > exten , AST_EXTENSION_REMOVED , prevcb - > data ) ;
free ( prevcb ) ;
}
} else {
thiscb = this - > callbacks ;
while ( thiscb - > next )
thiscb = thiscb - > next ;
thiscb - > next = hint - > callbacks ;
hint - > callbacks = this - > callbacks ;
hint - > laststate = this - > laststate ;
}
ast_mutex_unlock ( & hintlock ) ;
free ( this ) ;
}
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 , " * " ) ) {
2005-04-01 19:56:35 +00:00
for ( x = 0 ; x < 24 ; x + + )
2002-06-21 01:40:13 +00:00
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 + + ;
2005-04-01 19:56:35 +00:00
while ( * e & & ! isdigit ( * e ) )
e + + ;
2002-06-21 01:40:13 +00:00
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
2005-07-19 15:54:17 +00:00
for ( cth = 0 ; cth < 24 ; cth + + ) {
2004-01-11 09:19:16 +00:00
/* Initialize masks to blank */
i - > minmask [ cth ] = 0 ;
2005-07-19 15:54:17 +00:00
for ( ctm = 0 ; ctm < 30 ; ctm + + ) {
2004-01-11 09:19:16 +00:00
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 " ,
} ;
2005-04-01 19:56:35 +00:00
/*--- get_dow: Get day of week */
2002-06-21 01:40:13 +00:00
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 ;
2005-07-19 15:54:17 +00:00
for ( x = s ; x ! = e ; x = ( x + 1 ) % 31 ) {
2002-06-21 01:40:13 +00:00
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
{
2005-03-29 06:16:49 +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 */
2005-06-05 16:32:16 +00:00
ast_copy_string ( info_save , info_in , sizeof ( info_save ) ) ;
2004-11-11 21:23:45 +00:00
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 */
2005-04-01 19:56:35 +00:00
while ( * c & & ( * c ! = ' | ' ) )
c + + ;
2002-06-21 01:40:13 +00:00
/* 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
*/
2005-01-13 05:14:56 +00:00
int ast_context_add_switch ( const char * context , const char * sw , const char * data , int eval , 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 ) ) {
2005-01-13 05:14:56 +00:00
int ret = ast_context_add_switch2 ( c , sw , data , eval , registrar ) ;
2001-09-28 21:20:52 +00:00
/* ... 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 ,
2005-01-13 05:14:56 +00:00
const char * data , int eval , 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 + + ;
2005-01-13 05:14:56 +00:00
if ( eval ) {
/* Create buffer for evaluation of variables */
length + = SWITCH_DATA_LENGTH ;
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 ;
2005-01-13 05:14:56 +00:00
if ( data ) {
2004-10-03 04:19:59 +00:00
strcpy ( new_sw - > data , data ) ;
2005-01-13 05:14:56 +00:00
p + = strlen ( data ) + 1 ;
} else {
2004-10-03 04:19:59 +00:00
strcpy ( new_sw - > data , " " ) ;
2005-01-13 05:14:56 +00:00
p + + ;
}
if ( eval )
new_sw - > tmpdata = p ;
2001-09-28 21:20:52 +00:00
new_sw - > next = NULL ;
2005-01-13 05:14:56 +00:00
new_sw - > eval = eval ;
2001-09-28 21:20:52 +00:00
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 ;
}
2005-04-29 15:04:26 +00:00
int ast_explicit_goto ( struct ast_channel * chan , const char * context , const char * exten , int priority )
{
if ( ! chan )
return - 1 ;
if ( context & & ! ast_strlen_zero ( context ) )
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > context , context , sizeof ( chan - > context ) ) ;
2005-04-29 15:04:26 +00:00
if ( exten & & ! ast_strlen_zero ( exten ) )
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > exten , exten , sizeof ( chan - > exten ) ) ;
2005-04-29 15:04:26 +00:00
if ( priority > - 1 ) {
chan - > priority = priority ;
/* see flag description in channel.h for explanation */
if ( ast_test_flag ( chan , AST_FLAG_IN_AUTOLOOP ) )
chan - > priority - - ;
2004-11-23 20:25:02 +00:00
}
2005-04-29 15:04:26 +00:00
return 0 ;
2004-11-23 20:25:02 +00:00
}
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 ;
2005-04-29 15:04:26 +00:00
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 */
2005-04-29 15:04:26 +00:00
ast_explicit_goto ( chan , context , exten , priority ) ;
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 ,
2005-04-29 15:04:26 +00:00
( context & & ! ast_strlen_zero ( context ) ) ? context : chan - > context ,
( exten & & ! ast_strlen_zero ( exten ) ) ? exten : chan - > exten ,
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 ;
2005-06-06 02:29:18 +00:00
chan = ast_get_channel_by_name_locked ( channame ) ;
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
}
2005-06-03 02:21:07 +00:00
static void null_datad ( void * foo )
{
}
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 */
2005-06-03 02:21:07 +00:00
if ( datad = = NULL )
datad = null_datad ;
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 ) ;
2005-02-21 06:31:01 +00:00
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 )
2005-02-21 06:31:01 +00:00
ast_add_hint ( tmp ) ;
2003-04-06 18:19:51 +00:00
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 ;
2005-07-10 23:49:57 +00:00
char context [ AST_MAX_CONTEXT ] ;
2002-09-11 17:09:48 +00:00
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 )
2005-08-15 01:56:40 +00:00
ast_verbose ( VERBOSE_PREFIX_3 " Launching %s(%s) on %s \n " , as - > app , as - > appdata , chan - > name ) ;
2003-02-02 19:04:14 +00:00
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 ) )
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > context , as - > context , sizeof ( chan - > context ) ) ;
2004-05-04 06:34:34 +00:00
if ( ! ast_strlen_zero ( as - > exten ) )
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > exten , as - > exten , sizeof ( chan - > exten ) ) ;
2003-02-02 19:04:14 +00:00
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 */
2005-06-03 01:42:31 +00:00
ast_cdr_detach ( chan - > cdr ) ; /* post and free the record */
2004-10-15 17:51:37 +00:00
ast_channel_free ( chan ) ; /* free the channel */
return 0 ; /* success */
}
2005-07-15 23:24:51 +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 , struct ast_variable * vars , struct ast_channel * * channel )
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-09-22 15:27:09 +00:00
struct outgoing_helper oh ;
2003-10-23 03:55:58 +00:00
pthread_attr_t attr ;
2005-07-15 23:24:51 +00:00
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 ) ;
2005-02-02 02:54:15 +00:00
if ( channel ) {
* channel = chan ;
if ( chan )
ast_mutex_lock ( & chan - > lock ) ;
}
2002-09-11 17:09:48 +00:00
if ( chan ) {
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 */
2005-07-15 23:24:51 +00:00
if ( ! chan - > cdr ) {
2004-10-15 17:51:37 +00:00
/* allocation of the cdr failed */
ast_log ( LOG_WARNING , " Unable to create Call Detail Record \n " ) ;
free ( chan - > pbx ) ;
2005-07-15 23:24:51 +00:00
res = - 1 ;
goto outgoing_exten_cleanup ;
2004-10-15 17:51:37 +00:00
}
/* 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 ) {
2005-09-01 20:15:58 +00:00
if ( channel )
ast_mutex_unlock ( & chan - > lock ) ;
2003-02-02 19:04:14 +00:00
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 */
2005-07-15 23:24:51 +00:00
if ( ast_cdr_disposition ( chan - > cdr , chan - > hangupcause ) )
2004-10-15 17:51:37 +00:00
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 */
2005-07-15 23:24:51 +00:00
if ( * reason = = 0 ) { /* if the call failed (not busy or no answer)
2004-10-15 17:51:37 +00:00
* update the cdr with the failed message */
cdr_res = ast_pbx_outgoing_cdr_failed ( ) ;
2005-07-15 23:24:51 +00:00
if ( cdr_res ! = 0 ) {
res = cdr_res ;
goto outgoing_exten_cleanup ;
}
2004-10-15 17:51:37 +00:00
}
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 ) ;
2005-07-15 23:24:51 +00:00
if ( chan ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > name , " OutgoingSpoolFailed " , sizeof ( chan - > name ) ) ;
2004-05-04 06:34:34 +00:00
if ( context & & ! ast_strlen_zero ( context ) )
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > context , context , sizeof ( chan - > context ) ) ;
ast_copy_string ( chan - > exten , " failed " , sizeof ( chan - > exten ) ) ;
2003-09-12 16:51:35 +00:00
chan - > priority = 1 ;
2005-07-15 23:24:51 +00:00
ast_set_variables ( chan , vars ) ;
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 ) ) ;
2005-07-15 23:24:51 +00:00
if ( ! as ) {
res = - 1 ;
goto outgoing_exten_cleanup ;
}
2002-09-11 17:09:48 +00:00
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 ) ;
2005-02-02 02:54:15 +00:00
if ( channel ) {
* channel = chan ;
if ( chan )
ast_mutex_lock ( & chan - > lock ) ;
}
2002-09-11 17:09:48 +00:00
if ( ! chan ) {
free ( as ) ;
2005-07-15 23:24:51 +00:00
res = - 1 ;
goto outgoing_exten_cleanup ;
2002-09-11 17:09:48 +00:00
}
as - > chan = chan ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( as - > context , context , sizeof ( as - > context ) ) ;
ast_copy_string ( as - > exten , exten , sizeof ( as - > exten ) ) ;
2002-09-11 17:09:48 +00:00
as - > priority = priority ;
as - > timeout = timeout ;
2005-07-15 23:24:51 +00:00
ast_set_variables ( chan , vars ) ;
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 ) ;
2005-07-15 23:24:51 +00:00
res = - 1 ;
goto outgoing_exten_cleanup ;
2002-09-11 17:09:48 +00:00
}
res = 0 ;
}
2005-07-15 23:24:51 +00:00
outgoing_exten_cleanup :
ast_variables_destroy ( vars ) ;
2002-09-11 17:09:48 +00:00
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 )
2005-08-15 01:56:40 +00:00
ast_verbose ( VERBOSE_PREFIX_4 " Launching %s(%s) on %s \n " , tmp - > app , tmp - > data , tmp - > chan - > name ) ;
2003-02-02 19:04:14 +00:00
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 ;
}
2005-07-15 23:24:51 +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 , struct ast_variable * vars , struct ast_channel * * locked_channel )
2003-02-02 19:04:14 +00:00
{
struct ast_channel * chan ;
struct async_stat * as ;
struct app_tmp * tmp ;
2004-10-15 17:51:37 +00:00
int res = - 1 , cdr_res = - 1 ;
2005-07-15 23:24:51 +00:00
struct outgoing_helper oh ;
2003-10-23 03:55:58 +00:00
pthread_attr_t attr ;
2005-07-15 23:24:51 +00:00
memset ( & oh , 0 , sizeof ( oh ) ) ;
oh . vars = vars ;
2005-02-02 02:54:15 +00:00
if ( locked_channel )
* locked_channel = NULL ;
2005-07-15 23:24:51 +00:00
if ( ! app | | ast_strlen_zero ( app ) ) {
res = - 1 ;
goto outgoing_app_cleanup ;
}
2003-02-02 19:04:14 +00:00
if ( sync ) {
2005-07-15 23:24:51 +00:00
chan = __ast_request_and_dial ( type , format , data , timeout , reason , cid_num , cid_name , & oh ) ;
2003-02-02 19:04:14 +00:00
if ( chan ) {
2005-07-15 23:24:51 +00:00
if ( chan - > cdr ) { /* check if the channel already has a cdr record, if not give it one */
2004-10-15 17:51:37 +00:00
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 ) ;
2005-07-15 23:24:51 +00:00
res = - 1 ;
goto outgoing_app_cleanup ;
2004-10-15 17:51:37 +00:00
}
/* allocation of the cdr was successful */
ast_cdr_init ( chan - > cdr , chan ) ; /* initilize our channel's cdr */
ast_cdr_start ( chan - > cdr ) ;
}
2005-07-15 23:24:51 +00:00
ast_set_variables ( chan , vars ) ;
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 ) ) ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( tmp - > app , app , sizeof ( tmp - > app ) ) ;
2005-06-05 16:08:44 +00:00
if ( appdata )
ast_copy_string ( tmp - > data , appdata , sizeof ( tmp - > data ) ) ;
2003-02-02 19:04:14 +00:00
tmp - > chan = chan ;
if ( sync > 1 ) {
2005-04-17 03:44:19 +00:00
if ( locked_channel )
ast_mutex_unlock ( & chan - > lock ) ;
2003-02-02 19:04:14 +00:00
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 ) ;
2005-02-02 02:54:15 +00:00
if ( locked_channel )
ast_mutex_lock ( & chan - > lock ) ;
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 ) ;
2005-02-02 02:54:15 +00:00
if ( locked_channel )
ast_mutex_unlock ( & chan - > lock ) ;
2003-02-02 19:04:14 +00:00
ast_hangup ( chan ) ;
res = - 1 ;
2005-02-02 02:54:15 +00:00
} else {
if ( locked_channel )
* locked_channel = chan ;
2003-02-02 19:04:14 +00:00
}
}
} 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 ) ;
2005-07-15 23:24:51 +00:00
if ( chan - > cdr ) { /* update the cdr */
2004-10-15 17:51:37 +00:00
/* here we update the status of the call, which sould be busy.
* if that fails then we set the status to failed */
2005-07-15 23:24:51 +00:00
if ( ast_cdr_disposition ( chan - > cdr , chan - > hangupcause ) )
2004-10-15 17:51:37 +00:00
ast_cdr_failed ( chan - > cdr ) ;
}
2003-02-02 19:04:14 +00:00
ast_hangup ( chan ) ;
}
}
2004-10-15 17:51:37 +00:00
2005-07-15 23:24:51 +00:00
if ( res < 0 ) { /* the call failed for some reason */
if ( * reason = = 0 ) { /* if the call failed (not busy or no answer)
2004-10-15 17:51:37 +00:00
* update the cdr with the failed message */
cdr_res = ast_pbx_outgoing_cdr_failed ( ) ;
2005-07-15 23:24:51 +00:00
if ( cdr_res ! = 0 ) {
res = cdr_res ;
goto outgoing_app_cleanup ;
}
2004-10-15 17:51:37 +00:00
}
}
2003-02-02 19:04:14 +00:00
} else {
as = malloc ( sizeof ( struct async_stat ) ) ;
2005-07-15 23:24:51 +00:00
if ( ! as ) {
res = - 1 ;
goto outgoing_app_cleanup ;
}
2003-02-02 19:04:14 +00:00
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 ) ;
2005-07-15 23:24:51 +00:00
res = - 1 ;
goto outgoing_app_cleanup ;
2003-02-02 19:04:14 +00:00
}
as - > chan = chan ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( as - > app , app , sizeof ( as - > app ) ) ;
2003-02-02 19:04:14 +00:00
if ( appdata )
2005-06-05 16:32:16 +00:00
ast_copy_string ( as - > appdata , appdata , sizeof ( as - > appdata ) ) ;
2003-02-02 19:04:14 +00:00
as - > timeout = timeout ;
2005-07-15 23:24:51 +00:00
ast_set_variables ( chan , vars ) ;
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 ) ;
2005-02-02 02:54:15 +00:00
if ( locked_channel )
ast_mutex_lock ( & chan - > lock ) ;
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 ) ;
2005-02-02 02:54:15 +00:00
if ( locked_channel )
ast_mutex_unlock ( & chan - > lock ) ;
2003-02-02 19:04:14 +00:00
ast_hangup ( chan ) ;
2005-07-15 23:24:51 +00:00
res = - 1 ;
goto outgoing_app_cleanup ;
2005-02-02 02:54:15 +00:00
} else {
if ( locked_channel )
* locked_channel = chan ;
2003-02-02 19:04:14 +00:00
}
res = 0 ;
}
2005-07-15 23:24:51 +00:00
outgoing_app_cleanup :
ast_variables_destroy ( vars ) ;
2003-02-02 19:04:14 +00:00
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 ) ;
}
2005-03-29 06:16:49 +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 ;
2005-04-29 17:00:33 +00:00
if ( ! data | | ! strlen ( data ) | | ( sscanf ( data , " %d " , & waittime ) ! = 1 ) | | ( waittime < 0 ) )
2004-07-09 08:32:09 +00:00
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 ) ;
2005-07-15 16:02:37 +00:00
ast_setstate ( chan , AST_STATE_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 ) ;
2005-07-15 16:02:37 +00:00
ast_setstate ( chan , AST_STATE_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_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
{
2005-05-15 17:45:30 +00:00
static int deprecation_warning = 0 ;
if ( ! deprecation_warning ) {
2005-05-15 23:32:38 +00:00
ast_log ( LOG_WARNING , " SetLanguage is deprecated, please use Set(LANGUAGE()=language) instead. \n " ) ;
2005-05-15 17:45:30 +00:00
deprecation_warning = 1 ;
}
2000-01-24 07:14:18 +00:00
/* Copy the language as specified */
2004-10-13 22:47:42 +00:00
if ( data )
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > language , ( char * ) data , sizeof ( chan - > language ) ) ;
2005-05-15 17:45:30 +00:00
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 ;
2005-02-23 22:48:47 +00:00
if ( strchr ( ( char * ) data , ' v ' ) )
flags | = AST_CDR_FLAG_KEEP_VARS ;
2004-09-24 21:33:48 +00:00
}
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 ) ) {
2005-06-05 16:32:16 +00:00
ast_copy_string ( newexten , chan - > exten + atoi ( data ) , sizeof ( newexten ) ) ;
2000-01-07 10:54:40 +00:00
}
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > exten , newexten , sizeof ( chan - > exten ) ) ;
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
{
2005-09-07 21:01:31 +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 ) ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > exten , newexten , sizeof ( chan - > exten ) ) ;
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 )
{
2005-09-07 21:01:31 +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 ) ) {
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 ) ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > exten , newexten , sizeof ( chan - > exten ) ) ;
2003-04-28 04:18:47 +00:00
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
2005-02-25 00:25:28 +00:00
if ( ! data | | ast_strlen_zero ( data ) ) {
2003-04-28 04:18:47 +00:00
ast_log ( LOG_WARNING , " GotoIfTime requires an argument: \n <time range>|<days of week>|<days of month>|<months>?[[context|]extension|]priority \n " ) ;
return - 1 ;
}
2005-02-25 00:25:28 +00:00
if ( ( s = ast_strdupa ( ( char * ) data ) ) ) {
ts = s ;
/* Separate the Goto path */
strsep ( & ts , " ? " ) ;
/* struct ast_include include contained garbage here, fixed by zeroing it on get_timerange */
if ( ast_build_timing ( & timing , s ) & & ast_check_timing ( & timing ) )
res = pbx_builtin_goto ( chan , ( void * ) ts ) ;
} else {
ast_log ( LOG_ERROR , " Memory Error! \n " ) ;
}
return res ;
}
static int pbx_builtin_execiftime ( struct ast_channel * chan , void * data )
{
int res = 0 ;
char * ptr1 , * ptr2 ;
struct ast_timing timing ;
2005-08-19 07:12:53 +00:00
struct ast_app * app ;
2005-03-29 06:18:58 +00:00
const char * usage = " ExecIfTime requires an argument: \n <time range>|<days of week>|<days of month>|<months>?<appname>[|<appargs>] " ;
2003-04-28 04:18:47 +00:00
2005-02-25 00:25:28 +00:00
if ( ! data | | ast_strlen_zero ( data ) ) {
2005-03-29 06:18:58 +00:00
ast_log ( LOG_WARNING , " %s \n " , usage ) ;
2005-02-25 00:25:28 +00:00
return - 1 ;
}
2003-04-28 04:18:47 +00:00
2005-08-19 07:12:53 +00:00
ptr1 = ast_strdupa ( data ) ;
if ( ! ptr1 ) {
ast_log ( LOG_ERROR , " Out of Memory! \n " ) ;
return - 1 ;
}
ptr2 = ptr1 ;
/* Separate the Application data ptr1 is the time spec ptr2 is the app|data */
strsep ( & ptr2 , " ? " ) ;
if ( ! ast_build_timing ( & timing , ptr1 ) ) {
ast_log ( LOG_WARNING , " Invalid Time Spec: %s \n Correct usage: %s \n " , ptr1 , usage ) ;
res = - 1 ;
}
if ( ! res & & ast_check_timing ( & timing ) ) {
if ( ! ptr2 ) {
ast_log ( LOG_WARNING , " %s \n " , usage ) ;
}
/* ptr2 is now the app name
we ' re done with ptr1 now so recycle it and use it to point to the app args */
if ( ( ptr1 = strchr ( ptr2 , ' | ' ) ) ) {
* ptr1 = ' \0 ' ;
ptr1 + + ;
2005-05-26 15:50:50 +00:00
}
2005-08-19 07:12:53 +00:00
if ( ( app = pbx_findapp ( ptr2 ) ) ) {
res = pbx_exec ( chan , app , ptr1 ? ptr1 : " " , 1 ) ;
} else {
ast_log ( LOG_WARNING , " Cannot locate application %s \n " , ptr2 ) ;
res = - 1 ;
2005-02-25 00:25:28 +00:00
}
}
2005-08-19 07:12:53 +00:00
2003-04-28 04:18:47 +00:00
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 )
{
2005-04-15 05:47:40 +00:00
int ms , res , argc ;
char * args ;
char * argv [ 2 ] ;
char * options = NULL ;
char * mohclass = NULL ;
char * timeout = NULL ;
struct ast_flags flags = { 0 } ;
args = ast_strdupa ( data ) ;
if ( ( argc = ast_separate_app_args ( args , ' | ' , argv , sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) {
if ( argc > 0 ) {
timeout = argv [ 0 ] ;
if ( argc > 1 )
options = argv [ 1 ] ;
}
}
if ( options ) {
char * opts [ 1 ] ;
ast_parseoptions ( waitexten_opts , & flags , opts , options ) ;
if ( ast_test_flag ( & flags , WAITEXTEN_MOH ) ) {
mohclass = opts [ 0 ] ;
}
}
if ( ast_test_flag ( & flags , WAITEXTEN_MOH ) )
ast_moh_start ( chan , mohclass ) ;
2004-04-06 04:14:19 +00:00
/* Wait for "n" seconds */
2005-04-15 05:47:40 +00:00
if ( timeout & & atof ( ( char * ) timeout ) )
ms = atof ( ( char * ) timeout ) * 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 ) ;
2005-06-05 16:32:16 +00:00
ast_copy_string ( chan - > exten , " t " , sizeof ( chan - > exten ) ) ;
2004-10-16 19:46:02 +00:00
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
}
2005-04-15 05:47:40 +00:00
if ( ast_test_flag ( & flags , WAITEXTEN_MOH ) )
ast_moh_stop ( chan ) ;
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 ;
2005-04-15 05:47:40 +00:00
int argc ;
2005-09-14 17:19:55 +00:00
char * parse ;
2005-07-12 01:34:06 +00:00
char * argv [ 4 ] ;
2005-04-15 05:47:40 +00:00
char * options = NULL ;
2004-11-25 02:57:34 +00:00
char * filename = NULL ;
char * front = NULL , * back = NULL ;
2005-04-15 05:47:40 +00:00
char * lang = NULL ;
2005-07-12 01:34:06 +00:00
char * context = NULL ;
2005-04-15 05:47:40 +00:00
struct ast_flags flags = { 0 } ;
2004-09-07 14:51:20 +00:00
2005-09-14 17:19:55 +00:00
parse = ast_strdupa ( data ) ;
if ( ( argc = ast_separate_app_args ( parse , ' | ' , argv , sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ) ) {
switch ( argc ) {
case 4 :
context = argv [ 3 ] ;
case 3 :
lang = argv [ 2 ] ;
case 2 :
options = argv [ 1 ] ;
case 1 :
2005-04-15 05:47:40 +00:00
filename = argv [ 0 ] ;
2005-09-14 17:19:55 +00:00
break ;
default :
2005-04-15 05:47:40 +00:00
ast_log ( LOG_WARNING , " Background requires an argument (filename) \n " ) ;
2005-09-14 17:19:55 +00:00
break ;
2005-04-15 05:47:40 +00:00
}
}
2004-09-07 14:51:20 +00:00
2005-04-20 16:11:16 +00:00
if ( ! lang )
lang = chan - > language ;
2005-07-12 01:34:06 +00:00
if ( ! context )
context = chan - > context ;
2005-04-15 05:47:40 +00:00
if ( options ) {
if ( ! strcasecmp ( options , " skip " ) )
flags . flags = BACKGROUND_SKIP ;
else if ( ! strcasecmp ( options , " noanswer " ) )
flags . flags = BACKGROUND_NOANSWER ;
else
ast_parseoptions ( background_opts , & flags , NULL , options ) ;
}
2004-09-07 14:51:20 +00:00
/* Answer if need be */
if ( chan - > _state ! = AST_STATE_UP ) {
2005-04-15 05:47:40 +00:00
if ( ast_test_flag ( & flags , BACKGROUND_SKIP ) ) {
2004-09-07 14:51:20 +00:00
return 0 ;
2005-04-15 05:47:40 +00:00
} else if ( ! ast_test_flag ( & flags , BACKGROUND_NOANSWER ) ) {
2004-09-07 14:51:20 +00:00
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 ) {
2005-07-12 01:34:06 +00:00
if ( ast_test_flag ( & flags , BACKGROUND_PLAYBACK ) ) {
res = ast_waitstream ( chan , " " ) ;
} else {
if ( ast_test_flag ( & flags , BACKGROUND_MATCHEXTEN ) ) {
res = ast_waitstream_exten ( chan , context ) ;
} else {
res = ast_waitstream ( chan , AST_DIGIT_ANY ) ;
}
}
2004-11-25 02:57:34 +00:00
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
}
}
2005-07-12 01:34:06 +00:00
if ( context ! = chan - > context & & res ) {
snprintf ( chan - > exten , sizeof ( chan - > exten ) , " %c " , res ) ;
ast_copy_string ( chan - > context , context , sizeof ( chan - > context ) ) ;
chan - > priority = 0 ;
return 0 ;
} else {
return res ;
}
1999-12-04 20:45:45 +00:00
}
2001-11-24 15:15:01 +00:00
static int pbx_builtin_atimeout ( struct ast_channel * chan , void * data )
{
2005-05-15 17:45:30 +00:00
static int deprecation_warning = 0 ;
2001-11-24 15:15:01 +00:00
int x = atoi ( ( char * ) data ) ;
2004-07-17 02:25:53 +00:00
2005-05-15 17:45:30 +00:00
if ( ! deprecation_warning ) {
2005-05-15 23:32:38 +00:00
ast_log ( LOG_WARNING , " AbsoluteTimeout is deprecated, please use Set(TIMEOUT(absolute)=timeout) instead. \n " ) ;
2005-05-15 17:45:30 +00:00
deprecation_warning = 1 ;
}
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
{
2005-05-15 17:45:30 +00:00
static int deprecation_warning = 0 ;
if ( ! deprecation_warning ) {
2005-05-15 23:32:38 +00:00
ast_log ( LOG_WARNING , " ResponseTimeout is deprecated, please use Set(TIMEOUT(response)=timeout) instead. \n " ) ;
2005-05-15 17:45:30 +00:00
deprecation_warning = 1 ;
}
2005-04-27 02:48:25 +00:00
/* If the channel is not in a PBX, return now */
if ( ! chan - > pbx )
return 0 ;
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
{
2005-05-15 17:45:30 +00:00
static int deprecation_warning = 0 ;
if ( ! deprecation_warning ) {
2005-05-15 23:32:38 +00:00
ast_log ( LOG_WARNING , " DigitTimeout is deprecated, please use Set(TIMEOUT(digit)=timeout) instead. \n " ) ;
2005-05-15 17:45:30 +00:00
deprecation_warning = 1 ;
}
2005-04-27 02:48:25 +00:00
/* If the channel is not in a PBX, return now */
if ( ! chan - > pbx )
return 0 ;
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 ;
2005-06-20 23:37:01 +00:00
char * var , * val ;
2004-10-22 20:59:38 +00:00
int total = 0 ;
2005-06-20 23:37:01 +00:00
if ( ! chan )
return 0 ;
memset ( buf , 0 , size ) ;
AST_LIST_TRAVERSE ( & chan - > varshead , variables , entries ) {
if ( variables & &
( var = ast_var_name ( variables ) ) & & ( val = ast_var_value ( variables ) ) & &
! ast_strlen_zero ( var ) & & ! ast_strlen_zero ( val ) ) {
if ( ast_build_string ( & buf , & size , " %s=%s \n " , var , val ) ) {
ast_log ( LOG_ERROR , " Data Buffer Size Exceeded! \n " ) ;
2004-10-27 02:26:17 +00:00
break ;
2005-06-20 23:37:01 +00:00
} else
total + + ;
} else
break ;
2004-10-22 20:59:38 +00:00
}
return total ;
}
2005-03-29 06:16:49 +00:00
char * pbx_builtin_getvar_helper ( struct ast_channel * chan , const char * name )
2004-05-09 07:19:00 +00:00
{
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 ;
}
2005-03-29 06:16:49 +00:00
void pbx_builtin_setvar_helper ( struct ast_channel * chan , const char * name , const 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
2005-02-23 22:48:47 +00:00
2005-03-29 06:16:49 +00:00
if ( name [ strlen ( name ) - 1 ] = = ' ) ' )
return ast_func_write ( chan , name , value ) ;
2005-05-04 15:56:44 +00:00
headp = ( chan ) ? & chan - > varshead : & globals ;
2004-11-01 02:23:28 +00:00
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 ) )
2005-05-04 15:56:44 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Setting global variable '%s' to '%s' \n " , name , value ) ;
2004-11-01 02:23:28 +00:00
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
}
2005-05-15 23:32:38 +00:00
int pbx_builtin_setvar_old ( struct ast_channel * chan , void * data )
{
static int deprecation_warning = 0 ;
if ( ! deprecation_warning ) {
ast_log ( LOG_WARNING , " SetVar is deprecated, please use Set instead. \n " ) ;
deprecation_warning = 1 ;
}
return pbx_builtin_setvar ( chan , data ) ;
}
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
{
2005-05-04 15:56:44 +00:00
char * name , * value , * mydata ;
int argc ;
char * argv [ 24 ] ; /* this will only support a maximum of 24 variables being set in a single operation */
int global = 0 ;
int x ;
2005-02-23 22:48:47 +00:00
2005-05-04 15:56:44 +00:00
if ( ! data | | ast_strlen_zero ( data ) ) {
2005-05-15 23:32:38 +00:00
ast_log ( LOG_WARNING , " Set requires at least one variable name/value pair. \n " ) ;
2005-05-04 15:56:44 +00:00
return 0 ;
}
2004-11-01 02:23:28 +00:00
2005-05-04 15:56:44 +00:00
mydata = ast_strdupa ( data ) ;
argc = ast_separate_app_args ( mydata , ' | ' , argv , sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ;
/* check for a trailing flags argument */
if ( ( argc > 1 ) & & ! strchr ( argv [ argc - 1 ] , ' = ' ) ) {
argc - - ;
if ( strchr ( argv [ argc ] , ' g ' ) )
global = 1 ;
2002-09-11 17:09:48 +00:00
}
2005-05-04 15:56:44 +00:00
for ( x = 0 ; x < argc ; x + + ) {
name = argv [ x ] ;
if ( ( value = strchr ( name , ' = ' ) ) ) {
* value = ' \0 ' ;
value + + ;
pbx_builtin_setvar_helper ( ( global ) ? NULL : chan , name , value ) ;
} else
ast_log ( LOG_WARNING , " Ignoring entry '%s' with no = (and not last 'options' entry) \n " , name ) ;
}
2004-11-01 02:23:28 +00:00
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 ;
2005-06-06 02:29:18 +00:00
struct ast_channel * chan2 ;
2005-09-26 16:58:40 +00:00
char tmp [ VAR_BUF_SIZE ] = " " ;
2004-11-17 04:48:58 +00:00
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 ) {
2005-06-06 02:29:18 +00:00
chan2 = ast_get_channel_by_name_locked ( channel ) ;
2004-11-17 04:48:58 +00:00
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 ) ) {
2005-03-29 06:16:49 +00:00
ast_log ( LOG_WARNING , " SayNumber requires an argument (number) \n " ) ;
return - 1 ;
}
2005-06-05 16:32:16 +00:00
ast_copy_string ( tmp , ( char * ) data , sizeof ( tmp ) ) ;
2005-03-29 06:16:49 +00:00
number = tmp ;
strsep ( & number , " | " ) ;
options = strsep ( & number , " | " ) ;
if ( options ) {
2004-04-29 02:30:14 +00:00
if ( strcasecmp ( options , " f " ) & & strcasecmp ( options , " m " ) & &
strcasecmp ( options , " c " ) & & strcasecmp ( options , " n " ) ) {
2005-03-29 06:16:49 +00:00
ast_log ( LOG_WARNING , " SayNumber gender option is either 'f', 'm', 'c' or 'n' \n " ) ;
return - 1 ;
2004-04-29 02:30:14 +00:00
}
}
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 " ) ;
}
2005-03-29 06:16:49 +00:00
AST_LIST_HEAD_INIT ( & globals ) ;
2005-06-03 03:09:20 +00:00
ast_cli_register_multiple ( pbx_cli , sizeof ( pbx_cli ) / sizeof ( pbx_cli [ 0 ] ) ) ;
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 ;
2005-04-13 23:33:47 +00:00
ast_log ( LOG_WARNING , " Context '%s' tries includes nonexistent context '%s' \n " ,
2003-10-25 17:50:06 +00:00
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
2005-04-29 15:04:26 +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
{
2005-04-29 15:04:26 +00:00
int ( * goto_func ) ( struct ast_channel * chan , const char * context , const char * exten , int priority ) ;
2004-12-08 18:24:04 +00:00
2005-04-29 15:04:26 +00:00
if ( ! chan )
return - 2 ;
2004-12-08 18:24:04 +00:00
2005-04-29 15:04:26 +00:00
goto_func = ( async ) ? ast_async_goto : ast_explicit_goto ;
if ( ast_exists_extension ( chan , context ? context : chan - > context ,
exten ? exten : chan - > exten , priority ,
chan - > cid . cid_num ) )
return goto_func ( chan , context ? context : chan - > context ,
exten ? exten : chan - > exten , priority ) ;
else
return - 3 ;
2004-11-22 22:11:10 +00:00
}
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 + + ;
}
2005-04-29 15:04:26 +00:00
if ( sscanf ( pri , " %d " , & ipri ) ! = 1 ) {
2004-11-22 22:11:10 +00:00
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 ) ;
2005-04-29 15:04:26 +00:00
ast_explicit_goto ( chan , context , exten , ipri ) ;
2004-11-22 22:11:10 +00:00
ast_cdr_update ( chan ) ;
return 0 ;
}