From 358e9aab2211769d6e6dd190c47b13a0d909ad02 Mon Sep 17 00:00:00 2001
From: David Yat Sin <dyatsin@sangoma.com>
Date: Wed, 6 Apr 2011 17:25:29 -0400
Subject: [PATCH] chlog:FreeTDM - SS7 Support for transmitting Redirecting
 Number

---
 libs/freetdm/mod_freetdm/mod_freetdm.c        |  22 ++-
 .../ftmod_sangoma_ss7_main.h                  |  11 +-
 .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_out.c |  14 +-
 .../ftmod_sangoma_ss7_support.c               | 174 ++++++++++++++++--
 .../ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c |  17 +-
 5 files changed, 204 insertions(+), 34 deletions(-)

diff --git a/libs/freetdm/mod_freetdm/mod_freetdm.c b/libs/freetdm/mod_freetdm/mod_freetdm.c
index b8bd67fc1b..8739c4c0bf 100755
--- a/libs/freetdm/mod_freetdm/mod_freetdm.c
+++ b/libs/freetdm/mod_freetdm/mod_freetdm.c
@@ -1264,6 +1264,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
 			caller_data.ani.plan = (uint8_t)atoi(sipvar);
 		}
 
+		/* Used by ftmod_sangoma_ss7 only */
+		sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-ANI-NADI");
+		if (sipvar) {
+			ftdm_usrmsg_add_var(&usrmsg, "ss7_clg_nadi", sipvar);
+		}
+
 		sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-ANI2");
 		if (sipvar) {
 			ftdm_set_string(caller_data.aniII, sipvar);
@@ -1284,6 +1290,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
 			caller_data.dnis.plan = (uint8_t)atoi(sipvar);
 		}
 
+		/* Used by ftmod_sangoma_ss7 only */
+		sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-DNIS-NADI");
+		if (sipvar) {
+			ftdm_usrmsg_add_var(&usrmsg, "ss7_clg_nadi", sipvar);
+		}
+		
 		sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDNIS");
 		if (sipvar) {
 			ftdm_set_string(caller_data.rdnis.digits, sipvar);
@@ -1299,6 +1311,12 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
 			caller_data.rdnis.plan = (uint8_t)atoi(sipvar);
 		}
 
+		/* Used by ftmod_sangoma_ss7 only */
+		sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-RDNIS-NADI");
+		if (sipvar) {
+			ftdm_usrmsg_add_var(&usrmsg, "ss7_rdnis_nadi", sipvar);
+		}
+
 		sipvar = switch_channel_get_variable(channel, "sip_h_X-FreeTDM-Screen");
 		if (sipvar) {
 			caller_data.screen = (uint8_t)atoi(sipvar);
@@ -1308,6 +1326,8 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi
 		if (sipvar) {
 			caller_data.pres = (uint8_t)atoi(sipvar);
 		}
+
+
 	}
 
 	if (switch_test_flag(outbound_profile, SWITCH_CPF_SCREEN)) {
@@ -1568,7 +1588,7 @@ ftdm_status_t ftdm_channel_from_event(ftdm_sigmsg_t *sigmsg, switch_core_session
 		switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS", "%s", channel_caller_data->rdnis.digits);
 		switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-TON", "%d", channel_caller_data->rdnis.type);
 		switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-RDNIS-Plan", "%d", channel_caller_data->rdnis.plan);
-
+		
 		switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Screen", "%d", channel_caller_data->screen);
 		switch_channel_set_variable_printf(channel, "sip_h_X-FreeTDM-Presentation", "%d", channel_caller_data->pres);
 	}
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
index e7372ecd28..ea31a89c5b 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_main.h
@@ -316,8 +316,11 @@ typedef struct sng_isup_ckt {
 	uint32_t		typeCntrl;
 	uint32_t		ssf;
 	uint32_t		switchType;
+	
 	uint32_t		clg_nadi;
 	uint32_t		cld_nadi;
+	uint8_t			rdnis_nadi;
+			
 	uint32_t		min_digits;
 	void			*obj;
 	uint16_t		t3;
@@ -786,8 +789,12 @@ uint8_t copy_cgPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum
 uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum);
 uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum);
 uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum);
-uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven);
-uint8_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven);
+ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum);
+
+
+ftdm_status_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven);
+ftdm_status_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven);
+ftdm_status_t copy_tknStr_to_sngss7(char* str, TknStr *tknStr, TknU8 *oddEven);
 
 int check_for_state_change(ftdm_channel_t *ftdmchan);
 int check_cics_in_range(sngss7_chan_data_t *sngss7_info);
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 96446b4215..0e73c05c07 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
@@ -182,19 +182,9 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 	/* copy down the called number information */
 	copy_cdPtyNum_to_sngss7 (&ftdmchan->caller_data, &iam.cdPtyNum);
 	
-	/* copy down the calling number information */
-	
+	/* copy down the calling number information */	
 	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_usrmsg_get_var(ftdmchan->usrmsg, "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);
-	} else {
-		iam.cgPtyNum.natAddrInd.val	= g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].clg_nadi;
-		SS7_DEBUG_CHAN(ftdmchan,"No user supplied NADI value found for CLG, using \"%d\"\n", iam.cgPtyNum.natAddrInd.val);
-	}
 
 	cld_nadi = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_cld_nadi");
 	if ((cld_nadi != NULL) && (*cld_nadi)) {
@@ -244,6 +234,8 @@ void ft_to_sngss7_iam (ftdm_channel_t * ftdmchan)
 		} /* if (subAddrIE[0] != '0') */
 	}
 
+	copy_redirgNum_to_sngss7(ftdmchan, &iam.redirgNum);
+	
 	/* check if the user would like us to send a cld_sub-address */
 	cld_subAddr = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_cld_subaddr");
 	if ((cld_subAddr != NULL) && (*cld_subAddr)) {
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c
index 4513deebea..22b522409f 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_support.c
@@ -43,13 +43,6 @@ uint32_t sngss7_id;
 /******************************************************************************/
 
 /* PROTOTYPES *****************************************************************/
-uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven);
-uint8_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven);
-uint8_t copy_cgPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum);
-uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum);
-uint8_t copy_cdPtyNum_from_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum);
-uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum);
-
 int check_for_state_change(ftdm_channel_t *ftdmchan);
 int check_cics_in_range(sngss7_chan_data_t *sngss7_info);
 int check_for_reset(sngss7_chan_data_t *sngss7_info);
@@ -134,11 +127,12 @@ uint8_t copy_cgPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCgPtyNum *cgPtyNum)
 	cgPtyNum->niInd.val		 = 0x00;
 	/**************************************************************************/
 	cgPtyNum->addrSig.pres	  = PRSNT_NODEF;
-
+	
 	/* atoi will search through memory starting from the pointer it is given until
 	 * it finds the \0...since tmp is on the stack it will start going through the
 	 * possibly causing corruption.  Hard code a \0 to prevent this
 	 */
+	
 	tmp[1] = '\0';
 	k = 0;
 	j = 0;
@@ -334,8 +328,68 @@ uint8_t copy_cdPtyNum_to_sngss7(ftdm_caller_data_t *ftdm, SiCdPtyNum *cdPtyNum)
 	return 0;
 }
 
-/******************************************************************************/
-uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven)
+
+ftdm_status_t copy_redirgNum_to_sngss7(ftdm_channel_t *ftdmchan, SiRedirNum *redirgNum)
+{
+	const char* val = NULL;
+	sngss7_chan_data_t	*sngss7_info = ftdmchan->call_data;	
+	ftdm_caller_data_t *caller_data = &ftdmchan->caller_data;
+	uint8_t len = strlen(caller_data->rdnis.digits);
+	if (!len) {
+		return FTDM_SUCCESS;
+	}
+	SS7_DEBUG_CHAN(ftdmchan, "Redirecting Number %s\n", caller_data->rdnis.digits);
+	
+	redirgNum->eh.pres = PRSNT_NODEF;
+
+	/* Nature of address indicator */
+	redirgNum->natAddr.pres = PRSNT_NODEF;
+	
+	val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_nadi");
+	if (!ftdm_strlen_zero(val)) {
+		redirgNum->natAddr.val = atoi(val);
+	} else {		
+		redirgNum->natAddr.val = g_ftdm_sngss7_data.cfg.isupCkt[sngss7_info->circuit->id].rdnis_nadi;
+	}
+	SS7_DEBUG_CHAN(ftdmchan, "Redirecting Number NADI:%d\n", redirgNum->natAddr.val);
+
+	/* Screening indicator */
+	redirgNum->scrInd.pres = PRSNT_NODEF;
+	val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_screen_ind");
+	if (!ftdm_strlen_zero(val)) {
+		redirgNum->scrInd.val = atoi(val);
+	} else {
+		redirgNum->scrInd.val = FTDM_SCREENING_VERIFIED_PASSED;
+	}
+	SS7_DEBUG_CHAN(ftdmchan, "Redirecting Number Screening Ind:%d\n", redirgNum->scrInd.val);
+	
+	/* Address presentation restricted ind */
+	redirgNum->presRest.pres = PRSNT_NODEF;
+	
+	val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_pres_ind");
+	if (!ftdm_strlen_zero(val)) {
+		redirgNum->presRest.val = atoi(val);
+	} else {
+		redirgNum->presRest.val =  FTDM_PRES_ALLOWED;
+	}
+	SS7_DEBUG_CHAN(ftdmchan, "Redirecting Number Address Presentation Restricted Ind:%d\n", redirgNum->presRest.val);
+
+	/* Numbering plan */
+	redirgNum->numPlan.pres = PRSNT_NODEF;
+
+	val = ftdm_usrmsg_get_var(ftdmchan->usrmsg, "ss7_rdnis_plan");
+	if (!ftdm_strlen_zero(val)) {
+		redirgNum->numPlan.val = atoi(val);
+	} else {
+		redirgNum->numPlan.val = caller_data->rdnis.plan; 
+	}
+	
+	SS7_DEBUG_CHAN(ftdmchan, "Redirecting Number Numbering plan:%d\n", redirgNum->numPlan.val);
+
+	return copy_tknStr_to_sngss7(caller_data->rdnis.digits, &redirgNum->addrSig, &redirgNum->oddEven);
+}
+
+ftdm_status_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven)
 {
 	uint8_t i;
 	uint8_t j;
@@ -362,14 +416,14 @@ uint8_t copy_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven)
 		
 	} else {
 		SS7_ERROR("Asked to copy tknStr that is not present!\n");
-		return 1;
+		return FTDM_FAIL;
 	}
 
-	return 0;
+	return FTDM_SUCCESS;
 }
 
 /******************************************************************************/
-uint8_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven)
+ftdm_status_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven)
 {
 	int i = 0;
 	int j = 0;
@@ -382,7 +436,7 @@ uint8_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven)
 		/* confirm that we found an acceptable length */
 		if ( j > 25 ) {
 			SS7_ERROR("string length exceeds maxium value...aborting append!\n");
-			return 1;
+			return FTDM_FAIL;
 		} /* if ( j > 25 ) */
 
 		/* copy in digits */
@@ -405,12 +459,100 @@ uint8_t append_tknStr_from_sngss7(TknStr str, char *ftdm, TknU8 oddEven)
 		} /* if ((oddEven.pres == 1) && (oddEven.val == 1)) */
 	} else {
 		SS7_ERROR("Asked to copy tknStr that is not present!\n");
-		return 1;
+		return FTDM_FAIL;
 	} /* if (str.pres == 1) */
 
-	return 0;
+	return FTDM_SUCCESS;
 }
 
+
+ftdm_status_t copy_tknStr_to_sngss7(char* val, TknStr *tknStr, TknU8 *oddEven)
+{
+	char tmp[2];
+	int k = 0;
+	int j = 0;
+	uint8_t flag = 0;
+	uint8_t odd = 0;
+
+	uint8_t lower = 0x0;
+	uint8_t upper = 0x0;
+
+	tknStr->pres = PRSNT_NODEF;
+	
+	/* atoi will search through memory starting from the pointer it is given until
+	* it finds the \0...since tmp is on the stack it will start going through the
+	* possibly causing corruption.  Hard code a \0 to prevent this
+	*/
+	tmp[1] = '\0';
+
+	while (1) {
+		/* grab a digit from the ftdm digits */
+		tmp[0] = val[k];
+
+		/* check if the digit is a number and that is not null */
+		while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) {
+			SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
+			/* move on to the next value */
+			k++;
+			tmp[0] = val[k];
+		} /* while(!(isdigit(tmp))) */
+
+		/* check if tmp is null or a digit */
+		if (tmp[0] != '\0') {
+			/* push it into the lower nibble */
+			lower = strtol(&tmp[0], (char **)NULL, 16);
+			/* move to the next digit */
+			k++;
+			/* grab a digit from the ftdm digits */
+			tmp[0] = val[k];
+
+			/* check if the digit is a number and that is not null */
+			while (!(isxdigit(tmp[0])) && (tmp[0] != '\0')) {
+				SS7_INFO("Dropping invalid digit: %c\n", tmp[0]);
+				k++;
+				tmp[0] = val[k];
+			} /* while(!(isdigit(tmp))) */
+
+			/* check if tmp is null or a digit */
+			if (tmp[0] != '\0') {
+				/* push the digit into the upper nibble */
+				upper = (strtol(&tmp[0], (char **)NULL, 16)) << 4;
+			} else {
+				/* there is no upper ... fill in 0 */
+				upper = 0x0;
+				/* throw the odd flag */
+				odd = 1;
+				/* throw the end flag */
+				flag = 1;
+			} /* if (tmp != '\0') */
+		} else {
+			/* keep the odd flag down */
+			odd = 0;
+			/* break right away since we don't need to write the digits */
+			break;
+		}
+
+		/* push the digits into the trillium structure */
+		tknStr->val[j] = upper | lower;
+
+		/* increment the trillium pointer */
+		j++;
+
+		/* if the flag is up we're through all the digits */
+		if (flag) break;
+
+		/* move to the next digit */
+		k++;
+	} /* while(1) */
+	
+	tknStr->len = j;
+	oddEven->pres = PRSNT_NODEF;
+	oddEven->val = odd;
+	return FTDM_SUCCESS;
+}
+
+
+
 /******************************************************************************/
 int check_for_state_change(ftdm_channel_t *ftdmchan)
 {
diff --git a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c
index bf347f0019..815377b476 100644
--- a/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c
+++ b/libs/freetdm/src/ftmod/ftmod_sangoma_ss7/ftmod_sangoma_ss7_xml.c
@@ -122,6 +122,7 @@ typedef struct sng_ccSpan
 	uint32_t		ssf;
 	uint32_t		clg_nadi;
 	uint32_t		cld_nadi;
+	uint32_t		rdnis_nadi;
 	uint32_t		min_digits;
 	uint32_t		t3;
 	uint32_t		t12;
@@ -1841,6 +1842,7 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span)
 	int						num_parms = cc_span->n_parameters;
 	int						flag_clg_nadi = 0;
 	int						flag_cld_nadi = 0;
+	int						flag_rdnis_nadi = 0;
 	int						i;
 	int						ret;
 
@@ -1912,16 +1914,17 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span)
 			flag_clg_nadi = 1;
 			sng_ccSpan.clg_nadi = atoi(parm->val);
 			SS7_DEBUG("Found default CLG_NADI parm->value = %d\n", sng_ccSpan.clg_nadi);
-		/**********************************************************************/
 		} else if (!strcasecmp(parm->var, "cld_nadi")) {
-		/**********************************************************************/
 			/* throw the flag so that we know we got this optional parameter */
 			flag_cld_nadi = 1;
 			sng_ccSpan.cld_nadi = atoi(parm->val);
 			SS7_DEBUG("Found default CLD_NADI parm->value = %d\n", sng_ccSpan.cld_nadi);
-		/**********************************************************************/
+		} else if (!strcasecmp(parm->var, "rdnis_nadi")) {
+			/* throw the flag so that we know we got this optional parameter */
+			flag_rdnis_nadi = 1;
+			sng_ccSpan.rdnis_nadi = atoi(parm->val);
+			SS7_DEBUG("Found default RDNIS_NADI parm->value = %d\n", sng_ccSpan.rdnis_nadi);
 		} else if (!strcasecmp(parm->var, "obci_bita")) {
-		/**********************************************************************/
 			if (*parm->val == '1') {
 				sngss7_set_options(&sng_ccSpan, SNGSS7_ACM_OBCI_BITA);
 				SS7_DEBUG("Found Optional Backwards Indicator: Bit A (early media) enable option\n");
@@ -2012,6 +2015,11 @@ static int ftmod_ss7_parse_cc_span(ftdm_conf_node_t *cc_span)
 		sng_ccSpan.clg_nadi = 0x03;
 	}
 
+	if (!flag_rdnis_nadi) {
+		/* default the nadi value to national */
+		sng_ccSpan.rdnis_nadi = 0x03;
+	}
+
 	/* pull up the SSF and Switchtype from the isup interface */
 	sng_ccSpan.ssf = g_ftdm_sngss7_data.cfg.isupIntf[sng_ccSpan.isupInf].ssf;
 	sng_ccSpan.switchType = g_ftdm_sngss7_data.cfg.isupIntf[sng_ccSpan.isupInf].switchType;
@@ -2901,6 +2909,7 @@ static int ftmod_ss7_fill_in_ccSpan(sng_ccSpan_t *ccSpan)
 		g_ftdm_sngss7_data.cfg.isupCkt[x].ssf			= ccSpan->ssf;
 		g_ftdm_sngss7_data.cfg.isupCkt[x].cld_nadi		= ccSpan->cld_nadi;
 		g_ftdm_sngss7_data.cfg.isupCkt[x].clg_nadi		= ccSpan->clg_nadi;
+		g_ftdm_sngss7_data.cfg.isupCkt[x].rdnis_nadi	= ccSpan->rdnis_nadi;
 		g_ftdm_sngss7_data.cfg.isupCkt[x].options		= ccSpan->options;
 		g_ftdm_sngss7_data.cfg.isupCkt[x].switchType	= ccSpan->switchType;
 		g_ftdm_sngss7_data.cfg.isupCkt[x].min_digits	= ccSpan->min_digits;