diff --git a/src/include/switch_caller.h b/src/include/switch_caller.h index fde3372105..09ff57beb6 100644 --- a/src/include/switch_caller.h +++ b/src/include/switch_caller.h @@ -120,6 +120,9 @@ typedef struct profile_node_s { struct switch_caller_profile *next; switch_call_direction_t direction; profile_node_t *soft; + char *uuid_str; + char *clone_of; + char *transfer_source; }; /*! \brief An Abstract Representation of a dialplan Application */ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index bcdc508408..715f232556 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -131,6 +131,7 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_COPY_XML_CDR_VARIABLE "copy_xml_cdr" #define SWITCH_CURRENT_APPLICATION_VARIABLE "current_application" #define SWITCH_PROTO_SPECIFIC_HANGUP_CAUSE_VARIABLE "proto_specific_hangup_cause" +#define SWITCH_TRANSFER_HISTORY_VARIABLE "transfer_history" #define SWITCH_CHANNEL_EXECUTE_ON_ANSWER_VARIABLE "execute_on_answer" #define SWITCH_CHANNEL_EXECUTE_ON_PRE_ANSWER_VARIABLE "execute_on_pre_answer" diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 33b4173513..a5ba8fc73b 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -830,6 +830,8 @@ SWITCH_DECLARE(int) switch_split_user_domain(char *in, char **user, char **domai SWITCH_DECLARE(const char *) switch_inet_ntop(int af, void const *src, char *dst, size_t size); #endif +SWITCH_DECLARE(char *) switch_uuid_str(char *buf, switch_size_t len); + SWITCH_END_EXTERN_C #endif /* For Emacs: diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index efc4603d52..4daa339d4d 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -2435,12 +2435,11 @@ SWITCH_STANDARD_API(tone_detect_session_function) SWITCH_STANDARD_API(uuid_function) { - switch_uuid_t uuid; char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; - switch_uuid_get(&uuid); - switch_uuid_format(uuid_str, &uuid); - stream->write_function(stream, "%s", uuid_str); + switch_uuid_str(uuid_str, sizeof(uuid_str)); + + stream->write_function(stream, "%s", uuid_str); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index aad80e0579..183af3c44b 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -5093,6 +5093,81 @@ static void launch_media_on_hold(switch_core_session_t *session) switch_thread_create(&thread, thd_attr, media_on_hold_thread_run, session, switch_core_session_get_pool(session)); } +static void mark_transfer_record(switch_core_session_t *session, const char *br_a, const char *br_b) +{ + switch_core_session_t *br_b_session, *br_a_session; + switch_channel_t *channel; + const char *uvar1, *dvar1, *uvar2, *dvar2; + + channel = switch_core_session_get_channel(session); + + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { + uvar1 = "sip_from_user"; + dvar1 = "sip_from_host"; + } else { + uvar1 = "sip_to_user"; + dvar1 = "sip_to_host"; + } + + + if ((br_b_session = switch_core_session_locate(br_b)) ) { + switch_channel_t *br_b_channel = switch_core_session_get_channel(br_b_session); + switch_caller_profile_t *cp = switch_channel_get_caller_profile(br_b_channel); + + if (switch_channel_direction(br_b_channel) == SWITCH_CALL_DIRECTION_INBOUND) { + uvar2 = "sip_from_user"; + dvar2 = "sip_from_host"; + } else { + uvar2 = "sip_to_user"; + dvar2 = "sip_to_host"; + } + + cp->transfer_source = switch_core_sprintf(cp->pool, + "%ld:%s:att_xfer:%s@%s/%s@%s", + (long) switch_epoch_time_now(NULL), + cp->uuid_str, + switch_channel_get_variable(channel, uvar1), + switch_channel_get_variable(channel, dvar1), + switch_channel_get_variable(br_b_channel, uvar2), + switch_channel_get_variable(br_b_channel, dvar2)); + + switch_channel_add_variable_var_check(br_b_channel, SWITCH_TRANSFER_HISTORY_VARIABLE, cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH); + + switch_core_session_rwunlock(br_b_session); + } + + + + if ((br_a_session = switch_core_session_locate(br_a)) ) { + switch_channel_t *br_a_channel = switch_core_session_get_channel(br_a_session); + switch_caller_profile_t *cp = switch_channel_get_caller_profile(br_a_channel); + + if (switch_channel_direction(br_a_channel) == SWITCH_CALL_DIRECTION_INBOUND) { + uvar2 = "sip_from_user"; + dvar2 = "sip_from_host"; + } else { + uvar2 = "sip_to_user"; + dvar2 = "sip_to_host"; + } + + cp->transfer_source = switch_core_sprintf(cp->pool, + "%ld:%s:att_xfer:%s@%s/%s@%s", + (long) switch_epoch_time_now(NULL), + cp->uuid_str, + switch_channel_get_variable(channel, uvar1), + switch_channel_get_variable(channel, dvar1), + switch_channel_get_variable(br_a_channel, uvar2), + switch_channel_get_variable(br_a_channel, dvar2)); + + switch_channel_add_variable_var_check(br_a_channel, SWITCH_TRANSFER_HISTORY_VARIABLE, cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH); + + switch_core_session_rwunlock(br_a_session); + } + + +} + + static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, char const *phrase, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, @@ -5414,15 +5489,17 @@ static void sofia_handle_sip_i_state(switch_core_session_t *session, int status, const char *br_b = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE); char *br_a = b_private->uuid; + if (br_b) { - switch_core_session_t *tmp; - - if (switch_true(switch_channel_get_variable(channel, "recording_follow_transfer")) && + switch_core_session_t *tmp; + + if (switch_true(switch_channel_get_variable(channel, "recording_follow_transfer")) && (tmp = switch_core_session_locate(br_a))) { switch_core_media_bug_transfer_recordings(session, tmp); switch_core_session_rwunlock(tmp); } + mark_transfer_record(session, br_a, br_b); switch_ivr_uuid_bridge(br_a, br_b); switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); sofia_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD); @@ -5986,12 +6063,13 @@ void *SWITCH_THREAD_FUNC nightmare_xfer_thread_run(switch_thread_t *thread, void if ((status = switch_ivr_originate(NULL, &tsession, &cause, nhelper->exten_with_params, timeout, NULL, NULL, NULL, switch_channel_get_caller_profile(channel_a), nhelper->vars, SOF_NONE, NULL)) == SWITCH_STATUS_SUCCESS) { if (switch_channel_up(channel_a)) { - + if (switch_true(switch_channel_get_variable(channel_a, "recording_follow_transfer"))) { switch_core_media_bug_transfer_recordings(session, a_session); } tuuid_str = switch_core_session_get_uuid(tsession); + mark_transfer_record(session, nhelper->bridge_to_uuid, tuuid_str); switch_ivr_uuid_bridge(nhelper->bridge_to_uuid, tuuid_str); switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); sofia_set_flag_locked(tech_pvt, TFLAG_BYE); @@ -6355,6 +6433,8 @@ void sofia_handle_sip_i_refer(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_core_session_rwunlock(tmp); } + + mark_transfer_record(session, br_b, br_a); switch_ivr_uuid_bridge(br_b, br_a); switch_channel_set_variable(channel_b, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER"); diff --git a/src/switch_caller.c b/src/switch_caller.c index 5e3070548e..da92ce649f 100644 --- a/src/switch_caller.c +++ b/src/switch_caller.c @@ -48,11 +48,15 @@ SWITCH_DECLARE(switch_caller_profile_t *) switch_caller_profile_new(switch_memor const char *source, const char *context, const char *destination_number) { switch_caller_profile_t *profile = NULL; + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; profile = switch_core_alloc(pool, sizeof(*profile)); switch_assert(profile != NULL); memset(profile, 0, sizeof(*profile)); + switch_uuid_str(uuid_str, sizeof(uuid_str)); + profile->uuid_str = switch_core_strdup(pool, uuid_str); + if (!context) { context = "default"; } @@ -96,10 +100,15 @@ SWITCH_DECLARE(switch_caller_profile_t *) switch_caller_profile_new(switch_memor SWITCH_DECLARE(switch_caller_profile_t *) switch_caller_profile_dup(switch_memory_pool_t *pool, switch_caller_profile_t *tocopy) { switch_caller_profile_t *profile = NULL; + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; profile = switch_core_alloc(pool, sizeof(*profile)); switch_assert(profile != NULL); + switch_uuid_str(uuid_str, sizeof(uuid_str)); + profile->uuid_str = switch_core_strdup(pool, uuid_str); + profile->clone_of = switch_core_strdup(pool, tocopy->uuid_str); + profile_dup(tocopy->username, profile->username, pool); profile_dup(tocopy->dialplan, profile->dialplan, pool); profile_dup(tocopy->caller_id_name, profile->caller_id_name, pool); @@ -181,6 +190,9 @@ SWITCH_DECLARE(const char *) switch_caller_get_field_by_name(switch_caller_profi if (!strcasecmp(name, "source")) { return caller_profile->source; } + if (!strcasecmp(name, "transfer_source")) { + return caller_profile->transfer_source; + } if (!strcasecmp(name, "context")) { return caller_profile->context; } @@ -308,6 +320,10 @@ SWITCH_DECLARE(void) switch_caller_profile_event_set_data(switch_caller_profile_ switch_snprintf(header_name, sizeof(header_name), "%s-Source", prefix); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->source); } + if (!zstr(caller_profile->transfer_source)) { + switch_snprintf(header_name, sizeof(header_name), "%s-Transfer-Source", prefix); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->transfer_source); + } if (!zstr(caller_profile->context)) { switch_snprintf(header_name, sizeof(header_name), "%s-Context", prefix); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->context); diff --git a/src/switch_channel.c b/src/switch_channel.c index 30a2e85da2..e372ad0ff0 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -3500,7 +3500,7 @@ SWITCH_DECLARE(char *) switch_channel_build_param_string(switch_channel_t *chann switch_stream_handle_t stream = { 0 }; switch_size_t encode_len = 1024, new_len = 0; char *encode_buf = NULL; - const char *prof[12] = { 0 }, *prof_names[12] = { + const char *prof[13] = { 0 }, *prof_names[13] = { 0}; char *e = NULL; switch_event_header_t *hi; @@ -3532,7 +3532,8 @@ SWITCH_DECLARE(char *) switch_channel_build_param_string(switch_channel_t *chann prof[8] = caller_profile->source; prof[9] = caller_profile->chan_name; prof[10] = caller_profile->uuid; - + prof[11] = caller_profile->transfer_source; + prof_names[0] = "context"; prof_names[1] = "destination_number"; prof_names[2] = "caller_id_name"; @@ -3544,6 +3545,7 @@ SWITCH_DECLARE(char *) switch_channel_build_param_string(switch_channel_t *chann prof_names[8] = "source"; prof_names[9] = "chan_name"; prof_names[10] = "uuid"; + prof_names[11] = "transfer_source"; for (x = 0; prof[x]; x++) { if (zstr(prof[x])) { @@ -3565,6 +3567,30 @@ SWITCH_DECLARE(char *) switch_channel_build_param_string(switch_channel_t *chann stream.write_function(&stream, "%s=%s&", prof_names[x], encode_buf); } + if (channel->caller_profile->soft) { + profile_node_t *pn; + + for(pn = channel->caller_profile->soft; pn; pn = pn->next) { + char *var = pn->var; + char *val = pn->val; + + new_len = (strlen((char *) var) * 3) + 1; + if (encode_len < new_len) { + char *tmp; + + encode_len = new_len; + + tmp = realloc(encode_buf, encode_len); + switch_assert(tmp); + encode_buf = tmp; + } + + switch_url_encode((char *) val, encode_buf, encode_len); + stream.write_function(&stream, "%s=%s&", (char *) var, encode_buf); + + } + } + if ((hi = switch_channel_variable_first(channel))) { for (; hi; hi = hi->next) { char *var = hi->name; diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 19d3c102a1..3904d07e5f 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -1698,6 +1698,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Transfer %s to %s[%s@%s]\n", switch_channel_get_name(channel), use_dialplan, extension, use_context); + + + new_profile->transfer_source = switch_core_sprintf(new_profile->pool, "%ld:%s:bl_xfer:%s/%s/%s", + (long) switch_epoch_time_now(NULL), new_profile->uuid_str, + extension, use_context, use_dialplan); + switch_channel_add_variable_var_check(channel, SWITCH_TRANSFER_HISTORY_VARIABLE, new_profile->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH); + return SWITCH_STATUS_SUCCESS; } @@ -2051,6 +2058,13 @@ SWITCH_DECLARE(int) switch_ivr_set_xml_profile_data(switch_xml_t xml, switch_cal } switch_xml_set_txt_d(param, caller_profile->source); + if (caller_profile->transfer_source) { + if (!(param = switch_xml_add_child_d(xml, "transfer_source", off++))) { + return -1; + } + switch_xml_set_txt_d(param, caller_profile->transfer_source); + } + if (!(param = switch_xml_add_child_d(xml, "context", off++))) { return -1; } @@ -2212,6 +2226,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_xml_cdr(switch_core_session_ switch_xml_set_attr_d(x_callflow, "dialplan", caller_profile->dialplan); } + if (!zstr(caller_profile->uuid_str)) { + switch_xml_set_attr_d(x_callflow, "unique-id", caller_profile->uuid_str); + } + + if (!zstr(caller_profile->clone_of)) { + switch_xml_set_attr_d(x_callflow, "clone-of", caller_profile->clone_of); + } + if (!zstr(caller_profile->profile_index)) { switch_xml_set_attr_d(x_callflow, "profile_index", caller_profile->profile_index); } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index e458fe0390..f5d79bfe1c 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -1506,6 +1506,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_uuid_bridge(const char *originator_uu switch_channel_clear_flag(originator_channel, CF_ORIGINATING); switch_channel_clear_flag(originatee_channel, CF_ORIGINATING); + + originator_cp->transfer_source = switch_core_sprintf(originator_cp->pool, + "%ld:%s:uuid_br:%s", (long)switch_epoch_time_now(NULL), originator_cp->uuid_str, + switch_core_session_get_uuid(originatee_session)); + switch_channel_add_variable_var_check(originator_channel, SWITCH_TRANSFER_HISTORY_VARIABLE, + originator_cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH); + + + originatee_cp->transfer_source = switch_core_sprintf(originatee_cp->pool, + "%ld:%s:uuid_br:%s", (long)switch_epoch_time_now(NULL), originatee_cp->uuid_str, + switch_core_session_get_uuid(originator_session)); + switch_channel_add_variable_var_check(originatee_channel, SWITCH_TRANSFER_HISTORY_VARIABLE, + originatee_cp->transfer_source, SWITCH_FALSE, SWITCH_STACK_PUSH); + + /* change the states and let the chips fall where they may */ //switch_channel_set_variable(originator_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE, NULL); diff --git a/src/switch_utils.c b/src/switch_utils.c index 3f3f804d77..a008830ef6 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -2825,6 +2825,21 @@ SWITCH_DECLARE(int) switch_split_user_domain(char *in, char **user, char **domai } +SWITCH_DECLARE(char *) switch_uuid_str(char *buf, switch_size_t len) +{ + switch_uuid_t uuid; + + if (len < (SWITCH_UUID_FORMATTED_LENGTH + 1)) { + switch_snprintf(buf, len, "INVALID"); + } else { + switch_uuid_get(&uuid); + switch_uuid_format(buf, &uuid); + } + + return buf; +} + + /* For Emacs: * Local Variables: * mode:c