From 3c747978f4b1dc395846e90f613fbf2acb6324db Mon Sep 17 00:00:00 2001
From: David Yat Sin <dyatsin@sangoma.com>
Date: Thu, 9 Dec 2010 13:20:05 -0500
Subject: [PATCH 1/4] freetdm: support for call variables

---
 libs/freetdm/mod_freetdm/mod_freetdm.c        |  42 +++--
 libs/freetdm/src/ftdm_io.c                    | 129 ++++++++++++++-
 .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.c   |  31 +++-
 .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.h   |   8 +-
 .../ftmod_sangoma_isdn_stack_hndl.c           |   9 +-
 .../ftmod_sangoma_isdn_stack_out.c            |  26 ++-
 .../ftmod_sangoma_isdn_support.c              | 151 ++++++++++++++++--
 .../ftmod_sangoma_ss7_handle.c                |   4 +-
 .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c |  42 ++---
 libs/freetdm/src/include/freetdm.h            |  57 ++++++-
 libs/freetdm/src/include/private/ftdm_core.h  |   1 +
 11 files changed, 428 insertions(+), 72 deletions(-)

diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index 7ea6bb6d37..38197bb2f0 100755
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -429,7 +429,7 @@ static switch_status_t channel_on_routing(switch_core_session_t *session)
 	assert(tech_pvt->ftdmchan != NULL);
 
 	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s CHANNEL ROUTING\n", switch_channel_get_name(channel));
-	
+
 	ftdm_channel_call_indicate(tech_pvt->ftdmchan, FTDM_CHANNEL_INDICATE_PROCEED);
 	return SWITCH_STATUS_SUCCESS;
 }
@@ -1329,7 +1329,7 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
 			char *v = h->name + FREETDM_VAR_PREFIX_LEN;
 			if (!zstr(v)) {
 				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding outbound freetdm variable %s=%s to channel %d:%d\n", v, h->value, span_id, chan_id);
-				ftdm_channel_add_var(ftdmchan, v, h->value);
+				ftdm_call_add_var(&caller_data, v, h->value);
 			}
 		}
 	}
@@ -1528,6 +1528,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session
 	switch_channel_set_variable_printf(channel, "freetdm_chan_number", "%d", chanid);
 	switch_channel_set_variable_printf(channel, "freetdm_bearer_capability", "%d", channel_caller_data->bearer_capability);	
 	switch_channel_set_variable_printf(channel, "freetdm_bearer_layer1", "%d", channel_caller_data->bearer_layer1);
+	
 	if (globals.sip_headers) {
 		switch_channel_set_variable(channel, "sip_h_X-FreeTDM-SpanName", ftdm_channel_get_span_name(sigmsg->channel));
 		switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-SpanNumber", "%d", spanid);	
@@ -1561,8 +1562,18 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session
 		ftdm_channel_get_current_var(curr, &var_name, &var_value);
 		snprintf(name, sizeof(name), FREETDM_VAR_PREFIX "%s", var_name);
 		switch_channel_set_variable_printf(channel, name, "%s", var_value);
+	}	
+	
+	/* Add any call variable to the dial plan */
+	iter = ftdm_call_get_var_iterator(channel_caller_data, iter);
+	for (curr = iter ; curr; curr = ftdm_iterator_next(curr)) {
+		ftdm_call_get_current_var(curr, &var_name, &var_value);
+		snprintf(name, sizeof(name), FREETDM_VAR_PREFIX "%s", var_name);
+		switch_channel_set_variable_printf(channel, name, "%s", var_value);
+		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Call Variable: %s=%s\n", name, var_value);
 	}
 	ftdm_iterator_free(iter);
+	
 
 	switch_channel_set_state(channel, CS_INIT);
 	if (switch_core_session_thread_launch(session) != SWITCH_STATUS_SUCCESS) {
@@ -1661,11 +1672,11 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
 	ftdm_status_t status;
 	uint32_t spanid;
 	uint32_t chanid;
-	ftdm_caller_data_t *callerdata;
+	ftdm_caller_data_t *caller_data;
 
 	spanid = ftdm_channel_get_span_id(sigmsg->channel);
 	chanid = ftdm_channel_get_id(sigmsg->channel);
-	callerdata = ftdm_channel_get_caller_data(sigmsg->channel);
+	caller_data = ftdm_channel_get_caller_data(sigmsg->channel);
 
 	ftdm_log(FTDM_LOG_DEBUG, "got FXO sig %d:%d [%s]\n", spanid, chanid, ftdm_signal_event2str(sigmsg->event_id));
 
@@ -1688,7 +1699,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
 				switch_set_flag_locked(tech_pvt, TFLAG_DEAD);
 				ftdm_channel_clear_token(sigmsg->channel, 0);
 				channel = switch_core_session_get_channel(session);
-				switch_channel_hangup(channel, callerdata->hangup_cause);
+				switch_channel_hangup(channel, caller_data->hangup_cause);
 				ftdm_channel_clear_token(sigmsg->channel, switch_core_session_get_uuid(session));
 				switch_core_session_rwunlock(session);
 			}
@@ -1712,8 +1723,8 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxo_signal)
 			}
 		}
 		break;
-    case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
-
+	case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
+	
 	default:
 		{
 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Unhandled msg type %d for channel %d:%d\n",
@@ -1767,7 +1778,8 @@ static FIO_SIGNAL_CB_FUNCTION(on_fxs_signal)
 			}
 		}
 		break;
-    case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
+	case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
+	
     case FTDM_SIGEVENT_STOP:
 		{
 			private_t *tech_pvt = NULL;
@@ -1991,8 +2003,8 @@ static FIO_SIGNAL_CB_FUNCTION(on_r2_signal)
 		}
 		break;
 		
-    		case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
-
+		case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
+		
 		/* on DNIS received from the R2 forward side, return status == FTDM_BREAK to stop requesting DNIS */
 		case FTDM_SIGEVENT_COLLECTED_DIGIT: 
 		{
@@ -2104,14 +2116,14 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
     switch(sigmsg->event_id) {
     case FTDM_SIGEVENT_START:
 		{
-			ftdm_channel_add_var(sigmsg->channel, "screening_ind", ftdm_screening2str(caller_data->screen));
-			ftdm_channel_add_var(sigmsg->channel, "presentation_ind", ftdm_presentation2str(caller_data->pres));
+			ftdm_call_add_var(caller_data, "screening_ind", ftdm_screening2str(caller_data->screen));
+			ftdm_call_add_var(caller_data, "presentation_ind", ftdm_presentation2str(caller_data->pres));
 			return ftdm_channel_from_event(sigmsg, &session);
 		}
 		break;
 
-    case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
-
+	case FTDM_SIGEVENT_RELEASED: { /* twiddle */ } break;
+		
     case FTDM_SIGEVENT_STOP:
     case FTDM_SIGEVENT_RESTART:
 		{
@@ -2176,7 +2188,7 @@ static FIO_SIGNAL_CB_FUNCTION(on_clear_channel_signal)
 		}
 		break;
 	case FTDM_SIGEVENT_PROCEED:
-	case FTDM_SIGEVENT_MSG:
+	case FTDM_SIGEVENT_FACILITY:
 		/* FS does not have handlers for these messages, so ignore them for now */
 		break;
 	default:
diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index ef290964d4..7355c8497c 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -61,6 +61,8 @@ struct tm *localtime_r(const time_t *clock, struct tm *result);
 ftdm_time_t time_last_throttle_log = 0;
 ftdm_time_t time_current_throttle_log = 0;
 
+static ftdm_iterator_t *get_iterator(ftdm_iterator_type_t type, ftdm_iterator_t *iter);
+
 static int time_is_init = 0;
 
 static void time_init(void)
@@ -1893,7 +1895,9 @@ static ftdm_status_t ftdm_channel_reset(ftdm_channel_t *ftdmchan)
 	if (!ftdmchan->dtmf_off) {
 		ftdmchan->dtmf_off = FTDM_DEFAULT_DTMF_OFF;
 	}
-	
+
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
+			
 	memset(ftdmchan->dtmf_hangup_buf, '\0', ftdmchan->span->dtmf_hangup_len);
 
 	if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_TRANSCODE)) {
@@ -2432,6 +2436,27 @@ done:
 	return FTDM_SUCCESS;
 }
 
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_send_msg(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_sigmsg_t *sigmsg)
+{
+	ftdm_status_t status = FTDM_FAIL;
+	ftdm_assert_return(ftdmchan != NULL, FTDM_FAIL, "null channel");
+#ifdef __WINDOWS__
+	UNREFERENCED_PARAMETER(file);
+	UNREFERENCED_PARAMETER(func);
+	UNREFERENCED_PARAMETER(line);
+#endif
+
+	ftdm_channel_lock(ftdmchan);
+	if (ftdmchan->span->send_msg) {
+		status = ftdmchan->span->send_msg(ftdmchan, sigmsg);
+	} else {
+		status = FTDM_NOTIMPL;
+		ftdm_log(FTDM_LOG_ERROR, "send_msg method not implemented in this span!\n");
+	}
+	ftdm_channel_unlock(ftdmchan);
+	return status;
+}
+
 FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan)
 {
 	ftdm_status_t status = FTDM_FAIL;
@@ -3878,6 +3903,100 @@ done:
 	return status;
 }
 
+FT_DECLARE(void) ftdm_call_clear_data(ftdm_caller_data_t *caller_data)
+{
+	ftdm_call_clear_vars(caller_data);
+	memset(caller_data.raw_data, 0, sizeof(raw_data));
+	caller_data->raw_data_len = 0;
+	return;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_call_clear_vars(ftdm_caller_data_t *caller_data)
+{
+	if (caller_data->variables) {
+		hashtable_destroy(caller_data->variables);
+	}
+	caller_data->variables = NULL;
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_call_remove_var(ftdm_caller_data_t *caller_data, const char *var_name)
+{
+	if (caller_data->variables) {
+		hashtable_remove(caller_data->variables, (void *)var_name);
+	}
+	
+	return FTDM_SUCCESS;
+}
+
+
+FT_DECLARE(ftdm_status_t) ftdm_call_add_var(ftdm_caller_data_t *caller_data, const char *var_name, const char *value)
+{
+	char *t_name = 0, *t_val = 0;
+
+	if (!var_name || !value) {
+		return FTDM_FAIL;
+	}
+	
+	if (!caller_data->variables) {
+		/* initialize on first use */
+		caller_data->variables = create_hashtable(16, ftdm_hash_hashfromstring, ftdm_hash_equalkeys);
+		ftdm_assert_return(caller_data->variables, FTDM_FAIL, "Failed to create hash table\n");
+	}
+	
+	t_name = ftdm_strdup(var_name);
+	t_val = ftdm_strdup(value);
+	hashtable_insert(caller_data->variables, t_name, t_val, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_FLAG_FREE_VALUE);
+	return FTDM_SUCCESS;
+}
+
+FT_DECLARE(const char *) ftdm_call_get_var(ftdm_caller_data_t *caller_data, const char *var_name)
+{
+	const char *var = NULL;
+	
+	if (!caller_data->variables || !var_name) {
+		return NULL;
+	}
+
+	var = (const char *)hashtable_search(((struct hashtable*)caller_data->variables), (void *)var_name);
+	return var;
+}
+
+FT_DECLARE(ftdm_iterator_t *) ftdm_call_get_var_iterator(const ftdm_caller_data_t *caller_data, ftdm_iterator_t *iter)
+{
+	ftdm_hash_iterator_t *hashiter = NULL;
+	hashiter = caller_data->variables == NULL ? NULL : hashtable_first(caller_data->variables);
+	
+	if (hashiter == NULL) {
+		return NULL;
+	}
+	
+	if (!(iter = get_iterator(FTDM_ITERATOR_VARS, iter))) {
+		return NULL;
+	}
+	iter->pvt.hashiter = hashiter;
+	return iter;
+}
+
+FT_DECLARE(ftdm_status_t) ftdm_call_get_current_var(ftdm_iterator_t *iter, const char **var_name, const char **var_val)
+{
+	const void *key = NULL;
+	void *val = NULL;
+
+	*var_name = NULL;
+	*var_val = NULL;
+
+	ftdm_assert_return(iter && (iter->type == FTDM_ITERATOR_VARS) && iter->pvt.hashiter, FTDM_FAIL, "Cannot get variable from invalid iterator!\n");
+
+	hashtable_this(iter->pvt.hashiter, &key, NULL, &val);
+
+	*var_name = key;
+	*var_val = val;
+
+	return FTDM_SUCCESS;
+}
+
+
 static ftdm_status_t ftdm_channel_clear_vars(ftdm_channel_t *ftdmchan)
 {
 	ftdm_channel_lock(ftdmchan);
@@ -3924,6 +4043,7 @@ done:
 	return status;
 }
 
+
 FT_DECLARE(const char *) ftdm_channel_get_var(ftdm_channel_t *ftdmchan, const char *var_name)
 {
 	const char *var = NULL;
@@ -5157,7 +5277,11 @@ FT_DECLARE(ftdm_status_t) ftdm_group_create(ftdm_group_t **group, const char *na
 
 static ftdm_status_t ftdm_span_trigger_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg)
 {
-	return span->signal_cb(sigmsg);
+	ftdm_status_t status = span->signal_cb(sigmsg);
+	if (sigmsg->channel) {
+		ftdm_call_clear_data(&(sigmsg->channel->caller_data));
+	}
+	return status;
 }
 
 static ftdm_status_t ftdm_span_queue_signal(const ftdm_span_t *span, ftdm_sigmsg_t *sigmsg)
@@ -5261,6 +5385,7 @@ FT_DECLARE(ftdm_status_t) ftdm_span_send_signal(ftdm_span_t *span, ftdm_sigmsg_t
 	}
 
 done:
+	
 	if (sigmsg->channel) {
 		ftdm_mutex_unlock(sigmsg->channel->mutex);
 	}
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
index 03b5a5fb1d..96f1a2b430 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
@@ -626,8 +626,11 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
 	case FTDM_CHANNEL_STATE_GET_CALLERID:
 		{
 			if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
+				/* By default, we do not send a progress indicator in the proceed */
+				ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID};
+				
 				sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
-				sngisdn_snd_proceed(ftdmchan);
+				sngisdn_snd_proceed(ftdmchan, prog_ind);
 			}
 			/* Wait in this state until we get FACILITY msg */			
 		}
@@ -666,8 +669,11 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
 				ftdm_span_send_signal(ftdmchan->span, &sigev);
 			} else {
 				if (!sngisdn_test_flag(sngisdn_info, FLAG_SENT_PROCEED)) {
+					/* By default, we do not send a progress indicator in the proceed */
+					ftdm_sngisdn_progind_t prog_ind = {SNGISDN_PROGIND_LOC_USER, SNGISDN_PROGIND_DESCR_INVALID};
+					
 					sngisdn_set_flag(sngisdn_info, FLAG_SENT_PROCEED);
-					sngisdn_snd_proceed(ftdmchan);
+					sngisdn_snd_proceed(ftdmchan, prog_ind);
 				}
 			}
 		}
@@ -851,6 +857,26 @@ static void ftdm_sangoma_isdn_process_state_change(ftdm_channel_t *ftdmchan)
 	return;
 }
 
+static FIO_CHANNEL_SEND_MSG_FUNCTION(ftdm_sangoma_isdn_send_msg)
+{
+	ftdm_status_t status = FTDM_FAIL;
+
+	switch (sigmsg->event_id) {
+		case FTDM_SIGEVENT_RESTART:
+			/* TODO: Send a channel restart here */
+			/* Implement me */
+			break;
+		case FTDM_SIGEVENT_FACILITY:
+			sngisdn_snd_fac_req(ftdmchan);
+			break;
+		default:
+			ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Unsupported signalling msg requested\n");
+			status = FTDM_BREAK;
+	}
+	ftdm_call_clear_data(&ftdmchan->caller_data);
+	return status;
+}
+
 static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(ftdm_sangoma_isdn_outgoing_call)
 {
 	sngisdn_chan_data_t  *sngisdn_info = ftdmchan->call_data;
@@ -1030,6 +1056,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
 	span->stop = ftdm_sangoma_isdn_stop;
 	span->signal_type = FTDM_SIGTYPE_ISDN;
 	span->outgoing_call = ftdm_sangoma_isdn_outgoing_call;
+	span->send_msg = ftdm_sangoma_isdn_send_msg;
 	span->channel_request = NULL;
 	span->signal_cb	= sig_cb;
 	span->get_channel_sig_status = ftdm_sangoma_isdn_get_chan_sig_status;
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
index b9ab3395ae..f15eff9200 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.h
@@ -363,7 +363,7 @@ void stack_pst_init(Pst *pst);
 /* Outbound Call Control functions */
 void sngisdn_snd_setup(ftdm_channel_t *ftdmchan);
 void sngisdn_snd_setup_ack(ftdm_channel_t *ftdmchan);
-void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan);
+void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind);
 void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind);
 void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind);
 void sngisdn_snd_connect(ftdm_channel_t *ftdmchan);
@@ -436,6 +436,7 @@ void sngisdn_rcv_sng_log(uint8_t level, char *fmt,...);
 void sngisdn_rcv_sng_assert(char *message);
 
 ftdm_status_t get_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb);
+ftdm_status_t get_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb);
 ftdm_status_t get_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb);
 ftdm_status_t get_redir_num(ftdm_channel_t *ftdmchan, RedirNmb *redirNmb);
 ftdm_status_t get_calling_name_from_display(ftdm_channel_t *ftdmchan, Display *display);
@@ -443,16 +444,17 @@ ftdm_status_t get_calling_name_from_usr_usr(ftdm_channel_t *ftdmchan, UsrUsr *us
 ftdm_status_t get_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad);
 ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd);
 ftdm_status_t get_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr);
-ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t data_len);
+ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t data_len);
 
 ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb);
+ftdm_status_t set_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb);
 ftdm_status_t set_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb);
 ftdm_status_t set_redir_num(ftdm_channel_t *ftdmchan, RedirNmb *redirNmb);
 ftdm_status_t set_calling_name(ftdm_channel_t *ftdmchan, ConEvnt *conEvnt);
 ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad);
 ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_sngisdn_progind_t prog_ind);
 ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr);
-ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t *data_len);
+ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t *data_len);
 
 		
 uint8_t sngisdn_get_infoTranCap_from_stack(ftdm_bearer_cap_t bearer_capability);
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
index 086354a993..cb9f6d33e1 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
@@ -123,12 +123,9 @@ void sngisdn_process_con_ind (sngisdn_event_data_t *sngisdn_event)
 				break;
 			}
 
-#if 0
-			/* Export ftdmchan variables here if we need to */
-			ftdm_channel_add_var(ftdmchan, "isdn_specific_var", "1");
-#endif
 			/* Fill in call information */
 			get_calling_num(ftdmchan, &conEvnt->cgPtyNmb);
+			get_calling_num2(ftdmchan, &conEvnt->cgPtyNmb2);
 			get_called_num(ftdmchan, &conEvnt->cdPtyNmb);
 			get_redir_num(ftdmchan, &conEvnt->redirNmb);
 			get_calling_subaddr(ftdmchan, &conEvnt->cgPtySad);
@@ -757,14 +754,14 @@ void sngisdn_process_fac_ind (sngisdn_event_data_t *sngisdn_event)
 			{
 				ftdm_sigmsg_t sigev;
 				if (facEvnt->facElmt.facStr.pres) {
-					get_facility_ie_str(ftdmchan, &facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len);
+					get_facility_ie_str(ftdmchan, &facEvnt->facElmt.facStr.val[2], facEvnt->facElmt.facStr.len-2);
 				}
 				memset(&sigev, 0, sizeof(sigev));
 				sigev.chan_id = ftdmchan->chan_id;
 				sigev.span_id = ftdmchan->span_id;
 				sigev.channel = ftdmchan;
 				
-				sigev.event_id = FTDM_SIGEVENT_MSG;
+				sigev.event_id = FTDM_SIGEVENT_FACILITY;
 				ftdm_span_send_signal(ftdmchan->span, &sigev);
 			}
 			break;
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
index 38bbdb6968..297c59c3b7 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_out.c
@@ -128,6 +128,7 @@ void sngisdn_snd_setup(ftdm_channel_t *ftdmchan)
 
 	set_called_num(ftdmchan, &conEvnt.cdPtyNmb);
 	set_calling_num(ftdmchan, &conEvnt.cgPtyNmb);
+	set_calling_num2(ftdmchan, &conEvnt.cgPtyNmb2);
 	set_calling_subaddr(ftdmchan, &conEvnt.cgPtySad);
 	set_redir_num(ftdmchan, &conEvnt.redirNmb);
 	set_calling_name(ftdmchan, &conEvnt);
@@ -262,10 +263,9 @@ void sngisdn_snd_con_complete(ftdm_channel_t *ftdmchan)
 }
 
 
-void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan)
+void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind)
 {
 	CnStEvnt cnStEvnt;
-	
 	sngisdn_chan_data_t *sngisdn_info = (sngisdn_chan_data_t*) ftdmchan->call_data;
 	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
 
@@ -310,7 +310,9 @@ void sngisdn_snd_proceed(ftdm_channel_t *ftdmchan)
 		cnStEvnt.chanId.chanNmbSlotMap.val[0] = ftdmchan->physical_chan_id;
 	}
 
+	set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
 	set_facility_ie(ftdmchan, &cnStEvnt.facilityStr);
+	ftdm_call_clear_data(&ftdmchan->caller_data);
 
 	ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROCEED (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
 
@@ -343,6 +345,7 @@ void sngisdn_snd_progress(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_
 	memset(&cnStEvnt, 0, sizeof(cnStEvnt));	
 	set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
 	set_facility_ie(ftdmchan, &cnStEvnt.facilityStr);
+	ftdm_call_clear_data(&ftdmchan->caller_data);
 
 	ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending PROGRESS (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
 	if(sng_isdn_con_status(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId,&cnStEvnt, MI_PROGRESS, signal_data->dchan_id, sngisdn_info->ces)) {
@@ -369,6 +372,7 @@ void sngisdn_snd_alert(ftdm_channel_t *ftdmchan, ftdm_sngisdn_progind_t prog_ind
 
 	set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
 	set_facility_ie(ftdmchan, &cnStEvnt.facilityStr);
+	ftdm_call_clear_data(&ftdmchan->caller_data);
 
 	ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending ALERT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
 
@@ -428,6 +432,7 @@ void sngisdn_snd_connect(ftdm_channel_t *ftdmchan)
 
 	set_prog_ind_ie(ftdmchan, &cnStEvnt.progInd, prog_ind);
 	set_facility_ie(ftdmchan, &cnStEvnt.facilityStr);
+	ftdm_call_clear_data(&ftdmchan->caller_data);
 
 	ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending CONNECT (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
 	if (sng_isdn_con_response(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &cnStEvnt, signal_data->dchan_id, sngisdn_info->ces)) {
@@ -450,10 +455,17 @@ void sngisdn_snd_fac_req(ftdm_channel_t *ftdmchan)
 		
 	memset(&facEvnt, 0, sizeof(facEvnt));
 	
-	set_facility_ie_str(ftdmchan, &facEvnt.facElmt.facStr.val[2], (ftdm_size_t*)&facEvnt.facElmt.facStr.len);
+	if (set_facility_ie_str(ftdmchan, &facEvnt.facElmt.facStr.val[2], (uint8_t*)&facEvnt.facElmt.facStr.len) != FTDM_SUCCESS) {
+		/* No point in sending a FACILITY message if there is no Facility IE to transmit */
+		return;
+	}
+	ftdm_call_clear_data(&ftdmchan->caller_data);
 	
+	facEvnt.facElmt.eh.pres = PRSNT_NODEF;
+	facEvnt.facElmt.facStr.pres = PRSNT_NODEF;
 	facEvnt.facElmt.facStr.val[0] = 0x1C;
-	facEvnt.facElmt.facStr.val[1] = facEvnt.facElmt.facStr.len;
+	facEvnt.facElmt.facStr.val[1] = (uint8_t)facEvnt.facElmt.facStr.len;
+	facEvnt.facElmt.facStr.len +=2; /* Need to include the size of identifier + len */
 	
 	ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending FACILITY (suId:%d suInstId:%u spInstId:%u dchan:%d ces:%d)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
 
@@ -481,6 +493,8 @@ void sngisdn_snd_info_req(ftdm_channel_t *ftdmchan)
 	//ftdm_log_chan_msg(ftdmchan, FTDM_LOG_INFO, "Sending INFO REQ\n");
 
 
+	ftdm_call_clear_data(&ftdmchan->caller_data);
+	
 	ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending INFO REQ (suId:%d dchan:%d ces:%d)\n", signal_data->cc_id, signal_data->dchan_id, sngisdn_info->ces);
 
 	if (sng_isdn_con_status(signal_data->cc_id, 0, 0, &cnStEvnt, MI_INFO, signal_data->dchan_id, sngisdn_info->ces)) {
@@ -501,6 +515,8 @@ void sngisdn_snd_status_enq(ftdm_channel_t *ftdmchan)
 
 	memset(&staEvnt, 0, sizeof(StaEvnt));
 
+	ftdm_call_clear_data(&ftdmchan->caller_data);
+	
 	ftdm_log_chan(ftdmchan, FTDM_LOG_DEBUG, "Sending Status ENQ on suId:%d suInstId:%u spInstId:%d dchan:%d ces:%d\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, signal_data->dchan_id, sngisdn_info->ces);
 	if (sng_isdn_status_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &staEvnt, MI_STATENQ)) {
 		ftdm_log_chan_msg(ftdmchan, FTDM_LOG_CRIT, 	"stack refused Status ENQ request\n");
@@ -539,6 +555,7 @@ void sngisdn_snd_disconnect(ftdm_channel_t *ftdmchan)
 	discEvnt.causeDgn[0].dgnVal.pres = NOTPRSNT;
 
 	set_facility_ie(ftdmchan, &discEvnt.facilityStr);
+	ftdm_call_clear_data(&ftdmchan->caller_data);
 
 	ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending DISCONNECT (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId);
 	if (sng_isdn_disc_request(signal_data->cc_id, sngisdn_info->suInstId, sngisdn_info->spInstId, &discEvnt)) {
@@ -585,6 +602,7 @@ void sngisdn_snd_release(ftdm_channel_t *ftdmchan, uint8_t glare)
 	}
 
 	set_facility_ie(ftdmchan, &relEvnt.facilityStr);
+	ftdm_call_clear_data(&ftdmchan->caller_data);
 	
 	ftdm_log_chan(ftdmchan, FTDM_LOG_INFO, "Sending RELEASE/RELEASE COMPLETE (suId:%d suInstId:%u spInstId:%u)\n", signal_data->cc_id, suInstId, spInstId);
 
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
index fae25c9ad6..76d11d6d34 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_support.c
@@ -185,6 +185,39 @@ ftdm_status_t get_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
 	return FTDM_SUCCESS;
 }
 
+ftdm_status_t get_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
+{
+	ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
+	if (cgPtyNmb->eh.pres != PRSNT_NODEF) {
+		return FTDM_FAIL;
+	}
+
+	if (cgPtyNmb->screenInd.pres == PRSNT_NODEF) {
+		ftdm_call_add_var(caller_data, "isdn.cg_pty2.screen_ind", ftdm_screening2str(cgPtyNmb->screenInd.val));
+	}
+
+	if (cgPtyNmb->presInd0.pres == PRSNT_NODEF) {
+		ftdm_call_add_var(caller_data, "isdn.cg_pty2.presentation_ind", ftdm_presentation2str(cgPtyNmb->presInd0.val));
+	}
+
+	if (cgPtyNmb->nmbPlanId.pres == PRSNT_NODEF) {
+		ftdm_call_add_var(caller_data, "isdn.cg_pty2.npi", ftdm_npi2str(cgPtyNmb->nmbPlanId.val));
+	}
+		
+	if (cgPtyNmb->typeNmb1.pres == PRSNT_NODEF) {
+		ftdm_call_add_var(caller_data, "isdn.cg_pty2.ton", ftdm_ton2str(cgPtyNmb->typeNmb1.val));
+	}
+	
+	if (cgPtyNmb->nmbDigits.pres == PRSNT_NODEF) {
+		char digits_string [32];
+		memcpy(digits_string, (const char*)cgPtyNmb->nmbDigits.val, cgPtyNmb->nmbDigits.len);
+		digits_string[cgPtyNmb->nmbDigits.len] = '\0';
+		ftdm_call_add_var(caller_data, "isdn.cg_pty2.digits", digits_string);
+	}
+	memcpy(&caller_data->ani, &caller_data->cid_num, sizeof(caller_data->ani));
+	return FTDM_SUCCESS;
+}
+
 ftdm_status_t get_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb)
 {
 	ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
@@ -278,7 +311,7 @@ ftdm_status_t get_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad)
 		
 	memcpy(subaddress, (char*)cgPtySad->sadInfo.val, cgPtySad->sadInfo.len);
 	subaddress[cgPtySad->sadInfo.len] = '\0';
-	ftdm_channel_add_var(ftdmchan, "isdn.calling_subaddr", subaddress);
+	ftdm_call_add_var(&ftdmchan->caller_data, "isdn.calling_subaddr", subaddress);
 	return FTDM_SUCCESS;
 }
 
@@ -291,17 +324,16 @@ ftdm_status_t get_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr
 	return get_facility_ie_str(ftdmchan, facilityStr->facilityStr.val, facilityStr->facilityStr.len);
 }
 
-ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t data_len)
+ftdm_status_t get_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t data_len)
 {
 	ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
 	sngisdn_span_data_t *signal_data = (sngisdn_span_data_t*) ftdmchan->span->signal_data;
 	
 	if (signal_data->facility_ie_decode == SNGISDN_OPT_FALSE) {
-		if (data_len > sizeof(caller_data->raw_data)-2) {
-			ftdm_log(FTDM_LOG_CRIT, "Length of Facility IE exceeds maximum length\n");
-			return FTDM_FAIL;
-		}
-
+		/* size of facilityStr->facilityStr.len is a uint8_t so no need to check
+		for overflow here as facilityStr->facilityStr.len will always be smaller
+		than sizeof(caller_data->raw_data) */
+		
 		memset(caller_data->raw_data, 0, sizeof(caller_data->raw_data));
 		/* Always include Facility IE identifier + len so this can be used as a sanity check by the user */
 		caller_data->raw_data[0] = SNGISDN_Q931_FACILITY_IE_ID;
@@ -348,7 +380,7 @@ ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd)
 				val = SNGISDN_PROGIND_DESCR_INVALID;
 				break;
 		}
-		ftdm_channel_add_var(ftdmchan, "isdn.prog_ind.descr", ftdm_sngisdn_progind_descr2str(val));
+		ftdm_call_add_var(&ftdmchan->caller_data, "isdn.prog_ind.descr", ftdm_sngisdn_progind_descr2str(val));
 	}
 	
 	if (progInd->location.pres) {
@@ -379,7 +411,7 @@ ftdm_status_t get_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd)
 				val = SNGISDN_PROGIND_LOC_INVALID;
 				break;
 		}
-		ftdm_channel_add_var(ftdmchan, "isdn.prog_ind.loc", ftdm_sngisdn_progind_loc2str(val));
+		ftdm_call_add_var(&ftdmchan->caller_data, "isdn.prog_ind.loc", ftdm_sngisdn_progind_loc2str(val));
 	}	
 	return FTDM_SUCCESS;
 }
@@ -423,6 +455,89 @@ ftdm_status_t set_calling_num(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
 	return FTDM_SUCCESS;
 }
 
+ftdm_status_t set_calling_num2(ftdm_channel_t *ftdmchan, CgPtyNmb *cgPtyNmb)
+{
+	const char* string = NULL;
+	uint8_t len,val;
+	ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
+	
+	string = ftdm_call_get_var(caller_data, "isdn.cg_pty2.digits");
+	if ((string == NULL) || !(*string)) {
+		return FTDM_FAIL;
+	}
+
+	cgPtyNmb->eh.pres			= PRSNT_NODEF;
+	
+	len = strlen(string);
+	cgPtyNmb->nmbDigits.len		= len;
+
+	cgPtyNmb->nmbDigits.pres	= PRSNT_NODEF;
+	memcpy(cgPtyNmb->nmbDigits.val, string, len);
+
+	/* Screening Indicator */
+	cgPtyNmb->screenInd.pres	= PRSNT_NODEF;
+
+	val = FTDM_SCREENING_INVALID;
+	string = ftdm_call_get_var(caller_data, "isdn.cg_pty2.screening_ind");
+	if ((string != NULL) && (*string)) {
+		val = ftdm_str2ftdm_screening(string);
+	}
+
+	/* isdn.cg_pty2.screen_ind does not exist or we could not parse its value */
+	if (val == FTDM_SCREENING_INVALID) {		
+		/* default to caller data screening ind */
+		cgPtyNmb->screenInd.val = caller_data->screen;
+	} else {
+		cgPtyNmb->screenInd.val = val;
+	}
+
+	/* Presentation Indicator */
+	cgPtyNmb->presInd0.pres = PRSNT_NODEF;
+	
+	val = FTDM_PRES_INVALID;
+	string = ftdm_call_get_var(caller_data, "isdn.cg_pty2.presentation_ind");
+	if ((string != NULL) && (*string)) {
+		val = ftdm_str2ftdm_presentation(string);
+	}
+
+	if (val == FTDM_PRES_INVALID) {
+		cgPtyNmb->presInd0.val = caller_data->pres;
+	} else {
+		cgPtyNmb->presInd0.val = val;
+	}
+
+	/* Numbering Plan Indicator */
+	cgPtyNmb->nmbPlanId.pres	= PRSNT_NODEF;
+	
+	val = FTDM_NPI_INVALID;
+	string = ftdm_call_get_var(caller_data, "isdn.cg_pty2.npi");
+	if ((string != NULL) && (*string)) {
+		val = ftdm_str2ftdm_npi(string);
+	}
+
+	if (val == FTDM_NPI_INVALID) {
+		cgPtyNmb->nmbPlanId.val = caller_data->cid_num.plan;
+	} else {
+		cgPtyNmb->nmbPlanId.val	= val;
+	}
+
+	cgPtyNmb->typeNmb1.pres		= PRSNT_NODEF;
+
+	/* Type of Number */
+	val = FTDM_TON_INVALID;
+	string = ftdm_call_get_var(caller_data, "isdn.cg_pty2.ton");
+	if ((string != NULL) && (*string)) {
+		val = ftdm_str2ftdm_ton(string);
+	}
+
+	if (val == FTDM_TON_INVALID) {
+		cgPtyNmb->typeNmb1.val = caller_data->cid_num.type;
+	} else {
+		cgPtyNmb->typeNmb1.val = val;
+	}
+	return FTDM_SUCCESS;
+}
+
 ftdm_status_t set_called_num(ftdm_channel_t *ftdmchan, CdPtyNmb *cdPtyNmb)
 {
 	ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
@@ -544,7 +659,7 @@ ftdm_status_t set_calling_name(ftdm_channel_t *ftdmchan, ConEvnt *conEvnt)
 ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad)
 {
 	const char* clg_subaddr = NULL;
-	clg_subaddr = ftdm_channel_get_var(ftdmchan, "isdn.calling_subaddr");
+	clg_subaddr = ftdm_call_get_var(&ftdmchan->caller_data, "isdn.calling_subaddr");
 	if ((clg_subaddr != NULL) && (*clg_subaddr)) {
 		unsigned len = strlen (clg_subaddr);
 		cgPtySad->eh.pres = PRSNT_NODEF;
@@ -565,7 +680,7 @@ ftdm_status_t set_calling_subaddr(ftdm_channel_t *ftdmchan, CgPtySad *cgPtySad)
 ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr)
 {
 	ftdm_status_t status;
-	status = set_facility_ie_str(ftdmchan, facilityStr->facilityStr.val, (ftdm_size_t*)&facilityStr->facilityStr.len);
+	status = set_facility_ie_str(ftdmchan, facilityStr->facilityStr.val, (uint8_t*)&(facilityStr->facilityStr.len));
 	if (status == FTDM_SUCCESS) {
 		facilityStr->eh.pres = PRSNT_NODEF;
 		facilityStr->facilityStr.pres = PRSNT_NODEF;
@@ -573,13 +688,15 @@ ftdm_status_t set_facility_ie(ftdm_channel_t *ftdmchan, FacilityStr *facilityStr
 	return status;
 }
 
-ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, ftdm_size_t *data_len)
+ftdm_status_t set_facility_ie_str(ftdm_channel_t *ftdmchan, uint8_t *data, uint8_t *data_len)
 {
+	int len;
 	ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
 
 	if (caller_data->raw_data_len > 0 && caller_data->raw_data[0] == SNGISDN_Q931_FACILITY_IE_ID) {
-		*data_len = caller_data->raw_data[1];
-		memcpy(data, &caller_data->raw_data[2], *data_len);
+		len = caller_data->raw_data[1];
+		memcpy(data, &caller_data->raw_data[2], len);
+		*data_len = len;
 		return FTDM_SUCCESS;
 	}	
 	return FTDM_FAIL;
@@ -591,7 +708,7 @@ ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_s
 	int descr = prog_ind.descr;
 	int loc = prog_ind.loc;
 	
-	str = ftdm_channel_get_var(ftdmchan, "isdn.prog_ind.descr");	
+	str = ftdm_call_get_var(&ftdmchan->caller_data, "isdn.prog_ind.descr");
 	if (str && *str) {
 		/* User wants to override progress indicator */
 		descr = ftdm_str2ftdm_sngisdn_progind_descr(str);
@@ -602,8 +719,8 @@ ftdm_status_t set_prog_ind_ie(ftdm_channel_t *ftdmchan, ProgInd *progInd, ftdm_s
 		return FTDM_SUCCESS;
 	}
 
-	str = ftdm_channel_get_var(ftdmchan, "isdn.prog_ind.loc");
-	if (str && *str) {		
+	str = ftdm_call_get_var(&ftdmchan->caller_data, "isdn.prog_ind.loc");
+	if (str && *str) {
 		loc = ftdm_str2ftdm_sngisdn_progind_loc(str);
 	}
 	if (loc == SNGISDN_PROGIND_LOC_INVALID) {
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c
index 72e4bacf52..7517ee42a0 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_handle.c
@@ -211,10 +211,10 @@ ftdm_status_t handle_con_ind(uint32_t suInstId, uint32_t spInstId, uint32_t circ
 
 			/* add any special variables for the dialplan */
 			sprintf(nadi, "%d", siConEvnt->cgPtyNum.natAddrInd.val);
-			ftdm_channel_add_var(ftdmchan, "ss7_clg_nadi", nadi);
+			ftdm_call_add_var(&ftdmchan->caller_data, "ss7_clg_nadi", nadi);
 
 			sprintf(nadi, "%d", siConEvnt->cdPtyNum.natAddrInd.val);
-			ftdm_channel_add_var(ftdmchan, "ss7_cld_nadi", nadi);
+			ftdm_call_add_var(&ftdmchan->caller_data, "ss7_cld_nadi", nadi);
 
 
 			/* check if a COT test is requested */
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c
index 008265b9a4..ec8d7df12a 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c
@@ -187,7 +187,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 	copy_cgPtyNum_to_sngss7 (&ftdmchan->caller_data, &iam.cgPtyNum);
 
 	/* check if the user would like a custom NADI value for the calling Pty Num */
-	clg_nadi = ftdm_channel_get_var(ftdmchan, "ss7_clg_nadi");
+	clg_nadi = ftdm_call_get_var(&ftdmchan->caller_data, "ss7_clg_nadi");
 	if ((clg_nadi != NULL) && (*clg_nadi)) {
 		SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Calling NADI value \"%s\"\n", clg_nadi);
 		iam.cgPtyNum.natAddrInd.val	= atoi(clg_nadi);
@@ -196,7 +196,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 		SS7_DEBUG_CHAN(ftdmchan,"No user supplied NADI value found for CLG, using \"%d\"\n", iam.cgPtyNum.natAddrInd.val);
 	}
 
-	cld_nadi = ftdm_channel_get_var(ftdmchan, "ss7_cld_nadi");
+	cld_nadi = ftdm_call_get_var(&ftdmchan->caller_data, "ss7_cld_nadi");
 	if ((cld_nadi != NULL) && (*cld_nadi)) {
 		SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Called NADI value \"%s\"\n", cld_nadi);
 		iam.cdPtyNum.natAddrInd.val	= atoi(cld_nadi);
@@ -206,7 +206,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 	}
 
 	/* check if the user would like us to send a clg_sub-address */
-	clg_subAddr = ftdm_channel_get_var(ftdmchan, "ss7_clg_subaddr");
+	clg_subAddr = ftdm_call_get_var(&ftdmchan->caller_data, "ss7_clg_subaddr");
 	if ((clg_subAddr != NULL) && (*clg_subAddr)) {
 		SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Calling Sub-Address value \"%s\"\n", clg_subAddr);
 		
@@ -245,7 +245,7 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 	}
 
 	/* check if the user would like us to send a cld_sub-address */
-	cld_subAddr = ftdm_channel_get_var(ftdmchan, "ss7_cld_subaddr");
+	cld_subAddr = ftdm_call_get_var(&ftdmchan->caller_data, "ss7_cld_subaddr");
 	if ((cld_subAddr != NULL) && (*cld_subAddr)) {
 		SS7_DEBUG_CHAN(ftdmchan,"Found user supplied Called Sub-Address value \"%s\"\n", cld_subAddr);
 		
@@ -298,7 +298,8 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 							iam.cgPtyNum.natAddrInd.val,
 							ftdmchan->caller_data.dnis.digits,
 							iam.cdPtyNum.natAddrInd.val);
-	
+
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -379,7 +380,7 @@ void ft_to_sngss7_acm (ftdm_channel_t * ftdmchan)
 						ADDRCMPLT);
 	
 	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx ACM\n", sngss7_info->circuit->cic);
-	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -403,7 +404,7 @@ void ft_to_sngss7_anm (ftdm_channel_t * ftdmchan)
 						5);
 
   SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx ANM\n", sngss7_info->circuit->cic);
-
+  ftdm_call_clear_vars(&ftdmchan->caller_data);
   SS7_FUNC_TRACE_EXIT (__FUNCTION__);
   return;
 }
@@ -438,7 +439,7 @@ void ft_to_sngss7_rel (ftdm_channel_t * ftdmchan)
 	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx REL cause=%d \n",
 							sngss7_info->circuit->cic,
 							ftdmchan->caller_data.hangup_cause );
-	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -461,7 +462,7 @@ void ft_to_sngss7_rlc (ftdm_channel_t * ftdmchan)
 						&rlc);
 	
 	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx RLC\n", sngss7_info->circuit->cic);
-	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -482,7 +483,7 @@ void ft_to_sngss7_rsc (ftdm_channel_t * ftdmchan)
 						NULL);
 	
 	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx RSC\n", sngss7_info->circuit->cic);
-	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -503,7 +504,7 @@ void ft_to_sngss7_rsca (ftdm_channel_t * ftdmchan)
 						NULL);
 	
 	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx RSC-RLC\n", sngss7_info->circuit->cic);
-	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
   return;
 }
@@ -524,7 +525,7 @@ void ft_to_sngss7_blo (ftdm_channel_t * ftdmchan)
 						NULL);
 	
 	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx BLO\n", sngss7_info->circuit->cic);
-	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -545,7 +546,7 @@ void ft_to_sngss7_bla (ftdm_channel_t * ftdmchan)
 						NULL);
 	
 	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx BLA\n", sngss7_info->circuit->cic);
-	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -567,7 +568,7 @@ ft_to_sngss7_ubl (ftdm_channel_t * ftdmchan)
 						NULL);
 	
 	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx UBL\n", sngss7_info->circuit->cic);
-	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -588,7 +589,7 @@ void ft_to_sngss7_uba (ftdm_channel_t * ftdmchan)
 						NULL);
 	
 	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx UBA\n", sngss7_info->circuit->cic);
-	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -609,7 +610,7 @@ void ft_to_sngss7_lpa (ftdm_channel_t * ftdmchan)
 						NULL);
 	
 	SS7_INFO_CHAN(ftdmchan,"[CIC:%d]Tx LPA\n", sngss7_info->circuit->cic);
-	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 return;
 }
@@ -654,6 +655,7 @@ void ft_to_sngss7_gra (ftdm_channel_t * ftdmchan)
 							sngss7_info->circuit->cic,
 							(sngss7_info->circuit->cic + sngss7_span->rx_grs.range));
 	
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -686,7 +688,8 @@ void ft_to_sngss7_grs (ftdm_channel_t * ftdmchan)
 							sngss7_info->circuit->cic,
 							sngss7_info->circuit->cic,
 							(sngss7_info->circuit->cic + sngss7_span->tx_grs.range));
-	
+
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 return;
 }
@@ -735,7 +738,7 @@ void ft_to_sngss7_cgba(ftdm_channel_t * ftdmchan)
 
 	/* clean out the saved data */
 	memset(&sngss7_span->rx_cgb, 0x0, sizeof(sngss7_group_data_t));
-
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -785,6 +788,7 @@ void ft_to_sngss7_cgua(ftdm_channel_t * ftdmchan)
 	/* clean out the saved data */
 	memset(&sngss7_span->rx_cgu, 0x0, sizeof(sngss7_group_data_t));
 
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -835,6 +839,7 @@ void ft_to_sngss7_cgb(ftdm_channel_t * ftdmchan)
 	/* clean out the saved data */
 	memset(&sngss7_span->tx_cgb, 0x0, sizeof(sngss7_group_data_t));
 
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
@@ -885,6 +890,7 @@ void ft_to_sngss7_cgu(ftdm_channel_t * ftdmchan)
 	/* clean out the saved data */
 	memset(&sngss7_span->tx_cgu, 0x0, sizeof(sngss7_group_data_t));
 
+	ftdm_call_clear_vars(&ftdmchan->caller_data);
 	SS7_FUNC_TRACE_EXIT (__FUNCTION__);
 	return;
 }
diff --git a/libs/freetdm/src/include/freetdm.h b/libs/freetdm/src/include/freetdm.h
index 41e7f50ed8..4ee6ff5f52 100644
--- a/libs/freetdm/src/include/freetdm.h
+++ b/libs/freetdm/src/include/freetdm.h
@@ -272,6 +272,8 @@ typedef struct {
 	uint8_t plan;
 } ftdm_number_t;
 
+typedef void * ftdm_variable_container_t; 
+									 
 /*! \brief Caller information */
 typedef struct ftdm_caller_data {
 	char cid_date[8]; /*!< Caller ID date */
@@ -286,12 +288,13 @@ typedef struct ftdm_caller_data {
 	char collected[25]; /*!< Collected digits so far */
 	int hangup_cause; /*!< Hangup cause */
 	char raw_data[1024]; /*!< Protocol specific raw caller data */
-	uint32_t raw_data_len; /* !< Raw data length */
+	uint32_t raw_data_len; /*!< Raw data length */
 	/* these 2 are undocumented right now, only used by boost: */
 	/* bearer capability */
 	ftdm_bearer_cap_t bearer_capability;
 	/* user information layer 1 protocol */
 	ftdm_user_layer1_prot_t bearer_layer1;
+	ftdm_variable_container_t variables; /*!<variables attached to this call */
 } ftdm_caller_data_t;
 
 /*! \brief Tone type */
@@ -316,7 +319,7 @@ typedef enum {
 	FTDM_SIGEVENT_RESTART, /*!< Restart has been requested. Typically you hangup your call resources here */
 	FTDM_SIGEVENT_SIGSTATUS_CHANGED, /*!< Signaling protocol status changed (ie: D-chan up), see new status in raw_data ftdm_sigmsg_t member */
 	FTDM_SIGEVENT_COLLISION, /*!< Outgoing call was dropped because an incoming call arrived at the same time */
-	FTDM_SIGEVENT_MSG, /*!< We received an in-call msg */
+	FTDM_SIGEVENT_FACILITY, /* !< In call facility event */
 	FTDM_SIGEVENT_INVALID
 } ftdm_signal_event_t;
 #define SIGNAL_STRINGS "START", "STOP", "RELEASED", "UP", "FLASH", "PROCEED", "PROGRESS", \
@@ -378,7 +381,7 @@ struct ftdm_sigmsg {
 	ftdm_channel_t *channel; /*!< Related channel */
 	uint32_t chan_id; /*!< easy access to chan id */
 	uint32_t span_id; /*!< easy access to span_id */
-	ftdm_signaling_status_t sigstatus; /*!< Signaling status (valid if event_id is FTDM_SIGEVENT_SIGSTATUS_CHANGED) */
+	ftdm_signaling_status_t sigstatus; /*!< Signaling status (valid if event_id is FTDM_SIGEVENT_SIGSTATUS_CHANGED) */	
 	void *raw_data; /*!< Message specific data if any */
 	uint32_t raw_data_len; /*!< Data len in case is needed */
 };
@@ -507,6 +510,7 @@ struct ftdm_memory_handler {
  * You don't need these unless your implementing an I/O interface module (most users don't) */
 #define FIO_CHANNEL_REQUEST_ARGS (ftdm_span_t *span, uint32_t chan_id, ftdm_direction_t direction, ftdm_caller_data_t *caller_data, ftdm_channel_t **ftdmchan)
 #define FIO_CHANNEL_OUTGOING_CALL_ARGS (ftdm_channel_t *ftdmchan)
+#define FIO_CHANNEL_SEND_MSG_ARGS (ftdm_channel_t *ftdmchan, ftdm_sigmsg_t *sigmsg)
 #define FIO_CHANNEL_SET_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t status)
 #define FIO_CHANNEL_GET_SIG_STATUS_ARGS (ftdm_channel_t *ftdmchan, ftdm_signaling_status_t *status)
 #define FIO_SPAN_SET_SIG_STATUS_ARGS (ftdm_span_t *span, ftdm_signaling_status_t status)
@@ -539,6 +543,7 @@ struct ftdm_memory_handler {
  * You don't need these unless your implementing an I/O interface module (most users don't) */
 typedef ftdm_status_t (*fio_channel_request_t) FIO_CHANNEL_REQUEST_ARGS ;
 typedef ftdm_status_t (*fio_channel_outgoing_call_t) FIO_CHANNEL_OUTGOING_CALL_ARGS ;
+typedef ftdm_status_t (*fio_channel_send_msg_t) FIO_CHANNEL_SEND_MSG_ARGS;
 typedef ftdm_status_t (*fio_channel_set_sig_status_t) FIO_CHANNEL_SET_SIG_STATUS_ARGS;
 typedef ftdm_status_t (*fio_channel_get_sig_status_t) FIO_CHANNEL_GET_SIG_STATUS_ARGS;
 typedef ftdm_status_t (*fio_span_set_sig_status_t) FIO_SPAN_SET_SIG_STATUS_ARGS;
@@ -572,6 +577,7 @@ typedef ftdm_status_t (*fio_api_t) FIO_API_ARGS ;
  * You don't need these unless your implementing an I/O interface module (most users don't) */
 #define FIO_CHANNEL_REQUEST_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_REQUEST_ARGS
 #define FIO_CHANNEL_OUTGOING_CALL_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_OUTGOING_CALL_ARGS
+#define FIO_CHANNEL_SEND_MSG_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_SEND_MSG_ARGS
 #define FIO_CHANNEL_SET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_SET_SIG_STATUS_ARGS
 #define FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_CHANNEL_GET_SIG_STATUS_ARGS
 #define FIO_SPAN_SET_SIG_STATUS_FUNCTION(name) ftdm_status_t name FIO_SPAN_SET_SIG_STATUS_ARGS
@@ -672,6 +678,12 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_place(const char *file, const char
 /*! \brief Indicate a new condition in an incoming call recording the source code point where it was called (see ftdm_channel_call_indicate for an easy to use macro) */
 FT_DECLARE(ftdm_status_t) _ftdm_channel_call_indicate(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_channel_indication_t indication);
 
+/*! \brief Send a message on a call */
+#define ftdm_channel_call_send_msg(ftdmchan, sigmsg) _ftdm_channel_call_send_msg(__FILE__, __FUNCTION__, __LINE__, (ftdmchan), (sigmsg))
+
+/*! \brief Send a signal on a call recording the source code point where it was called (see ftdm_channel_call_send_msg for an easy to use macro) */
+FT_DECLARE(ftdm_status_t) _ftdm_channel_call_send_msg(const char *file, const char *func, int line, ftdm_channel_t *ftdmchan, ftdm_sigmsg_t *sigmsg);
+
 /*! \brief Hangup the call without cause */
 #define ftdm_channel_call_hangup(ftdmchan) _ftdm_channel_call_hangup(__FILE__, __FUNCTION__, __LINE__, (ftdmchan))
 
@@ -1128,6 +1140,45 @@ FT_DECLARE(ftdm_iterator_t *) ftdm_iterator_next(ftdm_iterator_t *iter);
  */
 FT_DECLARE(ftdm_status_t) ftdm_iterator_free(ftdm_iterator_t *iter);
 
+/*! \brief Add a custom variable to the call
+ *  \note This variables may be used by signaling modules to override signaling parameters
+ *  \todo Document which signaling variables are available
+ * */
+FT_DECLARE(ftdm_status_t) ftdm_call_add_var(ftdm_caller_data_t *caller_data, const char *var_name, const char *value);
+
+/*! \brief Get a custom variable from the call.
+ *  \note The variable pointer returned is only valid during the callback receiving SIGEVENT. */
+FT_DECLARE(const char *) ftdm_call_get_var(ftdm_caller_data_t *caller_data, const char *var_name);
+
+/*! \brief Get an iterator to iterate over the channel variables
+ *  \param caller_data The signal msg structure containing the variables
+ *  \param iter Optional iterator. You can reuse an old iterator (not previously freed) to avoid the extra allocation of a new iterator.
+ *  \note The iterator pointer returned is only valid while the signal message and it'll be destroyed when the signal message is processed.
+ *        This iterator is completely non-thread safe, if you are adding variables or removing variables while iterating
+ *        results are unpredictable
+ */
+FT_DECLARE(ftdm_iterator_t *) ftdm_call_get_var_iterator(const ftdm_caller_data_t *caller_data, ftdm_iterator_t *iter);
+
+/*! \brief Get variable name and value for the current iterator position */
+FT_DECLARE(ftdm_status_t) ftdm_call_get_current_var(ftdm_iterator_t *iter, const char **var_name, const char **var_val);
+
+/*! \brief Clear all variables  attached to the call
+ *  \note Variables are cleared at the end of each call back, so it is not necessary for the user to call this function.
+ *  \todo Document which signaling variables are available
+ * */
+FT_DECLARE(ftdm_status_t) ftdm_call_clear_vars(ftdm_caller_data_t *caller_data);
+
+/*! \brief Remove a variable attached to the call
+ *  \note Removes a variable that was attached to the call.
+ *  \todo Document which call variables are available
+ * */
+FT_DECLARE(ftdm_status_t) ftdm_call_remove_var(ftdm_caller_data_t *caller_data, const char *var_name);
+
+/*! \brief Clears all the temporary data attached to this call
+ *  \note Clears caller_data->variables and caller_data->raw_data.
+ * */
+FT_DECLARE(void) ftdm_call_clear_data(ftdm_caller_data_t *caller_data);
+		
 /*! \brief Get the span pointer associated to the channel */
 FT_DECLARE(ftdm_span_t *) ftdm_channel_get_span(const ftdm_channel_t *ftdmchan);
 
diff --git a/libs/freetdm/src/include/private/ftdm_core.h b/libs/freetdm/src/include/private/ftdm_core.h
index a1e1c02439..deabafd537 100644
--- a/libs/freetdm/src/include/private/ftdm_core.h
+++ b/libs/freetdm/src/include/private/ftdm_core.h
@@ -503,6 +503,7 @@ struct ftdm_span {
 	teletone_multi_tone_t tone_finder[FTDM_TONEMAP_INVALID+1];
 	ftdm_channel_t *channels[FTDM_MAX_CHANNELS_SPAN+1];
 	fio_channel_outgoing_call_t outgoing_call;
+	fio_channel_send_msg_t send_msg;
 	fio_channel_set_sig_status_t set_channel_sig_status;
 	fio_channel_get_sig_status_t get_channel_sig_status;
 	fio_span_set_sig_status_t set_span_sig_status;

From 5ab19aaa23dac4771baadd1f2a2b874c8c630154 Mon Sep 17 00:00:00 2001
From: David Yat Sin <dyatsin@sangoma.com>
Date: Thu, 9 Dec 2010 13:47:40 -0500
Subject: [PATCH 2/4] freetdm: fix compilation

---
 libs/freetdm/src/ftdm_io.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 7355c8497c..605f13c0bc 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -3906,7 +3906,7 @@ done:
 FT_DECLARE(void) ftdm_call_clear_data(ftdm_caller_data_t *caller_data)
 {
 	ftdm_call_clear_vars(caller_data);
-	memset(caller_data.raw_data, 0, sizeof(raw_data));
+	memset(&caller_data->raw_data, 0, sizeof(caller_data->raw_data));
 	caller_data->raw_data_len = 0;
 	return;
 }

From fced79a4933560500a5710af3c48019da700948b Mon Sep 17 00:00:00 2001
From: David Yat Sin <dyatsin@sangoma.com>
Date: Thu, 9 Dec 2010 17:13:34 -0500
Subject: [PATCH 3/4] fix not handling disconnect when in RINGING state

---
 .../ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c      | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
index cb9f6d33e1..fb65d20cab 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn_stack_hndl.c
@@ -407,6 +407,7 @@ void sngisdn_process_cnst_ind (sngisdn_event_data_t *sngisdn_event)
 					}
 					break;
 					case FTDM_CHANNEL_STATE_RING:
+					case FTDM_CHANNEL_STATE_RINGING:
 					case FTDM_CHANNEL_STATE_PROCEED:
 					case FTDM_CHANNEL_STATE_PROGRESS:
 					case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
@@ -447,6 +448,7 @@ void sngisdn_process_disc_ind (sngisdn_event_data_t *sngisdn_event)
 	ftdm_assert(!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE), "State change flag pending\n");
 	switch (ftdmchan->state) {		
 		case FTDM_CHANNEL_STATE_RING:
+		case FTDM_CHANNEL_STATE_RINGING:
 		case FTDM_CHANNEL_STATE_DIALING:
 		case FTDM_CHANNEL_STATE_PROCEED:
 		case FTDM_CHANNEL_STATE_PROGRESS:
@@ -537,6 +539,7 @@ void sngisdn_process_rel_ind (sngisdn_event_data_t *sngisdn_event)
 		case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
 		case FTDM_CHANNEL_STATE_UP:
 		case FTDM_CHANNEL_STATE_RING:
+		case FTDM_CHANNEL_STATE_RINGING:
 			/* If we previously had a glare on this channel,
 			this RELEASE could be for the previous call.  Confirm whether call_data has
 			not changed while we were waiting for ftdmchan->mutex by comparing suInstId's */
@@ -881,6 +884,7 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event)
 							break;
 						case FTDM_CHANNEL_STATE_PROCEED:
 						case FTDM_CHANNEL_STATE_PROGRESS:
+						case FTDM_CHANNEL_STATE_RINGING:
 						case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
 							ftdm_log_chan_msg(ftdmchan, FTDM_LOG_WARNING, "Remote switch expecting OVERLAP receive, but we are already PROCEEDING\n");
 							sngisdn_snd_disconnect(ftdmchan);
@@ -899,6 +903,7 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event)
 				switch (ftdmchan->state) {
 					case FTDM_CHANNEL_STATE_PROCEED:
 					case FTDM_CHANNEL_STATE_PROGRESS:
+					case FTDM_CHANNEL_STATE_RINGING:
 						/* T310 timer has expired */
 						ftdmchan->caller_data.hangup_cause = staEvnt->causeDgn[0].causeVal.val;
 						ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "T310 Timer expired, hanging up call\n");
@@ -935,6 +940,7 @@ void sngisdn_process_sta_cfm (sngisdn_event_data_t *sngisdn_event)
 				break;
 			case 9: /* Remote switch is in "Incoming call proceeding" state */
 				switch (ftdmchan->state) {
+					case FTDM_CHANNEL_STATE_RINGING:
 					case FTDM_CHANNEL_STATE_PROGRESS:
 					case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
 					case FTDM_CHANNEL_STATE_GET_CALLERID:

From 86c484c134ca46edd572c3b46c6480ac9011292b Mon Sep 17 00:00:00 2001
From: David Yat Sin <dyatsin@sangoma.com>
Date: Thu, 9 Dec 2010 18:01:31 -0500
Subject: [PATCH 4/4] freetdm: added support for skip states, used by
 sangoma_isdn module

---
 libs/freetdm/src/ftdm_io.c                    | 40 +++++++++----------
 .../ftmod_sangoma_isdn/ftmod_sangoma_isdn.c   |  1 +
 libs/freetdm/src/include/private/ftdm_types.h |  3 ++
 3 files changed, 24 insertions(+), 20 deletions(-)

diff --git a/libs/freetdm/src/ftdm_io.c b/libs/freetdm/src/ftdm_io.c
index 605f13c0bc..eaa25e3da5 100644
--- a/libs/freetdm/src/ftdm_io.c
+++ b/libs/freetdm/src/ftdm_io.c
@@ -2213,31 +2213,31 @@ FT_DECLARE(ftdm_status_t) _ftdm_channel_call_answer(const char *file, const char
 		goto done;
 	}
 
-#ifndef FREETDM_SKIP_SIG_STATES
-	/* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn 
-	 * expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP, so 
-	 * remove this only in netborder branch for now while we update the sig modules */
+	if (!ftdm_test_flag(ftdmchan->span, FTDM_SPAN_USE_SKIP_STATES)) {
+		/* We will fail RFC's if we not skip states, but some modules apart from ftmod_sangoma_isdn 
+		* expect the call to always to go PROGRESS and PROGRESS MEDIA state before going to UP, so
+		* use FTDM_SPAN_USE_SKIP_STATESfor now while we update the sig modules */
 
-	if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
-		ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
-	}
+		if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS) {
+			ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS, 1);
+		}
 
-	/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
-	if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
-		ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n");
-		goto done;
-	}
+		/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
+		if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
+			ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to PROGRESS\n");
+			goto done;
+		}
 
-	if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
-		ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
-	}
+		if (ftdmchan->state < FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
+			ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, 1);
+		}
 
-	/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
-	if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
-		ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n");
-		goto done;
+		/* set state unlocks the channel so we need to re-confirm that the channel hasn't gone to hell */
+		if (ftdmchan->state == FTDM_CHANNEL_STATE_TERMINATING) {
+			ftdm_log_chan_msg(ftdmchan, FTDM_LOG_DEBUG, "Ignoring answer because the call has moved to TERMINATING while we're moving to UP\n");
+			goto done;
+		}
 	}
-#endif
 	ftdm_channel_set_state(file, func, line, ftdmchan, FTDM_CHANNEL_STATE_UP, 1);
 
 done:
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
index 96f1a2b430..e20d3ae7e0 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_isdn/ftmod_sangoma_isdn.c
@@ -1067,6 +1067,7 @@ static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_sangoma_isdn_span_config)
 	ftdm_set_flag(span, FTDM_SPAN_USE_CHAN_QUEUE);
 	ftdm_set_flag(span, FTDM_SPAN_USE_SIGNALS_QUEUE);
 	ftdm_set_flag(span, FTDM_SPAN_USE_PROCEED_STATE);
+	ftdm_set_flag(span, FTDM_SPAN_USE_SKIP_STATES);
 
 	if (span->trunk_type == FTDM_TRUNK_BRI_PTMP ||
 		span->trunk_type == FTDM_TRUNK_BRI) {
diff --git a/libs/freetdm/src/include/private/ftdm_types.h b/libs/freetdm/src/include/private/ftdm_types.h
index df747021b2..313044abc4 100644
--- a/libs/freetdm/src/include/private/ftdm_types.h
+++ b/libs/freetdm/src/include/private/ftdm_types.h
@@ -184,6 +184,9 @@ typedef enum {
 	FTDM_SPAN_USE_SIGNALS_QUEUE = (1 << 10),
 	/* If this flag is set, channel will be moved to proceed state when calls goes to routing */
 	FTDM_SPAN_USE_PROCEED_STATE = (1 << 11),
+	/* If this flag is set, the signalling module supports jumping directly to state up, without
+		going through PROGRESS/PROGRESS_MEDIA */
+	FTDM_SPAN_USE_SKIP_STATES = (1 << 12),
 } ftdm_span_flag_t;
 
 /*! \brief Channel supported features */