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
*/
2004-09-28 14:14:00 +00:00
# include <sys/types.h>
2004-09-26 17:01:39 +00:00
# include <netdb.h>
# include <sys/socket.h>
# include <netinet/in.h>
# include <netinet/tcp.h>
# include <arpa/inet.h>
2001-09-28 13:19:43 +00:00
# include <math.h>
# include <stdlib.h>
# include <unistd.h>
# include <string.h>
# include <stdlib.h>
2003-09-08 16:48:07 +00:00
# include <signal.h>
2001-09-28 13:19:43 +00:00
# include <sys/time.h>
2003-02-06 22:11:43 +00:00
# include <stdio.h>
# include <fcntl.h>
# include <errno.h>
2005-06-06 22:12:19 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
# include "asterisk/file.h"
# include "asterisk/logger.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/logger.h"
# include "asterisk/options.h"
# include "asterisk/image.h"
# include "asterisk/say.h"
# include "asterisk/app.h"
# include "asterisk/dsp.h"
# include "asterisk/musiconhold.h"
# include "asterisk/manager.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"
2001-09-28 13:19:43 +00:00
# define MAX_ARGS 128
2004-07-17 20:12:28 +00:00
# define MAX_COMMANDS 128
2001-09-28 13:19:43 +00:00
/* Recycle some stuff from the CLI interface */
2004-09-25 14:22:27 +00:00
# define fdprintf agi_debug_cli
2001-09-28 13:19:43 +00:00
static char * tdesc = " Asterisk Gateway Interface (AGI) " ;
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 =
2004-03-03 18:58:57 +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 "
2004-03-03 18:58:57 +00:00
" Returns -1 on hangup (except for DeadAGI) or if application requested \n "
" hangup, or 0 on non-hangup exit. \n "
2004-01-30 05:37:39 +00:00
" Using 'EAGI' provides enhanced AGI, with incoming audio available out of band "
" on file descriptor 3 \n \n "
" Use the CLI command 'show agi' to list available agi commands \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
LOCAL_USER_DECL ;
# 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
2004-09-25 14:22:27 +00:00
static void agi_debug_cli ( int fd , char * fmt , . . . )
{
char * stuff ;
int res = 0 ;
va_list ap ;
va_start ( ap , fmt ) ;
res = vasprintf ( & stuff , fmt , ap ) ;
va_end ( ap ) ;
if ( res = = - 1 ) {
ast_log ( LOG_ERROR , " Out of memory \n " ) ;
} else {
if ( agidebug )
ast_verbose ( " AGI Tx >> %s " , stuff ) ;
ast_carefulwrite ( fd , stuff , strlen ( stuff ) , 100 ) ;
free ( stuff ) ;
}
}
2005-01-08 19:35:20 +00:00
/* launch_netscript: The fastagi handler.
FastAGI defaults to port 4573 */
2004-09-22 15:21:36 +00:00
static int launch_netscript ( char * agiurl , char * argv [ ] , int * fds , int * efd , int * opid )
{
int s ;
int flags ;
struct pollfd pfds [ 1 ] ;
char * host ;
char * c ; int port = AGI_PORT ;
2005-01-09 09:01:40 +00:00
char * 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
host = ast_strdupa ( agiurl + 6 ) ; /* Remove agi:// */
2004-09-22 15:21:36 +00:00
if ( ! host )
return - 1 ;
/* 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 ;
}
hp = ast_gethostbyname ( host , & ahp ) ;
if ( ! hp ) {
ast_log ( LOG_WARNING , " Unable to locate host '%s' \n " , host ) ;
return - 1 ;
}
s = socket ( AF_INET , SOCK_STREAM , 0 ) ;
if ( s < 0 ) {
ast_log ( LOG_WARNING , " Unable to create socket: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
flags = fcntl ( s , F_GETFL ) ;
if ( flags < 0 ) {
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 ) ;
return - 1 ;
}
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-02-15 00:38:27 +00:00
while ( poll ( pfds , 1 , MAX_AGI_CONNECT ) ! = 1 ) {
if ( errno ! = EINTR ) {
ast_log ( LOG_WARNING , " Connect to '%s' failed: %s \n " , agiurl , strerror ( errno ) ) ;
close ( s ) ;
return - 1 ;
}
2004-09-22 15:21:36 +00:00
}
2006-02-15 00:38:27 +00:00
while ( write ( s , " agi_network: yes \n " , strlen ( " agi_network: yes \n " ) ) < 0 ) {
if ( errno ! = EINTR ) {
ast_log ( LOG_WARNING , " Connect to '%s' failed: %s \n " , agiurl , strerror ( errno ) ) ;
close ( s ) ;
return - 1 ;
}
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 */
if ( ! ast_strlen_zero ( script ) )
fdprintf ( s , " agi_network_script: %s \n " , script ) ;
if ( option_debug > 3 )
ast_log ( LOG_DEBUG , " Wow, connected! \n " ) ;
2004-09-22 15:21:36 +00:00
fds [ 0 ] = s ;
fds [ 1 ] = s ;
* opid = - 1 ;
return 0 ;
}
2004-03-23 12:50:15 +00:00
static int launch_script ( char * script , char * argv [ ] , int * fds , int * efd , int * opid )
2001-09-28 13:19:43 +00:00
{
char tmp [ 256 ] ;
int pid ;
int toast [ 2 ] ;
int fromast [ 2 ] ;
2003-02-23 06:00:11 +00:00
int audio [ 2 ] ;
2001-09-28 13:19:43 +00:00
int x ;
2003-02-23 06:00:11 +00:00
int res ;
2005-08-03 04:17:12 +00:00
sigset_t signal_set ;
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 ] ! = ' / ' ) {
2003-02-06 22:11:43 +00:00
snprintf ( tmp , sizeof ( tmp ) , " %s/%s " , ( char * ) ast_config_AST_AGI_DIR , script ) ;
2001-09-28 13:19:43 +00:00
script = tmp ;
}
if ( pipe ( toast ) ) {
ast_log ( LOG_WARNING , " Unable to create toast pipe: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
if ( pipe ( fromast ) ) {
ast_log ( LOG_WARNING , " unable to create fromast pipe: %s \n " , strerror ( errno ) ) ;
close ( toast [ 0 ] ) ;
close ( toast [ 1 ] ) ;
return - 1 ;
}
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 ] ) ;
return - 1 ;
}
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 ] ) ;
return - 1 ;
}
}
2001-09-28 13:19:43 +00:00
pid = fork ( ) ;
if ( pid < 0 ) {
ast_log ( LOG_WARNING , " Failed to fork(): %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
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 ) ;
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 ) ;
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 ) ;
2003-02-23 06:00:11 +00:00
if ( efd ) {
dup2 ( audio [ 0 ] , STDERR_FILENO + 1 ) ;
} else {
close ( STDERR_FILENO + 1 ) ;
}
2005-08-03 04:17:12 +00:00
/* unblock important signal handlers */
if ( sigfillset ( & signal_set ) | | pthread_sigmask ( SIG_UNBLOCK , & signal_set , NULL ) ) {
ast_log ( LOG_WARNING , " unable to unblock signals for AGI script: %s \n " , strerror ( errno ) ) ;
exit ( 1 ) ;
}
2001-09-28 13:19:43 +00:00
/* Close everything but stdin/out/error */
2003-02-23 06:00:11 +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
2005-08-23 01:30:22 +00:00
/* Don't run AGI scripts with realtime priority -- it causes audio stutter */
ast_set_priority ( 0 ) ;
2001-09-28 13:19:43 +00:00
/* Execute script */
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 ) ;
2001-09-28 13:19:43 +00:00
exit ( 1 ) ;
}
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Launched AGI Script %s \n " , script ) ;
fds [ 0 ] = toast [ 0 ] ;
fds [ 1 ] = fromast [ 1 ] ;
2003-02-23 06:00:11 +00:00
if ( efd ) {
* 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
2004-01-01 00:26:11 +00:00
if ( efd ) {
2004-12-18 22:04:07 +00:00
/* [PHM 12/18/03] */
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 ;
return 0 ;
}
2003-02-23 06:00:11 +00:00
static void setup_env ( struct ast_channel * chan , char * request , int fd , int enhanced )
2001-09-28 13:19:43 +00:00
{
/* Print initial environment, with agi_request always being the first
thing */
fdprintf ( fd , " agi_request: %s \n " , request ) ;
fdprintf ( fd , " agi_channel: %s \n " , chan - > name ) ;
fdprintf ( fd , " agi_language: %s \n " , chan - > language ) ;
2006-02-01 23:05:28 +00:00
fdprintf ( fd , " agi_type: %s \n " , chan - > tech - > type ) ;
2003-06-26 01:20:45 +00:00
fdprintf ( fd , " agi_uniqueid: %s \n " , chan - > uniqueid ) ;
2001-09-28 13:19:43 +00:00
/* ANI/DNIS */
2004-10-02 00:58:31 +00:00
fdprintf ( fd , " agi_callerid: %s \n " , chan - > cid . cid_num ? chan - > cid . cid_num : " unknown " ) ;
fdprintf ( fd , " agi_calleridname: %s \n " , chan - > cid . cid_name ? chan - > cid . cid_name : " unknown " ) ;
2005-03-24 16:38:13 +00:00
fdprintf ( fd , " agi_callingpres: %d \n " , chan - > cid . cid_pres ) ;
fdprintf ( fd , " agi_callingani2: %d \n " , chan - > cid . cid_ani2 ) ;
fdprintf ( fd , " agi_callington: %d \n " , chan - > cid . cid_ton ) ;
fdprintf ( fd , " agi_callingtns: %d \n " , chan - > cid . cid_tns ) ;
2004-10-02 00:58:31 +00:00
fdprintf ( fd , " agi_dnid: %s \n " , chan - > cid . cid_dnid ? chan - > cid . cid_dnid : " unknown " ) ;
fdprintf ( fd , " agi_rdnis: %s \n " , chan - > cid . cid_rdnis ? chan - > cid . cid_rdnis : " unknown " ) ;
2001-09-28 13:19:43 +00:00
/* Context information */
fdprintf ( fd , " agi_context: %s \n " , chan - > context ) ;
fdprintf ( fd , " agi_extension: %s \n " , chan - > exten ) ;
fdprintf ( fd , " agi_priority: %d \n " , chan - > priority ) ;
2003-02-23 06:00:11 +00:00
fdprintf ( 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 */
fdprintf ( fd , " agi_accountcode: %s \n " , chan - > accountcode ? chan - > accountcode : " " ) ;
2003-07-14 14:39:52 +00:00
2001-09-28 13:19:43 +00:00
/* End with empty return */
fdprintf ( fd , " \n " ) ;
}
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
{
int res ;
res = 0 ;
2002-09-04 16:53:39 +00:00
if ( chan - > _state ! = AST_STATE_UP ) {
2002-06-14 15:50:42 +00:00
/* Answer the chan */
res = ast_answer ( chan ) ;
}
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
2002-06-14 15:50:42 +00:00
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
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
{
int res ;
int to ;
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 ) ;
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
2001-09-28 13:19:43 +00:00
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
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 ;
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
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 ] ) ;
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
2001-09-28 13:19:43 +00:00
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
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 ;
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
res = ast_recvchar ( chan , atoi ( argv [ 2 ] ) ) ;
if ( res = = 0 ) {
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=%d (timeout) \n " , res ) ;
2001-12-27 11:07:33 +00:00
return RESULT_SUCCESS ;
}
if ( res > 0 ) {
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
2001-12-27 11:07:33 +00:00
return RESULT_SUCCESS ;
}
else {
2003-02-23 06:00:11 +00:00
fdprintf ( 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 ;
buf = ast_recvtext ( chan , atoi ( argv [ 2 ] ) ) ;
if ( buf ) {
fdprintf ( agi - > fd , " 200 result=1 (%s) \n " , buf ) ;
free ( buf ) ;
} else {
fdprintf ( agi - > fd , " 200 result=-1 \n " ) ;
}
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
{
int res , x ;
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
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 )
2005-06-05 21:00:33 +00:00
fdprintf ( agi - > fd , " 200 result=0 \n " ) ;
2001-12-27 11:07:33 +00:00
else
2005-06-05 21:00:33 +00:00
fdprintf ( agi - > fd , " 200 result=1 \n " ) ;
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 ;
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
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 ;
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
2001-09-28 13:19:43 +00:00
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
2005-08-22 21:59:24 +00:00
static int handle_controlstreamfile ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
int res = 0 ;
int skipms = 3000 ;
char * fwd = NULL ;
char * rev = NULL ;
char * pause = NULL ;
char * stop = NULL ;
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 ;
if ( argc > 6 & & ! ast_strlen_zero ( argv [ 8 ] ) )
fwd = argv [ 6 ] ;
else
fwd = " # " ;
if ( argc > 7 & & ! ast_strlen_zero ( argv [ 8 ] ) )
rev = argv [ 7 ] ;
else
rev = " * " ;
if ( argc > 8 & & ! ast_strlen_zero ( argv [ 8 ] ) )
pause = argv [ 8 ] ;
else
pause = NULL ;
res = ast_control_streamfile ( chan , argv [ 3 ] , fwd , rev , stop , pause , NULL , skipms ) ;
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
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
{
int res ;
2003-02-06 22:11:43 +00:00
struct ast_filestream * fs ;
long sample_offset = 0 ;
long max_length ;
if ( argc < 4 )
return RESULT_SHOWUSAGE ;
if ( argc > 5 )
2001-09-28 13:19:43 +00:00
return RESULT_SHOWUSAGE ;
2003-02-06 22:11:43 +00:00
if ( ( argc > 4 ) & & ( sscanf ( argv [ 4 ] , " %ld " , & sample_offset ) ! = 1 ) )
return RESULT_SHOWUSAGE ;
fs = ast_openstream ( chan , argv [ 2 ] , chan - > language ) ;
2005-08-03 04:17:12 +00:00
if ( ! fs ) {
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=%d endpos=%ld \n " , 0 , sample_offset ) ;
2004-12-31 21:52:56 +00:00
return RESULT_SUCCESS ;
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 ) ;
res = ast_playstream ( fs ) ;
2001-09-28 13:19:43 +00:00
if ( res ) {
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=%d endpos=%ld \n " , res , sample_offset ) ;
2001-09-28 13:19:43 +00:00
if ( res > = 0 )
return RESULT_SHOWUSAGE ;
else
return RESULT_FAILURE ;
}
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 ;
}
fdprintf ( agi - > fd , " 200 result=%d endpos=%ld \n " , res , sample_offset ) ;
2001-09-28 13:19:43 +00:00
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
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 [ ] )
{
int res ;
struct ast_filestream * fs ;
long sample_offset = 0 ;
long max_length ;
int timeout = 0 ;
char * edigits = NULL ;
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
}
fs = ast_openstream ( chan , argv [ 2 ] , chan - > language ) ;
2005-08-03 04:17:12 +00:00
if ( ! fs ) {
2004-11-16 03:37:07 +00:00
fdprintf ( agi - > fd , " 200 result=%d endpos=%ld \n " , 0 , sample_offset ) ;
ast_log ( LOG_WARNING , " Unable to open %s \n " , argv [ 2 ] ) ;
2005-03-26 05:33:48 +00:00
return RESULT_SUCCESS ;
2004-11-16 03:37:07 +00:00
}
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Playing '%s' (escape_digits=%s) (timeout %d) \n " , argv [ 2 ] , edigits , timeout ) ;
ast_seekstream ( fs , 0 , SEEK_END ) ;
max_length = ast_tellstream ( fs ) ;
ast_seekstream ( fs , sample_offset , SEEK_SET ) ;
res = ast_applystream ( chan , fs ) ;
res = ast_playstream ( fs ) ;
if ( res ) {
fdprintf ( agi - > fd , " 200 result=%d endpos=%ld \n " , res , sample_offset ) ;
if ( res > = 0 )
return RESULT_SHOWUSAGE ;
else
return RESULT_FAILURE ;
}
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 ;
}
/* 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 ) )
res = 0 ;
}
fdprintf ( agi - > fd , " 200 result=%d endpos=%ld \n " , res , sample_offset ) ;
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
2004-05-15 15:34:31 +00:00
/*--- handle_saynumber: Say number in various language syntaxes ---*/
/* Need to add option for gender here as well. Coders wanted */
/* While waiting, we're sending a (char *) 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
{
int res ;
int num ;
if ( argc ! = 4 )
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 ;
2004-05-15 15:34:31 +00:00
res = ast_say_number_full ( chan , num , argv [ 3 ] , chan - > language , ( char * ) NULL , agi - > audio , agi - > ctrl ) ;
2003-02-23 06:00:11 +00:00
if ( res = = 1 )
return RESULT_SUCCESS ;
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
2001-09-28 13:19:43 +00:00
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
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
{
int res ;
int 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 ;
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
2002-06-14 15:50:42 +00:00
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
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 ;
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
2005-03-30 07:00:49 +00:00
static int handle_saydate ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
int res ;
int num ;
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 ;
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
2004-02-27 08:30:30 +00:00
static int handle_saytime ( struct ast_channel * chan , AGI * agi , int argc , char * argv [ ] )
{
int res ;
int num ;
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 ;
fdprintf ( 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 [ ] )
{
int res = 0 ;
2006-02-15 00:24:24 +00:00
time_t unixtime ;
2005-04-11 03:23:54 +00:00
char * format , * zone = NULL ;
if ( argc < 4 )
return RESULT_SHOWUSAGE ;
if ( argc > 4 ) {
format = argv [ 4 ] ;
} else {
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-15 00:24:24 +00:00
if ( ast_get_time_t ( argv [ 2 ] , & unixtime , 0 ) )
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 ;
fdprintf ( 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 ;
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
if ( res > = 0 )
return RESULT_SUCCESS ;
else
return RESULT_FAILURE ;
}
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
{
int res ;
2003-02-14 06:00:11 +00:00
char data [ 1024 ] ;
2001-09-28 13:19:43 +00:00
int max ;
int timeout ;
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 )
fdprintf ( agi - > fd , " 200 result=%s (timeout) \n " , data ) ;
2004-06-04 19:01:07 +00:00
else if ( res < 0 )
fdprintf ( agi - > fd , " 200 result=-1 \n " ) ;
2001-09-28 13:19:43 +00:00
else
2003-02-23 06:00:11 +00:00
fdprintf ( 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 ) ) ;
2003-02-23 06:00:11 +00:00
fdprintf ( 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 ) ) ;
2003-02-23 06:00:11 +00:00
fdprintf ( 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 ;
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 ) ;
2003-02-23 06:00:11 +00:00
fdprintf ( 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
2003-08-15 04:38:39 +00:00
struct ast_dsp * sildet = NULL ; /* silence detector dsp */
2003-05-01 03:52:45 +00:00
int totalsilence = 0 ;
int dspsilence = 0 ;
int silence = 0 ; /* amount of silence to allow */
int gotsilence = 0 ; /* did we timeout for silence? */
2003-08-15 04:38:39 +00:00
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 )
silence = atoi ( silencestr ) ;
if ( silence > 0 )
silence * = 1000 ;
}
}
}
if ( silence > 0 ) {
rfmt = chan - > readformat ;
2004-04-06 22:17:32 +00:00
res = ast_set_read_format ( chan , AST_FORMAT_SLINEAR ) ;
2003-05-01 03:52:45 +00:00
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-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 ) {
fdprintf ( agi - > fd , " 200 result=%d (randomerror) endpos=%ld \n " , res , sample_offset ) ;
} else {
2003-10-22 03:37:47 +00:00
fs = ast_writefile ( argv [ 2 ] , argv [ 3 ] , NULL , O_CREAT | O_WRONLY | ( sample_offset ? O_APPEND : 0 ) , 0 , 0644 ) ;
2002-09-04 16:53:39 +00:00
if ( ! fs ) {
res = - 1 ;
2003-02-23 06:00:11 +00:00
fdprintf ( 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
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 ) ;
2003-02-23 06:00:11 +00:00
fdprintf ( 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 ) {
2003-02-23 06:00:11 +00:00
fdprintf ( 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 ) ;
2003-02-23 06:00:11 +00:00
fdprintf ( 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 ) ;
2003-05-01 03:52:45 +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 */
ast_frfree ( f ) ;
gotsilence = 1 ;
break ;
}
}
2001-09-28 13:19:43 +00:00
break ;
}
ast_frfree ( f ) ;
2003-05-01 03:52:45 +00:00
if ( gotsilence )
break ;
2005-01-08 19:35:20 +00:00
}
2003-05-01 03:52:45 +00:00
if ( gotsilence ) {
ast_stream_rewind ( fs , silence - 1000 ) ;
ast_truncstream ( fs ) ;
2004-03-12 18:49:52 +00:00
sample_offset = ast_tellstream ( fs ) ;
2003-05-01 03:52:45 +00:00
}
2003-02-23 06:00:11 +00:00
fdprintf ( 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
if ( silence > 0 ) {
2004-04-06 22:17:32 +00:00
res = ast_set_read_format ( chan , rfmt ) ;
2003-05-01 03:52:45 +00:00
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 ;
2003-02-23 06:00:11 +00:00
fdprintf ( 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 ;
if ( argc = = 1 ) {
/* no argument: hangup the current channel */
ast_softhangup ( chan , AST_SOFTHANGUP_EXPLICIT ) ;
fdprintf ( agi - > fd , " 200 result=1 \n " ) ;
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 ) ;
fdprintf ( agi - > fd , " 200 result=1 \n " ) ;
2005-01-08 19:35:20 +00:00
ast_mutex_unlock ( & c - > lock ) ;
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 */
fdprintf ( agi - > fd , " 200 result=-1 \n " ) ;
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 ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " AGI Script Executing Application: (%s) Options: (%s) \n " , argv [ 1 ] , argv [ 2 ] ) ;
app = pbx_findapp ( argv [ 1 ] ) ;
if ( app ) {
2004-10-17 05:16:22 +00:00
res = pbx_exec ( chan , app , argv [ 2 ] , 1 ) ;
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
}
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=%d \n " , res ) ;
2002-09-04 16:53:39 +00:00
return res ;
}
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
2004-06-04 19:01:07 +00:00
fdprintf ( 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 */
fdprintf ( agi - > fd , " 200 result=%d \n " , chan - > _state ) ;
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 ) {
fdprintf ( agi - > fd , " 200 result=%d \n " , c - > _state ) ;
2004-06-04 19:01:07 +00:00
ast_mutex_unlock ( & c - > lock ) ;
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 */
fdprintf ( agi - > fd , " 200 result=-1 \n " ) ;
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 ] ) ;
2003-02-23 06:00:11 +00:00
fdprintf ( 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
{
2004-12-23 02:47:01 +00:00
char * ret ;
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 */
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 ;
2005-08-22 23:00:23 +00:00
} else {
pbx_retrieve_variable ( chan , argv [ 2 ] , & ret , tempstr , sizeof ( tempstr ) , NULL ) ;
}
2004-12-23 02:47:01 +00:00
if ( ret )
fdprintf ( agi - > fd , " 200 result=1 (%s) \n " , ret ) ;
2003-02-06 22:11:43 +00:00
else
2004-06-04 19:01:07 +00:00
fdprintf ( 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 )
{
2005-11-03 21:25:57 +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 ;
}
2005-06-06 02:29:18 +00:00
if ( chan ) { /* XXX isn't this chan2 ? */
2004-11-17 04:02:56 +00:00
pbx_substitute_variables_helper ( chan2 , argv [ 3 ] , tmp , sizeof ( tmp ) - 1 ) ;
fdprintf ( agi - > fd , " 200 result=1 (%s) \n " , tmp ) ;
} else {
fdprintf ( agi - > fd , " 200 result=0 \n " ) ;
}
if ( chan2 & & ( chan2 ! = chan ) )
ast_mutex_unlock ( & chan2 - > lock ) ;
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 ] ) ;
2003-02-23 06:00:11 +00:00
fdprintf ( 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 )
2004-06-04 19:01:07 +00:00
fdprintf ( agi - > fd , " 200 result=0 \n " ) ;
2003-02-06 22:11:43 +00:00
else
2004-06-04 19:01:07 +00:00
fdprintf ( 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 ] ) ;
if ( res )
2004-06-04 19:01:07 +00:00
fdprintf ( agi - > fd , " 200 result=0 \n " ) ;
2003-02-06 22:11:43 +00:00
else
2004-06-04 19:01:07 +00:00
fdprintf ( 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_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 ] ) ;
if ( res )
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=0 \n " ) ;
2003-02-06 22:11:43 +00:00
else
2003-02-23 06:00:11 +00:00
fdprintf ( 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_dbdeltree ( struct ast_channel * chan , AGI * agi , int argc , char * * argv )
2003-02-06 22:11:43 +00:00
{
int res ;
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 ) ;
if ( res )
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=0 \n " ) ;
2003-02-06 22:11:43 +00:00
else
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 200 result=1 \n " ) ;
return RESULT_SUCCESS ;
}
2004-09-25 14:22:27 +00:00
static char debug_usage [ ] =
" Usage: agi debug \n "
" Enables dumping of AGI transactions for debugging purposes \n " ;
static char no_debug_usage [ ] =
" Usage: agi no debug \n "
" Disables dumping of AGI transactions for debugging purposes \n " ;
static int agi_do_debug ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 2 )
return RESULT_SHOWUSAGE ;
agidebug = 1 ;
ast_cli ( fd , " AGI Debugging Enabled \n " ) ;
return RESULT_SUCCESS ;
}
static int agi_no_debug ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
agidebug = 0 ;
ast_cli ( fd , " AGI Debugging Disabled \n " ) ;
return RESULT_SUCCESS ;
}
static struct ast_cli_entry cli_debug =
{ { " agi " , " debug " , NULL } , agi_do_debug , " Enable AGI debugging " , debug_usage } ;
static struct ast_cli_entry cli_no_debug =
{ { " agi " , " no " , " debug " , NULL } , agi_no_debug , " Disable AGI debugging " , no_debug_usage } ;
2003-02-23 06:00:11 +00:00
static int handle_noop ( struct ast_channel * chan , AGI * agi , int arg , char * argv [ ] )
{
fdprintf ( 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 [ ] )
{
if ( ! strncasecmp ( argv [ 2 ] , " on " , 2 ) ) {
if ( argc > 3 )
ast_moh_start ( chan , argv [ 3 ] ) ;
else
ast_moh_start ( chan , NULL ) ;
}
if ( ! strncasecmp ( argv [ 2 ] , " off " , 3 ) ) {
ast_moh_stop ( chan ) ;
}
fdprintf ( agi - > fd , " 200 result=0 \n " ) ;
return RESULT_SUCCESS ;
}
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 [ ] =
" Usage: SAY NUMBER <number> <escape digits> \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
2004-07-17 20:12:28 +00:00
static agi_command commands [ MAX_COMMANDS ] = {
2004-12-28 23:01:22 +00:00
{ { " answer " , NULL } , handle_answer , " Answer channel " , usage_answer } ,
{ { " channel " , " status " , NULL } , handle_channelstatus , " Returns status of the connected channel " , usage_channelstatus } ,
{ { " database " , " del " , NULL } , handle_dbdel , " Removes database key/value " , usage_dbdel } ,
{ { " database " , " deltree " , NULL } , handle_dbdeltree , " Removes database keytree/value " , usage_dbdeltree } ,
{ { " database " , " get " , NULL } , handle_dbget , " Gets database value " , usage_dbget } ,
{ { " database " , " put " , NULL } , handle_dbput , " Adds/updates database value " , usage_dbput } ,
{ { " exec " , NULL } , handle_exec , " Executes a given Application " , usage_exec } ,
{ { " get " , " data " , NULL } , handle_getdata , " Prompts for DTMF on a channel " , usage_getdata } ,
{ { " get " , " full " , " variable " , NULL } , handle_getvariablefull , " Evaluates a channel expression " , usage_getvariablefull } ,
{ { " get " , " option " , NULL } , handle_getoption , " Stream file, prompt for DTMF, with timeout " , usage_getoption } ,
{ { " get " , " variable " , NULL } , handle_getvariable , " Gets a channel variable " , usage_getvariable } ,
{ { " hangup " , NULL } , handle_hangup , " Hangup the current channel " , usage_hangup } ,
{ { " noop " , NULL } , handle_noop , " Does nothing " , usage_noop } ,
2005-06-21 01:16:18 +00:00
{ { " receive " , " char " , NULL } , handle_recvchar , " Receives one character from channels supporting it " , usage_recvchar } ,
{ { " receive " , " text " , NULL } , handle_recvtext , " Receives text from channels supporting it " , usage_recvtext } ,
2004-12-28 23:01:22 +00:00
{ { " record " , " file " , NULL } , handle_recordfile , " Records to a given file " , usage_recordfile } ,
2004-12-14 18:39:25 +00:00
{ { " say " , " alpha " , NULL } , handle_sayalpha , " Says a given character string " , usage_sayalpha } ,
2004-12-28 23:01:22 +00:00
{ { " say " , " digits " , NULL } , handle_saydigits , " Says a given digit string " , usage_saydigits } ,
2001-09-28 13:19:43 +00:00
{ { " say " , " number " , NULL } , handle_saynumber , " Says a given number " , usage_saynumber } ,
2004-07-17 20:12:28 +00:00
{ { " say " , " phonetic " , NULL } , handle_sayphonetic , " Says a given character string with phonetics " , usage_sayphonetic } ,
2005-03-30 07:00:49 +00:00
{ { " say " , " date " , NULL } , handle_saydate , " Says a given date " , usage_saydate } ,
2004-02-27 08:30:30 +00:00
{ { " say " , " time " , NULL } , handle_saytime , " Says a given time " , usage_saytime } ,
2005-04-11 03:23:54 +00:00
{ { " say " , " datetime " , NULL } , handle_saydatetime , " Says a given time as specfied by the format given " , usage_saydatetime } ,
2004-12-28 23:01:22 +00:00
{ { " send " , " image " , NULL } , handle_sendimage , " Sends images to channels supporting it " , usage_sendimage } ,
{ { " send " , " text " , NULL } , handle_sendtext , " Sends text to channels supporting it " , usage_sendtext } ,
2002-09-04 16:53:39 +00:00
{ { " set " , " autohangup " , NULL } , handle_autohangup , " Autohangup channel in some time " , usage_autohangup } ,
{ { " set " , " callerid " , NULL } , handle_setcallerid , " Sets callerid for the current channel " , usage_setcallerid } ,
2004-12-28 23:01:22 +00:00
{ { " set " , " context " , NULL } , handle_setcontext , " Sets channel context " , usage_setcontext } ,
{ { " set " , " extension " , NULL } , handle_setextension , " Changes channel extension " , usage_setextension } ,
{ { " set " , " music " , NULL } , handle_setmusic , " Enable/Disable Music on hold generator " , usage_setmusic } ,
{ { " set " , " priority " , NULL } , handle_setpriority , " Set channel dialplan priority " , usage_setpriority } ,
2003-02-06 22:11:43 +00:00
{ { " set " , " variable " , NULL } , handle_setvariable , " Sets a channel variable " , usage_setvariable } ,
2004-12-28 23:01:22 +00:00
{ { " stream " , " file " , NULL } , handle_streamfile , " Sends audio file on channel " , usage_streamfile } ,
2005-08-22 21:59:24 +00:00
{ { " control " , " stream " , " file " , NULL } , handle_controlstreamfile , " Sends audio file on channel and allows the listner to control the stream " , usage_controlstreamfile } ,
2004-12-28 23:01:22 +00:00
{ { " tdd " , " mode " , NULL } , handle_tddmode , " Toggles TDD mode (for the deaf) " , usage_tddmode } ,
2003-02-06 22:11:43 +00:00
{ { " verbose " , NULL } , handle_verbose , " Logs a message to the asterisk verbose log " , usage_verbose } ,
2004-12-28 23:01:22 +00:00
{ { " wait " , " for " , " digit " , NULL } , handle_waitfordigit , " Waits for a digit to be pressed " , usage_waitfordigit } ,
2001-09-28 13:19:43 +00:00
} ;
2003-02-06 22:11:43 +00:00
static int help_workhorse ( int fd , char * match [ ] )
{
char fullcmd [ 80 ] ;
char matchstr [ 80 ] ;
int x ;
struct agi_command * e ;
if ( match )
2005-12-20 20:20:04 +00:00
ast_join ( matchstr , sizeof ( matchstr ) , match ) ;
2003-02-06 22:11:43 +00:00
for ( x = 0 ; x < sizeof ( commands ) / sizeof ( commands [ 0 ] ) ; x + + ) {
e = & commands [ x ] ;
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 ;
ast_cli ( fd , " %20.20s %s \n " , fullcmd , e - > summary ) ;
}
return 0 ;
}
2004-08-08 17:15:02 +00:00
int agi_register ( agi_command * agi )
2004-07-17 20:25:39 +00:00
{
int x ;
2005-01-08 19:35:20 +00:00
for ( x = 0 ; x < MAX_COMMANDS - 1 ; x + + ) {
2004-07-17 20:25:39 +00:00
if ( commands [ x ] . cmda [ 0 ] = = agi - > cmda [ 0 ] ) {
ast_log ( LOG_WARNING , " Command already registered! \n " ) ;
return - 1 ;
}
}
2005-01-08 19:35:20 +00:00
for ( x = 0 ; x < MAX_COMMANDS - 1 ; x + + ) {
2004-07-17 20:25:39 +00:00
if ( ! commands [ x ] . cmda [ 0 ] ) {
commands [ x ] = * agi ;
return 0 ;
}
}
ast_log ( LOG_WARNING , " No more room for new commands! \n " ) ;
return - 1 ;
}
2004-08-08 17:15:02 +00:00
void agi_unregister ( agi_command * agi )
2004-07-17 20:25:39 +00:00
{
int x ;
2005-01-08 19:35:20 +00:00
for ( x = 0 ; x < MAX_COMMANDS - 1 ; x + + ) {
2004-07-17 20:25:39 +00:00
if ( commands [ x ] . cmda [ 0 ] = = agi - > cmda [ 0 ] ) {
memset ( & commands [ x ] , 0 , sizeof ( agi_command ) ) ;
}
}
}
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
{
int x ;
int y ;
int match ;
2005-01-08 19:35:20 +00:00
for ( x = 0 ; x < sizeof ( commands ) / sizeof ( commands [ 0 ] ) ; x + + ) {
if ( ! commands [ x ] . cmda [ 0 ] )
break ;
2001-09-28 13:19:43 +00:00
/* start optimistic */
match = 1 ;
2005-01-08 19:35:20 +00:00
for ( y = 0 ; match & & cmds [ y ] ; y + + ) {
2001-09-28 13:19:43 +00:00
/* 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 */
2003-02-06 22:11:43 +00:00
if ( ! commands [ x ] . cmda [ y ] & & ! exact )
2001-09-28 13:19:43 +00:00
break ;
2003-02-18 18:15:30 +00:00
/* don't segfault if the next part of a command doesn't exist */
2005-01-08 19:35:20 +00:00
if ( ! commands [ x ] . cmda [ y ] )
return NULL ;
2001-09-28 13:19:43 +00:00
if ( strcasecmp ( commands [ x ] . cmda [ y ] , cmds [ y ] ) )
match = 0 ;
}
/* If more words are needed to complete the command then this is not
a candidate ( unless we ' re looking for a really inexact answer */
2003-02-06 22:11:43 +00:00
if ( ( exact > - 1 ) & & commands [ x ] . cmda [ y ] )
2001-09-28 13:19:43 +00:00
match = 0 ;
if ( match )
return & commands [ x ] ;
}
return NULL ;
}
static int parse_args ( char * s , int * max , char * argv [ ] )
{
int x = 0 ;
int quoted = 0 ;
int escaped = 0 ;
int whitespace = 1 ;
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 ;
}
2003-02-23 06:00:11 +00:00
static int agi_handle_command ( struct ast_channel * chan , AGI * agi , char * buf )
2001-09-28 13:19:43 +00:00
{
char * argv [ MAX_ARGS ] ;
2005-12-20 20:20:04 +00:00
int argc = MAX_ARGS ;
2001-09-28 13:19:43 +00:00
int res ;
agi_command * c ;
2005-01-08 19:35:20 +00:00
2001-09-28 13:19:43 +00:00
parse_args ( buf , & argc , argv ) ;
#if 0
{ int x ;
2005-01-08 19:35:20 +00:00
for ( x = 0 ; x < argc ; x + + )
2001-09-28 13:19:43 +00:00
fprintf ( stderr , " Got Arg%d: %s \n " , x , argv [ x ] ) ; }
# endif
2003-02-06 22:11:43 +00:00
c = find_command ( argv , 0 ) ;
2001-09-28 13:19:43 +00:00
if ( c ) {
2003-02-23 06:00:11 +00:00
res = c - > handler ( chan , agi , argc , argv ) ;
2001-09-28 13:19:43 +00:00
switch ( res ) {
case RESULT_SHOWUSAGE :
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 520-Invalid command syntax. Proper usage follows: \n " ) ;
fdprintf ( agi - > fd , c - > usage ) ;
fdprintf ( 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 ;
}
} else {
2003-02-23 06:00:11 +00:00
fdprintf ( agi - > fd , " 510 Invalid or unknown command \n " ) ;
2001-09-28 13:19:43 +00:00
}
return 0 ;
}
2003-11-05 23:43:31 +00:00
# define RETRY 3
2004-03-03 18:58:57 +00:00
static int run_agi ( struct ast_channel * chan , char * request , AGI * agi , int pid , int dead )
2001-09-28 13:19:43 +00:00
{
struct ast_channel * c ;
int outfd ;
int ms ;
int returnstatus = 0 ;
struct ast_frame * f ;
char buf [ 2048 ] ;
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 ) */
2003-11-05 23:43:31 +00:00
int retry = RETRY ;
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 ) ;
2001-09-28 13:19:43 +00:00
return - 1 ;
}
setlinebuf ( readf ) ;
2003-02-23 06:00:11 +00:00
setup_env ( chan , request , agi - > fd , ( agi - > audio > - 1 ) ) ;
2001-09-28 13:19:43 +00:00
for ( ; ; ) {
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 ) {
2003-11-05 23:43:31 +00:00
retry = RETRY ;
2001-09-28 13:19:43 +00:00
/* Idle the channel until we get a command */
f = ast_read ( c ) ;
if ( ! f ) {
ast_log ( LOG_DEBUG , " %s hungup \n " , chan - > name ) ;
returnstatus = - 1 ;
break ;
} 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 ) {
2003-11-05 23:43:31 +00:00
retry = RETRY ;
2001-09-28 13:19:43 +00:00
if ( ! fgets ( buf , sizeof ( buf ) , readf ) ) {
/* Program terminated */
if ( returnstatus )
returnstatus = - 1 ;
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " AGI Script %s completed, returning %d \n " , request , returnstatus ) ;
/* No need to kill the pid anymore, since they closed us */
pid = - 1 ;
break ;
}
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 )
ast_verbose ( " AGI Rx << %s \n " , buf ) ;
2003-02-23 06:00:11 +00:00
returnstatus | = agi_handle_command ( chan , agi , buf ) ;
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 ) ) {
2001-09-28 13:19:43 +00:00
break ;
}
} else {
2003-11-05 23:43:31 +00:00
if ( - - retry < = 0 ) {
ast_log ( LOG_WARNING , " No channel, no fd? \n " ) ;
returnstatus = - 1 ;
break ;
}
2001-09-28 13:19:43 +00:00
}
}
/* Notify process */
2005-08-03 04:17:12 +00:00
if ( pid > - 1 ) {
if ( kill ( pid , SIGHUP ) )
ast_log ( LOG_WARNING , " unable to send SIGHUP to AGI process %d: %s \n " , pid , strerror ( errno ) ) ;
}
2001-09-28 13:19:43 +00:00
fclose ( readf ) ;
return returnstatus ;
}
2003-02-06 22:11:43 +00:00
static int handle_showagi ( int fd , int argc , char * argv [ ] ) {
struct agi_command * e ;
char fullcmd [ 80 ] ;
if ( ( argc < 2 ) )
return RESULT_SHOWUSAGE ;
if ( argc > 2 ) {
e = find_command ( argv + 2 , 1 ) ;
if ( e )
ast_cli ( fd , e - > usage ) ;
else {
if ( find_command ( argv + 2 , - 1 ) ) {
return help_workhorse ( fd , argv + 1 ) ;
} else {
2005-12-20 20:20:04 +00:00
ast_join ( fullcmd , sizeof ( fullcmd ) , argv + 1 ) ;
2003-02-06 22:11:43 +00:00
ast_cli ( fd , " No such command '%s'. \n " , fullcmd ) ;
}
}
} else {
return help_workhorse ( fd , NULL ) ;
}
return RESULT_SUCCESS ;
}
static int handle_dumpagihtml ( int fd , int argc , char * argv [ ] ) {
struct agi_command * e ;
char fullcmd [ 80 ] ;
int x ;
FILE * htmlfile ;
if ( ( argc < 3 ) )
return RESULT_SHOWUSAGE ;
if ( ! ( htmlfile = fopen ( argv [ 2 ] , " wt " ) ) ) {
ast_cli ( fd , " Could not create file '%s' \n " , argv [ 2 ] ) ;
return RESULT_SHOWUSAGE ;
}
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 " ) ;
for ( x = 0 ; x < sizeof ( commands ) / sizeof ( commands [ 0 ] ) ; x + + ) {
2005-12-20 20:20:04 +00:00
char * stringp , * tempstr ;
2003-02-06 22:11:43 +00:00
e = & commands [ x ] ;
2005-12-20 20:20:04 +00:00
if ( ! e - > cmda [ 0 ] ) /* end ? */
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 ] = = ' _ ' )
2003-02-06 22:11:43 +00:00
continue ;
2005-12-20 20:20:04 +00:00
ast_join ( fullcmd , sizeof ( fullcmd ) , e - > cmda ) ;
2003-02-06 22:11:43 +00:00
fprintf ( htmlfile , " <TR><TD><TABLE BORDER= \" 1 \" CELLPADDING= \" 5 \" WIDTH= \" 100%% \" > \n " ) ;
fprintf ( htmlfile , " <TR><TH ALIGN= \" CENTER \" ><B>%s - %s</B></TD></TR> \n " , fullcmd , e - > summary ) ;
stringp = e - > usage ;
tempstr = strsep ( & stringp , " \n " ) ;
fprintf ( htmlfile , " <TR><TD ALIGN= \" CENTER \" >%s</TD></TR> \n " , tempstr ) ;
fprintf ( htmlfile , " <TR><TD ALIGN= \" CENTER \" > \n " ) ;
2005-12-20 20:20:04 +00:00
while ( ( tempstr = strsep ( & stringp , " \n " ) ) ! = NULL )
fprintf ( htmlfile , " %s<BR> \n " , tempstr ) ;
2003-02-06 22:11:43 +00:00
fprintf ( htmlfile , " </TD></TR> \n " ) ;
fprintf ( htmlfile , " </TABLE></TD></TR> \n \n " ) ;
}
fprintf ( htmlfile , " </TABLE> \n </BODY> \n </HTML> \n " ) ;
fclose ( htmlfile ) ;
ast_cli ( fd , " AGI HTML Commands Dumped to: %s \n " , argv [ 2 ] ) ;
return RESULT_SUCCESS ;
}
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
{
int res = 0 ;
struct localuser * u ;
2004-03-23 12:50:15 +00:00
char * argv [ MAX_ARGS ] ;
2004-05-22 04:52:50 +00:00
char buf [ 2048 ] = " " ;
char * tmp = ( char * ) buf ;
2004-03-23 12:50:15 +00:00
int argc = 0 ;
2001-09-28 13:19:43 +00:00
int fds [ 2 ] ;
2003-02-23 06:00:11 +00:00
int efd = - 1 ;
2001-09-28 13:19:43 +00:00
int pid ;
2004-03-23 12:50:15 +00:00
char * stringp ;
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 ;
}
2005-07-10 23:21:39 +00:00
ast_copy_string ( buf , data , sizeof ( buf ) ) ;
2001-09-28 13:19:43 +00:00
2003-02-23 06:00:11 +00:00
memset ( & agi , 0 , sizeof ( agi ) ) ;
2005-12-20 20:20:04 +00:00
while ( ( stringp = strsep ( & tmp , " | " ) ) & & argc < MAX_ARGS - 1 )
2004-03-23 12:50:15 +00:00
argv [ argc + + ] = stringp ;
argv [ argc ] = NULL ;
2001-09-28 13:19:43 +00:00
LOCAL_USER_ADD ( u ) ;
2002-06-14 15:50:42 +00:00
#if 0
2001-09-28 13:19:43 +00:00
/* Answer if need be */
2002-09-04 16:53:39 +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
2004-03-23 12:50:15 +00:00
res = launch_script ( argv [ 0 ] , argv , fds , enhanced ? & efd : NULL , & pid ) ;
2001-09-28 13:19:43 +00:00
if ( ! res ) {
2003-02-23 06:00:11 +00:00
agi . fd = fds [ 1 ] ;
agi . ctrl = fds [ 0 ] ;
agi . audio = efd ;
2004-05-22 04:52:50 +00:00
res = run_agi ( chan , argv [ 0 ] , & agi , pid , dead ) ;
2001-09-28 13:19:43 +00:00
close ( fds [ 1 ] ) ;
2003-02-23 06:00:11 +00:00
if ( efd > - 1 )
close ( efd ) ;
2001-09-28 13:19:43 +00:00
}
LOCAL_USER_REMOVE ( u ) ;
return res ;
}
2003-02-23 06:00:11 +00:00
static int agi_exec ( struct ast_channel * chan , void * data )
{
2004-04-15 21:01:55 +00:00
if ( chan - > _softhangup )
ast_log ( LOG_WARNING , " If you want to run AGI on hungup channels you should use DeadAGI! \n " ) ;
2004-03-03 18:58:57 +00:00
return agi_exec_full ( chan , data , 0 , 0 ) ;
2003-02-23 06:00:11 +00:00
}
static int eagi_exec ( struct ast_channel * chan , void * data )
{
int readformat ;
int res ;
2005-01-08 19:35:20 +00:00
2004-04-15 21:01:55 +00:00
if ( chan - > _softhangup )
ast_log ( LOG_WARNING , " If you want to run AGI on hungup channels you should use DeadAGI! \n " ) ;
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 )
{
return agi_exec_full ( chan , data , 0 , 1 ) ;
}
2003-02-06 22:11:43 +00:00
static char showagi_help [ ] =
" Usage: show agi [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 " ;
static char dumpagihtml_help [ ] =
" Usage: dump agihtml <filename> \n "
" Dumps the agi command list in html format to given filename \n " ;
2003-04-27 21:34:27 +00:00
static struct ast_cli_entry showagi =
2003-02-06 22:11:43 +00:00
{ { " show " , " agi " , NULL } , handle_showagi , " Show AGI commands or specific help " , showagi_help } ;
2003-04-27 21:34:27 +00:00
static struct ast_cli_entry dumpagihtml =
2003-02-06 22:11:43 +00:00
{ { " dump " , " agihtml " , NULL } , handle_dumpagihtml , " Dumps a list of agi command in html format " , dumpagihtml_help } ;
2001-09-28 13:19:43 +00:00
int unload_module ( void )
{
STANDARD_HANGUP_LOCALUSERS ;
2003-02-06 22:11:43 +00:00
ast_cli_unregister ( & showagi ) ;
ast_cli_unregister ( & dumpagihtml ) ;
2004-09-25 14:22:27 +00:00
ast_cli_unregister ( & cli_debug ) ;
ast_cli_unregister ( & cli_no_debug ) ;
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 ) ;
}
int load_module ( void )
{
2003-02-06 22:11:43 +00:00
ast_cli_register ( & showagi ) ;
ast_cli_register ( & dumpagihtml ) ;
2004-09-25 14:22:27 +00:00
ast_cli_register ( & cli_debug ) ;
ast_cli_register ( & cli_no_debug ) ;
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 ) ;
}
char * description ( void )
{
return tdesc ;
}
int usecount ( void )
{
int res ;
STANDARD_USECOUNT ( res ) ;
return res ;
}
char * key ( )
{
return ASTERISK_GPL_KEY ;
}