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 */
#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"
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:
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;
}
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,
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);
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);
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");
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";
}
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);
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;
}
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);
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;
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";
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])) {
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;
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;
}
}
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;
}
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);
}
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);
}
+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