Merge branch 'master' into smgmaster

Conflicts:
	libs/esl/fs_cli.c
This commit is contained in:
Moises Silva committed 2011-02-07 17:26:01 -05:00
commit c41ea35739
88 files changed
+3786 -1129

No files matched your search

@@ -2049,7 +2049,7 @@ static void set_profile_val(mdl_profile_t *profile, char *var, char *val)
} else if (!strcasecmp(var, "ext-rtp-ip")) {
char *ip = globals.guess_ip;
if (val && !strcasecmp(val, "auto-nat")) {
ip = globals.auto_nat ? switch_core_get_variable("nat_public_addr") : globals.guess_ip;
ip = globals.auto_nat ? switch_core_get_variable_pdup("nat_public_addr", module_pool) : globals.guess_ip;
} else if (val && !strcasecmp(val, "auto")) {
globals.auto_nat = 0;
ip = globals.guess_ip;
@@ -2523,7 +2523,7 @@ static switch_status_t load_config(void)
memset(&globals, 0, sizeof(globals));
globals.running = 1;
globals.auto_nat = (switch_core_get_variable("nat_type") ? 1 : 0);
globals.auto_nat = (switch_nat_get_type() ? 1 : 0);
switch_find_local_ip(globals.guess_ip, sizeof(globals.guess_ip), NULL, AF_INET);
@@ -1625,9 +1625,10 @@ bool Board::KhompPvt::setCollectCall()
DBG(FUNC, PVT_FMT(_target, "option drop collect call is '%s'") % (Opt::_options._drop_collect_call() ? "yes" : "no"));
// get global filter configuration value
tmp_var = switch_core_get_variable("KDropCollectCall");
tmp_var = switch_core_get_variable_dup("KDropCollectCall");
confvalues.push_back(getTriStateValue(tmp_var));
DBG(FUNC, PVT_FMT(_target, "global KDropCollectCall was '%s'") % (tmp_var ? tmp_var : "(empty)"));
switch_safe_free(tmp_var);
try
{
+28 -30
View File
@@ -77,11 +77,12 @@ struct private_object {
switch_frame_t cng_frame;
unsigned char cng_databuf[SWITCH_RECOMMENDED_BUFFER_SIZE];
switch_timer_t timer;
switch_caller_profile_t *caller_profile;
int32_t bowout_frame_count;
char *other_uuid;
switch_queue_t *frame_queue;
switch_codec_implementation_t read_impl;
int64_t packet_count;
};
typedef struct private_object private_t;
@@ -111,6 +112,7 @@ static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *ses
int interval = 20;
switch_status_t status = SWITCH_STATUS_SUCCESS;
switch_channel_t *channel = switch_core_session_get_channel(session);
const switch_codec_implementation_t *read_impl;
if (codec) {
iananame = codec->implementation->iananame;
@@ -165,7 +167,15 @@ static switch_status_t tech_init(private_t *tech_pvt, switch_core_session_t *ses
switch_core_session_set_read_codec(session, &tech_pvt->read_codec);
switch_core_session_set_write_codec(session, &tech_pvt->write_codec);
tech_pvt->read_impl = *tech_pvt->read_codec.implementation;
if (tech_pvt->flag_mutex) {
switch_core_timer_destroy(&tech_pvt->timer);
}
read_impl = tech_pvt->read_codec.implementation;
switch_core_timer_init(&tech_pvt->timer, "soft",
read_impl->microseconds_per_packet / 1000, read_impl->samples_per_packet * 4, switch_core_session_get_pool(session));
if (!tech_pvt->flag_mutex) {
switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
@@ -367,6 +377,7 @@ static switch_status_t channel_on_destroy(switch_core_session_t *session)
tech_pvt = switch_core_session_get_private(session);
if (tech_pvt) {
switch_core_timer_destroy(&tech_pvt->timer);
if (switch_core_codec_ready(&tech_pvt->read_codec)) {
switch_core_codec_destroy(&tech_pvt->read_codec);
@@ -558,49 +569,31 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
goto end;
}
switch_core_timer_next(&tech_pvt->timer);
mutex = tech_pvt->mutex;
switch_mutex_lock(mutex);
if (switch_queue_pop_timeout(tech_pvt->frame_queue, &pop, tech_pvt->read_impl.microseconds_per_packet) == SWITCH_STATUS_SUCCESS && pop) {
if (switch_queue_trypop(tech_pvt->frame_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
if (tech_pvt->write_frame) {
switch_frame_free(&tech_pvt->write_frame);
}
tech_pvt->write_frame = (switch_frame_t *) pop;
tech_pvt->write_frame->codec = &tech_pvt->read_codec;
*frame = tech_pvt->write_frame;
tech_pvt->packet_count++;
switch_clear_flag_locked(tech_pvt, TFLAG_CNG);
switch_clear_flag(tech_pvt->write_frame, SFF_CNG);
} else {
switch_set_flag(tech_pvt, TFLAG_CNG);
}
switch_mutex_lock(mutex);
if (switch_test_flag(tech_pvt, TFLAG_CNG)) {
unsigned char data[SWITCH_RECOMMENDED_BUFFER_SIZE];
uint32_t flag = 0;
switch_status_t encode_status;
uint32_t rate = tech_pvt->read_codec.implementation->actual_samples_per_second;
*frame = &tech_pvt->cng_frame;
tech_pvt->cng_frame.codec = &tech_pvt->read_codec;
tech_pvt->cng_frame.datalen = tech_pvt->read_codec.implementation->decoded_bytes_per_packet;
memset(tech_pvt->cng_frame.data, 0, tech_pvt->cng_frame.datalen);
memset(&data, 0, tech_pvt->read_codec.implementation->decoded_bytes_per_packet);
if (strcasecmp(tech_pvt->read_codec.implementation->iananame, "L16")) {
encode_status = switch_core_codec_encode(&tech_pvt->read_codec,
NULL,
data,
tech_pvt->read_codec.implementation->decoded_bytes_per_packet,
tech_pvt->read_codec.implementation->actual_samples_per_second,
tech_pvt->cng_frame.data, &tech_pvt->cng_frame.datalen, &rate, &flag);
if (encode_status != SWITCH_STATUS_SUCCESS) {
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
}
}
//switch_set_flag((&tech_pvt->cng_frame), SFF_CNG);
switch_set_flag((&tech_pvt->cng_frame), SFF_CNG);
switch_clear_flag_locked(tech_pvt, TFLAG_CNG);
}
@@ -632,7 +625,10 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc
tech_pvt = switch_core_session_get_private(session);
switch_assert(tech_pvt != NULL);
if (switch_test_flag(frame, SFF_CNG) || switch_test_flag(tech_pvt, TFLAG_CNG) || (switch_test_flag(tech_pvt, TFLAG_BOWOUT) && switch_test_flag(tech_pvt, TFLAG_BOWOUT_USED))) {
if (switch_test_flag(frame, SFF_CNG) ||
switch_test_flag(tech_pvt, TFLAG_CNG) || (switch_test_flag(tech_pvt, TFLAG_BOWOUT) && switch_test_flag(tech_pvt, TFLAG_BOWOUT_USED))) {
switch_core_timer_sync(&tech_pvt->timer);
switch_core_timer_sync(&tech_pvt->other_tech_pvt->timer);
return SWITCH_STATUS_SUCCESS;
}
@@ -765,6 +761,8 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s
switch_frame_free(&frame);
}
switch_core_timer_sync(&tech_pvt->timer);
}
break;
default:
File diff suppressed because it is too large. Load diff
@@ -68,6 +68,13 @@ struct PACKED keypad_button_message {
uint32_t call_id;
};
/* EnblocCallMessage */
#define ENBLOC_CALL_MESSAGE 0x0004
struct PACKED enbloc_call_message {
char called_party[24];
uint32_t line_instance;
};
/* StimulusMessage */
#define STIMULUS_MESSAGE 0x0005
struct PACKED stimulus_message {
@@ -562,6 +569,7 @@ union skinny_data {
struct register_message reg;
struct port_message port;
struct keypad_button_message keypad_button;
struct enbloc_call_message enbloc_call;
struct stimulus_message stimulus;
struct off_hook_message off_hook;
struct on_hook_message on_hook;
@@ -1171,6 +1171,29 @@ switch_status_t skinny_handle_keypad_button_message(listener_t *listener, skinny
return SWITCH_STATUS_SUCCESS;
}
switch_status_t skinny_handle_enbloc_call_message(listener_t *listener, skinny_message_t *request)
{
uint32_t line_instance = 1;
switch_core_session_t *session = NULL;
skinny_check_data_length(request, sizeof(request->data.enbloc_call.called_party));
if(skinny_check_data_length_soft(request, sizeof(request->data.enbloc_call))) {
if (request->data.enbloc_call.line_instance > 0) {
line_instance = request->data.enbloc_call.line_instance;
}
}
session = skinny_profile_find_session(listener->profile, listener, &line_instance, 0);
if(session) {
skinny_session_process_dest(session, listener, line_instance, request->data.enbloc_call.called_party, '\0', 0);
switch_core_session_rwunlock(session);
}
return SWITCH_STATUS_SUCCESS;
}
switch_status_t skinny_handle_stimulus_message(listener_t *listener, skinny_message_t *request)
{
switch_status_t status = SWITCH_STATUS_SUCCESS;
@@ -2004,6 +2027,8 @@ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *re
return skinny_handle_port_message(listener, request);
case KEYPAD_BUTTON_MESSAGE:
return skinny_handle_keypad_button_message(listener, request);
case ENBLOC_CALL_MESSAGE:
return skinny_handle_enbloc_call_message(listener, request);
case STIMULUS_MESSAGE:
return skinny_handle_stimulus_message(listener, request);
case OFF_HOOK_MESSAGE:
@@ -39,6 +39,7 @@ struct skinny_table SKINNY_MESSAGE_TYPES[] = {
{"RegisterMessage", REGISTER_MESSAGE},
{"PortMessage", PORT_MESSAGE},
{"KeypadButtonMessage", KEYPAD_BUTTON_MESSAGE},
{"EnblocCallMessage", ENBLOC_CALL_MESSAGE},
{"StimulusMessage", STIMULUS_MESSAGE},
{"OffHookMessage", OFF_HOOK_MESSAGE},
{"OnHookMessage", ON_HOOK_MESSAGE},
+1 -1
View File
@@ -87,7 +87,7 @@ uint32_t func(const char *str)\
}
extern struct skinny_table SKINNY_MESSAGE_TYPES[66];
extern struct skinny_table SKINNY_MESSAGE_TYPES[67];
const char *skinny_message_type2str(uint32_t id);
uint32_t skinny_str2message_type(const char *str);
#define SKINNY_PUSH_MESSAGE_TYPES SKINNY_DECLARE_PUSH_MATCH(SKINNY_MESSAGE_TYPES)
+17 -8
View File
@@ -707,11 +707,20 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session)
cid = generate_pai_str(tech_pvt);
if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->early_sdp && strcmp(tech_pvt->early_sdp, tech_pvt->local_sdp_str)) {
/* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless
we do so in this case we will abandon the SOA rules and go rogue.
*/
sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
if (switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) && tech_pvt->early_sdp) {
char *a, *b;
/* start at the s= line to avoid some devices who update the o= between messages */
a = strstr(tech_pvt->early_sdp, "s=");
b = strstr(tech_pvt->local_sdp_str, "s=");
if (!a || !b || strcmp(a, b)) {
/* The SIP RFC for SOA forbids sending a 183 with one sdp then a 200 with another but it won't do us much good unless
we do so in this case we will abandon the SOA rules and go rogue.
*/
sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
}
}
if (sofia_use_soa(tech_pvt)) {
@@ -3494,7 +3503,7 @@ SWITCH_STANDARD_API(sofia_contact_function)
}
if (zstr(domain)) {
domain = switch_core_get_variable("domain");
domain = switch_core_get_variable_pdup("domain", switch_core_session_get_pool(session));
}
if (!user) goto end;
@@ -3794,7 +3803,7 @@ SWITCH_STANDARD_API(sofia_function)
if (argc > 2) {
if (strstr(argv[2], "presence")) {
mod_sofia_globals.debug_presence = 1;
mod_sofia_globals.debug_presence = 10;
stream->write_function(stream, "+OK Debugging presence\n");
}
@@ -4862,7 +4871,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load)
mod_sofia_globals.running = 1;
switch_mutex_unlock(mod_sofia_globals.mutex);
mod_sofia_globals.auto_nat = (switch_core_get_variable("nat_type") ? 1 : 0);
mod_sofia_globals.auto_nat = (switch_nat_get_type() ? 1 : 0);
switch_queue_create(&mod_sofia_globals.presence_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool);
switch_queue_create(&mod_sofia_globals.mwi_queue, SOFIA_QUEUE_SIZE, mod_sofia_globals.pool);
+6 -5
View File
@@ -1459,7 +1459,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
supported = switch_core_sprintf(profile->pool, "%s%sprecondition, path, replaces", use_100rel ? "100rel, " : "", use_timer ? "timer, " : "");
if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && switch_core_get_variable("nat_type")) {
if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && switch_nat_get_type()) {
if (switch_nat_add_mapping(profile->sip_port, SWITCH_NAT_UDP, NULL, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Created UDP nat mapping for %s port %d\n", profile->name, profile->sip_port);
}
@@ -1676,7 +1676,7 @@ void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t *thread, void
switch_event_fire(&s_event);
}
if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && switch_core_get_variable("nat_type")) {
if (sofia_test_pflag(profile, PFLAG_AUTO_NAT) && switch_nat_get_type()) {
if (switch_nat_del_mapping(profile->sip_port, SWITCH_NAT_UDP) == SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Deleted UDP nat mapping for %s port %d\n", profile->name, profile->sip_port);
}
@@ -3741,9 +3741,9 @@ switch_status_t config_sofia(int reload, char *profile_name)
if (!profile->rtpip[0]) {
profile->rtpip[profile->rtpip_index++] = switch_core_strdup(profile->pool, mod_sofia_globals.guess_ip);
}
if (switch_core_get_variable("nat_type")) {
const char *ip = switch_core_get_variable("nat_public_addr");
if (switch_nat_get_type()) {
char *ip = switch_core_get_variable_dup("nat_public_addr");
if (ip && !strchr(profile->sipip, ':')) {
if (!profile->extrtpip) {
profile->extrtpip = switch_core_strdup(profile->pool, ip);
@@ -3754,6 +3754,7 @@ switch_status_t config_sofia(int reload, char *profile_name)
sofia_set_pflag(profile, PFLAG_AUTO_NAT);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "NAT detected setting external ip to %s\n", ip);
}
switch_safe_free(ip);
}
if (profile->nonce_ttl < 60) {
+17 -10
View File
@@ -4071,15 +4071,22 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
greedy = !!sofia_test_pflag(tech_pvt->profile, PFLAG_GREEDY);
scrooge = !!sofia_test_pflag(tech_pvt->profile, PFLAG_SCROOGE);
if (!greedy || !scrooge) {
if ((val = switch_channel_get_variable(channel, "sip_codec_negotiation"))) {
if (!strcasecmp(val, "greedy")) {
greedy = 1;
} else if (!strcasecmp(val, "scrooge")) {
scrooge = 1;
greedy = 1;
}
}
if ((val = switch_channel_get_variable(channel, "sip_codec_negotiation"))) {
if (!strcasecmp(val, "generous")) {
greedy = 0;
scrooge = 0;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : generous\n" );
} else if (!strcasecmp(val, "greedy")) {
greedy = 1;
scrooge = 0;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : greedy\n" );
} else if (!strcasecmp(val, "scrooge")) {
scrooge = 1;
greedy = 1;
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation overriding sofia inbound-codec-negotiation : scrooge\n" );
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "sip_codec_negotiation ignored invalid value : '%s' \n", val );
}
}
if ((tech_pvt->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) {
@@ -4473,7 +4480,7 @@ uint8_t sofia_glue_negotiate_sdp(switch_core_session_t *session, const char *r_s
match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
}
if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate) {
if (match && bit_rate && map_bit_rate && map_bit_rate != bit_rate && strcasecmp(map->rm_encoding, "ilbc")) {
/* nevermind */
match = 0;
}
+41 -21
View File
@@ -2570,6 +2570,19 @@ static int sofia_counterpath_crutch(void *pArg, int argc, char **argv, char **co
return 0;
}
uint32_t sofia_presence_contact_count(sofia_profile_t *profile, const char *contact_str)
{
char buf[32] = "";
char *sql;
sql = switch_mprintf("select count(*) from sip_subscriptions where profile_name='%q' and contact='%q'", profile->name, contact_str);
sofia_glue_execute_sql2str(profile, profile->ireg_mutex, sql, buf, sizeof(buf));
switch_safe_free(sql);
return atoi(buf);
}
void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip,
tagi_t tags[])
{
@@ -2584,7 +2597,7 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n
char expstr[30] = "";
long exp = 0, exp_delta = 3600;
char *pd_dup = NULL;
int count = 1;
int count = 1, sub_count = 0;
char *contact_str;
int open = 1;
@@ -2667,24 +2680,25 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n
count = sofia_reg_reg_count(profile, from_user, from_host);
}
sub_count = sofia_presence_contact_count(profile, contact_str);
/* if (count > 1) let's not and say we did or all the clients who subscribe to their own presence will think they selves is offline */
event_type = sip_header_as_string(profile->home, (void *) sip->sip_event);
if (count < 2) {
if ((sql =
switch_mprintf("delete from sip_presence where sip_user='%q' and sip_host='%q' "
" and profile_name='%q' and hostname='%q'", from_user, from_host, profile->name, mod_sofia_globals.hostname))) {
if ((sql = switch_mprintf("delete from sip_presence where sip_user='%q' and sip_host='%q' "
" and profile_name='%q' and hostname='%q'",
from_user, from_host, profile->name, mod_sofia_globals.hostname))) {
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
}
if ((sql =
switch_mprintf("insert into sip_presence (sip_user, sip_host, status, rpid, expires, user_agent,"
" profile_name, hostname, open_closed) "
"values ('%q','%q','%q','%q',%ld,'%q','%q','%q','%q')",
from_user, from_host, note_txt, rpid, exp, full_agent, profile->name, mod_sofia_globals.hostname, open_closed))) {
if (sub_count > 0 && (sql = switch_mprintf("insert into sip_presence (sip_user, sip_host, status, rpid, expires, user_agent,"
" profile_name, hostname, open_closed) "
"values ('%q','%q','%q','%q',%ld,'%q','%q','%q','%q')",
from_user, from_host, note_txt, rpid, exp, full_agent, profile->name,
mod_sofia_globals.hostname, open_closed))) {
sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE);
}
@@ -2696,16 +2710,17 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n
switch_safe_free(sql);
}
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user-agent", full_agent);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", note_txt);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", event_type);
switch_event_fire(&event);
if (sub_count > 0) {
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", rpid);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", profile->url);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "user-agent", full_agent);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "status", note_txt);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", event_type);
switch_event_fire(&event);
}
}
if (event_type) {
@@ -2728,7 +2743,12 @@ void sofia_presence_handle_sip_i_publish(nua_t *nua, sofia_profile_t *profile, n
switch_snprintf(expstr, sizeof(expstr), "%d", exp_delta);
switch_stun_random_string(etag, 8, NULL);
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), SIPTAG_ETAG_STR(etag), SIPTAG_EXPIRES_STR(expstr), TAG_END());
if (sub_count > 0) {
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), SIPTAG_ETAG_STR(etag), SIPTAG_EXPIRES_STR(expstr), TAG_END());
} else {
nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END());
}
switch_safe_free(contact_str);
}