From 8cc89ab04287107480e38bf5b650af89c0416518 Mon Sep 17 00:00:00 2001 From: Mathieu Parent Date: Thu, 20 May 2010 15:10:33 +0200 Subject: [PATCH] Skinny: rewrite of the skinny state machine - for incoming calls, go CS_ROUTING only when number is dialed. CS_HIBERNATE before - start media when both side have answered Also: - send tone for UNALLOCATED_NUMBER and USER_BUSY - if channel variables are not sufficent to set call info, ask the partner channel --- src/mod/endpoints/mod_skinny/mod_skinny.c | 119 ++++++++++++++++-- src/mod/endpoints/mod_skinny/mod_skinny.h | 5 +- .../endpoints/mod_skinny/skinny_protocol.c | 14 ++- .../endpoints/mod_skinny/skinny_protocol.h | 1 + src/mod/endpoints/mod_skinny/skinny_server.c | 117 +++++------------ src/mod/endpoints/mod_skinny/skinny_server.h | 1 + 6 files changed, 156 insertions(+), 101 deletions(-) diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.c b/src/mod/endpoints/mod_skinny/mod_skinny.c index 0dcc6ac167..f414c96998 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.c +++ b/src/mod/endpoints/mod_skinny/mod_skinny.c @@ -561,24 +561,104 @@ void tech_init(private_t *tech_pvt, skinny_profile_t *profile, switch_core_sessi switch_status_t channel_on_init(switch_core_session_t *session) { switch_channel_t *channel = switch_core_session_get_channel(session); - private_t *tech_pvt = switch_core_session_get_private(session); - - switch_set_flag_locked(tech_pvt, TFLAG_IO); - - /* Move channel's state machine to ROUTING. This means the call is trying - to get from the initial start where the call because, to the point - where a destination has been identified. If the channel is simply - left in the initial state, nothing will happen. */ - switch_channel_set_state(channel, CS_ROUTING); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL INIT\n", switch_channel_get_name(channel)); return SWITCH_STATUS_SUCCESS; } +struct channel_on_routing_helper { + private_t *tech_pvt; + listener_t *listener; + uint32_t line_instance; +}; + +int channel_on_routing_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct channel_on_routing_helper *helper = pArg; + listener_t *listener = NULL; + + char *device_name = argv[0]; + uint32_t device_instance = atoi(argv[1]); + /* uint32_t position = atoi(argv[2]); */ + uint32_t line_instance = atoi(argv[3]); + /* char *label = argv[4]; */ + /* char *value = argv[5]; */ + /* char *caller_name = argv[6]; */ + /* uint32_t ring_on_idle = atoi(argv[7]); */ + /* uint32_t ring_on_active = atoi(argv[8]); */ + /* uint32_t busy_trigger = atoi(argv[9]); */ + /* char *forward_all = argv[10]; */ + /* char *forward_busy = argv[11]; */ + /* char *forward_noanswer = argv[12]; */ + /* uint32_t noanswer_duration = atoi(argv[13]); */ + /* char *channel_uuid = argv[14]; */ + /* uint32_t call_id = atoi(argv[15]); */ + /* uint32_t call_state = atoi(argv[16]); */ + + skinny_profile_find_listener_by_device_name_and_instance(helper->tech_pvt->profile, device_name, device_instance, &listener); + if(listener) { + if(!strcmp(device_name, helper->listener->device_name) + && (device_instance == helper->listener->device_instance) + && (line_instance == helper->line_instance)) {/* the calling line */ + helper->tech_pvt->caller_profile->dialplan = switch_core_strdup(helper->tech_pvt->caller_profile->pool, listener->profile->dialplan); + helper->tech_pvt->caller_profile->context = switch_core_strdup(helper->tech_pvt->caller_profile->pool, listener->profile->context); + send_dialed_number(listener, helper->tech_pvt->caller_profile->destination_number, line_instance, helper->tech_pvt->call_id); + skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_PROCEED); + skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance); + } else { + send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_ON); + skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_IN_USE_REMOTELY); + send_select_soft_keys(listener, line_instance, helper->tech_pvt->call_id, 10, 0xffff); + send_display_prompt_status(listener, 0, SKINNY_DISP_IN_USE_REMOTE, + line_instance, helper->tech_pvt->call_id); + skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance); + } + } + return 0; +} + switch_status_t channel_on_routing(switch_core_session_t *session) { switch_channel_t *channel = switch_core_session_get_channel(session); + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { + skinny_action_t action; + private_t *tech_pvt = switch_core_session_get_private(session); + char *data = NULL; + listener_t *listener = NULL; + struct channel_on_routing_helper helper = {0}; + + if(switch_test_flag(tech_pvt, TFLAG_FORCE_ROUTE)) { + action = SKINNY_ACTION_ROUTE; + switch_clear_flag_locked(tech_pvt, TFLAG_FORCE_ROUTE); + } else { + action = skinny_session_dest_match_pattern(session, &data); + } + switch(action) { + case SKINNY_ACTION_ROUTE: + skinny_profile_find_listener_by_device_name_and_instance(tech_pvt->profile, + switch_channel_get_variable(channel, "skinny_device_name"), + atoi(switch_channel_get_variable(channel, "skinny_device_instance")), &listener); + if (listener) { + helper.tech_pvt = tech_pvt; + helper.listener = listener; + helper.line_instance = atoi(switch_channel_get_variable(channel, "skinny_line_instance")); + skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), channel_on_routing_callback, &helper); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Could not find listener %s:%s for Channel %s\n", + switch_channel_get_variable(channel, "skinny_device_name"), switch_channel_get_variable(channel, "skinny_device_instance"), + switch_channel_get_name(channel)); + } + break; + case SKINNY_ACTION_WAIT: + /* for now, wait forever */ + switch_channel_set_state(channel, CS_HIBERNATE); + break; + case SKINNY_ACTION_DROP: + default: + switch_channel_hangup(channel, SWITCH_CAUSE_UNALLOCATED_NUMBER); + } + } switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel)); @@ -591,7 +671,6 @@ switch_status_t channel_on_execute(switch_core_session_t *session) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL EXECUTE\n", switch_channel_get_name(channel)); - return SWITCH_STATUS_SUCCESS; } @@ -651,11 +730,14 @@ int channel_on_hangup_callback(void *pArg, int argc, char **argv, char **columnN send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_OFF); switch (helper->cause) { case SWITCH_CAUSE_UNALLOCATED_NUMBER: + send_start_tone(listener, SKINNY_TONE_REORDER, 0, line_instance, call_id); + skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance); send_display_prompt_status(listener, 0, SKINNY_DISP_UNKNOWN_NUMBER, line_instance, call_id); break; case SWITCH_CAUSE_USER_BUSY: + send_start_tone(listener, SKINNY_TONE_BUSYTONE, 0, line_instance, call_id); send_display_prompt_status(listener, 0, SKINNY_DISP_BUSY, line_instance, call_id); - break; + break; case SWITCH_CAUSE_NORMAL_CLEARING: send_clear_prompt_status(listener, line_instance, call_id); break; @@ -842,6 +924,20 @@ switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame switch_status_t channel_answer_channel(switch_core_session_t *session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + private_t *tech_pvt = switch_core_session_get_private(session); + listener_t *listener = NULL; + + skinny_profile_find_listener_by_device_name_and_instance(tech_pvt->profile, + switch_channel_get_variable(channel, "skinny_device_name"), + atoi(switch_channel_get_variable(channel, "skinny_device_instance")), &listener); + if (listener) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Bli!\n"); + skinny_session_start_media(session, listener, atoi(switch_channel_get_variable(channel, "skinny_line_instance"))); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Unable to find listener to answer %s:%s\n", + switch_channel_get_variable(channel, "skinny_device_name"), switch_channel_get_variable(channel, "skinny_device_instance")); + } return SWITCH_STATUS_SUCCESS; } @@ -925,7 +1021,6 @@ switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, swi tech_pvt->caller_profile = caller_profile; switch_channel_set_flag(channel, CF_OUTBOUND); - switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); if ((sql = switch_mprintf( "INSERT INTO skinny_active_lines " diff --git a/src/mod/endpoints/mod_skinny/mod_skinny.h b/src/mod/endpoints/mod_skinny/mod_skinny.h index 314e29ba73..90947e20c1 100644 --- a/src/mod/endpoints/mod_skinny/mod_skinny.h +++ b/src/mod/endpoints/mod_skinny/mod_skinny.h @@ -146,8 +146,6 @@ typedef switch_status_t (*skinny_listener_callback_func_t) (listener_t *listener /*****************************************************************************/ typedef enum { TFLAG_IO = (1 << 0), - TFLAG_INBOUND = (1 << 1), - TFLAG_OUTBOUND = (1 << 2), TFLAG_DTMF = (1 << 3), TFLAG_VOICE = (1 << 4), TFLAG_HANGUP = (1 << 5), @@ -155,7 +153,8 @@ typedef enum { TFLAG_CODEC = (1 << 7), TFLAG_READING = (1 << 9), - TFLAG_WRITING = (1 << 10) + TFLAG_WRITING = (1 << 10), + TFLAG_FORCE_ROUTE = (1 << 11) } TFLAGS; typedef enum { diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.c b/src/mod/endpoints/mod_skinny/skinny_protocol.c index f1479ba0dd..aefbf7e31a 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.c +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.c @@ -242,6 +242,15 @@ switch_status_t skinny_device_event(listener_t *listener, switch_event_t **ev, s return SWITCH_STATUS_SUCCESS; } +switch_status_t skinny_set_channel_variables(switch_channel_t *channel, listener_t *listener, uint32_t line_instance) +{ + switch_channel_set_variable(channel, "skinny_profile_name", listener->profile->name); + switch_channel_set_variable(channel, "skinny_device_name", listener->device_name); + switch_channel_set_variable_printf(channel, "skinny_device_instance", "%d", listener->device_instance); + switch_channel_set_variable_printf(channel, "skinny_line_instance", "%d", line_instance); + return SWITCH_STATUS_SUCCESS; +} + /*****************************************************************************/ /*****************************************************************************/ switch_status_t skinny_session_walk_lines(skinny_profile_t *profile, char *channel_uuid, switch_core_db_callback_func_t callback, void *data) @@ -916,8 +925,9 @@ switch_status_t skinny_perform_send_reply(listener_t *listener, const char *file ptr = (char *) reply; switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_DEBUG, - "Sending %s (type=%x,length=%d).\n", - skinny_message_type2str(reply->type), reply->type, reply->length); + "Sending %s (type=%x,length=%d) to %s:%d.\n", + skinny_message_type2str(reply->type), reply->type, reply->length, + listener->device_name, listener->device_instance); switch_socket_send(listener->sock, ptr, &len); return SWITCH_STATUS_SUCCESS; diff --git a/src/mod/endpoints/mod_skinny/skinny_protocol.h b/src/mod/endpoints/mod_skinny/skinny_protocol.h index 45bac96243..c9dcb4b81b 100644 --- a/src/mod/endpoints/mod_skinny/skinny_protocol.h +++ b/src/mod/endpoints/mod_skinny/skinny_protocol.h @@ -637,6 +637,7 @@ char* skinny_codec2string(enum skinny_codecs skinnycodec); switch_status_t skinny_read_packet(listener_t *listener, skinny_message_t **req); switch_status_t skinny_device_event(listener_t *listener, switch_event_t **ev, switch_event_types_t event_id, const char *subclass_name); +switch_status_t skinny_set_channel_variables(switch_channel_t *channel, listener_t *listener, uint32_t line_instance); switch_status_t skinny_session_walk_lines(skinny_profile_t *profile, char *channel_uuid, switch_core_db_callback_func_t callback, void *data); diff --git a/src/mod/endpoints/mod_skinny/skinny_server.c b/src/mod/endpoints/mod_skinny/skinny_server.c index 6ed1f36017..62ceffa446 100644 --- a/src/mod/endpoints/mod_skinny/skinny_server.c +++ b/src/mod/endpoints/mod_skinny/skinny_server.c @@ -117,6 +117,7 @@ switch_status_t skinny_create_incoming_session(listener_t *listener, uint32_t *l snprintf(name, sizeof(name), "SKINNY/%s/%s:%d/%d", listener->profile->name, listener->device_name, listener->device_instance, *line_instance_p); switch_channel_set_name(channel, name); + skinny_set_channel_variables(channel, listener, *line_instance_p); if (switch_core_session_thread_launch(nsession) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nsession), SWITCH_LOG_CRIT, @@ -163,6 +164,12 @@ switch_status_t skinny_create_incoming_session(listener_t *listener, uint32_t *l send_display_prompt_status(listener, 0, "\200\000", *line_instance_p, tech_pvt->call_id); send_activate_call_plane(listener, *line_instance_p); + if (switch_channel_get_state(channel) == CS_NEW) { + switch_channel_set_state(channel, CS_HIBERNATE); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(nsession), SWITCH_LOG_CRIT, + "Wow! this channel should be in CS_NEW state, but it is not!\n"); + } goto done; error: @@ -246,60 +253,10 @@ found: } -struct skinny_session_process_dest_helper { - private_t *tech_pvt; - listener_t *listener; - uint32_t line_instance; -}; - -int skinny_session_process_dest_callback(void *pArg, int argc, char **argv, char **columnNames) -{ - struct skinny_session_process_dest_helper *helper = pArg; - listener_t *listener = NULL; - - char *device_name = argv[0]; - uint32_t device_instance = atoi(argv[1]); - /* uint32_t position = atoi(argv[2]); */ - uint32_t line_instance = atoi(argv[3]); - /* char *label = argv[4]; */ - /* char *value = argv[5]; */ - /* char *caller_name = argv[6]; */ - /* uint32_t ring_on_idle = atoi(argv[7]); */ - /* uint32_t ring_on_active = atoi(argv[8]); */ - /* uint32_t busy_trigger = atoi(argv[9]); */ - /* char *forward_all = argv[10]; */ - /* char *forward_busy = argv[11]; */ - /* char *forward_noanswer = argv[12]; */ - /* uint32_t noanswer_duration = atoi(argv[13]); */ - /* char *channel_uuid = argv[14]; */ - /* uint32_t call_id = atoi(argv[15]); */ - /* uint32_t call_state = atoi(argv[16]); */ - - skinny_profile_find_listener_by_device_name_and_instance(helper->tech_pvt->profile, device_name, device_instance, &listener); - if(listener) { - if(!strcmp(device_name, helper->listener->device_name) - && (device_instance == helper->listener->device_instance) - && (line_instance == helper->line_instance)) {/* the calling line */ - /* nothing */ - } else { - send_set_lamp(listener, SKINNY_BUTTON_LINE, line_instance, SKINNY_LAMP_ON); - skinny_line_set_state(listener, line_instance, helper->tech_pvt->call_id, SKINNY_IN_USE_REMOTELY); - send_select_soft_keys(listener, line_instance, helper->tech_pvt->call_id, 10, 0xffff); - send_display_prompt_status(listener, 0, SKINNY_DISP_IN_USE_REMOTE, - line_instance, helper->tech_pvt->call_id); - skinny_session_send_call_info(helper->tech_pvt->session, listener, line_instance); - } - } - return 0; -} - switch_status_t skinny_session_process_dest(switch_core_session_t *session, listener_t *listener, uint32_t line_instance, char *dest, char append_dest, uint32_t backspace) { - skinny_action_t action; switch_channel_t *channel = NULL; private_t *tech_pvt = NULL; - char *data = NULL; - struct skinny_session_process_dest_helper helper = {0}; switch_assert(session); switch_assert(listener); @@ -333,34 +290,10 @@ switch_status_t skinny_session_process_dest(switch_core_session_t *session, list } else { tech_pvt->caller_profile->destination_number = switch_core_strdup(tech_pvt->caller_profile->pool, dest); + switch_set_flag_locked(tech_pvt, TFLAG_FORCE_ROUTE); } - if(dest) { - action = SKINNY_ACTION_ROUTE; - } else { - action = skinny_session_dest_match_pattern(session, &data); - } - switch(action) { - case SKINNY_ACTION_ROUTE: - tech_pvt->caller_profile->dialplan = switch_core_strdup(tech_pvt->caller_profile->pool, listener->profile->dialplan); - tech_pvt->caller_profile->context = switch_core_strdup(tech_pvt->caller_profile->pool, listener->profile->context); - send_dialed_number(listener, tech_pvt->caller_profile->destination_number, line_instance, tech_pvt->call_id); - skinny_line_set_state(listener, line_instance, tech_pvt->call_id, SKINNY_PROCEED); - skinny_session_send_call_info(session, listener, line_instance); - - skinny_session_start_media(session, listener, line_instance); - - helper.tech_pvt = tech_pvt; - helper.listener = listener; - helper.line_instance = line_instance; - skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), skinny_session_process_dest_callback, &helper); - break; - case SKINNY_ACTION_WAIT: - /* for now, wait forever */ - break; - case SKINNY_ACTION_DROP: - default: - switch_channel_hangup(channel, SWITCH_CAUSE_UNALLOCATED_NUMBER); - } + + switch_channel_set_state(channel, CS_ROUTING); return SWITCH_STATUS_SUCCESS; } @@ -383,20 +316,28 @@ switch_status_t skinny_session_send_call_info(switch_core_session_t *session, li /* Calling party */ if (zstr((caller_party_name = switch_channel_get_variable(channel, "effective_caller_id_name"))) && - zstr((caller_party_name = switch_channel_get_variable(channel, "caller_id_name")))) { + zstr((caller_party_name = switch_channel_get_variable(channel, "caller_id_name"))) && + zstr((caller_party_name = switch_channel_get_variable_partner(channel, "effective_caller_id_name"))) && + zstr((caller_party_name = switch_channel_get_variable_partner(channel, "caller_id_name")))) { caller_party_name = SWITCH_DEFAULT_CLID_NAME; } if (zstr((caller_party_number = switch_channel_get_variable(channel, "effective_caller_id_number"))) && - zstr((caller_party_number = switch_channel_get_variable(channel, "caller_id_number")))) { + zstr((caller_party_number = switch_channel_get_variable(channel, "caller_id_number"))) && + zstr((caller_party_number = switch_channel_get_variable_partner(channel, "effective_caller_id_number"))) && + zstr((caller_party_number = switch_channel_get_variable_partner(channel, "caller_id_number")))) { caller_party_number = "0000000000"; } /* Called party */ if (zstr((called_party_name = switch_channel_get_variable(channel, "effective_callee_id_name"))) && - zstr((called_party_name = switch_channel_get_variable(channel, "callee_id_name")))) { + zstr((called_party_name = switch_channel_get_variable(channel, "callee_id_name"))) && + zstr((called_party_name = switch_channel_get_variable_partner(channel, "effective_callee_id_name"))) && + zstr((called_party_name = switch_channel_get_variable_partner(channel, "callee_id_name")))) { called_party_name = SWITCH_DEFAULT_CLID_NAME; } if (zstr((called_party_number = switch_channel_get_variable(channel, "effective_callee_id_number"))) && zstr((called_party_number = switch_channel_get_variable(channel, "callee_id_number"))) && + zstr((called_party_number = switch_channel_get_variable_partner(channel, "effective_callee_id_number"))) && + zstr((called_party_number = switch_channel_get_variable_partner(channel, "callee_id_number"))) && zstr((called_party_number = switch_channel_get_variable(channel, "destination_number")))) { called_party_number = "0000000000"; } @@ -615,6 +556,9 @@ switch_status_t skinny_session_answer(switch_core_session_t *session, listener_t skinny_session_walk_lines(tech_pvt->profile, switch_core_session_get_uuid(session), skinny_session_answer_callback, &helper); + if (switch_channel_get_state(channel) == CS_INIT) { + switch_channel_set_state(channel, CS_ROUTING); + } skinny_session_start_media(session, listener, line_instance); return SWITCH_STATUS_SUCCESS; @@ -763,6 +707,8 @@ switch_status_t skinny_session_stop_media(switch_core_session_t *session, listen channel = switch_core_session_get_channel(session); tech_pvt = switch_core_session_get_private(session); + switch_clear_flag_locked(tech_pvt, TFLAG_IO); + send_close_receive_channel(listener, tech_pvt->call_id, /* uint32_t conference_id, */ tech_pvt->party_id, /* uint32_t pass_thru_party_id, */ @@ -1565,10 +1511,12 @@ switch_status_t skinny_handle_open_receive_channel_ack_message(listener_t *liste 0 /* uint32_t g723_bitrate */ ); - if (switch_channel_get_state(channel) == CS_NEW) { - switch_channel_set_state(channel, CS_INIT); - } + switch_set_flag_locked(tech_pvt, TFLAG_IO); switch_channel_mark_answered(channel); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Unable to find session for device %s:%d (call id=%d).\n", + listener->device_name, listener->device_instance, request->data.open_receive_channel_ack.pass_thru_party_id); } end: if(session) { @@ -1819,7 +1767,8 @@ switch_status_t skinny_handle_feature_stat_request(listener_t *listener, skinny_ switch_status_t skinny_handle_request(listener_t *listener, skinny_message_t *request) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - "Received %s (type=%x,length=%d).\n", skinny_message_type2str(request->type), request->type, request->length); + "Received %s (type=%x,length=%d) from %s:%d.\n", skinny_message_type2str(request->type), request->type, request->length, + listener->device_name, listener->device_instance); if(zstr(listener->device_name) && request->type != REGISTER_MESSAGE && request->type != ALARM_MESSAGE) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Device should send a register message first.\n"); diff --git a/src/mod/endpoints/mod_skinny/skinny_server.h b/src/mod/endpoints/mod_skinny/skinny_server.h index f4651e184c..6aab6b99ff 100644 --- a/src/mod/endpoints/mod_skinny/skinny_server.h +++ b/src/mod/endpoints/mod_skinny/skinny_server.h @@ -36,6 +36,7 @@ /* SESSION FUNCTIONS */ switch_status_t skinny_create_ingoing_session(listener_t *listener, uint32_t *line_instance, switch_core_session_t **session); +skinny_action_t skinny_session_dest_match_pattern(switch_core_session_t *session, char **data); switch_status_t skinny_session_process_dest(switch_core_session_t *session, listener_t *listener, uint32_t line_instance, char *dest, char append_dest, uint32_t backspace); switch_status_t skinny_session_send_call_info(switch_core_session_t *session, listener_t *listener, uint32_t line_instance); switch_call_cause_t skinny_ring_lines(private_t *tech_pvt);