2001-09-28 13:19:43 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2001-09-28 13:19:43 +00:00
*
2006-02-15 00:38:27 +00:00
* Copyright ( C ) 1999 - 2006 , Digium , Inc .
2001-09-28 13:19:43 +00:00
*
2004-09-22 15:21:36 +00:00
* Mark Spencer < markster @ digium . com >
2001-09-28 13:19:43 +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 .
*
2001-09-28 13:19:43 +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 .
*/
2005-10-24 20:12:06 +00:00
/*! \file
2005-09-14 20:46:50 +00:00
*
2005-10-24 20:12:06 +00:00
* \ brief AGI - the Asterisk Gateway Interface
2005-12-30 21:18:06 +00:00
*
* \ author Mark Spencer < markster @ digium . com >
2001-09-28 13:19:43 +00:00
*/
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2001-09-28 13:19:43 +00:00
# include <math.h>
2003-09-08 16:48:07 +00:00
# include <signal.h>
2001-09-28 13:19:43 +00:00
# include <sys/time.h>
2006-05-25 18:31:19 +00:00
# include <sys/wait.h>
2007-06-25 13:00:49 +00:00
# include <sys/stat.h>
2005-06-06 22:12:19 +00:00
2007-11-20 23:16:15 +00:00
# include "asterisk/paths.h" /* use many ast_config_AST_*_DIR */
2007-11-17 14:11:53 +00:00
# include "asterisk/network.h"
2005-06-06 22:12:19 +00:00
# include "asterisk/file.h"
# include "asterisk/channel.h"
# include "asterisk/pbx.h"
# include "asterisk/module.h"
# include "asterisk/astdb.h"
# include "asterisk/callerid.h"
2005-04-21 06:02:45 +00:00
# include "asterisk/cli.h"
# include "asterisk/image.h"
# include "asterisk/say.h"
# include "asterisk/app.h"
# include "asterisk/dsp.h"
# include "asterisk/musiconhold.h"
# include "asterisk/utils.h"
# include "asterisk/lock.h"
2005-08-22 23:00:23 +00:00
# include "asterisk/strings.h"
2005-04-21 06:02:45 +00:00
# include "asterisk/agi.h"
2007-12-04 15:01:57 +00:00
# include "asterisk/version.h"
2007-12-03 21:03:05 +00:00
# include "asterisk/speech.h"
2001-09-28 13:19:43 +00:00
# define MAX_ARGS 128
2007-09-11 15:28:46 +00:00
# define AGI_NANDFS_RETRY 3
# define AGI_BUF_LEN 2048
2001-09-28 13:19:43 +00:00
static char * app = " AGI " ;
2003-02-23 06:00:11 +00:00
static char * eapp = " EAGI " ;
2004-03-03 18:58:57 +00:00
static char * deadapp = " DeadAGI " ;
2001-09-28 13:19:43 +00:00
static char * synopsis = " Executes an AGI compliant application " ;
2004-01-30 05:37:39 +00:00
static char * esynopsis = " Executes an EAGI compliant application " ;
2004-03-03 18:58:57 +00:00
static char * deadsynopsis = " Executes AGI on a hungup channel " ;
2001-09-28 13:19:43 +00:00
static char * descrip =
2007-07-31 01:10:47 +00:00
" [E|Dead]AGI(command,args): Executes an Asterisk Gateway Interface compliant \n "
2004-01-30 05:37:39 +00:00
" program on a channel. AGI allows Asterisk to launch external programs \n "
2001-09-28 13:19:43 +00:00
" written in any language to control a telephony channel, play audio, \n "
" read DTMF digits, etc. by communicating with the AGI protocol on stdin \n "
2004-01-30 05:37:39 +00:00
" and stdout. \n "
2006-05-25 16:44:22 +00:00
" This channel will stop dialplan execution on hangup inside of this \n "
" application, except when using DeadAGI. Otherwise, dialplan execution \n "
" will continue normally. \n "
2006-05-25 19:01:26 +00:00
" A locally executed AGI script will receive SIGHUP on hangup from the channel \n "
" except when using DeadAGI. This can be disabled by setting the AGISIGHUP channel \n "
" variable to \" no \" before executing the AGI application. \n "
2006-05-25 16:44:22 +00:00
" Using 'EAGI' provides enhanced AGI, with incoming audio available out of band \n "
2004-01-30 05:37:39 +00:00
" on file descriptor 3 \n \n "
2006-11-02 23:16:09 +00:00
" Use the CLI command 'agi show' to list available agi commands \n "
2006-05-25 16:44:22 +00:00
" This application sets the following channel variable upon completion: \n "
" AGISTATUS The status of the attempt to the run the AGI script \n "
2007-06-21 15:58:05 +00:00
" text string, one of SUCCESS | FAILED | NOTFOUND | HANGUP \n " ;
2001-09-28 13:19:43 +00:00
2004-09-25 14:22:27 +00:00
static int agidebug = 0 ;
2001-09-28 13:19:43 +00:00
# define TONE_BLOCK_SIZE 200
2004-09-22 15:21:36 +00:00
/* Max time to connect to an AGI remote host */
# define MAX_AGI_CONNECT 2000
# define AGI_PORT 4573
2006-05-25 16:44:22 +00:00
enum agi_result {
AGI_RESULT_SUCCESS ,
2007-09-18 22:46:05 +00:00
AGI_RESULT_SUCCESS_FAST ,
2006-05-25 16:44:22 +00:00
AGI_RESULT_FAILURE ,
2007-06-21 15:58:05 +00:00
AGI_RESULT_NOTFOUND ,
AGI_RESULT_HANGUP ,
2006-05-25 16:44:22 +00:00
} ;
2007-07-23 22:02:05 +00:00
static agi_command * find_command ( char * cmds [ ] , int exact ) ;
2007-07-30 19:35:33 +00:00
AST_THREADSTORAGE ( agi_buf ) ;
# define AGI_BUF_INITSIZE 256
2007-11-07 00:00:38 +00:00
int ast_agi_fdprintf ( struct ast_channel * chan , int fd , char * fmt , . . . )
2004-09-25 14:22:27 +00:00
{
int res = 0 ;
va_list ap ;
2007-07-30 19:35:33 +00:00
struct ast_str * buf ;
if ( ! ( buf = ast_str_thread_get ( & agi_buf , AGI_BUF_INITSIZE ) ) )
return - 1 ;
2004-09-25 14:22:27 +00:00
va_start ( ap , fmt ) ;
2007-07-30 19:35:33 +00:00
res = ast_str_set_va ( & buf , 0 , fmt , ap ) ;
2004-09-25 14:22:27 +00:00
va_end ( ap ) ;
2007-07-11 21:09:42 +00:00
2004-09-25 14:22:27 +00:00
if ( res = = - 1 ) {
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
2007-07-30 19:18:24 +00:00
return - 1 ;
2004-09-25 14:22:27 +00:00
}
2007-07-11 21:09:42 +00:00
2007-11-07 00:00:38 +00:00
if ( agidebug ) {
if ( chan ) {
ast_verbose ( " <%s>AGI Tx >> %s " , chan - > name , buf - > str ) ;
} else {
ast_verbose ( " AGI Tx >> %s " , buf - > str ) ;
}
}
2007-07-30 19:35:33 +00:00
2007-07-30 19:39:52 +00:00
return ast_carefulwrite ( fd , buf - > str , buf - > used , 100 ) ;
2004-09-25 14:22:27 +00:00
}
2005-01-08 19:35:20 +00:00
/* launch_netscript: The fastagi handler.
FastAGI defaults to port 4573 */
2006-05-25 16:44:22 +00:00
static enum agi_result launch_netscript ( char * agiurl , char * argv [ ] , int * fds , int * efd , int * opid )
2004-09-22 15:21:36 +00:00
{
2007-07-11 21:09:42 +00:00
int s , flags , res , port = AGI_PORT ;
2004-09-22 15:21:36 +00:00
struct pollfd pfds [ 1 ] ;
2007-07-11 21:09:42 +00:00
char * host , * c , * script = " " ;
2004-09-22 15:21:36 +00:00
struct sockaddr_in sin ;
struct hostent * hp ;
struct ast_hostent ahp ;
2005-01-08 19:35:20 +00:00
2006-04-06 16:17:04 +00:00
/* agiusl is "agi://host.domain[:port][/script/name]" */
2005-01-08 19:35:20 +00:00
host = ast_strdupa ( agiurl + 6 ) ; /* Remove agi:// */
2004-09-22 15:21:36 +00:00
/* Strip off any script name */
if ( ( c = strchr ( host , ' / ' ) ) ) {
* c = ' \0 ' ;
c + + ;
script = c ;
}
if ( ( c = strchr ( host , ' : ' ) ) ) {
* c = ' \0 ' ;
c + + ;
2004-09-29 03:32:58 +00:00
port = atoi ( c ) ;
2004-09-22 15:21:36 +00:00
}
if ( efd ) {
ast_log ( LOG_WARNING , " AGI URI's don't support Enhanced AGI yet \n " ) ;
return - 1 ;
}
2007-07-11 21:09:42 +00:00
if ( ! ( hp = ast_gethostbyname ( host , & ahp ) ) ) {
2004-09-22 15:21:36 +00:00
ast_log ( LOG_WARNING , " Unable to locate host '%s' \n " , host ) ;
return - 1 ;
}
2007-07-11 21:09:42 +00:00
if ( ( s = socket ( AF_INET , SOCK_STREAM , 0 ) ) < 0 ) {
2004-09-22 15:21:36 +00:00
ast_log ( LOG_WARNING , " Unable to create socket: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
2007-07-11 21:09:42 +00:00
if ( ( flags = fcntl ( s , F_GETFL ) ) < 0 ) {
2004-09-22 15:21:36 +00:00
ast_log ( LOG_WARNING , " Fcntl(F_GETFL) failed: %s \n " , strerror ( errno ) ) ;
close ( s ) ;
return - 1 ;
}
if ( fcntl ( s , F_SETFL , flags | O_NONBLOCK ) < 0 ) {
ast_log ( LOG_WARNING , " Fnctl(F_SETFL) failed: %s \n " , strerror ( errno ) ) ;
close ( s ) ;
return - 1 ;
}
memset ( & sin , 0 , sizeof ( sin ) ) ;
sin . sin_family = AF_INET ;
sin . sin_port = htons ( port ) ;
memcpy ( & sin . sin_addr , hp - > h_addr , sizeof ( sin . sin_addr ) ) ;
if ( connect ( s , ( struct sockaddr * ) & sin , sizeof ( sin ) ) & & ( errno ! = EINPROGRESS ) ) {
ast_log ( LOG_WARNING , " Connect failed with unexpected error: %s \n " , strerror ( errno ) ) ;
close ( s ) ;
2006-05-25 16:44:22 +00:00
return AGI_RESULT_FAILURE ;
2004-09-22 15:21:36 +00:00
}
2006-02-15 00:38:27 +00:00
2004-09-22 15:21:36 +00:00
pfds [ 0 ] . fd = s ;
pfds [ 0 ] . events = POLLOUT ;
2006-05-31 23:51:39 +00:00
while ( ( res = poll ( pfds , 1 , MAX_AGI_CONNECT ) ) ! = 1 ) {
2006-02-15 00:38:27 +00:00
if ( errno ! = EINTR ) {
2006-05-31 23:51:39 +00:00
if ( ! res ) {
ast_log ( LOG_WARNING , " FastAGI connection to '%s' timed out after MAX_AGI_CONNECT (%d) milliseconds. \n " ,
agiurl , MAX_AGI_CONNECT ) ;
} else
ast_log ( LOG_WARNING , " Connect to '%s' failed: %s \n " , agiurl , strerror ( errno ) ) ;
2006-02-15 00:38:27 +00:00
close ( s ) ;
2006-05-25 16:44:22 +00:00
return AGI_RESULT_FAILURE ;
2006-02-15 00:38:27 +00:00
}
2004-09-22 15:21:36 +00:00
}
2007-07-30 19:18:24 +00:00
2007-11-07 00:00:38 +00:00
if ( ast_agi_fdprintf ( NULL , s , " agi_network: yes \n " ) < 0 ) {
2006-02-15 00:38:27 +00:00
if ( errno ! = EINTR ) {
ast_log ( LOG_WARNING , " Connect to '%s' failed: %s \n " , agiurl , strerror ( errno ) ) ;
close ( s ) ;
2006-05-25 16:44:22 +00:00
return AGI_RESULT_FAILURE ;
2006-02-15 00:38:27 +00:00
}
2004-09-22 15:21:36 +00:00
}
2005-01-08 19:35:20 +00:00
/* If we have a script parameter, relay it to the fastagi server */
2006-10-17 23:06:13 +00:00
/* Script parameters take the form of: AGI(agi://my.example.com/?extension=${EXTEN}) */
2005-01-08 19:35:20 +00:00
if ( ! ast_strlen_zero ( script ) )
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( NULL , s , " agi_network_script: %s \n " , script ) ;
2005-01-08 19:35:20 +00:00
2007-06-14 19:39:12 +00:00
ast_debug ( 4 , " Wow, connected! \n " ) ;
2004-09-22 15:21:36 +00:00
fds [ 0 ] = s ;
fds [ 1 ] = s ;
* opid = - 1 ;
2007-09-18 22:46:05 +00:00
return AGI_RESULT_SUCCESS_FAST ;
2004-09-22 15:21:36 +00:00
}
2006-05-25 16:44:22 +00:00
static enum agi_result launch_script ( char * script , char * argv [ ] , int * fds , int * efd , int * opid )
2001-09-28 13:19:43 +00:00
{
char tmp [ 256 ] ;
2007-07-11 21:09:42 +00:00
int pid , toast [ 2 ] , fromast [ 2 ] , audio [ 2 ] , x , res ;
2006-12-11 00:52:19 +00:00
sigset_t signal_set , old_set ;
2007-06-22 16:19:53 +00:00
struct stat st ;
2004-09-22 15:21:36 +00:00
if ( ! strncasecmp ( script , " agi:// " , 6 ) )
return launch_netscript ( script , argv , fds , efd , opid ) ;
2001-09-28 13:19:43 +00:00
if ( script [ 0 ] ! = ' / ' ) {
2006-11-04 01:40:49 +00:00
snprintf ( tmp , sizeof ( tmp ) , " %s/%s " , ast_config_AST_AGI_DIR , script ) ;
2001-09-28 13:19:43 +00:00
script = tmp ;
}
2007-06-21 15:58:05 +00:00
/* Before even trying let's see if the file actually exists */
2007-06-22 16:19:53 +00:00
if ( stat ( script , & st ) ) {
2007-06-21 15:58:05 +00:00
ast_log ( LOG_WARNING , " Failed to execute '%s': File does not exist. \n " , script ) ;
return AGI_RESULT_NOTFOUND ;
}
2001-09-28 13:19:43 +00:00
if ( pipe ( toast ) ) {
ast_log ( LOG_WARNING , " Unable to create toast pipe: %s \n " , strerror ( errno ) ) ;
2006-05-25 16:44:22 +00:00
return AGI_RESULT_FAILURE ;
2001-09-28 13:19:43 +00:00
}
if ( pipe ( fromast ) ) {
ast_log ( LOG_WARNING , " unable to create fromast pipe: %s \n " , strerror ( errno ) ) ;
close ( toast [ 0 ] ) ;
close ( toast [ 1 ] ) ;
2006-05-25 16:44:22 +00:00
return AGI_RESULT_FAILURE ;
2001-09-28 13:19:43 +00:00
}
2003-02-23 06:00:11 +00:00
if ( efd ) {
if ( pipe ( audio ) ) {
ast_log ( LOG_WARNING , " unable to create audio pipe: %s \n " , strerror ( errno ) ) ;
close ( fromast [ 0 ] ) ;
close ( fromast [ 1 ] ) ;
close ( toast [ 0 ] ) ;
close ( toast [ 1 ] ) ;
2006-05-25 16:44:22 +00:00
return AGI_RESULT_FAILURE ;
2003-02-23 06:00:11 +00:00
}
res = fcntl ( audio [ 1 ] , F_GETFL ) ;
if ( res > - 1 )
res = fcntl ( audio [ 1 ] , F_SETFL , res | O_NONBLOCK ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " unable to set audio pipe parameters: %s \n " , strerror ( errno ) ) ;
close ( fromast [ 0 ] ) ;
close ( fromast [ 1 ] ) ;
close ( toast [ 0 ] ) ;
close ( toast [ 1 ] ) ;
close ( audio [ 0 ] ) ;
close ( audio [ 1 ] ) ;
2006-05-25 16:44:22 +00:00
return AGI_RESULT_FAILURE ;
2003-02-23 06:00:11 +00:00
}
}
2006-12-11 00:52:19 +00:00
/* Block SIGHUP during the fork - prevents a race */
sigfillset ( & signal_set ) ;
pthread_sigmask ( SIG_BLOCK , & signal_set , & old_set ) ;
2007-07-11 21:09:42 +00:00
if ( ( pid = fork ( ) ) < 0 ) {
2001-09-28 13:19:43 +00:00
ast_log ( LOG_WARNING , " Failed to fork(): %s \n " , strerror ( errno ) ) ;
2006-12-11 00:52:19 +00:00
pthread_sigmask ( SIG_SETMASK , & old_set , NULL ) ;
2006-05-25 16:44:22 +00:00
return AGI_RESULT_FAILURE ;
2001-09-28 13:19:43 +00:00
}
if ( ! pid ) {
2006-01-21 05:22:18 +00:00
/* Pass paths to AGI via environmental variables */
setenv ( " AST_CONFIG_DIR " , ast_config_AST_CONFIG_DIR , 1 ) ;
setenv ( " AST_CONFIG_FILE " , ast_config_AST_CONFIG_FILE , 1 ) ;
setenv ( " AST_MODULE_DIR " , ast_config_AST_MODULE_DIR , 1 ) ;
setenv ( " AST_SPOOL_DIR " , ast_config_AST_SPOOL_DIR , 1 ) ;
setenv ( " AST_MONITOR_DIR " , ast_config_AST_MONITOR_DIR , 1 ) ;
setenv ( " AST_VAR_DIR " , ast_config_AST_VAR_DIR , 1 ) ;
2006-04-15 22:53:53 +00:00
setenv ( " AST_DATA_DIR " , ast_config_AST_DATA_DIR , 1 ) ;
2006-01-21 05:22:18 +00:00
setenv ( " AST_LOG_DIR " , ast_config_AST_LOG_DIR , 1 ) ;
setenv ( " AST_AGI_DIR " , ast_config_AST_AGI_DIR , 1 ) ;
setenv ( " AST_KEY_DIR " , ast_config_AST_KEY_DIR , 1 ) ;
setenv ( " AST_RUN_DIR " , ast_config_AST_RUN_DIR , 1 ) ;
2006-06-12 15:30:32 +00:00
/* Don't run AGI scripts with realtime priority -- it causes audio stutter */
ast_set_priority ( 0 ) ;
2003-02-23 06:00:11 +00:00
/* Redirect stdin and out, provide enhanced audio channel if desired */
2001-09-28 13:19:43 +00:00
dup2 ( fromast [ 0 ] , STDIN_FILENO ) ;
dup2 ( toast [ 1 ] , STDOUT_FILENO ) ;
2007-07-11 21:09:42 +00:00
if ( efd )
2003-02-23 06:00:11 +00:00
dup2 ( audio [ 0 ] , STDERR_FILENO + 1 ) ;
2007-07-11 21:09:42 +00:00
else
2003-02-23 06:00:11 +00:00
close ( STDERR_FILENO + 1 ) ;
2006-12-11 00:52:19 +00:00
/* Before we unblock our signals, return our trapped signals back to the defaults */
signal ( SIGHUP , SIG_DFL ) ;
signal ( SIGCHLD , SIG_DFL ) ;
signal ( SIGINT , SIG_DFL ) ;
signal ( SIGURG , SIG_DFL ) ;
signal ( SIGTERM , SIG_DFL ) ;
signal ( SIGPIPE , SIG_DFL ) ;
signal ( SIGXFSZ , SIG_DFL ) ;
2005-08-03 04:17:12 +00:00
/* unblock important signal handlers */
2006-12-11 00:52:19 +00:00
if ( pthread_sigmask ( SIG_UNBLOCK , & signal_set , NULL ) ) {
2005-08-03 04:17:12 +00:00
ast_log ( LOG_WARNING , " unable to unblock signals for AGI script: %s \n " , strerror ( errno ) ) ;
2006-10-27 17:42:57 +00:00
_exit ( 1 ) ;
2005-08-03 04:17:12 +00:00
}
2001-09-28 13:19:43 +00:00
/* Close everything but stdin/out/error */
2007-07-11 21:09:42 +00:00
for ( x = STDERR_FILENO + 2 ; x < 1024 ; x + + )
2001-09-28 13:19:43 +00:00
close ( x ) ;
2005-08-03 04:17:12 +00:00
2001-09-28 13:19:43 +00:00
/* Execute script */
2006-10-17 23:06:13 +00:00
/* XXX argv should be deprecated in favor of passing agi_argX paramaters */
2004-03-23 12:50:15 +00:00
execv ( script , argv ) ;
2003-02-06 22:11:43 +00:00
/* Can't use ast_log since FD's are closed */
2006-02-01 20:40:45 +00:00
fprintf ( stdout , " verbose \" Failed to execute '%s': %s \" 2 \n " , script , strerror ( errno ) ) ;
fflush ( stdout ) ;
2006-10-27 17:42:57 +00:00
_exit ( 1 ) ;
2001-09-28 13:19:43 +00:00
}
2006-12-11 00:52:19 +00:00
pthread_sigmask ( SIG_SETMASK , & old_set , NULL ) ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Launched AGI Script %s \n " , script ) ;
2001-09-28 13:19:43 +00:00
fds [ 0 ] = toast [ 0 ] ;
fds [ 1 ] = fromast [ 1 ] ;
2007-07-11 21:09:42 +00:00
if ( efd )
2003-02-23 06:00:11 +00:00
* efd = audio [ 1 ] ;
2001-09-28 13:19:43 +00:00
/* close what we're not using in the parent */
close ( toast [ 1 ] ) ;
close ( fromast [ 0 ] ) ;
2003-12-27 23:39:57 +00:00
2006-05-25 16:44:22 +00:00
if ( efd )
2004-01-01 00:26:11 +00:00
close ( audio [ 0 ] ) ;
2003-12-27 23:39:57 +00:00
2001-09-28 13:19:43 +00:00
* opid = pid ;
2006-05-25 16:44:22 +00:00
return AGI_RESULT_SUCCESS ;
2001-09-28 13:19:43 +00:00
}
2006-10-17 23:06:13 +00:00
static void setup_env ( struct ast_channel * chan , char * request , int fd , int enhanced , int argc , char * argv [ ] )
2001-09-28 13:19:43 +00:00
{
2006-10-17 23:06:13 +00:00
int count ;
2001-09-28 13:19:43 +00:00
/* Print initial environment, with agi_request always being the first
thing */
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , fd , " agi_request: %s \n " , request ) ;
ast_agi_fdprintf ( chan , fd , " agi_channel: %s \n " , chan - > name ) ;
ast_agi_fdprintf ( chan , fd , " agi_language: %s \n " , chan - > language ) ;
ast_agi_fdprintf ( chan , fd , " agi_type: %s \n " , chan - > tech - > type ) ;
ast_agi_fdprintf ( chan , fd , " agi_uniqueid: %s \n " , chan - > uniqueid ) ;
2007-12-04 15:01:57 +00:00
ast_agi_fdprintf ( chan , fd , " agi_version: %s \n " , ASTERISK_VERSION ) ;
2001-09-28 13:19:43 +00:00
/* ANI/DNIS */
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , fd , " agi_callerid: %s \n " , S_OR ( chan - > cid . cid_num , " unknown " ) ) ;
ast_agi_fdprintf ( chan , fd , " agi_calleridname: %s \n " , S_OR ( chan - > cid . cid_name , " unknown " ) ) ;
ast_agi_fdprintf ( chan , fd , " agi_callingpres: %d \n " , chan - > cid . cid_pres ) ;
ast_agi_fdprintf ( chan , fd , " agi_callingani2: %d \n " , chan - > cid . cid_ani2 ) ;
ast_agi_fdprintf ( chan , fd , " agi_callington: %d \n " , chan - > cid . cid_ton ) ;
ast_agi_fdprintf ( chan , fd , " agi_callingtns: %d \n " , chan - > cid . cid_tns ) ;
ast_agi_fdprintf ( chan , fd , " agi_dnid: %s \n " , S_OR ( chan - > cid . cid_dnid , " unknown " ) ) ;
ast_agi_fdprintf ( chan , fd , " agi_rdnis: %s \n " , S_OR ( chan - > cid . cid_rdnis , " unknown " ) ) ;
2001-09-28 13:19:43 +00:00
/* Context information */
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , fd , " agi_context: %s \n " , chan - > context ) ;
ast_agi_fdprintf ( chan , fd , " agi_extension: %s \n " , chan - > exten ) ;
ast_agi_fdprintf ( chan , fd , " agi_priority: %d \n " , chan - > priority ) ;
ast_agi_fdprintf ( chan , fd , " agi_enhanced: %s \n " , enhanced ? " 1.0 " : " 0.0 " ) ;
2001-09-28 13:19:43 +00:00
2005-01-08 19:35:20 +00:00
/* User information */
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , fd , " agi_accountcode: %s \n " , chan - > accountcode ? chan - > accountcode : " " ) ;
2007-07-23 22:02:05 +00:00
2006-10-17 23:06:13 +00:00
/* Send any parameters to the fastagi server that have been passed via the agi application */
/* Agi application paramaters take the form of: AGI(/path/to/example/script|${EXTEN}) */
for ( count = 1 ; count < argc ; count + + )
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , fd , " agi_arg_%d: %s \n " , count , argv [ count ] ) ;
2006-10-17 23:06:13 +00:00
2001-09-28 13:19:43 +00:00
/* End with empty return */
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , fd , " \n " ) ;
2001-09-28 13:19:43 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_answer ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2002-06-14 15:50:42 +00:00
{
2007-07-11 21:09:42 +00:00
int res = 0 ;
/* Answer the channel */
if ( chan - > _state ! = AST_STATE_UP )
2002-06-14 15:50:42 +00:00
res = ast_answer ( chan ) ;
2007-07-11 21:09:42 +00:00
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2002-06-14 15:50:42 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_waitfordigit ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2001-09-28 13:19:43 +00:00
{
2007-07-11 21:09:42 +00:00
int res , to ;
2001-09-28 13:19:43 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
2005-04-27 01:42:33 +00:00
if ( sscanf ( argv [ 3 ] , " %d " , & to ) ! = 1 )
2001-09-28 13:19:43 +00:00
return RESULT_SHOWUSAGE ;
2003-02-23 06:00:11 +00:00
res = ast_waitfordigit_full ( chan , to , agi - > audio , agi - > ctrl ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2001-09-28 13:19:43 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_sendtext ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2001-09-28 13:19:43 +00:00
{
int res ;
2007-07-11 21:09:42 +00:00
2001-09-28 13:19:43 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2007-07-11 21:09:42 +00:00
2001-12-27 11:07:33 +00:00
/* At the moment, the parser (perhaps broken) returns with
the last argument PLUS the newline at the end of the input
buffer . This probably needs to be fixed , but I wont do that
because other stuff may break as a result . The right way
would probably be to strip off the trailing newline before
parsing , then here , add a newline at the end of the string
before sending it to ast_sendtext - - DUDE */
2001-09-28 13:19:43 +00:00
res = ast_sendtext ( chan , argv [ 2 ] ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2001-09-28 13:19:43 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_recvchar ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2001-12-27 11:07:33 +00:00
{
int res ;
2007-07-11 21:09:42 +00:00
2001-12-27 11:07:33 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2007-07-11 21:09:42 +00:00
2001-12-27 11:07:33 +00:00
res = ast_recvchar ( chan , atoi ( argv [ 2 ] ) ) ;
if ( res = = 0 ) {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d (timeout) \n " , res ) ;
2001-12-27 11:07:33 +00:00
return RESULT_SUCCESS ;
}
if ( res > 0 ) {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2001-12-27 11:07:33 +00:00
return RESULT_SUCCESS ;
}
else {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d (hangup) \n " , res ) ;
2001-12-27 11:07:33 +00:00
return RESULT_FAILURE ;
}
}
2005-06-21 01:16:18 +00:00
static int handle_recvtext ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
char * buf ;
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2007-07-11 21:09:42 +00:00
2005-06-21 01:16:18 +00:00
buf = ast_recvtext ( chan , atoi ( argv [ 2 ] ) ) ;
if ( buf ) {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 (%s) \n " , buf ) ;
2007-06-06 21:20:11 +00:00
ast_free ( buf ) ;
2005-06-21 01:16:18 +00:00
} else {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=-1 \n " ) ;
2005-06-21 01:16:18 +00:00
}
2005-07-11 20:40:02 +00:00
return RESULT_SUCCESS ;
2005-06-21 01:16:18 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_tddmode ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2001-12-27 11:07:33 +00:00
{
2007-07-11 21:09:42 +00:00
int res , x ;
2001-12-27 11:07:33 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2007-07-11 21:09:42 +00:00
2005-01-08 19:35:20 +00:00
if ( ! strncasecmp ( argv [ 2 ] , " on " , 2 ) )
x = 1 ;
else
x = 0 ;
if ( ! strncasecmp ( argv [ 2 ] , " mate " , 4 ) )
x = 2 ;
if ( ! strncasecmp ( argv [ 2 ] , " tdd " , 3 ) )
x = 1 ;
res = ast_channel_setoption ( chan , AST_OPTION_TDD , & x , sizeof ( char ) , 0 ) ;
2005-08-03 04:17:12 +00:00
if ( res ! = RESULT_SUCCESS )
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
2001-12-27 11:07:33 +00:00
else
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
2005-06-05 21:00:33 +00:00
return RESULT_SUCCESS ;
2001-12-27 11:07:33 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_sendimage ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2001-09-28 13:19:43 +00:00
{
int res ;
2007-07-11 21:09:42 +00:00
2001-09-28 13:19:43 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2007-07-11 21:09:42 +00:00
2001-09-28 13:19:43 +00:00
res = ast_send_image ( chan , argv [ 2 ] ) ;
2001-12-27 11:07:33 +00:00
if ( ! ast_check_hangup ( chan ) )
2001-09-28 13:19:43 +00:00
res = 0 ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2001-09-28 13:19:43 +00:00
}
2005-08-22 21:59:24 +00:00
static int handle_controlstreamfile ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
2007-07-11 21:09:42 +00:00
int res = 0 , skipms = 3000 ;
char * fwd = NULL , * rev = NULL , * pause = NULL , * stop = NULL ;
2005-08-22 21:59:24 +00:00
if ( argc < 5 | | argc > 9 )
return RESULT_SHOWUSAGE ;
if ( ! ast_strlen_zero ( argv [ 4 ] ) )
stop = argv [ 4 ] ;
else
stop = NULL ;
if ( ( argc > 5 ) & & ( sscanf ( argv [ 5 ] , " %d " , & skipms ) ! = 1 ) )
return RESULT_SHOWUSAGE ;
2006-10-31 06:15:12 +00:00
if ( argc > 6 & & ! ast_strlen_zero ( argv [ 6 ] ) )
2005-08-22 21:59:24 +00:00
fwd = argv [ 6 ] ;
else
fwd = " # " ;
2006-10-31 06:15:12 +00:00
if ( argc > 7 & & ! ast_strlen_zero ( argv [ 7 ] ) )
2005-08-22 21:59:24 +00:00
rev = argv [ 7 ] ;
else
rev = " * " ;
if ( argc > 8 & & ! ast_strlen_zero ( argv [ 8 ] ) )
pause = argv [ 8 ] ;
else
pause = NULL ;
2007-06-08 21:02:46 +00:00
res = ast_control_streamfile ( chan , argv [ 3 ] , fwd , rev , stop , pause , NULL , skipms , NULL ) ;
2005-08-22 21:59:24 +00:00
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2005-08-22 21:59:24 +00:00
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2005-08-22 21:59:24 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_streamfile ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2001-09-28 13:19:43 +00:00
{
2007-07-11 21:09:42 +00:00
int res , vres ;
struct ast_filestream * fs , * vfs ;
long sample_offset = 0 , max_length ;
2006-07-20 16:18:07 +00:00
char * edigits = " " ;
2003-02-06 22:11:43 +00:00
2006-04-06 16:17:04 +00:00
if ( argc < 4 | | argc > 5 )
2001-09-28 13:19:43 +00:00
return RESULT_SHOWUSAGE ;
2006-07-20 16:18:07 +00:00
if ( argv [ 3 ] )
edigits = argv [ 3 ] ;
2003-02-06 22:11:43 +00:00
if ( ( argc > 4 ) & & ( sscanf ( argv [ 4 ] , " %ld " , & sample_offset ) ! = 1 ) )
return RESULT_SHOWUSAGE ;
2007-07-11 21:09:42 +00:00
if ( ! ( fs = ast_openstream ( chan , argv [ 2 ] , chan - > language ) ) ) {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d endpos=%ld \n " , 0 , sample_offset ) ;
2004-12-31 21:52:56 +00:00
return RESULT_SUCCESS ;
2007-09-10 13:41:54 +00:00
}
if ( ( vfs = ast_openvstream ( chan , argv [ 2 ] , chan - > language ) ) )
ast_debug ( 1 , " Ooh, found a video stream, too \n " ) ;
2006-05-26 17:43:11 +00:00
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Playing '%s' (escape_digits=%s) (sample_offset %ld) \n " , argv [ 2 ] , edigits , sample_offset ) ;
2006-07-20 16:18:07 +00:00
2003-02-06 22:11:43 +00:00
ast_seekstream ( fs , 0 , SEEK_END ) ;
max_length = ast_tellstream ( fs ) ;
ast_seekstream ( fs , sample_offset , SEEK_SET ) ;
res = ast_applystream ( chan , fs ) ;
2006-05-26 17:43:11 +00:00
if ( vfs )
vres = ast_applystream ( chan , vfs ) ;
2007-06-22 15:03:32 +00:00
ast_playstream ( fs ) ;
2006-05-26 17:43:11 +00:00
if ( vfs )
2007-06-22 15:03:32 +00:00
ast_playstream ( vfs ) ;
2006-05-26 17:43:11 +00:00
2003-02-23 06:00:11 +00:00
res = ast_waitstream_full ( chan , argv [ 3 ] , agi - > audio , agi - > ctrl ) ;
2003-02-06 22:11:43 +00:00
/* this is to check for if ast_waitstream closed the stream, we probably are at
* the end of the stream , return that amount , else check for the amount */
2005-01-08 19:35:20 +00:00
sample_offset = ( chan - > stream ) ? ast_tellstream ( fs ) : max_length ;
2002-06-14 15:50:42 +00:00
ast_stopstream ( chan ) ;
2003-02-23 06:00:11 +00:00
if ( res = = 1 ) {
/* Stop this command, don't print a result line, as there is a new command */
return RESULT_SUCCESS ;
}
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d endpos=%ld \n " , res , sample_offset ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2001-09-28 13:19:43 +00:00
}
2004-11-16 03:37:07 +00:00
/* get option - really similar to the handle_streamfile, but with a timeout */
static int handle_getoption ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
2007-07-11 21:09:42 +00:00
int res , vres ;
struct ast_filestream * fs , * vfs ;
long sample_offset = 0 , max_length ;
2004-11-16 03:37:07 +00:00
int timeout = 0 ;
2006-07-20 16:18:07 +00:00
char * edigits = " " ;
2004-11-16 03:37:07 +00:00
if ( argc < 4 | | argc > 5 )
return RESULT_SHOWUSAGE ;
if ( argv [ 3 ] )
edigits = argv [ 3 ] ;
if ( argc = = 5 )
timeout = atoi ( argv [ 4 ] ) ;
else if ( chan - > pbx - > dtimeout ) {
/* by default dtimeout is set to 5sec */
2004-12-18 22:04:07 +00:00
timeout = chan - > pbx - > dtimeout * 1000 ; /* in msec */
2004-11-16 03:37:07 +00:00
}
2007-07-11 21:09:42 +00:00
if ( ! ( fs = ast_openstream ( chan , argv [ 2 ] , chan - > language ) ) ) {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d endpos=%ld \n " , 0 , sample_offset ) ;
2006-05-26 17:43:11 +00:00
ast_log ( LOG_WARNING , " Unable to open %s \n " , argv [ 2 ] ) ;
2005-03-26 05:33:48 +00:00
return RESULT_SUCCESS ;
2006-05-26 17:43:11 +00:00
}
2007-09-10 13:41:54 +00:00
if ( ( vfs = ast_openvstream ( chan , argv [ 2 ] , chan - > language ) ) )
ast_debug ( 1 , " Ooh, found a video stream, too \n " ) ;
2006-05-26 17:43:11 +00:00
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " Playing '%s' (escape_digits=%s) (timeout %d) \n " , argv [ 2 ] , edigits , timeout ) ;
2004-11-16 03:37:07 +00:00
2006-05-26 17:43:11 +00:00
ast_seekstream ( fs , 0 , SEEK_END ) ;
max_length = ast_tellstream ( fs ) ;
ast_seekstream ( fs , sample_offset , SEEK_SET ) ;
res = ast_applystream ( chan , fs ) ;
if ( vfs )
vres = ast_applystream ( chan , vfs ) ;
2007-06-22 15:03:32 +00:00
ast_playstream ( fs ) ;
2006-05-26 17:43:11 +00:00
if ( vfs )
2007-06-22 15:03:32 +00:00
ast_playstream ( vfs ) ;
2006-05-26 17:43:11 +00:00
res = ast_waitstream_full ( chan , argv [ 3 ] , agi - > audio , agi - > ctrl ) ;
/* this is to check for if ast_waitstream closed the stream, we probably are at
* the end of the stream , return that amount , else check for the amount */
sample_offset = ( chan - > stream ) ? ast_tellstream ( fs ) : max_length ;
ast_stopstream ( chan ) ;
if ( res = = 1 ) {
/* Stop this command, don't print a result line, as there is a new command */
return RESULT_SUCCESS ;
}
2004-11-16 03:37:07 +00:00
/* If the user didnt press a key, wait for digitTimeout*/
if ( res = = 0 ) {
res = ast_waitfordigit_full ( chan , timeout , agi - > audio , agi - > ctrl ) ;
/* Make sure the new result is in the escape digits of the GET OPTION */
if ( ! strchr ( edigits , res ) )
2006-05-26 17:43:11 +00:00
res = 0 ;
2004-11-16 03:37:07 +00:00
}
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d endpos=%ld \n " , res , sample_offset ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2004-11-16 03:37:07 +00:00
}
2004-05-15 15:34:31 +00:00
/*--- handle_saynumber: Say number in various language syntaxes ---*/
2006-11-04 01:40:49 +00:00
/* While waiting, we're sending a NULL. */
2003-02-23 06:00:11 +00:00
static int handle_saynumber ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2001-09-28 13:19:43 +00:00
{
2007-07-11 21:09:42 +00:00
int res , num ;
2007-05-11 16:16:50 +00:00
if ( argc < 4 | | argc > 5 )
2001-09-28 13:19:43 +00:00
return RESULT_SHOWUSAGE ;
2005-03-29 06:21:21 +00:00
if ( sscanf ( argv [ 2 ] , " %d " , & num ) ! = 1 )
2001-09-28 13:19:43 +00:00
return RESULT_SHOWUSAGE ;
2007-05-11 16:16:50 +00:00
res = ast_say_number_full ( chan , num , argv [ 3 ] , chan - > language , argc > 4 ? argv [ 4 ] : NULL , agi - > audio , agi - > ctrl ) ;
2003-02-23 06:00:11 +00:00
if ( res = = 1 )
return RESULT_SUCCESS ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2001-09-28 13:19:43 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_saydigits ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2002-06-14 15:50:42 +00:00
{
2007-07-11 21:09:42 +00:00
int res , num ;
2004-05-03 00:54:16 +00:00
2002-06-14 15:50:42 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
2005-04-27 01:42:33 +00:00
if ( sscanf ( argv [ 2 ] , " %d " , & num ) ! = 1 )
2002-06-14 15:50:42 +00:00
return RESULT_SHOWUSAGE ;
2004-05-03 00:54:16 +00:00
2003-02-23 06:00:11 +00:00
res = ast_say_digit_str_full ( chan , argv [ 2 ] , argv [ 3 ] , chan - > language , agi - > audio , agi - > ctrl ) ;
if ( res = = 1 ) /* New command */
return RESULT_SUCCESS ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2002-06-14 15:50:42 +00:00
}
2004-12-14 18:39:25 +00:00
static int handle_sayalpha ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
int res ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
res = ast_say_character_str_full ( chan , argv [ 2 ] , argv [ 3 ] , chan - > language , agi - > audio , agi - > ctrl ) ;
if ( res = = 1 ) /* New command */
return RESULT_SUCCESS ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2004-12-14 18:39:25 +00:00
}
2005-03-30 07:00:49 +00:00
static int handle_saydate ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
2007-07-11 21:09:42 +00:00
int res , num ;
2005-03-30 07:00:49 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
2005-04-27 01:42:33 +00:00
if ( sscanf ( argv [ 2 ] , " %d " , & num ) ! = 1 )
2005-03-30 07:00:49 +00:00
return RESULT_SHOWUSAGE ;
res = ast_say_date ( chan , num , argv [ 3 ] , chan - > language ) ;
if ( res = = 1 )
return RESULT_SUCCESS ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2005-03-30 07:00:49 +00:00
}
2004-02-27 08:30:30 +00:00
static int handle_saytime ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
2007-07-11 21:09:42 +00:00
int res , num ;
2004-02-27 08:30:30 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
2005-04-27 01:42:33 +00:00
if ( sscanf ( argv [ 2 ] , " %d " , & num ) ! = 1 )
2004-02-27 08:30:30 +00:00
return RESULT_SHOWUSAGE ;
res = ast_say_time ( chan , num , argv [ 3 ] , chan - > language ) ;
if ( res = = 1 )
return RESULT_SUCCESS ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-02-15 00:24:24 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2004-02-27 08:30:30 +00:00
}
2005-04-11 03:23:54 +00:00
static int handle_saydatetime ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
2007-07-11 21:09:42 +00:00
int res = 0 ;
2006-02-15 00:24:24 +00:00
time_t unixtime ;
2007-07-11 21:09:42 +00:00
char * format , * zone = NULL ;
2005-04-11 03:23:54 +00:00
if ( argc < 4 )
return RESULT_SHOWUSAGE ;
if ( argc > 4 ) {
format = argv [ 4 ] ;
} else {
2006-04-06 16:17:04 +00:00
/* XXX this doesn't belong here, but in the 'say' module */
2005-04-11 03:23:54 +00:00
if ( ! strcasecmp ( chan - > language , " de " ) ) {
format = " A dBY HMS " ;
} else {
format = " ABdY 'digits/at' IMp " ;
}
}
if ( argc > 5 & & ! ast_strlen_zero ( argv [ 5 ] ) )
zone = argv [ 5 ] ;
2006-02-23 17:13:57 +00:00
if ( ast_get_time_t ( argv [ 2 ] , & unixtime , 0 , NULL ) )
2005-04-11 03:23:54 +00:00
return RESULT_SHOWUSAGE ;
2006-02-15 00:24:24 +00:00
res = ast_say_date_with_format ( chan , unixtime , argv [ 3 ] , chan - > language , format , zone ) ;
2005-04-11 03:23:54 +00:00
if ( res = = 1 )
return RESULT_SUCCESS ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-02-15 00:24:24 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2005-04-11 03:23:54 +00:00
}
2004-05-03 00:54:16 +00:00
static int handle_sayphonetic ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
int res ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
res = ast_say_phonetic_str_full ( chan , argv [ 2 ] , argv [ 3 ] , chan - > language , agi - > audio , agi - > ctrl ) ;
if ( res = = 1 ) /* New command */
return RESULT_SUCCESS ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2006-04-06 16:17:04 +00:00
return ( res > = 0 ) ? RESULT_SUCCESS : RESULT_FAILURE ;
2004-05-03 00:54:16 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_getdata ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2001-09-28 13:19:43 +00:00
{
2007-07-11 21:09:42 +00:00
int res , max , timeout ;
2003-02-14 06:00:11 +00:00
char data [ 1024 ] ;
2001-09-28 13:19:43 +00:00
if ( argc < 3 )
return RESULT_SHOWUSAGE ;
2005-01-08 19:35:20 +00:00
if ( argc > = 4 )
timeout = atoi ( argv [ 3 ] ) ;
else
timeout = 0 ;
if ( argc > = 5 )
max = atoi ( argv [ 4 ] ) ;
else
max = 1024 ;
2003-02-23 06:00:11 +00:00
res = ast_app_getdata_full ( chan , argv [ 2 ] , data , max , timeout , agi - > audio , agi - > ctrl ) ;
if ( res = = 2 ) /* New command */
return RESULT_SUCCESS ;
else if ( res = = 1 )
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%s (timeout) \n " , data ) ;
2004-06-04 19:01:07 +00:00
else if ( res < 0 )
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=-1 \n " ) ;
2001-09-28 13:19:43 +00:00
else
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%s \n " , data ) ;
2005-03-28 07:08:39 +00:00
return RESULT_SUCCESS ;
2001-09-28 13:19:43 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_setcontext ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2001-09-28 13:19:43 +00:00
{
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2005-07-10 23:21:39 +00:00
ast_copy_string ( chan - > context , argv [ 2 ] , sizeof ( chan - > context ) ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
2001-09-28 13:19:43 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_setextension ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2001-09-28 13:19:43 +00:00
{
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2005-07-10 23:21:39 +00:00
ast_copy_string ( chan - > exten , argv [ 2 ] , sizeof ( chan - > exten ) ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
2001-09-28 13:19:43 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_setpriority ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2001-09-28 13:19:43 +00:00
{
int pri ;
2007-07-11 21:09:42 +00:00
2001-09-28 13:19:43 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2005-05-19 02:57:45 +00:00
if ( sscanf ( argv [ 2 ] , " %d " , & pri ) ! = 1 ) {
if ( ( pri = ast_findlabel_extension ( chan , chan - > context , chan - > exten , argv [ 2 ] , chan - > cid . cid_num ) ) < 1 )
return RESULT_SHOWUSAGE ;
}
ast_explicit_goto ( chan , NULL , NULL , pri ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
2001-09-28 13:19:43 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_recordfile ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2001-09-28 13:19:43 +00:00
{
struct ast_filestream * fs ;
2002-09-04 16:53:39 +00:00
struct ast_frame * f ;
2005-07-15 23:00:47 +00:00
struct timeval start ;
2003-02-06 22:11:43 +00:00
long sample_offset = 0 ;
2002-09-04 16:53:39 +00:00
int res = 0 ;
int ms ;
2001-09-28 13:19:43 +00:00
2007-07-23 22:02:05 +00:00
struct ast_dsp * sildet = NULL ; /* silence detector dsp */
int totalsilence = 0 ;
int dspsilence = 0 ;
int silence = 0 ; /* amount of silence to allow */
int gotsilence = 0 ; /* did we timeout for silence? */
char * silencestr = NULL ;
int rfmt = 0 ;
2003-05-01 03:52:45 +00:00
2003-02-23 06:00:11 +00:00
/* XXX EAGI FIXME XXX */
2001-09-28 13:19:43 +00:00
if ( argc < 6 )
return RESULT_SHOWUSAGE ;
2005-04-27 01:42:33 +00:00
if ( sscanf ( argv [ 5 ] , " %d " , & ms ) ! = 1 )
2001-09-28 13:19:43 +00:00
return RESULT_SHOWUSAGE ;
2003-05-01 03:52:45 +00:00
if ( argc > 6 )
silencestr = strchr ( argv [ 6 ] , ' s ' ) ;
if ( ( argc > 7 ) & & ( ! silencestr ) )
silencestr = strchr ( argv [ 7 ] , ' s ' ) ;
if ( ( argc > 8 ) & & ( ! silencestr ) )
silencestr = strchr ( argv [ 8 ] , ' s ' ) ;
if ( silencestr ) {
if ( strlen ( silencestr ) > 2 ) {
if ( ( silencestr [ 0 ] = = ' s ' ) & & ( silencestr [ 1 ] = = ' = ' ) ) {
silencestr + + ;
silencestr + + ;
if ( silencestr )
2007-07-23 22:02:05 +00:00
silence = atoi ( silencestr ) ;
if ( silence > 0 )
silence * = 1000 ;
}
2003-05-01 03:52:45 +00:00
}
}
2007-07-23 22:02:05 +00:00
if ( silence > 0 ) {
rfmt = chan - > readformat ;
res = ast_set_read_format ( chan , AST_FORMAT_SLINEAR ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " Unable to set to linear mode, giving up \n " ) ;
return - 1 ;
}
sildet = ast_dsp_new ( ) ;
if ( ! sildet ) {
ast_log ( LOG_WARNING , " Unable to create silence detector :( \n " ) ;
return - 1 ;
}
ast_dsp_set_threshold ( sildet , 256 ) ;
}
2003-05-01 03:52:45 +00:00
2003-02-06 22:11:43 +00:00
/* backward compatibility, if no offset given, arg[6] would have been
* caught below and taken to be a beep , else if it is a digit then it is a
* offset */
2003-05-01 03:52:45 +00:00
if ( ( argc > 6 ) & & ( sscanf ( argv [ 6 ] , " %ld " , & sample_offset ) ! = 1 ) & & ( ! strchr ( argv [ 6 ] , ' = ' ) ) )
2003-02-06 22:11:43 +00:00
res = ast_streamfile ( chan , " beep " , chan - > language ) ;
2001-09-28 13:19:43 +00:00
2003-05-01 03:52:45 +00:00
if ( ( argc > 7 ) & & ( ! strchr ( argv [ 7 ] , ' = ' ) ) )
2002-09-04 16:53:39 +00:00
res = ast_streamfile ( chan , " beep " , chan - > language ) ;
2003-05-01 03:52:45 +00:00
2002-09-04 16:53:39 +00:00
if ( ! res )
res = ast_waitstream ( chan , argv [ 4 ] ) ;
2005-07-15 23:00:47 +00:00
if ( res ) {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d (randomerror) endpos=%ld \n " , res , sample_offset ) ;
2005-07-15 23:00:47 +00:00
} else {
2006-12-21 19:44:20 +00:00
fs = ast_writefile ( argv [ 2 ] , argv [ 3 ] , NULL , O_CREAT | O_WRONLY | ( sample_offset ? O_APPEND : 0 ) , 0 , AST_FILE_MODE ) ;
2002-09-04 16:53:39 +00:00
if ( ! fs ) {
res = - 1 ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d (writefile) \n " , res ) ;
2004-03-10 21:17:13 +00:00
if ( sildet )
ast_dsp_free ( sildet ) ;
2002-09-04 16:53:39 +00:00
return RESULT_FAILURE ;
}
2003-02-06 22:11:43 +00:00
2006-05-24 17:02:54 +00:00
/* Request a video update */
ast_indicate ( chan , AST_CONTROL_VIDUPDATE ) ;
2003-02-06 22:11:43 +00:00
chan - > stream = fs ;
ast_applystream ( chan , fs ) ;
/* really should have checks */
ast_seekstream ( fs , sample_offset , SEEK_SET ) ;
ast_truncstream ( fs ) ;
2005-07-15 23:00:47 +00:00
start = ast_tvnow ( ) ;
while ( ( ms < 0 ) | | ast_tvdiff_ms ( ast_tvnow ( ) , start ) < ms ) {
2002-09-04 16:53:39 +00:00
res = ast_waitfor ( chan , - 1 ) ;
if ( res < 0 ) {
ast_closestream ( fs ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d (waitfor) endpos=%ld \n " , res , sample_offset ) ;
2004-03-10 21:17:13 +00:00
if ( sildet )
ast_dsp_free ( sildet ) ;
2001-09-28 13:19:43 +00:00
return RESULT_FAILURE ;
}
f = ast_read ( chan ) ;
if ( ! f ) {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d (hangup) endpos=%ld \n " , 0 , sample_offset ) ;
2002-09-04 16:53:39 +00:00
ast_closestream ( fs ) ;
2004-03-10 21:17:13 +00:00
if ( sildet )
ast_dsp_free ( sildet ) ;
2001-09-28 13:19:43 +00:00
return RESULT_FAILURE ;
}
switch ( f - > frametype ) {
case AST_FRAME_DTMF :
if ( strchr ( argv [ 4 ] , f - > subclass ) ) {
2005-10-04 22:35:43 +00:00
/* This is an interrupting chracter, so rewind to chop off any small
amount of DTMF that may have been recorded
*/
ast_stream_rewind ( fs , 200 ) ;
ast_truncstream ( fs ) ;
2003-02-06 22:11:43 +00:00
sample_offset = ast_tellstream ( fs ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d (dtmf) endpos=%ld \n " , f - > subclass , sample_offset ) ;
2002-09-04 16:53:39 +00:00
ast_closestream ( fs ) ;
2001-09-28 13:19:43 +00:00
ast_frfree ( f ) ;
2004-03-10 21:17:13 +00:00
if ( sildet )
ast_dsp_free ( sildet ) ;
2001-09-28 13:19:43 +00:00
return RESULT_SUCCESS ;
}
break ;
case AST_FRAME_VOICE :
2002-09-04 16:53:39 +00:00
ast_writestream ( fs , f ) ;
2003-02-06 22:11:43 +00:00
/* this is a safe place to check progress since we know that fs
* is valid after a write , and it will then have our current
* location */
sample_offset = ast_tellstream ( fs ) ;
2007-07-23 22:02:05 +00:00
if ( silence > 0 ) {
dspsilence = 0 ;
ast_dsp_silence ( sildet , f , & dspsilence ) ;
if ( dspsilence ) {
totalsilence = dspsilence ;
} else {
totalsilence = 0 ;
}
if ( totalsilence > silence ) {
/* Ended happily with silence */
gotsilence = 1 ;
break ;
}
}
2001-09-28 13:19:43 +00:00
break ;
2006-05-24 17:02:54 +00:00
case AST_FRAME_VIDEO :
ast_writestream ( fs , f ) ;
2006-08-31 01:59:02 +00:00
default :
/* Ignore all other frames */
2006-05-24 17:02:54 +00:00
break ;
2001-09-28 13:19:43 +00:00
}
ast_frfree ( f ) ;
2003-05-01 03:52:45 +00:00
if ( gotsilence )
break ;
2007-07-23 22:02:05 +00:00
}
2003-05-01 03:52:45 +00:00
2007-07-30 19:11:28 +00:00
if ( gotsilence ) {
ast_stream_rewind ( fs , silence - 1000 ) ;
ast_truncstream ( fs ) ;
sample_offset = ast_tellstream ( fs ) ;
2003-05-01 03:52:45 +00:00
}
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d (timeout) endpos=%ld \n " , res , sample_offset ) ;
2002-09-04 16:53:39 +00:00
ast_closestream ( fs ) ;
2005-07-15 23:00:47 +00:00
}
2003-05-01 03:52:45 +00:00
2007-07-23 22:02:05 +00:00
if ( silence > 0 ) {
res = ast_set_read_format ( chan , rfmt ) ;
if ( res )
ast_log ( LOG_WARNING , " Unable to restore read format on '%s' \n " , chan - > name ) ;
ast_dsp_free ( sildet ) ;
}
2002-09-04 16:53:39 +00:00
return RESULT_SUCCESS ;
}
2001-09-28 13:19:43 +00:00
2003-02-23 06:00:11 +00:00
static int handle_autohangup ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
2002-09-04 16:53:39 +00:00
{
int timeout ;
2001-09-28 13:19:43 +00:00
2002-09-04 16:53:39 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
if ( sscanf ( argv [ 2 ] , " %d " , & timeout ) ! = 1 )
return RESULT_SHOWUSAGE ;
if ( timeout < 0 )
timeout = 0 ;
if ( timeout )
chan - > whentohangup = time ( NULL ) + timeout ;
else
chan - > whentohangup = 0 ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
2002-09-04 16:53:39 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_hangup ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2002-09-04 16:53:39 +00:00
{
2005-01-08 19:35:20 +00:00
struct ast_channel * c ;
2007-07-11 21:09:42 +00:00
2005-01-08 19:35:20 +00:00
if ( argc = = 1 ) {
/* no argument: hangup the current channel */
ast_softhangup ( chan , AST_SOFTHANGUP_EXPLICIT ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
2005-01-08 19:35:20 +00:00
return RESULT_SUCCESS ;
2005-06-06 02:29:18 +00:00
} else if ( argc = = 2 ) {
2005-01-08 19:35:20 +00:00
/* one argument: look for info on the specified channel */
2005-06-06 02:29:18 +00:00
c = ast_get_channel_by_name_locked ( argv [ 1 ] ) ;
if ( c ) {
/* we have a matching channel */
ast_softhangup ( c , AST_SOFTHANGUP_EXPLICIT ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
2006-04-29 14:50:18 +00:00
ast_channel_unlock ( c ) ;
2005-06-06 02:29:18 +00:00
return RESULT_SUCCESS ;
2005-01-08 19:35:20 +00:00
}
/* if we get this far no channel name matched the argument given */
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=-1 \n " ) ;
2005-01-08 19:35:20 +00:00
return RESULT_SUCCESS ;
} else {
return RESULT_SHOWUSAGE ;
}
2002-09-04 16:53:39 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_exec ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2002-09-04 16:53:39 +00:00
{
int res ;
struct ast_app * app ;
if ( argc < 2 )
return RESULT_SHOWUSAGE ;
2007-07-26 15:49:18 +00:00
ast_verb ( 3 , " AGI Script Executing Application: (%s) Options: (%s) \n " , argv [ 1 ] , argv [ 2 ] ) ;
2002-09-04 16:53:39 +00:00
2007-07-11 21:09:42 +00:00
if ( ( app = pbx_findapp ( argv [ 1 ] ) ) ) {
2006-03-30 21:29:39 +00:00
res = pbx_exec ( chan , app , argv [ 2 ] ) ;
2002-09-04 16:53:39 +00:00
} else {
ast_log ( LOG_WARNING , " Could not find application (%s) \n " , argv [ 1 ] ) ;
res = - 2 ;
2001-09-28 13:19:43 +00:00
}
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , res ) ;
2002-09-04 16:53:39 +00:00
2007-07-30 18:45:09 +00:00
/* Even though this is wrong, users are depending upon this result. */
return res ;
2002-09-04 16:53:39 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_setcallerid ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2002-09-04 16:53:39 +00:00
{
2004-10-02 00:58:31 +00:00
char tmp [ 256 ] = " " ;
char * l = NULL , * n = NULL ;
2005-01-08 19:35:20 +00:00
2004-10-02 00:58:31 +00:00
if ( argv [ 2 ] ) {
2005-07-10 23:21:39 +00:00
ast_copy_string ( tmp , argv [ 2 ] , sizeof ( tmp ) ) ;
2004-10-02 00:58:31 +00:00
ast_callerid_parse ( tmp , & n , & l ) ;
if ( l )
ast_shrink_phone_number ( l ) ;
else
l = " " ;
if ( ! n )
n = " " ;
ast_set_callerid ( chan , l , n , NULL ) ;
}
2002-09-04 16:53:39 +00:00
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
2001-09-28 13:19:43 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_channelstatus ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2002-09-04 16:53:39 +00:00
{
2004-06-04 19:01:07 +00:00
struct ast_channel * c ;
2005-01-08 19:35:20 +00:00
if ( argc = = 2 ) {
2004-06-04 19:01:07 +00:00
/* no argument: supply info on the current channel */
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , chan - > _state ) ;
2004-06-04 19:01:07 +00:00
return RESULT_SUCCESS ;
2005-01-08 19:35:20 +00:00
} else if ( argc = = 3 ) {
2004-06-04 19:01:07 +00:00
/* one argument: look for info on the specified channel */
2005-06-06 02:29:18 +00:00
c = ast_get_channel_by_name_locked ( argv [ 2 ] ) ;
if ( c ) {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%d \n " , c - > _state ) ;
2006-04-29 14:50:18 +00:00
ast_channel_unlock ( c ) ;
2005-06-06 02:29:18 +00:00
return RESULT_SUCCESS ;
2004-06-04 19:01:07 +00:00
}
/* if we get this far no channel name matched the argument given */
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=-1 \n " ) ;
2004-06-04 19:01:07 +00:00
return RESULT_SUCCESS ;
} else {
return RESULT_SHOWUSAGE ;
}
2003-02-06 22:11:43 +00:00
}
2003-02-23 06:00:11 +00:00
static int handle_setvariable ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2003-02-06 22:11:43 +00:00
{
if ( argv [ 3 ] )
pbx_builtin_setvar_helper ( chan , argv [ 2 ] , argv [ 3 ] ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
2003-02-06 22:11:43 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_getvariable ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2003-02-06 22:11:43 +00:00
{
2006-08-23 16:14:18 +00:00
char * ret ;
2004-12-23 02:47:01 +00:00
char tempstr [ 1024 ] ;
2005-01-08 19:35:20 +00:00
2004-11-17 04:02:56 +00:00
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
2005-08-22 23:00:23 +00:00
/* check if we want to execute an ast_custom_function */
2006-08-23 16:14:18 +00:00
if ( ! ast_strlen_zero ( argv [ 2 ] ) & & ( argv [ 2 ] [ strlen ( argv [ 2 ] ) - 1 ] = = ' ) ' ) ) {
2006-02-12 04:28:58 +00:00
ret = ast_func_read ( chan , argv [ 2 ] , tempstr , sizeof ( tempstr ) ) ? NULL : tempstr ;
2006-08-23 16:14:18 +00:00
} else {
pbx_retrieve_variable ( chan , argv [ 2 ] , & ret , tempstr , sizeof ( tempstr ) , NULL ) ;
}
2005-08-22 23:00:23 +00:00
2004-12-23 02:47:01 +00:00
if ( ret )
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 (%s) \n " , ret ) ;
2003-02-06 22:11:43 +00:00
else
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
2003-02-06 22:11:43 +00:00
return RESULT_SUCCESS ;
}
2004-11-17 04:02:56 +00:00
static int handle_getvariablefull ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
{
This commits the performance mods that give the priority processing engine in the pbx, a 25-30% speed boost. The two updates used, are, first, to merge the ast_exists_extension() and the ast_spawn_extension() where they are called sequentially in a loop in the code, into a slightly upgraded version of ast_spawn_extension(), with a few extra args; and, second, I modified the substitute_variables_helper_full, so it zeroes out the byte after the evaluated string instead of demanding you pre-zero the buffer; I also went thru the code and removed the code that zeroed this buffer before every call to the substitute_variables_helper_full. The first fix provides about a 9% speedup, and the second the rest. These figures come from the 'PIPS' benchmark I describe in blogs, conf. reports, etc.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@88166 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-11-01 22:26:51 +00:00
char tmp [ 4096 ] ;
2004-11-17 04:02:56 +00:00
struct ast_channel * chan2 = NULL ;
2005-01-08 19:35:20 +00:00
2004-11-17 04:02:56 +00:00
if ( ( argc ! = 4 ) & & ( argc ! = 5 ) )
return RESULT_SHOWUSAGE ;
if ( argc = = 5 ) {
2005-06-06 02:29:18 +00:00
chan2 = ast_get_channel_by_name_locked ( argv [ 4 ] ) ;
2004-11-17 04:02:56 +00:00
} else {
chan2 = chan ;
}
2007-09-12 21:57:30 +00:00
if ( chan2 ) {
2004-11-17 04:02:56 +00:00
pbx_substitute_variables_helper ( chan2 , argv [ 3 ] , tmp , sizeof ( tmp ) - 1 ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 (%s) \n " , tmp ) ;
2004-11-17 04:02:56 +00:00
} else {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
2004-11-17 04:02:56 +00:00
}
if ( chan2 & & ( chan2 ! = chan ) )
2006-04-29 14:50:18 +00:00
ast_channel_unlock ( chan2 ) ;
2004-11-17 04:02:56 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_verbose ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2003-02-06 22:11:43 +00:00
{
int level = 0 ;
char * prefix ;
if ( argc < 2 )
return RESULT_SHOWUSAGE ;
if ( argv [ 2 ] )
sscanf ( argv [ 2 ] , " %d " , & level ) ;
switch ( level ) {
case 4 :
prefix = VERBOSE_PREFIX_4 ;
break ;
case 3 :
prefix = VERBOSE_PREFIX_3 ;
break ;
case 2 :
prefix = VERBOSE_PREFIX_2 ;
break ;
case 1 :
default :
prefix = VERBOSE_PREFIX_1 ;
break ;
}
if ( level < = option_verbose )
ast_verbose ( " %s %s: %s \n " , prefix , chan - > data , argv [ 1 ] ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
2003-02-06 22:11:43 +00:00
2002-09-04 16:53:39 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_dbget ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2003-02-06 22:11:43 +00:00
{
int res ;
char tmp [ 256 ] ;
2005-01-08 19:35:20 +00:00
2003-02-06 22:11:43 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
res = ast_db_get ( argv [ 2 ] , argv [ 3 ] , tmp , sizeof ( tmp ) ) ;
if ( res )
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
2003-02-06 22:11:43 +00:00
else
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 (%s) \n " , tmp ) ;
2003-02-06 22:11:43 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_dbput ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2003-02-06 22:11:43 +00:00
{
int res ;
2005-01-08 19:35:20 +00:00
2003-02-06 22:11:43 +00:00
if ( argc ! = 5 )
return RESULT_SHOWUSAGE ;
res = ast_db_put ( argv [ 2 ] , argv [ 3 ] , argv [ 4 ] ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%c \n " , res ? ' 0 ' : ' 1 ' ) ;
2003-02-06 22:11:43 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_dbdel ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2003-02-06 22:11:43 +00:00
{
int res ;
2005-01-08 19:35:20 +00:00
2003-02-06 22:11:43 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
res = ast_db_del ( argv [ 2 ] , argv [ 3 ] ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%c \n " , res ? ' 0 ' : ' 1 ' ) ;
2003-02-06 22:11:43 +00:00
return RESULT_SUCCESS ;
}
2003-02-23 06:00:11 +00:00
static int handle_dbdeltree ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2003-02-06 22:11:43 +00:00
{
int res ;
2007-07-11 21:09:42 +00:00
2003-02-06 22:11:43 +00:00
if ( ( argc < 3 ) | | ( argc > 4 ) )
return RESULT_SHOWUSAGE ;
if ( argc = = 4 )
res = ast_db_deltree ( argv [ 2 ] , argv [ 3 ] ) ;
else
res = ast_db_deltree ( argv [ 2 ] , NULL ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=%c \n " , res ? ' 0 ' : ' 1 ' ) ;
2003-02-23 06:00:11 +00:00
return RESULT_SUCCESS ;
}
2007-09-18 22:43:45 +00:00
static char * handle_cli_agi_debug ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2004-09-25 14:22:27 +00:00
{
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " agi debug [off] " ;
e - > usage =
" Usage: agi debug [off] \n "
" Enables/disables dumping of AGI transactions for \n "
" debugging purposes. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
if ( a - > argc < e - > args - 1 | | a - > argc > e - > args )
return CLI_SHOWUSAGE ;
if ( a - > argc = = e - > args - 1 ) {
agidebug = 1 ;
} else {
if ( strncasecmp ( a - > argv [ e - > args - 1 ] , " off " , 3 ) = = 0 ) {
agidebug = 0 ;
} else {
return CLI_SHOWUSAGE ;
}
}
ast_cli ( a - > fd , " AGI Debugging %sabled \n " , agidebug ? " En " : " Dis " ) ;
return CLI_SUCCESS ;
2006-09-18 19:54:18 +00:00
}
2004-09-25 14:22:27 +00:00
2003-02-23 06:00:11 +00:00
static int handle_noop ( struct ast_channel * chan , AGI * agi , int arg , char * argv [ ] )
{
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
2003-02-06 22:11:43 +00:00
return RESULT_SUCCESS ;
}
2003-06-11 12:17:43 +00:00
static int handle_setmusic ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
2006-04-06 16:17:04 +00:00
if ( ! strncasecmp ( argv [ 2 ] , " on " , 2 ) )
2006-07-19 20:44:39 +00:00
ast_moh_start ( chan , argc > 3 ? argv [ 3 ] : NULL , NULL ) ;
2006-04-06 16:17:04 +00:00
else if ( ! strncasecmp ( argv [ 2 ] , " off " , 3 ) )
2003-06-11 12:17:43 +00:00
ast_moh_stop ( chan ) ;
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
2003-06-11 12:17:43 +00:00
return RESULT_SUCCESS ;
}
2007-12-03 21:03:05 +00:00
static int handle_speechcreate ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
{
/* If a structure already exists, return an error */
if ( agi - > speech ) {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
return RESULT_SUCCESS ;
}
if ( ( agi - > speech = ast_speech_new ( argv [ 2 ] , AST_FORMAT_SLINEAR ) ) )
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
else
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
return RESULT_SUCCESS ;
}
static int handle_speechset ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
{
/* Check for minimum arguments */
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
/* Check to make sure speech structure exists */
if ( ! agi - > speech ) {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
return RESULT_SUCCESS ;
}
ast_speech_change ( agi - > speech , argv [ 2 ] , argv [ 3 ] ) ;
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
return RESULT_SUCCESS ;
}
static int handle_speechdestroy ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
{
if ( agi - > speech ) {
ast_speech_destroy ( agi - > speech ) ;
agi - > speech = NULL ;
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
} else {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
}
return RESULT_SUCCESS ;
}
static int handle_speechloadgrammar ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
{
if ( argc ! = 5 )
return RESULT_SHOWUSAGE ;
if ( ! agi - > speech ) {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
return RESULT_SUCCESS ;
}
if ( ast_speech_grammar_load ( agi - > speech , argv [ 3 ] , argv [ 4 ] ) )
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
else
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
return RESULT_SUCCESS ;
}
static int handle_speechunloadgrammar ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
{
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
if ( ! agi - > speech ) {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
return RESULT_SUCCESS ;
}
if ( ast_speech_grammar_unload ( agi - > speech , argv [ 3 ] ) )
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
else
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
return RESULT_SUCCESS ;
}
static int handle_speechactivategrammar ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
{
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
if ( ! agi - > speech ) {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
return RESULT_SUCCESS ;
}
if ( ast_speech_grammar_activate ( agi - > speech , argv [ 3 ] ) )
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
else
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
return RESULT_SUCCESS ;
}
static int handle_speechdeactivategrammar ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
{
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
if ( ! agi - > speech ) {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
return RESULT_SUCCESS ;
}
if ( ast_speech_grammar_deactivate ( agi - > speech , argv [ 3 ] ) )
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
else
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 \n " ) ;
return RESULT_SUCCESS ;
}
static int speech_streamfile ( struct ast_channel * chan , const char * filename , const char * preflang , int offset )
{
struct ast_filestream * fs = NULL ;
if ( ! ( fs = ast_openstream ( chan , filename , preflang ) ) )
return - 1 ;
if ( offset )
ast_seekstream ( fs , offset , SEEK_SET ) ;
if ( ast_applystream ( chan , fs ) )
return - 1 ;
if ( ast_playstream ( fs ) )
return - 1 ;
return 0 ;
}
static int handle_speechrecognize ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
{
struct ast_speech * speech = agi - > speech ;
char * prompt , dtmf = 0 , tmp [ 4096 ] = " " , * buf = tmp ;
int timeout = 0 , offset = 0 , old_read_format = 0 , res = 0 , i = 0 ;
long current_offset = 0 ;
const char * reason = NULL ;
struct ast_frame * fr = NULL ;
struct ast_speech_result * result = NULL ;
size_t left = sizeof ( tmp ) ;
time_t start = 0 , current ;
if ( argc < 4 )
return RESULT_SHOWUSAGE ;
if ( ! speech ) {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
return RESULT_SUCCESS ;
}
prompt = argv [ 2 ] ;
timeout = atoi ( argv [ 3 ] ) ;
/* If offset is specified then convert from text to integer */
if ( argc = = 5 )
offset = atoi ( argv [ 4 ] ) ;
/* We want frames coming in signed linear */
old_read_format = chan - > readformat ;
if ( ast_set_read_format ( chan , AST_FORMAT_SLINEAR ) ) {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 \n " ) ;
return RESULT_SUCCESS ;
}
/* Setup speech structure */
if ( speech - > state = = AST_SPEECH_STATE_NOT_READY | | speech - > state = = AST_SPEECH_STATE_DONE ) {
ast_speech_change_state ( speech , AST_SPEECH_STATE_NOT_READY ) ;
ast_speech_start ( speech ) ;
}
/* Start playing prompt */
speech_streamfile ( chan , prompt , chan - > language , offset ) ;
/* Go into loop reading in frames, passing to speech thingy, checking for hangup, all that jazz */
while ( ast_strlen_zero ( reason ) ) {
/* Run scheduled items */
ast_sched_runq ( chan - > sched ) ;
/* See maximum time of waiting */
if ( ( res = ast_sched_wait ( chan - > sched ) ) < 0 )
res = 1000 ;
/* Wait for frame */
if ( ast_waitfor ( chan , res ) > 0 ) {
if ( ! ( fr = ast_read ( chan ) ) ) {
reason = " hangup " ;
break ;
}
}
/* Perform timeout check */
if ( ( timeout > 0 ) & & ( start > 0 ) ) {
time ( & current ) ;
if ( ( current - start ) > = timeout ) {
reason = " timeout " ;
if ( fr )
ast_frfree ( fr ) ;
break ;
}
}
/* Check the speech structure for any changes */
ast_mutex_lock ( & speech - > lock ) ;
/* See if we need to quiet the audio stream playback */
if ( ast_test_flag ( speech , AST_SPEECH_QUIET ) & & chan - > stream ) {
current_offset = ast_tellstream ( chan - > stream ) ;
ast_stopstream ( chan ) ;
ast_clear_flag ( speech , AST_SPEECH_QUIET ) ;
}
/* Check each state */
switch ( speech - > state ) {
case AST_SPEECH_STATE_READY :
/* If the stream is done, start timeout calculation */
if ( ( timeout > 0 ) & & ( ( ! chan - > stream ) | | ( chan - > streamid = = - 1 & & chan - > timingfunc = = NULL ) ) ) {
ast_stopstream ( chan ) ;
time ( & start ) ;
}
/* Write audio frame data into speech engine if possible */
if ( fr & & fr - > frametype = = AST_FRAME_VOICE )
ast_speech_write ( speech , fr - > data , fr - > datalen ) ;
break ;
case AST_SPEECH_STATE_WAIT :
/* Cue waiting sound if not already playing */
if ( ( ! chan - > stream ) | | ( chan - > streamid = = - 1 & & chan - > timingfunc = = NULL ) ) {
ast_stopstream ( chan ) ;
/* If a processing sound exists, or is not none - play it */
if ( ! ast_strlen_zero ( speech - > processing_sound ) & & strcasecmp ( speech - > processing_sound , " none " ) )
speech_streamfile ( chan , speech - > processing_sound , chan - > language , 0 ) ;
}
break ;
case AST_SPEECH_STATE_DONE :
/* Get the results */
speech - > results = ast_speech_results_get ( speech ) ;
/* Change state to not ready */
ast_speech_change_state ( speech , AST_SPEECH_STATE_NOT_READY ) ;
reason = " speech " ;
break ;
default :
break ;
}
ast_mutex_unlock ( & speech - > lock ) ;
/* Check frame for DTMF or hangup */
if ( fr ) {
if ( fr - > frametype = = AST_FRAME_DTMF ) {
reason = " dtmf " ;
dtmf = fr - > subclass ;
} else if ( fr - > frametype = = AST_FRAME_CONTROL & & fr - > subclass = = AST_CONTROL_HANGUP ) {
reason = " hangup " ;
}
ast_frfree ( fr ) ;
}
}
if ( ! strcasecmp ( reason , " speech " ) ) {
/* Build string containing speech results */
for ( result = speech - > results ; result ; result = AST_LIST_NEXT ( result , list ) ) {
/* Build result string */
ast_build_string ( & buf , & left , " %sscore%d=%d text%d= \" %s \" grammar%d=%s " , ( i > 0 ? " " : " " ) , i , result - > score , i , result - > text , i , result - > grammar ) ;
/* Increment result count */
i + + ;
}
/* Print out */
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 (speech) endpos=%ld results=%d %s \n " , current_offset , i , tmp ) ;
} else if ( ! strcasecmp ( reason , " dtmf " ) ) {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 (digit) digit=%c endpos=%ld \n " , dtmf , current_offset ) ;
} else if ( ! strcasecmp ( reason , " hangup " ) | | ! strcasecmp ( reason , " timeout " ) ) {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=1 (%s) endpos=%ld \n " , reason , current_offset ) ;
} else {
ast_agi_fdprintf ( chan , agi - > fd , " 200 result=0 endpos=%ld \n " , current_offset ) ;
}
return RESULT_SUCCESS ;
}
2003-06-11 12:17:43 +00:00
static char usage_setmusic [ ] =
" Usage: SET MUSIC ON <on|off> <class> \n "
" Enables/Disables the music on hold generator. If <class> is \n "
2004-12-28 23:01:22 +00:00
" not specified, then the default music on hold class will be used. \n "
" Always returns 0. \n " ;
2003-06-11 12:17:43 +00:00
2003-02-06 22:11:43 +00:00
static char usage_dbput [ ] =
" Usage: DATABASE PUT <family> <key> <value> \n "
" Adds or updates an entry in the Asterisk database for a \n "
" given family, key, and value. \n "
2004-12-28 23:01:22 +00:00
" Returns 1 if successful, 0 otherwise. \n " ;
2003-02-06 22:11:43 +00:00
static char usage_dbget [ ] =
" Usage: DATABASE GET <family> <key> \n "
" Retrieves an entry in the Asterisk database for a \n "
" given family and key. \n "
2004-12-28 23:01:22 +00:00
" Returns 0 if <key> is not set. Returns 1 if <key> \n "
" is set and returns the variable in parentheses. \n "
" Example return code: 200 result=1 (testvariable) \n " ;
2003-02-06 22:11:43 +00:00
static char usage_dbdel [ ] =
" Usage: DATABASE DEL <family> <key> \n "
" Deletes an entry in the Asterisk database for a \n "
" given family and key. \n "
2004-12-28 23:01:22 +00:00
" Returns 1 if successful, 0 otherwise. \n " ;
2003-02-06 22:11:43 +00:00
static char usage_dbdeltree [ ] =
" Usage: DATABASE DELTREE <family> [keytree] \n "
2004-12-28 23:01:22 +00:00
" Deletes a family or specific keytree within a family \n "
2003-02-06 22:11:43 +00:00
" in the Asterisk database. \n "
2004-12-28 23:01:22 +00:00
" Returns 1 if successful, 0 otherwise. \n " ;
2003-02-06 22:11:43 +00:00
static char usage_verbose [ ] =
" Usage: VERBOSE <message> <level> \n "
" Sends <message> to the console via verbose message system. \n "
2004-12-28 23:01:22 +00:00
" <level> is the the verbose level (1-4) \n "
" Always returns 1. \n " ;
2003-02-06 22:11:43 +00:00
static char usage_getvariable [ ] =
" Usage: GET VARIABLE <variablename> \n "
" Returns 0 if <variablename> is not set. Returns 1 if <variablename> \n "
2004-12-28 23:01:22 +00:00
" is set and returns the variable in parentheses. \n "
2003-02-06 22:11:43 +00:00
" example return code: 200 result=1 (testvariable) \n " ;
2004-11-17 04:02:56 +00:00
static char usage_getvariablefull [ ] =
" Usage: GET FULL VARIABLE <variablename> [<channel name>] \n "
" Returns 0 if <variablename> is not set or channel does not exist. Returns 1 \n "
" if <variablename> is set and returns the variable in parenthesis. Understands \n "
" complex variable names and builtin variables, unlike GET VARIABLE. \n "
" example return code: 200 result=1 (testvariable) \n " ;
2003-02-06 22:11:43 +00:00
static char usage_setvariable [ ] =
" Usage: SET VARIABLE <variablename> <value> \n " ;
2002-09-04 16:53:39 +00:00
static char usage_channelstatus [ ] =
2003-02-06 22:11:43 +00:00
" Usage: CHANNEL STATUS [<channelname>] \n "
" Returns the status of the specified channel. \n "
2004-12-28 23:01:22 +00:00
" If no channel name is given the returns the status of the \n "
" current channel. Return values: \n "
" 0 Channel is down and available \n "
" 1 Channel is down, but reserved \n "
" 2 Channel is off hook \n "
" 3 Digits (or equivalent) have been dialed \n "
" 4 Line is ringing \n "
" 5 Remote end is ringing \n "
" 6 Line is up \n "
" 7 Line is busy \n " ;
2002-09-04 16:53:39 +00:00
static char usage_setcallerid [ ] =
" Usage: SET CALLERID <number> \n "
" Changes the callerid of the current channel. \n " ;
static char usage_exec [ ] =
" Usage: EXEC <application> <options> \n "
" Executes <application> with given <options>. \n "
2004-12-28 23:01:22 +00:00
" Returns whatever the application returns, or -2 on failure to find application \n " ;
2002-09-04 16:53:39 +00:00
static char usage_hangup [ ] =
2003-02-06 22:11:43 +00:00
" Usage: HANGUP [<channelname>] \n "
" Hangs up the specified channel. \n "
2004-12-28 23:01:22 +00:00
" If no channel name is given, hangs up the current channel \n " ;
2002-09-04 16:53:39 +00:00
2002-06-14 15:50:42 +00:00
static char usage_answer [ ] =
" Usage: ANSWER \n "
2004-12-28 23:01:22 +00:00
" Answers channel if not already in answer state. Returns -1 on \n "
2002-06-14 15:50:42 +00:00
" channel failure, or 0 if successful. \n " ;
2001-09-28 13:19:43 +00:00
static char usage_waitfordigit [ ] =
" Usage: WAIT FOR DIGIT <timeout> \n "
2004-12-28 23:01:22 +00:00
" Waits up to 'timeout' milliseconds for channel to receive a DTMF digit. \n "
2001-09-28 13:19:43 +00:00
" Returns -1 on channel failure, 0 if no digit is received in the timeout, or \n "
" the numerical value of the ascii of the digit if one is received. Use -1 \n "
" for the timeout value if you desire the call to block indefinitely. \n " ;
static char usage_sendtext [ ] =
" Usage: SEND TEXT \" <text to send> \" \n "
2005-01-08 19:35:20 +00:00
" Sends the given text on a channel. Most channels do not support the \n "
2001-09-28 13:19:43 +00:00
" transmission of text. Returns 0 if text is sent, or if the channel does not \n "
" support text transmission. Returns -1 only on error/hangup. Text \n "
" consisting of greater than one word should be placed in quotes since the \n "
" command only accepts a single argument. \n " ;
2001-12-27 11:07:33 +00:00
static char usage_recvchar [ ] =
" Usage: RECEIVE CHAR <timeout> \n "
2005-01-08 19:35:20 +00:00
" Receives a character of text on a channel. Specify timeout to be the \n "
2001-12-27 11:07:33 +00:00
" maximum time to wait for input in milliseconds, or 0 for infinite. Most channels \n "
2005-01-08 19:35:20 +00:00
" do not support the reception of text. Returns the decimal value of the character \n "
2001-12-27 11:07:33 +00:00
" if one is received, or 0 if the channel does not support text reception. Returns \n "
" -1 only on error/hangup. \n " ;
2005-06-21 01:16:18 +00:00
static char usage_recvtext [ ] =
2005-08-15 02:45:34 +00:00
" Usage: RECEIVE TEXT <timeout> \n "
2005-06-21 01:16:18 +00:00
" Receives a string of text on a channel. Specify timeout to be the \n "
" maximum time to wait for input in milliseconds, or 0 for infinite. Most channels \n "
" do not support the reception of text. Returns -1 for failure or 1 for success, and the string in parentheses. \n " ;
2001-12-27 11:07:33 +00:00
static char usage_tddmode [ ] =
" Usage: TDD MODE <on|off> \n "
2004-12-28 23:01:22 +00:00
" Enable/Disable TDD transmission/reception on a channel. Returns 1 if \n "
2001-12-27 11:07:33 +00:00
" successful, or 0 if channel is not TDD-capable. \n " ;
2001-09-28 13:19:43 +00:00
static char usage_sendimage [ ] =
" Usage: SEND IMAGE <image> \n "
2005-01-08 19:35:20 +00:00
" Sends the given image on a channel. Most channels do not support the \n "
" transmission of images. Returns 0 if image is sent, or if the channel does not \n "
" support image transmission. Returns -1 only on error/hangup. Image names \n "
2001-09-28 13:19:43 +00:00
" should not include extensions. \n " ;
static char usage_streamfile [ ] =
2003-02-06 22:11:43 +00:00
" Usage: STREAM FILE <filename> <escape digits> [sample offset] \n "
2004-12-28 23:01:22 +00:00
" Send the given file, allowing playback to be interrupted by the given \n "
2005-01-08 19:35:20 +00:00
" digits, if any. Use double quotes for the digits if you wish none to be \n "
" permitted. If sample offset is provided then the audio will seek to sample \n "
2003-02-06 22:11:43 +00:00
" offset before play starts. Returns 0 if playback completes without a digit \n "
" being pressed, or the ASCII numerical value of the digit if one was pressed, \n "
2005-01-08 19:35:20 +00:00
" or -1 on error or if the channel was disconnected. Remember, the file \n "
2003-02-06 22:11:43 +00:00
" extension must not be included in the filename. \n " ;
2001-09-28 13:19:43 +00:00
2005-08-22 21:59:24 +00:00
static char usage_controlstreamfile [ ] =
" Usage: CONTROL STREAM FILE <filename> <escape digits> [skipms] [ffchar] [rewchr] [pausechr] \n "
" Send the given file, allowing playback to be controled by the given \n "
" digits, if any. Use double quotes for the digits if you wish none to be \n "
" permitted. Returns 0 if playback completes without a digit \n "
" being pressed, or the ASCII numerical value of the digit if one was pressed, \n "
" or -1 on error or if the channel was disconnected. Remember, the file \n "
" extension must not be included in the filename. \n \n "
" Note: ffchar and rewchar default to * and # respectively. \n " ;
2004-11-16 03:37:07 +00:00
static char usage_getoption [ ] =
" Usage: GET OPTION <filename> <escape_digits> [timeout] \n "
2004-12-28 23:01:22 +00:00
" Behaves similar to STREAM FILE but used with a timeout option. \n " ;
2004-11-16 03:37:07 +00:00
2001-09-28 13:19:43 +00:00
static char usage_saynumber [ ] =
2007-05-11 16:16:50 +00:00
" Usage: SAY NUMBER <number> <escape digits> [gender] \n "
2004-12-28 23:01:22 +00:00
" Say a given number, returning early if any of the given DTMF digits \n "
2001-09-28 13:19:43 +00:00
" are received on the channel. Returns 0 if playback completes without a digit \n "
" being pressed, or the ASCII numerical value of the digit if one was pressed or \n "
" -1 on error/hangup. \n " ;
2002-06-14 15:50:42 +00:00
static char usage_saydigits [ ] =
" Usage: SAY DIGITS <number> <escape digits> \n "
2004-12-28 23:01:22 +00:00
" Say a given digit string, returning early if any of the given DTMF digits \n "
2005-01-08 19:35:20 +00:00
" are received on the channel. Returns 0 if playback completes without a digit \n "
2002-06-14 15:50:42 +00:00
" being pressed, or the ASCII numerical value of the digit if one was pressed or \n "
" -1 on error/hangup. \n " ;
2004-12-14 18:39:25 +00:00
static char usage_sayalpha [ ] =
" Usage: SAY ALPHA <number> <escape digits> \n "
2004-12-28 23:01:22 +00:00
" Say a given character string, returning early if any of the given DTMF digits \n "
2005-01-08 19:35:20 +00:00
" are received on the channel. Returns 0 if playback completes without a digit \n "
2004-12-14 18:39:25 +00:00
" being pressed, or the ASCII numerical value of the digit if one was pressed or \n "
" -1 on error/hangup. \n " ;
2005-03-30 07:00:49 +00:00
static char usage_saydate [ ] =
" Usage: SAY DATE <date> <escape digits> \n "
" Say a given date, returning early if any of the given DTMF digits are \n "
" received on the channel. <date> is number of seconds elapsed since 00:00:00 \n "
" on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback \n "
" completes without a digit being pressed, or the ASCII numerical value of the \n "
" digit if one was pressed or -1 on error/hangup. \n " ;
2004-02-27 08:30:30 +00:00
static char usage_saytime [ ] =
" Usage: SAY TIME <time> <escape digits> \n "
2004-12-28 23:01:22 +00:00
" Say a given time, returning early if any of the given DTMF digits are \n "
2004-02-27 08:30:30 +00:00
" received on the channel. <time> is number of seconds elapsed since 00:00:00 \n "
2005-01-08 19:35:20 +00:00
" on January 1, 1970, Coordinated Universal Time (UTC). Returns 0 if playback \n "
2004-02-27 08:30:30 +00:00
" completes without a digit being pressed, or the ASCII numerical value of the \n "
" digit if one was pressed or -1 on error/hangup. \n " ;
2005-04-11 03:23:54 +00:00
static char usage_saydatetime [ ] =
" Usage: SAY DATETIME <time> <escape digits> [format] [timezone] \n "
" Say a given time, returning early if any of the given DTMF digits are \n "
" received on the channel. <time> is number of seconds elapsed since 00:00:00 \n "
" on January 1, 1970, Coordinated Universal Time (UTC). [format] is the format \n "
" the time should be said in. See voicemail.conf (defaults to \" ABdY \n "
" 'digits/at' IMp \" ). Acceptable values for [timezone] can be found in \n "
" /usr/share/zoneinfo. Defaults to machine default. Returns 0 if playback \n "
" completes without a digit being pressed, or the ASCII numerical value of the \n "
" digit if one was pressed or -1 on error/hangup. \n " ;
2004-05-03 00:54:16 +00:00
static char usage_sayphonetic [ ] =
" Usage: SAY PHONETIC <string> <escape digits> \n "
2004-12-28 23:01:22 +00:00
" Say a given character string with phonetics, returning early if any of the \n "
2005-01-08 19:35:20 +00:00
" given DTMF digits are received on the channel. Returns 0 if playback \n "
2004-12-28 23:01:22 +00:00
" completes without a digit pressed, the ASCII numerical value of the digit \n "
" if one was pressed, or -1 on error/hangup. \n " ;
2004-05-03 00:54:16 +00:00
2001-09-28 13:19:43 +00:00
static char usage_getdata [ ] =
" Usage: GET DATA <file to be streamed> [timeout] [max digits] \n "
2004-12-28 23:01:22 +00:00
" Stream the given file, and recieve DTMF data. Returns the digits received \n "
2001-09-28 13:19:43 +00:00
" from the channel at the other end. \n " ;
static char usage_setcontext [ ] =
" Usage: SET CONTEXT <desired context> \n "
2004-12-28 23:01:22 +00:00
" Sets the context for continuation upon exiting the application. \n " ;
2001-09-28 13:19:43 +00:00
static char usage_setextension [ ] =
" Usage: SET EXTENSION <new extension> \n "
2004-12-28 23:01:22 +00:00
" Changes the extension for continuation upon exiting the application. \n " ;
2001-09-28 13:19:43 +00:00
static char usage_setpriority [ ] =
2005-05-19 02:57:45 +00:00
" Usage: SET PRIORITY <priority> \n "
" Changes the priority for continuation upon exiting the application. \n "
" The priority must be a valid priority or label. \n " ;
2001-09-28 13:19:43 +00:00
static char usage_recordfile [ ] =
2004-12-28 23:01:22 +00:00
" Usage: RECORD FILE <filename> <format> <escape digits> <timeout> \\ \n "
" [offset samples] [BEEP] [s=silence] \n "
" Record to a file until a given dtmf digit in the sequence is received \n "
2001-09-28 13:19:43 +00:00
" Returns -1 on hangup or error. The format will specify what kind of file \n "
" will be recorded. The timeout is the maximum record time in milliseconds, or \n "
2004-12-28 23:01:22 +00:00
" -1 for no timeout. \" Offset samples \" is optional, and, if provided, will seek \n "
" to the offset without exceeding the end of the file. \" silence \" is the number \n "
2003-05-01 03:52:45 +00:00
" of seconds of silence allowed before the function returns despite the \n "
" lack of dtmf digits or reaching timeout. Silence value must be \n "
2004-12-28 23:01:22 +00:00
" preceeded by \" s= \" and is also optional. \n " ;
2001-09-28 13:19:43 +00:00
2002-09-04 16:53:39 +00:00
static char usage_autohangup [ ] =
" Usage: SET AUTOHANGUP <time> \n "
2004-12-28 23:01:22 +00:00
" Cause the channel to automatically hangup at <time> seconds in the \n "
2005-01-08 19:35:20 +00:00
" future. Of course it can be hungup before then as well. Setting to 0 will \n "
2004-12-28 23:01:22 +00:00
" cause the autohangup feature to be disabled on this channel. \n " ;
2002-09-04 16:53:39 +00:00
2003-02-23 06:00:11 +00:00
static char usage_noop [ ] =
2004-12-28 23:01:22 +00:00
" Usage: NoOp \n "
" Does nothing. \n " ;
2003-02-23 06:00:11 +00:00
2007-12-03 21:03:05 +00:00
static char usage_speechcreate [ ] =
" Usage: SPEECH CREATE <engine> \n "
" Create a speech object to be used by the other Speech AGI commands. \n " ;
static char usage_speechset [ ] =
" Usage: SPEECH SET <name> <value> \n "
" Set an engine-specific setting. \n " ;
static char usage_speechdestroy [ ] =
" Usage: SPEECH DESTROY \n "
" Destroy the speech object created by SPEECH CREATE. \n " ;
static char usage_speechloadgrammar [ ] =
" Usage: SPEECH LOAD GRAMMAR <grammar name> <path to grammar> \n "
" Loads the specified grammar as the specified name. \n " ;
static char usage_speechunloadgrammar [ ] =
" Usage: SPEECH UNLOAD GRAMMAR <grammar name> \n "
" Unloads the specified grammar. \n " ;
static char usage_speechactivategrammar [ ] =
" Usage: SPEECH ACTIVATE GRAMMAR <grammar name> \n "
" Activates the specified grammar on the speech object. \n " ;
static char usage_speechdeactivategrammar [ ] =
" Usage: SPEECH DEACTIVATE GRAMMAR <grammar name> \n "
" Deactivates the specified grammar on the speech object. \n " ;
static char usage_speechrecognize [ ] =
" Usage: SPEECH RECOGNIZE <prompt> <timeout> [<offset>] \n "
" Plays back given prompt while listening for speech and dtmf. \n " ;
2007-07-02 19:01:16 +00:00
/*!
2007-07-23 22:02:05 +00:00
* \ brief AGI commands list
2007-07-02 19:01:16 +00:00
*/
2007-07-30 19:11:28 +00:00
static struct agi_command commands [ ] = {
2007-07-23 22:02:05 +00:00
{ { " answer " , NULL } , handle_answer , " Answer channel " , usage_answer , 0 } ,
{ { " channel " , " status " , NULL } , handle_channelstatus , " Returns status of the connected channel " , usage_channelstatus , 0 } ,
{ { " database " , " del " , NULL } , handle_dbdel , " Removes database key/value " , usage_dbdel , 1 } ,
{ { " database " , " deltree " , NULL } , handle_dbdeltree , " Removes database keytree/value " , usage_dbdeltree , 1 } ,
{ { " database " , " get " , NULL } , handle_dbget , " Gets database value " , usage_dbget , 1 } ,
{ { " database " , " put " , NULL } , handle_dbput , " Adds/updates database value " , usage_dbput , 1 } ,
{ { " exec " , NULL } , handle_exec , " Executes a given Application " , usage_exec , 1 } ,
{ { " get " , " data " , NULL } , handle_getdata , " Prompts for DTMF on a channel " , usage_getdata , 0 } ,
{ { " get " , " full " , " variable " , NULL } , handle_getvariablefull , " Evaluates a channel expression " , usage_getvariablefull , 1 } ,
{ { " get " , " option " , NULL } , handle_getoption , " Stream file, prompt for DTMF, with timeout " , usage_getoption , 0 } ,
{ { " get " , " variable " , NULL } , handle_getvariable , " Gets a channel variable " , usage_getvariable , 1 } ,
{ { " hangup " , NULL } , handle_hangup , " Hangup the current channel " , usage_hangup , 0 } ,
{ { " noop " , NULL } , handle_noop , " Does nothing " , usage_noop , 1 } ,
{ { " receive " , " char " , NULL } , handle_recvchar , " Receives one character from channels supporting it " , usage_recvchar , 0 } ,
{ { " receive " , " text " , NULL } , handle_recvtext , " Receives text from channels supporting it " , usage_recvtext , 0 } ,
{ { " record " , " file " , NULL } , handle_recordfile , " Records to a given file " , usage_recordfile , 0 } ,
{ { " say " , " alpha " , NULL } , handle_sayalpha , " Says a given character string " , usage_sayalpha , 0 } ,
{ { " say " , " digits " , NULL } , handle_saydigits , " Says a given digit string " , usage_saydigits , 0 } ,
{ { " say " , " number " , NULL } , handle_saynumber , " Says a given number " , usage_saynumber , 0 } ,
{ { " say " , " phonetic " , NULL } , handle_sayphonetic , " Says a given character string with phonetics " , usage_sayphonetic , 0 } ,
{ { " say " , " date " , NULL } , handle_saydate , " Says a given date " , usage_saydate , 0 } ,
{ { " say " , " time " , NULL } , handle_saytime , " Says a given time " , usage_saytime , 0 } ,
{ { " say " , " datetime " , NULL } , handle_saydatetime , " Says a given time as specfied by the format given " , usage_saydatetime , 0 } ,
{ { " send " , " image " , NULL } , handle_sendimage , " Sends images to channels supporting it " , usage_sendimage , 0 } ,
{ { " send " , " text " , NULL } , handle_sendtext , " Sends text to channels supporting it " , usage_sendtext , 0 } ,
{ { " set " , " autohangup " , NULL } , handle_autohangup , " Autohangup channel in some time " , usage_autohangup , 0 } ,
{ { " set " , " callerid " , NULL } , handle_setcallerid , " Sets callerid for the current channel " , usage_setcallerid , 0 } ,
{ { " set " , " context " , NULL } , handle_setcontext , " Sets channel context " , usage_setcontext , 0 } ,
{ { " set " , " extension " , NULL } , handle_setextension , " Changes channel extension " , usage_setextension , 0 } ,
{ { " set " , " music " , NULL } , handle_setmusic , " Enable/Disable Music on hold generator " , usage_setmusic , 0 } ,
{ { " set " , " priority " , NULL } , handle_setpriority , " Set channel dialplan priority " , usage_setpriority , 0 } ,
{ { " set " , " variable " , NULL } , handle_setvariable , " Sets a channel variable " , usage_setvariable , 1 } ,
{ { " stream " , " file " , NULL } , handle_streamfile , " Sends audio file on channel " , usage_streamfile , 0 } ,
{ { " control " , " stream " , " file " , NULL } , handle_controlstreamfile , " Sends audio file on channel and allows the listner to control the stream " , usage_controlstreamfile , 0 } ,
{ { " tdd " , " mode " , NULL } , handle_tddmode , " Toggles TDD mode (for the deaf) " , usage_tddmode , 0 } ,
{ { " verbose " , NULL } , handle_verbose , " Logs a message to the asterisk verbose log " , usage_verbose , 1 } ,
{ { " wait " , " for " , " digit " , NULL } , handle_waitfordigit , " Waits for a digit to be pressed " , usage_waitfordigit , 0 } ,
2007-12-03 21:03:05 +00:00
{ { " speech " , " create " , NULL } , handle_speechcreate , " Creates a speech object " , usage_speechcreate , 0 } ,
{ { " speech " , " set " , NULL } , handle_speechset , " Sets a speech engine setting " , usage_speechset , 0 } ,
{ { " speech " , " destroy " , NULL } , handle_speechdestroy , " Destroys a speech object " , usage_speechdestroy , 1 } ,
{ { " speech " , " load " , " grammar " , NULL } , handle_speechloadgrammar , " Loads a grammar " , usage_speechloadgrammar , 0 } ,
{ { " speech " , " unload " , " grammar " , NULL } , handle_speechunloadgrammar , " Unloads a grammar " , usage_speechunloadgrammar , 1 } ,
{ { " speech " , " activate " , " grammar " , NULL } , handle_speechactivategrammar , " Activates a grammar " , usage_speechactivategrammar , 0 } ,
{ { " speech " , " deactivate " , " grammar " , NULL } , handle_speechdeactivategrammar , " Deactivates a grammar " , usage_speechdeactivategrammar , 0 } ,
{ { " speech " , " recognize " , NULL } , handle_speechrecognize , " Recognizes speech " , usage_speechrecognize , 0 } ,
2001-09-28 13:19:43 +00:00
} ;
2007-07-23 23:14:20 +00:00
static AST_RWLIST_HEAD_STATIC ( agi_commands , agi_command ) ;
2007-07-23 22:02:05 +00:00
2007-09-18 22:43:45 +00:00
static char * help_workhorse ( int fd , char * match [ ] )
2003-02-06 22:11:43 +00:00
{
2007-07-11 21:09:42 +00:00
char fullcmd [ 80 ] , matchstr [ 80 ] ;
2003-02-06 22:11:43 +00:00
struct agi_command * e ;
2007-07-11 21:09:42 +00:00
2003-02-06 22:11:43 +00:00
if ( match )
2005-12-20 20:20:04 +00:00
ast_join ( matchstr , sizeof ( matchstr ) , match ) ;
2007-07-11 21:09:42 +00:00
2007-12-03 21:03:05 +00:00
ast_cli ( fd , " %5.5s %30.30s %s \n " , " Dead " , " Command " , " Description " ) ;
2007-07-23 22:02:05 +00:00
AST_RWLIST_RDLOCK ( & agi_commands ) ;
AST_RWLIST_TRAVERSE ( & agi_commands , e , list ) {
2005-12-20 20:20:04 +00:00
if ( ! e - > cmda [ 0 ] )
break ;
2003-02-06 22:11:43 +00:00
/* Hide commands that start with '_' */
2005-12-20 20:20:04 +00:00
if ( ( e - > cmda [ 0 ] ) [ 0 ] = = ' _ ' )
continue ;
ast_join ( fullcmd , sizeof ( fullcmd ) , e - > cmda ) ;
if ( match & & strncasecmp ( matchstr , fullcmd , strlen ( matchstr ) ) )
2003-02-06 22:11:43 +00:00
continue ;
2007-12-03 21:03:05 +00:00
ast_cli ( fd , " %5.5s %30.30s %s \n " , e - > dead ? " Yes " : " No " , fullcmd , e - > summary ) ;
2003-02-06 22:11:43 +00:00
}
2007-07-23 22:02:05 +00:00
AST_RWLIST_UNLOCK ( & agi_commands ) ;
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2003-02-06 22:11:43 +00:00
}
2007-07-30 19:11:28 +00:00
int ast_agi_register ( struct ast_module * mod , agi_command * cmd )
2004-07-17 20:25:39 +00:00
{
2007-07-30 19:11:28 +00:00
char fullcmd [ 80 ] ;
ast_join ( fullcmd , sizeof ( fullcmd ) , cmd - > cmda ) ;
if ( ! find_command ( cmd - > cmda , 1 ) ) {
2007-08-01 04:36:15 +00:00
cmd - > mod = mod ;
2007-07-23 22:02:05 +00:00
AST_RWLIST_WRLOCK ( & agi_commands ) ;
2007-07-30 19:11:28 +00:00
AST_LIST_INSERT_TAIL ( & agi_commands , cmd , list ) ;
2007-07-23 22:02:05 +00:00
AST_RWLIST_UNLOCK ( & agi_commands ) ;
2007-07-30 19:11:28 +00:00
if ( mod ! = ast_module_info - > self )
ast_module_ref ( ast_module_info - > self ) ;
ast_verb ( 2 , " AGI Command '%s' registered \n " , fullcmd ) ;
2007-07-23 22:02:05 +00:00
return 1 ;
} else {
ast_log ( LOG_WARNING , " Command already registered! \n " ) ;
return 0 ;
2004-07-17 20:25:39 +00:00
}
}
2007-07-30 19:11:28 +00:00
int ast_agi_unregister ( struct ast_module * mod , agi_command * cmd )
2004-07-17 20:25:39 +00:00
{
2007-07-23 22:02:05 +00:00
struct agi_command * e ;
int unregistered = 0 ;
2007-07-30 19:11:28 +00:00
char fullcmd [ 80 ] ;
ast_join ( fullcmd , sizeof ( fullcmd ) , cmd - > cmda ) ;
2007-07-23 22:02:05 +00:00
AST_RWLIST_WRLOCK ( & agi_commands ) ;
AST_RWLIST_TRAVERSE_SAFE_BEGIN ( & agi_commands , e , list ) {
if ( cmd = = e ) {
2007-11-08 05:28:47 +00:00
AST_RWLIST_REMOVE_CURRENT ( list ) ;
2007-07-30 19:11:28 +00:00
if ( mod ! = ast_module_info - > self )
ast_module_unref ( ast_module_info - > self ) ;
2007-07-23 22:02:05 +00:00
unregistered = 1 ;
break ;
2004-07-17 20:25:39 +00:00
}
}
2007-11-08 05:28:47 +00:00
AST_RWLIST_TRAVERSE_SAFE_END ;
2007-07-23 22:02:05 +00:00
AST_RWLIST_UNLOCK ( & agi_commands ) ;
2007-07-30 19:11:28 +00:00
if ( unregistered )
ast_verb ( 2 , " AGI Command '%s' unregistered \n " , fullcmd ) ;
else
ast_log ( LOG_WARNING , " Unable to unregister command: '%s'! \n " , fullcmd ) ;
2007-07-23 22:02:05 +00:00
return unregistered ;
2004-07-17 20:25:39 +00:00
}
2007-07-30 19:11:28 +00:00
void ast_agi_register_multiple ( struct ast_module * mod , agi_command * cmd , int len )
{
int i ;
for ( i = 0 ; i < len ; i + + )
ast_agi_register ( mod , cmd + i ) ;
}
void ast_agi_unregister_multiple ( struct ast_module * mod , agi_command * cmd , int len )
{
int i ;
for ( i = 0 ; i < len ; i + + )
ast_agi_unregister ( mod , cmd + i ) ;
}
2003-02-06 22:11:43 +00:00
static agi_command * find_command ( char * cmds [ ] , int exact )
2001-09-28 13:19:43 +00:00
{
2007-07-23 22:02:05 +00:00
int y , match ;
struct agi_command * e ;
2005-01-08 19:35:20 +00:00
2007-07-23 22:02:05 +00:00
AST_RWLIST_RDLOCK ( & agi_commands ) ;
AST_RWLIST_TRAVERSE ( & agi_commands , e , list ) {
if ( ! e - > cmda [ 0 ] )
2005-01-08 19:35:20 +00:00
break ;
2007-08-01 04:36:15 +00:00
/* start optimistic */
match = 1 ;
for ( y = 0 ; match & & cmds [ y ] ; y + + ) {
/* If there are no more words in the command (and we're looking for
an exact match ) or there is a difference between the two words ,
then this is not a match */
if ( ! e - > cmda [ y ] & & ! exact )
break ;
/* don't segfault if the next part of a command doesn't exist */
if ( ! e - > cmda [ y ] )
return NULL ;
if ( strcasecmp ( e - > cmda [ y ] , cmds [ y ] ) )
2001-09-28 13:19:43 +00:00
match = 0 ;
2007-08-01 04:36:15 +00:00
}
/* If more words are needed to complete the command then this is not
a candidate ( unless we ' re looking for a really inexact answer */
if ( ( exact > - 1 ) & & e - > cmda [ y ] )
match = 0 ;
if ( match )
return e ;
2001-09-28 13:19:43 +00:00
}
2007-07-23 22:02:05 +00:00
AST_RWLIST_UNLOCK ( & agi_commands ) ;
2001-09-28 13:19:43 +00:00
return NULL ;
}
static int parse_args ( char * s , int * max , char * argv [ ] )
{
2007-07-11 21:09:42 +00:00
int x = 0 , quoted = 0 , escaped = 0 , whitespace = 1 ;
2001-09-28 13:19:43 +00:00
char * cur ;
cur = s ;
while ( * s ) {
switch ( * s ) {
case ' " ' :
/* If it's escaped, put a literal quote */
if ( escaped )
goto normal ;
else
quoted = ! quoted ;
if ( quoted & & whitespace ) {
/* If we're starting a quote, coming off white space start a new word, too */
argv [ x + + ] = cur ;
whitespace = 0 ;
}
escaped = 0 ;
break ;
case ' ' :
case ' \t ' :
if ( ! quoted & & ! escaped ) {
/* If we're not quoted, mark this as whitespace, and
end the previous argument */
whitespace = 1 ;
* ( cur + + ) = ' \0 ' ;
} else
/* Otherwise, just treat it as anything else */
goto normal ;
break ;
case ' \\ ' :
/* If we're escaped, print a literal, otherwise enable escaping */
if ( escaped ) {
goto normal ;
} else {
escaped = 1 ;
}
break ;
default :
normal :
if ( whitespace ) {
if ( x > = MAX_ARGS - 1 ) {
ast_log ( LOG_WARNING , " Too many arguments, truncating \n " ) ;
break ;
}
/* Coming off of whitespace, start the next argument */
argv [ x + + ] = cur ;
whitespace = 0 ;
}
* ( cur + + ) = * s ;
escaped = 0 ;
}
s + + ;
}
/* Null terminate */
* ( cur + + ) = ' \0 ' ;
argv [ x ] = NULL ;
* max = x ;
return 0 ;
}
2007-07-23 22:02:05 +00:00
static int agi_handle_command ( struct ast_channel * chan , AGI * agi , char * buf , int dead )
2001-09-28 13:19:43 +00:00
{
char * argv [ MAX_ARGS ] ;
2007-07-11 21:09:42 +00:00
int argc = MAX_ARGS , res ;
2001-09-28 13:19:43 +00:00
agi_command * c ;
2005-01-08 19:35:20 +00:00
2001-09-28 13:19:43 +00:00
parse_args ( buf , & argc , argv ) ;
2007-07-23 22:02:05 +00:00
if ( ( c = find_command ( argv , 0 ) ) & & ( ! dead | | ( dead & & c - > dead ) ) ) {
2007-07-30 19:11:28 +00:00
/* if this command wasnt registered by res_agi, be sure to usecount
the module we are using */
if ( c - > mod ! = ast_module_info - > self )
ast_module_ref ( c - > mod ) ;
2003-02-23 06:00:11 +00:00
res = c - > handler ( chan , agi , argc , argv ) ;
2007-07-30 19:11:28 +00:00
if ( c - > mod ! = ast_module_info - > self )
ast_module_unref ( c - > mod ) ;
2001-09-28 13:19:43 +00:00
switch ( res ) {
case RESULT_SHOWUSAGE :
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 520-Invalid command syntax. Proper usage follows: \n " ) ;
ast_agi_fdprintf ( chan , agi - > fd , c - > usage ) ;
ast_agi_fdprintf ( chan , agi - > fd , " 520 End of proper usage. \n " ) ;
2001-09-28 13:19:43 +00:00
break ;
2004-03-05 14:23:22 +00:00
case AST_PBX_KEEPALIVE :
/* We've been asked to keep alive, so do so */
return AST_PBX_KEEPALIVE ;
break ;
2001-09-28 13:19:43 +00:00
case RESULT_FAILURE :
/* They've already given the failure. We've been hung up on so handle this
appropriately */
return - 1 ;
}
2007-07-23 22:02:05 +00:00
} else if ( ( c = find_command ( argv , 0 ) ) ) {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 511 Command Not Permitted on a dead channel \n " ) ;
2001-09-28 13:19:43 +00:00
} else {
2007-11-07 00:00:38 +00:00
ast_agi_fdprintf ( chan , agi - > fd , " 510 Invalid or unknown command \n " ) ;
2001-09-28 13:19:43 +00:00
}
return 0 ;
}
2006-10-17 23:06:13 +00:00
static enum agi_result run_agi ( struct ast_channel * chan , char * request , AGI * agi , int pid , int * status , int dead , int argc , char * argv [ ] )
2001-09-28 13:19:43 +00:00
{
struct ast_channel * c ;
2007-07-23 22:02:05 +00:00
int outfd , ms , needhup = 0 ;
2006-05-25 16:44:22 +00:00
enum agi_result returnstatus = AGI_RESULT_SUCCESS ;
2001-09-28 13:19:43 +00:00
struct ast_frame * f ;
2007-09-11 15:28:46 +00:00
char buf [ AGI_BUF_LEN ] ;
2007-09-18 22:46:05 +00:00
char * res = NULL ;
2001-09-28 13:19:43 +00:00
FILE * readf ;
2004-03-03 18:58:57 +00:00
/* how many times we'll retry if ast_waitfor_nandfs will return without either
channel or file descriptor in case select is interrupted by a system call ( EINTR ) */
2007-09-11 15:28:46 +00:00
int retry = AGI_NANDFS_RETRY ;
2003-11-05 23:43:31 +00:00
2003-02-23 06:00:11 +00:00
if ( ! ( readf = fdopen ( agi - > ctrl , " r " ) ) ) {
2001-09-28 13:19:43 +00:00
ast_log ( LOG_WARNING , " Unable to fdopen file descriptor \n " ) ;
2004-09-22 15:21:36 +00:00
if ( pid > - 1 )
kill ( pid , SIGHUP ) ;
2004-04-23 04:38:11 +00:00
close ( agi - > ctrl ) ;
2006-05-25 16:44:22 +00:00
return AGI_RESULT_FAILURE ;
2001-09-28 13:19:43 +00:00
}
setlinebuf ( readf ) ;
2006-10-17 23:06:13 +00:00
setup_env ( chan , request , agi - > fd , ( agi - > audio > - 1 ) , argc , argv ) ;
2001-09-28 13:19:43 +00:00
for ( ; ; ) {
2007-07-23 22:02:05 +00:00
if ( needhup ) {
needhup = 0 ;
dead = 1 ;
kill ( pid , SIGHUP ) ;
}
2001-09-28 13:19:43 +00:00
ms = - 1 ;
2004-03-03 18:58:57 +00:00
c = ast_waitfor_nandfds ( & chan , dead ? 0 : 1 , & agi - > ctrl , 1 , NULL , & outfd , & ms ) ;
2001-09-28 13:19:43 +00:00
if ( c ) {
2007-09-11 15:28:46 +00:00
retry = AGI_NANDFS_RETRY ;
2001-09-28 13:19:43 +00:00
/* Idle the channel until we get a command */
f = ast_read ( c ) ;
if ( ! f ) {
2007-06-14 19:39:12 +00:00
ast_debug ( 1 , " %s hungup \n " , chan - > name ) ;
2006-05-25 16:44:22 +00:00
returnstatus = AGI_RESULT_HANGUP ;
2007-07-23 22:02:05 +00:00
needhup = 1 ;
continue ;
2001-09-28 13:19:43 +00:00
} else {
2003-02-23 06:00:11 +00:00
/* If it's voice, write it to the audio pipe */
if ( ( agi - > audio > - 1 ) & & ( f - > frametype = = AST_FRAME_VOICE ) ) {
/* Write, ignoring errors */
write ( agi - > audio , f - > data , f - > datalen ) ;
}
2001-09-28 13:19:43 +00:00
ast_frfree ( f ) ;
}
} else if ( outfd > - 1 ) {
2007-09-18 22:46:05 +00:00
size_t len = sizeof ( buf ) ;
size_t buflen = 0 ;
2007-09-11 15:28:46 +00:00
retry = AGI_NANDFS_RETRY ;
2007-08-22 19:54:52 +00:00
buf [ 0 ] = ' \0 ' ;
2007-09-11 15:28:46 +00:00
2007-09-18 22:46:05 +00:00
while ( buflen < ( len - 1 ) ) {
res = fgets ( buf + buflen , len , readf ) ;
if ( feof ( readf ) )
break ;
if ( ferror ( readf ) & & ( ( errno ! = EINTR ) & & ( errno ! = EAGAIN ) ) )
break ;
if ( res ! = NULL & & ! agi - > fast )
break ;
buflen = strlen ( buf ) ;
2007-10-01 19:58:29 +00:00
if ( buflen & & buf [ buflen - 1 ] = = ' \n ' )
break ;
2007-09-18 22:46:05 +00:00
len - = buflen ;
if ( agidebug )
ast_verbose ( " AGI Rx << temp buffer %s - errno %s \n " , buf , strerror ( errno ) ) ;
}
if ( ! buf [ 0 ] ) {
2001-09-28 13:19:43 +00:00
/* Program terminated */
2007-07-23 22:02:05 +00:00
if ( returnstatus & & returnstatus ! = AST_PBX_KEEPALIVE )
2001-09-28 13:19:43 +00:00
returnstatus = - 1 ;
2007-11-07 00:00:38 +00:00
ast_verb ( 3 , " <%s>AGI Script %s completed, returning %d \n " , chan - > name , request , returnstatus ) ;
2006-10-24 20:22:29 +00:00
if ( pid > 0 )
waitpid ( pid , status , 0 ) ;
2001-09-28 13:19:43 +00:00
/* No need to kill the pid anymore, since they closed us */
pid = - 1 ;
break ;
}
2007-09-11 15:28:46 +00:00
2005-01-08 19:35:20 +00:00
/* get rid of trailing newline, if any */
2001-12-27 11:07:33 +00:00
if ( * buf & & buf [ strlen ( buf ) - 1 ] = = ' \n ' )
buf [ strlen ( buf ) - 1 ] = 0 ;
2004-09-25 14:22:27 +00:00
if ( agidebug )
2007-11-07 00:00:38 +00:00
ast_verbose ( " <%s>AGI Rx << %s \n " , chan - > name , buf ) ;
2007-07-23 22:02:05 +00:00
returnstatus | = agi_handle_command ( chan , agi , buf , dead ) ;
2001-09-28 13:19:43 +00:00
/* If the handle_command returns -1, we need to stop */
2004-03-05 14:23:22 +00:00
if ( ( returnstatus < 0 ) | | ( returnstatus = = AST_PBX_KEEPALIVE ) ) {
2007-07-23 22:02:05 +00:00
needhup = 1 ;
continue ;
2001-09-28 13:19:43 +00:00
}
} else {
2003-11-05 23:43:31 +00:00
if ( - - retry < = 0 ) {
ast_log ( LOG_WARNING , " No channel, no fd? \n " ) ;
2006-05-25 16:44:22 +00:00
returnstatus = AGI_RESULT_FAILURE ;
2003-11-05 23:43:31 +00:00
break ;
}
2001-09-28 13:19:43 +00:00
}
}
/* Notify process */
2005-08-03 04:17:12 +00:00
if ( pid > - 1 ) {
2006-05-25 19:01:26 +00:00
const char * sighup = pbx_builtin_getvar_helper ( chan , " AGISIGHUP " ) ;
if ( ast_strlen_zero ( sighup ) | | ! ast_false ( sighup ) ) {
if ( kill ( pid , SIGHUP ) )
ast_log ( LOG_WARNING , " unable to send SIGHUP to AGI process %d: %s \n " , pid , strerror ( errno ) ) ;
}
2005-08-03 04:17:12 +00:00
}
2001-09-28 13:19:43 +00:00
fclose ( readf ) ;
return returnstatus ;
}
2007-09-18 22:43:45 +00:00
static char * handle_cli_agi_show ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-04-06 16:17:04 +00:00
{
2007-09-18 22:43:45 +00:00
struct agi_command * command ;
2003-02-06 22:11:43 +00:00
char fullcmd [ 80 ] ;
2007-07-11 21:09:42 +00:00
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " agi show " ;
e - > usage =
" Usage: agi show [topic] \n "
" When called with a topic as an argument, displays usage \n "
" information on the given command. If called without a \n "
" topic, it provides a list of AGI commands. \n " ;
break ;
case CLI_GENERATE :
return NULL ;
}
if ( a - > argc < e - > args )
return CLI_SHOWUSAGE ;
if ( a - > argc > e - > args ) {
command = find_command ( a - > argv + e - > args , 1 ) ;
if ( command ) {
ast_cli ( a - > fd , command - > usage ) ;
ast_cli ( a - > fd , " Runs Dead : %s \n " , command - > dead ? " Yes " : " No " ) ;
2007-07-23 22:02:05 +00:00
} else {
2007-09-18 22:43:45 +00:00
if ( find_command ( a - > argv + e - > args , - 1 ) ) {
return help_workhorse ( a - > fd , a - > argv + e - > args ) ;
2003-02-06 22:11:43 +00:00
} else {
2007-09-18 22:43:45 +00:00
ast_join ( fullcmd , sizeof ( fullcmd ) , a - > argv + e - > args ) ;
ast_cli ( a - > fd , " No such command '%s'. \n " , fullcmd ) ;
2003-02-06 22:11:43 +00:00
}
}
} else {
2007-09-18 22:43:45 +00:00
return help_workhorse ( a - > fd , NULL ) ;
2003-02-06 22:11:43 +00:00
}
2007-09-18 22:43:45 +00:00
return CLI_SUCCESS ;
2003-02-06 22:11:43 +00:00
}
2007-02-16 11:47:48 +00:00
/*! \brief Convert string to use HTML escaped characters
\ note Maybe this should be a generic function ?
*/
static void write_html_escaped ( FILE * htmlfile , char * str )
{
char * cur = str ;
while ( * cur ) {
switch ( * cur ) {
case ' < ' :
fprintf ( htmlfile , " %s " , " < " ) ;
break ;
case ' > ' :
fprintf ( htmlfile , " %s " , " > " ) ;
break ;
case ' & ' :
fprintf ( htmlfile , " %s " , " & " ) ;
break ;
case ' " ' :
fprintf ( htmlfile , " %s " , " " " ) ;
break ;
default :
fprintf ( htmlfile , " %c " , * cur ) ;
break ;
}
cur + + ;
}
return ;
}
2007-09-18 22:43:45 +00:00
static char * handle_cli_agi_dumphtml ( struct ast_cli_entry * e , int cmd , struct ast_cli_args * a )
2006-04-06 16:17:04 +00:00
{
2007-09-18 22:43:45 +00:00
struct agi_command * command ;
2003-02-06 22:11:43 +00:00
char fullcmd [ 80 ] ;
FILE * htmlfile ;
2007-09-18 22:43:45 +00:00
switch ( cmd ) {
case CLI_INIT :
e - > command = " agi dumphtml " ;
e - > usage =
" Usage: agi dumphtml <filename> \n "
" Dumps the AGI command list in HTML format to the given \n "
" file. \n " ;
return NULL ;
case CLI_GENERATE :
return NULL ;
}
if ( a - > argc < e - > args + 1 )
return CLI_SHOWUSAGE ;
2003-02-06 22:11:43 +00:00
2007-09-18 22:43:45 +00:00
if ( ! ( htmlfile = fopen ( a - > argv [ 2 ] , " wt " ) ) ) {
ast_cli ( a - > fd , " Could not create file '%s' \n " , a - > argv [ 2 ] ) ;
return CLI_SHOWUSAGE ;
2003-02-06 22:11:43 +00:00
}
fprintf ( htmlfile , " <HTML> \n <HEAD> \n <TITLE>AGI Commands</TITLE> \n </HEAD> \n " ) ;
fprintf ( htmlfile , " <BODY> \n <CENTER><B><H1>AGI Commands</H1></B></CENTER> \n \n " ) ;
fprintf ( htmlfile , " <TABLE BORDER= \" 0 \" CELLSPACING= \" 10 \" > \n " ) ;
2007-07-23 22:02:05 +00:00
AST_RWLIST_RDLOCK ( & agi_commands ) ;
2007-09-18 22:43:45 +00:00
AST_RWLIST_TRAVERSE ( & agi_commands , command , list ) {
2005-12-20 20:20:04 +00:00
char * stringp , * tempstr ;
2007-07-23 22:02:05 +00:00
2007-09-18 22:43:45 +00:00
if ( ! command - > cmda [ 0 ] ) /* end ? */
2005-12-20 20:20:04 +00:00
break ;
2003-02-06 22:11:43 +00:00
/* Hide commands that start with '_' */
2007-09-18 22:43:45 +00:00
if ( ( command - > cmda [ 0 ] ) [ 0 ] = = ' _ ' )
2003-02-06 22:11:43 +00:00
continue ;
2007-09-18 22:43:45 +00:00
ast_join ( fullcmd , sizeof ( fullcmd ) , command - > cmda ) ;
2003-02-06 22:11:43 +00:00
fprintf ( htmlfile , " <TR><TD><TABLE BORDER= \" 1 \" CELLPADDING= \" 5 \" WIDTH= \" 100%% \" > \n " ) ;
2007-09-18 22:43:45 +00:00
fprintf ( htmlfile , " <TR><TH ALIGN= \" CENTER \" ><B>%s - %s</B></TH></TR> \n " , fullcmd , command - > summary ) ;
2003-02-06 22:11:43 +00:00
2007-09-18 22:43:45 +00:00
stringp = command - > usage ;
2003-02-06 22:11:43 +00:00
tempstr = strsep ( & stringp , " \n " ) ;
2007-02-16 11:47:48 +00:00
fprintf ( htmlfile , " <TR><TD ALIGN= \" CENTER \" > " ) ;
write_html_escaped ( htmlfile , tempstr ) ;
fprintf ( htmlfile , " </TD></TR> \n " ) ;
2003-02-06 22:11:43 +00:00
fprintf ( htmlfile , " <TR><TD ALIGN= \" CENTER \" > \n " ) ;
2007-09-18 22:43:45 +00:00
2007-02-16 11:47:48 +00:00
while ( ( tempstr = strsep ( & stringp , " \n " ) ) ! = NULL ) {
write_html_escaped ( htmlfile , tempstr ) ;
fprintf ( htmlfile , " <BR> \n " ) ;
}
2003-02-06 22:11:43 +00:00
fprintf ( htmlfile , " </TD></TR> \n " ) ;
fprintf ( htmlfile , " </TABLE></TD></TR> \n \n " ) ;
}
2007-07-23 22:02:05 +00:00
AST_RWLIST_UNLOCK ( & agi_commands ) ;
2003-02-06 22:11:43 +00:00
fprintf ( htmlfile , " </TABLE> \n </BODY> \n </HTML> \n " ) ;
fclose ( htmlfile ) ;
2007-09-18 22:43:45 +00:00
ast_cli ( a - > fd , " AGI HTML commands dumped to: %s \n " , a - > argv [ 2 ] ) ;
return CLI_SUCCESS ;
2003-02-06 22:11:43 +00:00
}
2004-03-03 18:58:57 +00:00
static int agi_exec_full ( struct ast_channel * chan , void * data , int enhanced , int dead )
2001-09-28 13:19:43 +00:00
{
2006-05-25 16:44:22 +00:00
enum agi_result res ;
2006-08-21 02:11:39 +00:00
struct ast_module_user * u ;
2007-09-11 15:28:46 +00:00
char buf [ AGI_BUF_LEN ] = " " , * tmp = buf ;
2007-07-23 20:27:26 +00:00
int fds [ 2 ] , efd = - 1 , pid ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( arg ) [ MAX_ARGS ] ;
) ;
2003-02-23 06:00:11 +00:00
AGI agi ;
2005-01-08 19:35:20 +00:00
2005-11-08 01:55:31 +00:00
if ( ast_strlen_zero ( data ) ) {
2001-09-28 13:19:43 +00:00
ast_log ( LOG_WARNING , " AGI requires an argument (script) \n " ) ;
return - 1 ;
}
2007-07-23 22:02:05 +00:00
if ( dead )
2007-11-28 15:38:03 +00:00
ast_log ( LOG_NOTICE , " Hungup channel detected, running agi in dead mode. \n " ) ;
2005-07-10 23:21:39 +00:00
ast_copy_string ( buf , data , sizeof ( buf ) ) ;
2003-02-23 06:00:11 +00:00
memset ( & agi , 0 , sizeof ( agi ) ) ;
2007-07-23 20:27:26 +00:00
AST_STANDARD_APP_ARGS ( args , tmp ) ;
args . argv [ args . argc ] = NULL ;
2004-03-23 12:50:15 +00:00
2006-08-21 02:11:39 +00:00
u = ast_module_user_add ( chan ) ;
2002-06-14 15:50:42 +00:00
#if 0
2001-09-28 13:19:43 +00:00
/* Answer if need be */
2007-07-23 22:02:05 +00:00
if ( chan - > _state ! = AST_STATE_UP ) {
2001-09-28 13:19:43 +00:00
if ( ast_answer ( chan ) ) {
LOCAL_USER_REMOVE ( u ) ;
return - 1 ;
}
}
2002-06-14 15:50:42 +00:00
# endif
2007-07-23 20:27:26 +00:00
res = launch_script ( args . argv [ 0 ] , args . argv , fds , enhanced ? & efd : NULL , & pid ) ;
2007-09-18 22:46:05 +00:00
if ( res = = AGI_RESULT_SUCCESS | | res = = AGI_RESULT_SUCCESS_FAST ) {
2006-05-25 18:31:19 +00:00
int status = 0 ;
2003-02-23 06:00:11 +00:00
agi . fd = fds [ 1 ] ;
agi . ctrl = fds [ 0 ] ;
agi . audio = efd ;
2007-09-18 22:46:05 +00:00
agi . fast = ( res = = AGI_RESULT_SUCCESS_FAST ) ? 1 : 0 ;
2007-07-23 20:27:26 +00:00
res = run_agi ( chan , args . argv [ 0 ] , & agi , pid , & status , dead , args . argc , args . argv ) ;
2006-05-25 18:31:19 +00:00
/* If the fork'd process returns non-zero, set AGISTATUS to FAILURE */
2007-09-18 22:46:05 +00:00
if ( ( res = = AGI_RESULT_SUCCESS | | res = = AGI_RESULT_SUCCESS_FAST ) & & status )
2006-05-25 18:31:19 +00:00
res = AGI_RESULT_FAILURE ;
2006-09-06 20:04:17 +00:00
if ( fds [ 1 ] ! = fds [ 0 ] )
close ( fds [ 1 ] ) ;
2003-02-23 06:00:11 +00:00
if ( efd > - 1 )
close ( efd ) ;
2006-05-25 18:31:19 +00:00
ast_unreplace_sigchld ( ) ;
2001-09-28 13:19:43 +00:00
}
2006-08-21 02:11:39 +00:00
ast_module_user_remove ( u ) ;
2006-05-25 16:44:22 +00:00
switch ( res ) {
case AGI_RESULT_SUCCESS :
2007-09-18 22:46:05 +00:00
case AGI_RESULT_SUCCESS_FAST :
2006-05-25 16:44:22 +00:00
pbx_builtin_setvar_helper ( chan , " AGISTATUS " , " SUCCESS " ) ;
break ;
case AGI_RESULT_FAILURE :
pbx_builtin_setvar_helper ( chan , " AGISTATUS " , " FAILURE " ) ;
break ;
2007-06-21 15:58:05 +00:00
case AGI_RESULT_NOTFOUND :
pbx_builtin_setvar_helper ( chan , " AGISTATUS " , " NOTFOUND " ) ;
break ;
2006-05-25 16:44:22 +00:00
case AGI_RESULT_HANGUP :
pbx_builtin_setvar_helper ( chan , " AGISTATUS " , " HANGUP " ) ;
return - 1 ;
}
return 0 ;
2001-09-28 13:19:43 +00:00
}
2003-02-23 06:00:11 +00:00
static int agi_exec ( struct ast_channel * chan , void * data )
{
2007-07-23 22:02:05 +00:00
if ( ! ast_check_hangup ( chan ) )
return agi_exec_full ( chan , data , 0 , 0 ) ;
else
return agi_exec_full ( chan , data , 0 , 1 ) ;
2003-02-23 06:00:11 +00:00
}
static int eagi_exec ( struct ast_channel * chan , void * data )
{
2007-07-11 21:09:42 +00:00
int readformat , res ;
2005-01-08 19:35:20 +00:00
2007-07-19 15:59:19 +00:00
if ( ast_check_hangup ( chan ) ) {
ast_log ( LOG_ERROR , " If you want to run AGI on hungup channels you should use DeadAGI! \n " ) ;
return 0 ;
}
2003-02-23 06:00:11 +00:00
readformat = chan - > readformat ;
2004-04-06 22:17:32 +00:00
if ( ast_set_read_format ( chan , AST_FORMAT_SLINEAR ) ) {
2003-02-23 06:00:11 +00:00
ast_log ( LOG_WARNING , " Unable to set channel '%s' to linear mode \n " , chan - > name ) ;
return - 1 ;
}
2004-03-03 18:58:57 +00:00
res = agi_exec_full ( chan , data , 1 , 0 ) ;
2003-02-23 06:00:11 +00:00
if ( ! res ) {
2004-04-06 22:17:32 +00:00
if ( ast_set_read_format ( chan , readformat ) ) {
2003-08-16 05:10:35 +00:00
ast_log ( LOG_WARNING , " Unable to restore channel '%s' to format %s \n " , chan - > name , ast_getformatname ( readformat ) ) ;
2003-02-23 06:00:11 +00:00
}
}
return res ;
}
2004-03-03 18:58:57 +00:00
static int deadagi_exec ( struct ast_channel * chan , void * data )
{
2007-11-28 15:38:03 +00:00
ast_log ( LOG_WARNING , " DeadAGI has been deprecated, please use AGI in all cases! \n " ) ;
2007-07-23 22:02:05 +00:00
return agi_exec ( chan , data ) ;
2004-03-03 18:58:57 +00:00
}
2006-09-18 19:54:18 +00:00
static struct ast_cli_entry cli_agi [ ] = {
2007-10-22 20:05:18 +00:00
AST_CLI_DEFINE ( handle_cli_agi_debug , " Enable/Disable AGI debugging " ) ,
AST_CLI_DEFINE ( handle_cli_agi_show , " List AGI commands or specific help " ) ,
AST_CLI_DEFINE ( handle_cli_agi_dumphtml , " Dumps a list of AGI commands in HTML format " )
2006-09-18 19:54:18 +00:00
} ;
2003-02-06 22:11:43 +00:00
2006-08-21 02:11:39 +00:00
static int unload_module ( void )
2001-09-28 13:19:43 +00:00
{
2006-09-18 19:54:18 +00:00
ast_cli_unregister_multiple ( cli_agi , sizeof ( cli_agi ) / sizeof ( struct ast_cli_entry ) ) ;
2007-07-30 19:11:28 +00:00
ast_agi_unregister_multiple ( ast_module_info - > self , commands , sizeof ( commands ) / sizeof ( struct agi_command ) ) ;
2003-02-23 06:00:11 +00:00
ast_unregister_application ( eapp ) ;
2004-03-03 18:58:57 +00:00
ast_unregister_application ( deadapp ) ;
2001-09-28 13:19:43 +00:00
return ast_unregister_application ( app ) ;
}
2006-08-21 02:11:39 +00:00
static int load_module ( void )
2001-09-28 13:19:43 +00:00
{
2006-09-18 19:54:18 +00:00
ast_cli_register_multiple ( cli_agi , sizeof ( cli_agi ) / sizeof ( struct ast_cli_entry ) ) ;
2007-07-30 19:11:28 +00:00
ast_agi_register_multiple ( ast_module_info - > self , commands , sizeof ( commands ) / sizeof ( struct agi_command ) ) ;
2004-03-03 18:58:57 +00:00
ast_register_application ( deadapp , deadagi_exec , deadsynopsis , descrip ) ;
2004-01-30 05:37:39 +00:00
ast_register_application ( eapp , eagi_exec , esynopsis , descrip ) ;
2001-09-28 13:19:43 +00:00
return ast_register_application ( app , agi_exec , synopsis , descrip ) ;
}
2007-05-20 18:01:05 +00:00
AST_MODULE_INFO ( ASTERISK_GPL_KEY , AST_MODFLAG_GLOBAL_SYMBOLS , " Asterisk Gateway Interface (AGI) " ,
2007-07-23 22:02:05 +00:00
. load = load_module ,
. unload = unload_module ,
2007-05-20 18:01:05 +00:00
) ;