2002-09-12 18:32:42 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2002-09-12 18:32:42 +00:00
*
2006-01-03 22:16:23 +00:00
* Copyright ( C ) 1999 - 2006 , Digium , Inc .
2002-09-12 18:32:42 +00:00
*
2004-08-31 00:08:52 +00:00
* Mark Spencer < markster @ digium . com >
2002-09-12 18:32:42 +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 .
*
2002-09-12 18:32:42 +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 The Asterisk Management Interface - AMI
2005-09-14 20:46:50 +00:00
*
2005-12-30 21:18:06 +00:00
* \ author Mark Spencer < markster @ digium . com >
*
2005-09-14 20:46:50 +00:00
* Channel Management and more
*
2005-10-26 23:11:36 +00:00
* \ ref amiconf
2002-09-12 18:32:42 +00:00
*/
2005-11-14 19:00:38 +00:00
/*! \addtogroup Group_AMI AMI functions
*/
/*! @{
Doxygen group */
2002-09-12 18:32:42 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
2006-04-01 08:49:54 +00:00
# include <ctype.h>
2002-09-12 18:32:42 +00:00
# include <sys/time.h>
2003-03-20 17:21:54 +00:00
# include <sys/types.h>
# include <netdb.h>
2002-09-12 18:32:42 +00:00
# include <sys/socket.h>
# include <netinet/in.h>
2003-03-20 17:21:54 +00:00
# include <netinet/tcp.h>
2002-09-12 18:32:42 +00:00
# include <arpa/inet.h>
# include <signal.h>
# include <errno.h>
# include <unistd.h>
2005-04-21 06:02:45 +00:00
2005-06-06 20:27:51 +00:00
# include "asterisk.h"
2005-06-06 22:12:19 +00:00
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-06-06 20:27:51 +00:00
2005-04-21 06:02:45 +00:00
# include "asterisk/channel.h"
# include "asterisk/file.h"
# include "asterisk/manager.h"
# include "asterisk/config.h"
# include "asterisk/callerid.h"
# include "asterisk/lock.h"
# include "asterisk/logger.h"
# include "asterisk/options.h"
# include "asterisk/cli.h"
# include "asterisk/app.h"
# include "asterisk/pbx.h"
# include "asterisk/md5.h"
# include "asterisk/acl.h"
# include "asterisk/utils.h"
2006-04-01 08:49:54 +00:00
# include "asterisk/http.h"
2002-09-12 18:32:42 +00:00
2005-07-15 23:24:51 +00:00
struct fast_originate_helper {
2006-02-11 18:31:59 +00:00
char tech [ AST_MAX_MANHEADER_LEN ] ;
char data [ AST_MAX_MANHEADER_LEN ] ;
2004-05-01 23:52:27 +00:00
int timeout ;
2006-02-11 18:31:59 +00:00
char app [ AST_MAX_APP ] ;
char appdata [ AST_MAX_MANHEADER_LEN ] ;
char cid_name [ AST_MAX_MANHEADER_LEN ] ;
char cid_num [ AST_MAX_MANHEADER_LEN ] ;
char context [ AST_MAX_CONTEXT ] ;
char exten [ AST_MAX_EXTENSION ] ;
char idtext [ AST_MAX_MANHEADER_LEN ] ;
char account [ AST_MAX_ACCOUNT_CODE ] ;
2004-05-01 23:52:27 +00:00
int priority ;
2005-07-15 23:24:51 +00:00
struct ast_variable * vars ;
2004-05-01 23:52:27 +00:00
} ;
2006-04-02 19:59:55 +00:00
struct eventqent {
int usecount ;
int category ;
ast_mutex_t lock ;
struct eventqent * next ;
char eventdata [ 1 ] ;
} ;
2002-09-12 18:32:42 +00:00
static int enabled = 0 ;
static int portno = DEFAULT_MANAGER_PORT ;
static int asock = - 1 ;
2005-01-05 06:24:59 +00:00
static int displayconnects = 1 ;
2006-01-03 22:07:12 +00:00
static int timestampevents = 0 ;
2006-04-01 08:49:54 +00:00
static int httptimeout = 60 ;
2005-01-05 06:24:59 +00:00
2002-09-12 18:32:42 +00:00
static pthread_t t ;
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( sessionlock ) ;
2004-03-01 21:12:32 +00:00
static int block_sockets = 0 ;
2006-04-02 19:59:55 +00:00
static int num_sessions = 0 ;
struct eventqent * master_eventq = NULL ;
2002-09-12 18:32:42 +00:00
static struct permalias {
int num ;
char * label ;
} perms [ ] = {
{ EVENT_FLAG_SYSTEM , " system " } ,
{ EVENT_FLAG_CALL , " call " } ,
{ EVENT_FLAG_LOG , " log " } ,
{ EVENT_FLAG_VERBOSE , " verbose " } ,
{ EVENT_FLAG_COMMAND , " command " } ,
{ EVENT_FLAG_AGENT , " agent " } ,
2003-04-14 18:47:36 +00:00
{ EVENT_FLAG_USER , " user " } ,
2002-09-12 18:32:42 +00:00
{ - 1 , " all " } ,
2005-04-04 16:18:11 +00:00
{ 0 , " none " } ,
2002-09-12 18:32:42 +00:00
} ;
2006-03-25 23:50:09 +00:00
static struct mansession {
/*! Execution thread */
pthread_t t ;
/*! Thread lock -- don't use in action callbacks, it's already taken care of */
ast_mutex_t __lock ;
/*! socket address */
struct sockaddr_in sin ;
/*! TCP socket */
int fd ;
/*! Whether or not we're busy doing an action */
int busy ;
/*! Whether or not we're "dead" */
int dead ;
2006-04-01 08:49:54 +00:00
/*! Whether an HTTP manager is in use */
int inuse ;
/*! Whether an HTTP session should be destroyed */
int needdestroy ;
/*! Whether an HTTP session has someone waiting on events */
pthread_t waiting_thread ;
/*! Unique manager identifer */
unsigned long managerid ;
/*! Session timeout if HTTP */
time_t sessiontimeout ;
/*! Output from manager interface */
char * outputstr ;
2006-03-25 23:50:09 +00:00
/*! Logged in username */
char username [ 80 ] ;
/*! Authentication challenge */
char challenge [ 10 ] ;
/*! Authentication status */
int authenticated ;
/*! Authorization for reading */
int readperm ;
/*! Authorization for writing */
int writeperm ;
/*! Buffer */
char inbuf [ AST_MAX_MANHEADER_LEN ] ;
int inlen ;
int send_events ;
/* Queued events that we've not had the ability to send yet */
struct eventqent * eventq ;
/* Timeout for ast_carefulwrite() */
int writetimeout ;
struct mansession * next ;
} * sessions = NULL ;
2003-01-28 22:33:41 +00:00
static struct manager_action * first_action = NULL ;
2004-06-09 01:45:08 +00:00
AST_MUTEX_DEFINE_STATIC ( actionlock ) ;
2002-09-12 18:32:42 +00:00
2005-10-24 20:12:06 +00:00
/*! If you are calling ast_carefulwrite, it is assumed that you are calling
2005-05-17 18:30:44 +00:00
it on a file descriptor that _DOES_ have NONBLOCK set . This way ,
there is only one system call made to do a write , unless we actually
have a need to wait . This way , we get better performance . */
2004-03-01 21:12:32 +00:00
int ast_carefulwrite ( int fd , char * s , int len , int timeoutms )
{
/* Try to write string, but wait no more than ms milliseconds
before timing out */
2006-04-04 19:03:12 +00:00
int res = 0 ;
2004-04-25 20:42:45 +00:00
struct pollfd fds [ 1 ] ;
2006-04-04 19:03:12 +00:00
while ( len ) {
2004-03-01 21:12:32 +00:00
res = write ( fd , s , len ) ;
if ( ( res < 0 ) & & ( errno ! = EAGAIN ) ) {
return - 1 ;
}
2006-04-04 19:03:12 +00:00
if ( res < 0 )
res = 0 ;
2004-03-01 21:12:32 +00:00
len - = res ;
s + = res ;
2005-10-14 20:37:40 +00:00
res = 0 ;
if ( len ) {
fds [ 0 ] . fd = fd ;
fds [ 0 ] . events = POLLOUT ;
/* Wait until writable again */
res = poll ( fds , 1 , timeoutms ) ;
if ( res < 1 )
return - 1 ;
}
2004-03-01 21:12:32 +00:00
}
return res ;
}
2005-10-24 20:12:06 +00:00
/*! authority_to_str: Convert authority code to string with serveral options */
2004-07-30 20:27:42 +00:00
static char * authority_to_str ( int authority , char * res , int reslen )
{
int running_total = 0 , i ;
memset ( res , 0 , reslen ) ;
for ( i = 0 ; i < sizeof ( perms ) / sizeof ( perms [ 0 ] ) - 1 ; i + + ) {
if ( authority & perms [ i ] . num ) {
if ( * res ) {
strncat ( res , " , " , ( reslen > running_total ) ? reslen - running_total : 0 ) ;
running_total + + ;
}
strncat ( res , perms [ i ] . label , ( reslen > running_total ) ? reslen - running_total : 0 ) ;
running_total + = strlen ( perms [ i ] . label ) ;
}
}
2005-02-26 07:15:18 +00:00
if ( ast_strlen_zero ( res ) ) {
2005-07-10 22:56:21 +00:00
ast_copy_string ( res , " <none> " , reslen ) ;
2005-02-26 07:15:18 +00:00
}
2004-07-30 20:27:42 +00:00
return res ;
}
2006-01-18 22:17:31 +00:00
static char * complete_show_mancmd ( const char * line , const char * word , int pos , int state )
2004-06-02 20:08:08 +00:00
{
2006-03-28 23:52:21 +00:00
struct manager_action * cur ;
2004-06-02 20:08:08 +00:00
int which = 0 ;
2006-03-28 23:52:21 +00:00
char * ret = NULL ;
2004-06-02 20:08:08 +00:00
ast_mutex_lock ( & actionlock ) ;
2006-03-28 23:52:21 +00:00
for ( cur = first_action ; cur ; cur = cur - > next ) { /* Walk the list of actions */
if ( ! strncasecmp ( word , cur - > action , strlen ( word ) ) & & + + which > state ) {
ret = ast_strdup ( cur - > action ) ;
break ; /* make sure we exit even if ast_strdup() returns NULL */
2004-06-02 20:08:08 +00:00
}
}
ast_mutex_unlock ( & actionlock ) ;
2006-03-28 23:52:21 +00:00
return ret ;
2004-06-02 20:08:08 +00:00
}
2006-04-03 18:38:28 +00:00
static void xml_copy_escape ( char * * dst , size_t * maxlen , const char * src , int lower )
2006-04-01 08:49:54 +00:00
{
while ( * src & & ( * maxlen > 6 ) ) {
2006-04-04 19:03:12 +00:00
switch ( * src ) {
2006-04-01 08:49:54 +00:00
case ' < ' :
strcpy ( * dst , " < " ) ;
( * dst ) + = 4 ;
* maxlen - = 4 ;
break ;
case ' > ' :
strcpy ( * dst , " > " ) ;
( * dst ) + = 4 ;
* maxlen - = 4 ;
break ;
case ' \" ' :
strcpy ( * dst , " " " ) ;
( * dst ) + = 6 ;
* maxlen - = 6 ;
break ;
case ' \' ' :
strcpy ( * dst , " ' " ) ;
( * dst ) + = 6 ;
* maxlen - = 6 ;
break ;
case ' & ' :
strcpy ( * dst , " & " ) ;
( * dst ) + = 4 ;
* maxlen - = 4 ;
break ;
default :
* ( * dst ) + + = lower ? tolower ( * src ) : * src ;
( * maxlen ) - - ;
}
src + + ;
}
}
2006-04-03 18:38:28 +00:00
2006-04-01 08:49:54 +00:00
static char * xml_translate ( char * in , struct ast_variable * vars )
{
struct ast_variable * v ;
2006-04-04 19:03:12 +00:00
char * dest = NULL ;
2006-04-01 08:49:54 +00:00
char * out , * tmp , * var , * val ;
2006-04-04 19:03:12 +00:00
char * objtype = NULL ;
2006-04-01 08:49:54 +00:00
int colons = 0 ;
int breaks = 0 ;
2006-04-03 18:38:28 +00:00
size_t len ;
2006-04-01 08:49:54 +00:00
int count = 1 ;
int escaped = 0 ;
int inobj = 0 ;
int x ;
v = vars ;
2006-04-03 18:38:28 +00:00
2006-04-04 19:03:12 +00:00
while ( v ) {
2006-04-01 08:49:54 +00:00
if ( ! dest & & ! strcasecmp ( v - > name , " ajaxdest " ) )
dest = v - > value ;
else if ( ! objtype & & ! strcasecmp ( v - > name , " ajaxobjtype " ) )
objtype = v - > value ;
v = v - > next ;
}
if ( ! dest )
dest = " unknown " ;
if ( ! objtype )
objtype = " generic " ;
2006-04-03 18:38:28 +00:00
for ( x = 0 ; in [ x ] ; x + + ) {
2006-04-01 08:49:54 +00:00
if ( in [ x ] = = ' : ' )
colons + + ;
else if ( in [ x ] = = ' \n ' )
breaks + + ;
else if ( strchr ( " & \" <> " , in [ x ] ) )
escaped + + ;
}
2006-04-03 18:38:28 +00:00
len = ( size_t ) ( strlen ( in ) + colons * 5 + breaks * ( 40 + strlen ( dest ) + strlen ( objtype ) ) + escaped * 10 ) ; /* foo="bar", "<response type=\"object\" id=\"dest\"", "&" */
2006-04-01 08:49:54 +00:00
out = malloc ( len ) ;
if ( ! out )
return 0 ;
tmp = out ;
2006-04-04 19:03:12 +00:00
while ( * in ) {
2006-04-01 08:49:54 +00:00
var = in ;
2006-04-03 18:38:28 +00:00
while ( * in & & ( * in > = 32 ) )
in + + ;
2006-04-01 08:49:54 +00:00
if ( * in ) {
if ( ( count > 3 ) & & inobj ) {
ast_build_string ( & tmp , & len , " /></response> \n " ) ;
inobj = 0 ;
}
count = 0 ;
while ( * in & & ( * in < 32 ) ) {
* in = ' \0 ' ;
in + + ;
count + + ;
}
val = strchr ( var , ' : ' ) ;
if ( val ) {
* val = ' \0 ' ;
val + + ;
if ( * val = = ' ' )
val + + ;
if ( ! inobj ) {
ast_build_string ( & tmp , & len , " <response type='object' id='%s'><%s " , dest , objtype ) ;
inobj = 1 ;
}
ast_build_string ( & tmp , & len , " " ) ;
xml_copy_escape ( & tmp , & len , var , 1 ) ;
ast_build_string ( & tmp , & len , " =' " ) ;
xml_copy_escape ( & tmp , & len , val , 0 ) ;
ast_build_string ( & tmp , & len , " ' " ) ;
}
}
}
if ( inobj )
ast_build_string ( & tmp , & len , " /></response> \n " ) ;
return out ;
}
static char * html_translate ( char * in )
{
int x ;
int colons = 0 ;
int breaks = 0 ;
2006-04-03 18:38:28 +00:00
size_t len ;
2006-04-04 19:03:12 +00:00
int count = 1 ;
2006-04-01 08:49:54 +00:00
char * tmp , * var , * val , * out ;
2006-04-03 18:38:28 +00:00
for ( x = 0 ; in [ x ] ; x + + ) {
2006-04-01 08:49:54 +00:00
if ( in [ x ] = = ' : ' )
colons + + ;
if ( in [ x ] = = ' \n ' )
breaks + + ;
}
len = strlen ( in ) + colons * 40 + breaks * 40 ; /* <tr><td></td><td></td></tr>, "<tr><td colspan=\"2\"><hr></td></tr> */
out = malloc ( len ) ;
if ( ! out )
return 0 ;
tmp = out ;
2006-04-04 19:03:12 +00:00
while ( * in ) {
2006-04-01 08:49:54 +00:00
var = in ;
2006-04-03 18:38:28 +00:00
while ( * in & & ( * in > = 32 ) )
in + + ;
2006-04-01 08:49:54 +00:00
if ( * in ) {
if ( ( count % 4 ) = = 0 ) {
ast_build_string ( & tmp , & len , " <tr><td colspan= \" 2 \" ><hr></td></tr> \r \n " ) ;
}
count = 0 ;
while ( * in & & ( * in < 32 ) ) {
* in = ' \0 ' ;
in + + ;
count + + ;
}
val = strchr ( var , ' : ' ) ;
if ( val ) {
* val = ' \0 ' ;
val + + ;
if ( * val = = ' ' )
val + + ;
ast_build_string ( & tmp , & len , " <tr><td>%s</td><td>%s</td></tr> \r \n " , var , val ) ;
}
}
}
return out ;
}
2006-03-25 23:50:09 +00:00
void astman_append ( struct mansession * s , const char * fmt , . . . )
{
char * stuff ;
int res ;
va_list ap ;
2006-04-01 08:49:54 +00:00
char * tmp ;
2006-03-25 23:50:09 +00:00
va_start ( ap , fmt ) ;
res = vasprintf ( & stuff , fmt , ap ) ;
va_end ( ap ) ;
if ( res = = - 1 ) {
ast_log ( LOG_ERROR , " Memory allocation failure \n " ) ;
2006-04-03 18:38:28 +00:00
return ;
}
if ( s - > fd > - 1 )
ast_carefulwrite ( s - > fd , stuff , strlen ( stuff ) , s - > writetimeout ) ;
else {
tmp = realloc ( s - > outputstr , ( s - > outputstr ? strlen ( s - > outputstr ) : 0 ) + strlen ( stuff ) + 1 ) ;
if ( tmp ) {
if ( ! s - > outputstr )
tmp [ 0 ] = ' \0 ' ;
s - > outputstr = tmp ;
strcat ( s - > outputstr , stuff ) ;
2006-04-01 08:49:54 +00:00
}
2006-03-25 23:50:09 +00:00
}
2006-04-03 18:38:28 +00:00
free ( stuff ) ;
2006-03-25 23:50:09 +00:00
}
2004-06-02 20:08:08 +00:00
static int handle_showmancmd ( int fd , int argc , char * argv [ ] )
{
struct manager_action * cur = first_action ;
2004-07-30 20:27:42 +00:00
char authority [ 80 ] ;
2004-06-02 20:08:08 +00:00
int num ;
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
ast_mutex_lock ( & actionlock ) ;
while ( cur ) { /* Walk the list of actions */
for ( num = 3 ; num < argc ; num + + ) {
if ( ! strcasecmp ( cur - > action , argv [ num ] ) ) {
2004-07-30 20:27:42 +00:00
ast_cli ( fd , " Action: %s \n Synopsis: %s \n Privilege: %s \n %s \n " , cur - > action , cur - > synopsis , authority_to_str ( cur - > authority , authority , sizeof ( authority ) - 1 ) , cur - > description ? cur - > description : " " ) ;
2004-06-02 20:08:08 +00:00
}
}
cur = cur - > next ;
}
ast_mutex_unlock ( & actionlock ) ;
return RESULT_SUCCESS ;
}
2005-10-26 13:03:17 +00:00
/*! \brief handle_showmancmds: CLI command */
2005-04-04 16:18:11 +00:00
/* Should change to "manager show commands" */
2003-01-28 22:33:41 +00:00
static int handle_showmancmds ( int fd , int argc , char * argv [ ] )
{
struct manager_action * cur = first_action ;
2004-07-30 20:27:42 +00:00
char authority [ 80 ] ;
2005-04-04 16:18:11 +00:00
char * format = " %-15.15s %-15.15s %-55.55s \n " ;
2002-09-12 18:32:42 +00:00
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & actionlock ) ;
2004-07-30 20:27:42 +00:00
ast_cli ( fd , format , " Action " , " Privilege " , " Synopsis " ) ;
2005-04-04 16:18:11 +00:00
ast_cli ( fd , format , " ------ " , " --------- " , " -------- " ) ;
2004-06-02 20:08:08 +00:00
while ( cur ) { /* Walk the list of actions */
2004-07-30 20:27:42 +00:00
ast_cli ( fd , format , cur - > action , authority_to_str ( cur - > authority , authority , sizeof ( authority ) - 1 ) , cur - > synopsis ) ;
2003-01-28 22:33:41 +00:00
cur = cur - > next ;
}
2002-09-12 18:32:42 +00:00
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & actionlock ) ;
2003-01-28 22:33:41 +00:00
return RESULT_SUCCESS ;
}
2005-10-26 13:03:17 +00:00
/*! \brief handle_showmanconn: CLI command show manager connected */
2005-04-04 16:18:11 +00:00
/* Should change to "manager show connected" */
2003-02-21 06:00:08 +00:00
static int handle_showmanconn ( int fd , int argc , char * argv [ ] )
{
struct mansession * s ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2004-01-22 21:44:47 +00:00
char * format = " %-15.15s %-15.15s \n " ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & sessionlock ) ;
2003-02-21 06:00:08 +00:00
s = sessions ;
2004-01-22 21:44:47 +00:00
ast_cli ( fd , format , " Username " , " IP Address " ) ;
2004-06-02 20:08:08 +00:00
while ( s ) {
2004-06-29 12:56:46 +00:00
ast_cli ( fd , format , s - > username , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
2003-02-21 06:00:08 +00:00
s = s - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & sessionlock ) ;
2003-02-21 06:00:08 +00:00
return RESULT_SUCCESS ;
}
2006-04-02 19:59:55 +00:00
/*! \brief handle_showmanconn: CLI command show manager connected */
/* Should change to "manager show connected" */
static int handle_showmaneventq ( int fd , int argc , char * argv [ ] )
{
struct eventqent * s ;
ast_mutex_lock ( & sessionlock ) ;
s = master_eventq ;
while ( s ) {
ast_cli ( fd , " Usecount: %d \n " , s - > usecount ) ;
ast_cli ( fd , " Category: %d \n " , s - > category ) ;
ast_cli ( fd , " Event: \n %s " , s - > eventdata ) ;
s = s - > next ;
}
ast_mutex_unlock ( & sessionlock ) ;
return RESULT_SUCCESS ;
}
2004-06-02 20:08:08 +00:00
static char showmancmd_help [ ] =
" Usage: show manager command <actionname> \n "
2005-02-26 07:15:18 +00:00
" Shows the detailed description for a specific Asterisk manager interface command. \n " ;
2004-06-02 20:08:08 +00:00
2003-01-28 22:33:41 +00:00
static char showmancmds_help [ ] =
" Usage: show manager commands \n "
2005-02-26 07:15:18 +00:00
" Prints a listing of all the available Asterisk manager interface commands. \n " ;
2003-01-28 22:33:41 +00:00
2003-02-21 06:00:08 +00:00
static char showmanconn_help [ ] =
" Usage: show manager connected \n "
2005-02-26 07:15:18 +00:00
" Prints a listing of the users that are currently connected to the \n "
" Asterisk manager interface. \n " ;
2003-02-21 06:00:08 +00:00
2006-04-02 19:59:55 +00:00
static char showmaneventq_help [ ] =
" Usage: show manager eventq \n "
" Prints a listing of all events pending in the Asterisk manger \n "
" event queue. \n " ;
2004-06-02 20:08:08 +00:00
static struct ast_cli_entry show_mancmd_cli =
{ { " show " , " manager " , " command " , NULL } ,
2005-02-26 07:15:18 +00:00
handle_showmancmd , " Show a manager interface command " , showmancmd_help , complete_show_mancmd } ;
2004-06-02 20:08:08 +00:00
2003-01-28 22:33:41 +00:00
static struct ast_cli_entry show_mancmds_cli =
{ { " show " , " manager " , " commands " , NULL } ,
2005-02-26 07:15:18 +00:00
handle_showmancmds , " List manager interface commands " , showmancmds_help } ;
2002-09-12 18:32:42 +00:00
2003-02-21 06:00:08 +00:00
static struct ast_cli_entry show_manconn_cli =
{ { " show " , " manager " , " connected " , NULL } ,
2005-02-26 07:15:18 +00:00
handle_showmanconn , " Show connected manager interface users " , showmanconn_help } ;
2003-02-21 06:00:08 +00:00
2006-04-02 19:59:55 +00:00
static struct ast_cli_entry show_maneventq_cli =
{ { " show " , " manager " , " eventq " , NULL } ,
handle_showmaneventq , " Show manager interface queued events " , showmaneventq_help } ;
static void unuse_eventqent ( struct eventqent * e )
{
/* XXX Need to atomically decrement the users. Change this to atomic_dec
one day when we have such a beast XXX */
int val ;
ast_mutex_lock ( & e - > lock ) ;
e - > usecount - - ;
2006-04-02 20:11:55 +00:00
val = ! e - > usecount & & e - > next ;
2006-04-02 19:59:55 +00:00
ast_mutex_unlock ( & e - > lock ) ;
/* Wake up sleeping beauty */
if ( val )
pthread_kill ( t , SIGURG ) ;
}
2005-09-28 23:10:14 +00:00
static void free_session ( struct mansession * s )
{
struct eventqent * eqe ;
if ( s - > fd > - 1 )
close ( s - > fd ) ;
2006-04-01 08:49:54 +00:00
if ( s - > outputstr )
free ( s - > outputstr ) ;
2005-09-28 23:10:14 +00:00
ast_mutex_destroy ( & s - > __lock ) ;
2006-04-04 19:03:12 +00:00
while ( s - > eventq ) {
2005-09-28 23:10:14 +00:00
eqe = s - > eventq ;
s - > eventq = s - > eventq - > next ;
2006-04-02 19:59:55 +00:00
unuse_eventqent ( eqe ) ;
2005-09-28 23:10:14 +00:00
}
free ( s ) ;
}
2002-09-12 18:32:42 +00:00
static void destroy_session ( struct mansession * s )
{
struct mansession * cur , * prev = NULL ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & sessionlock ) ;
2002-09-12 18:32:42 +00:00
cur = sessions ;
2006-04-04 19:03:12 +00:00
while ( cur ) {
2002-09-12 18:32:42 +00:00
if ( cur = = s )
break ;
prev = cur ;
cur = cur - > next ;
}
if ( cur ) {
if ( prev )
prev - > next = cur - > next ;
else
sessions = cur - > next ;
2005-09-28 23:10:14 +00:00
free_session ( s ) ;
2006-04-02 19:59:55 +00:00
num_sessions - - ;
2002-09-12 18:32:42 +00:00
} else
2005-04-13 23:33:47 +00:00
ast_log ( LOG_WARNING , " Trying to delete nonexistent session %p? \n " , s ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & sessionlock ) ;
2002-09-12 18:32:42 +00:00
}
2003-03-31 17:40:18 +00:00
char * astman_get_header ( struct message * m , char * var )
2002-09-12 18:32:42 +00:00
{
char cmp [ 80 ] ;
int x ;
snprintf ( cmp , sizeof ( cmp ) , " %s: " , var ) ;
2006-04-04 19:03:12 +00:00
for ( x = 0 ; x < m - > hdrcount ; x + + )
2002-09-12 18:32:42 +00:00
if ( ! strncasecmp ( cmp , m - > headers [ x ] , strlen ( cmp ) ) )
return m - > headers [ x ] + strlen ( cmp ) ;
return " " ;
}
2005-07-15 23:24:51 +00:00
struct ast_variable * astman_get_variables ( struct message * m )
{
2005-11-08 02:11:42 +00:00
int varlen , x , y ;
2005-07-15 23:24:51 +00:00
struct ast_variable * head = NULL , * cur ;
char * var , * val ;
2006-01-23 18:07:12 +00:00
char * parse ;
AST_DECLARE_APP_ARGS ( args ,
AST_APP_ARG ( vars ) [ 32 ] ;
) ;
2005-07-15 23:24:51 +00:00
varlen = strlen ( " Variable: " ) ;
for ( x = 0 ; x < m - > hdrcount ; x + + ) {
2005-11-08 02:11:42 +00:00
if ( strncasecmp ( " Variable: " , m - > headers [ x ] , varlen ) )
continue ;
2006-01-23 18:07:12 +00:00
if ( ! ( parse = ast_strdupa ( m - > headers [ x ] + varlen ) ) )
2005-11-08 02:11:42 +00:00
return head ;
2006-01-23 18:07:12 +00:00
AST_STANDARD_APP_ARGS ( args , parse ) ;
if ( args . argc ) {
for ( y = 0 ; y < args . argc ; y + + ) {
if ( ! args . vars [ y ] )
2005-11-15 01:33:31 +00:00
continue ;
2006-01-23 18:07:12 +00:00
var = val = ast_strdupa ( args . vars [ y ] ) ;
2005-11-08 02:11:42 +00:00
strsep ( & val , " = " ) ;
if ( ! val | | ast_strlen_zero ( var ) )
continue ;
cur = ast_variable_new ( var , val ) ;
if ( head ) {
cur - > next = head ;
head = cur ;
} else
head = cur ;
}
2005-07-15 23:24:51 +00:00
}
}
return head ;
}
2005-10-24 20:12:06 +00:00
/*! NOTE:
2005-09-30 23:52:04 +00:00
Callers of astman_send_error ( ) , astman_send_response ( ) or astman_send_ack ( ) must EITHER
hold the session lock _or_ be running in an action callback ( in which case s - > busy will
be non - zero ) . In either of these cases , there is no need to lock - protect the session ' s
fd , since no other output will be sent ( events will be queued ) , and no input will
be read until either the current action finishes or get_input ( ) obtains the session
lock .
*/
2003-09-08 16:44:36 +00:00
void astman_send_error ( struct mansession * s , struct message * m , char * error )
2002-09-12 18:32:42 +00:00
{
2003-09-08 16:44:36 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
2005-09-30 23:52:04 +00:00
2006-03-25 23:50:09 +00:00
astman_append ( s , " Response: Error \r \n " ) ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( id ) )
2006-04-04 19:03:12 +00:00
astman_append ( s , " ActionID: %s \r \n " , id ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " Message: %s \r \n \r \n " , error ) ;
2002-09-12 18:32:42 +00:00
}
2003-09-08 16:44:36 +00:00
void astman_send_response ( struct mansession * s , struct message * m , char * resp , char * msg )
2002-09-12 18:32:42 +00:00
{
2003-09-08 16:44:36 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
2005-09-30 23:52:04 +00:00
2006-03-25 23:50:09 +00:00
astman_append ( s , " Response: %s \r \n " , resp ) ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( id ) )
2006-04-04 19:03:12 +00:00
astman_append ( s , " ActionID: %s \r \n " , id ) ;
2002-09-12 18:32:42 +00:00
if ( msg )
2006-03-25 23:50:09 +00:00
astman_append ( s , " Message: %s \r \n \r \n " , msg ) ;
2002-09-12 18:32:42 +00:00
else
2006-03-25 23:50:09 +00:00
astman_append ( s , " \r \n " ) ;
2002-09-12 18:32:42 +00:00
}
2003-09-08 16:44:36 +00:00
void astman_send_ack ( struct mansession * s , struct message * m , char * msg )
2002-09-12 18:32:42 +00:00
{
2003-09-08 16:44:36 +00:00
astman_send_response ( s , m , " Success " , msg ) ;
2002-09-12 18:32:42 +00:00
}
2005-10-24 20:12:06 +00:00
/*! Tells you if smallstr exists inside bigstr
2004-07-08 15:39:35 +00:00
which is delim by delim and uses no buf or stringsep
ast_instring ( " this|that|more " , " this " , ' , ' ) = = 1 ;
feel free to move this to app . c - anthm */
2004-07-08 17:08:38 +00:00
static int ast_instring ( char * bigstr , char * smallstr , char delim )
{
char * val = bigstr , * next ;
2004-07-08 15:39:35 +00:00
2004-07-08 17:08:38 +00:00
do {
if ( ( next = strchr ( val , delim ) ) ) {
if ( ! strncmp ( val , smallstr , ( next - val ) ) )
return 1 ;
else
continue ;
} else
return ! strcmp ( smallstr , val ) ;
2004-07-08 15:39:35 +00:00
2004-07-08 17:08:38 +00:00
} while ( * ( val = ( next + 1 ) ) ) ;
2004-07-08 15:39:35 +00:00
2004-07-08 17:08:38 +00:00
return 0 ;
2004-07-08 15:39:35 +00:00
}
2002-09-12 18:32:42 +00:00
static int get_perm ( char * instr )
{
2004-07-08 15:39:35 +00:00
int x = 0 , ret = 0 ;
2003-01-28 22:33:41 +00:00
if ( ! instr )
return 0 ;
2004-07-08 15:39:35 +00:00
for ( x = 0 ; x < sizeof ( perms ) / sizeof ( perms [ 0 ] ) ; x + + )
if ( ast_instring ( instr , perms [ x ] . label , ' , ' ) )
ret | = perms [ x ] . num ;
return ret ;
}
2004-07-08 17:08:38 +00:00
static int ast_is_number ( char * string )
{
2004-07-08 15:39:35 +00:00
int ret = 1 , x = 0 ;
2004-07-08 17:08:38 +00:00
if ( ! string )
2004-07-08 15:39:35 +00:00
return 0 ;
2004-07-08 17:08:38 +00:00
for ( x = 0 ; x < strlen ( string ) ; x + + ) {
if ( ! ( string [ x ] > = 48 & & string [ x ] < = 57 ) ) {
2004-07-08 15:39:35 +00:00
ret = 0 ;
break ;
2002-09-12 18:32:42 +00:00
}
}
2004-07-08 15:39:35 +00:00
return ret ? atoi ( string ) : 0 ;
}
2004-07-08 17:08:38 +00:00
static int ast_strings_to_mask ( char * string )
{
2005-08-26 23:04:20 +00:00
int x , ret = - 1 ;
2004-07-08 15:39:35 +00:00
x = ast_is_number ( string ) ;
2005-08-26 23:04:20 +00:00
if ( x ) {
2004-07-08 15:39:35 +00:00
ret = x ;
2005-10-26 18:54:24 +00:00
} else if ( ast_strlen_zero ( string ) ) {
2004-07-08 15:39:35 +00:00
ret = - 1 ;
2005-08-26 23:04:20 +00:00
} else if ( ast_false ( string ) ) {
2004-07-08 15:39:35 +00:00
ret = 0 ;
2005-08-26 23:04:20 +00:00
} else if ( ast_true ( string ) ) {
ret = 0 ;
for ( x = 0 ; x < sizeof ( perms ) / sizeof ( perms [ 0 ] ) ; x + + )
ret | = perms [ x ] . num ;
} else {
2004-07-08 15:39:35 +00:00
ret = 0 ;
2004-07-08 17:08:38 +00:00
for ( x = 0 ; x < sizeof ( perms ) / sizeof ( perms [ 0 ] ) ; x + + ) {
2004-07-08 15:39:35 +00:00
if ( ast_instring ( string , perms [ x ] . label , ' , ' ) )
ret | = perms [ x ] . num ;
2004-07-08 17:08:38 +00:00
}
2004-07-08 15:39:35 +00:00
}
2002-09-12 18:32:42 +00:00
return ret ;
}
2005-10-24 20:12:06 +00:00
/*!
2004-07-08 15:39:35 +00:00
Rather than braindead on , off this now can also accept a specific int mask value
or a ' , ' delim list of mask strings ( the same as manager . conf ) - anthm
*/
2004-03-02 08:45:51 +00:00
static int set_eventmask ( struct mansession * s , char * eventmask )
{
2004-07-08 15:39:35 +00:00
int maskint = ast_strings_to_mask ( eventmask ) ;
2005-09-28 23:10:14 +00:00
ast_mutex_lock ( & s - > __lock ) ;
2005-07-25 23:01:39 +00:00
if ( maskint > = 0 )
s - > send_events = maskint ;
2005-09-28 23:10:14 +00:00
ast_mutex_unlock ( & s - > __lock ) ;
2004-07-08 15:39:35 +00:00
2005-07-25 23:01:39 +00:00
return maskint ;
2004-03-02 08:45:51 +00:00
}
2002-09-12 18:32:42 +00:00
static int authenticate ( struct mansession * s , struct message * m )
{
struct ast_config * cfg ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-09-12 18:32:42 +00:00
char * cat ;
2003-03-31 17:40:18 +00:00
char * user = astman_get_header ( m , " Username " ) ;
char * pass = astman_get_header ( m , " Secret " ) ;
char * authtype = astman_get_header ( m , " AuthType " ) ;
char * key = astman_get_header ( m , " Key " ) ;
2004-03-01 21:12:32 +00:00
char * events = astman_get_header ( m , " Events " ) ;
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( " manager.conf " ) ;
2002-09-12 18:32:42 +00:00
if ( ! cfg )
return - 1 ;
cat = ast_category_browse ( cfg , NULL ) ;
2006-04-04 19:03:12 +00:00
while ( cat ) {
2002-09-12 18:32:42 +00:00
if ( strcasecmp ( cat , " general " ) ) {
/* This is a user */
if ( ! strcasecmp ( cat , user ) ) {
2003-05-05 06:14:25 +00:00
struct ast_variable * v ;
struct ast_ha * ha = NULL ;
char * password = NULL ;
v = ast_variable_browse ( cfg , cat ) ;
while ( v ) {
if ( ! strcasecmp ( v - > name , " secret " ) ) {
password = v - > value ;
} else if ( ! strcasecmp ( v - > name , " permit " ) | |
! strcasecmp ( v - > name , " deny " ) ) {
2005-01-05 06:24:59 +00:00
ha = ast_append_ha ( v - > name , v - > value , ha ) ;
2005-10-04 22:25:15 +00:00
} else if ( ! strcasecmp ( v - > name , " writetimeout " ) ) {
int val = atoi ( v - > value ) ;
if ( val < 100 )
ast_log ( LOG_WARNING , " Invalid writetimeout value '%s' at line %d \n " , v - > value , v - > lineno ) ;
else
s - > writetimeout = val ;
}
2005-01-05 06:24:59 +00:00
2003-05-05 06:14:25 +00:00
v = v - > next ;
}
if ( ha & & ! ast_apply_ha ( ha , & ( s - > sin ) ) ) {
2004-06-29 12:56:46 +00:00
ast_log ( LOG_NOTICE , " %s failed to pass IP ACL as '%s' \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) , user ) ;
2003-05-05 06:14:25 +00:00
ast_free_ha ( ha ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-05-05 06:14:25 +00:00
return - 1 ;
} else if ( ha )
ast_free_ha ( ha ) ;
2003-03-10 06:00:17 +00:00
if ( ! strcasecmp ( authtype , " MD5 " ) ) {
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( key ) & & s - > challenge ) {
2003-03-10 06:00:17 +00:00
int x ;
2006-04-04 19:03:12 +00:00
int len = 0 ;
2003-03-10 06:00:17 +00:00
char md5key [ 256 ] = " " ;
struct MD5Context md5 ;
unsigned char digest [ 16 ] ;
MD5Init ( & md5 ) ;
2005-08-05 16:29:30 +00:00
MD5Update ( & md5 , ( unsigned char * ) s - > challenge , strlen ( s - > challenge ) ) ;
MD5Update ( & md5 , ( unsigned char * ) password , strlen ( password ) ) ;
2003-03-10 06:00:17 +00:00
MD5Final ( digest , & md5 ) ;
2006-04-04 19:03:12 +00:00
for ( x = 0 ; x < 16 ; x + + )
2003-03-10 06:00:17 +00:00
len + = sprintf ( md5key + len , " %2.2x " , digest [ x ] ) ;
if ( ! strcmp ( md5key , key ) )
break ;
else {
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-03-10 06:00:17 +00:00
return - 1 ;
}
}
2006-04-01 08:49:54 +00:00
} else if ( password & & ! strcmp ( password , pass ) ) {
2002-09-12 18:32:42 +00:00
break ;
} else {
2004-06-29 12:56:46 +00:00
ast_log ( LOG_NOTICE , " %s failed to authenticate as '%s' \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) , user ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2002-09-12 18:32:42 +00:00
return - 1 ;
}
}
}
cat = ast_category_browse ( cfg , cat ) ;
}
if ( cat ) {
2005-07-10 22:56:21 +00:00
ast_copy_string ( s - > username , cat , sizeof ( s - > username ) ) ;
2002-09-12 18:32:42 +00:00
s - > readperm = get_perm ( ast_variable_retrieve ( cfg , cat , " read " ) ) ;
s - > writeperm = get_perm ( ast_variable_retrieve ( cfg , cat , " write " ) ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2004-03-02 08:45:51 +00:00
if ( events )
set_eventmask ( s , events ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2005-04-13 23:33:47 +00:00
ast_log ( LOG_NOTICE , " %s tried to authenticate with nonexistent user '%s' \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) , user ) ;
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2002-09-12 18:32:42 +00:00
return - 1 ;
}
2005-11-14 19:00:38 +00:00
/*! \brief PING: Manager PING */
2004-06-02 20:08:08 +00:00
static char mandescr_ping [ ] =
2006-04-01 08:49:54 +00:00
" Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the \n "
2004-06-02 20:08:08 +00:00
" manager connection open. \n "
" Variables: NONE \n " ;
2002-09-12 18:32:42 +00:00
static int action_ping ( struct mansession * s , struct message * m )
{
2003-09-08 16:44:36 +00:00
astman_send_response ( s , m , " Pong " , NULL ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2006-04-01 08:49:54 +00:00
/*! \brief WAITEVENT: Manager WAITEVENT */
static char mandescr_waitevent [ ] =
" Description: A 'WaitEvent' action will ellicit a 'Success' response. Whenever \n "
" a manager event is queued. Once WaitEvent has been called on an HTTP manager \n "
" session, events will be generated and queued. \n "
" Variables: \n "
" Timeout: Maximum time to wait for events \n " ;
static int action_waitevent ( struct mansession * s , struct message * m )
{
char * timeouts = astman_get_header ( m , " Timeout " ) ;
int timeout = - 1 , max ;
int x ;
int needexit = 0 ;
time_t now ;
struct eventqent * eqe ;
char * id = astman_get_header ( m , " ActionID " ) ;
2006-04-04 19:03:12 +00:00
char idText [ 256 ] = " " ;
2006-04-01 08:49:54 +00:00
if ( ! ast_strlen_zero ( id ) )
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
if ( ! ast_strlen_zero ( timeouts ) ) {
sscanf ( timeouts , " %i " , & timeout ) ;
}
ast_mutex_lock ( & s - > __lock ) ;
if ( s - > waiting_thread ! = AST_PTHREADT_NULL ) {
pthread_kill ( s - > waiting_thread , SIGURG ) ;
}
if ( s - > sessiontimeout ) {
time ( & now ) ;
max = s - > sessiontimeout - now - 10 ;
if ( max < 0 )
max = 0 ;
if ( ( timeout < 0 ) | | ( timeout > max ) )
timeout = max ;
if ( ! s - > send_events )
s - > send_events = - 1 ;
/* Once waitevent is called, always queue events from now on */
if ( s - > busy = = 1 )
s - > busy = 2 ;
}
ast_mutex_unlock ( & s - > __lock ) ;
s - > waiting_thread = pthread_self ( ) ;
2006-04-01 20:39:33 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Starting waiting for an event! \n " ) ;
2006-04-04 19:03:12 +00:00
for ( x = 0 ; ( ( x < timeout ) | | ( timeout < 0 ) ) ; x + + ) {
2006-04-01 08:49:54 +00:00
ast_mutex_lock ( & s - > __lock ) ;
2006-04-02 19:59:55 +00:00
if ( s - > eventq & & s - > eventq - > next )
2006-04-01 08:49:54 +00:00
needexit = 1 ;
if ( s - > waiting_thread ! = pthread_self ( ) )
needexit = 1 ;
if ( s - > needdestroy )
needexit = 1 ;
ast_mutex_unlock ( & s - > __lock ) ;
if ( needexit )
break ;
if ( s - > fd > 0 ) {
if ( ast_wait_for_input ( s - > fd , 1000 ) )
break ;
} else {
sleep ( 1 ) ;
}
}
2006-04-01 20:39:33 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Finished waiting for an event! \n " ) ;
2006-04-01 08:49:54 +00:00
ast_mutex_lock ( & s - > __lock ) ;
if ( s - > waiting_thread = = pthread_self ( ) ) {
astman_send_response ( s , m , " Success " , " Waiting for Event... " ) ;
/* Only show events if we're the most recent waiter */
2006-04-02 19:59:55 +00:00
while ( s - > eventq - > next ) {
eqe = s - > eventq - > next ;
if ( ( ( s - > readperm & eqe - > category ) = = eqe - > category ) & &
( ( s - > send_events & eqe - > category ) = = eqe - > category ) ) {
astman_append ( s , " %s " , eqe - > eventdata ) ;
}
unuse_eventqent ( s - > eventq ) ;
s - > eventq = eqe ;
2006-04-01 08:49:54 +00:00
}
astman_append ( s ,
" Event: WaitEventComplete \r \n "
" %s "
2006-04-04 19:03:12 +00:00
" \r \n " , idText ) ;
2006-04-01 08:49:54 +00:00
s - > waiting_thread = AST_PTHREADT_NULL ;
} else {
ast_log ( LOG_DEBUG , " Abandoning event request! \n " ) ;
}
ast_mutex_unlock ( & s - > __lock ) ;
return 0 ;
}
2004-06-02 22:30:42 +00:00
static char mandescr_listcommands [ ] =
" Description: Returns the action name and synopsis for every \n "
" action that is available to the user \n "
" Variables: NONE \n " ;
static int action_listcommands ( struct mansession * s , struct message * m )
{
struct manager_action * cur = first_action ;
char idText [ 256 ] = " " ;
2005-04-04 16:18:11 +00:00
char temp [ BUFSIZ ] ;
2004-06-02 22:30:42 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( id ) )
2006-03-28 23:52:21 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " Response: Success \r \n %s " , idText ) ;
2004-06-02 22:30:42 +00:00
ast_mutex_lock ( & actionlock ) ;
while ( cur ) { /* Walk the list of actions */
if ( ( s - > writeperm & cur - > authority ) = = cur - > authority )
2006-04-04 19:03:12 +00:00
astman_append ( s , " %s: %s (Priv: %s) \r \n " , cur - > action , cur - > synopsis , authority_to_str ( cur - > authority , temp , sizeof ( temp ) ) ) ;
2004-06-02 22:30:42 +00:00
cur = cur - > next ;
}
ast_mutex_unlock ( & actionlock ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " \r \n " ) ;
2004-06-02 22:30:42 +00:00
return 0 ;
}
2004-06-29 05:04:48 +00:00
static char mandescr_events [ ] =
" Description: Enable/Disable sending of events to this manager \n "
" client. \n "
" Variables: \n "
2004-07-08 15:39:35 +00:00
" EventMask: 'on' if all events should be sent, \n "
2004-07-08 17:08:38 +00:00
" 'off' if no events should be sent, \n "
" 'system,call,log' to select which flags events should have to be sent. \n " ;
2004-06-29 05:04:48 +00:00
2004-03-01 21:12:32 +00:00
static int action_events ( struct mansession * s , struct message * m )
{
char * mask = astman_get_header ( m , " EventMask " ) ;
int res ;
2004-03-02 08:45:51 +00:00
res = set_eventmask ( s , mask ) ;
if ( res > 0 )
astman_send_response ( s , m , " Events On " , NULL ) ;
else if ( res = = 0 )
astman_send_response ( s , m , " Events Off " , NULL ) ;
2004-07-08 15:39:35 +00:00
2004-03-01 21:12:32 +00:00
return 0 ;
}
2004-06-29 05:04:48 +00:00
static char mandescr_logoff [ ] =
" Description: Logoff this manager session \n "
" Variables: NONE \n " ;
2002-09-12 18:32:42 +00:00
static int action_logoff ( struct mansession * s , struct message * m )
{
2003-09-08 16:44:36 +00:00
astman_send_response ( s , m , " Goodbye " , " Thanks for all the fish. " ) ;
2002-09-12 18:32:42 +00:00
return - 1 ;
}
2004-06-29 05:04:48 +00:00
static char mandescr_hangup [ ] =
" Description: Hangup a channel \n "
" Variables: \n "
" Channel: The channel name to be hungup \n " ;
2002-09-12 18:32:42 +00:00
static int action_hangup ( struct mansession * s , struct message * m )
{
struct ast_channel * c = NULL ;
2003-03-31 17:40:18 +00:00
char * name = astman_get_header ( m , " Channel " ) ;
2004-05-26 19:30:12 +00:00
if ( ast_strlen_zero ( name ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " No channel specified " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2005-06-06 02:29:18 +00:00
c = ast_get_channel_by_name_locked ( name ) ;
2002-09-12 18:32:42 +00:00
if ( ! c ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " No such channel " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
ast_softhangup ( c , AST_SOFTHANGUP_EXPLICIT ) ;
2004-05-20 16:30:10 +00:00
ast_mutex_unlock ( & c - > lock ) ;
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Channel Hungup " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2005-02-26 07:15:18 +00:00
static char mandescr_setvar [ ] =
2005-11-08 03:35:40 +00:00
" Description: Set a global or local channel variable. \n "
2005-02-26 07:15:18 +00:00
" Variables: (Names marked with * are required) \n "
2005-11-08 03:35:40 +00:00
" Channel: Channel to set variable for \n "
2005-02-26 07:15:18 +00:00
" *Variable: Variable name \n "
" *Value: Value \n " ;
2004-06-03 15:42:36 +00:00
static int action_setvar ( struct mansession * s , struct message * m )
{
struct ast_channel * c = NULL ;
char * name = astman_get_header ( m , " Channel " ) ;
char * varname = astman_get_header ( m , " Variable " ) ;
char * varval = astman_get_header ( m , " Value " ) ;
2005-11-08 03:35:40 +00:00
if ( ast_strlen_zero ( varname ) ) {
2004-06-03 15:42:36 +00:00
astman_send_error ( s , m , " No variable specified " ) ;
return 0 ;
}
2005-11-15 18:35:30 +00:00
if ( ast_strlen_zero ( varval ) ) {
astman_send_error ( s , m , " No value specified " ) ;
return 0 ;
}
2004-06-03 15:42:36 +00:00
2005-11-08 03:35:40 +00:00
if ( ! ast_strlen_zero ( name ) ) {
c = ast_get_channel_by_name_locked ( name ) ;
if ( ! c ) {
astman_send_error ( s , m , " No such channel " ) ;
return 0 ;
}
2004-06-03 15:42:36 +00:00
}
2005-11-15 18:35:30 +00:00
pbx_builtin_setvar_helper ( c , varname , varval ) ;
2004-06-03 15:42:36 +00:00
2005-11-15 18:35:30 +00:00
if ( c )
ast_mutex_unlock ( & c - > lock ) ;
astman_send_ack ( s , m , " Variable Set " ) ;
2005-11-08 03:35:40 +00:00
2004-06-03 15:42:36 +00:00
return 0 ;
}
2005-02-26 07:15:18 +00:00
static char mandescr_getvar [ ] =
2005-10-13 20:30:39 +00:00
" Description: Get the value of a global or local channel variable. \n "
2005-02-26 07:15:18 +00:00
" Variables: (Names marked with * are required) \n "
2005-10-13 20:30:39 +00:00
" Channel: Channel to read variable from \n "
2005-02-26 07:15:18 +00:00
" *Variable: Variable name \n "
" ActionID: Optional Action id for message matching. \n " ;
2004-06-03 15:42:36 +00:00
static int action_getvar ( struct mansession * s , struct message * m )
{
2005-12-27 19:13:13 +00:00
struct ast_channel * c = NULL ;
char * name = astman_get_header ( m , " Channel " ) ;
char * varname = astman_get_header ( m , " Variable " ) ;
2004-09-09 12:50:56 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
2005-12-27 19:13:13 +00:00
char * varval ;
char workspace [ 1024 ] ;
2004-06-03 15:42:36 +00:00
2005-12-27 19:13:13 +00:00
if ( ast_strlen_zero ( varname ) ) {
2004-06-03 15:42:36 +00:00
astman_send_error ( s , m , " No variable specified " ) ;
return 0 ;
}
2005-12-27 19:13:13 +00:00
if ( ! ast_strlen_zero ( name ) ) {
2005-10-13 20:30:39 +00:00
c = ast_get_channel_by_name_locked ( name ) ;
if ( ! c ) {
astman_send_error ( s , m , " No such channel " ) ;
return 0 ;
}
2004-06-03 15:42:36 +00:00
}
2005-12-27 19:13:13 +00:00
2006-01-15 05:50:19 +00:00
if ( varname [ strlen ( varname ) - 1 ] = = ' ) ' ) {
2006-02-12 04:28:58 +00:00
ast_func_read ( c , varname , workspace , sizeof ( workspace ) ) ;
2006-01-15 05:50:19 +00:00
} else {
pbx_retrieve_variable ( c , varname , & varval , workspace , sizeof ( workspace ) , NULL ) ;
}
2005-12-27 19:13:13 +00:00
2005-10-13 20:30:39 +00:00
if ( c )
ast_mutex_unlock ( & c - > lock ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " Response: Success \r \n "
2005-12-27 19:13:13 +00:00
" Variable: %s \r \n Value: %s \r \n " , varname , varval ) ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( id ) )
2006-03-25 23:50:09 +00:00
astman_append ( s , " ActionID: %s \r \n " , id ) ;
astman_append ( s , " \r \n " ) ;
2004-06-03 15:42:36 +00:00
return 0 ;
}
2005-10-26 13:03:17 +00:00
/*! \brief action_status: Manager "status" command to show channels */
2005-04-13 05:45:53 +00:00
/* Needs documentation... */
2002-09-12 18:32:42 +00:00
static int action_status ( struct mansession * s , struct message * m )
{
2003-09-08 16:44:36 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
2004-06-26 14:31:09 +00:00
char * name = astman_get_header ( m , " Channel " ) ;
2003-09-08 16:44:36 +00:00
char idText [ 256 ] = " " ;
2002-09-12 18:32:42 +00:00
struct ast_channel * c ;
char bridge [ 256 ] ;
2005-07-15 23:00:47 +00:00
struct timeval now = ast_tvnow ( ) ;
2006-04-04 19:03:12 +00:00
long elapsed_seconds = 0 ;
2005-10-26 18:54:24 +00:00
int all = ast_strlen_zero ( name ) ; /* set if we want all channels */
2004-08-03 17:48:18 +00:00
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Channel status will follow " ) ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( id ) )
2006-03-28 23:52:21 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
2005-06-06 02:29:18 +00:00
if ( all )
c = ast_channel_walk_locked ( NULL ) ;
else {
c = ast_get_channel_by_name_locked ( name ) ;
2004-06-26 14:31:09 +00:00
if ( ! c ) {
astman_send_error ( s , m , " No such channel " ) ;
return 0 ;
}
}
2005-06-06 02:29:18 +00:00
/* if we look by name, we break after the first iteration */
2006-04-04 19:03:12 +00:00
while ( c ) {
2004-10-23 12:19:47 +00:00
if ( c - > _bridge )
snprintf ( bridge , sizeof ( bridge ) , " Link: %s \r \n " , c - > _bridge - > name ) ;
2002-09-12 18:32:42 +00:00
else
2004-07-14 07:44:19 +00:00
bridge [ 0 ] = ' \0 ' ;
2002-09-12 18:32:42 +00:00
if ( c - > pbx ) {
2004-08-03 17:48:18 +00:00
if ( c - > cdr ) {
elapsed_seconds = now . tv_sec - c - > cdr - > start . tv_sec ;
}
2006-03-25 23:50:09 +00:00
astman_append ( s ,
2002-09-12 18:32:42 +00:00
" Event: Status \r \n "
2005-04-04 16:18:11 +00:00
" Privilege: Call \r \n "
2002-09-12 18:32:42 +00:00
" Channel: %s \r \n "
" CallerID: %s \r \n "
2004-10-02 00:58:31 +00:00
" CallerIDName: %s \r \n "
2004-06-26 14:31:09 +00:00
" Account: %s \r \n "
2002-09-12 18:32:42 +00:00
" State: %s \r \n "
" Context: %s \r \n "
" Extension: %s \r \n "
" Priority: %d \r \n "
2004-08-03 17:48:18 +00:00
" Seconds: %ld \r \n "
2002-09-12 18:32:42 +00:00
" %s "
2003-06-14 14:57:35 +00:00
" Uniqueid: %s \r \n "
2003-09-08 16:44:36 +00:00
" %s "
2003-06-14 14:57:35 +00:00
" \r \n " ,
2004-10-02 00:58:31 +00:00
c - > name ,
c - > cid . cid_num ? c - > cid . cid_num : " <unknown> " ,
c - > cid . cid_name ? c - > cid . cid_name : " <unknown> " ,
2004-06-26 14:31:09 +00:00
c - > accountcode ,
2002-09-12 18:32:42 +00:00
ast_state2str ( c - > _state ) , c - > context ,
2004-08-03 17:48:18 +00:00
c - > exten , c - > priority , ( long ) elapsed_seconds , bridge , c - > uniqueid , idText ) ;
2002-09-12 18:32:42 +00:00
} else {
2006-03-25 23:50:09 +00:00
astman_append ( s ,
2002-09-12 18:32:42 +00:00
" Event: Status \r \n "
2005-04-04 16:18:11 +00:00
" Privilege: Call \r \n "
2002-09-12 18:32:42 +00:00
" Channel: %s \r \n "
" CallerID: %s \r \n "
2004-10-02 00:58:31 +00:00
" CallerIDName: %s \r \n "
2004-06-26 14:31:09 +00:00
" Account: %s \r \n "
2002-09-12 18:32:42 +00:00
" State: %s \r \n "
" %s "
2003-08-12 23:08:49 +00:00
" Uniqueid: %s \r \n "
2003-09-08 16:44:36 +00:00
" %s "
2003-08-12 23:08:49 +00:00
" \r \n " ,
2004-10-02 00:58:31 +00:00
c - > name ,
c - > cid . cid_num ? c - > cid . cid_num : " <unknown> " ,
c - > cid . cid_name ? c - > cid . cid_name : " <unknown> " ,
2004-06-26 14:31:09 +00:00
c - > accountcode ,
2003-09-08 16:44:36 +00:00
ast_state2str ( c - > _state ) , bridge , c - > uniqueid , idText ) ;
2002-09-12 18:32:42 +00:00
}
2005-06-09 19:27:19 +00:00
ast_mutex_unlock ( & c - > lock ) ;
2005-06-06 02:29:18 +00:00
if ( ! all )
2004-06-26 14:31:09 +00:00
break ;
2004-05-20 16:30:10 +00:00
c = ast_channel_walk_locked ( c ) ;
2002-09-12 18:32:42 +00:00
}
2006-03-25 23:50:09 +00:00
astman_append ( s ,
2004-01-29 00:28:51 +00:00
" Event: StatusComplete \r \n "
" %s "
" \r \n " , idText ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2005-04-13 05:45:53 +00:00
static char mandescr_redirect [ ] =
" Description: Redirect (transfer) a call. \n "
" Variables: (Names marked with * are required) \n "
" *Channel: Channel to redirect \n "
" ExtraChannel: Second call leg to transfer (optional) \n "
" *Exten: Extension to transfer to \n "
" *Context: Context to transfer to \n "
" *Priority: Priority to transfer to \n "
" ActionID: Optional Action id for message matching. \n " ;
2005-10-26 13:03:17 +00:00
/*! \brief action_redirect: The redirect manager command */
2002-09-12 18:32:42 +00:00
static int action_redirect ( struct mansession * s , struct message * m )
{
2003-03-31 17:40:18 +00:00
char * name = astman_get_header ( m , " Channel " ) ;
char * name2 = astman_get_header ( m , " ExtraChannel " ) ;
char * exten = astman_get_header ( m , " Exten " ) ;
char * context = astman_get_header ( m , " Context " ) ;
char * priority = astman_get_header ( m , " Priority " ) ;
2004-05-22 04:11:22 +00:00
struct ast_channel * chan , * chan2 = NULL ;
2002-09-12 18:32:42 +00:00
int pi = 0 ;
int res ;
2005-04-13 05:45:53 +00:00
2005-10-26 18:54:24 +00:00
if ( ast_strlen_zero ( name ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Channel not specified " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2004-05-26 19:30:12 +00:00
if ( ! ast_strlen_zero ( priority ) & & ( sscanf ( priority , " %d " , & pi ) ! = 1 ) ) {
2005-12-27 19:13:13 +00:00
if ( ( pi = ast_findlabel_extension ( NULL , context , exten , priority , NULL ) ) < 1 ) {
astman_send_error ( s , m , " Invalid priority \n " ) ;
return 0 ;
}
2002-09-12 18:32:42 +00:00
}
2006-03-28 23:52:21 +00:00
/* XXX watch out, possible deadlock!!! */
2004-05-22 04:11:22 +00:00
chan = ast_get_channel_by_name_locked ( name ) ;
2004-05-24 15:28:36 +00:00
if ( ! chan ) {
2005-04-13 05:45:53 +00:00
char buf [ BUFSIZ ] ;
snprintf ( buf , sizeof ( buf ) , " Channel does not exist: %s " , name ) ;
astman_send_error ( s , m , buf ) ;
2004-05-24 15:28:36 +00:00
return 0 ;
}
2004-05-26 19:30:12 +00:00
if ( ! ast_strlen_zero ( name2 ) )
2004-05-22 04:11:22 +00:00
chan2 = ast_get_channel_by_name_locked ( name2 ) ;
res = ast_async_goto ( chan , context , exten , pi ) ;
2002-09-12 18:32:42 +00:00
if ( ! res ) {
2004-05-26 19:30:12 +00:00
if ( ! ast_strlen_zero ( name2 ) ) {
2004-05-22 04:11:22 +00:00
if ( chan2 )
res = ast_async_goto ( chan2 , context , exten , pi ) ;
else
res = - 1 ;
2002-09-12 18:32:42 +00:00
if ( ! res )
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Dual Redirect successful " ) ;
2002-09-12 18:32:42 +00:00
else
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Secondary redirect failed " ) ;
2002-09-12 18:32:42 +00:00
} else
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Redirect successful " ) ;
2002-09-12 18:32:42 +00:00
} else
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Redirect failed " ) ;
2004-05-22 04:11:22 +00:00
if ( chan )
ast_mutex_unlock ( & chan - > lock ) ;
if ( chan2 )
ast_mutex_unlock ( & chan2 - > lock ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2005-02-26 07:15:18 +00:00
static char mandescr_command [ ] =
" Description: Run a CLI command. \n "
" Variables: (Names marked with * are required) \n "
" *Command: Asterisk CLI command to run \n "
" ActionID: Optional Action id for message matching. \n " ;
2005-04-13 05:45:53 +00:00
2005-10-26 13:03:17 +00:00
/*! \brief action_command: Manager command "command" - execute CLI command */
2003-01-28 22:33:41 +00:00
static int action_command ( struct mansession * s , struct message * m )
{
2003-03-31 17:40:18 +00:00
char * cmd = astman_get_header ( m , " Command " ) ;
2004-04-29 02:59:29 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " Response: Follows \r \n Privilege: Command \r \n " ) ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( id ) )
2006-03-25 23:50:09 +00:00
astman_append ( s , " ActionID: %s \r \n " , id ) ;
2003-09-08 16:44:36 +00:00
/* FIXME: Wedge a ActionID response in here, waiting for later changes */
2003-01-28 22:33:41 +00:00
ast_cli_command ( s - > fd , cmd ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " --END COMMAND-- \r \n \r \n " ) ;
2003-01-28 22:33:41 +00:00
return 0 ;
}
2004-05-01 23:52:27 +00:00
static void * fast_originate ( void * data )
{
struct fast_originate_helper * in = data ;
int res ;
int reason = 0 ;
2005-02-02 02:54:15 +00:00
struct ast_channel * chan = NULL ;
2004-05-26 19:30:12 +00:00
if ( ! ast_strlen_zero ( in - > app ) ) {
2004-10-02 00:58:31 +00:00
res = ast_pbx_outgoing_app ( in - > tech , AST_FORMAT_SLINEAR , in - > data , in - > timeout , in - > app , in - > appdata , & reason , 1 ,
2006-03-26 16:08:42 +00:00
S_OR ( in - > cid_num , NULL ) ,
S_OR ( in - > cid_name , NULL ) ,
2006-02-11 18:31:59 +00:00
in - > vars , in - > account , & chan ) ;
2004-05-01 23:52:27 +00:00
} else {
2004-10-02 00:58:31 +00:00
res = ast_pbx_outgoing_exten ( in - > tech , AST_FORMAT_SLINEAR , in - > data , in - > timeout , in - > context , in - > exten , in - > priority , & reason , 1 ,
2006-03-26 16:08:42 +00:00
S_OR ( in - > cid_num , NULL ) ,
S_OR ( in - > cid_name , NULL ) ,
2006-02-11 18:31:59 +00:00
in - > vars , in - > account , & chan ) ;
2004-05-01 23:52:27 +00:00
}
2006-01-03 11:31:56 +00:00
/* Tell the manager what happened with the channel */
manager_event ( EVENT_FLAG_CALL ,
res ? " OriginateSuccess " : " OriginateFailure " ,
" %s "
" Channel: %s/%s \r \n "
" Context: %s \r \n "
" Exten: %s \r \n "
" Reason: %d \r \n "
" Uniqueid: %s \r \n "
" CallerID: %s \r \n "
" CallerIDName: %s \r \n " ,
in - > idtext , in - > tech , in - > data , in - > context , in - > exten , reason ,
chan ? chan - > uniqueid : " <null> " ,
in - > cid_num ? in - > cid_num : " <unknown> " ,
in - > cid_name ? in - > cid_name : " <unknown> "
) ;
2004-09-14 22:15:50 +00:00
2005-02-02 02:54:15 +00:00
/* Locked by ast_pbx_outgoing_exten or ast_pbx_outgoing_app */
if ( chan )
ast_mutex_unlock ( & chan - > lock ) ;
2004-05-01 23:52:27 +00:00
free ( in ) ;
return NULL ;
}
2004-06-02 20:08:08 +00:00
static char mandescr_originate [ ] =
" Description: Generates an outgoing call to a Extension/Context/Priority or \n "
" Application/Data \n "
" Variables: (Names marked with * are required) \n "
" *Channel: Channel name to call \n "
" Exten: Extension to use (requires 'Context' and 'Priority') \n "
" Context: Context to use (requires 'Exten' and 'Priority') \n "
" Priority: Priority to use (requires 'Exten' and 'Context') \n "
" Application: Application to use \n "
" Data: Data to use (requires 'Application') \n "
" Timeout: How long to wait for call to be answered (in ms) \n "
" CallerID: Caller ID to be set on the outgoing channel \n "
2005-10-05 21:12:57 +00:00
" Variable: Channel variable to set, multiple Variable: headers are allowed \n "
2004-06-02 20:08:08 +00:00
" Account: Account code \n "
" Async: Set to 'true' for fast origination \n " ;
2002-09-12 18:32:42 +00:00
static int action_originate ( struct mansession * s , struct message * m )
{
2003-03-31 17:40:18 +00:00
char * name = astman_get_header ( m , " Channel " ) ;
char * exten = astman_get_header ( m , " Exten " ) ;
char * context = astman_get_header ( m , " Context " ) ;
char * priority = astman_get_header ( m , " Priority " ) ;
char * timeout = astman_get_header ( m , " Timeout " ) ;
char * callerid = astman_get_header ( m , " CallerID " ) ;
2005-01-27 16:33:12 +00:00
char * account = astman_get_header ( m , " Account " ) ;
2003-06-26 20:32:52 +00:00
char * app = astman_get_header ( m , " Application " ) ;
char * appdata = astman_get_header ( m , " Data " ) ;
2004-05-01 23:52:27 +00:00
char * async = astman_get_header ( m , " Async " ) ;
2004-09-14 22:15:50 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
2005-07-15 23:24:51 +00:00
struct ast_variable * vars = astman_get_variables ( m ) ;
2002-09-12 18:32:42 +00:00
char * tech , * data ;
2006-04-04 19:03:12 +00:00
char * l = NULL , * n = NULL ;
2002-09-12 18:32:42 +00:00
int pi = 0 ;
int res ;
int to = 30000 ;
int reason = 0 ;
char tmp [ 256 ] ;
2005-07-15 23:24:51 +00:00
char tmp2 [ 256 ] ;
2004-10-02 00:58:31 +00:00
2004-05-01 23:52:27 +00:00
pthread_t th ;
pthread_attr_t attr ;
2002-09-12 18:32:42 +00:00
if ( ! name ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Channel not specified " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2004-05-26 19:30:12 +00:00
if ( ! ast_strlen_zero ( priority ) & & ( sscanf ( priority , " %d " , & pi ) ! = 1 ) ) {
2005-12-27 19:13:13 +00:00
if ( ( pi = ast_findlabel_extension ( NULL , context , exten , priority , NULL ) ) < 1 ) {
astman_send_error ( s , m , " Invalid priority \n " ) ;
return 0 ;
}
2002-09-12 18:32:42 +00:00
}
2004-05-26 19:30:12 +00:00
if ( ! ast_strlen_zero ( timeout ) & & ( sscanf ( timeout , " %d " , & to ) ! = 1 ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Invalid timeout \n " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2005-07-10 22:56:21 +00:00
ast_copy_string ( tmp , name , sizeof ( tmp ) ) ;
2002-09-12 18:32:42 +00:00
tech = tmp ;
data = strchr ( tmp , ' / ' ) ;
if ( ! data ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Invalid channel \n " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2006-03-28 23:52:21 +00:00
* data + + = ' \0 ' ;
2005-07-10 22:56:21 +00:00
ast_copy_string ( tmp2 , callerid , sizeof ( tmp2 ) ) ;
2004-10-02 00:58:31 +00:00
ast_callerid_parse ( tmp2 , & n , & l ) ;
if ( n ) {
if ( ast_strlen_zero ( n ) )
n = NULL ;
}
if ( l ) {
ast_shrink_phone_number ( l ) ;
if ( ast_strlen_zero ( l ) )
l = NULL ;
}
2004-09-17 14:15:11 +00:00
if ( ast_true ( async ) ) {
2004-05-01 23:52:27 +00:00
struct fast_originate_helper * fast = malloc ( sizeof ( struct fast_originate_helper ) ) ;
2004-09-17 14:15:11 +00:00
if ( ! fast ) {
2004-05-01 23:52:27 +00:00
res = - 1 ;
2004-09-17 14:15:11 +00:00
} else {
2004-05-01 23:52:27 +00:00
memset ( fast , 0 , sizeof ( struct fast_originate_helper ) ) ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( id ) )
2004-09-14 22:15:50 +00:00
snprintf ( fast - > idtext , sizeof ( fast - > idtext ) , " ActionID: %s \r \n " , id ) ;
2005-07-10 22:56:21 +00:00
ast_copy_string ( fast - > tech , tech , sizeof ( fast - > tech ) ) ;
ast_copy_string ( fast - > data , data , sizeof ( fast - > data ) ) ;
ast_copy_string ( fast - > app , app , sizeof ( fast - > app ) ) ;
ast_copy_string ( fast - > appdata , appdata , sizeof ( fast - > appdata ) ) ;
2004-10-02 00:58:31 +00:00
if ( l )
2005-07-10 22:56:21 +00:00
ast_copy_string ( fast - > cid_num , l , sizeof ( fast - > cid_num ) ) ;
2004-10-02 00:58:31 +00:00
if ( n )
2005-07-10 22:56:21 +00:00
ast_copy_string ( fast - > cid_name , n , sizeof ( fast - > cid_name ) ) ;
2005-07-15 23:24:51 +00:00
fast - > vars = vars ;
2005-07-10 22:56:21 +00:00
ast_copy_string ( fast - > context , context , sizeof ( fast - > context ) ) ;
ast_copy_string ( fast - > exten , exten , sizeof ( fast - > exten ) ) ;
2006-02-11 18:31:59 +00:00
ast_copy_string ( fast - > account , account , sizeof ( fast - > account ) ) ;
2004-05-01 23:52:27 +00:00
fast - > timeout = to ;
fast - > priority = pi ;
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2004-09-17 14:15:11 +00:00
if ( ast_pthread_create ( & th , & attr , fast_originate , fast ) ) {
2004-05-01 23:52:27 +00:00
res = - 1 ;
2004-09-17 14:15:11 +00:00
} else {
2004-05-01 23:52:27 +00:00
res = 0 ;
}
}
2004-05-26 19:30:12 +00:00
} else if ( ! ast_strlen_zero ( app ) ) {
2006-02-11 18:31:59 +00:00
res = ast_pbx_outgoing_app ( tech , AST_FORMAT_SLINEAR , data , to , app , appdata , & reason , 1 , l , n , vars , account , NULL ) ;
2004-01-14 09:31:24 +00:00
} else {
2004-03-09 20:01:46 +00:00
if ( exten & & context & & pi )
2006-02-11 18:31:59 +00:00
res = ast_pbx_outgoing_exten ( tech , AST_FORMAT_SLINEAR , data , to , context , exten , pi , & reason , 1 , l , n , vars , account , NULL ) ;
2004-03-09 20:01:46 +00:00
else {
astman_send_error ( s , m , " Originate with 'Exten' requires 'Context' and 'Priority' " ) ;
return 0 ;
}
2003-06-26 20:32:52 +00:00
}
2002-09-12 18:32:42 +00:00
if ( ! res )
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Originate successfully queued " ) ;
2002-09-12 18:32:42 +00:00
else
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Originate failed " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2005-11-14 19:00:38 +00:00
/*! \brief Help text for manager command mailboxstatus
*/
2005-02-26 07:15:18 +00:00
static char mandescr_mailboxstatus [ ] =
" Description: Checks a voicemail account for status. \n "
" Variables: (Names marked with * are required) \n "
" *Mailbox: Full mailbox ID <mailbox>@<vm-context> \n "
" ActionID: Optional ActionID for message matching. \n "
" Returns number of messages. \n "
" Message: Mailbox Status \n "
" Mailbox: <mailboxid> \n "
" Waiting: <count> \n "
" \n " ;
2005-11-14 19:00:38 +00:00
2003-02-24 06:00:18 +00:00
static int action_mailboxstatus ( struct mansession * s , struct message * m )
{
2003-03-31 17:40:18 +00:00
char * mailbox = astman_get_header ( m , " Mailbox " ) ;
2003-09-08 16:44:36 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
char idText [ 256 ] = " " ;
2004-09-10 15:11:38 +00:00
int ret ;
2005-10-26 18:54:24 +00:00
if ( ast_strlen_zero ( mailbox ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Mailbox not specified " ) ;
2003-02-24 06:00:18 +00:00
return 0 ;
}
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( id ) )
2006-03-28 23:52:21 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
2004-10-03 21:18:27 +00:00
ret = ast_app_has_voicemail ( mailbox , NULL ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " Response: Success \r \n "
2003-09-08 16:44:36 +00:00
" %s "
2003-04-07 02:04:56 +00:00
" Message: Mailbox Status \r \n "
" Mailbox: %s \r \n "
2004-09-10 15:11:38 +00:00
" Waiting: %d \r \n \r \n " , idText , mailbox , ret ) ;
2003-04-06 18:19:51 +00:00
return 0 ;
}
2005-02-26 07:15:18 +00:00
static char mandescr_mailboxcount [ ] =
" Description: Checks a voicemail account for new messages. \n "
" Variables: (Names marked with * are required) \n "
" *Mailbox: Full mailbox ID <mailbox>@<vm-context> \n "
" ActionID: Optional ActionID for message matching. \n "
" Returns number of new and old messages. \n "
" Message: Mailbox Message Count \n "
" Mailbox: <mailboxid> \n "
" NewMessages: <count> \n "
" OldMessages: <count> \n "
" \n " ;
2003-06-21 20:05:16 +00:00
static int action_mailboxcount ( struct mansession * s , struct message * m )
{
char * mailbox = astman_get_header ( m , " Mailbox " ) ;
2003-09-08 16:44:36 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
char idText [ 256 ] = " " ;
2003-06-21 20:05:16 +00:00
int newmsgs = 0 , oldmsgs = 0 ;
2005-10-26 18:54:24 +00:00
if ( ast_strlen_zero ( mailbox ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Mailbox not specified " ) ;
2003-06-21 20:05:16 +00:00
return 0 ;
}
ast_app_messagecount ( mailbox , & newmsgs , & oldmsgs ) ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( id ) ) {
2006-03-28 23:52:21 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
2005-09-28 23:10:14 +00:00
}
2006-03-25 23:50:09 +00:00
astman_append ( s , " Response: Success \r \n "
2003-09-08 16:44:36 +00:00
" %s "
2003-06-21 20:05:16 +00:00
" Message: Mailbox Message Count \r \n "
" Mailbox: %s \r \n "
" NewMessages: %d \r \n "
" OldMessages: %d \r \n "
" \r \n " ,
2003-09-08 16:44:36 +00:00
idText , mailbox , newmsgs , oldmsgs ) ;
2003-06-21 20:05:16 +00:00
return 0 ;
}
2005-02-26 07:15:18 +00:00
static char mandescr_extensionstate [ ] =
" Description: Report the extension state for given extension. \n "
" If the extension has a hint, will use devicestate to check \n "
" the status of the device connected to the extension. \n "
" Variables: (Names marked with * are required) \n "
" *Exten: Extension to check state on \n "
" *Context: Context for extension \n "
" ActionId: Optional ID for this transaction \n "
" Will return an \" Extension Status \" message. \n "
" The response will include the hint for the extension and the status. \n " ;
2003-04-06 18:19:51 +00:00
static int action_extensionstate ( struct mansession * s , struct message * m )
{
char * exten = astman_get_header ( m , " Exten " ) ;
char * context = astman_get_header ( m , " Context " ) ;
2003-09-08 16:44:36 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
char idText [ 256 ] = " " ;
2003-04-07 02:04:56 +00:00
char hint [ 256 ] = " " ;
2003-04-06 18:19:51 +00:00
int status ;
2005-10-26 18:54:24 +00:00
if ( ast_strlen_zero ( exten ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Extension not specified " ) ;
2003-04-06 18:19:51 +00:00
return 0 ;
}
2005-10-26 18:54:24 +00:00
if ( ast_strlen_zero ( context ) )
2003-04-06 18:19:51 +00:00
context = " default " ;
status = ast_extension_state ( NULL , context , exten ) ;
2005-02-01 01:53:25 +00:00
ast_get_hint ( hint , sizeof ( hint ) - 1 , NULL , 0 , NULL , context , exten ) ;
2005-10-26 18:54:24 +00:00
if ( ! ast_strlen_zero ( id ) ) {
2006-03-28 23:52:21 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
2003-09-08 16:44:36 +00:00
}
2006-03-25 23:50:09 +00:00
astman_append ( s , " Response: Success \r \n "
2003-09-08 16:44:36 +00:00
" %s "
2003-04-07 02:04:56 +00:00
" Message: Extension Status \r \n "
" Exten: %s \r \n "
" Context: %s \r \n "
" Hint: %s \r \n "
2003-09-08 16:44:36 +00:00
" Status: %d \r \n \r \n " ,
idText , exten , context , hint , status ) ;
2003-02-24 06:00:18 +00:00
return 0 ;
}
2005-02-26 07:15:18 +00:00
static char mandescr_timeout [ ] =
" Description: Hangup a channel after a certain time. \n "
" Variables: (Names marked with * are required) \n "
" *Channel: Channel name to hangup \n "
" *Timeout: Maximum duration of the call (sec) \n "
" Acknowledges set time with 'Timeout Set' message \n " ;
2003-06-09 21:40:20 +00:00
static int action_timeout ( struct mansession * s , struct message * m )
{
struct ast_channel * c = NULL ;
char * name = astman_get_header ( m , " Channel " ) ;
int timeout = atoi ( astman_get_header ( m , " Timeout " ) ) ;
2004-05-26 19:30:12 +00:00
if ( ast_strlen_zero ( name ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " No channel specified " ) ;
2003-06-09 21:40:20 +00:00
return 0 ;
}
if ( ! timeout ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " No timeout specified " ) ;
2003-06-09 21:40:20 +00:00
return 0 ;
}
2005-06-06 02:29:18 +00:00
c = ast_get_channel_by_name_locked ( name ) ;
2003-06-09 21:40:20 +00:00
if ( ! c ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " No such channel " ) ;
2003-06-09 21:40:20 +00:00
return 0 ;
}
ast_channel_setwhentohangup ( c , timeout ) ;
2004-05-20 16:30:10 +00:00
ast_mutex_unlock ( & c - > lock ) ;
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Timeout Set " ) ;
2003-06-09 21:40:20 +00:00
return 0 ;
}
2006-04-02 19:59:55 +00:00
static int process_events ( struct mansession * s )
{
struct eventqent * eqe ;
int ret = 0 ;
ast_mutex_lock ( & s - > __lock ) ;
if ( s - > fd > - 1 ) {
s - > busy - - ;
if ( ! s - > eventq )
s - > eventq = master_eventq ;
while ( s - > eventq - > next ) {
eqe = s - > eventq - > next ;
if ( ( s - > authenticated & & ( s - > readperm & eqe - > category ) = = eqe - > category ) & &
( ( s - > send_events & eqe - > category ) = = eqe - > category ) ) {
if ( ! ret & & ast_carefulwrite ( s - > fd , eqe - > eventdata , strlen ( eqe - > eventdata ) , s - > writetimeout ) < 0 )
ret = - 1 ;
}
unuse_eventqent ( s - > eventq ) ;
s - > eventq = eqe ;
}
}
ast_mutex_unlock ( & s - > __lock ) ;
return ret ;
}
2002-09-12 18:32:42 +00:00
static int process_message ( struct mansession * s , struct message * m )
{
2004-07-14 07:44:19 +00:00
char action [ 80 ] = " " ;
2003-01-28 22:33:41 +00:00
struct manager_action * tmp = first_action ;
2003-09-08 16:44:36 +00:00
char * id = astman_get_header ( m , " ActionID " ) ;
char idText [ 256 ] = " " ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2006-04-02 19:59:55 +00:00
int ret = 0 ;
2003-01-28 22:33:41 +00:00
2005-07-10 22:56:21 +00:00
ast_copy_string ( action , astman_get_header ( m , " Action " ) , sizeof ( action ) ) ;
2003-03-20 17:21:54 +00:00
ast_log ( LOG_DEBUG , " Manager received command '%s' \n " , action ) ;
2003-01-28 22:33:41 +00:00
2004-05-26 19:30:12 +00:00
if ( ast_strlen_zero ( action ) ) {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Missing action in request " ) ;
2002-09-12 18:32:42 +00:00
return 0 ;
}
2006-04-02 19:59:55 +00:00
if ( ! ast_strlen_zero ( id ) ) {
2006-04-04 19:03:12 +00:00
snprintf ( idText , sizeof ( idText ) , " ActionID: %s \r \n " , id ) ;
2006-04-02 19:59:55 +00:00
}
2002-09-12 18:32:42 +00:00
if ( ! s - > authenticated ) {
2003-03-10 06:00:17 +00:00
if ( ! strcasecmp ( action , " Challenge " ) ) {
char * authtype ;
2003-03-31 17:40:18 +00:00
authtype = astman_get_header ( m , " AuthType " ) ;
2003-03-10 06:00:17 +00:00
if ( ! strcasecmp ( authtype , " MD5 " ) ) {
2005-10-26 18:54:24 +00:00
if ( ast_strlen_zero ( s - > challenge ) )
2006-04-05 17:44:44 +00:00
snprintf ( s - > challenge , sizeof ( s - > challenge ) , " %ld " , ast_random ( ) ) ;
2005-09-28 23:10:14 +00:00
ast_mutex_lock ( & s - > __lock ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " Response: Success \r \n "
2003-09-08 16:44:36 +00:00
" %s "
" Challenge: %s \r \n \r \n " ,
2006-04-04 19:03:12 +00:00
idText , s - > challenge ) ;
2005-09-28 23:10:14 +00:00
ast_mutex_unlock ( & s - > __lock ) ;
2003-03-10 06:00:17 +00:00
return 0 ;
} else {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Must specify AuthType " ) ;
2003-03-10 06:00:17 +00:00
return 0 ;
}
} else if ( ! strcasecmp ( action , " Login " ) ) {
2002-09-12 18:32:42 +00:00
if ( authenticate ( s , m ) ) {
sleep ( 1 ) ;
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Authentication failed " ) ;
2002-09-12 18:32:42 +00:00
return - 1 ;
} else {
s - > authenticated = 1 ;
2005-01-05 06:24:59 +00:00
if ( option_verbose > 1 ) {
2006-04-04 19:03:12 +00:00
if ( displayconnects ) {
2006-04-01 08:49:54 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " %sManager '%s' logged on from %s \n " , ( s - > sessiontimeout ? " HTTP " : " " ) , s - > username , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
2005-01-05 06:24:59 +00:00
}
}
2006-04-01 08:49:54 +00:00
ast_log ( LOG_EVENT , " %sManager '%s' logged on from %s \n " , ( s - > sessiontimeout ? " HTTP " : " " ) , s - > username , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " Authentication accepted " ) ;
2002-09-12 18:32:42 +00:00
}
2003-08-18 06:03:16 +00:00
} else if ( ! strcasecmp ( action , " Logoff " ) ) {
2003-09-08 16:44:36 +00:00
astman_send_ack ( s , m , " See ya " ) ;
2003-08-18 06:03:16 +00:00
return - 1 ;
} else
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Authentication Required " ) ;
2002-09-12 18:32:42 +00:00
} else {
2005-09-28 23:10:14 +00:00
ast_mutex_lock ( & s - > __lock ) ;
2006-04-01 08:49:54 +00:00
s - > busy + + ;
2005-09-28 23:10:14 +00:00
ast_mutex_unlock ( & s - > __lock ) ;
2006-04-04 19:03:12 +00:00
while ( tmp ) {
2003-01-28 22:33:41 +00:00
if ( ! strcasecmp ( action , tmp - > action ) ) {
if ( ( s - > writeperm & tmp - > authority ) = = tmp - > authority ) {
if ( tmp - > func ( s , m ) )
2005-09-28 23:10:14 +00:00
ret = - 1 ;
2002-09-12 18:32:42 +00:00
} else {
2003-09-08 16:44:36 +00:00
astman_send_error ( s , m , " Permission denied " ) ;
2002-09-12 18:32:42 +00:00
}
2005-09-28 23:10:14 +00:00
break ;
2002-09-12 18:32:42 +00:00
}
2003-01-28 22:33:41 +00:00
tmp = tmp - > next ;
2002-09-12 18:32:42 +00:00
}
2005-10-03 21:01:29 +00:00
if ( ! tmp )
2005-09-30 23:44:12 +00:00
astman_send_error ( s , m , " Invalid/unknown command " ) ;
2002-09-12 18:32:42 +00:00
}
2006-04-02 19:59:55 +00:00
if ( ret )
return ret ;
return process_events ( s ) ;
2002-09-12 18:32:42 +00:00
}
static int get_input ( struct mansession * s , char * output )
{
/* output must have at least sizeof(s->inbuf) space */
int res ;
int x ;
2004-04-25 20:42:45 +00:00
struct pollfd fds [ 1 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2006-04-04 19:03:12 +00:00
for ( x = 1 ; x < s - > inlen ; x + + ) {
2002-09-12 18:32:42 +00:00
if ( ( s - > inbuf [ x ] = = ' \n ' ) & & ( s - > inbuf [ x - 1 ] = = ' \r ' ) ) {
/* Copy output data up to and including \r\n */
memcpy ( output , s - > inbuf , x + 1 ) ;
/* Add trailing \0 */
output [ x + 1 ] = ' \0 ' ;
/* Move remaining data back to the front */
memmove ( s - > inbuf , s - > inbuf + x + 1 , s - > inlen - x ) ;
s - > inlen - = ( x + 1 ) ;
return 1 ;
}
}
if ( s - > inlen > = sizeof ( s - > inbuf ) - 1 ) {
2004-06-29 12:56:46 +00:00
ast_log ( LOG_WARNING , " Dumping long line with no return from %s: %s \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) , s - > inbuf ) ;
2002-09-12 18:32:42 +00:00
s - > inlen = 0 ;
}
2004-04-25 20:42:45 +00:00
fds [ 0 ] . fd = s - > fd ;
fds [ 0 ] . events = POLLIN ;
2005-09-25 16:58:56 +00:00
do {
2006-04-02 19:59:55 +00:00
ast_mutex_lock ( & s - > __lock ) ;
s - > waiting_thread = pthread_self ( ) ;
ast_mutex_unlock ( & s - > __lock ) ;
2005-09-25 16:58:56 +00:00
res = poll ( fds , 1 , - 1 ) ;
2006-04-02 19:59:55 +00:00
ast_mutex_lock ( & s - > __lock ) ;
s - > waiting_thread = AST_PTHREADT_NULL ;
ast_mutex_unlock ( & s - > __lock ) ;
2005-09-25 16:58:56 +00:00
if ( res < 0 ) {
2005-09-29 20:37:01 +00:00
if ( errno = = EINTR ) {
if ( s - > dead )
return - 1 ;
2006-04-02 19:59:55 +00:00
return 0 ;
2005-09-29 20:37:01 +00:00
}
2005-09-25 16:58:56 +00:00
ast_log ( LOG_WARNING , " Select returned error: %s \n " , strerror ( errno ) ) ;
return - 1 ;
} else if ( res > 0 ) {
2005-09-28 23:10:14 +00:00
ast_mutex_lock ( & s - > __lock ) ;
2005-09-25 16:58:56 +00:00
res = read ( s - > fd , s - > inbuf + s - > inlen , sizeof ( s - > inbuf ) - 1 - s - > inlen ) ;
2005-09-28 23:10:14 +00:00
ast_mutex_unlock ( & s - > __lock ) ;
2005-09-25 16:58:56 +00:00
if ( res < 1 )
return - 1 ;
break ;
}
} while ( 1 ) ;
2002-09-12 18:32:42 +00:00
s - > inlen + = res ;
s - > inbuf [ s - > inlen ] = ' \0 ' ;
return 0 ;
}
static void * session_do ( void * data )
{
struct mansession * s = data ;
struct message m ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-09-12 18:32:42 +00:00
int res ;
2005-09-28 23:10:14 +00:00
ast_mutex_lock ( & s - > __lock ) ;
2006-03-25 23:50:09 +00:00
astman_append ( s , " Asterisk Call Manager/1.0 \r \n " ) ;
2005-09-28 23:10:14 +00:00
ast_mutex_unlock ( & s - > __lock ) ;
2005-09-30 16:27:14 +00:00
memset ( & m , 0 , sizeof ( m ) ) ;
2002-09-12 18:32:42 +00:00
for ( ; ; ) {
res = get_input ( s , m . headers [ m . hdrcount ] ) ;
if ( res > 0 ) {
/* Strip trailing \r\n */
if ( strlen ( m . headers [ m . hdrcount ] ) < 2 )
continue ;
m . headers [ m . hdrcount ] [ strlen ( m . headers [ m . hdrcount ] ) - 2 ] = ' \0 ' ;
2004-05-26 19:30:12 +00:00
if ( ast_strlen_zero ( m . headers [ m . hdrcount ] ) ) {
2002-09-12 18:32:42 +00:00
if ( process_message ( s , & m ) )
break ;
2005-09-30 16:27:14 +00:00
memset ( & m , 0 , sizeof ( m ) ) ;
2006-02-11 18:31:59 +00:00
} else if ( m . hdrcount < AST_MAX_MANHEADERS - 1 )
2002-09-12 18:32:42 +00:00
m . hdrcount + + ;
2006-04-02 19:59:55 +00:00
} else if ( res < 0 ) {
2002-09-12 18:32:42 +00:00
break ;
2006-04-02 19:59:55 +00:00
} else if ( s - > eventq - > next ) {
if ( process_events ( s ) )
break ;
}
2002-09-12 18:32:42 +00:00
}
if ( s - > authenticated ) {
2005-01-05 06:24:59 +00:00
if ( option_verbose > 1 ) {
if ( displayconnects )
2006-04-04 19:03:12 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Manager '%s' logged off from %s \n " , s - > username , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
2005-01-05 06:24:59 +00:00
}
2004-06-29 12:56:46 +00:00
ast_log ( LOG_EVENT , " Manager '%s' logged off from %s \n " , s - > username , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
2002-09-12 18:32:42 +00:00
} else {
2005-01-05 06:24:59 +00:00
if ( option_verbose > 1 ) {
2006-04-04 19:03:12 +00:00
if ( displayconnects )
2005-01-05 06:24:59 +00:00
ast_verbose ( VERBOSE_PREFIX_2 " Connect attempt from '%s' unable to authenticate \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
}
2004-06-29 12:56:46 +00:00
ast_log ( LOG_EVENT , " Failed attempt from %s \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
2002-09-12 18:32:42 +00:00
}
destroy_session ( s ) ;
return NULL ;
}
static void * accept_thread ( void * ignore )
{
int as ;
struct sockaddr_in sin ;
2005-05-15 03:21:51 +00:00
socklen_t sinlen ;
2006-04-02 19:59:55 +00:00
struct eventqent * eqe ;
2006-04-04 19:03:12 +00:00
struct mansession * s , * prev = NULL , * next ;
2003-03-20 17:21:54 +00:00
struct protoent * p ;
int arg = 1 ;
2004-02-07 07:13:33 +00:00
int flags ;
2003-03-06 06:00:17 +00:00
pthread_attr_t attr ;
2006-04-01 08:49:54 +00:00
time_t now ;
struct pollfd pfds [ 1 ] ;
char iabuf [ INET_ADDRSTRLEN ] ;
2003-03-06 06:00:17 +00:00
pthread_attr_init ( & attr ) ;
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_DETACHED ) ;
2003-03-20 17:21:54 +00:00
2002-09-12 18:32:42 +00:00
for ( ; ; ) {
2006-04-01 08:49:54 +00:00
time ( & now ) ;
ast_mutex_lock ( & sessionlock ) ;
prev = NULL ;
s = sessions ;
2006-04-04 19:03:12 +00:00
while ( s ) {
2006-04-01 08:49:54 +00:00
next = s - > next ;
if ( s - > sessiontimeout & & ( now > s - > sessiontimeout ) & & ! s - > inuse ) {
2006-04-02 19:59:55 +00:00
num_sessions - - ;
2006-04-01 08:49:54 +00:00
if ( prev )
prev - > next = next ;
else
sessions = next ;
if ( s - > authenticated & & ( option_verbose > 1 ) & & displayconnects ) {
ast_verbose ( VERBOSE_PREFIX_2 " HTTP Manager '%s' timed out from %s \n " ,
s - > username , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
}
free_session ( s ) ;
} else
prev = s ;
s = next ;
}
2006-04-02 19:59:55 +00:00
/* Purge master event queue of old, unused events, but make sure we
always keep at least one in the queue */
eqe = master_eventq ;
while ( master_eventq - > next & & ! master_eventq - > usecount ) {
eqe = master_eventq ;
master_eventq = master_eventq - > next ;
free ( eqe ) ;
}
2006-04-01 08:49:54 +00:00
ast_mutex_unlock ( & sessionlock ) ;
2002-09-12 18:32:42 +00:00
sinlen = sizeof ( sin ) ;
2006-04-01 08:49:54 +00:00
pfds [ 0 ] . fd = asock ;
pfds [ 0 ] . events = POLLIN ;
/* Wait for something to happen, but timeout every few seconds so
we can ditch any old manager sessions */
if ( poll ( pfds , 1 , 5000 ) < 1 )
continue ;
2003-09-08 16:48:07 +00:00
as = accept ( asock , ( struct sockaddr * ) & sin , & sinlen ) ;
2002-09-12 18:32:42 +00:00
if ( as < 0 ) {
ast_log ( LOG_NOTICE , " Accept returned -1: %s \n " , strerror ( errno ) ) ;
continue ;
}
2003-03-20 17:21:54 +00:00
p = getprotobyname ( " tcp " ) ;
2005-03-23 05:56:32 +00:00
if ( p ) {
2003-03-20 17:21:54 +00:00
if ( setsockopt ( as , p - > p_proto , TCP_NODELAY , ( char * ) & arg , sizeof ( arg ) ) < 0 ) {
ast_log ( LOG_WARNING , " Failed to set manager tcp connection to TCP_NODELAY mode: %s \n " , strerror ( errno ) ) ;
}
}
2002-09-12 18:32:42 +00:00
s = malloc ( sizeof ( struct mansession ) ) ;
if ( ! s ) {
ast_log ( LOG_WARNING , " Failed to allocate management session: %s \n " , strerror ( errno ) ) ;
continue ;
}
memset ( s , 0 , sizeof ( struct mansession ) ) ;
memcpy ( & s - > sin , & sin , sizeof ( sin ) ) ;
2005-10-04 22:25:15 +00:00
s - > writetimeout = 100 ;
2006-04-01 08:49:54 +00:00
s - > waiting_thread = AST_PTHREADT_NULL ;
2004-03-01 21:12:32 +00:00
2006-04-04 19:03:12 +00:00
if ( ! block_sockets ) {
2004-03-01 21:12:32 +00:00
/* For safety, make sure socket is non-blocking */
flags = fcntl ( as , F_GETFL ) ;
fcntl ( as , F_SETFL , flags | O_NONBLOCK ) ;
}
2005-09-28 23:10:14 +00:00
ast_mutex_init ( & s - > __lock ) ;
2002-09-12 18:32:42 +00:00
s - > fd = as ;
2004-07-08 15:39:35 +00:00
s - > send_events = - 1 ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & sessionlock ) ;
2006-04-02 19:59:55 +00:00
num_sessions + + ;
2002-09-12 18:32:42 +00:00
s - > next = sessions ;
sessions = s ;
2006-04-02 19:59:55 +00:00
/* Find the last place in the master event queue and hook ourselves
in there */
s - > eventq = master_eventq ;
while ( s - > eventq - > next )
s - > eventq = s - > eventq - > next ;
ast_mutex_lock ( & s - > eventq - > lock ) ;
s - > eventq - > usecount + + ;
ast_mutex_unlock ( & s - > eventq - > lock ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & sessionlock ) ;
2005-09-29 20:37:01 +00:00
if ( ast_pthread_create ( & s - > t , & attr , session_do , s ) )
2002-09-12 18:32:42 +00:00
destroy_session ( s ) ;
}
2003-03-06 06:00:17 +00:00
pthread_attr_destroy ( & attr ) ;
2003-01-28 22:33:41 +00:00
return NULL ;
2002-09-12 18:32:42 +00:00
}
2006-04-02 19:59:55 +00:00
static int append_event ( const char * str , int category )
2005-09-28 23:10:14 +00:00
{
2006-04-04 19:03:12 +00:00
struct eventqent * tmp , * prev = NULL ;
2005-09-28 23:10:14 +00:00
tmp = malloc ( sizeof ( struct eventqent ) + strlen ( str ) ) ;
if ( tmp ) {
2006-04-02 19:59:55 +00:00
ast_mutex_init ( & tmp - > lock ) ;
2005-09-28 23:10:14 +00:00
tmp - > next = NULL ;
2006-04-02 19:59:55 +00:00
tmp - > category = category ;
2005-09-28 23:10:14 +00:00
strcpy ( tmp - > eventdata , str ) ;
2006-04-02 19:59:55 +00:00
if ( master_eventq ) {
prev = master_eventq ;
2006-04-04 19:03:12 +00:00
while ( prev - > next )
2005-09-28 23:10:14 +00:00
prev = prev - > next ;
prev - > next = tmp ;
} else {
2006-04-02 19:59:55 +00:00
master_eventq = tmp ;
2005-09-28 23:10:14 +00:00
}
2006-04-02 19:59:55 +00:00
tmp - > usecount = num_sessions ;
2005-09-28 23:10:14 +00:00
return 0 ;
}
return - 1 ;
}
2005-10-26 13:03:17 +00:00
/*! \brief manager_event: Send AMI event to client */
2006-01-07 15:23:38 +00:00
int manager_event ( int category , const char * event , const char * fmt , . . . )
2002-09-12 18:32:42 +00:00
{
struct mansession * s ;
2005-10-01 15:41:27 +00:00
char auth [ 80 ] ;
2005-10-03 19:40:03 +00:00
char tmp [ 4096 ] = " " ;
2005-10-01 15:41:27 +00:00
char * tmp_next = tmp ;
size_t tmp_left = sizeof ( tmp ) - 2 ;
2002-09-12 18:32:42 +00:00
va_list ap ;
2006-04-02 19:59:55 +00:00
struct timeval now ;
2002-09-12 18:32:42 +00:00
2006-04-02 19:59:55 +00:00
/* Abort if there aren't any manager sessions */
if ( ! num_sessions )
return 0 ;
ast_build_string ( & tmp_next , & tmp_left , " Event: %s \r \n Privilege: %s \r \n " ,
event , authority_to_str ( category , auth , sizeof ( auth ) ) ) ;
if ( timestampevents ) {
now = ast_tvnow ( ) ;
ast_build_string ( & tmp_next , & tmp_left , " Timestamp: %ld.%06lu \r \n " ,
now . tv_sec , ( unsigned long ) now . tv_usec ) ;
}
va_start ( ap , fmt ) ;
ast_build_string_va ( & tmp_next , & tmp_left , fmt , ap ) ;
va_end ( ap ) ;
* tmp_next + + = ' \r ' ;
* tmp_next + + = ' \n ' ;
* tmp_next = ' \0 ' ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & sessionlock ) ;
2006-04-02 19:59:55 +00:00
/* Append even to master list and wake up any sleeping sessions */
append_event ( tmp , category ) ;
2005-09-30 23:52:04 +00:00
for ( s = sessions ; s ; s = s - > next ) {
ast_mutex_lock ( & s - > __lock ) ;
2006-04-02 19:59:55 +00:00
if ( s - > waiting_thread ! = AST_PTHREADT_NULL )
pthread_kill ( s - > waiting_thread , SIGURG ) ;
2005-09-30 23:52:04 +00:00
ast_mutex_unlock ( & s - > __lock ) ;
2002-09-12 18:32:42 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & sessionlock ) ;
2005-09-30 23:52:04 +00:00
2002-09-12 18:32:42 +00:00
return 0 ;
}
2005-09-28 23:10:14 +00:00
int ast_manager_unregister ( char * action )
{
2003-01-28 22:33:41 +00:00
struct manager_action * cur = first_action , * prev = first_action ;
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & actionlock ) ;
2006-04-04 19:03:12 +00:00
while ( cur ) {
2003-01-28 22:33:41 +00:00
if ( ! strcasecmp ( action , cur - > action ) ) {
prev - > next = cur - > next ;
free ( cur ) ;
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Manager unregistered action %s \n " , action ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & actionlock ) ;
2003-01-28 22:33:41 +00:00
return 0 ;
}
prev = cur ;
cur = cur - > next ;
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & actionlock ) ;
2003-01-28 22:33:41 +00:00
return 0 ;
}
2003-04-06 23:32:31 +00:00
static int manager_state_cb ( char * context , char * exten , int state , void * data )
{
/* Notify managers of change */
manager_event ( EVENT_FLAG_CALL , " ExtensionStatus " , " Exten: %s \r \n Context: %s \r \n Status: %d \r \n " , exten , context , state ) ;
return 0 ;
}
2004-06-02 20:08:08 +00:00
static int ast_manager_register_struct ( struct manager_action * act )
2003-01-28 22:33:41 +00:00
{
struct manager_action * cur = first_action , * prev = NULL ;
2004-06-02 20:08:08 +00:00
int ret ;
2003-01-28 22:33:41 +00:00
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & actionlock ) ;
2006-04-04 19:03:12 +00:00
while ( cur ) { /* Walk the list of actions */
2004-06-02 20:08:08 +00:00
ret = strcasecmp ( cur - > action , act - > action ) ;
if ( ret = = 0 ) {
ast_log ( LOG_WARNING , " Manager: Action '%s' already registered \n " , act - > action ) ;
2004-01-14 06:31:18 +00:00
ast_mutex_unlock ( & actionlock ) ;
return - 1 ;
2004-06-02 20:08:08 +00:00
} else if ( ret > 0 ) {
/* Insert these alphabetically */
if ( prev ) {
act - > next = prev - > next ;
prev - > next = act ;
} else {
act - > next = first_action ;
first_action = act ;
}
break ;
2004-01-14 06:31:18 +00:00
}
2003-01-28 22:33:41 +00:00
prev = cur ;
cur = cur - > next ;
}
2004-06-02 20:08:08 +00:00
if ( ! cur ) {
if ( prev )
prev - > next = act ;
else
first_action = act ;
act - > next = NULL ;
}
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " Manager registered action %s \n " , act - > action ) ;
ast_mutex_unlock ( & actionlock ) ;
return 0 ;
}
2005-11-14 19:00:38 +00:00
/*! \brief register a new command with manager, including online help. This is
the preferred way to register a manager command */
2005-03-22 19:09:12 +00:00
int ast_manager_register2 ( const char * action , int auth , int ( * func ) ( struct mansession * s , struct message * m ) , const char * synopsis , const char * description )
2004-06-02 20:08:08 +00:00
{
struct manager_action * cur ;
cur = malloc ( sizeof ( struct manager_action ) ) ;
if ( ! cur ) {
2003-01-28 22:33:41 +00:00
ast_log ( LOG_WARNING , " Manager: out of memory trying to register action \n " ) ;
return - 1 ;
}
2004-06-02 20:08:08 +00:00
cur - > action = action ;
2003-01-28 22:33:41 +00:00
cur - > authority = auth ;
cur - > func = func ;
cur - > synopsis = synopsis ;
2004-06-02 20:08:08 +00:00
cur - > description = description ;
2003-01-28 22:33:41 +00:00
cur - > next = NULL ;
2004-06-02 20:08:08 +00:00
ast_manager_register_struct ( cur ) ;
2003-01-28 22:33:41 +00:00
return 0 ;
}
2005-11-14 19:00:38 +00:00
/*! @}
END Doxygen group */
2003-01-28 22:33:41 +00:00
2006-04-01 08:49:54 +00:00
static struct mansession * find_session ( unsigned long ident )
{
struct mansession * s ;
ast_mutex_lock ( & sessionlock ) ;
s = sessions ;
2006-04-04 19:03:12 +00:00
while ( s ) {
2006-04-01 08:49:54 +00:00
ast_mutex_lock ( & s - > __lock ) ;
if ( s - > sessiontimeout & & ( s - > managerid = = ident ) & & ! s - > needdestroy ) {
s - > inuse + + ;
break ;
}
ast_mutex_unlock ( & s - > __lock ) ;
s = s - > next ;
}
ast_mutex_unlock ( & sessionlock ) ;
return s ;
}
static void vars2msg ( struct message * m , struct ast_variable * vars )
{
int x ;
2006-04-04 19:03:12 +00:00
for ( x = 0 ; vars & & ( x < AST_MAX_MANHEADERS ) ; x + + , vars = vars - > next ) {
2006-04-01 08:49:54 +00:00
if ( ! vars )
break ;
m - > hdrcount = x + 1 ;
snprintf ( m - > headers [ x ] , sizeof ( m - > headers [ x ] ) , " %s: %s " , vars - > name , vars - > value ) ;
}
}
# define FORMAT_RAW 0
# define FORMAT_HTML 1
# define FORMAT_XML 2
static char * contenttype [ ] = { " plain " , " html " , " xml " } ;
static char * generic_http_callback ( int format , struct sockaddr_in * requestor , const char * uri , struct ast_variable * params , int * status , char * * title , int * contentlength )
{
2006-04-04 19:03:12 +00:00
struct mansession * s = NULL ;
unsigned long ident = 0 ;
2006-04-01 08:49:54 +00:00
char workspace [ 256 ] ;
char cookie [ 128 ] ;
char iabuf [ INET_ADDRSTRLEN ] ;
2006-04-03 18:38:28 +00:00
size_t len = sizeof ( workspace ) ;
2006-04-01 08:49:54 +00:00
int blastaway = 0 ;
char * c = workspace ;
2006-04-04 19:03:12 +00:00
char * retval = NULL ;
2006-04-01 08:49:54 +00:00
struct message m ;
struct ast_variable * v ;
2006-04-04 19:03:12 +00:00
2006-04-01 08:49:54 +00:00
v = params ;
2006-04-04 19:03:12 +00:00
while ( v ) {
2006-04-01 08:49:54 +00:00
if ( ! strcasecmp ( v - > name , " mansession_id " ) ) {
sscanf ( v - > value , " %lx " , & ident ) ;
break ;
}
v = v - > next ;
}
s = find_session ( ident ) ;
if ( ! s ) {
/* Create new session */
s = calloc ( 1 , sizeof ( struct mansession ) ) ;
memcpy ( & s - > sin , requestor , sizeof ( s - > sin ) ) ;
s - > fd = - 1 ;
s - > waiting_thread = AST_PTHREADT_NULL ;
s - > send_events = 0 ;
ast_mutex_init ( & s - > __lock ) ;
ast_mutex_lock ( & s - > __lock ) ;
ast_mutex_lock ( & sessionlock ) ;
s - > inuse = 1 ;
s - > managerid = rand ( ) | ( unsigned long ) s ;
s - > next = sessions ;
sessions = s ;
2006-04-02 19:59:55 +00:00
num_sessions + + ;
/* Hook into the last spot in the event queue */
s - > eventq = master_eventq ;
2006-04-04 19:03:12 +00:00
while ( s - > eventq - > next )
2006-04-02 19:59:55 +00:00
s - > eventq = s - > eventq - > next ;
ast_mutex_lock ( & s - > eventq - > lock ) ;
s - > eventq - > usecount + + ;
ast_mutex_unlock ( & s - > eventq - > lock ) ;
2006-04-01 08:49:54 +00:00
ast_mutex_unlock ( & sessionlock ) ;
}
2006-04-02 19:59:55 +00:00
/* Reset HTTP timeout. If we're not yet authenticated, keep it extremely short */
2006-04-01 08:49:54 +00:00
time ( & s - > sessiontimeout ) ;
2006-04-02 19:59:55 +00:00
if ( ! s - > authenticated & & ( httptimeout > 5 ) )
s - > sessiontimeout + = 5 ;
else
s - > sessiontimeout + = httptimeout ;
2006-04-01 08:49:54 +00:00
ast_mutex_unlock ( & s - > __lock ) ;
memset ( & m , 0 , sizeof ( m ) ) ;
if ( s ) {
char tmp [ 80 ] ;
ast_build_string ( & c , & len , " Content-type: text/%s \n " , contenttype [ format ] ) ;
sprintf ( tmp , " %08lx " , s - > managerid ) ;
ast_build_string ( & c , & len , " %s \r \n " , ast_http_setcookie ( " mansession_id " , tmp , httptimeout , cookie , sizeof ( cookie ) ) ) ;
if ( format = = FORMAT_HTML )
ast_build_string ( & c , & len , " <title>Asterisk™ Manager Test Interface</title> " ) ;
vars2msg ( & m , params ) ;
if ( format = = FORMAT_XML ) {
ast_build_string ( & c , & len , " <ajax-response> \n " ) ;
} else if ( format = = FORMAT_HTML ) {
ast_build_string ( & c , & len , " <body bgcolor= \" #ffffff \" ><table align=center bgcolor= \" #f1f1f1 \" width= \" 500 \" > \r \n " ) ;
ast_build_string ( & c , & len , " <tr><td colspan= \" 2 \" bgcolor= \" #f1f1ff \" ><h1> Manager Tester</h1></td></tr> \r \n " ) ;
}
if ( process_message ( s , & m ) ) {
if ( s - > authenticated ) {
if ( option_verbose > 1 ) {
if ( displayconnects )
ast_verbose ( VERBOSE_PREFIX_2 " HTTP Manager '%s' logged off from %s \n " , s - > username , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
}
ast_log ( LOG_EVENT , " HTTP Manager '%s' logged off from %s \n " , s - > username , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
} else {
if ( option_verbose > 1 ) {
if ( displayconnects )
ast_verbose ( VERBOSE_PREFIX_2 " HTTP Connect attempt from '%s' unable to authenticate \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
}
ast_log ( LOG_EVENT , " HTTP Failed attempt from %s \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , s - > sin . sin_addr ) ) ;
}
s - > needdestroy = 1 ;
}
if ( s - > outputstr ) {
char * tmp ;
if ( format = = FORMAT_XML )
tmp = xml_translate ( s - > outputstr , params ) ;
else if ( format = = FORMAT_HTML )
tmp = html_translate ( s - > outputstr ) ;
else
tmp = s - > outputstr ;
if ( tmp ) {
retval = malloc ( strlen ( workspace ) + strlen ( tmp ) + 128 ) ;
if ( retval ) {
strcpy ( retval , workspace ) ;
strcpy ( retval + strlen ( retval ) , tmp ) ;
c = retval + strlen ( retval ) ;
len = 120 ;
}
free ( tmp ) ;
}
if ( tmp ! = s - > outputstr )
free ( s - > outputstr ) ;
s - > outputstr = NULL ;
}
/* Still okay because c would safely be pointing to workspace even
if retval failed to allocate above */
if ( format = = FORMAT_XML ) {
ast_build_string ( & c , & len , " </ajax-response> \n " ) ;
} else if ( format = = FORMAT_HTML )
ast_build_string ( & c , & len , " </table></body> \r \n " ) ;
} else {
* status = 500 ;
* title = strdup ( " Server Error " ) ;
}
ast_mutex_lock ( & s - > __lock ) ;
if ( s - > needdestroy ) {
if ( s - > inuse = = 1 ) {
ast_log ( LOG_DEBUG , " Need destroy, doing it now! \n " ) ;
blastaway = 1 ;
} else {
ast_log ( LOG_DEBUG , " Need destroy, but can't do it yet! \n " ) ;
if ( s - > waiting_thread ! = AST_PTHREADT_NULL )
pthread_kill ( s - > waiting_thread , SIGURG ) ;
s - > inuse - - ;
}
} else
s - > inuse - - ;
ast_mutex_unlock ( & s - > __lock ) ;
if ( blastaway )
destroy_session ( s ) ;
if ( * status ! = 200 )
return ast_http_error ( 500 , " Server Error " , NULL , " Internal Server Error (out of memory) \ n " ) ;
return retval ;
}
static char * manager_http_callback ( struct sockaddr_in * requestor , const char * uri , struct ast_variable * params , int * status , char * * title , int * contentlength )
{
return generic_http_callback ( FORMAT_HTML , requestor , uri , params , status , title , contentlength ) ;
}
static char * mxml_http_callback ( struct sockaddr_in * requestor , const char * uri , struct ast_variable * params , int * status , char * * title , int * contentlength )
{
return generic_http_callback ( FORMAT_XML , requestor , uri , params , status , title , contentlength ) ;
}
static char * rawman_http_callback ( struct sockaddr_in * requestor , const char * uri , struct ast_variable * params , int * status , char * * title , int * contentlength )
{
return generic_http_callback ( FORMAT_RAW , requestor , uri , params , status , title , contentlength ) ;
}
struct ast_http_uri rawmanuri = {
. description = " Raw HTTP Manager Event Interface " ,
. uri = " rawman " ,
. has_subtree = 0 ,
. callback = rawman_http_callback ,
} ;
struct ast_http_uri manageruri = {
. description = " HTML Manager Event Interface " ,
. uri = " manager " ,
. has_subtree = 0 ,
. callback = manager_http_callback ,
} ;
struct ast_http_uri managerxmluri = {
. description = " XML Manager Event Interface " ,
. uri = " mxml " ,
. has_subtree = 0 ,
. callback = mxml_http_callback ,
} ;
2003-01-28 22:33:41 +00:00
static int registered = 0 ;
2006-04-01 08:49:54 +00:00
static int webregged = 0 ;
2003-01-28 22:33:41 +00:00
2002-09-12 18:32:42 +00:00
int init_manager ( void )
{
struct ast_config * cfg ;
char * val ;
int oldportno = portno ;
static struct sockaddr_in ba ;
int x = 1 ;
2006-04-01 08:49:54 +00:00
int flags ;
2006-04-04 19:03:12 +00:00
int webenabled = 0 ;
2006-04-01 08:49:54 +00:00
int newhttptimeout = 60 ;
2003-01-28 22:33:41 +00:00
if ( ! registered ) {
/* Register default actions */
2005-04-04 16:18:11 +00:00
ast_manager_register2 ( " Ping " , 0 , action_ping , " Keepalive command " , mandescr_ping ) ;
ast_manager_register2 ( " Events " , 0 , action_events , " Control Event Flow " , mandescr_events ) ;
2004-06-29 05:04:48 +00:00
ast_manager_register2 ( " Logoff " , 0 , action_logoff , " Logoff Manager " , mandescr_logoff ) ;
ast_manager_register2 ( " Hangup " , EVENT_FLAG_CALL , action_hangup , " Hangup Channel " , mandescr_hangup ) ;
2005-04-13 05:45:53 +00:00
ast_manager_register ( " Status " , EVENT_FLAG_CALL , action_status , " Lists channel status " ) ;
ast_manager_register2 ( " Setvar " , EVENT_FLAG_CALL , action_setvar , " Set Channel Variable " , mandescr_setvar ) ;
ast_manager_register2 ( " Getvar " , EVENT_FLAG_CALL , action_getvar , " Gets a Channel Variable " , mandescr_getvar ) ;
ast_manager_register2 ( " Redirect " , EVENT_FLAG_CALL , action_redirect , " Redirect (transfer) a call " , mandescr_redirect ) ;
2004-06-02 20:08:08 +00:00
ast_manager_register2 ( " Originate " , EVENT_FLAG_CALL , action_originate , " Originate Call " , mandescr_originate ) ;
2005-04-13 05:45:53 +00:00
ast_manager_register2 ( " Command " , EVENT_FLAG_COMMAND , action_command , " Execute Asterisk CLI Command " , mandescr_command ) ;
ast_manager_register2 ( " ExtensionState " , EVENT_FLAG_CALL , action_extensionstate , " Check Extension Status " , mandescr_extensionstate ) ;
ast_manager_register2 ( " AbsoluteTimeout " , EVENT_FLAG_CALL , action_timeout , " Set Absolute Timeout " , mandescr_timeout ) ;
ast_manager_register2 ( " MailboxStatus " , EVENT_FLAG_CALL , action_mailboxstatus , " Check Mailbox " , mandescr_mailboxstatus ) ;
ast_manager_register2 ( " MailboxCount " , EVENT_FLAG_CALL , action_mailboxcount , " Check Mailbox Message Count " , mandescr_mailboxcount ) ;
2004-06-02 22:30:42 +00:00
ast_manager_register2 ( " ListCommands " , 0 , action_listcommands , " List available manager commands " , mandescr_listcommands ) ;
2006-04-01 08:49:54 +00:00
ast_manager_register2 ( " WaitEvent " , 0 , action_waitevent , " Wait for an event to occur " , mandescr_waitevent ) ;
2002-09-12 18:32:42 +00:00
2004-06-02 20:08:08 +00:00
ast_cli_register ( & show_mancmd_cli ) ;
2003-01-28 22:33:41 +00:00
ast_cli_register ( & show_mancmds_cli ) ;
2003-02-21 06:00:08 +00:00
ast_cli_register ( & show_manconn_cli ) ;
2006-04-02 19:59:55 +00:00
ast_cli_register ( & show_maneventq_cli ) ;
2003-04-06 23:32:31 +00:00
ast_extension_state_add ( NULL , NULL , manager_state_cb , NULL ) ;
2003-01-28 22:33:41 +00:00
registered = 1 ;
2006-04-02 19:59:55 +00:00
/* Append placeholder event so master_eventq never runs dry */
append_event ( " Event: Placeholder \r \n \r \n " , 0 ) ;
2003-01-28 22:33:41 +00:00
}
2002-09-12 18:32:42 +00:00
portno = DEFAULT_MANAGER_PORT ;
2005-01-05 06:24:59 +00:00
displayconnects = 1 ;
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( " manager.conf " ) ;
2002-09-12 18:32:42 +00:00
if ( ! cfg ) {
ast_log ( LOG_NOTICE , " Unable to open management configuration manager.conf. Call management disabled. \n " ) ;
return 0 ;
}
val = ast_variable_retrieve ( cfg , " general " , " enabled " ) ;
if ( val )
enabled = ast_true ( val ) ;
2004-03-01 21:12:32 +00:00
val = ast_variable_retrieve ( cfg , " general " , " block-sockets " ) ;
2006-04-04 19:03:12 +00:00
if ( val )
2004-03-01 21:12:32 +00:00
block_sockets = ast_true ( val ) ;
2006-04-01 08:49:54 +00:00
val = ast_variable_retrieve ( cfg , " general " , " webenabled " ) ;
if ( val )
webenabled = ast_true ( val ) ;
2004-04-05 19:40:30 +00:00
if ( ( val = ast_variable_retrieve ( cfg , " general " , " port " ) ) ) {
2002-09-12 18:32:42 +00:00
if ( sscanf ( val , " %d " , & portno ) ! = 1 ) {
ast_log ( LOG_WARNING , " Invalid port number '%s' \n " , val ) ;
portno = DEFAULT_MANAGER_PORT ;
}
}
2006-01-03 22:07:12 +00:00
if ( ( val = ast_variable_retrieve ( cfg , " general " , " displayconnects " ) ) )
displayconnects = ast_true ( val ) ;
if ( ( val = ast_variable_retrieve ( cfg , " general " , " timestampevents " ) ) )
timestampevents = ast_true ( val ) ;
2006-04-01 08:49:54 +00:00
if ( ( val = ast_variable_retrieve ( cfg , " general " , " httptimeout " ) ) )
newhttptimeout = atoi ( val ) ;
2006-04-03 07:30:07 +00:00
memset ( & ba , 0 , sizeof ( ba ) ) ;
2002-09-12 18:32:42 +00:00
ba . sin_family = AF_INET ;
ba . sin_port = htons ( portno ) ;
2006-04-03 07:30:07 +00:00
2002-09-12 18:32:42 +00:00
if ( ( val = ast_variable_retrieve ( cfg , " general " , " bindaddr " ) ) ) {
if ( ! inet_aton ( val , & ba . sin_addr ) ) {
ast_log ( LOG_WARNING , " Invalid address '%s' specified, using 0.0.0.0 \n " , val ) ;
memset ( & ba . sin_addr , 0 , sizeof ( ba . sin_addr ) ) ;
}
}
2004-03-01 21:12:32 +00:00
2006-04-04 19:03:12 +00:00
2002-09-12 18:32:42 +00:00
if ( ( asock > - 1 ) & & ( ( portno ! = oldportno ) | | ! enabled ) ) {
#if 0
/* Can't be done yet */
close ( asock ) ;
asock = - 1 ;
# else
ast_log ( LOG_WARNING , " Unable to change management port / enabled \n " ) ;
# endif
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-08-04 21:44:48 +00:00
2006-04-01 08:49:54 +00:00
if ( webenabled & & enabled ) {
if ( ! webregged ) {
ast_http_uri_link ( & rawmanuri ) ;
ast_http_uri_link ( & manageruri ) ;
ast_http_uri_link ( & managerxmluri ) ;
webregged = 1 ;
}
} else {
if ( webregged ) {
ast_http_uri_unlink ( & rawmanuri ) ;
ast_http_uri_unlink ( & manageruri ) ;
ast_http_uri_unlink ( & managerxmluri ) ;
webregged = 0 ;
}
}
if ( newhttptimeout > 0 )
httptimeout = newhttptimeout ;
2006-04-04 19:03:12 +00:00
2002-09-12 18:32:42 +00:00
/* If not enabled, do nothing */
2003-08-04 21:44:48 +00:00
if ( ! enabled ) {
2002-09-12 18:32:42 +00:00
return 0 ;
2003-08-04 21:44:48 +00:00
}
2006-04-04 19:03:12 +00:00
2002-09-12 18:32:42 +00:00
if ( asock < 0 ) {
asock = socket ( AF_INET , SOCK_STREAM , 0 ) ;
if ( asock < 0 ) {
ast_log ( LOG_WARNING , " Unable to create socket: %s \n " , strerror ( errno ) ) ;
return - 1 ;
}
setsockopt ( asock , SOL_SOCKET , SO_REUSEADDR , & x , sizeof ( x ) ) ;
2003-09-08 16:48:07 +00:00
if ( bind ( asock , ( struct sockaddr * ) & ba , sizeof ( ba ) ) ) {
2002-09-12 18:32:42 +00:00
ast_log ( LOG_WARNING , " Unable to bind socket: %s \n " , strerror ( errno ) ) ;
close ( asock ) ;
asock = - 1 ;
return - 1 ;
}
if ( listen ( asock , 2 ) ) {
ast_log ( LOG_WARNING , " Unable to listen on socket: %s \n " , strerror ( errno ) ) ;
close ( asock ) ;
asock = - 1 ;
return - 1 ;
}
2006-04-01 08:49:54 +00:00
flags = fcntl ( asock , F_GETFL ) ;
fcntl ( asock , F_SETFL , flags | O_NONBLOCK ) ;
2002-09-12 18:32:42 +00:00
if ( option_verbose )
ast_verbose ( " Asterisk Management interface listening on port %d \n " , portno ) ;
2004-08-08 17:15:02 +00:00
ast_pthread_create ( & t , NULL , accept_thread , NULL ) ;
2002-09-12 18:32:42 +00:00
}
return 0 ;
}
int reload_manager ( void )
{
2003-03-12 06:00:18 +00:00
manager_event ( EVENT_FLAG_SYSTEM , " Reload " , " Message: Reload Requested \r \n " ) ;
2002-09-12 18:32:42 +00:00
return init_manager ( ) ;
}