view src/aci2/atb/ATBCommon.c @ 662:8cd8fd15a095

SIM speed enhancement re-enabled and made configurable TI's original code supported SIM speed enhancement, but Openmoko had it disabled, and OM's disabling of speed enhancement somehow caused certain SIM cards to start working which didn't work before (OM's bug #666). Because our FC community is much smaller in year 2020 than OM's community was in their day, we are not able to find one of those #666-affected SIMs, thus the real issue they had encountered remains elusive. Thus our solution is to re-enable SIM speed enhancement and simply wait for if and when someone runs into a #666-affected SIM once again. We provide a SIM_allow_speed_enhancement global variable that allows SIM speed enhancement to be enabled or disabled per session, and an /etc/SIM_spenh file in FFS that allows it to enabled or disabled on a non-volatile basis. SIM speed enhancement is now enabled by default.
author Mychaela Falconia <falcon@freecalypso.org>
date Sun, 24 May 2020 05:02:28 +0000
parents 93999a60b835
children
line wrap: on
line source

/*******************************************************************************

					CONDAT (UK)

********************************************************************************                                                                              

 This software product is the property of Condat (UK) Ltd and may not be
 disclosed to any third party without the express permission of the owner.                                 
                                                                              
********************************************************************************

 $Project name:	                                                      
 $Project code:	                                                           
 $Module:		
 $File:		    ATBCommon.c
 $Revision:		                                                      
                                                                              
 $Author:		SH - Condat(UK)                                                         
 $Date:		                                                          
                                                                               
********************************************************************************
                                                                              
 Description: ATB Common functions and definitions.
    
                        
********************************************************************************

 $History: ATBCommon.c

	Mar 30, 2005	REF: CRR 29986	xpradipg
	Description: Optimisation 1: Removal of unused variables and dynamically
	allocate/ deallocate mbndata
	Solution: removed the definition of translation_ascii_2_unicode and added 
	the extern declaration

       March 24, 2005 REF: CRR MMI-FIX-9828 x0012852
	Description: BMI having problems with Umlauts ,especially "ü"
	Solution: g_translation_8bit_table[] array is modified . Changed codes 0x80 , 0x81,      
                     0x82 to ox81, 0x82 ,0x83 respectively.

	Jan 05, 2005 REF: CRR MMI-FIX-24757 xnkulkar
	Description: the display doesn´t show special chars correctly; if there is an "@" in the text, the "@" and 
			    text after is not visible
	Solution: Fix for MMI-SPR-25978 has solved the problem of data loss after '@' symbol. However, some other 
	              symbols (like ¥ etc.) were not displayed properly. Modified the g_translation_8bit_table[] array 
			to take care of all the special GSM character set .
 
	Nov 30, 2004 REF: CRR MMI-SPR-25978 xnkulkar
	Description: Messages:Not able to receive message after @ in the receiver phone (Bug raised in 3.x)
	Solution: in g_translation_8bit_table, the value for '@' symbol was used as 0x00. It has been
	              changed to 0x40 now.
 	
 	26-05-04      CRR 19656    Sandip and Deepa M.D
      	Fix for The Dsample doesn't display lines ( <CR> or <LF> ) in the SETUP IDLE 
	TEXT command.
	Fix for The idle screen is empty when a SETUP IDLE TEXT command is sent with 
	a long text ( 239 characters ).
	
	   
 $End

*******************************************************************************/

/* includes */
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#if defined (NEW_FRAME)

#include "typedefs.h"
#include "vsi.h"
#include "pei.h"
#include "custom.h"
#include "gsm.h"

#else

#include "STDDEFS.H"
#include "custom.h"
#include "gsm.h"
#include "vsi.h"

#endif

#include "mfw_mfw.h"
#include "mfw_win.h"
#include "mfw_kbd.h"
#include "mfw_tim.h"
#include "mfw_phb.h"
#include "mfw_sms.h"
#include "mfw_ss.h"
#include "mfw_icn.h"
#include "mfw_mnu.h"
#include "mfw_lng.h"
#include "mfw_sat.h"
#include "mfw_kbd.h"
#include "mfw_nm.h"
#include "mfw_cm.h"
#include "ATBCommon.h"

/*SPR2175, Added macro and tables for string conversion routines*/
#define MAX_STRING_LEN (5+MFW_NUM_LEN+MAX_MSG_LEN+4)

/*SPR 1508, changed codes 128, 129 and 130 to 129, 130, and 131 respectively.*/
static const char g_translation_ascii_table[128] = { 64, 156, 36, 157, 138, 131, 151, 141, 149, 129,
													 10,   2 ,  7,  32, 143, 134,   4,  95, 232, 226, 239, 234, 227,   5, 228,
											 		233, 240,  32, 146, 145, 225, 144,  32,  33,  34,  35,   1,  37,  38,  39,
											 		 40,  41,  42,  43,  44, 45,  46,  47,  48,  49,  50,  51,  52,  53,  54,
											 		 55,  56,  57,  58,  59,  60,  61,  62,  63, 173,  65,  66,  67,  68,  69,
											 		 70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,  84,
											 		 85,  86,  87,  88,  89,  90, 142, 153, 165, 154,  168, 06,  97,  98,  99,
											 		100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
											 		115, 116, 117, 118, 119, 120, 121, 122, 132, 148, 164, 130, 133};



static const int g_translation_unicode[128] = { 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC, 0x00F2, 0x00C7, 0x000A, 0x00D8, 0x00F8,
												0x000D, 0x00C5, 0x00E5, 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8, 0x03A3, 0x0398,
												0x039E, 0x03A2, 0x00C6, 0x00E6, 0x00DF, 0x00C9, 0x0020, 0x0021, 0x0022, 0x0023, 0x00A4, 0x0025, 0x0026,
												0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, 0x0030, 0x0031, 0x0032, 0x0033,
												0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, 0x00A1,
												0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D,
												0x004E, 0x004F, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A,
												0x00C4, 0x00D6, 0x00D1, 0x00DC, 0x00A7, 0x00BF, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
												0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074,
												0x0075,	0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0x00E4, 0x00F6, 0x00F1, 0x00FC,	0x00E0};

/*SPR 1508, added conversion table*/												
//	Mar 30, 2005	REF: CRR 29986	xpradipg
//	remove the definition of the table
#ifdef FF_MMI_OPTIM
extern const int translation_ascii_2_unicode[];
#else
static const int translation_ascii_2_unicode[256] = { 
	0x0000, 0x00A4, 0x00d8, 0xFFFF, 0x0394, 0x03A8, 0x00BF, 0x00F8, 0xFFFF, 0xFFFF, 0x000A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
	0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026,0x0027, 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F,
	0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
	0x0040,0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F,
	0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, 0x0059, 0x005A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x005F, 
	0xFFFF, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F,
	0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007A, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,

	0xFFFF, 0x00C7, 0x00FC, 0x00E9, 0x00E4, 0x00E0, 0x00E5, 0xFFFF, 0xFFFF, 0xFFFF, 0x00E8, 0xFFFF, 0xFFFF, 0x00EC, 0x00C4, 0x00C5, 
	0x00C9, 0x00E6, 0x00C6, 0xFFFF, 0x00F6, 0x00F2, 0xFFFF, 0x00F9, 0xFFFF, 0x00D6, 0x00DC, 0xFFFF, 0x00A3, 0x00A5, 0xFFFF, 0xFFFF,
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00F1, 0x00D1, 0xFFFF, 0xFFFF, 0x00A7, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x00A1, 0xFFFF, 0xFFFF,
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
	0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
	0xFFFF, 0x00DF, 0x0393, 0x03A0, 0x03A3, 0xFFFF, 0xFFFF, 0xFFFF, 0x03A6, 0x0398, 0x03A9, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x039B, 
	0x039E, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF
	};
#endif	
//	MMI_FIX-19656   Using 8 bit table for dispay start
//	Nov 30, 2004 REF: CRR MMI-SPR-25978 xnkulkar
//	Description: Messages:Not able to receive message after @ in the receiver phone (Bug raised in 3.x)
//	Solution: in g_translation_8bit_table, the value for '@' symbol was used as 0x00. It has been
//	              changed to 0x40 now.

//	Jan 05, 2005 REF: CRR MMI-FIX-24757 xnkulkar
//	Description: the display doesn´t show special chars correctly; if there is an "@" in the text, the "@" and 
//			    text after is not visible
//	Solution: Fix for MMI-SPR-25978 has solved the problem of data loss after '@' symbol. However, some other 
//                 symbols (like ¥ etc.) were not displayed properly. Modified the g_translation_8bit_table[] array 
//		       to take care of all the special GSM character set .

//   March 24, 2005 REF: CRR MMI-FIX-9828 x0012852
//   Description: BMI having problems with Umlauts ,especially "ü"
//   Solution: g_translation_8bit_table[] array is modified . Changed codes 0x80 , 0x81,      
//                 0x82 to ox81, 0x82 ,0x83 respectively.


static const char g_translation_8bit_table[256] ={ 
	0x40, 0x9C, 0x24, 0x9D, 0x8A, 0x83, 0x97, 0x8D, 0x95, 0x81, 0x0A, 0x02, 0x07, 0x20, 0x8F, 0x86,   
	0x04, 0x5F, 0xE8, 0xE2, 0xEF, 0xEA, 0xE3, 0x05, 0xE4, 0xE9,0xF0, 0xFF, 0x92, 0x91, 0xE1, 0x90,   
	0x20, 0x21, 0x22, 0x23, 0x01, 0x25, 0x26,0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,  
	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
	0xAD,0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x8E, 0x99, 0xA5, 0x9A, 0xA8,    
	0x06, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,  
	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x84, 0x94, 0xA4, 0x82, 0x85,  

	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
//MMI_FIX-19656   Using 8 bit table for dispay start

static char convertUCS2_2_ascii_char(char* ipString);
static char convertUCS2_2_gsm_char(char* ipString);
static USHORT ATB_swap_bytes(USHORT character);

/*******************************************************************************

 $Function:    	convertUCS2_2_ascii_char

 $Description:	convert unicode char to ASCII char. Added for SPR 1508. 
 				moved here for SPR 2175

 $Returns:		ASCII char
 $Arguments:	pointer to first byte of unicode char
*******************************************************************************/
static char convertUCS2_2_ascii_char(char* ipString) 
{
	U16 word_code;
	BOOL match_found= FALSE;
	int k;
	char debug[60];
	
	word_code = ipString[0]*0x100 + ipString[1];
	sprintf(debug, "Word code: %d", word_code);
	TRACE_EVENT(debug);
	if (word_code <= 0xFF)
		if (translation_ascii_2_unicode[word_code] == word_code)
			return word_code;
		

		for (k=0; k < 256; k++)
		{	if(translation_ascii_2_unicode[k] == word_code)
			{	sprintf(debug, "Match found: %d, %d", word_code, k);
				TRACE_EVENT(debug);
				match_found = TRUE;
				return k;
			}
							
		}

	if (!match_found)
	{	TRACE_EVENT("No match");

		return 0x3F;/*question mark*/
	}
}
/*******************************************************************************

 $Function:    	convertUCS2_2_ascii_char

 $Description:	convert unicode char to GSM char.  Added for SPR 1508.
 				moved here for SPR 2175

 $Returns:		GSM char
 $Arguments:	pointer to first byte of unicode char
*******************************************************************************/
static char convertUCS2_2_gsm_char(char* ipString) 
{
	U16 word_code;
	BOOL match_found= FALSE;
	int k;
	word_code = ipString[0]*0x100 + ipString[1];
			
					
	if ( word_code > 0x7F || g_translation_unicode[word_code] != word_code)
	{	

		for (k=0; k < 256; k++)
		{	if(g_translation_unicode[k] == word_code)
			{
				match_found = TRUE;
				return k;
			}
							
		}
	}
	else
		return word_code;
	if (!match_found)
	{	return '?';
	}
}
/*******************************************************************************

 $Function:    	ATB_convert_String

 $Description:	Convert a string into an ascii string with 0x80 as first word if data is unicode
 				moved here and renamed for SPR 2175
 $Returns:		execution status

 $Arguments:	ipString - input byte array
 				ipDataType - type of input data
 				ipLength - length of input string (in bytes) 
				opString - output byte array
 				opDataType - type of output data
 				opLength - length of output string (in bytes) 
*******************************************************************************/
/* MC, SPR 1257, merged in b-sample version of this function*/
int ATB_convert_String(			char * ipString,	UBYTE ipDataType,	int ipLength,
										char * opString, 	UBYTE opDataType,	int opLength, UBYTE addNull)
{
	int i;/*SPR 1946, changed from byte to int*/
	int j;/*SPR 1946, changed from byte to int*/
    /*JVJ SPR1298 Converted to dynamic variable */
	UBYTE* text_8bit = NULL;/*SPR1991, don't alloacte this till it's needed*/ 
	int  len;/*SPR 1946, changed from byte to int*/
  	
	
#ifdef TRACE_SMSREAD

  char buf[150];
  sprintf(buf, "opString%x ipString%x ipLength%d opLength%d",opString, ipString, ipLength, opLength);
  TRACE_EVENT(buf);
#endif
  
	if ((opString == NULL) || (ipString==NULL) || (opLength ==0))
		return (FALSE);
	if (ipLength>MAX_STRING_LEN)
		{
		TRACE_EVENT("Too long, returning.");
		return;
		}
	opString[0] = 'X';
	opString[1] = '?';
	opString[2] = 0x00;
	
#ifdef TRACE_SMSREAD
  sprintf(buf,"iDT: %d,iL:%d, oDT:%d, oL:%d, A0:%d",ipDataType,ipLength,opDataType,opLength,addNull);
  TRACE_EVENT(buf);
#endif
  
		
	switch (ipDataType)
	{
	case MFW_DCS_UCS2:
			if (opDataType == MFW_DCS_UCS2)
			{	//Copy array and add 0x80, 0x7F as first word
				if (ipLength < opLength)
					len = ipLength;
				else
					len = opLength;
		/*SPR 1507, copy the bytes in pairs*/
				for (i=0;i<len;i+=2)
				{ opString[i] = ipString[i];
					opString[i+1] = ipString[i+1];
				}
				if (i+1<opLength)
				{
					opString[i  ] = 0x00;
					opString[i+1] = 0x00;
				}
			}
			else if ((opDataType == MFW_DCS_8bits) ||
					(opDataType == MFW_ASCII))
			{			
				if ((ipLength/2 ) < opLength)
					len = ipLength/2;
				else
					len = opLength;

				for (i=0;i<len;i++)
				{	/*SPR 1508, use new functions to convert to ASCII/GSM*/
					if (opDataType == MFW_ASCII)
						opString[i] = convertUCS2_2_ascii_char(&ipString[i*2]);
					else
						opString[i] = convertUCS2_2_gsm_char(&ipString[i*2]);
				}
				if (len<opLength)
				{
					opString[len  ] = 0x00;
				}
	
			}
			else	//Output data type is 7 bits - not implemented
			{
			}
			break;
	case MFW_DCS_8bits:
		
			if (opDataType == MFW_DCS_UCS2)
			{	//Convert data to unicode
				if (ipLength*2 < opLength)
					len = ipLength;
				else
					len = opLength/2;
#ifdef TRACE_SMSREAD
				sprintf(buf, "8->UCS2, len:%d", len);
				TRACE_EVENT(buf);
#endif				
				for (i = 0; i < len; i++)
				{	/*SPR 1508 use table to convert to Unicode*/
					opString[i*2]   = (g_translation_unicode[ipString[i]]>>8)&0x00FF;
					opString[i*2+1] = (g_translation_unicode[ipString[i]])&0x00FF;
				}
				if (len*2+1 < opLength)
				{
					opString[len*2]   = 0x00;
					opString[len*2+1] = 0x00;
				}
			}
			else if (opDataType == MFW_DCS_8bits)
			{	//Data already in correct format - copy
				if (ipLength < opLength)
					len = ipLength;
				else
					len = opLength;
				for (i=0;i<len;i++)
					{
					opString[i] = g_translation_8bit_table[ipString[i]];
					}
				if (len<opLength)
					opString[len] = 0x00;
			}
			else if (opDataType == MFW_ASCII)	// SH - translate characters, don't change bit width
			{
				len = ipLength;
				if (len > opLength)
					len = opLength;
				for (i=0;i<len;i++)
					{
					opString[i] = g_translation_8bit_table[ipString[i]];
					}
				if (len<opLength)
					opString[len] = 0x00;

				//MMI_FIX-19656   Using 8 bit table for mapping end
			}
			else // convert data to 7bit
			{
				len = utl_cvt8To7 ((UBYTE *)ipString , ipLength, (UBYTE*)opString, 0);
			}
		break;
	case MFW_DCS_7bits:
	default:
		/*SPR 1991, allocate memory to conversion buffer*/
		text_8bit = (UBYTE*)mfwAlloc(MAX_STRING_LEN+1);  
		
			if (opDataType == MFW_DCS_7bits) //text string is already in this format
			{
				//Data already in correct format - copy
				if (ipLength < opLength)
					len = ipLength;
				else
					len = opLength;
				for (i=0;i<len;i++)
					opString[i] = ipString[i];
				if (len<opLength)
					opString[len] = 0x00;
			}
			else if (opDataType == MFW_DCS_8bits)
			{
				len = utl_cvt7To8 ((UBYTE *)ipString , ipLength, (UBYTE *)opString, 0 );
				if (len <opLength)
					opString[len] = 0x00;
        else
          opString[opLength]=0x00;
			}
			else if (opDataType == MFW_ASCII)	// SH - expand to 8 bit and convert chars
			{
				len = utl_cvt7To8 ((UBYTE *)ipString , ipLength, text_8bit, 0 );
				if (len > opLength)
					len = opLength;
  				for (i = 0; i < len; i++)
					{
					opString[i] = g_translation_ascii_table[UBYTEToChar(text_8bit[i])];
					}
				if (len <opLength)
					opString[len] = 0x00;
			}
			else
			{	//Convert to unicode
				len = utl_cvt7To8 ((UBYTE *)ipString , ipLength, text_8bit, 0);
				if (len*2 > opLength)
					len = opLength/2;
				for (i = 0; i < len; i++)
				{/*SPR 1508, use new table to convert to Unicode*/
					opString[i*2]   = (g_translation_unicode[ipString[i]]>>8)&0x00FF;
					opString[i*2+1] = g_translation_unicode[UBYTEToChar(text_8bit[i])];
				}
				if (len*2+1 < opLength)
				{
					opString[len*2]   = 0x00;
					opString[len*2+1] = 0x00;
				}
			}
		break;
		
	case MFW_ASCII:
			if (ipLength <=0)
				ipLength = strlen(ipString); //calculate length if not supplied
			if (opDataType == MFW_DCS_UCS2)
			{	//Convert data to unicode
				if (ipLength*2 < opLength)
					len = ipLength;
				else
					len = opLength/2;
				for (i = 0; i < len; i++)
				{	/*SPR 1508, convert to Unicode using new table*/
					opString[i*2]   = (translation_ascii_2_unicode[ ipString[i]]>>8)&0x00FF;
					opString[i*2+1] = (translation_ascii_2_unicode[ ipString[i]])&0x00FF;
				}
				if (len*2+1 < opLength)
				{
					opString[len*2]   = 0x00;
					opString[len*2+1] = 0x00;
				}
			}
			else if (opDataType == MFW_ASCII)
			{	//Data already in correct format - copy
				if (ipLength < opLength)
					len = ipLength;
				else
					len = opLength;
				for (i=0;i<len;i++)
					opString[i] = ipString[i];
				if (len<opLength)
					opString[len] = 0x00;
			}
			else if (opDataType == MFW_DCS_8bits || opDataType == MFW_DCS_7bits)	// SH - translate characters, don't change bit width
			{

				if (ipLength < opLength)
					len = ipLength;
				else
					len = opLength;
				for (i=0;i<len;i++)
					{
					opString[i] = ipString[i];
					if (ipString[i]>=128 || g_translation_ascii_table[ipString[i]]!=ipString[i])
						{
						for (j=0; j<128; j++)			// Reverse translation
							{
							if (ipString[i] == g_translation_ascii_table[j])
								opString[i] = j;
							}
						#ifdef TRACE_SMSREAD
						sprintf(buf, "Converted %x to %x", ipString[i], opString[i]);
						TRACE_EVENT(buf);
						#endif
						}
					}
				if (len<opLength)
					opString[len] = 0x00;
			}
			if (opDataType == MFW_DCS_7bits) // convert data to 7bit
			{
				len = utl_cvt8To7 ((UBYTE *)ipString , ipLength, (UBYTE*)opString, 0);
			}
		break;
	}

	if (addNull)
	{	//Add 0x00 (or 0x00,0x00) to end of array

	/*SPR925 - SH - changed so NULL is in right place for unicode*/
		if (opDataType == MFW_DCS_UCS2)
		{
			if (len*2+1>opLength)
				len = opLength/2;

			opString[len*2] = 0x00;
			opString[len*2+1] = 0x00;
		}
		else
		{
			if (len>opLength)
				len = opLength;

			opString[len] = 0x00;
		}
	/* end SPR925 */
	}
	/*SPR 1991, free memory only if it has been allocated*/
	if (text_8bit!= NULL)
        mfwFree(text_8bit,MAX_STRING_LEN+1);
	return TRUE;
}



/*******************************************************************************

 $Function:    	ATB_mem_Alloc

 $Description:	ATB memory allocation function.
 
 $Returns:		Address if successful, null if not.

 $Arguments:	Size of memory to be allocated.
 
*******************************************************************************/

UBYTE* ATB_mem_Alloc(USHORT size)
{
	return (UBYTE *)mfwAlloc(size);
}


/*******************************************************************************

 $Function:    	ATB_mem_Free

 $Description:	Frees memory allocated by the ATB
 
 $Returns:		None.

 $Arguments:	address		- Pointer to memory to free
 				size		- Size of the allocated block
 
*******************************************************************************/

void ATB_mem_Free(UBYTE* address, USHORT size)
{
	mfwFree(address,size);
	return;
}
/*******************************************************************************

 $Function:		ATB_swap_bytes

 $Description:	Returns a unicode character with the bytes swapped. Added for SPR2175

 $Returns:		USHORT

 $Arguments:	USHORT

*******************************************************************************/
static USHORT ATB_swap_bytes(USHORT character)
{
	return ((UNICODE_NONASCII&character) << 8) + ((UNICODE_ASCII&character) >>8);

}

/*******************************************************************************

 $Function:		ATB_char_GSM

 $Description:	Returns the GSM of the provided ascii character.Added for SPR 2175.

 $Returns:		A GSM character

 $Arguments:	character - The ascii character

*******************************************************************************/

char ATB_char_GSM(char ascii_character)
{	int i;
	/*check if GSM and ASCII encoding are the same value*/
	if (g_translation_ascii_table[ascii_character] == ascii_character)
		return ascii_character;
	
	/*otherwise we have to search for the correct entry in the GSM to ASCII table*/
	for (i=0; i<128; i++)
	{
		if (g_translation_ascii_table[i] == ascii_character)
			return i;

	}
}
/*******************************************************************************

 $Function:		ATB_char_Ascii

 $Description:	Returns the ascii of the provided unicode character

 $Returns:		An ascii character

 $Arguments:	character - The unicode character

*******************************************************************************/

char ATB_char_Ascii(USHORT character)
{	int i;

	/*SPR2175, rewrote function*/
	/*if the first byte of the character is the same as the ASCII code, return the first byte*/
	if (translation_ascii_2_unicode[((character & UNICODE_ASCII)>>8)] == ((character & UNICODE_ASCII)>>8))
		return (char)((character & UNICODE_ASCII)>>8);
	
	/*otherwise we have to search for the correct entry in the ASCII to unicode table*/
	for (i=0; i<256; i++)
	{
		if (translation_ascii_2_unicode[i] == ATB_swap_bytes(character))
			return i;

	}
}


/*******************************************************************************

 $Function:		ATB_char_Unicode

 $Description:	Returns the unicode of the provided ascii character

 $Returns:		A unicode character

 $Arguments:	character - The ascii character

*******************************************************************************/

USHORT ATB_char_Unicode(char character)
{	/*SPR 2175, re-wrote function*/
	USHORT table_value;
	USHORT return_value = NULL;
	/*look up corresponding Unicode char in table*/
	table_value= translation_ascii_2_unicode[character];

	/*swap bytes as little-endian*/
	return_value = ATB_swap_bytes(table_value);

	return return_value;
}


/*******************************************************************************

 $Function:		ATB_char_IsAscii

 $Description:	Returns TRUE if the unicode character provided is ascii

 $Returns:		TRUE or FALSE

 $Arguments:	character - The unicode character

*******************************************************************************/

BOOL ATB_char_IsAscii(USHORT character)
{
	BOOL	result = FALSE;

	if (character & UNICODE_NONASCII)					// Make sure character is ASCII
	{
		result = FALSE;
	}
	else
	{
		result = TRUE;
	}

	return result;
}


/*******************************************************************************

 $Function:		ATB_char_IsAlphabetic

 $Description:	Return TRUE if unicode character is part of latin alphabet

 $Returns:		TRUE or FALSE

 $Arguments:	character - The unicode character

*******************************************************************************/

BOOL ATB_char_IsAlphabetic(USHORT character)
{
	BOOL	result = FALSE;
	UBYTE	asciiChar; 

	if (ATB_char_IsAscii(character))					// Make sure character is ASCII
	{
		asciiChar = ATB_char_Ascii(character);
		if ( (asciiChar >='A') && (asciiChar <='Z') )
			result = TRUE;
		else if ( (asciiChar >='a') && (asciiChar <='z') )
			result = TRUE;
	}

	return result;
}


/*******************************************************************************

 $Function:		ATB_char_IsNumierc

 $Description:	Return TRUE if unicode character is a digit, 0-9

 $Returns:		TRUE or FALSE

 $Arguments:	character - The unicode character

*******************************************************************************/

BOOL ATB_char_IsNumeric(USHORT character)
{
	BOOL	result = FALSE;
	UBYTE	asciiChar;
 
	if (ATB_char_IsAscii(character))				// Make sure character is ASCII
	{
		asciiChar = ATB_char_Ascii(character);
		if ( (asciiChar >='0') && (asciiChar <='9') )
			result = TRUE;
	}

	return result;
}

/*******************************************************************************

 $Function:		ATB_char_IsVisible

 $Description:	Return TRUE if unicode character is visible, i.e. not ascii <32

 $Returns:		TRUE or FALSE

 $Arguments:	character - The unicode character

*******************************************************************************/

BOOL ATB_char_IsVisible(USHORT character)
{
	BOOL	result = TRUE;
	UBYTE	asciiChar; 

	if (ATB_char_IsAscii(character))					// Make sure character is ASCII
	{
		asciiChar = ATB_char_Ascii(character);
		/*SPR 2175, if ASCII value has no unicode equivalent assume not visible*/
		if (translation_ascii_2_unicode[asciiChar] == 0xFFFF)
			result = FALSE;
	}

	return result;
}


/*******************************************************************************

 $Function:		ATB_string_Size

 $Description:	Return the size in bytes of a character in the string

 $Returns:		No. of bytes per character

 $Arguments:	text	- The text string

*******************************************************************************/
  
UBYTE ATB_string_Size(T_ATB_TEXT *text)
{
	UBYTE size;
	
	switch(text->dcs)
	{
		case ATB_DCS_UNICODE:
			size = 2;
			break;

		default:
			size = 1;
			break;
	}
	
	return size;
}


/*******************************************************************************

 $Function:		ATB_string_SetChar

 $Description:	Set a character in the string to a value.  Use this function rather than
 				accessing text data directly; it allows transparent ASCII and Unicode
 				handling.
 
 $Returns:		None

 $Arguments:	text		- The text string
 				textIndex	- The position of the character to set
 				character	- The unicode character to set it to

*******************************************************************************/
  
void ATB_string_SetChar(T_ATB_TEXT *text, USHORT textIndex, USHORT character)
{
	USHORT *unicode;
	
	if (text->dcs==ATB_DCS_UNICODE)
	{
		unicode = (USHORT *)text->data;
		unicode[textIndex] = character;
	}
	else
		text->data[textIndex] = ATB_char_Ascii(character);

	return;
}


/*******************************************************************************

 $Function:		ATB_string_GetChar

 $Description:	Gets the value of a character in the string.  Use this function rather than
 				accessing text data directly; it allows transparent ASCII and Unicode
 				handling.
 
 $Returns:		The unicode character at the required position

 $Arguments:	text		- The text string
 				textIndex	- The position of the character to get

*******************************************************************************/

USHORT ATB_string_GetChar(T_ATB_TEXT *text, USHORT textIndex)
{
	USHORT *unicode;
	USHORT character;
	
	if (text->dcs==ATB_DCS_UNICODE)
	{
		unicode = (USHORT *)text->data;
		character = unicode[textIndex];
	}
	else
		character = ATB_char_Unicode(text->data[textIndex]);

	return character;
}


/*******************************************************************************

 $Function:		ATB_string_MoveLeft

 $Description:	Move part of string left by 'offset' characters
 
 $Returns:		TRUE if the operation was successful

 $Arguments:	text		- The text string
 				textIndex	- The place where the newly moved section is to go
 				offset		- The number of characters to move the section left by

*******************************************************************************/
  
BOOL ATB_string_MoveLeft(T_ATB_TEXT *text, USHORT textIndex, USHORT offset)
{
	BOOL outcome;
	USHORT character;
	
	/* Copy until end of line char reached */

	while ((textIndex+offset)<=text->len)
	{
		character = ATB_string_GetChar(text, textIndex+offset);
		ATB_string_SetChar(text, textIndex, character);
		textIndex++;
	}
	outcome = TRUE;
	text->len -= offset;
	
	return outcome;
}


/*******************************************************************************

 $Function:		ATB_string_MoveRight

 $Description:	Move part of string right by 'offset' characters
 
 $Returns:		TRUE if the operation was successful

 $Arguments:	text		- The text string
 				textIndex	- The start of the section to be moved right
 				offset		- The number of characters to move the section right by
 				size		- The maximum possible length of the string

*******************************************************************************/

BOOL ATB_string_MoveRight(T_ATB_TEXT *text, USHORT textStart, USHORT offset, USHORT size)
{
	int textIndex;
	BOOL outcome;
	USHORT character;
	
	textIndex = text->len;
	
	if ((text->len+ offset) < size)	/* SPR#1995 - SH - <= should be < */
	{
		while (textIndex >= textStart)
		{
			character = ATB_string_GetChar(text, textIndex);
			ATB_string_SetChar(text, textIndex+offset, character);
			textIndex--;
		}
		text->len += offset;
		outcome = TRUE;
	}
	else
		outcome = FALSE;
	
	return outcome;
}


/*******************************************************************************

 $Function:		ATB_string_Length

 $Description:	Returns the length of the string, also setting the 'len' parameter of
 				the text structure
 
 $Returns:		Length of the string in characters

 $Arguments:	text		- The text string

*******************************************************************************/

USHORT ATB_string_Length(T_ATB_TEXT* text)
{
	USHORT 	length;

	if (text->dcs==ATB_DCS_UNICODE)
	{
		text->len = ATB_string_UCLength((USHORT *)text->data);
	}
	else
	{
		text->len = strlen((char *)text->data);
	}
	
	return text->len;
}


/*******************************************************************************

 $Function:		ATB_string_UCLength

 $Description:	Returns the length of the provided unicode string
 
 $Returns:		Length of the string in characters

 $Arguments:	text		- Pointer to the unicode string

*******************************************************************************/

USHORT ATB_string_UCLength(USHORT* text)
{
	USHORT 	length = 0;

	while (text[length]!=UNICODE_EOLN)
	{
		length++;
	}
	
	return (length);
}


/*******************************************************************************

 $Function:		ATB_string_Copy

 $Description:	Copy 'src' string into 'dest' string.
 
 $Returns:		None.

 $Arguments:	dest		- The destination string (allocated by caller)
 				src			- The source string (allocated by caller)

*******************************************************************************/

void ATB_string_Copy(T_ATB_TEXT* dest, T_ATB_TEXT* src)
{
	USHORT textIndex;
	USHORT character; 

	dest->dcs = src->dcs;
	
	for (textIndex=0; textIndex<src->len; textIndex++)
	{
		character = ATB_string_GetChar(src, textIndex);
		ATB_string_SetChar(dest, textIndex, character);
	}

	ATB_string_SetChar(dest, textIndex, UNICODE_EOLN);
	dest->len = textIndex;

	return;
}


/*******************************************************************************

 $Function:		ATB_string_Concat

 $Description:	Concatenate the second string, adding it to the end of the first.
 				N.B. The strings don't have to have the same DCS.
 
 $Returns:		None.

 $Arguments:	dest		- The destination string (allocated by caller)
 				src			- The source string (allocated by caller)

*******************************************************************************/

void ATB_string_Concat(T_ATB_TEXT* dest, T_ATB_TEXT* src)
{
	USHORT textIndex;
	USHORT character;
 	TRACE_EVENT_P4("dest_len:%d, src len:%d, dest dcs: %d, src dcs:%d", dest->len, src->len, dest->dcs, src->dcs);
 	
	for (textIndex = 0; textIndex<src->len; textIndex++)
	{
		character = ATB_string_GetChar(src, textIndex);
		/*SPR 2512, use destination length */
		ATB_string_SetChar(dest, textIndex+dest->len, character);
	}
	
	dest->len += src->len;
	/*SPR 2512, use destination length to find point to insert termination*/
	ATB_string_SetChar(dest, dest->len, UNICODE_EOLN);

	return;
}


/*******************************************************************************

 $Function:		ATB_string_Concat

 $Description:	Return position of character in string, or -1 if not found
 
 $Returns:		Position of character in string

 $Arguments:	text		- The text string to search
 				findChar	- The character to find

*******************************************************************************/

SHORT ATB_string_FindChar(T_ATB_TEXT* text, USHORT findChar)
{
	USHORT textIndex;
	SHORT foundPos;
	USHORT character;
	 
	textIndex = 0;
	foundPos = -1;

	character = ATB_string_GetChar(text, 0);

	while (character!=UNICODE_EOLN && foundPos==-1)
	{
		if (character==findChar)
			foundPos = (int)textIndex;
		textIndex++;
		character = ATB_string_GetChar(text, textIndex);
	}
	
	return foundPos;
}


/*******************************************************************************

 $Function:		ATB_string_ToUnicode

 $Description:	Convert a string to a unicode string.  Memory for the unicode
  				string should be allocated before calling.  Returns a pointer to the
  				unicode string.
  
 $Returns:		None.

 $Arguments:	dest		- The destination string (allocated by caller)
 				src			- The source string (allocated by caller)

*******************************************************************************/

void ATB_string_ToUnicode(T_ATB_TEXT *dest, T_ATB_TEXT *src)
{
	USHORT textIndex;
	USHORT character; 
	
	dest->dcs = ATB_DCS_UNICODE;

	for (textIndex=0; textIndex<src->len; textIndex++)
	{
		character = ATB_string_GetChar(src, textIndex);
		ATB_string_SetChar(dest, textIndex, character);
	}

	ATB_string_SetChar(dest, textIndex, UNICODE_EOLN);
	dest->len = textIndex;

	return;
}


/*******************************************************************************

 $Function:		ATB_string_ToAscii

 $Description:	Convert a string to an ascii string.  Memory for the ascii
  				string should be allocated before calling.  Returns a pointer to the
  				ascii string.
  
 $Returns:		None.

 $Arguments:	dest		- The destination string (allocated by caller)
 				src			- The source string (allocated by caller)

*******************************************************************************/

void ATB_string_ToAscii(T_ATB_TEXT *dest, T_ATB_TEXT *src)
{
	USHORT textIndex;
	USHORT character;
	 
	dest->dcs = ATB_DCS_ASCII;

	for (textIndex = 0; textIndex<src->len; textIndex++)
	{
		character = ATB_string_GetChar(src, textIndex);

		if (ATB_char_IsAscii(character) && ATB_char_IsVisible(character)) // Filter out non-ascii characters
		{
			character = ATB_char_Unicode('?');
		}

		ATB_string_SetChar(dest, textIndex, character);
	}

	return;
}


/*******************************************************************************

 $Function:		ATB_string_ToUnicode

 $Description:	Moves index position through text
  
 $Returns:		The new index.

 $Arguments:	text		- The text string
				textIndex	- Current position within the text buffer
				offset		- Negative for backwards movement, positive for forwards
							  movement.

*******************************************************************************/ 

USHORT ATB_string_IndexMove(T_ATB_TEXT *text, USHORT textIndex, SHORT offset)
{ 
	while (textIndex>0 && offset<0)
	{
		textIndex--;
		offset++;
	}

	while (ATB_string_GetChar(text, textIndex)!=UNICODE_EOLN && offset>0)
	{
		textIndex++;
		offset--;
	}

	return textIndex;
}