@ -170,6 +170,13 @@ struct cel_linkedid {
/*! Container of channel references to a linkedid for CEL purposes. */
static AO2_GLOBAL_OBJ_STATIC ( cel_linkedids ) ;
struct cel_dialstatus {
/*! Uniqueid of the channel */
char uniqueid [ AST_MAX_UNIQUEID ] ;
/*! The dial status */
char dialstatus [ 0 ] ;
} ;
/*! \brief Destructor for cel_config */
static void cel_general_config_dtor ( void * obj )
{
@ -372,20 +379,10 @@ static int cel_backend_cmp(void *obj, void *arg, int flags)
return CMP_MATCH ;
}
static const char * get_caller_uniqueid ( struct ast_multi_channel_blob * blob )
{
struct ast_channel_snapshot * caller = ast_multi_channel_blob_get_channel ( blob , " caller " ) ;
if ( ! caller ) {
return NULL ;
}
return caller - > uniqueid ;
}
/*! \brief Hashing function for dialstatus container */
static int dialstatus_hash ( const void * obj , int flags )
{
struct ast_multi_channel_blob * blob ;
const struct cel_dialstatus * dialstatus ;
const char * key ;
switch ( flags & OBJ_SEARCH_MASK ) {
@ -393,8 +390,8 @@ static int dialstatus_hash(const void *obj, int flags)
key = obj ;
break ;
case OBJ_SEARCH_OBJECT :
blob = ( void * ) obj ;
key = get_caller_uniqueid ( blob ) ;
dialstatus = obj ;
key = dialstatus - > uniqueid ;
break ;
default :
/* Hash can only work on something with a full key. */
@ -407,24 +404,24 @@ static int dialstatus_hash(const void *obj, int flags)
/*! \brief Comparator function for dialstatus container */
static int dialstatus_cmp ( void * obj , void * arg , int flags )
{
struct ast_multi_channel_blob * object_left = obj ;
struct ast_multi_channel_blob * object_right = arg ;
struct cel_dialstatus * object_left = obj ;
struct cel_dialstatus * object_right = arg ;
const char * right_key = arg ;
int cmp ;
switch ( flags & OBJ_SEARCH_MASK ) {
case OBJ_SEARCH_OBJECT :
right_key = get_caller_uniqueid ( object_right ) ;
right_key = object_right - > uniqueid ;
/* Fall through */
case OBJ_SEARCH_KEY :
cmp = strcmp ( get_caller_uniqueid ( object_left ) , right_key ) ;
cmp = strcmp ( object_left - > uniqueid , right_key ) ;
break ;
case OBJ_SEARCH_PARTIAL_KEY :
/*
* We could also use a partial key struct containing a length
* so strlen ( ) does not get called for every comparison instead .
*/
cmp = strncmp ( get_caller_uniqueid ( object_left ) , right_key , strlen ( right_key ) ) ;
cmp = strncmp ( object_left - > uniqueid , right_key , strlen ( right_key ) ) ;
break ;
default :
/*
@ -958,16 +955,16 @@ typedef void (*cel_channel_snapshot_monitor)(
struct ast_channel_snapshot * old_snapshot ,
struct ast_channel_snapshot * new_snapshot ) ;
static struct ast_multi_channel_blob * get_dialstatus_blob ( const char * uniqueid )
static struct cel_dialstatus * get_dialstatus ( const char * uniqueid )
{
struct ao2_container * dial_statuses = ao2_global_obj_ref ( cel_dialstatus_store ) ;
struct ast_multi_channel_blob * blob = NULL ;
struct cel_dialstatus * dialstatus = NULL ;
if ( dial_statuses ) {
blob = ao2_find ( dial_statuses , uniqueid , OBJ_SEARCH_KEY | OBJ_UNLINK ) ;
dialstatus = ao2_find ( dial_statuses , uniqueid , OBJ_SEARCH_KEY | OBJ_UNLINK ) ;
ao2_ref ( dial_statuses , - 1 ) ;
}
return blob ;
return dialstatus ;
}
static const char * get_blob_variable ( struct ast_multi_channel_blob * blob , const char * varname )
@ -1010,19 +1007,15 @@ static void cel_channel_state_change(
if ( ! was_hungup & & is_hungup ) {
struct ast_json * extra ;
struct ast_multi_channel_blob * blob = get_dialstatus_blob ( new_snapshot - > uniqueid ) ;
const char * dialstatus = " " ;
struct cel_dialstatus * dialstatus = get_dialstatus ( new_snapshot - > uniqueid ) ;
if ( blob & & ! ast_strlen_zero ( get_blob_variable ( blob , " dialstatus " ) ) ) {
dialstatus = get_blob_variable ( blob , " dialstatus " ) ;
}
extra = ast_json_pack ( " {s: i, s: s, s: s} " ,
" hangupcause " , new_snapshot - > hangupcause ,
" hangupsource " , new_snapshot - > hangupsource ,
" dialstatus " , dialstatus ) ;
" dialstatus " , dialstatus ? dialstatus - > dialstatus : " " ) ;
cel_report_event ( new_snapshot , AST_CEL_HANGUP , NULL , extra , NULL ) ;
ast_json_unref ( extra ) ;
ao2_cleanup ( blob ) ;
ao2_cleanup ( dialstatus ) ;
return ;
}
@ -1254,16 +1247,48 @@ static void cel_parking_cb(
}
}
static void save_dialstatus ( struct ast_multi_channel_blob * blob )
static void save_dialstatus ( struct ast_multi_channel_blob * blob , struct ast_channel_snapshot * snapshot )
{
struct ao2_container * dial_statuses = ao2_global_obj_ref ( cel_dialstatus_store ) ;
const char * dialstatus_string = get_blob_variable ( blob , " dialstatus " ) ;
struct cel_dialstatus * dialstatus ;
size_t dialstatus_string_len ;
ast_assert ( blob ! = NULL ) ;
if ( ! dial_statuses | | ast_strlen_zero ( dialstatus_string ) ) {
ao2_cleanup ( dial_statuses ) ;
return ;
}
if ( dial_statuses ) {
ao2_link ( dial_statuses , blob ) ;
dialstatus = ao2_find ( dial_statuses , snapshot - > uniqueid , OBJ_SEARCH_KEY ) ;
if ( dialstatus ) {
if ( ! strcasecmp ( dialstatus_string , " ANSWER " ) & & strcasecmp ( dialstatus - > dialstatus , " ANSWER " ) ) {
/* In the case of an answer after we already have a dial status we give
* priority to the answer since the call was , well , answered . In the case of
* failure dial status results we simply let the first failure be the status .
*/
ao2_unlink ( dial_statuses , dialstatus ) ;
ao2_ref ( dialstatus , - 1 ) ;
} else {
ao2_ref ( dialstatus , - 1 ) ;
ao2_ref ( dial_statuses , - 1 ) ;
return ;
}
}
dialstatus_string_len = strlen ( dialstatus_string ) + 1 ;
dialstatus = ao2_alloc_options ( sizeof ( * dialstatus ) + dialstatus_string_len , NULL ,
AO2_ALLOC_OPT_LOCK_NOLOCK ) ;
if ( ! dialstatus ) {
ao2_ref ( dial_statuses , - 1 ) ;
return ;
}
ast_copy_string ( dialstatus - > uniqueid , snapshot - > uniqueid , sizeof ( dialstatus - > uniqueid ) ) ;
ast_copy_string ( dialstatus - > dialstatus , dialstatus_string , dialstatus_string_len ) ;
ao2_link ( dial_statuses , dialstatus ) ;
ao2_ref ( dialstatus , - 1 ) ;
ao2_ref ( dial_statuses , - 1 ) ;
}
static int is_valid_dialstatus ( struct ast_multi_channel_blob * blob )
@ -1299,32 +1324,25 @@ static void cel_dial_cb(void *data, struct stasis_subscription *sub,
struct stasis_message * message )
{
struct ast_multi_channel_blob * blob = stasis_message_data ( message ) ;
struct ast_channel_snapshot * snapshot ;
if ( cel_filter_channel_snapshot ( ast_multi_channel_blob_get_channel ( blob , " caller " ) ) ) {
return ;
}
if ( ! get_caller_uniqueid ( blob ) ) {
snapshot = ast_multi_channel_blob_get_channel ( blob , " caller " ) ;
if ( ! snapshot | | cel_filter_channel_snapshot ( snapshot ) ) {
return ;
}
if ( ! ast_strlen_zero ( get_blob_variable ( blob , " forward " ) ) ) {
struct ast_channel_snapshot * caller = ast_multi_channel_blob_get_channel ( blob , " caller " ) ;
struct ast_json * extra ;
if ( ! caller ) {
return ;
}
extra = ast_json_pack ( " {s: s} " , " forward " , get_blob_variable ( blob , " forward " ) ) ;
if ( extra ) {
cel_report_event ( caller , AST_CEL_FORWARD , NULL , extra , NULL ) ;
cel_report_event ( snapshot , AST_CEL_FORWARD , NULL , extra , NULL ) ;
ast_json_unref ( extra ) ;
}
}
if ( is_valid_dialstatus ( blob ) ) {
save_dialstatus ( blob );
save_dialstatus ( blob , snapshot );
}
}