@ -44,6 +44,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
# include "asterisk/causes.h"
# include "asterisk/format_cache.h"
# include "asterisk/core_local.h"
# include "asterisk/dial.h"
# include "resource_channels.h"
# include <limits.h>
@ -723,6 +724,69 @@ void ast_ari_channels_list(struct ast_variable *headers,
ast_ari_response_ok ( response , ast_json_ref ( json ) ) ;
}
/*! \brief Structure used for origination */
struct ari_origination {
/*! \brief Dialplan context */
char context [ AST_MAX_CONTEXT ] ;
/*! \brief Dialplan extension */
char exten [ AST_MAX_EXTENSION ] ;
/*! \brief Dialplan priority */
int priority ;
/*! \brief Application data to pass to Stasis application */
char appdata [ 0 ] ;
} ;
/*! \brief Thread which dials and executes upon answer */
static void * ari_originate_dial ( void * data )
{
struct ast_dial * dial = data ;
struct ari_origination * origination = ast_dial_get_user_data ( dial ) ;
enum ast_dial_result res ;
res = ast_dial_run ( dial , NULL , 0 ) ;
if ( res ! = AST_DIAL_RESULT_ANSWERED ) {
goto end ;
}
if ( ! ast_strlen_zero ( origination - > appdata ) ) {
struct ast_app * app = pbx_findapp ( " Stasis " ) ;
if ( app ) {
ast_verb ( 4 , " Launching Stasis(%s) on %s \n " , origination - > appdata ,
ast_channel_name ( ast_dial_answered ( dial ) ) ) ;
pbx_exec ( ast_dial_answered ( dial ) , app , origination - > appdata ) ;
} else {
ast_log ( LOG_WARNING , " No such application 'Stasis' \n " ) ;
}
} else {
struct ast_channel * answered = ast_dial_answered ( dial ) ;
if ( ! ast_strlen_zero ( origination - > context ) ) {
ast_channel_context_set ( answered , origination - > context ) ;
}
if ( ! ast_strlen_zero ( origination - > exten ) ) {
ast_channel_exten_set ( answered , origination - > exten ) ;
}
if ( origination - > priority > 0 ) {
ast_channel_priority_set ( answered , origination - > priority ) ;
}
if ( ast_pbx_run ( answered ) ) {
ast_log ( LOG_ERROR , " Failed to start PBX on %s \n " , ast_channel_name ( answered ) ) ;
} else {
/* PBX will have taken care of hanging up, so we steal the answered channel so dial doesn't do it */
ast_dial_answered_steal ( dial ) ;
}
}
end :
ast_dial_destroy ( dial ) ;
ast_free ( origination ) ;
return NULL ;
}
static void ari_channels_handle_originate_with_id ( const char * args_endpoint ,
const char * args_extension ,
const char * args_context ,
@ -734,23 +798,27 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
struct ast_variable * variables ,
const char * args_channel_id ,
const char * args_other_channel_id ,
const char * args_originator ,
struct ast_ari_response * response )
{
char * dialtech ;
char dialdevice [ AST_CHANNEL_NAME ] ;
struct ast_dial * dial ;
char * caller_id = NULL ;
char * cid_num = NULL ;
char * cid_name = NULL ;
int timeout = 30000 ;
RAII_VAR ( struct ast_format_cap * , cap ,
ast_format_cap_alloc ( AST_FORMAT_CAP_FLAG_DEFAULT ) , ao2_cleanup ) ;
char * stuff ;
struct ast_channel * other = NULL ;
struct ast_channel * chan ;
RAII_VAR ( struct ast_channel_snapshot * , snapshot , NULL , ao2_cleanup ) ;
struct ast_assigned_ids assignedids = {
. uniqueid = args_channel_id ,
. uniqueid2 = args_other_channel_id ,
} ;
struct ari_origination * origination ;
pthread_t thread ;
if ( ! cap ) {
ast_ari_response_alloc_failed ( response ) ;
@ -783,24 +851,7 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
return ;
}
if ( args_timeout > 0 ) {
timeout = args_timeout * 1000 ;
} else if ( args_timeout = = - 1 ) {
timeout = - 1 ;
}
if ( ! ast_strlen_zero ( args_caller_id ) ) {
caller_id = ast_strdupa ( args_caller_id ) ;
ast_callerid_parse ( caller_id , & cid_name , & cid_num ) ;
if ( ast_is_shrinkable_phonenumber ( cid_num ) ) {
ast_shrink_phone_number ( cid_num ) ;
}
}
if ( ! ast_strlen_zero ( args_app ) ) {
const char * app = " Stasis " ;
RAII_VAR ( struct ast_str * , appdata , ast_str_create ( 64 ) , ast_free ) ;
if ( ! appdata ) {
@ -813,23 +864,125 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
ast_str_append ( & appdata , 0 , " ,%s " , args_app_args ) ;
}
/* originate a channel, putting it into an application */
if ( ast_pbx_outgoing_app ( dialtech , cap , dialdevice , timeout , app , ast_str_buffer ( appdata ) , NULL , 0 , cid_num , cid_name , variables , NULL , & chan , & assignedids ) ) {
origination = ast_calloc ( 1 , sizeof ( * origination ) + ast_str_size ( appdata ) + 1 ) ;
if ( ! origination ) {
ast_ari_response_alloc_failed ( response ) ;
return ;
}
strcpy ( origination - > appdata , ast_str_buffer ( appdata ) ) ;
} else if ( ! ast_strlen_zero ( args_extension ) ) {
/* originate a channel, sending it to an extension */
if ( ast_pbx_outgoing_exten ( dialtech , cap , dialdevice , timeout , S_OR ( args_context , " default " ) , args_extension , args_priority ? args_priority : 1 , NULL , 0 , cid_num , cid_name , variables , NULL , & chan , 0 , & assignedids ) ) {
origination = ast_calloc ( 1 , sizeof ( * origination ) + 1 ) ;
if ( ! origination ) {
ast_ari_response_alloc_failed ( response ) ;
return ;
}
ast_copy_string ( origination - > context , S_OR ( args_context , " default " ) , sizeof ( origination - > context ) ) ;
ast_copy_string ( origination - > exten , args_extension , sizeof ( origination - > exten ) ) ;
origination - > priority = args_priority ? args_priority : 1 ;
origination - > appdata [ 0 ] = ' \0 ' ;
} else {
ast_ari_response_error ( response , 400 , " Bad Request " ,
" Application or extension must be specified " ) ;
return ;
}
dial = ast_dial_create ( ) ;
if ( ! dial ) {
ast_ari_response_alloc_failed ( response ) ;
ast_free ( origination ) ;
return ;
}
ast_dial_set_user_data ( dial , origination ) ;
if ( ast_dial_append ( dial , dialtech , dialdevice , & assignedids ) ) {
ast_ari_response_alloc_failed ( response ) ;
ast_dial_destroy ( dial ) ;
ast_free ( origination ) ;
return ;
}
if ( args_timeout > 0 ) {
ast_dial_set_global_timeout ( dial , args_timeout * 1000 ) ;
} else if ( args_timeout = = - 1 ) {
ast_dial_set_global_timeout ( dial , - 1 ) ;
} else {
ast_dial_set_global_timeout ( dial , 30000 ) ;
}
if ( ! ast_strlen_zero ( args_caller_id ) ) {
caller_id = ast_strdupa ( args_caller_id ) ;
ast_callerid_parse ( caller_id , & cid_name , & cid_num ) ;
if ( ast_is_shrinkable_phonenumber ( cid_num ) ) {
ast_shrink_phone_number ( cid_num ) ;
}
}
if ( ! ast_strlen_zero ( args_originator ) ) {
other = ast_channel_get_by_name ( args_originator ) ;
if ( ! other ) {
ast_ari_response_error (
response , 400 , " Bad Request " ,
" Provided originator channel was not found " ) ;
ast_dial_destroy ( dial ) ;
ast_free ( origination ) ;
return ;
}
}
if ( ast_dial_prerun ( dial , other , cap ) ) {
ast_ari_response_alloc_failed ( response ) ;
ast_dial_destroy ( dial ) ;
ast_free ( origination ) ;
ast_channel_cleanup ( other ) ;
return ;
}
ast_channel_cleanup ( other ) ;
chan = ast_dial_get_channel ( dial , 0 ) ;
if ( ! chan ) {
ast_ari_response_alloc_failed ( response ) ;
ast_dial_destroy ( dial ) ;
ast_free ( origination ) ;
return ;
}
if ( ! ast_strlen_zero ( cid_num ) | | ! ast_strlen_zero ( cid_name ) ) {
struct ast_party_connected_line connected ;
/*
* It seems strange to set the CallerID on an outgoing call leg
* to whom we are calling , but this function ' s callers are doing
* various Originate methods . This call leg goes to the local
* user . Once the called party answers , the dialplan needs to
* be able to access the CallerID from the CALLERID function as
* if the called party had placed this call .
*/
ast_set_callerid ( chan , cid_num , cid_name , cid_num ) ;
ast_party_connected_line_set_init ( & connected , ast_channel_connected ( chan ) ) ;
if ( ! ast_strlen_zero ( cid_num ) ) {
connected . id . number . valid = 1 ;
connected . id . number . str = ( char * ) cid_num ;
connected . id . number . presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED ;
}
if ( ! ast_strlen_zero ( cid_name ) ) {
connected . id . name . valid = 1 ;
connected . id . name . str = ( char * ) cid_name ;
connected . id . name . presentation = AST_PRES_ALLOWED_USER_NUMBER_NOT_SCREENED ;
}
ast_channel_set_connected_line ( chan , & connected , NULL ) ;
}
ast_channel_lock ( chan ) ;
if ( variables ) {
ast_set_variables ( chan , variables ) ;
}
ast_set_flag ( ast_channel_flags ( chan ) , AST_FLAG_ORIGINATED ) ;
if ( ! ast_strlen_zero ( args_app ) ) {
struct ast_channel * local_peer ;
@ -846,8 +999,21 @@ static void ari_channels_handle_originate_with_id(const char *args_endpoint,
snapshot = ast_channel_snapshot_get_latest ( ast_channel_uniqueid ( chan ) ) ;
ast_channel_unlock ( chan ) ;
ast_ari_response_ok ( response , ast_channel_snapshot_to_json ( snapshot , NULL ) ) ;
/* Before starting the async dial bump the ref in case the dial quickly goes away and takes
* the reference with it
*/
ast_channel_ref ( chan ) ;
if ( ast_pthread_create_detached ( & thread , NULL , ari_originate_dial , dial ) ) {
ast_ari_response_alloc_failed ( response ) ;
ast_dial_destroy ( dial ) ;
ast_free ( origination ) ;
} else {
ast_ari_response_ok ( response , ast_channel_snapshot_to_json ( snapshot , NULL ) ) ;
}
ast_channel_unref ( chan ) ;
return ;
}
void ast_ari_channels_originate_with_id ( struct ast_variable * headers ,
@ -883,6 +1049,7 @@ void ast_ari_channels_originate_with_id(struct ast_variable *headers,
variables ,
args - > channel_id ,
args - > other_channel_id ,
args - > originator ,
response ) ;
}
@ -919,6 +1086,7 @@ void ast_ari_channels_originate(struct ast_variable *headers,
variables ,
args - > channel_id ,
args - > other_channel_id ,
args - > originator ,
response ) ;
}