/*===========================================================================
                              OEMWSMS.c

  OEM REFERENCE SMS SUPPORT ROUTINES
  
  This file contains a reference implementation of SMS support.
  This file interfaces with WMS services of DMSS.
    
        Copyright © 1999-2004 QUALCOMM Incorporated.
               All Rights Reserved.
            QUALCOMM Proprietary/GTDR
============================================================================*/
#include "OEMFeatures.h"

#ifdef FEATURE_WMS

#if !defined(AEE_SIMULATOR)
#include "clk.h"
#else 
#include "clki.h"
#endif //AEE_SIMULATOR

#include "OEMHeap.h"
#include "OEMSMS_priv.h"
#include "OEMSMS.h"
#include "OEMSMSStorage.h"
#include "OEMTAPI.h"
#include "OEMConfig.h"
#ifndef PHONE_SVC
# define PHONE_SVC
#endif
#include "msm/OEMPhone.h"
#include "AEEComdef.h"
#include "AEEShell.h"
#include "AEEStdLib.h"
#include "AEE_OEMDispatch.h"
#include "AEESMS.h"

#ifndef AEE_SIMULATOR
#include "AEE_OEM.h"
#endif

struct _OEMMsg
{
   wms_client_message_s_type  CMsg;
   AEECallback                *pcb;
   uint32                     *pdwStatus;
};

struct _OEMBcCfg
{
   boolean              bBroadcastInUse;
   OEMSMSBCRequestType  eCurRequest;
   AEESMSMode           dwMode;
   uint32               nNumCommands;
   AEECallback         *pcb;
   uint32              *pnErr;
   AEESMSBCConfig      *pConfig;
   AEESMSBCPref        *pPref;
   uint32              *pnCount;
   AEESMSBCSrvID       *psid;        // To Store the Service IDs got from WMS
   OEMSMSBCSrvInfo     *pSrvInfo;    // To Store the Service Info got from WMS
   boolean              bSrvIDAlloc;
   boolean              bSrvInfoAlloc;
};

typedef struct _OEMReadMsg
{
   AEECallback                *pcb;
   uint32                     *pdwStatus;
   OEMMsgData                 *pMsgData;
   OEMMsgPayload              *pMsgPayload;
} OEMReadMsg;

typedef struct _OEMDeleteMsg
{
   AEECallback                *pcb;
   uint32                     *pdwStatus;
} OEMDeleteMsg;

typedef struct _OEMWms 
{
   wms_client_id_type   clientId;
   OEMMsg               *pCurMOSMS;
   OEMMsg               *pCurStoreSMS;
   OEMReadMsg           *pCurReadSMS;
   OEMDeleteMsg         *pCurDeleteSMS;
   OEMBcCfg             sBcCfg;
   boolean              bTranmissionPending;
   boolean              bDedicatedChannel;
   boolean              bMOOnAccessChannel;     // Send MO SMS on access channel
   boolean              bMOOnTrafficChannel;    // Send MO SMS on traffic channel
   uint32               dwTextStatus;           // Client Status for text messages
   uint32               dwVMStatus;             // Client Status for voice mail messages
   uint32               dwPageStatus;           // Client Status for page messages
   uint32               dwWapStatus;            // Client Status for WAP push messages
   uint32               dwEMSStatus;            // Client Status for EMS messages
   uint32               dwBREWDirectedTS;       // Teleservice ID for BREW directed messages
   boolean              bStrInit[AEESMS_STORAGE_LAST];            // Initilization Status for various storage type
   uint32               ucStrSMSCount[AEESMS_STORAGE_LAST];       // SMS count for various storage type
   int                  strSMSMsgList[AEESMS_STORAGE_LAST][WMS_MESSAGE_LIST_MAX];  // SMS list for various storage type
   wms_gw_domain_pref_e_type gwDomainPref;      // Domain preference for GW messages
} OEMWms;

OEMWms * gpWms = 0;

//Language Mapping between WMS and BREW
typedef struct
{
   wms_language_e_type              OEM_Lang;
   uint32                           AEE_Lang;
} LangMap;

static const LangMap      gsLangMap[]  = {{WMS_LANGUAGE_UNSPECIFIED,    0},
                                         {WMS_LANGUAGE_ENGLISH,         LNG_ENGLISH},
                                         {WMS_LANGUAGE_FRENCH,          LNG_FRENCH},
                                         {WMS_LANGUAGE_SPANISH,         LNG_SPANISH},
                                         {WMS_LANGUAGE_JAPANESE,        LNG_JAPANESE},
                                         {WMS_LANGUAGE_KOREAN,          LNG_KOREAN},
                                         {WMS_LANGUAGE_CHINESE,         LNG_CHINESE},
                                         {WMS_LANGUAGE_HEBREW,          LNG_HEBREW}};


// Teleservice Mapping Between WMS and OEM layer SMS teleservice defines
typedef struct
{
   int                        OEM_TsId;
   wms_teleservice_e_type     DMSS_TsId;
} TsIdMap;

static const TsIdMap   gsTsIdMap[] = 
                  {{SMS_TELESERVICE_CPT_95,              WMS_TELESERVICE_CPT_95 },
                  {SMS_TELESERVICE_CMT_95,               WMS_TELESERVICE_CMT_95 },
                  {SMS_TELESERVICE_VMN_95,               WMS_TELESERVICE_VMN_95 },
                  {SMS_TELESERVICE_IS91_PAGE,            WMS_TELESERVICE_IS91_PAGE },
                  {SMS_TELESERVICE_IS91_VOICE_MAIL,      WMS_TELESERVICE_IS91_VOICE_MAIL},
                  {SMS_TELESERVICE_IS91_SHORT_MESSAGE,   WMS_TELESERVICE_IS91_SHORT_MESSAGE},
                  {SMS_TELESERVICE_MWI,                  WMS_TELESERVICE_MWI},
                  {SMS_TELESERVICE_WAP,                  WMS_TELESERVICE_WAP},
                  {SMS_TELESERVICE_WEMT,                 WMS_TELESERVICE_WEMT}};

//Priority Mapping between DMSS and BREW
typedef struct
{
   int                     AEE_Priority;
   wms_priority_e_type     OEM_Priority;
} PriorityMap;

static const PriorityMap   gsPriorityMap[] = 
                  {{SMS_PRIORITY_NORMAL,      WMS_PRIORITY_NORMAL},
                  {SMS_PRIORITY_INTERACTIVE,  WMS_PRIORITY_INTERACTIVE},
                  {SMS_PRIORITY_URGENT,       WMS_PRIORITY_URGENT},
                  {SMS_PRIORITY_EMERGENCY,    WMS_PRIORITY_EMERGENCY }};

//Privacy Mapping between DMSS and BREW
typedef struct
{
   int                     AEE_Privacy;
   wms_privacy_e_type      OEM_Privacy;
} PrivacyMap;


static const PrivacyMap   gsPrivacyMap[] = 
                  {{SMS_PRIVACY_NORMAL,         WMS_PRIVACY_NORMAL},
                  {SMS_PRIVACY_RESTRICTED,      WMS_PRIVACY_RESTRICTED},
                  {SMS_PRIVACY_CONFIDENTIAL,    WMS_PRIVACY_CONFIDENTIAL},
                  {SMS_PRIVACY_SECRET,          WMS_PRIVACY_SECRET}};

//Encoding Mapping between DMSS and OEM layer encoding
typedef struct
{
   int                                 AEE_Enc;
   wms_user_data_encoding_e_type       OEM_Enc;
} EncMap;

static const EncMap   gsEncMap[] =  
                  {{AEESMS_ENC_OCTET,            WMS_ENCODING_OCTET},
                  {AEESMS_ENC_IS91EP,            WMS_ENCODING_IS91EP},
                  {AEESMS_ENC_ASCII,             WMS_ENCODING_ASCII},
                  {AEESMS_ENC_LATIN,             WMS_ENCODING_LATIN},
                  {AEESMS_ENC_IA5,               WMS_ENCODING_IA5},
                  {AEESMS_ENC_UNICODE,           WMS_ENCODING_UNICODE},
                  {AEESMS_ENC_SHIFT_JIS,         WMS_ENCODING_SHIFT_JIS},
                  {AEESMS_ENC_KOREAN,            WMS_ENCODING_KOREAN},
                  {AEESMS_ENC_LATIN_HEBREW,      WMS_ENCODING_LATIN_HEBREW},
                  {AEESMS_ENC_GSM_7_BIT_DEFAULT, WMS_ENCODING_GSM_7_BIT_DEFAULT}};

//Tag Mapping between DMSS and AEE layer tags
typedef struct
{
   int                                 AEE_Tag;
   wms_message_tag_e_type              OEM_Tag;
} TagMap;

static const TagMap   gsTagMap[] =  
                  {{AEESMS_TAG_NONE,                     WMS_TAG_NONE},
                  {AEESMS_TAG_MT_READ,                   WMS_TAG_MT_READ},
                  {AEESMS_TAG_MT_NOT_READ,               WMS_TAG_MT_NOT_READ},
                  {AEESMS_TAG_MO_SENT,                   WMS_TAG_MO_SENT},
                  {AEESMS_TAG_MO_NOT_SENT,               WMS_TAG_MO_NOT_SENT},
                  {AEESMS_TAG_MO_SENT_ST_NOT_RECEIVED,   WMS_TAG_MO_SENT_ST_NOT_RECEIVED},
                  {AEESMS_TAG_MO_SENT_ST_NOT_STORED,     WMS_TAG_MO_SENT_ST_NOT_STORED},
                  {AEESMS_TAG_MO_SENT_ST_STORED,         WMS_TAG_MO_SENT_ST_STORED},
                  {AEESMS_TAG_MO_TEMPLATE,               WMS_TAG_MO_TEMPLATE},
                  {AEESMS_TAG_STATUS_RPT,                WMS_TAG_STATUS_RPT}};

//Tag Mapping between DMSS and AEE layer storage type
typedef struct
{
   int                                 AEE_StorageType;
   wms_message_tag_e_type              OEM_StorageType;
} StorageTypeMap;

static const StorageTypeMap   gsStorageTypeMap[] =
                  {{AEESMS_CARD_RUIM,                    WMS_MEMORY_STORE_RUIM},
                   {AEESMS_CARD_SIM,                     WMS_MEMORY_STORE_SIM},
                   {AEESMS_NV_CDMA,                      WMS_MEMORY_STORE_NV_CDMA},
                   {AEESMS_NV_GW,                        WMS_MEMORY_STORE_NV_GW}};

//Tag Mapping between DMSS and AEE layer UDH IDs
typedef struct
{
   AEESMSUDHId                         AEE_UDHID;
   wms_udh_id_e_type                   DMSS_UDHID;
} UDHIDMap;

static const UDHIDMap   gsUDHIDMap[] =  
                  {{AEESMS_UDH_CONCAT_8,        WMS_UDH_CONCAT_8},
                  {AEESMS_UDH_SPECIAL_SM,       WMS_UDH_SPECIAL_SM},
                  {AEESMS_UDH_PORT_8,           WMS_UDH_PORT_8},
                  {AEESMS_UDH_PORT_16,          WMS_UDH_PORT_16},
                  {AEESMS_UDH_SMSC_CONTROL,     WMS_UDH_SMSC_CONTROL},
                  {AEESMS_UDH_SOURCE,           WMS_UDH_SOURCE},
                  {AEESMS_UDH_CONCAT_16,        WMS_UDH_CONCAT_16},
                  {AEESMS_UDH_WCMP,             WMS_UDH_WCMP},
                  {AEESMS_UDH_TEXT_FORMATING,   WMS_UDH_TEXT_FORMATING},
                  {AEESMS_UDH_PRE_DEF_SOUND,    WMS_UDH_PRE_DEF_SOUND},
                  {AEESMS_UDH_USER_DEF_SOUND,   WMS_UDH_USER_DEF_SOUND},
                  {AEESMS_UDH_PRE_DEF_ANIM,     WMS_UDH_PRE_DEF_ANIM},
                  {AEESMS_UDH_LARGE_ANIM,       WMS_UDH_LARGE_ANIM},
                  {AEESMS_UDH_SMALL_ANIM,       WMS_UDH_SMALL_ANIM},
                  {AEESMS_UDH_LARGE_PICTURE,    WMS_UDH_LARGE_PICTURE},
                  {AEESMS_UDH_SMALL_PICTURE,    WMS_UDH_SMALL_PICTURE},
                  {AEESMS_UDH_VAR_PICTURE,      WMS_UDH_VAR_PICTURE},
                  {AEESMS_UDH_RFC822,           WMS_UDH_RFC822}};

//Tag Mapping between DMSS and AEE layer message wait types
typedef struct
{
   AEESMSMsgWaitingType                AEE_MsgWaitType;
   wms_gw_msg_waiting_e_type           DMSS_MsgWaitType;
} MsgWaitTypeMap;

static const MsgWaitTypeMap gsMsgWaitTypeMap[] = 
                 {{AEESMS_MSGWAITINGTYPE_NONE,        WMS_GW_MSG_WAITING_NONE}, 
                  {AEESMS_MSGWAITINGTYPE_DISCARD,     WMS_GW_MSG_WAITING_DISCARD},
                  {AEESMS_MSGWAITINGTYPE_STORE,       WMS_GW_MSG_WAITING_STORE},
                  {AEESMS_MSGWAITINGTYPE_NONE_1111,   WMS_GW_MSG_WAITING_NONE_1111}};

//Tag Mapping between DMSS and AEE layer message wait kinds
typedef struct
{
   AEESMSMsgWaitingKind                AEE_MsgWaitKind;
   wms_gw_msg_waiting_kind_e_type      DMSS_MsgWaitKind;
} MsgWaitKindMap;

static const MsgWaitKindMap gsMsgWaitKindMap[] = 
                 {{AEESMS_MSGWAITINGKIND_VOICEMAIL,   WMS_GW_MSG_WAITING_VOICEMAIL}, 
                  {AEESMS_MSGWAITINGKIND_FAX,         WMS_GW_MSG_WAITING_FAX},
                  {AEESMS_MSGWAITINGKIND_EMAIL,       WMS_GW_MSG_WAITING_EMAIL},
                  {AEESMS_MSGWAITINGKIND_OTHER,       WMS_GW_MSG_WAITING_OTHER}};

//GW Domain Preference Mapping between DMSS and AEE layer
typedef struct
{
   int AEE_DomainPref;
   wms_gw_domain_pref_e_type DMSS_DomainPref;
} GWDomainPrefMap;

static const GWDomainPrefMap gsGWDomainPrefMap[] = 
                 {{AEESMS_GW_DOMAIN_PREF_CS_PREFERRED,   WMS_GW_DOMAIN_PREF_CS_PREFERRED}, 
                  {AEESMS_GW_DOMAIN_PREF_PS_PREFERRED,   WMS_GW_DOMAIN_PREF_PS_PREFERRED},
                  {AEESMS_GW_DOMAIN_PREF_CS_ONLY,        WMS_GW_DOMAIN_PREF_CS_ONLY},
                  {AEESMS_GW_DOMAIN_PREF_PS_ONLY,        WMS_GW_DOMAIN_PREF_PS_ONLY}};

/*===========================================================================

  Prototypes

===========================================================================*/
void OEMWMS_MessageListener
( 
   wms_msg_event_e_type event,
   wms_msg_event_info_s_type * info_ptr,
   boolean * pshared 
);

static wms_status_e_type OEMWMS_MoMessageListener
( 
   wms_msg_event_e_type event,
   const wms_msg_event_info_s_type * info_ptr,
   boolean * pshared 
);

static void OEMWSMS_CommandCallback 
(
   wms_cmd_id_e_type cmd, 
   void * user_data, 
   wms_cmd_err_e_type cmd_err 
);

static uint32 OEMWMS_GetSubmitStatus( const wms_submit_report_info_s_type *submit_info );

static void OEMWMS_EventListener
(
   wms_dc_event_e_type event, 
   wms_dc_event_info_s_type * info_ptr
);

static void OEMWMS_CfgListener
(
   wms_cfg_event_e_type event,
   wms_cfg_event_info_s_type * info_ptr
);

static void OEMWMS_PreProcessor
( 
   const wms_client_message_s_type * pCMsg, 
   boolean * pshared 
);

boolean OEMWMS_CopyMessage
( 
   wms_transaction_id_type transaction_id, 
   wms_client_message_s_type * pCMsg,
   SMSCacheEntry *pce 
);

static boolean OEMWMS_GetNumMsgsInfoFromCDMABDMsg 
(
   wms_client_bd_s_type * pcd,
   wms_teleservice_e_type ts,
   int * pnNumMsgs
);

static boolean OEMWMS_GetNumMsgsInfoFromGWMsg 
(
   wms_gw_deliver_s_type * pData,
   wms_teleservice_e_type ts,
   int * pnNumMsgs
);

static void OEMWMS_SetNumMsgsInfoToGWMsg 
(
   wms_gw_deliver_s_type * pData,
   wms_teleservice_e_type ts,
   int nNumMsgs
);

static boolean OEMWMS_GetCallBackNumberFromCDMABDMsg
( 
   wms_client_bd_s_type *pcd,
   wms_teleservice_e_type ts,
   char * pBuffer
);

boolean OEMWMS_GetAddressString
(
   byte * pSrc,
   int nDigits,
   wms_digit_mode_e_type digitMode,
   wms_number_type_e_type numberType,
   wms_teleservice_e_type ts,
   char * pBuffer
);

static wms_teleservice_e_type OEMWMS_DetermineGSMMessageType
(
   wms_gw_pp_ts_data_s_type *pgw_pp
);

static void OEMWMS_SetGSMMessageType
(
   wms_gw_dcs_s_type *pdcs,
   wms_teleservice_e_type ts
);

static wms_teleservice_e_type OEMWMS_GetGSMMessageType
(
   wms_gw_dcs_s_type *pdcs
);

static boolean OEMWMS_ConstructClientBD 
(
   OEMMsgData * pMsgData,
   OEMMsgPayload * pMsgPayload,
   wms_client_ts_data_s_type * pClientTS,
   sys_sys_mode_e_type sysMode
);

static boolean OEMWMS_SetCDMAAddress(wms_address_s_type * psadr, char* pszAddress);

static boolean OEMWMS_ConstructClientMessage 
(
   OEMMsgData * pMsgData,
   wms_client_message_s_type * pMsg,
   wms_raw_ts_data_s_type * pRaw,
   sys_sys_mode_e_type sysMode
);
 
static boolean OEMWMS_ConstructCDMATemplate
(
   OEMMsgData * pMsgData, 
   wms_client_message_s_type * pMsg, 
   wms_client_bd_s_type * pClientBD
);

static boolean OEMWMS_ConstructGWTemplate
(
   OEMMsgData * pMsgData, 
   wms_client_message_s_type * pMsg
);

static boolean OEMWMS_SetGWAddress(wms_address_s_type * padr, char * pszAddress);

static boolean OEMWMS_SetGWSCAddress(wms_address_s_type * pscadr, char * pszSCAddress);

static uint32 OEMWMS_GetTimeFromWmsTimestamp(wms_timestamp_s_type *pTime);

static void OEMWMS_SetTimeToWmsTimestamp(wms_timestamp_s_type *pTime, uint32 ts);

static void OEMWMS_AckCDMAMessage
(
   wms_transaction_id_type tid,
   wms_error_class_e_type eErr,
   wms_cdma_tl_status_e_type eStatus
);

static void OEMWMS_AckGSMMessage
(
   wms_transaction_id_type tid,
   wms_gw_tpdu_type_e_type tpdu_type,
   wms_gw_deliver_report_ack_s_type * pAckInfo
);

static void OEMWMS_NackGSMMessage
(
   wms_transaction_id_type tid,
   wms_gw_tpdu_type_e_type tpdu_type,
   wms_gw_deliver_report_error_s_type * pError
);

static void OEMWMS_StoreSMSListener
(
   wms_msg_event_info_s_type * info_ptr
);

static void OEMWMS_DeleteSMSListener
(
   wms_msg_event_info_s_type * info_ptr
);

static void OEMWMS_ReadSMSListener
(
   wms_msg_event_info_s_type * info_ptr
);

static void OEMWMS_GetMemoryStatus(wms_memory_store_e_type wmsMemoryStore);

static void OEMWMS_GetMessageList(wms_memory_store_e_type wmsMemoryStore);

static void OEMWMS_ReleaseStoreSMS( AEECallback *pcb );

static void OEMWMS_StoreSMS( OEMMsg* hMsg, AEECallback *pcb, uint32 *pdwStatus );

static void OEMWMS_DeleteStoreSMS(OEMMsg * hMsg);

static void OEMWMS_ReleaseReadSMS( AEECallback *pcb );

static void OEMWMS_ReadSMS( OEMReadMsg* hMsg, AEECallback *pcb, uint32 *pdwStatus, OEMMsgData *pMsgData, OEMMsgPayload *pMsgPayload, uint32 nIndex, int st );

static void OEMWMS_DeleteReadSMS(OEMReadMsg * hMsg);

static void OEMWMS_ReleaseDeleteSMS( AEECallback *pcb );

static void OEMWMS_DeleteSMS( OEMDeleteMsg* hMsg, AEECallback *pcb, uint32 *pdwStatus, uint32 nIndex, wms_memory_store_e_type wmsMemoryStore, wms_message_tag_e_type wmsMessageTag);

static void OEMWMS_DeleteDeleteSMS(OEMDeleteMsg * hMsg);

static wms_status_e_type OEMSMS_GetMsgAckStatus(uint32 ts);

static wms_status_e_type OEMWMS_SendSMSOnTrafficChannel(void);

static int OEMWMS_GetUDHSize(int nNumHeaders, wms_udh_s_type udh[]);

static void OEMWMS_GetUDHData(int nNumHeaders, wms_udh_s_type udh[], byte * pBuffer);

static void OEMWMS_ProcessUDHData(wms_client_ts_data_s_type * pctsdata, byte * pBuffer, int nBytes);

static int OEMWMS_SetUDHData(int nMaxHeaders, wms_udh_s_type udh[], byte * pBuffer, int nBytes);

static void OEMWMS_SetMsgTransferRoute(void);

static void OEMWMS_GetDomainPref(void);

static void OEMWSMS_NoopCommandCallback 
(
   wms_cmd_id_e_type cmd, 
   void * user_data, 
   wms_cmd_err_e_type cmd_err 
);

static uint32 Xlate_TS(wms_teleservice_e_type ts);
static uint32 Xlate_Lang(wms_language_e_type lang);
static uint32 Xlate_Tag(wms_message_tag_e_type tag);
static int Xlate_Priority(wms_priority_e_type priority);
static int Xlate_Privacy(wms_privacy_e_type privacy);
static int Xlate_Encoding(wms_user_data_encoding_e_type enc);
static int Xlate_StorageType(wms_memory_store_e_type st);
static int Xlate_DomainPref(wms_gw_domain_pref_e_type dp);

static int Xlate_wms_status_e_type_2_MOSMS_ERR( wms_status_e_type e );
static int Xlate_wms_cdma_tl_status_e_type_2_MOSMS_ERR( wms_cdma_tl_status_e_type e );
static int Xlate_wms_report_status_e_type_2_MOSMS_ERR( wms_report_status_e_type e );
static int Xlate_wms_tp_cause_e_type_2_MOSMS_ERR( wms_tp_cause_e_type e );
static int Xlate_wms_error_class_e_type_2_MOSMS_ERRTYPE( wms_error_class_e_type e );
static AEESMSMsgWaitingType Xlate_MsgWaitingType(wms_gw_msg_waiting_e_type dt);
static AEESMSMsgWaitingKind Xlate_MsgWaitingKind(wms_gw_msg_waiting_kind_e_type dk);

static wms_teleservice_e_type Xlate_2_NativeTS(uint32 ts);
static wms_user_data_encoding_e_type Xlate_2_NativeEncoding( int enc );
static wms_priority_e_type Xlate_2_NativePriority(int priority);
static wms_privacy_e_type Xlate_2_NativePrivacy(int privacy);
static wms_language_e_type Xlate_2_NativeLang(int lang);
static wms_message_tag_e_type Xlate_2_NativeTag(int tag);
static wms_memory_store_e_type Xlate_2_NativeStorageType(int st);
static wms_udh_id_e_type Xlate_2_NativeUDHId(AEESMSUDHId id);
static wms_gw_msg_waiting_e_type Xlate_2_NativeMsgWaitingType(AEESMSMsgWaitingType at);
static wms_gw_msg_waiting_kind_e_type Xlate_2_NativeMsgWaitingKind(AEESMSMsgWaitingKind ak);
static wms_gw_domain_pref_e_type Xlate_2_NativeDomainPref(int dp);
static int Xlate_wms_status_2_AEEErrorCode(wms_status_e_type st);
static int Xlate_wms_cmd_err_2_AEEErrorCode(wms_cmd_err_e_type cmd_err);

static SMSCacheEntry sce;

#ifdef FEATURE_BREW_BROADCAST_SMS

#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
static wms_message_mode_e_type Xlate_AEESMSMode_2_wms_message_mode(AEESMSMode mode);
static void OEMWSMSBCMMConfig_EventCallback(wms_bc_mm_event_e_type event, wms_bc_mm_event_info_s_type *info_ptr);
static boolean ConvertAEESMSBCSrvIDToWMSBCMMSrvID( AEESMSBCSrvID *pSrvID, wms_message_mode_e_type mode, wms_bc_mm_srv_id_type *service_id);
static boolean ConvertWMSBCMMSrvIDToAEESMSBCSrvID(wms_bc_mm_srv_id_type *service_id, wms_message_mode_e_type msg_mode, AEESMSBCSrvID *pSrvID);
static boolean ConvertOEMSMSBCSrvInfoToWMSBCMMSrvInfo(OEMSMSBCSrvInfo *pSrvInfo, wms_message_mode_e_type mode, wms_bc_mm_service_info_s_type *srv_info);
static boolean ConvertWMSBCMMSrvInfoToOEMSMSBCSrvInfo(wms_bc_mm_service_info_s_type *srv_info, wms_message_mode_e_type msg_mode, OEMSMSBCSrvInfo *pSrvInfo);
#endif // FEATURE_BROADCAST_SMS_MULTIMODE

static void OEMWSMSBCConfig_CommandCallback(wms_cmd_id_e_type cmd, void *user_data, wms_cmd_err_e_type cmd_err);
static void OEMWSMSBCConfig_EventCallback(wms_bc_event_e_type event, wms_bc_event_info_s_type *info_ptr);
static boolean ConvertAEESMSBCSrvIDToWMSBCSrvID( AEESMSBCSrvID *pSrvID, wms_message_mode_e_type mode, wms_bc_service_id_s_type *service_id);
static boolean ConvertWMSBCSrvIDToAEESMSBCSrvID(wms_bc_service_id_s_type *service_id, wms_message_mode_e_type msg_mode, AEESMSBCSrvID *pSrvID);
static boolean ConvertOEMSMSBCSrvInfoToWMSBCSrvInfo(OEMSMSBCSrvInfo *pSrvInfo, wms_message_mode_e_type mode, wms_bc_service_info_s_type *srv_info);
static boolean ConvertWMSBCSrvInfoToOEMSMSBCSrvInfo(wms_bc_service_info_s_type *srv_info, wms_message_mode_e_type msg_mode, OEMSMSBCSrvInfo *pSrvInfo);
#endif // FEATURE_BREW_BROADCAST_SMS

/*===========================================================================

  Called as part of SMS initialization. Registers message, event and status
  listeners with SMS task

===========================================================================*/
int OEMSMS_Init( void )
{
   int nErr, i;

   FARF(SMS, ("==> OEMSMS_Init"));

   if (gpWms)
      return SUCCESS;

   if ((gpWms = sys_malloc(sizeof(OEMWms))) == NULL)
      return ENOMEMORY;

   gpWms->clientId = WMS_DUMMY_CLIENT_ID;
   
   if ((nErr = wms_client_init(WMS_CLIENT_TYPE_BREW, &gpWms->clientId)) != WMS_CLIENT_ERR_NONE)
   {
      FARF(SMS, ("wms_client_init err=%d", nErr));
      goto Done;
   }

   if ((nErr = wms_client_reg_msg_cb(gpWms->clientId, OEMWMS_MessageListener)) != WMS_CLIENT_ERR_NONE)
   {
      FARF(SMS, ("wms_client_reg_msg_cb err=%d",nErr));
      goto Done;
   }
   
   if ((nErr = wms_client_reg_cfg_cb(gpWms->clientId, OEMWMS_CfgListener)) != WMS_CLIENT_ERR_NONE)
   {
      FARF(SMS, ("wms_client_reg_cfg_cb err=%d",nErr));
      goto Done;
   }

#ifdef FEATURE_CDSMS
   if ((nErr = wms_client_reg_dc_cb(gpWms->clientId, OEMWMS_EventListener)) != WMS_CLIENT_ERR_NONE)
   {
      FARF(SMS, ("wms_client_reg_dc_cb err=%d", nErr));
      goto Done;
   }
#endif /*FEATURE_CDSMS*/

   if ((nErr = wms_client_reg_parse_msg_cb(gpWms->clientId, OEMWMS_PreProcessor)) != WMS_CLIENT_ERR_NONE)
   {
      FARF(SMS, ("wms_client_reg_parse_msg_cb err=%d",nErr));
      goto Done;
   }
   
#ifdef FEATURE_BREW_BROADCAST_SMS
#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
   if ((nErr = wms_client_reg_bc_mm_cb(gpWms->clientId, OEMWSMSBCMMConfig_EventCallback)) != WMS_CLIENT_ERR_NONE)
   {
      FARF(SMS, ("wms_client_reg_bc_mm_cb err=%d",nErr));
      goto Done;
   }

#ifndef FEATURE_CDSMS_BROADCAST
   // This mean we use old API for CDMA BC
   if ((nErr = wms_client_reg_bc_cb(gpWms->clientId, OEMWSMSBCConfig_EventCallback)) != WMS_CLIENT_ERR_NONE)
   {
      FARF(SMS, ("wms_client_reg_bc_cb err=%d",nErr));
      goto Done;
   }
#endif // !FEATURE_CDSMS_BROADCAST
#else  // FEATURE_BROADCAST_SMS_MULTIMODE
   if ((nErr = wms_client_reg_bc_cb(gpWms->clientId, OEMWSMSBCConfig_EventCallback)) != WMS_CLIENT_ERR_NONE)
   {
      FARF(SMS, ("wms_client_reg_bc_cb err=%d",nErr));
      goto Done;
   }
#endif // FEATURE_BROADCAST_SMS_MULTIMODE
#endif // FEATURE_BREW_BROADCAST_SMS 

   for (i = 0; i < AEESMS_STORAGE_LAST; i++)
   {
      gpWms->bStrInit[i] = FALSE;
      gpWms->ucStrSMSCount[i] = WMS_MESSAGE_LIST_MAX;
   }

   if ((nErr = wms_client_activate(gpWms->clientId)) != WMS_CLIENT_ERR_NONE)
   {
      FARF(SMS, ("wms_client_activate err=%d", nErr));
      goto Done;
   }

   if (OEM_GetConfig(CFGI_BREWDIR_SMS_TELESERVICE, (void*)&gpWms->dwBREWDirectedTS, sizeof(gpWms->dwBREWDirectedTS)) != SUCCESS)
      gpWms->dwBREWDirectedTS = 0;
   
   if (OEM_GetConfig(CFGI_SMS_MO_ON_ACCESS_CHANNEL, (void*)&gpWms->bMOOnAccessChannel, sizeof(gpWms->bMOOnAccessChannel)) != SUCCESS)
      gpWms->bMOOnAccessChannel = FALSE;   // Disable by default

   if (OEM_GetConfig(CFGI_SMS_MO_ON_TRAFFIC_CHANNEL, (void*)&gpWms->bMOOnTrafficChannel, sizeof(gpWms->bMOOnTrafficChannel)) != SUCCESS)
      gpWms->bMOOnTrafficChannel = TRUE;   // Enable by default

Done:
   if (nErr != WMS_CLIENT_ERR_NONE)
   {
      nErr = EFAILED;
      OEMSMS_Cleanup();
   }
   else
      nErr = SUCCESS;

   return nErr;
}

/*===========================================================================

  Called by SMS task to handle incoming SMS message.  Cache the message
  and notify the registered handler...

===========================================================================*/
void OEMWMS_MessageListener
( 
   wms_msg_event_e_type event,
   wms_msg_event_info_s_type * info_ptr,
   boolean * pshared 
)
{
   FARF(SMS, ("==> OEMWMS_MessageListener"));

   if (pshared)
   {
      *pshared = TRUE;
   }

   switch (event)
   {
      case WMS_MSG_EVENT_RECEIVED_MESSAGE:
      {
         SMSCacheEntry * pce = NULL;
         wms_message_mode_e_type eMsgMode = info_ptr->mt_message_info.message.msg_hdr.message_mode;
         wms_transaction_id_type tid = info_ptr->mt_message_info.transaction_id;

         if (OEMSMS_IsInitialized() == FALSE) 
         {
            FARF(SMS, ("SMS object not present"));      
            FARF(SMS, ("Rejected SMS Msg (Id = %d)", tid));
         
            if (eMsgMode == WMS_MESSAGE_MODE_CDMA)
            {
               OEMWMS_AckCDMAMessage(tid, WMS_ERROR_TEMP, WMS_TL_DESTINATION_OUT_OF_SERVICE_S);
            }
            else if (eMsgMode == WMS_MESSAGE_MODE_GW)
            {
               wms_gw_deliver_report_error_s_type error;
               MEMSET(&error, 0, sizeof(error));
               error.tp_cause = WMS_TP_CAUSE_UNSPECIFIED_ERROR;
               OEMWMS_NackGSMMessage(tid, info_ptr->mt_message_info.message.u.gw_message.raw_ts_data.tpdu_type, &error);
            }
            return;
         }

         FARF(SMS, ("Received SMS Msg (Id = %d)", tid));

         if (eMsgMode == WMS_MESSAGE_MODE_CDMA)
         {
            FARF(SMS, ("Message Teleservice Id = %x", info_ptr->mt_message_info.message.u.cdma_message.teleservice));
         }

         // Get a buffer to copy
         pce = OEMSMSCache_GetEntry();

         if (pce == NULL) 
         {
            // Ooops, we do not have any free Cache Entry's available!
            FARF(SMS, ("No Cache Entry available, SMS Msg (Id = %d) Discarded", tid));         
         
            if (eMsgMode == WMS_MESSAGE_MODE_CDMA)
            {
               OEMWMS_AckCDMAMessage(tid, WMS_ERROR_TEMP, WMS_TL_DESTINATION_BUSY_S);
            }            
            else if (eMsgMode == WMS_MESSAGE_MODE_GW)
            {
               wms_gw_deliver_report_error_s_type error;
               MEMSET(&error, 0, sizeof(error));
               error.tp_cause = WMS_TP_CAUSE_UNSPECIFIED_ERROR;
               OEMWMS_NackGSMMessage(tid, info_ptr->mt_message_info.message.u.gw_message.raw_ts_data.tpdu_type, &error);
            }
            return;
         }

         // Decode the incoming message and populate the Cache Entry

         // If it's not a valid message, exit
         if (OEMWMS_CopyMessage(info_ptr->mt_message_info.transaction_id,&info_ptr->mt_message_info.message,pce) == FALSE) 
         {
            OEMSMSCache_Release(pce);     
         
            FARF(SMS, ("Error processing MT SMS Msg (Id = %d)", tid));          
         
            if (eMsgMode == WMS_MESSAGE_MODE_CDMA)
            {
               OEMWMS_AckCDMAMessage(tid, WMS_ERROR_TEMP, WMS_TL_INVALID_TELESERVICE_ID_S);
            }            
            else if (eMsgMode == WMS_MESSAGE_MODE_GW)
            {
               wms_gw_deliver_report_error_s_type error;
               MEMSET(&error, 0, sizeof(error));
               error.tp_cause = WMS_TP_CAUSE_UNSPECIFIED_ERROR;
               OEMWMS_NackGSMMessage(tid, info_ptr->mt_message_info.message.u.gw_message.raw_ts_data.tpdu_type, &error);
            }
         }
         else
         {    
            wms_status_e_type eStatus = OEMSMS_GetMsgAckStatus(pce->ts);

            OEMSMSCache_Ready(pce);

            if (eMsgMode == WMS_MESSAGE_MODE_CDMA)
            {
               if (info_ptr->mt_message_info.message.u.cdma_message.is_tl_ack_requested)
               {
                  FARF(SMS, ("ACK requested and sent for Msg (Id = %d)", tid));
                  OEMWMS_AckCDMAMessage(tid, (eStatus == WMS_OK_S ? WMS_ERROR_NONE : WMS_ERROR_PERM), eStatus);
               } 
               else 
               {
                  FARF(SMS, ("No ACK requested for MT SMS Msg (Id = %d)", tid));
               }
            }
            else if (eMsgMode == WMS_MESSAGE_MODE_GW)
            {
               if (eStatus == WMS_OK_S)
               {
                  wms_gw_deliver_report_ack_s_type ack;
                  MEMSET(&ack, 0, sizeof(ack));
                  OEMWMS_AckGSMMessage(tid, info_ptr->mt_message_info.message.u.gw_message.raw_ts_data.tpdu_type, &ack);
               }
               else
               {               
                  wms_gw_deliver_report_error_s_type error;
                  MEMSET(&error, 0, sizeof(error));
                  error.tp_cause = WMS_TP_CAUSE_MEMORY_FULL;
                  OEMWMS_NackGSMMessage(tid, info_ptr->mt_message_info.message.u.gw_message.raw_ts_data.tpdu_type, &error);
               }
            }
         }
      }
      break;

      case WMS_MSG_EVENT_SEND:
         if (info_ptr->status_info.client_id == gpWms->clientId)
         {
            OEMWMS_MoMessageListener(event, info_ptr, pshared);
         }
         break;

      case WMS_MSG_EVENT_SUBMIT_REPORT:
         if (info_ptr->submit_report_info.client_id == gpWms->clientId)
         {
            OEMWMS_MoMessageListener(event, info_ptr, pshared);
         }
         break;

      case WMS_MSG_EVENT_WRITE:
         if (info_ptr->status_info.client_id == gpWms->clientId)
         {
            OEMWMS_StoreSMSListener(info_ptr);
         }
         break;

      case WMS_MSG_EVENT_DELETE_ALL:
      case WMS_MSG_EVENT_DELETE:
         if (info_ptr->status_info.client_id == gpWms->clientId)
         {
            OEMWMS_DeleteSMSListener(info_ptr);
         }
         break;

      case WMS_MSG_EVENT_READ:
         if (info_ptr->status_info.client_id == gpWms->clientId)
         {
            OEMWMS_ReadSMSListener(info_ptr);
         }
         break;

      default:
         break;
   }
}

/*===========================================================================

  Invoked to pass along the configuration events from the WMS

===========================================================================*/
static void OEMWMS_CfgListener
(
   wms_cfg_event_e_type event,
   wms_cfg_event_info_s_type *info_ptr
)
{
   switch(event)
   {
      case WMS_CFG_EVENT_CDMA_READY:
         OEMWMS_SetMsgTransferRoute();
         OEMWMS_GetMemoryStatus(WMS_MEMORY_STORE_RUIM);
         OEMWMS_GetMemoryStatus(WMS_MEMORY_STORE_NV_CDMA);
         break;

      case WMS_CFG_EVENT_GW_READY:
         OEMWMS_GetDomainPref();
         OEMWMS_SetMsgTransferRoute();
         OEMWMS_GetMemoryStatus(WMS_MEMORY_STORE_SIM);
         OEMWMS_GetMemoryStatus(WMS_MEMORY_STORE_NV_GW);
         break;

      case WMS_CFG_EVENT_MEMORY_STATUS:
         {
            int nStrIdx = Xlate_StorageType(info_ptr->memory_status.mem_store);

            // If Storage isn't initialized, calculate max slots for Storage and get 
            // message tag information for occupied slots
            if ((nStrIdx < AEESMS_STORAGE_LAST) && !gpWms->bStrInit[nStrIdx])
            {
               gpWms->ucStrSMSCount[nStrIdx] = info_ptr->memory_status.max_slots;
               OEMWMS_GetMessageList(info_ptr->memory_status.mem_store);
            }
         }
         break;

      case WMS_CFG_EVENT_MESSAGE_LIST:
         {
            int nStrIdx = Xlate_StorageType(info_ptr->message_list.mem_store);

            if (nStrIdx < AEESMS_STORAGE_LAST)
            {
               int i = 0;
               uint32 index = 0; //which index are occupied

               // First set all the msgType for all the elements in strSMSMsgList[nStrIdx]
               // as avaiable. Then for the indexes returned in the message list, 
               // assign the proper tags. This way applet will know which slots are 
               // occupied and which are available
               MEMSET((void*)gpWms->strSMSMsgList[nStrIdx], 0, sizeof(gpWms->strSMSMsgList[nStrIdx]));
            
               for ( i = 0; i < info_ptr->message_list.len; i++) 
               {               
                  index = info_ptr->message_list.indices[i];
                  gpWms->strSMSMsgList[nStrIdx][index] = (uint8) info_ptr->message_list.tags[i];            
               }
               gpWms->bStrInit[nStrIdx] = TRUE;
            }
         }
         break;
     
      case WMS_CFG_EVENT_GW_DOMAIN_PREF:
         if (gpWms)
         {
            gpWms->gwDomainPref = info_ptr->gw_domain_pref;
         }
         break;

      default:
         break;
   }
}

/*===========================================================================

  Called to ack CDMA message

===========================================================================*/
static void OEMWMS_AckCDMAMessage
(
   wms_transaction_id_type tid,
   wms_error_class_e_type eErr,
   wms_cdma_tl_status_e_type eStatus
)
{
   wms_ack_info_s_type ackInfo;

   MEMSET(&ackInfo, 0, sizeof(ackInfo));

   ackInfo.transaction_id = tid;
   ackInfo.message_mode = WMS_MESSAGE_MODE_CDMA;
   ackInfo.u.cdma.error_class = eErr;
   ackInfo.u.cdma.tl_status = eStatus;

   wms_msg_ack( gpWms->clientId, &OEMWSMS_NoopCommandCallback, NULL, &ackInfo );
}

/*===========================================================================

  Called to ack GSM message

===========================================================================*/
static void OEMWMS_AckGSMMessage
(
   wms_transaction_id_type tid,
   wms_gw_tpdu_type_e_type tpdu_type,
   wms_gw_deliver_report_ack_s_type * pAck
)
{
   wms_ack_info_s_type ackInfo;

   MEMSET(&ackInfo, 0, sizeof(ackInfo));

   ackInfo.transaction_id = tid;
   ackInfo.message_mode = WMS_MESSAGE_MODE_GW;

   ackInfo.u.gw.success = TRUE;
   ackInfo.u.gw.tpdu_type = tpdu_type;
   MEMCPY(&ackInfo.u.gw.u.ack, pAck, sizeof(ackInfo.u.gw.u.ack));

   wms_msg_ack( gpWms->clientId, &OEMWSMS_NoopCommandCallback, NULL, &ackInfo );
}

/*===========================================================================

  Called to nack GSM message

===========================================================================*/
static void OEMWMS_NackGSMMessage
(
   wms_transaction_id_type tid,
   wms_gw_tpdu_type_e_type tpdu_type,
   wms_gw_deliver_report_error_s_type * pError
)
{
   wms_ack_info_s_type ackInfo;

   MEMSET(&ackInfo, 0, sizeof(ackInfo));

   ackInfo.transaction_id = tid;
   ackInfo.message_mode = WMS_MESSAGE_MODE_GW;

   ackInfo.u.gw.success = FALSE;
   ackInfo.u.gw.tpdu_type = tpdu_type;
   MEMCPY(&ackInfo.u.gw.u.error, pError, sizeof(ackInfo.u.gw.u.error));

   wms_msg_ack( gpWms->clientId, &OEMWSMS_NoopCommandCallback, NULL, &ackInfo );
}

/*===========================================================================

  Gives a chance to us to ensure that message isn't shared with any one else.
  Use this to make sure that BREW directed messages aren't shared.

===========================================================================*/
static void OEMWMS_PreProcessor
( 
   const wms_client_message_s_type * pCMsg, 
   boolean * pshared 
)
{
   wms_status_e_type decodeStatus;
   wms_client_ts_data_s_type * pctsdata = NULL;

   FARF(SMS, ("==> OEMWMS_PreProcessor"));   
   
   if (!pshared)
   {   
      FARF(SMS, ("pshared == 0 in OEMWMS_PreProcessor"));   
      return;
   }

   MEMSET(&sce, 0, sizeof(sce));

   pctsdata = (wms_client_ts_data_s_type *)sce.data;
 
   *pshared = TRUE;

   if( pCMsg->msg_hdr.message_mode == WMS_MESSAGE_MODE_CDMA)
   {
      wms_cdma_message_s_type * pm = (wms_cdma_message_s_type *)&pCMsg->u.cdma_message;
      wms_client_bd_s_type *pcd = (wms_client_bd_s_type *)&pctsdata->u.cdma;
         
      FARF(SMS,("SMS Len: %d, Format: %d",pm->raw_ts.len, pm->raw_ts.format));

      decodeStatus = wms_ts_decode(&pm->raw_ts, pctsdata);

      if ((decodeStatus == WMS_OK_S)                             &&
          (pcd->mask & WMS_MASK_BD_USER_DATA)                    && 
          ((pm->teleservice == WMS_TELESERVICE_CMT_95)      ||
           ((pm->teleservice == WMS_TELESERVICE_CMT_91) &&
            (pcd->user_data.is91ep_type == WMS_IS91EP_SHORT_MESSAGE ||
             pcd->user_data.is91ep_type == WMS_IS91EP_SHORT_MESSAGE_FULL))))
      {
         char * pszText = NULL;

         sce.pText = (pcd->mask & WMS_MASK_BD_USER_DATA ? (byte*)pcd->user_data.data : NULL);
         sce.nText = (pcd->mask & WMS_MASK_BD_USER_DATA ? pcd->user_data.data_len : 0);
         sce.nEncoding = Xlate_Encoding(pcd->user_data.encoding);

         FARF(SMS, ("nText = %d, nEncoding = %d", sce.nText, sce.nEncoding));
         FARF(SMS, ("Text = %s", sce.pText));

         if ((pszText = (char*)AEE_GetDecodedTextString(sce.pText, sce.nText, sce.nEncoding, NULL, NULL)) != NULL)
         {
            if (AEE_IsBREWDirectedSMS(pszText) == TRUE)
               *pshared = FALSE;
            FREE(pszText);
         }
      }
   }
   else if ((pCMsg->msg_hdr.message_mode == WMS_MESSAGE_MODE_GW) &&
            (pCMsg->u.gw_message.raw_ts_data.tpdu_type == WMS_TPDU_DELIVER) &&
            (pCMsg->u.gw_message.is_broadcast != TRUE))
   {           
      wms_gw_message_s_type * pm = (wms_gw_message_s_type *)&pCMsg->u.gw_message;

      FARF(SMS,("SMS Len: %d, Format: %d",pm->raw_ts_data.len, pm->raw_ts_data.format));

      decodeStatus = wms_ts_decode(&pm->raw_ts_data, pctsdata);

      if ((decodeStatus == WMS_OK_S) &&
          (OEMWMS_DetermineGSMMessageType(&pctsdata->u.gw_pp) == WMS_TELESERVICE_CMT_95))
      {
         char * pszText = NULL;

         sce.pText = pctsdata->u.gw_pp.u.deliver.user_data.sm_data;
         sce.nText = pctsdata->u.gw_pp.u.deliver.user_data.sm_len;

         switch(pctsdata->u.gw_pp.u.deliver.dcs.alphabet)
         {
            case WMS_GW_ALPHABET_UCS2:
               sce.nEncoding = Xlate_Encoding(WMS_ENCODING_UNICODE);
               break;

            case WMS_GW_ALPHABET_8_BIT:
               sce.nEncoding = Xlate_Encoding(WMS_ENCODING_OCTET);
               break;

            default:
               sce.nEncoding = Xlate_Encoding(WMS_ENCODING_GSM_7_BIT_DEFAULT);
         }
         
         FARF(SMS, ("nText = %d, nEncoding = %d", sce.nText, sce.nEncoding));
         FARF(SMS, ("Text = %s", sce.pText));         
         
         if ((pszText = (char*)AEE_GetDecodedTextString(sce.pText, sce.nText, sce.nEncoding, NULL, NULL)) != NULL)
         {
            if (AEE_IsBREWDirectedSMS(pszText) == TRUE)
               *pshared = FALSE;
            FREE(pszText);
         }
      }
   }
}

/*===========================================================================

  Called by OEMWMS_MessageListener to copy incoming SMS message to SMS cache

===========================================================================*/
boolean OEMWMS_CopyMessage
( 
   wms_transaction_id_type transaction_id,
   wms_client_message_s_type *pCMsg,
   SMSCacheEntry *pce 
)
{
   wms_status_e_type decodeStatus;
   wms_teleservice_e_type ts;
   wms_client_ts_data_s_type * pctsdata = NULL;

   FARF(SMS, ("==> OEMWMS_CopyMessage"));   

   pctsdata = (wms_client_ts_data_s_type *)pce->data;
   
   if( pCMsg->msg_hdr.message_mode == WMS_MESSAGE_MODE_CDMA)
   {
      if (pCMsg->msg_hdr.tag != WMS_TAG_MO_TEMPLATE)
      {
      wms_cdma_message_s_type * pm = (wms_cdma_message_s_type *)&pCMsg->u.cdma_message;
      wms_client_bd_s_type *pcd = (wms_client_bd_s_type *)&pctsdata->u.cdma;
         
      FARF(SMS,("SMS Len: %d, Format: %d",pm->raw_ts.len, pm->raw_ts.format));

      // Check if message is MO SMS which will mean copy message was called
      // for processing an MO SMS read from storage
      pce->bIsMOSMS = pm->is_mo;

      decodeStatus = wms_ts_decode(&pm->raw_ts, pctsdata);

      // Only continue if we have bearer data (text) or it's a voice mail message
      // or an IS91 Page message. (We reject CPT-95, CMT-95 and IS91 Short Message
      // Types if the Message does not contain user data ).

         if (decodeStatus == WMS_OK_S)         
      {
         // If the teleservice of the message happens to be WMS_TELESERVICE_CMT_91
         // we shall map the teleservice to the teleservice corresponding 
         // to the Message Type of the embedded Analog IS91-EP message.
         // See section '4.3.2 IS-91 Extended Protocol Enhanced Services' of IS-637-B
         // for information about CMT_91 teleservice ( note that the section does not 
         // directly mention CMT_91 teleservice, but talks about how a IS91-EP message
         // can be embedded inside a SMS Deliver Message. )
         // CMT_91 teleservice is used to embed a IS-91 EP SMS message inside a SMS 
         // Deliver Message in a CDMA network.

         if (pm->teleservice == WMS_TELESERVICE_CMT_91) 
         {
            // A CMT_91 Teleservice message contains a embedded IS91 message
            // the is91ep_type in the user_data specifies the IS91 Message 
            // type ( See Section 4.5.2 of IS637-B ).

            if (pcd->user_data.is91ep_type == WMS_IS91EP_CLI_ORDER) 
            {
               ts = WMS_TELESERVICE_IS91_PAGE; 
            } 
            else if (pcd->user_data.is91ep_type == WMS_IS91EP_VOICE_MAIL) 
            {
               ts = WMS_TELESERVICE_IS91_VOICE_MAIL;
            } 
            else if (pcd->user_data.is91ep_type == WMS_IS91EP_SHORT_MESSAGE ||
                     pcd->user_data.is91ep_type == WMS_IS91EP_SHORT_MESSAGE_FULL) 
            {
               ts = WMS_TELESERVICE_IS91_SHORT_MESSAGE;
            } 
            else 
            {
               // This should never happen, but better safe than sorry....
               FARF(SMS, ("CMT_91 Msg with unknown IS91-EP Message Type %d", pcd->user_data.is91ep_type));
               FARF(SMS, ("Rejecting CMT_91 Msg"));
               return(FALSE);
            }
         }
         else
         {
            ts = pm->teleservice;
         }
      
         pce->ts  = Xlate_TS(ts);
         pce->pText = (pcd->mask & WMS_MASK_BD_USER_DATA ? (byte*)pcd->user_data.data : NULL);
         pce->nText = (pcd->mask & WMS_MASK_BD_USER_DATA ? pcd->user_data.data_len : 0);
         
         if (ts == WMS_TELESERVICE_WAP)
         {
            pce->nEncoding = AEESMS_ENC_OCTET;
         }
         else
         {
            pce->nEncoding = Xlate_Encoding(pcd->user_data.encoding);
         }

         // Before rest of the processing, let's ensure that if message is BREW directed,
         // its sent with teleservice ID designated for BREW directed messages
         if (gpWms->dwBREWDirectedTS && pce->pText && pce->nText &&
             (ts == WMS_TELESERVICE_CMT_95 || ts == WMS_TELESERVICE_IS91_SHORT_MESSAGE))
         {
            char * pszText = NULL;

            if (((pszText = (char*)AEE_GetDecodedTextString(pce->pText, pce->nText, pce->nEncoding, NULL, NULL)) != NULL) &&
               (AEE_IsBREWDirectedSMS(pszText) == TRUE) &&
               (ts != gpWms->dwBREWDirectedTS))
            { 
               // Reject messages which are BREW directed but aren't sent with 
               // teleservice ID designated for BREW directed messages
               FREE(pszText);
               return FALSE;  
            }

            if (pszText)         
               FREE(pszText);
         }

         pce->nPriority = Xlate_Priority(pcd->priority);
         pce->nPrivacy = Xlate_Privacy(pcd->privacy);
         pce->dwLang = Xlate_Lang(pcd->language);
         pce->bRequestDLAck = pcd->reply_option.delivery_ack_requested;
         pce->bRequestUserAck = pcd->reply_option.user_ack_requested;
            pce->bRequestReadAck = pcd->reply_option.read_ack_requested;
         pce->dwTag = Xlate_Tag(pCMsg->msg_hdr.tag);
            pce->dwMsgID = pcd->message_id.id_number;      
            pce->bIsDLAck = (boolean)(WMS_BD_TYPE_DELIVERY_ACK == pcd->message_id.type);
            pce->bIsUserAck = (boolean)(WMS_BD_TYPE_USER_ACK == pcd->message_id.type);
            pce->bIsReadAck = (boolean)(WMS_BD_TYPE_READ_ACK == pcd->message_id.type);
         pce->bIsSCAddress = FALSE;

         if (OEMWMS_GetNumMsgsInfoFromCDMABDMsg (pcd, ts, &pce->nNumMsgs) == FALSE)
            return FALSE;

         if (OEMWMS_GetCallBackNumberFromCDMABDMsg(pcd, ts, pce->szCallback) == FALSE)
            return FALSE;

            OEMWMS_GetAddressString((byte*)pm->address.digits, pm->address.number_of_digits,
                                      pm->address.digit_mode, pm->address.number_type,
                                    ts, pce->szFrom);

         FARF(SMS, ("tid = %d, nText = %d, nEncoding = %d", pce->dwTransactionId, pce->nText, pce->nEncoding));
         FARF(SMS, ("Text = %s", pce->pText));
         FARF(SMS, ("nPriority = %d, nPrivacy = %d, dwLang = %d", pce->nPriority, pce->nPrivacy, pce->dwLang));
         FARF(SMS, ("Callback = %s", (char*)(*pce->szCallback ? pce->szCallback : "Unknown")));
         
         if (pce->bIsMOSMS)
         {
               pce->dwTimeStamp = OEMWMS_GetTimeFromWmsTimestamp(&pcd->validity_relative);         
               FARF(SMS, ("RelativeValidity = %d", pce->dwTimeStamp));
            FARF(SMS, ("To = %s", (char*)(*pce->szFrom ? pce->szFrom : "Unknown")));
         }
         else
         {
               pce->dwTimeStamp = OEMWMS_GetTimeFromWmsTimestamp(&pcd->mc_time);         
               FARF(SMS, ("TimeStamp = %d, nNumMsgs = %d", pce->dwTimeStamp, pce->nNumMsgs));
            FARF(SMS, ("From = %s", (char*)(*pce->szFrom ? pce->szFrom : "Unknown")));
         }

         return(TRUE);
      }
      FARF(SMS, ("Teleservice %d Msg has no UserData",pce->ts));
   }
      else
      {
         wms_cdma_template_s_type * pm = (wms_cdma_template_s_type *)&pCMsg->u.cdma_template;
         wms_client_bd_s_type *pcd = (wms_client_bd_s_type *)&pctsdata->u.cdma;

         MEMCPY(pcd, &pm->client_bd, sizeof(wms_client_bd_s_type));

         // Only continue if we have bearer data (text)
         if ((pm->mask & WMS_CDMA_TEMPLATE_MASK_BEARER_DATA) &&
             (pm->teleservice == WMS_TELESERVICE_CMT_95)) 
         {
            pce->ts  = Xlate_TS(pm->teleservice);
            pce->pText = (pcd->mask & WMS_MASK_BD_USER_DATA ? (byte*)pcd->user_data.data : NULL);
            pce->nText = (pcd->mask & WMS_MASK_BD_USER_DATA ? pcd->user_data.data_len : 0);
            pce->nEncoding = Xlate_Encoding(pcd->user_data.encoding);
            pce->nPriority = Xlate_Priority(pcd->priority);
            pce->nPrivacy = Xlate_Privacy(pcd->privacy);
            pce->dwLang = Xlate_Lang(pcd->language);
            pce->bRequestDLAck = pcd->reply_option.delivery_ack_requested;
            pce->bRequestUserAck = pcd->reply_option.user_ack_requested;
            pce->bRequestReadAck = pcd->reply_option.read_ack_requested;
            pce->dwTag = Xlate_Tag(pCMsg->msg_hdr.tag);
            pce->dwMsgID = pcd->message_id.id_number;      
            pce->bIsDLAck = (boolean)(WMS_BD_TYPE_DELIVERY_ACK == pcd->message_id.type);
            pce->bIsUserAck = (boolean)(WMS_BD_TYPE_USER_ACK == pcd->message_id.type);
            pce->bIsReadAck = (boolean)(WMS_BD_TYPE_READ_ACK == pcd->message_id.type);
            pce->bIsSCAddress = FALSE;

            if (OEMWMS_GetCallBackNumberFromCDMABDMsg(pcd, ts, pce->szCallback) == FALSE)
               return FALSE;

            FARF(SMS, ("tid = %d, nText = %d, nEncoding = %d", pce->dwTransactionId, pce->nText, pce->nEncoding));
            FARF(SMS, ("Text = %s", pce->pText));
            FARF(SMS, ("nPriority = %d, nPrivacy = %d, dwLang = %d", pce->nPriority, pce->nPrivacy, pce->dwLang));
            FARF(SMS, ("Callback = %s", (char*)(*pce->szCallback ? pce->szCallback : "Unknown")));

            if (pm->mask & WMS_CDMA_TEMPLATE_MASK_DEST_ADDR)
            {
               OEMWMS_GetAddressString((byte*)pm->address.digits, pm->address.number_of_digits,
                                            pm->address.digit_mode, pm->address.number_type,
                                       ts, pce->szFrom);
               FARF(SMS, ("To = %s", (char*)(*pce->szFrom ? pce->szFrom : "Unknown")));
            }

            if (pm->mask & WMS_CDMA_TEMPLATE_MASK_VALIDITY)
            {
               pce->dwTimeStamp = OEMWMS_GetTimeFromWmsTimestamp(&pm->relative_validity);           
               FARF(SMS, ("RelativeValidity = %d", pce->dwTimeStamp));
            }
            return(TRUE);
         }
         FARF(SMS, ("Teleservice %d Msg has no UserData",pce->ts));
      }
   }
   else if( pCMsg->msg_hdr.message_mode == WMS_MESSAGE_MODE_GW)
   {   
      if (pCMsg->msg_hdr.tag != WMS_TAG_MO_TEMPLATE)
      {
      switch (pCMsg->u.gw_message.raw_ts_data.tpdu_type)
      {
         case WMS_TPDU_DELIVER:
            {
               wms_gw_message_s_type * pm = (wms_gw_message_s_type *)&pCMsg->u.gw_message;

               FARF(SMS,("SMS Len: %d, Format: %d",pm->raw_ts_data.len, pm->raw_ts_data.format));

               // If this is a broadcast message we shall reject it.
               if (pm->is_broadcast == TRUE) 
               {
                  FARF(SMS, ("Rejecting SMS Broadcast Msg (tid=%d)", transaction_id));
                  return(FALSE);
               }

               decodeStatus = wms_ts_decode(&pm->raw_ts_data, pctsdata);

               if (decodeStatus == WMS_OK_S)
               {
                     ts = OEMWMS_DetermineGSMMessageType(&pctsdata->u.gw_pp);
                  
                  if (ts == WMS_TELESERVICE_UNKNOWN)
                  {
                     FARF(SMS, ("GSM SMS with unknown teleservice (tid = %d)", transaction_id));
                     return(FALSE);
                  }

                  pce->ts = Xlate_TS(ts);
                  pce->pText = pctsdata->u.gw_pp.u.deliver.user_data.sm_data;
                  pce->nText = pctsdata->u.gw_pp.u.deliver.user_data.sm_len;

                  if (ts == WMS_TELESERVICE_WAP)
                  {
                        pce->nEncoding = AEESMS_ENC_OCTET;
                  }
                  else
                  {
                     switch(pctsdata->u.gw_pp.u.deliver.dcs.alphabet)
                     {
                        case WMS_GW_ALPHABET_UCS2:
                           pce->nEncoding = Xlate_Encoding(WMS_ENCODING_UNICODE);
                           break;

                        case WMS_GW_ALPHABET_8_BIT:
                           pce->nEncoding = Xlate_Encoding(WMS_ENCODING_OCTET);
                           break;

                        default:
                           pce->nEncoding = Xlate_Encoding(WMS_ENCODING_GSM_7_BIT_DEFAULT);
                     }
                  }

                     pce->dwTimeStamp = OEMWMS_GetTimeFromWmsTimestamp(&pctsdata->u.gw_pp.u.deliver.timestamp);

                  if (OEMWMS_GetNumMsgsInfoFromGWMsg((wms_gw_deliver_s_type *)&pctsdata->u.gw_pp.u.deliver, ts, &pce->nNumMsgs) == FALSE)
                     return FALSE;
         
                     OEMWMS_GetAddressString((byte*)pctsdata->u.gw_pp.u.deliver.address.digits, 
                                              pctsdata->u.gw_pp.u.deliver.address.number_of_digits,
                                              pctsdata->u.gw_pp.u.deliver.address.digit_mode,
                                              pctsdata->u.gw_pp.u.deliver.address.number_type,
                                             ts, pce->szFrom);

                     OEMWMS_GetAddressString((byte*)pCMsg->u.gw_message.sc_address.digits, 
                                              pCMsg->u.gw_message.sc_address.number_of_digits,
                                              pCMsg->u.gw_message.sc_address.digit_mode, 
                                              pCMsg->u.gw_message.sc_address.number_type,
                                             ts, pce->szCallback);
         
                  pce->dwTag = Xlate_Tag(pCMsg->msg_hdr.tag);
                  pce->bIsMOSMS = FALSE;
                  pce->bIsSCAddress = TRUE;

                  FARF(SMS, ("tid = %d, nText = %d, nEncoding = %d", pce->dwTransactionId, pce->nText, pce->nEncoding));
                  FARF(SMS, ("Text = %s", pce->pText));
                  FARF(SMS, ("TimeStamp = %d, nNumMsgs = %d", pce->dwTimeStamp, pce->nNumMsgs));
                  FARF(SMS, ("SCAddress = %s", (char*)(*pce->szCallback ? pce->szCallback : "Unknown")));
                  FARF(SMS, ("From = %s", (char*)(*pce->szFrom ? pce->szFrom : "Unknown")));
                  return(TRUE);
               }
               else
               {
                  FARF(SMS, ("Failed to decode (tid=%d)", transaction_id));
                  return(FALSE);
               }
            }

         case WMS_TPDU_SUBMIT:
            {
               // This will be used when a stored MO message is read from storage
               wms_gw_message_s_type * pm = (wms_gw_message_s_type *)&pCMsg->u.gw_message;

               FARF(SMS,("SMS Len: %d, Format: %d",pm->raw_ts_data.len, pm->raw_ts_data.format));

               decodeStatus = wms_ts_decode(&pm->raw_ts_data, pctsdata);

               if (decodeStatus == WMS_OK_S)
               {
                  ts = WMS_TELESERVICE_CMT_95;
                  pce->ts = Xlate_TS(ts);
                  pce->pText = pctsdata->u.gw_pp.u.submit.user_data.sm_data;
                  pce->nText = pctsdata->u.gw_pp.u.submit.user_data.sm_len;

                  switch(pctsdata->u.gw_pp.u.submit.dcs.alphabet)
                  {
                     case WMS_GW_ALPHABET_UCS2:
                        pce->nEncoding = Xlate_Encoding(WMS_ENCODING_UNICODE);
                        break;

                     case WMS_GW_ALPHABET_8_BIT:
                        pce->nEncoding = Xlate_Encoding(WMS_ENCODING_OCTET);
                        break;

                     default:
                        pce->nEncoding = Xlate_Encoding(WMS_ENCODING_GSM_7_BIT_DEFAULT);
                  }

                     if (pctsdata->u.gw_pp.u.submit.validity.format == WMS_GW_VALIDITY_RELATIVE)
                     {
                        pce->dwTimeStamp = OEMWMS_GetTimeFromWmsTimestamp(&pctsdata->u.gw_pp.u.submit.validity.u.time);
                     }
                  pce->nNumMsgs = 0;
         
                     OEMWMS_GetAddressString((byte*)pctsdata->u.gw_pp.u.submit.address.digits, 
                                              pctsdata->u.gw_pp.u.submit.address.number_of_digits,
                                              pctsdata->u.gw_pp.u.submit.address.digit_mode,
                                              pctsdata->u.gw_pp.u.submit.address.number_type,
                                             ts, pce->szFrom);

                     OEMWMS_GetAddressString((byte*)pCMsg->u.gw_message.sc_address.digits, 
                                              pCMsg->u.gw_message.sc_address.number_of_digits,
                                              pCMsg->u.gw_message.sc_address.digit_mode, 
                                              pCMsg->u.gw_message.sc_address.number_type,
                                             ts, pce->szCallback);
         
                  pce->dwTag = Xlate_Tag(pCMsg->msg_hdr.tag);
                  pce->bIsSCAddress = TRUE;
                  pce->bRequestDLAck = pctsdata->u.gw_pp.u.submit.status_report_enabled;
                     pce->bIsMOSMS = TRUE;

                  FARF(SMS, ("tid = %d, nText = %d, nEncoding = %d", pce->dwTransactionId, pce->nText, pce->nEncoding));
                  FARF(SMS, ("Text = %s", pce->pText));
                  FARF(SMS, ("TimeStamp = %d, nNumMsgs = %d", pce->dwTimeStamp, pce->nNumMsgs));
                  FARF(SMS, ("SCAddress = %s", (char*)(*pce->szCallback ? pce->szCallback : "Unknown")));
                  FARF(SMS, ("To = %s", (char*)(*pce->szFrom ? pce->szFrom : "Unknown")));
                  return(TRUE);
               }
               else
               {
                  FARF(SMS, ("Failed to decode (tid=%d)", transaction_id));
                  return(FALSE);
               }
            }

            case WMS_TPDU_STATUS_REPORT:
               {
                  wms_gw_message_s_type * pm = (wms_gw_message_s_type *)&pCMsg->u.gw_message;

                  FARF(SMS,("SMS Len: %d, Format: %d",pm->raw_ts_data.len, pm->raw_ts_data.format));

                  // If this is a broadcast message we shall reject it.
                  if (pm->is_broadcast == TRUE) 
                  {
                     FARF(SMS, ("Rejecting SMS Broadcast Msg (tid=%d)", transaction_id));
                     return(FALSE);
                  }

                  decodeStatus = wms_ts_decode(&pm->raw_ts_data, pctsdata);

                  if (decodeStatus == WMS_OK_S)
                  {
                     ts = OEMWMS_DetermineGSMMessageType(&pctsdata->u.gw_pp);
                  
                     if (ts == WMS_TELESERVICE_UNKNOWN)
                     {
                        FARF(SMS, ("GSM SMS with unknown teleservice (tid = %d)", transaction_id));
                        return(FALSE);
                     }

                     pce->ts = Xlate_TS(ts);
                     pce->pText = pctsdata->u.gw_pp.u.status_report.user_data.sm_data;
                     pce->nText = pctsdata->u.gw_pp.u.status_report.user_data.sm_len;
                     pce->bIsDLAck = TRUE;
                     pce->dwMsgID = pctsdata->u.gw_pp.u.status_report.message_reference;

                     if (ts == WMS_TELESERVICE_WAP)
                     {
                        pce->nEncoding = AEESMS_ENC_OCTET;
                     }
                     else
                     {
                        switch(pctsdata->u.gw_pp.u.status_report.dcs.alphabet)
                        {
                           case WMS_GW_ALPHABET_UCS2:
                              pce->nEncoding = Xlate_Encoding(WMS_ENCODING_UNICODE);
                              break;

                           case WMS_GW_ALPHABET_8_BIT:
                              pce->nEncoding = Xlate_Encoding(WMS_ENCODING_OCTET);
                              break;

                           default:
                              pce->nEncoding = Xlate_Encoding(WMS_ENCODING_GSM_7_BIT_DEFAULT);
                        }
                     }

                     pce->dwTimeStamp = OEMWMS_GetTimeFromWmsTimestamp(&pctsdata->u.gw_pp.u.status_report.timestamp);
         
                     OEMWMS_GetAddressString((byte*)pctsdata->u.gw_pp.u.status_report.address.digits, 
                                                 pctsdata->u.gw_pp.u.status_report.address.number_of_digits,
                                                 pctsdata->u.gw_pp.u.status_report.address.digit_mode,
                                                 pctsdata->u.gw_pp.u.status_report.address.number_type,
                                             ts, pce->szFrom);

                     OEMWMS_GetAddressString((byte*)pCMsg->u.gw_message.sc_address.digits, 
                                                 pCMsg->u.gw_message.sc_address.number_of_digits,
                                                 pCMsg->u.gw_message.sc_address.digit_mode, 
                                                 pCMsg->u.gw_message.sc_address.number_type,
                                             ts, pce->szCallback);
         
                     pce->dwTag = Xlate_Tag(pCMsg->msg_hdr.tag);
                     pce->bIsMOSMS = FALSE;
                     pce->bIsSCAddress = TRUE;

                     FARF(SMS, ("tid = %d, nText = %d, nEncoding = %d", pce->dwTransactionId, pce->nText, pce->nEncoding));
                     FARF(SMS, ("Text = %s", pce->pText));
                     FARF(SMS, ("TimeStamp = %d, nNumMsgs = %d", pce->dwTimeStamp, pce->nNumMsgs));
                     FARF(SMS, ("SCAddress = %s", (char*)(*pce->szCallback ? pce->szCallback : "Unknown")));
                     FARF(SMS, ("From = %s", (char*)(*pce->szFrom ? pce->szFrom : "Unknown")));
                     return(TRUE);
                  }
                  else
                  {
                     FARF(SMS, ("Failed to decode (tid=%d)", transaction_id));
                     return(FALSE);
                  }
               }

         case WMS_TPDU_SUBMIT_REPORT_ACK:
            FARF(SMS, ("Rejecting SMS-SUBMIT-REPORT-ACK TPDU (tid=%d)", transaction_id));
            return(FALSE);

         case WMS_TPDU_SUBMIT_REPORT_ERROR:
            FARF(SMS, ("Rejecting SMS-SUBMIT-REPORT-ERROR TPDU (tid=%d)", transaction_id));
            return(FALSE);

         default:
            FARF(SMS, ("Rejecting TPDU Type = %d (tid=%d)", pCMsg->u.gw_message.raw_ts_data.tpdu_type, transaction_id));
            return(FALSE);
      }
   }
      else
      {
         // Read from GW Template
         wms_gw_template_s_type * pm = (wms_gw_template_s_type *)&pCMsg->u.gw_template;

         wms_teleservice_e_type ts = WMS_TELESERVICE_CMT_95;

         if (pm->mask & WMS_GW_TEMPLATE_MASK_DCS)
         {
            ts = OEMWMS_GetGSMMessageType(&pm->dcs);
            pce->ts = ts;
         }

         if (pm->mask & WMS_GW_TEMPLATE_MASK_VALIDITY)
         {
            pce->dwTimeStamp = OEMWMS_GetTimeFromWmsTimestamp(&pm->relative_validity);
         }

         if (pm->mask & WMS_GW_TEMPLATE_MASK_DEST_ADDR)
         {
            OEMWMS_GetAddressString((byte*)pm->dest_addr.digits, 
                                         pm->dest_addr.number_of_digits,
                                         pm->dest_addr.digit_mode,
                                         pm->dest_addr.number_type,
                                    ts, pce->szFrom);
         }
         
         if (pm->mask & WMS_GW_TEMPLATE_MASK_SC_ADDR)
         {
            OEMWMS_GetAddressString((byte*)pm->sc_addr.digits, 
                                        pm->sc_addr.number_of_digits,
                                        pm->sc_addr.digit_mode, 
                                        pm->sc_addr.number_type,
                                    ts, pce->szCallback);
         }
         
         pce->dwTag = Xlate_Tag(pCMsg->msg_hdr.tag);
         pce->bIsSCAddress = TRUE;
         FARF(SMS, ("TimeStamp = %d, nNumMsgs = %d", pce->dwTimeStamp, pce->nNumMsgs));
         FARF(SMS, ("SCAddress = %s", (char*)(*pce->szCallback ? pce->szCallback : "Unknown")));
         FARF(SMS, ("To = %s", (char*)(*pce->szFrom ? pce->szFrom : "Unknown")));
         return(TRUE);
      }
   }
   return(FALSE);
}
/*===========================================================================

  Translates DMSS Teleservice ID to OEM Teleservice ID

===========================================================================*/
static uint32 Xlate_TS(wms_teleservice_e_type ts)
{
   TsIdMap* pe;
   int i,nEntries = sizeof(gsTsIdMap) / sizeof(TsIdMap);

   for(i = 0, pe = (TsIdMap *)gsTsIdMap; i < nEntries; pe++,i++)
   {
      if(pe->DMSS_TsId == ts)
         return(pe->OEM_TsId);
   }

   // Assume DMSS uses standard TS IDs so that we dont need a mapping table and 
   // we can return the same TS ID
   return(ts); 
}

/*===========================================================================

  Translates OEM Teleservice ID to DMSS Teleservice ID

===========================================================================*/
static wms_teleservice_e_type Xlate_2_NativeTS(uint32 ts)
{
   TsIdMap* pe;
   int i,nEntries = sizeof(gsTsIdMap) / sizeof(TsIdMap);

   for(i = 0, pe = (TsIdMap *)gsTsIdMap; i < nEntries; pe++,i++)
   {
      if(pe->OEM_TsId == ts)
         return(pe->DMSS_TsId);
   }

   // Assume DMSS uses standard TS IDs so that we dont need a mapping table and 
   // we can return the same TS ID
   return(ts); 
}

/*===========================================================================

   Translation of Priority Codes from DMSS to AEE

===========================================================================*/
static int Xlate_Priority(wms_priority_e_type priority)
{
   PriorityMap * pe;
   int i,nEntries = sizeof(gsPriorityMap) / sizeof(PriorityMap);

   for(i = 0, pe = (PriorityMap *)gsPriorityMap; i < nEntries; pe++,i++)
   {
      if(pe->OEM_Priority == priority)
         return(pe->AEE_Priority);

   }

   return(SMS_PRIORITY_NORMAL); // Default   

}

/*===========================================================================

  Translation of Privacy Codes from DMSS to AEE

===========================================================================*/
static int Xlate_Privacy(wms_privacy_e_type privacy)
{
   PrivacyMap * pe;
   int i,nEntries = sizeof(gsPrivacyMap) / sizeof(PrivacyMap);

   for(i = 0, pe = (PrivacyMap *)gsPrivacyMap; i < nEntries; pe++,i++)
   {
      if(pe->OEM_Privacy == privacy)
         return(pe->AEE_Privacy);
   }

   return(SMS_PRIVACY_NORMAL); // Default   
}

/*===========================================================================

  Translation of Language Codes from DMSS to AEE

===========================================================================*/
static uint32 Xlate_Lang(wms_language_e_type lang)
{
   LangMap * pe;
   int i,nEntries = sizeof(gsLangMap) / sizeof(LangMap);

   for(i = 0, pe = (LangMap *)gsLangMap; i < nEntries; pe++,i++)
   {
      if(pe->OEM_Lang == lang)
         return(pe->AEE_Lang);
   }

   // Assume DMSS uses our LanguageCodes so that we dont need a mapping table and 
   // we can return the same code
   return(lang); 
}

/*===========================================================================

  Translation of Encoding Codes from DMSS to AEE

===========================================================================*/
static int Xlate_Encoding(wms_user_data_encoding_e_type enc)
{
   EncMap * pe;
   int i,nEntries = sizeof(gsEncMap) / sizeof(EncMap);

   for(i = 0, pe = (EncMap *)gsEncMap; i < nEntries; pe++,i++)
   {
      if(pe->OEM_Enc == enc)
         return(pe->AEE_Enc);

   }

   // We don't understand this encoding. Anyway, pass it to client and hope
   // that client understands it
   return(enc); 
}

/*===========================================================================

  This function converts the Time from Julian format to seconds format for CDMA
  messages.

===========================================================================*/
static uint32 OEMWMS_GetTimeFromWmsTimestamp(wms_timestamp_s_type *pTime)
   {
      uint8           tmp;
      clk_julian_type jt;

   FARF(SMS, ("==>  OEMWMS_GetTimeFromWmsTimestamp"));

      MEMSET(&jt, 0, sizeof(jt));

   tmp = BCD2INT(pTime->year);
   
      // If the year is above 95 it we assume it is in 20 th century(1900+ year
      // otherwise we assume it is in 21 century(2000+year)
      jt.year = (tmp <= 95) ? (YEAR_2000 + tmp) : (YEAR_1900 + tmp);
   jt.month = BCD2INT(pTime->month);
   jt.day = BCD2INT(pTime->day);
   jt.hour = BCD2INT(pTime->hour);
   jt.minute = BCD2INT(pTime->minute);
   jt.second = BCD2INT(pTime->second);

      return clk_julian_to_secs(&jt);
   } 


/*===========================================================================

  This function converts the Time from seconds format to julian format for CDMA
  messages.

===========================================================================*/
static void OEMWMS_SetTimeToWmsTimestamp(wms_timestamp_s_type *pTime, uint32 ts)
   {
   clk_julian_type jt;

   FARF(SMS, ("==>  OEMWMS_SetTimeToWmsTimestamp"));

   MEMSET(&jt, 0, sizeof(jt));

   clk_secs_to_julian(ts, &jt);               
   pTime->year = INT2BCD((jt.year >= 2000) ? (jt.year - 2000) : (jt.year - 1900));
   pTime->month = INT2BCD(jt.month); 
   pTime->day = INT2BCD(jt.day);
   pTime->hour = INT2BCD(jt.hour);
   pTime->minute = INT2BCD(jt.minute);
   pTime->second = INT2BCD(jt.second);
}

/*===========================================================================

  Gets number of messages information from the WMS Client Bearer Data.

===========================================================================*/
static boolean OEMWMS_GetNumMsgsInfoFromCDMABDMsg 
(
   wms_client_bd_s_type * pcd, 
   wms_teleservice_e_type ts, 
   int * pnNumMsgs
)
{
   FARF(SMS, ("==>  OEMWMS_GetNumMsgsInfoFromCDMABDMsg"));

   *pnNumMsgs = 0;

   // Check if Num Messages information is present in the Bearer Data
   // Structure.
   if (pcd->mask & WMS_MASK_BD_NUM_OF_MSGS) 
   {
      *pnNumMsgs = pcd->num_messages;
   }
   
   return TRUE;
}

/*===========================================================================

  Gets number of messages information from the WMS GW Message Data.

===========================================================================*/
static boolean OEMWMS_GetNumMsgsInfoFromGWMsg 
(
   wms_gw_deliver_s_type * pData,
   wms_teleservice_e_type ts,
   int * pnNumMsgs
)
{
   FARF(SMS, ("==>  OEMWMS_GetNumMsgsInfoFromGWMsg"));

   *pnNumMsgs = 0;

   if (ts == WMS_TELESERVICE_VMN_95) 
   {
      // Determine number of Voice Messages.

      // If the User Data Header has a Special Message Indication 
      // Information Element, then process the IE to extract the 
      // number of Messages Information. See section 9.2.3.24.2 
      // of TS 23.040.

      int i;

      for (i = 0; i < pData->user_data.num_headers; i++) 
      {
         if ((pData->user_data.headers[i].header_id == WMS_UDH_SPECIAL_SM) &&
             (pData->user_data.headers[i].u.special_sm.msg_waiting_kind == WMS_GW_MSG_WAITING_VOICEMAIL)) 
         {
            *pnNumMsgs = pData->user_data.headers[i].u.special_sm.message_count;
            break;
         }
      }

      // There are multiple ways in which a GSM SMS message could indicate 
      // Voice Mail Notification, if SMI does not indicate VMN, then check 
      // the DCS to see if it indicates Voice Mail Notification ( see Section
      // 4 - Data Encoding Scheme of TS 23.038 )

      if ((*pnNumMsgs == 0) && 
          (pData->dcs.msg_waiting_kind == WMS_GW_MSG_WAITING_VOICEMAIL) &&
          (pData->dcs.msg_waiting_active == TRUE)) 
      {
         // Since we do not have information about how many 
         // Messages are awaiting we shall set nMessages to a value of 1.
         *pnNumMsgs = 1;
      } 

      if (*pnNumMsgs == 0)
      {
         FARF(SMS, ("Received Voice Mail Message with 0 message count"));
         return FALSE;
      }
   }
   return TRUE;
}

/*===========================================================================

  Sets number of messages information to the WMS GW Message Data.

===========================================================================*/
static void OEMWMS_SetNumMsgsInfoToGWMsg 
(
   wms_gw_deliver_s_type * pData,
   wms_teleservice_e_type ts,
   int nNumMsgs
)
{
   FARF(SMS, ("==>  OEMWMS_SetNumMsgsInfoToGWMsg"));

   // This function is used to store a MT message. We set deliver message
   // parameters from which we can get number of messages when msg is read

   if (ts == WMS_TELESERVICE_VMN_95) 
   {
      pData->user_data.num_headers = 1;
      pData->user_data.headers[0].header_id = WMS_UDH_SPECIAL_SM;
      pData->user_data.headers[0].u.special_sm.msg_waiting_kind = WMS_GW_MSG_WAITING_VOICEMAIL;
      pData->user_data.headers[0].u.special_sm.message_count = nNumMsgs;
   }
}

/*===========================================================================

  This function gets the Callback number from the WMS Client Bearer Data
  in the specified buffer.              

===========================================================================*/
static boolean OEMWMS_GetCallBackNumberFromCDMABDMsg
( 
   wms_client_bd_s_type *pcd,
   wms_teleservice_e_type ts,
   char * pBuffer
)
{
   FARF(SMS, ("==>  OEMWMS_GetCallBackNumberFromCDMABDMsg"));

   // Check if the WMS bd message has Callback number 
   if (pcd->mask & WMS_MASK_BD_CALLBACK) 
   {
      // If the incoming message is  IS91 Page message, we shall
      // re-compute the number of digits in the callback number by
      // ignoring the trailing '0x0' digits. ( A real 0 is encoded in
      // the IS91 CLI message as '0xA' so we are not in danger of ignoring
      // legitimate 0 digits from the message. )

      if (ts == WMS_TELESERVICE_IS91_PAGE) 
      {
         int j = 0;

         // In an IS91 Page message, the Callback number is padded with trailing
         // zeroes, we do not want to display these digits, so we try to strip
         // the trailing zeroes out by setting the number_of_digits information
         // appropriately. E.g. 55512120000 ( for 5551212 )

         // Count the number of trailing zeros in the callback number
         // array and recompute the length of the callback number ignoring
         // the trailing zeros.

         for (j = pcd->callback.number_of_digits - 1; j >= 0; j--) 
         {
            if (pcd->callback.digits[j] == 0x0) 
            {
               pcd->callback.number_of_digits--;
            } 
            else 
            {
               // break at the first occurance of a non zero digit.
               break;
            }
         }
      }
      
      return OEMWMS_GetAddressString((byte*)pcd->callback.digits, 
                                     pcd->callback.number_of_digits,
                                     pcd->callback.digit_mode, 
                                     pcd->callback.number_type,
                                     ts, 
                                     pBuffer);
   }
   return TRUE;
}

/*===========================================================================

  This function gets the phone number as string copied to pBuffer              

===========================================================================*/
boolean OEMWMS_GetAddressString
(
   byte * pSrc,
   int nDigits,
   wms_digit_mode_e_type digitMode,
   wms_number_type_e_type numberType,
   wms_teleservice_e_type ts,
   char * pBuffer
)
{
   int i;
   byte * pDst, bval;
   boolean bCBNumIsAllZeros = FALSE;

   FARF(SMS, ("==>  OEMWMS_GetAddressString"));

   pDst = (byte*)pBuffer;
   
   if (numberType == WMS_NUMBER_INTERNATIONAL) 
   {
      *pDst = DIALER_PLUS_CHAR;
      pDst++;
   }

   if (digitMode == WMS_DIGIT_MODE_8_BIT) 
   {
      // Each byte in the callback.digits array is a ascii representation
      // of a digit, so we can directly copy each byte into the cbDigits
      // array.
      MEMCPY(pDst, pSrc, (unsigned int)nDigits);
   }   
   else if (digitMode == WMS_DIGIT_MODE_4_BIT) 
   {
      // If the digit mode is 4 Bit Mode, then each byte in the 
      // callback.digits array has a four bit numeric representation of
      // a digit, where values 0x0A represents '0', 0x0b - '#', '0x0c' - '*'
      // 0x01 - 0x09 - '1' - '9'.
      // We call GetDigit to convert each byte to corresponding 
      // digit.

      i = nDigits;

      while (i--) 
      {
         bval = (byte)*(pSrc++);
         *(pDst++) = (char)GetDigit((byte)(bval & 0x0f));
      }
   } 
   else 
   {
      // Unknown Digit mode
      FARF(SMS, ("Unknown Digit Mode in Address %d", digitMode));
      return FALSE;
   }

   // Reset pDst to point to the beginning of pBuffer string.
   pDst = (byte*)pBuffer;

   // If the Callback number is all '0' then report error
   for (i = 0; i < nDigits; i++) 
   {
      if (pDst[i] != '0') 
      {
         bCBNumIsAllZeros = FALSE;
         break;
      }
   }

   if (bCBNumIsAllZeros == TRUE) 
   {
      FARF(SMS, ("Callback number in SMS Msg has all 0 digits"));
      return FALSE;
   }
   return TRUE;
}

/*===========================================================================
   This function determines the message type of the GSM Deliver Message and 
   maps the Message Type to a IS-637 Teleservice Id.
===========================================================================*/
static wms_teleservice_e_type OEMWMS_DetermineGSMMessageType
(
   wms_gw_pp_ts_data_s_type *pgw_pp
)
{
   wms_teleservice_e_type ts = WMS_TELESERVICE_UNKNOWN;
   wms_gw_dcs_s_type * pdcs = NULL;
   wms_gw_user_data_s_type * puserdata = NULL;
   boolean bUDHPresent = FALSE;
   wms_pid_e_type pid;

   if (!pgw_pp) 
   {
      FARF(SMS, ("Null pMsg"));
      return WMS_TELESERVICE_UNKNOWN;
   }

   if (pgw_pp->tpdu_type == WMS_TPDU_DELIVER)
   {
      pdcs = &pgw_pp->u.deliver.dcs;
      puserdata = &pgw_pp->u.deliver.user_data;
      bUDHPresent = pgw_pp->u.deliver.user_data_header_present;
      pid = pgw_pp->u.deliver.pid;

      FARF(SMS, ("MT GSM: more = %d, RPP = %d", pgw_pp->u.deliver.more, pgw_pp->u.deliver.reply_path_present));
   
      FARF(SMS, ("MT GSM: SRE = %d", pgw_pp->u.deliver.status_report_enabled));
   }
   else if (pgw_pp->tpdu_type == WMS_TPDU_STATUS_REPORT)
   {
      pdcs = &pgw_pp->u.status_report.dcs;
      puserdata = &pgw_pp->u.status_report.user_data;
      bUDHPresent = pgw_pp->u.status_report.user_data_header_present;
      pid = pgw_pp->u.status_report.pid;
   }
   else
   {
      FARF(SMS, ("Invalid Message Type"));
      return WMS_TELESERVICE_UNKNOWN;
   }
   
   FARF(SMS, ("UDH = %d, pid = %d", bUDHPresent, pid));
       
   FARF(SMS, ("MT GSM DCS: MsgClass = %d, compr = %d, alpha = %d",
              pdcs->msg_class, pdcs->is_compressed, pdcs->alphabet));
 
   FARF(SMS, ("MT GSM DCS: MW = %d, MWA = %d, MWK = %d",
              pdcs->msg_waiting, pdcs->msg_waiting_active, pdcs->msg_waiting_kind ));
 
   // The message type shall be determined by examining the parameters TP-PID, TP-DCS, 
   // TP-UDHI and TP-UD. For detailed information about these parameters refer to documents 
   // 3GPP TS 23.040 and 3GPP TS 23.038.
   // The Message is determined to be a VoiceMailNotification Message if one of the 
   // following is TRUE.
   // 1. PID is 0x5F ( 3GPP TS 23.040, section 9.2.3.9 )
   // 2. TP-DCS indicates MessageWaiting Coding Group & Message Kind
   //    is Voice Mail.  Section 4 of TS 23.038.
   // 3. TP-UHDI is True ( User Header present ) and TP-UD Header has
   //    Special Message Indication Information Element which indicates
   //    Voice Message Waiting.
   // Here we go...

   if (bUDHPresent) 
   {
      int i;

      // Initialize with EMS teleservice ID
      ts = WMS_TELESERVICE_WEMT;

      for (i = 0; i < puserdata->num_headers; i++) 
      {
         if((puserdata->headers[i].header_id == WMS_UDH_SPECIAL_SM) &&
            (puserdata->headers[i].u.special_sm.msg_waiting_kind == WMS_GW_MSG_WAITING_VOICEMAIL)) 
         {
            FARF(SMS, ("GSM Voice Mail Notification Message Received"));
            ts =  WMS_TELESERVICE_VMN_95;
            break;
         }
         else if((puserdata->headers[i].header_id == WMS_UDH_PORT_16) &&
            (puserdata->headers[i].u.wap_16.dest_port == 2948)) 
         {
            FARF(SMS, ("GSM WAP Push Message Received"));
            ts =  WMS_TELESERVICE_WAP;
            break;
         }
      }
   }
   else if ( pid == WMS_PID_RETURN_CALL )
   {
      FARF(SMS, ("GSM Return Call Message Message Received"));

      // Even though this is a Voice Mail Notification message,
      // the standard does not explicitly specify how Number of Messages
      // information is specified nor does it explicitly specify how
      // Message Indication Active/ Inactive is specified. So upon
      // receiving this message, we would not know whether we should
      // display or clear the Message Waiting Indication Annunciators.
      // Hence, we shall treat this message as a regular text message
      // and only display the contents of the UserData.

      // For now the this message shall not be treated in the way
      // 'Replace Short Message Type' ought to be treated as specified
      // at 9.2.3.9 of TS 23.040. Future enhancements could consider this.

      // For now we shall treat it as a simple text message.
      ts =  WMS_TELESERVICE_CMT_95;
   }
   else if ((pdcs->msg_waiting_kind == WMS_GW_MSG_WAITING_VOICEMAIL) && 
            (pdcs->msg_waiting_active == TRUE) && 
            (pdcs->msg_waiting != WMS_GW_MSG_WAITING_NONE)) 
   {         
      FARF(SMS, ("GSM Voice Mail Notification Message Received"));
      ts =  WMS_TELESERVICE_VMN_95;      
   }

   if (ts == WMS_TELESERVICE_UNKNOWN) 
   {
      // Message is not Voice Mail, so check if it is Text Message.
      // The Message is determined to be a Text Message if the following
      // is true.

      // PID = 0x0 and the TP-DCS Coding Group is not MessageWaiting
      if ((pid == WMS_PID_DEFAULT) && (pdcs->msg_waiting_active == FALSE)) 
      {
         FARF(SMS, ("GSM Text Message Received"));
         ts = WMS_TELESERVICE_CMT_95;
      }
   }

   // Reject the Text Message if it is compressed
   if ((ts == WMS_TELESERVICE_CMT_95) && (pdcs->is_compressed == TRUE)) 
   {
      FARF(SMS, ("Rejecting GSM SMS Compressed Text Message"));
      ts = WMS_TELESERVICE_UNKNOWN;
   }

   return ts;
}

/*===========================================================================
   This function sets pdcs corresponding to teleservice
===========================================================================*/
static void OEMWMS_SetGSMMessageType
(
   wms_gw_dcs_s_type *pdcs,
   wms_teleservice_e_type ts
)
{
   if (!pdcs) 
   {
      FARF(SMS, ("Null pMsg"));
   }

   if (ts == WMS_TELESERVICE_VMN_95)
   {
      pdcs->msg_waiting_kind = WMS_GW_MSG_WAITING_VOICEMAIL;
      pdcs->msg_waiting_active = TRUE; 
      pdcs->msg_waiting = WMS_GW_MSG_WAITING_STORE;
   }
   else if (ts == WMS_TELESERVICE_CMT_95)
   {
      pdcs->msg_waiting = WMS_GW_MSG_WAITING_NONE;
      pdcs->msg_waiting_active = FALSE;
   }
   else
   {
      pdcs->msg_waiting = WMS_GW_MSG_WAITING_NONE;
      pdcs->msg_waiting_active = FALSE;
      pdcs->is_compressed = TRUE;
   }
}

/*===========================================================================
   This function gets teleservice corresponding to pdcs
===========================================================================*/
static wms_teleservice_e_type OEMWMS_GetGSMMessageType
(
   wms_gw_dcs_s_type *pdcs
)
{
   wms_teleservice_e_type ts = WMS_TELESERVICE_UNKNOWN;

   if (!pdcs) 
   {
      FARF(SMS, ("Null pMsg"));
   }

   if (pdcs->msg_waiting != WMS_GW_MSG_WAITING_NONE)
   {
      ts = WMS_TELESERVICE_VMN_95;
   }
   else
   {
      if (!pdcs->is_compressed)
      {
         ts = WMS_TELESERVICE_CMT_95;
      }
   }

   return ts;
}

/*===========================================================================

  Called to handle MO SMS events

===========================================================================*/
static wms_status_e_type OEMWMS_MoMessageListener
( 
   wms_msg_event_e_type event,
   const wms_msg_event_info_s_type * info_ptr,
   boolean * pshared 
)
{
   wms_status_e_type nRet = WMS_GENERAL_ERROR_S;
   OEMMsg  *hMsg = (OEMMsg *)info_ptr->status_info.user_data;

   if ( event == WMS_MSG_EVENT_SEND ) 
   {
      FARF(SMS, ("MessageListener: Send"));

      //Null pointer check 
      if (!gpWms || !gpWms->pCurMOSMS)
         goto Done;

      //Check if it is a CB for our MOSMS 
      if( hMsg == gpWms->pCurMOSMS ) 
      {
         FARF(SMS, ("Phone_StatusListener. Yes. CB Match"));
         if (pshared)
         {
            *pshared = FALSE;
         }
         nRet = WMS_OK_S;
      }
   }
   else if ( event == WMS_MSG_EVENT_SUBMIT_REPORT ) 
   {
      FARF(SMS, ("MessageListener: Submit"));

      if( info_ptr->submit_report_info.client_id != gpWms->clientId ) 
      {
         // Message didnot originate from this module. Ignore the
         // report.
         nRet = WMS_OK_S;
         goto Done;
      }

      //Null pointer check 
      if (!gpWms || !gpWms->pCurMOSMS)
         goto Done;

      if(hMsg == gpWms->pCurMOSMS)
      {
         if ((info_ptr->submit_report_info.message_mode == WMS_MESSAGE_MODE_CDMA) &&
              (info_ptr->submit_report_info.report_status == WMS_RPT_ACCESS_TOO_LARGE))
      {  
         if ((nRet = OEMWMS_SendSMSOnTrafficChannel()) != WMS_OK_S)
         {
            AEESMS_SETERROR(*(gpWms->pCurMOSMS->pdwStatus), AEESMS_ERRORTYPE_UNKNOWN, Xlate_wms_status_e_type_2_MOSMS_ERR(nRet));
            AEE_SVC_RESUME( gpWms->pCurMOSMS->pcb );
            OEMSMS_DeleteMessage(gpWms->pCurMOSMS);
         }
      }
         else 
      {
         FARF(SMS, ("Phone_StatusListener. Yes. CB Match"));
         if (pshared)
         {
            *pshared = FALSE;
         }
         *(gpWms->pCurMOSMS->pdwStatus) = OEMWMS_GetSubmitStatus( &info_ptr->submit_report_info );
         AEE_SVC_RESUME( gpWms->pCurMOSMS->pcb );
         OEMSMS_DeleteMessage( gpWms->pCurMOSMS );

         nRet = WMS_OK_S;
      }
   }
   }

Done:
   return nRet;
}

/*===========================================================================

  A NO OP Callback function for WMS

===========================================================================*/
static void OEMWSMS_NoopCommandCallback (wms_cmd_id_e_type cmd, void* user_data, wms_cmd_err_e_type cmd_err )
{
   FARF(SMS, ("CMDCB: Err code %d",cmd_err));
}

/*===========================================================================

  Called to get Submit Statuse

===========================================================================*/
static uint32 OEMWMS_GetSubmitStatus( const wms_submit_report_info_s_type *submit_info )
{
   uint32 dwStatus;

   if (submit_info->message_mode == WMS_MESSAGE_MODE_CDMA)
   {
      if (submit_info->report_status == WMS_RPT_OK)
      {
         AEESMS_SETERROR(dwStatus, 
                         Xlate_wms_error_class_e_type_2_MOSMS_ERRTYPE(submit_info->cause_info.error_class), 
                         Xlate_wms_report_status_e_type_2_MOSMS_ERR(submit_info->report_status));
      }
      else
      {
         AEESMS_SETERROR(dwStatus, 
                         Xlate_wms_error_class_e_type_2_MOSMS_ERRTYPE(submit_info->cause_info.error_class), 
                         Xlate_wms_cdma_tl_status_e_type_2_MOSMS_ERR(submit_info->cause_info.tl_status));
      }
   }
   else if (submit_info->message_mode == WMS_MESSAGE_MODE_GW)
   {
      if (submit_info->report_status == WMS_RPT_OK)
      {
         AEESMS_SETERROR(dwStatus, 
                         Xlate_wms_error_class_e_type_2_MOSMS_ERRTYPE(submit_info->cause_info.error_class), 
                         Xlate_wms_report_status_e_type_2_MOSMS_ERR(submit_info->report_status));
      }
      else
      {
         AEESMS_SETERROR(dwStatus, 
                         Xlate_wms_error_class_e_type_2_MOSMS_ERRTYPE(submit_info->cause_info.error_class), 
                         Xlate_wms_tp_cause_e_type_2_MOSMS_ERR(submit_info->u.error.tp_cause));
      }
   }
   else
   {         
      AEESMS_SETERROR(dwStatus, AEESMS_ERRORTYPE_UNKNOWN, AEESMS_ERROR_GENERAL_PROBLEM);
   }
   return dwStatus;
}

/*===========================================================================

  Determines system mode

===========================================================================*/   
sys_sys_mode_e_type OEMWMS_GetSystemMode()
{
   sys_sys_mode_e_type sysMode = SYS_SYS_MODE_NONE;
   OEMPhone * pPhone = NULL;

   if(SUCCESS == OEMPhone_New(&pPhone))
   {
      const cm_mm_ss_info_s_type * pSysInfo = OEMPhone_GetSystemInfo(pPhone);

      if (pSysInfo)
         sysMode = pSysInfo->sys_mode;

      OEMPhone_Release(pPhone);
   }
   return sysMode;
}

/*===========================================================================

  Constructs OEMMsg struct to be sent              

===========================================================================*/   
OEMMsg* OEMSMS_NewMessage( OEMMsgData * pMsgData, OEMMsgPayload * pMsgPayload )
{
   OEMMsg* hMsg = NULL;
   wms_client_ts_data_s_type clientBD;
   sys_sys_mode_e_type sysMode;

   FARF(SMS, ("==>  OEMSMS_NewMessage"));

   // Determine System Mode
   sysMode = OEMWMS_GetSystemMode();

   if ((SYS_SYS_MODE_CDMA != sysMode) &&
       (SYS_SYS_MODE_GSM != sysMode))
   {
      FARF(SMS, ("Unknown Mode"));
      return NULL;
   }

   hMsg = sys_malloc( sizeof(OEMMsg) );

   if(!hMsg) 
   {
      FARF(SMS, ("Memory Allocation Failed!"));
      return NULL;
   }
   
   MEMSET(&clientBD, 0, sizeof(clientBD));

   if (pMsgData->dwTag != AEESMS_TAG_MO_TEMPLATE)
   {
      wms_raw_ts_data_s_type rawBD;   
   MEMSET(&rawBD, 0, sizeof(rawBD));

   // Construct Client BD Type
   if (OEMWMS_ConstructClientBD( pMsgData, pMsgPayload, &clientBD, sysMode) == FALSE)
   {
      sys_free(hMsg);
      hMsg = NULL;
      goto Done;
   }

   // Construct Raw BD Type
   wms_ts_encode(&clientBD, &rawBD);

   // Construct Client Message
   if (OEMWMS_ConstructClientMessage( pMsgData, &hMsg->CMsg, &rawBD, sysMode ) == FALSE)
   {
      sys_free(hMsg);
      hMsg = NULL;
   }
   }
   else
   {
      hMsg->CMsg.msg_hdr.tag = Xlate_2_NativeTag(pMsgData->dwTag);
      if (SYS_SYS_MODE_CDMA == sysMode)
      {
         // Construct Client BD Type
         if (OEMWMS_ConstructClientBD(pMsgData, pMsgPayload, &clientBD, sysMode) == FALSE)
         {
            sys_free(hMsg);
            hMsg = NULL;
            goto Done;
         }

         // Construct CDMA Template
         if (OEMWMS_ConstructCDMATemplate(pMsgData, &hMsg->CMsg, &clientBD.u.cdma) == FALSE)
         {
            sys_free(hMsg);
            hMsg = NULL;
         }      
      }
      else
      {
         // Construct GW Template
         if (OEMWMS_ConstructGWTemplate(pMsgData, &hMsg->CMsg) == FALSE)
         {
            sys_free(hMsg);
            hMsg = NULL;
         }
      }
   }

Done:
   return hMsg;
}

/*===========================================================================

  Converts AEE encoding to DMSS encoding            

===========================================================================*/
static wms_user_data_encoding_e_type Xlate_2_NativeEncoding( int enc )
{
   EncMap * pe;
   int i,nEntries = sizeof(gsEncMap) / sizeof(EncMap);

   for(i = 0, pe = (EncMap *)gsEncMap; i < nEntries; pe++,i++)
   {
      if(pe->AEE_Enc == enc)
         return(pe->OEM_Enc);
   }
   // Assume that we are being passed an encoding understood by DMSS
   return(enc); 
}

/*===========================================================================

  Provides message ID

===========================================================================*/
uint16 OEMWMS_GetUniqueSMSMessageID (void)
{   
   static uint16 id = 0;
   return id++;
}

/*===========================================================================

  Constructs the client bearer data from the message and the user data

===========================================================================*/
static boolean OEMWMS_ConstructClientBD 
(
   OEMMsgData * pMsgData,
   OEMMsgPayload * pMsgPayload,
   wms_client_ts_data_s_type * pClientTS,
   sys_sys_mode_e_type sysMode
) 
{
   FARF(SMS, ("==>  OEMWMS_ConstructClientBD"));

   switch (sysMode)
   {
      case SYS_SYS_MODE_CDMA:
         {
            wms_user_data_encoding_e_type ne;
            wms_client_bd_s_type * pClientBD = (wms_client_bd_s_type *)&pClientTS->u.cdma;

            FARF(SMS, ("CDMA Mode Client BD"));

            // Set Format
            pClientTS->format = WMS_FORMAT_CDMA;

            // Reset Mask
            pClientBD->mask = 0;
   
            // Set User Data   
            ne = Xlate_2_NativeEncoding( pMsgPayload->nEncoding );

            switch (ne) 
            {
               case WMS_ENCODING_ASCII:  // 7-bit ASCII
               case WMS_ENCODING_IA5:
                  pClientBD->user_data.encoding = ne;
                  pClientBD->user_data.is91ep_type = (wms_IS91EP_type_e_type)0;
                  pClientBD->user_data.padding_bits = pMsgPayload->nPadding;
                  pClientBD->user_data.data_len = (uint8)MIN(pMsgPayload->nBytes,WMS_CDMA_USER_DATA_MAX);
                  pClientBD->user_data.number_of_digits = (pClientBD->user_data.data_len*8 - pClientBD->user_data.padding_bits)/7;
                  // copy the data directly
                  MEMCPY((void*)pClientBD->user_data.data, (void*)pMsgPayload->data, (uint32)pClientBD->user_data.data_len);
                  break;

               case WMS_ENCODING_UNICODE: // Unicode
                  pClientBD->user_data.encoding = ne;
                  pClientBD->user_data.is91ep_type = (wms_IS91EP_type_e_type)0;
                  pClientBD->user_data.data_len = (uint8)MIN(pMsgPayload->nBytes,WMS_CDMA_USER_DATA_MAX);
                  if( pClientBD->user_data.data_len & 0x01 ) // Even it
                  { 
                     pClientBD->user_data.data_len--;
                  }
                  pClientBD->user_data.padding_bits = pMsgPayload->nPadding;
                  pClientBD->user_data.number_of_digits = pClientBD->user_data.data_len;
                  // copy the data directly
                  MEMCPY((void*)pClientBD->user_data.data, (void*)pMsgPayload->data, (uint32)pClientBD->user_data.data_len);
                  break;

               default:
                  // return the data as is--no interpretation
                  pClientBD->user_data.encoding = ne;
                  pClientBD->user_data.is91ep_type = (wms_IS91EP_type_e_type)0;
                  pClientBD->user_data.data_len = (uint8)MIN(pMsgPayload->nBytes,WMS_CDMA_USER_DATA_MAX);
                  pClientBD->user_data.padding_bits = pMsgPayload->nPadding;
                  pClientBD->user_data.number_of_digits = pClientBD->user_data.data_len;
                  // copy the data directly
                  MEMCPY((void*)pClientBD->user_data.data, (void*)pMsgPayload->data, (uint32)pClientBD->user_data.data_len);
            }
            pClientBD->mask |= WMS_MASK_BD_USER_DATA;

            // Message Identifier
            if (pMsgData->bIsDLAck)
            {
               pClientBD->message_id.type = WMS_BD_TYPE_DELIVERY_ACK;
            }
            else if (pMsgData->bIsUserAck)
            {
               pClientBD->message_id.type = WMS_BD_TYPE_USER_ACK;
            }
            else if (pMsgData->bIsReadAck)
            {
               pClientBD->message_id.type = WMS_BD_TYPE_READ_ACK;
            }
            else
            {
               if (pMsgData->bIsMOSMS)
               {
                  pClientBD->message_id.type = WMS_BD_TYPE_SUBMIT;
               }
               else
               {
                  pClientBD->message_id.type = WMS_BD_TYPE_DELIVER;
               }
            }
            pClientBD->message_id.id_number = (pMsgData->dwMsgID ? pMsgData->dwMsgID : OEMWMS_GetUniqueSMSMessageID()); // Message Id
            pClientBD->mask |= WMS_MASK_BD_MSG_ID;                            // set mask

            // Reply Option
            pClientBD->reply_option.delivery_ack_requested = pMsgData->bRequestDLAck;
            pClientBD->reply_option.user_ack_requested = pMsgData->bRequestUserAck;
            pClientBD->reply_option.read_ack_requested = pMsgData->bRequestReadAck;
            pClientBD->mask |= WMS_MASK_BD_REPLY_OPTION; //BD reply option on

            // Set Time Stamp
            if (pMsgData->bIsMOSMS)
            {
               if (pMsgData->dwTimeStamp)
               {                  
                  // Set Relative Validity 
                  pClientBD->mask |= WMS_MASK_BD_VALID_REL;
                  OEMWMS_SetTimeToWmsTimestamp(&pClientBD->validity_relative, pMsgData->dwTimeStamp);
               }
            }
            else
            {
               if (pMsgData->dwTimeStamp)
               {
                  // Set Time Stamp 
                  pClientBD->mask |= WMS_MASK_BD_MC_TIME;
                  OEMWMS_SetTimeToWmsTimestamp(&pClientBD->mc_time, pMsgData->dwTimeStamp);
               }

               if (pMsgData->nNumMsgs)
               {            
                  // Number of messages
                  pClientBD->num_messages = (byte)(pMsgData->nNumMsgs);
                  pClientBD->mask |= WMS_MASK_BD_NUM_OF_MSGS;
               }
            }

            // callback number
            if (*pMsgData->szCallback)
            {
               pClientBD->callback.digit_mode = WMS_DIGIT_MODE_4_BIT;
               pClientBD->callback.number_type = WMS_NUMBER_NATIONAL;
               pClientBD->callback.number_plan = WMS_NUMBER_PLAN_TELEPHONY;
               pClientBD->callback.number_of_digits = (byte)GetASCII2DTMF(pMsgData->szCallback, 
                                                                          (byte*)pClientBD->callback.digits, 
                                                                          STRLEN(pMsgData->szCallback));
               if (pClientBD->callback.number_of_digits)
                  pClientBD->mask |= WMS_MASK_BD_CALLBACK;
            }

            // Priority
            pClientBD->priority = Xlate_2_NativePriority(pMsgData->nPriority);
            pClientBD->mask |= WMS_MASK_BD_PRIORITY;

            // Privacy
            pClientBD->privacy = Xlate_2_NativePrivacy(pMsgData->nPrivacy);
            pClientBD->mask |= WMS_MASK_BD_PRIVACY;

            // Language
            pClientBD->language = Xlate_2_NativeLang(pMsgData->dwLang);
            pClientBD->mask |= WMS_MASK_BD_LANGUAGE;

            // User Data Headers
            OEMWMS_ProcessUDHData(pClientTS, pMsgData->data, pMsgData->nBytes);
         }
         return TRUE;

      case SYS_SYS_MODE_GSM:
         {
            FARF(SMS, ("GSM Mode Client BD"));

            // Set Format
            pClientTS->format = WMS_FORMAT_GW_PP;

            if (pMsgData->bIsMOSMS)
            {  
               wms_gw_submit_s_type * pSubmitMsg = NULL;

               // For now we only originate a GSM Submit Message.
               pClientTS->u.gw_pp.tpdu_type = WMS_TPDU_SUBMIT;

               // Start populating the Submit Message.
               pSubmitMsg = (wms_gw_submit_s_type *)&pClientTS->u.gw_pp.u.submit;

               // We'll set the Reject Duplicates field to FALSE for now,
               // currently we do not support re-attempts, so there should not
               // be any duplicate messages that we sent.
               pSubmitMsg->reject_duplicates = FALSE;

               // We do not support reply path currently.
               pSubmitMsg->reply_path_present = FALSE;

               // User data shall only contain user text and no header information.
               pSubmitMsg->user_data_header_present = FALSE;

               // We do not care about Status Report currently.
               pSubmitMsg->status_report_enabled = FALSE;

               // Request Status Report
               pSubmitMsg->status_report_enabled = pMsgData->bRequestDLAck;

               // TP-MR TP-Message-Reference - Section 9.2.3.6 of TS 23.040
               // TP-MR needs to be a number between 0 and 255. The standard
               // requires that we use the Last-Used-TP-MR value on the SIM.
               // For now we shall generate the TP-MR the same way that we
               // generate Message Ids for CDMA messages.
               pSubmitMsg->message_reference = OEMWMS_GetUniqueSMSMessageID() % 255;

               // TP-DA Destination Address
               if (OEMWMS_SetGWAddress(&pSubmitMsg->address, pMsgData->szMOFromMTTo) != TRUE)
               {
                  // Invalid Destination Address
                  FARF(SMS, ("Invalid Destination Address"));
                  return FALSE;
               }

               // TP-PID Protocol Identifier - Section 9.2.3.9 of TS 23.040.
               // Standard indicates that value of 0 can be used for simple
               // MS-to-SC short message transfer.
               pSubmitMsg->pid = WMS_PID_DEFAULT;

               // TP-DCS Data Coding Scheme
               switch (Xlate_2_NativeEncoding( pMsgPayload->nEncoding ))
               {
                  case WMS_ENCODING_UNICODE:
                     pSubmitMsg->dcs.alphabet = WMS_GW_ALPHABET_UCS2;
                     break;

                  case WMS_ENCODING_GSM_7_BIT_DEFAULT:
                     pSubmitMsg->dcs.alphabet = WMS_GW_ALPHABET_7_BIT_DEFAULT;
                     break;

                  default:
                     pSubmitMsg->dcs.alphabet = WMS_GW_ALPHABET_8_BIT;
               }
   
               pSubmitMsg->dcs.msg_class         = WMS_MESSAGE_CLASS_NONE;
               pSubmitMsg->dcs.is_compressed = FALSE;
               pSubmitMsg->dcs.msg_waiting   = WMS_GW_MSG_WAITING_NONE;

               // TP-VP TP-Validity-Period - We shall not make use of this field
               // currently.
               if (pMsgData->dwTimeStamp)
               {
                  pSubmitMsg->validity.format = WMS_GW_VALIDITY_RELATIVE;
                  OEMWMS_SetTimeToWmsTimestamp(&pSubmitMsg->validity.u.time, pMsgData->dwTimeStamp);
               }
               else
               {
               pSubmitMsg->validity.format = WMS_GW_VALIDITY_NONE;
               }

               // TP-UD - User Data
               pSubmitMsg->user_data.sm_len = (uint8)MIN(pMsgPayload->nBytes,sizeof(pSubmitMsg->user_data.sm_data));
               MEMCPY((void*)&pSubmitMsg->user_data.sm_data, (void*)pMsgPayload->data, (uint32)pSubmitMsg->user_data.sm_len);

               // User Data Headers
               OEMWMS_ProcessUDHData(pClientTS, pMsgData->data, pMsgData->nBytes);
            }
            else
            {
               wms_gw_deliver_s_type * pDeliverMsg = NULL;

               // This will get exercised when storing an MT message
               pClientTS->u.gw_pp.tpdu_type = WMS_TPDU_DELIVER;

               // Start populating the Deliver Message.
               pDeliverMsg = (wms_gw_deliver_s_type *)&pClientTS->u.gw_pp.u.deliver;

               // TP-DA Source Address
               if (OEMWMS_SetGWAddress(&pDeliverMsg->address, pMsgData->szMOFromMTTo) != TRUE)
               {      
                  // Destination address has more digits than allowed
                  FARF(SMS, ("Destination address too large"));
                  return FALSE;
               }

               // TP-PID Protocol Identifier - Section 9.2.3.9 of TS 23.040.
               // Standard indicates that value of 0 can be used for simple
               // MS-to-SC short message transfer.
               pDeliverMsg->pid = WMS_PID_DEFAULT;

               // TP-DCS Data Coding Scheme
               switch (Xlate_2_NativeEncoding( pMsgPayload->nEncoding ))
               {
                  case WMS_ENCODING_UNICODE:
                     pDeliverMsg->dcs.alphabet = WMS_GW_ALPHABET_UCS2;
                     break;

                  case WMS_ENCODING_GSM_7_BIT_DEFAULT:
                     pDeliverMsg->dcs.alphabet = WMS_GW_ALPHABET_7_BIT_DEFAULT;
                     break;

                  default:
                     pDeliverMsg->dcs.alphabet = WMS_GW_ALPHABET_8_BIT;
               }
   
               pDeliverMsg->dcs.msg_class         = WMS_MESSAGE_CLASS_NONE;

               // TP-UD - User Data
               pDeliverMsg->user_data.sm_len = (uint8)MIN(pMsgPayload->nBytes,sizeof(pDeliverMsg->user_data.sm_data));
               MEMCPY((void*)&pDeliverMsg->user_data.sm_data, (void*)pMsgPayload->data, (uint32)pDeliverMsg->user_data.sm_len);

               // Teleservice
               OEMWMS_SetGSMMessageType(&pDeliverMsg->dcs, Xlate_2_NativeTS(pMsgData->ts));

               // Timestamp
               OEMWMS_SetTimeToWmsTimestamp(&pDeliverMsg->timestamp, pMsgData->dwTimeStamp);

               // Number of messages
               OEMWMS_SetNumMsgsInfoToGWMsg(pDeliverMsg, Xlate_2_NativeTS(pMsgData->ts), pMsgData->nNumMsgs);

               // User Data Headers
               OEMWMS_ProcessUDHData(pClientTS, pMsgData->data, pMsgData->nBytes);
            }
         }
         return TRUE;

      default:
         FARF(SMS, ("Unknown Mode"));
         return FALSE;
   }
}

/*===========================================================================

  Sets address in structure from address string for GW messages

===========================================================================*/
static boolean OEMWMS_SetGWAddress(wms_address_s_type * padr, char * pszAddress)
{
   char * pDst = NULL;
          
   if (!padr || !pszAddress || !*pszAddress)
   {
      return FALSE;
   }

   padr->digit_mode  = WMS_DIGIT_MODE_4_BIT;
   padr->number_mode = WMS_NUMBER_MODE_NONE_DATA_NETWORK;
   padr->number_plan = WMS_NUMBER_PLAN_TELEPHONY;

   pDst = (char *)pszAddress;

   if (DIALER_PLUS_CHAR == *pDst) 
   {
      padr->number_type = WMS_NUMBER_INTERNATIONAL;
      pDst++;
   } 
   else 
   {
      padr->number_type = WMS_NUMBER_NATIONAL;
   }

   if (STRLEN(pDst) <= WMS_ADDRESS_MAX)
   {
      padr->number_of_digits = STRLEN(pDst);
      GetASCII2DTMF(pDst, padr->digits, padr->number_of_digits);
   }
   else
   {      
      // Destination address has more digits than allowed
      FARF(SMS, ("Destination address too large"));
      return FALSE;
   }
   return TRUE;
}

/*===========================================================================

  Translates to native priority

===========================================================================*/
static wms_priority_e_type Xlate_2_NativePriority(int priority)
{
   int i;

   for (i = 0; i < sizeof(gsPriorityMap)/sizeof(PriorityMap); i++)
   {
      if (gsPriorityMap[i].AEE_Priority == priority)
         return gsPriorityMap[i].OEM_Priority;
   }
   return priority;
}

/*===========================================================================

  Translates to native privacy

===========================================================================*/
static wms_privacy_e_type Xlate_2_NativePrivacy(int privacy)
{
   int i;

   for (i = 0; i < sizeof(gsPrivacyMap)/sizeof(PrivacyMap); i++)
   {
      if (gsPrivacyMap[i].AEE_Privacy == privacy)
         return gsPrivacyMap[i].OEM_Privacy;
   }
   return privacy;
}

/*===========================================================================

  Translates to native language

===========================================================================*/
static wms_language_e_type Xlate_2_NativeLang(int lang)
{
   int i;

   for (i = 0; i < sizeof(gsLangMap)/sizeof(LangMap); i++)
   {
      if (gsLangMap[i].AEE_Lang == lang)
         return gsLangMap[i].OEM_Lang;
   }
   return lang;
}

/*===========================================================================

  Translates to AEE tag

===========================================================================*/
static uint32 Xlate_Tag(wms_message_tag_e_type tag)
{
   int i;

   for (i = 0; i < sizeof(gsTagMap)/sizeof(TagMap); i++)
   {
      if (gsTagMap[i].OEM_Tag == tag)
         return gsTagMap[i].AEE_Tag;
   }
   return tag;
}

/*===========================================================================

  Translates to native tag

===========================================================================*/
static wms_message_tag_e_type Xlate_2_NativeTag(int tag)
{
   int i;

   for (i = 0; i < sizeof(gsTagMap)/sizeof(TagMap); i++)
   {
      if (gsTagMap[i].AEE_Tag == tag)
         return gsTagMap[i].OEM_Tag;
   }
   return tag;
}

/*===========================================================================

  Translates to storage type

===========================================================================*/
static int Xlate_StorageType(wms_memory_store_e_type st)
{
   int i;

   for (i = 0; i < sizeof(gsStorageTypeMap)/sizeof(StorageTypeMap); i++)
   {
      if (gsStorageTypeMap[i].OEM_StorageType == st)
         return gsStorageTypeMap[i].AEE_StorageType;
   }
   return st;
}

/*===========================================================================

  Translates to native storage type

===========================================================================*/
static wms_memory_store_e_type Xlate_2_NativeStorageType(int st)
{
   int i;

   for (i = 0; i < sizeof(gsStorageTypeMap)/sizeof(StorageTypeMap); i++)
   {
      if (gsStorageTypeMap[i].AEE_StorageType == st)
         return gsStorageTypeMap[i].OEM_StorageType;
   }
   return st;
}

/*===========================================================================

  Translates to domain preference

===========================================================================*/
static int Xlate_DomainPref(wms_gw_domain_pref_e_type dp)
{
   int i;

   for (i = 0; i < sizeof(gsGWDomainPrefMap)/sizeof(GWDomainPrefMap); i++)
   {
      if (gsGWDomainPrefMap[i].DMSS_DomainPref == dp)
         return gsGWDomainPrefMap[i].AEE_DomainPref;
   }
   return dp;
}

/*===========================================================================

  Translates to native domain preference

===========================================================================*/
static wms_gw_domain_pref_e_type Xlate_2_NativeDomainPref(int dp)
{
   int i;

   for (i = 0; i < sizeof(gsGWDomainPrefMap)/sizeof(GWDomainPrefMap); i++)
   {
      if (gsGWDomainPrefMap[i].AEE_DomainPref == dp)
         return gsGWDomainPrefMap[i].DMSS_DomainPref;
   }
   return dp;
}

/*===========================================================================

  Constructs a client message type from the raw bearer data

===========================================================================*/
static boolean OEMWMS_ConstructClientMessage
(
   OEMMsgData * pMsgData,
   wms_client_message_s_type * pMsg,
   wms_raw_ts_data_s_type * pRaw,
   sys_sys_mode_e_type sysMode
) 
{
   FARF(SMS, ("==>  OEMWMS_ConstructClientMessage"));

   switch (sysMode)
   {
      case SYS_SYS_MODE_CDMA:
         {
            wms_cdma_message_s_type * pCMsg;

            FARF(SMS, ("CDMA Mode Message"));

            pMsg->msg_hdr.message_mode = WMS_MESSAGE_MODE_CDMA;
            pMsg->msg_hdr.tag          = Xlate_2_NativeTag(pMsgData->dwTag);
            pMsg->msg_hdr.mem_store    = WMS_MEMORY_STORE_NONE;
            pMsg->msg_hdr.index        = WMS_DUMMY_MESSAGE_INDEX;

            pCMsg = (wms_cdma_message_s_type *)&pMsg->u.cdma_message;

            pCMsg->is_mo = pMsgData->bIsMOSMS; 
            pCMsg->is_tl_ack_requested = TRUE;
            pCMsg->service = WMS_SRV_UNKOWN;

            if (pMsgData->bIsMOSMS)
            {
               if (pMsgData->bIsBREWDirectedSMS)
               {
                  if (OEM_GetConfig(CFGI_BREWDIR_SMS_TELESERVICE, (void*)&pCMsg->teleservice, sizeof(pCMsg->teleservice)) != SUCCESS)
                  {
                     pCMsg->teleservice = WMS_TELESERVICE_CMT_95;
                  }
               }
               else
               {
                  pCMsg->teleservice = Xlate_2_NativeTS(pMsgData->ts);
               }
            }
            else
            {
               pCMsg->teleservice = Xlate_2_NativeTS(pMsgData->ts);
            }

            // Set the raw_bd field with what we created above
            MEMCPY(&pCMsg->raw_ts, pRaw, sizeof(wms_raw_ts_data_s_type));   
   
            OEMWMS_SetCDMAAddress(&pCMsg->address, pMsgData->szMOFromMTTo);

         }
         return TRUE;

      case SYS_SYS_MODE_GSM:
         {
            wms_gw_message_s_type * pCMsg;
         
            FARF(SMS, ("GSM Mode Message"));

            // Populate the msg_hdr structure
            pMsg->msg_hdr.index        = WMS_DUMMY_MESSAGE_INDEX;
            pMsg->msg_hdr.mem_store    = WMS_MEMORY_STORE_NONE;
            pMsg->msg_hdr.message_mode = WMS_MESSAGE_MODE_GW;
            pMsg->msg_hdr.tag          = Xlate_2_NativeTag(pMsgData->dwTag);

            pCMsg = (wms_gw_message_s_type *)&pMsg->u.gw_message;

            // Populate the gw_message structure
            pCMsg->is_broadcast = FALSE;
   
            if (*pMsgData->szCallback)
            {
               if (OEMWMS_SetGWSCAddress(&pCMsg->sc_address, pMsgData->szCallback) != TRUE)
               {
                  FARF(SMS, ("Failed to set SC address"));
                  return FALSE; 
               }
            }
            else
            {
               int nSize;
               char * pszSCAddress = NULL;
               if ((OEM_GetConfig(CFGI_SMS_GW_SCADDRESS_LENGTH, &nSize, sizeof(nSize)) != SUCCESS) ||
                   ((pszSCAddress = (char*)MALLOC(nSize+1)) == NULL) ||
                   (OEM_GetConfig(CFGI_SMS_GW_SCADDRESS, (uint32*)pszSCAddress, nSize + 1) != SUCCESS) ||
                   (OEMWMS_SetGWSCAddress(&pCMsg->sc_address, pszSCAddress) != TRUE))
               {
                  FREEIF(pszSCAddress);
                  FARF(SMS, ("Failed to set SC address"));
                  return FALSE;
               }
               else
               {
                  FREEIF(pszSCAddress);
               }
            }

            MEMCPY(&pCMsg->raw_ts_data, pRaw, sizeof(wms_raw_ts_data_s_type));
         }
         return TRUE;

      default:
         FARF(SMS, ("Unknown Mode"));
         return FALSE;
   }
}

/*===========================================================================

  Sets SC address in structure from address string

===========================================================================*/
static boolean OEMWMS_SetGWSCAddress(wms_address_s_type * pscadr, char * pszSCAddress)
{
   char * pDst = pszSCAddress;

   if (!pscadr || !pszSCAddress || !*pszSCAddress)
   {
      return FALSE;
   }

   if (DIALER_PLUS_CHAR == pszSCAddress[0]) 
   {
      pDst++; // Skip '+'
      STRNCPY((char*)pscadr->digits, pDst, STRLEN(pDst));
      pscadr->number_type = WMS_NUMBER_INTERNATIONAL;
   } 
   else 
   {
      STRNCPY((char*)pscadr->digits, pDst, STRLEN(pDst));
      pscadr->number_type = WMS_NUMBER_UNKNOWN;
   }

   pscadr->number_of_digits = (uint8)STRLEN((char*)pscadr->digits);
      
   pscadr->digit_mode  = WMS_DIGIT_MODE_4_BIT;

   pscadr->number_plan = WMS_NUMBER_PLAN_TELEPHONY;

   return TRUE;
}

/*===========================================================================

  Sets address in structure from address string for CDMA messages

===========================================================================*/
static boolean OEMWMS_SetCDMAAddress(wms_address_s_type * psadr, char* pszAddress)
{
   char * atStringPtr, * dotStringPtr;

   if (!psadr || !pszAddress || !*pszAddress)
   {
      return FALSE;
   }

            // Determine whether the To address is an email address or a phone number.
            // We just check for <some chars>@<some chars>.<some chars>. May not be a 
            // totally fool proof way of checking/validating the email address. 
            // But it works!!!
   atStringPtr = STRCHR(pszAddress,(char)'@');
   dotStringPtr = STRCHR(pszAddress,(char)'.');

            // Check to make sure that the user entered both "@" and "." symbols
            // in his send to address.
            if (atStringPtr && dotStringPtr) 
            {   
               // Send address is an email address. Code the digit mode, number mode and
               // the number type accordingly.
      psadr->digit_mode = WMS_DIGIT_MODE_8_BIT;            // 8 bit ASCII codes
      psadr->number_mode = WMS_NUMBER_MODE_DATA_NETWORK; 
      psadr->number_type = WMS_NUMBER_INTERNET_EMAIL;          // EMAIL address
      MEMSET((byte*)psadr->digits, 0, sizeof(psadr->digits));
      STRNCPY((char*)psadr->digits, pszAddress, sizeof(psadr->digits)-1);
      psadr->number_of_digits = (byte)STRLEN((char *)pszAddress);
            } 
            else 
            {  
      if (DIALER_PLUS_CHAR == *pszAddress) 
               {
                  if (OEM_CONFIG_ALLOW_INTERNATIONAL) 
                  {
            char * pcBuf = (char*)(pszAddress + 1); // Remove '+' char
            psadr->digit_mode  = WMS_DIGIT_MODE_8_BIT;
            psadr->number_mode = WMS_NUMBER_MODE_NONE_DATA_NETWORK;
            psadr->number_type = WMS_NUMBER_INTERNATIONAL;
            MEMSET((byte*)psadr->digits, 0, sizeof(psadr->digits));
                     // Remove the plus character and copy
            STRNCPY((char*)psadr->digits, pcBuf, sizeof(psadr->digits) - 1);         
            psadr->number_of_digits = (byte)STRLEN((char *)pcBuf);
                  } 
                  else 
                  {
                     int nPrefix = STRLEN(OEM_CONFIG_INTERNATIONAL_PREFIX);
            psadr->digit_mode = WMS_DIGIT_MODE_4_BIT;   // DTMF digits
            psadr->number_mode = WMS_NUMBER_MODE_NONE_DATA_NETWORK;  
            psadr->number_type = WMS_NUMBER_UNKNOWN;  
            psadr->number_plan = WMS_NUMBER_PLAN_UNKNOWN; 

                     if (nPrefix)
                     {            
               GetASCII2DTMF((char *)OEM_CONFIG_INTERNATIONAL_PREFIX, (byte*)psadr->digits, nPrefix);
                     }         
            
            GetASCII2DTMF((char *)pszAddress, (byte*)(psadr->digits + nPrefix), STRLEN((char *)pszAddress));
            psadr->number_of_digits = (byte)(nPrefix + STRLEN((char *)pszAddress));
                  }
               }
               else
               {
         psadr->digit_mode = WMS_DIGIT_MODE_4_BIT;   // DTMF digits
         psadr->number_mode = WMS_NUMBER_MODE_NONE_DATA_NETWORK; 
         psadr->number_type = WMS_NUMBER_UNKNOWN;  
         psadr->number_plan = WMS_NUMBER_PLAN_UNKNOWN; 
   
         GetASCII2DTMF((char *)pszAddress, (byte*)psadr->digits, STRLEN((char *)pszAddress));
   
         psadr->number_of_digits = (byte)STRLEN((char *)pszAddress);
               }
            }
   return TRUE;
         }

/*===========================================================================
         
  Constructs a client message type from the raw bearer data

===========================================================================*/
static boolean OEMWMS_ConstructCDMATemplate
(
   OEMMsgData * pMsgData, 
   wms_client_message_s_type * pMsg, 
   wms_client_bd_s_type * pClientBD
)
{
   FARF(SMS, ("==>  OEMWMS_ConstructCDMATemplate"));

   pMsg->u.cdma_template.teleservice = Xlate_2_NativeTS(pMsgData->ts);

   pMsg->u.cdma_template.mask |= WMS_CDMA_TEMPLATE_MASK_DEST_ADDR;
   OEMWMS_SetCDMAAddress(&pMsg->u.cdma_template.address, pMsgData->szMOFromMTTo);
   
   if (pMsgData->dwTimeStamp)
            {
      pMsg->u.cdma_template.mask |= WMS_CDMA_TEMPLATE_MASK_VALIDITY;
      OEMWMS_SetTimeToWmsTimestamp(&pMsg->u.cdma_template.relative_validity, pMsgData->dwTimeStamp);
   }

   pMsg->u.cdma_template.mask |= WMS_CDMA_TEMPLATE_MASK_BEARER_DATA;
   MEMCPY(&pMsg->u.cdma_template.client_bd, pClientBD, sizeof(wms_client_bd_s_type));
               } 

/*===========================================================================

  Constructs a client message type from the raw bearer data

===========================================================================*/
static boolean OEMWMS_ConstructGWTemplate
(
   OEMMsgData * pMsgData, 
   wms_client_message_s_type * pMsg
)
               {
   FARF(SMS, ("==>  OEMWMS_ConstructGWTemplate"));

   pMsg->u.gw_template.mask |= WMS_GW_TEMPLATE_MASK_DEST_ADDR;
   OEMWMS_SetGWAddress(&pMsg->u.gw_template.dest_addr, pMsgData->szMOFromMTTo);
      
   pMsg->u.gw_template.mask |= WMS_GW_TEMPLATE_MASK_SC_ADDR;
   OEMWMS_SetGWAddress(&pMsg->u.gw_template.sc_addr, pMsgData->szCallback);

   if (pMsgData->dwTimeStamp)
            {
      pMsg->u.gw_template.mask |= WMS_GW_TEMPLATE_MASK_VALIDITY;
      OEMWMS_SetTimeToWmsTimestamp(&pMsg->u.gw_template.relative_validity, pMsgData->dwTimeStamp);
            }

   pMsg->u.gw_template.mask |= WMS_GW_TEMPLATE_MASK_DCS;
   OEMWMS_SetGSMMessageType(&pMsg->u.gw_template.dcs, pMsgData->ts);
}

/*===========================================================================

  Called to send SMS

===========================================================================*/
void OEMSMS_SendSMS( OEMMsg* hMsg, AEECallback *pcb, uint32 *pdwStatus )
{
   int nErr = SUCCESS;
   uint32 dwStatus = 0;

   FARF(SMS, ("==>  OEMSMS_SendSMS"));

   if(!gpWms) 
   {
      nErr = EFAILED;
      AEESMS_SETERROR(dwStatus, AEESMS_ERRORTYPE_TEMP, AEESMS_ERROR_GENERAL_PROBLEM);
      goto Done;
   }

   if(gpWms->pCurMOSMS != 0) 
   {
      nErr = EITEMBUSY;
      AEESMS_SETERROR(dwStatus, AEESMS_ERRORTYPE_TEMP, AEESMS_ERROR_BUSY);
      goto Done;
   }

   // Install the message being processed
   hMsg->pcb = pcb;
   hMsg->pdwStatus = pdwStatus;
   gpWms->pCurMOSMS = hMsg;

   if (gpWms->bMOOnAccessChannel)
   {
      nErr = wms_msg_send( gpWms->clientId, 
                           &OEMWSMS_CommandCallback, 
                           (const void *)hMsg, 
                           WMS_SEND_MODE_CLIENT_MESSAGE, 
                           &hMsg->CMsg );
   }
   else if (gpWms->bMOOnTrafficChannel)
   {
      nErr = OEMWMS_SendSMSOnTrafficChannel();
   }
   else
   {
      FARF(SMS, ("Configuration Problem - Channel not specified for MO SMS"));
      nErr = EFAILED;
      AEESMS_SETERROR(dwStatus, AEESMS_ERRORTYPE_TEMP, AEESMS_ERROR_GENERAL_PROBLEM);
      goto Done;
   }

   if( nErr != WMS_OK_S )
   {
      AEESMS_SETERROR(dwStatus, AEESMS_ERRORTYPE_UNKNOWN, Xlate_wms_status_e_type_2_MOSMS_ERR(nErr));
      nErr = EFAILED;
   }
   else 
   {
      nErr = SUCCESS;
   }

Done:
   if (nErr != SUCCESS)
   {
      OEMSMS_DeleteMessage(hMsg);
      *pdwStatus = dwStatus;
      AEE_SVC_RESUME(pcb);
   }
}

/*===========================================================================

   Event Listener

===========================================================================*/
static void OEMWMS_EventListener( wms_dc_event_e_type event, 
                                  wms_dc_event_info_s_type * info_ptr )
{
   wms_status_e_type ret = WMS_NETWORK_FAILURE_S;

   FARF(SMS,("Phone_EventListener"));

   //We are interested in the Events only if we had initiated the DC to be brought up for
   //sending a SMS.

   if( gpWms->bTranmissionPending == FALSE ) 
   {
      return;
   }

   if( gpWms->pCurMOSMS == 0 ) 
   {
      gpWms->bTranmissionPending = FALSE;
      return;
   }

   switch( event ) 
   {
      case WMS_DC_EVENT_CONNECTING:
         break;

      case WMS_DC_EVENT_CONNECTED:
         FARF(SMS, ("Phone_EL_CONN"));

         //When message is sent (or failed), the function OEMSMS_MessageListener() is invoked
         ret  = wms_msg_send( gpWms->clientId, 
                              &OEMWSMS_CommandCallback, 
                              gpWms->pCurMOSMS, 
                              WMS_SEND_MODE_CLIENT_MESSAGE, 
                              &gpWms->pCurMOSMS->CMsg ); 

         // Flag to indicate a dedicated traffic channel has been setup.
         gpWms->bDedicatedChannel = TRUE;

         // Fall through

      default:
         gpWms->bTranmissionPending = FALSE;

         if( ret != WMS_OK_S ) 
         {
            AEESMS_SETERROR(*(gpWms->pCurMOSMS->pdwStatus), AEESMS_ERRORTYPE_UNKNOWN, Xlate_wms_status_e_type_2_MOSMS_ERR(ret));
            AEE_SVC_RESUME( gpWms->pCurMOSMS->pcb );
            OEMSMS_DeleteMessage( gpWms->pCurMOSMS );
         }
   }
}

/*===========================================================================

  Translates WMS status to AEE error

===========================================================================*/
static int Xlate_wms_status_e_type_2_MOSMS_ERR( wms_status_e_type e )
{  
   switch(e) 
   {
      case WMS_OK_S:
         return AEESMS_ERROR_NONE;

      case WMS_OUT_OF_RESOURCES_S:
         return AEESMS_ERROR_NO_MEMORY;

      case WMS_NOT_ALLOWED_IN_AMPS_S:
      case WMS_NETWORK_FAILURE_S:
      case WMS_NETWORK_NOT_READY_S:
         return AEESMS_ERROR_NETWORK_PROBLEM;

      default:
         return AEESMS_ERROR_GENERAL_PROBLEM;
   }
}

/*===========================================================================

  Translates WMS CDMA TL status to AEE error

===========================================================================*/
static int Xlate_wms_cdma_tl_status_e_type_2_MOSMS_ERR( wms_cdma_tl_status_e_type e )
{  
   switch(e) 
   {
      case WMS_TL_ADDRESS_TRANSLATION_FAILURE_S:
         return AEESMS_ERROR_ADDRESS_TRANSLATION_FAILURE;

      case WMS_TL_SMS_ORIGINATION_DENIED_S:
         return AEESMS_ERROR_SMS_ORIGINATION_DENIED;

      case WMS_TL_SMS_TERMINATION_DENIED_S:
         return AEESMS_ERROR_SMS_TERMINATION_DENIED;

      case WMS_TL_SMS_NOT_SUPPORTED_S:
         return AEESMS_ERROR_SMS_NOT_SUPPORTED;

      case WMS_TL_ADDRESS_VACANT_S:
      case WMS_TL_NETWORK_RESOURCE_SHORTAGE_S:
      case WMS_TL_NETWORK_FAILURE_S:
      case WMS_TL_INVALID_TELESERVICE_ID_S:
      case WMS_TL_OTHER_NETWORK_PROBLEM_S:
         return AEESMS_ERROR_NETWORK_PROBLEM;

      case WMS_TL_NO_PAGE_RESPONSE_S:
      case WMS_TL_DESTINATION_BUSY_S:
      case WMS_TL_NO_ACK_S:
      case WMS_TL_DESTINATION_RESOURCE_SHORTAGE_S:
      case WMS_TL_SMS_DELIVERY_POSTPONED_S:
      case WMS_TL_DESTINATION_OUT_OF_SERVICE_S:
      case WMS_TL_DESTINATION_NO_LONGER_AT_THIS_ADDRESS_S:
      case WMS_TL_OTHER_TERMINAL_PROBLEM_S:
         return AEESMS_ERROR_DESTINATION_PROBLEM;


      case WMS_TL_RADIO_IF_RESOURCE_SHORTAGE_S:
      case WMS_TL_RADIO_IF_INCOMPATIBLE_S:
      case WMS_TL_OTHER_RADIO_IF_PROBLEM_S:
         return AEESMS_ERROR_RADIO_PROBLEM;

      default:
         return AEESMS_ERROR_GENERAL_PROBLEM;
   }
}

/*===========================================================================

  Translates WMS retort status to AEE error

===========================================================================*/
static int Xlate_wms_report_status_e_type_2_MOSMS_ERR( wms_report_status_e_type e )
{  
   switch(e) 
   {
      case WMS_RPT_OK:
         return AEESMS_ERROR_NONE;

      case WMS_RPT_OUT_OF_RESOURCES:
         return AEESMS_ERROR_NO_MEMORY;

      case WMS_RPT_NOT_ALLOWED_IN_AMPS:
      case WMS_NETWORK_FAILURE_S:
      case WMS_RPT_NETWORK_NOT_READY:
         return AEESMS_ERROR_NETWORK_PROBLEM;

      default:
         return AEESMS_ERROR_GENERAL_PROBLEM;
   }
}

/*===========================================================================

  Translates cause to AEE error

===========================================================================*/
static int Xlate_wms_tp_cause_e_type_2_MOSMS_ERR( wms_tp_cause_e_type e )
{  
   switch(e) 
   {
      case WMS_TP_CAUSE_TELEMATIC_NOT_SUPPORTED:
         return AEESMS_ERROR_UNSUPPORTED_TELEMATIC;

      case WMS_TP_CAUSE_SM_TYPE0_NOT_SUPPORTED:
      case WMS_TP_CAUSE_CANNOT_REPLACE_SM:
      case WMS_TP_CAUSE_UNSPECIFIED_PID_ERROR:
         return AEESMS_ERROR_PID_PROBLEM;
      
      case WMS_TP_CAUSE_ALPHABET_NOT_SUPPORTED:
         return AEESMS_ERROR_ALPHABET_NOT_SUPPORTED;

      case WMS_TP_CAUSE_MSG_CLASS_NOT_SUPPORTED:
         return AEESMS_ERROR_MSG_CLASS_NOT_SUPPORTED;

      case WMS_TP_CAUSE_SC_BUSY:
         return AEESMS_ERROR_SC_BUSY;

      case WMS_TP_CAUSE_NO_SC_SUBSCRIPTION:
         return AEESMS_ERROR_NO_SC_SUBSCRIPTION;

      case WMS_TP_CAUSE_SC_FAILURE:
         return AEESMS_ERROR_SC_FAILURE;

      default:
         return AEESMS_ERROR_GENERAL_PROBLEM;
   }
}

/*===========================================================================

  Translates wms_error_class_e_type to MOSMS error type
===========================================================================*/
static int Xlate_wms_error_class_e_type_2_MOSMS_ERRTYPE( wms_error_class_e_type e )
{
   switch (e)
   {
      case WMS_ERROR_NONE:
         return AEESMS_ERRORTYPE_NONE;

      case WMS_ERROR_TEMP:
         return AEESMS_ERRORTYPE_TEMP;

      case WMS_ERROR_PERM:
         return AEESMS_ERRORTYPE_PERM;

      default:
         return AEESMS_ERRORTYPE_UNKNOWN;
   }
}
/*===========================================================================

  Deletes OEMMsg instance

===========================================================================*/
void OEMSMS_DeleteMessage( OEMMsg* hMsg )
{
   if( gpWms && gpWms->pCurMOSMS == hMsg ) 
   {      
      if( gpWms->bDedicatedChannel ) 
      {
#ifdef FEATURE_CDSMS
         (void) wms_dc_disconnect( gpWms->clientId, &OEMWSMS_NoopCommandCallback, NULL );
         gpWms->bDedicatedChannel = FALSE;
#endif
      }

      gpWms->bTranmissionPending = FALSE;
      gpWms->pCurMOSMS = 0;
   }

   if ( hMsg )
      sys_free( hMsg );
}

/*===========================================================================

   Deregisters Message, Event and Status listeners

===========================================================================*/
int OEMSMS_Cleanup( void )
{
   if( gpWms ) 
   {
      wms_client_deactivate(gpWms->clientId);
      wms_client_release(gpWms->clientId);

      sys_free( gpWms );

      gpWms = 0;
   }

   return SUCCESS;
}

/*===========================================================================

   Sends SMS on traffic channel

===========================================================================*/
static wms_status_e_type OEMWMS_SendSMSOnTrafficChannel(void)
{
   OEMPhone * pPhone = NULL;
   wms_status_e_type nErr = WMS_OUT_OF_RESOURCES_S;

   //Check if the Traffic Channel is Already up. If yes, proceed with sending the msg
   if(SUCCESS == OEMPhone_New(&pPhone))
   {
      if(OEMPhone_InConversation(pPhone)) 
      {
         FARF(SMS, ("SMS in call"));

         // if this succeeds, response falls in OEMSMS_EventListener()
         if ((nErr = wms_msg_send( gpWms->clientId, 
                              &OEMWSMS_CommandCallback, 
                              (const void *)gpWms->pCurMOSMS, 
                              WMS_SEND_MODE_CLIENT_MESSAGE, 
                              &gpWms->pCurMOSMS->CMsg )) != WMS_OK_S)         
         {
            FARF(SMS, ("Send SMS in call failed"));
         }
      }
      else 
      {      
         // Raise the SO6 traffic channel
         // Flag for sending over traffic channel
         gpWms->bTranmissionPending = TRUE;
         
         // If this succeeds, response falls in OEMSMS_EventListener()         
         if ((nErr = wms_dc_connect( gpWms->clientId, 
                                &OEMWSMS_CommandCallback, 
                                (const void *)gpWms->pCurMOSMS, 
                                WMS_DC_SO_6 )) != WMS_OK_S)

         {
            FARF(SMS, ("DTC connect failed"));
            gpWms->bTranmissionPending = FALSE;
         }
      }
      OEMPhone_Release(pPhone);
   }
   else
   {
      FARF(SMS, ("OEMPhone_New failed during MO SMS"));
   }
   return nErr;
}

/*===========================================================================

   OEMWMS_GetMemoryStatus

===========================================================================*/
static void OEMWMS_GetMemoryStatus(wms_memory_store_e_type wmsMemoryStore)
{
   wms_status_e_type wmsStatus;

   FARF(SMS, ("OEMWMS_GetMemoryStatus"));

   wmsStatus = wms_cfg_get_memory_status(gpWms->clientId,
                                        &OEMWSMS_NoopCommandCallback,
                                        NULL,
                                        wmsMemoryStore,
                                        WMS_TAG_NONE);
   if (wmsStatus != WMS_OK_S) 
   {
      FARF(SMS, ("wms_cfg_get_memory_status failed err = %d", wmsStatus));
   }
}

/*===========================================================================

   OEMWMS_SetMsgTransferRoute

===========================================================================*/
static void OEMWMS_SetMsgTransferRoute()
{
   int i;
   wms_status_e_type wmsStatus;
   wms_routes_s_type routes;

   FARF(SMS, ("OEMWMS_SetMsgTransferRoute"));

   MEMSET(&routes, 0, sizeof(wms_routes_s_type));
   for (i = 0; i < WMS_MESSAGE_CLASS_MAX; i++)
   {
      routes.pp_routes[i].route = WMS_ROUTE_TRANSFER_ONLY;
      routes.pp_routes[i].mem_store = WMS_MEMORY_STORE_NONE;

      routes.bc_routes[i].route = WMS_ROUTE_TRANSFER_ONLY;
      routes.bc_routes[i].mem_store = WMS_MEMORY_STORE_NONE;
   }
   routes.transfer_status_report = 1;

   wmsStatus = wms_cfg_set_routes(gpWms->clientId,
                                  &OEMWSMS_NoopCommandCallback,
                                  NULL,
                                  &routes);
   if (wmsStatus != WMS_OK_S) 
   {
      FARF(SMS, ("wms_cfg_set_routes failed err = %d", wmsStatus));
   }
}

/*===========================================================================

   OEMWMS_GetDomainPref

===========================================================================*/
static void OEMWMS_GetDomainPref()
{
   wms_status_e_type wmsStatus;

   FARF(SMS, ("OEMWMS_GetDomainPref"));

   wmsStatus = wms_cfg_get_gw_domain_pref(gpWms->clientId,
                                          &OEMWSMS_NoopCommandCallback,
                                          NULL);

   if (wmsStatus != WMS_OK_S) 
   {
      FARF(SMS, ("wms_cfg_get_gw_domain_pref failed err = %d", wmsStatus));
   }
}

/*===========================================================================

   OEMSMS_GetDomainPref

===========================================================================*/
int OEMSMS_GetDomainPref(int * pgwDomainPref)
{
   FARF(SMS, ("OEMSMS_GetDomainPref"));

   if (!pgwDomainPref)
   {
      return EBADPARM;
   }

   if (gpWms)
   {
      *pgwDomainPref = Xlate_DomainPref(gpWms->gwDomainPref);
      return SUCCESS;
   }
   else
   {
      return EFAILED;
   }
}

/*===========================================================================

   OEMSMS_SetDomainPref

===========================================================================*/
int OEMSMS_SetDomainPref(int gwDomainPref)
{
   FARF(SMS, ("OEMSMS_SetDomainPref"));

   if (!gpWms)
   {
      return EFAILED;
   }

   if (gwDomainPref < AEESMS_GW_DOMAIN_PREF_LAST)
   {
      wms_status_e_type wmsStatus;
      wmsStatus = wms_cfg_set_gw_domain_pref(gpWms->clientId,
                                             &OEMWSMS_NoopCommandCallback,
                                             NULL,
                                             Xlate_2_NativeDomainPref(gwDomainPref));

      if (wmsStatus != WMS_OK_S) 
      {
         FARF(SMS, ("wms_cfg_set_gw_domain_pref failed err = %d", wmsStatus));
         return EFAILED;
      }
      return SUCCESS;
   }
   else
   {
      return EBADPARM;
   }
}

/*===========================================================================

   OEMWMS_GetMessageList

===========================================================================*/
static void OEMWMS_GetMessageList(wms_memory_store_e_type wmsMemoryStore)
{
   wms_status_e_type wmsStatus;

   FARF(SMS, ("OEMWMS_GetMessageList"));

   wmsStatus = wms_cfg_get_message_list(gpWms->clientId,
                                        &OEMWSMS_NoopCommandCallback,
                                        NULL,
                                        wmsMemoryStore,
                                        WMS_TAG_NONE);
   if (wmsStatus != WMS_OK_S) 
   {
      FARF(SMS, ("wms_cfg_get_message_list failed err = %d", wmsStatus));
   }
}

/*===========================================================================

   Returns TRUE if storage is initialized. Returns FALSE otherwise.

===========================================================================*/
boolean OEMSMS_IsStorageInitialized( void )
{
   sys_sys_mode_e_type sysMode;

   FARF(SMS, ("OEMSMS_IsStorageInitialized"));

   sysMode = OEMWMS_GetSystemMode();

   switch (sysMode)
   {
      case SYS_SYS_MODE_CDMA:
         return (gpWms->bStrInit[AEESMS_CARD_RUIM] && gpWms->bStrInit[AEESMS_NV_CDMA]);

      case SYS_SYS_MODE_GSM:
         return (gpWms->bStrInit[AEESMS_CARD_SIM] && gpWms->bStrInit[AEESMS_NV_GW]);

      default:
         return FALSE;
   }
}

/*===========================================================================

   Returns storage status

===========================================================================*/  
void OEMSMS_GetStorageStatus( AEESMSStorageType st, AEESMSTag mt, AEESMSStorageStatus * pss, uint32 * pnRv, AEECallback *pcb )
{
   int i, nErr = SUCCESS;

   FARF(SMS, ("OEMSMS_GetStorageStatus"));

   if (st < AEESMS_STORAGE_LAST)
   {
      if (gpWms->bStrInit[st] == FALSE) 
      {
         nErr = EFAILED;
         goto Done;
      }

      for (i = 0; i < gpWms->ucStrSMSCount[st]; i++)
      {
         if (gpWms->strSMSMsgList[st][i] == WMS_TAG_NONE)
            pss->nFreeSlots++;

         if (gpWms->strSMSMsgList[st][i] == Xlate_2_NativeTag(mt))
            pss->nUsedTagSlots++;
      }
      pss->nMaxSlots = gpWms->ucStrSMSCount[st];
      pss->nSize = sizeof(AEESMSStorageStatus);
   }
   else
   {
      nErr = EBADPARM;
      goto Done;
   }

Done:
   *pnRv = nErr;
   AEE_SVC_RESUME(pcb);
}

/*===========================================================================

   Stores a message on the card

===========================================================================*/  
void OEMSMS_StoreMsg( AEESMSStorageType st, OEMMsgData * pMsgData, OEMMsgPayload * pMsgPayload, uint32 * pnIndex, uint32 *pnRv, AEECallback *pcb )
{
   int nErr = SUCCESS, nIndex; 
   OEMMsg *hMsg;

   FARF(SMS, ("OEMSMS_StoreMsg"));

   if (st < AEESMS_STORAGE_LAST)
   {
      if (gpWms->bStrInit[st] == FALSE) 
      {
         nErr = EFAILED;
         goto Done;
      }

      for (nIndex = 0; nIndex < gpWms->ucStrSMSCount[st]; nIndex++)
      {
         if (gpWms->strSMSMsgList[st][nIndex] == WMS_TAG_NONE)
            break;
      }

      if (nIndex >= gpWms->ucStrSMSCount[st])
      {
         nErr = EFAILED;
         goto Done;
      }
   }
   else
   {
      nErr = EBADPARM;
      goto Done;
   }

   hMsg = OEMSMS_NewMessage( pMsgData, pMsgPayload );

   if (hMsg) 
   {
      *pnIndex = nIndex;

      gpWms->strSMSMsgList[st][nIndex] = Xlate_2_NativeTag(pMsgData->dwTag);
      hMsg->CMsg.msg_hdr.mem_store = Xlate_2_NativeStorageType(st);

      if (st == AEESMS_CARD_RUIM || st == AEESMS_NV_CDMA)
      {
         hMsg->CMsg.msg_hdr.message_mode = WMS_MESSAGE_MODE_CDMA;
      }
      else if (st == AEESMS_CARD_SIM || st == AEESMS_NV_GW)
      {
         hMsg->CMsg.msg_hdr.message_mode = WMS_MESSAGE_MODE_GW;
      }

      hMsg->CMsg.msg_hdr.index = nIndex;
   
      CALLBACK_Cancel(pcb);
      pcb->pCancelData = hMsg;
      pcb->pfnCancel   = OEMWMS_ReleaseStoreSMS;
      OEMWMS_StoreSMS( hMsg, pcb, pnRv );
   }
   else
      nErr = ENOMEMORY;

Done:
   if( SUCCESS != nErr ) 
   {
      *pnRv = nErr;
      AEE_SVC_RESUME( pcb );
   }
}

/*===========================================================================

  Called to store SMS

===========================================================================*/
static void OEMWMS_StoreSMS( OEMMsg* hMsg, AEECallback *pcb, uint32 *pdwStatus )
{
   int nErr = SUCCESS;   
   wms_status_e_type wmsStatus;

   FARF(SMS, ("==>  OEMWMS_StoreSMS"));

   if(!gpWms) 
   {
      nErr = EFAILED;
      goto Done;
   }

   if(gpWms->pCurStoreSMS != 0) 
   {
      nErr = EITEMBUSY;
      goto Done;
   }

   wmsStatus = wms_msg_write( gpWms->clientId, 
                              &OEMWSMS_CommandCallback,
                              (const void *)hMsg,
                              WMS_WRITE_MODE_INSERT,
                              &hMsg->CMsg);
   
   if( wmsStatus != WMS_OK_S )
   {
      nErr = EFAILED;
   }
   else 
   {
      hMsg->pcb = pcb;
      hMsg->pdwStatus = pdwStatus;
      gpWms->pCurStoreSMS = hMsg;
      nErr = SUCCESS;
   }

Done:
   if (nErr != SUCCESS)
   {
      *pdwStatus = nErr;
      AEE_SVC_RESUME(pcb);
      OEMWMS_DeleteStoreSMS(hMsg);
   }
}

/*===========================================================================

  Called to release store SMS struct

===========================================================================*/
static void OEMWMS_ReleaseStoreSMS( AEECallback *pcb )
{
   FARF(SMS, ("==>  OEMWMS_ReleaseStoreSMS"));

  //Verify that it is me set as the cancel function.
   //Cross-task cancellations need this check.
   if(pcb->pfnCancel != OEMWMS_ReleaseStoreSMS)
      return;
   
   OEMWMS_DeleteStoreSMS( (OEMMsg*)pcb->pCancelData );

   pcb->pCancelData = 0;
   pcb->pfnCancel   = 0;
}

/*===========================================================================

  Deletes OEMMsg instance for Store SMS

===========================================================================*/
static void OEMWMS_DeleteStoreSMS(OEMMsg * hMsg)
{
   if( gpWms && gpWms->pCurStoreSMS == hMsg ) 
   {      
      gpWms->pCurStoreSMS = 0;
   }

   if ( hMsg )
      sys_free( hMsg );
}

/*===========================================================================

   Listener Invoked on WMS_MSG_EVENT_WRITE

===========================================================================*/  
static void OEMWMS_StoreSMSListener
(
   wms_msg_event_info_s_type * info_ptr
)
{
   OEMMsg  *hMsg = (OEMMsg *)info_ptr->status_info.user_data;

   if (!gpWms || !gpWms->pCurStoreSMS)
   {
      return;
   }

   if( hMsg == gpWms->pCurStoreSMS )
      *gpWms->pCurStoreSMS->pdwStatus = SUCCESS;
   else
      *gpWms->pCurStoreSMS->pdwStatus = EFAILED;
   
      AEE_SVC_RESUME( gpWms->pCurStoreSMS->pcb );
   OEMWMS_DeleteStoreSMS(gpWms->pCurStoreSMS);
   }

/*===========================================================================

   Reads a message from the card

===========================================================================*/  
void OEMSMS_ReadMsg( AEESMSStorageType st, uint32 nIndex, OEMMsgData * pMsgData, OEMMsgPayload * pMsgPayload, uint32 * pnRv, AEECallback *pcb )
{
   int nErr = SUCCESS; 
   void *hMsg;

   FARF(SMS, ("OEMSMS_StoreMsg"));

   if (st < AEESMS_STORAGE_LAST)
   {
      if (gpWms->bStrInit[st] == FALSE) 
      {
         nErr = EFAILED;
         goto Done;
      }

      if (nIndex >= gpWms->ucStrSMSCount[st])
      {
         nErr = EFAILED;
         goto Done;
      }

      if (gpWms->strSMSMsgList[st][nIndex] == WMS_TAG_NONE)
      {
         nErr = EBADPARM;
         goto Done;
      }
   }
   else
   {
      nErr = EBADPARM;
      goto Done;
   }

   hMsg = sys_malloc(sizeof(OEMReadMsg));

   if (hMsg) 
   {   
      CALLBACK_Cancel(pcb);
      pcb->pCancelData = hMsg;
      pcb->pfnCancel   = OEMWMS_ReleaseReadSMS;
      OEMWMS_ReadSMS( hMsg, pcb, pnRv, pMsgData, pMsgPayload, nIndex, st);
   }
   else
      nErr = ENOMEMORY;

Done:
   if( SUCCESS != nErr ) 
   {
      *pnRv = nErr;
      AEE_SVC_RESUME( pcb );
   }
}

/*===========================================================================

  Called to read SMS

===========================================================================*/
static void OEMWMS_ReadSMS( OEMReadMsg* hMsg, AEECallback *pcb, uint32 *pdwStatus, OEMMsgData *pMsgData, OEMMsgPayload *pMsgPayload, uint32 nIndex, int st )
{
   int nErr = SUCCESS;   
   wms_status_e_type wmsStatus;

   FARF(SMS, ("==>  OEMWMS_ReadSMS"));

   if(!gpWms) 
   {
      nErr = EFAILED;
      goto Done;
   }

   if(gpWms->pCurReadSMS != 0) 
   {
      nErr = EITEMBUSY;
      goto Done;
   }

   wmsStatus = wms_msg_read( gpWms->clientId, 
                              &OEMWSMS_CommandCallback,
                              (const void *)hMsg,
                              Xlate_2_NativeStorageType(st),
                              nIndex);
   
   if( wmsStatus != WMS_OK_S )
   {
      nErr = EFAILED;
   }
   else 
   {
      hMsg->pcb = pcb;
      hMsg->pdwStatus = pdwStatus;
      hMsg->pMsgData = pMsgData;
      hMsg->pMsgPayload = pMsgPayload;
      gpWms->pCurReadSMS = hMsg;
      nErr = SUCCESS;
   }

Done:
   if (nErr != SUCCESS)
   {
      *pdwStatus = nErr;
      AEE_SVC_RESUME(pcb);
      OEMWMS_DeleteReadSMS(hMsg);
   }
}

/*===========================================================================

  Called to release read SMS struct

===========================================================================*/
static void OEMWMS_ReleaseReadSMS( AEECallback *pcb )
{
   FARF(SMS, ("==>  OEMWMS_ReleaseReadSMS"));

  //Verify that it is me set as the cancel function.
   //Cross-task cancellations need this check.
   if(pcb->pfnCancel != OEMWMS_ReleaseReadSMS)
      return;
   
   OEMWMS_DeleteReadSMS( (OEMReadMsg*)pcb->pCancelData );

   pcb->pCancelData = 0;
   pcb->pfnCancel   = 0;
}

/*===========================================================================

  Deletes OEMReadMsg instance for Read SMS

===========================================================================*/
static void OEMWMS_DeleteReadSMS(OEMReadMsg * hMsg)
{
   if( gpWms && gpWms->pCurReadSMS == hMsg ) 
   {      
      gpWms->pCurReadSMS = 0;
   }

   if ( hMsg )
      sys_free( hMsg );
}

/*===========================================================================

   Listener Invoked on WMS_MSG_EVENT_READ

===========================================================================*/  
static void OEMWMS_ReadSMSListener
(
   wms_msg_event_info_s_type * info_ptr
)
{
   OEMReadMsg  *hMsg = (OEMReadMsg *)info_ptr->status_info.user_data;

   if (!gpWms || !gpWms->pCurReadSMS)
   {
      return;
   }

   if (hMsg != gpWms->pCurReadSMS)
   {
      *gpWms->pCurReadSMS->pdwStatus = EFAILED;
      goto Done;
   }

   MEMSET(&sce, 0, sizeof(sce));

   if (OEMWMS_CopyMessage(0,&info_ptr->status_info.message,&sce) == FALSE) 
   {
      *hMsg->pdwStatus = EFAILED;
   }
   else
   {
      *hMsg->pdwStatus = SUCCESS;

      if (hMsg->pMsgPayload)
      {
         hMsg->pMsgPayload->nEncoding = sce.nEncoding;
         hMsg->pMsgPayload->nBytes = sce.nText;
         hMsg->pMsgPayload->nPadding = 0;
         MEMCPY(hMsg->pMsgPayload->data, sce.pText, sce.nText);
      }

      if (hMsg->pMsgData)
      {
         hMsg->pMsgData->dwLang = sce.dwLang;
         hMsg->pMsgData->dwTimeStamp = sce.dwTimeStamp;
         hMsg->pMsgData->nNumMsgs = sce.nNumMsgs;
         hMsg->pMsgData->nPriority = sce.nPriority;
         hMsg->pMsgData->nPrivacy = sce.nPrivacy;
         STRCPY(hMsg->pMsgData->szCallback, sce.szCallback);
         STRCPY(hMsg->pMsgData->szMOFromMTTo, sce.szFrom);
         hMsg->pMsgData->ts = sce.ts;
         hMsg->pMsgData->bRequestDLAck = sce.bRequestDLAck;
         hMsg->pMsgData->bRequestUserAck = sce.bRequestUserAck;
         hMsg->pMsgData->bRequestReadAck = sce.bRequestReadAck;
         hMsg->pMsgData->bIsMOSMS = sce.bIsMOSMS;
         hMsg->pMsgData->dwTag = sce.dwTag;
         hMsg->pMsgData->bIsSCAddress = sce.bIsSCAddress;
         hMsg->pMsgData->bIsDLAck = sce.bIsDLAck;
         hMsg->pMsgData->bIsUserAck = sce.bIsUserAck;
         hMsg->pMsgData->bIsReadAck = sce.bIsReadAck;
      }
   }
   
Done:
      AEE_SVC_RESUME( gpWms->pCurReadSMS->pcb );
   OEMWMS_DeleteReadSMS(gpWms->pCurReadSMS);
}

/*===========================================================================

   Removes a message from the card

===========================================================================*/  
void OEMSMS_RemoveMsg( AEESMSStorageType st, AEESMSTag mt, uint32 nIndex, uint32 * pnRv, AEECallback *pcb )
{
   int nErr = SUCCESS; 
   OEMDeleteMsg *hMsg;

   FARF(SMS, ("OEMSMS_RemoveMsg"));

   if (st < AEESMS_STORAGE_LAST)
   {
      if (gpWms->bStrInit[st] == FALSE) 
      {
         nErr = EFAILED;
         goto Done;
      }

      if (nIndex >= gpWms->ucStrSMSCount[st] && nIndex != 0xffffffff)
      {
         nErr = EFAILED;
         goto Done;
      }
   }
   else
   {
      nErr = EBADPARM;
      goto Done;
   }

   hMsg = sys_malloc(sizeof(OEMDeleteMsg));

   if (hMsg) 
   {   
      CALLBACK_Cancel(pcb);
      pcb->pCancelData = hMsg;
      pcb->pfnCancel   = OEMWMS_ReleaseDeleteSMS;
      OEMWMS_DeleteSMS( hMsg, pcb, pnRv, nIndex, Xlate_2_NativeStorageType(st), Xlate_2_NativeTag(mt));
   }
   else
      nErr = ENOMEMORY;

Done:
   if( SUCCESS != nErr ) 
   {
      *pnRv = nErr;
      AEE_SVC_RESUME( pcb );
   }
}

/*===========================================================================

  Called to delete stored SMS

===========================================================================*/
static void OEMWMS_DeleteSMS( OEMDeleteMsg* hMsg, AEECallback *pcb, uint32 *pdwStatus, uint32 nIndex, wms_memory_store_e_type wmsMemoryStore, wms_message_tag_e_type wmsMessageTag)
{
   int nErr = SUCCESS;   
   wms_status_e_type wmsStatus;

   FARF(SMS, ("==>  OEMWMS_DeleteSMS"));

   if(!gpWms) 
   {
      nErr = EFAILED;
      goto Done;
   }

   if(gpWms->pCurDeleteSMS != 0) 
   {
      nErr = EITEMBUSY;
      goto Done;
   }

   if (nIndex != 0xffffffff)
   {
      wmsStatus = wms_msg_delete(gpWms->clientId, 
                                 &OEMWSMS_CommandCallback,
                                 (const void *)hMsg,
                                 wmsMemoryStore,
                                 nIndex);
   }
   else
   {
      wmsStatus = wms_msg_delete_all(gpWms->clientId, 
                                 &OEMWSMS_CommandCallback,
                                 (const void *)hMsg,
                                 wmsMemoryStore,
                                 wmsMessageTag);
   }
   
   if( wmsStatus != WMS_OK_S )
   {
      nErr = EFAILED;
   }
   else 
   {
      hMsg->pcb = pcb;
      hMsg->pdwStatus = pdwStatus;
      gpWms->pCurDeleteSMS = hMsg;
      nErr = SUCCESS;
   }

Done:
   if (nErr != SUCCESS)
   {
      *pdwStatus = nErr;
      AEE_SVC_RESUME(pcb);
      OEMWMS_DeleteDeleteSMS(hMsg);
   }
}


/*===========================================================================

  Called to release delete SMS struct

===========================================================================*/
static void OEMWMS_ReleaseDeleteSMS( AEECallback *pcb )
{
   FARF(SMS, ("==>  OEMWMS_ReleaseDeleteSMS"));

   //Verify that it is me set as the cancel function.
   //Cross-task cancellations need this check.
   if(pcb->pfnCancel != OEMWMS_ReleaseDeleteSMS)
      return;
   
   OEMWMS_DeleteDeleteSMS( (OEMDeleteMsg*)pcb->pCancelData );

   pcb->pCancelData = 0;
   pcb->pfnCancel   = 0;
}


/*===========================================================================

  Deletes OEMDeleteMsg instance for Delete SMS

===========================================================================*/
static void OEMWMS_DeleteDeleteSMS(OEMDeleteMsg * hMsg)
{
   if( gpWms && gpWms->pCurDeleteSMS == hMsg ) 
   {      
      gpWms->pCurDeleteSMS = 0;
   }

   if ( hMsg )
      sys_free( hMsg );
}

/*===========================================================================

   Listener Invoked on WMS_MSG_EVENT_DELETE and WMS_MSG_EVENT_DELETE_ALL

===========================================================================*/  
static void OEMWMS_DeleteSMSListener
(
   wms_msg_event_info_s_type * info_ptr
)
{
   OEMDeleteMsg *hMsg = (OEMDeleteMsg *)info_ptr->status_info.user_data;

   if (!gpWms || !gpWms->pCurDeleteSMS)
   {
      return;
   }

   if( hMsg == gpWms->pCurDeleteSMS )
      *gpWms->pCurDeleteSMS->pdwStatus = SUCCESS;
   else
      *gpWms->pCurDeleteSMS->pdwStatus = EFAILED;
   
      AEE_SVC_RESUME( gpWms->pCurDeleteSMS->pcb );
   OEMWMS_DeleteDeleteSMS(gpWms->pCurDeleteSMS);
   }

/*=============================================================================

  Returns list of IDs matching message type

=============================================================================*/
int OEMSMS_GetEnumMsgIDs(AEESMSStorageType st, AEESMSTag mt, uint32 * pdwIndex, uint32 * pdwSize )
{
   int nErr = SUCCESS, i = 0, nCount = 0;
   FARF(SMS, ("OEMSMS_GetEnumMsgIDs"));

   if (!pdwSize || (st >= AEESMS_STORAGE_LAST))
   {
      return EBADPARM;
   }
   
   if (AEESMS_TAG_NONE == mt)
   {
      // Tag none means don't care here so count all messages
      for (i = 0; i < gpWms->ucStrSMSCount[st]; i++)
      {
         nCount++;

         if (*pdwSize >= nCount*sizeof(uint32))
   {
            *pdwIndex++ = i;
         }
   }
}
   else
   {
      // Count messages of specific tag type
      for (i = 0; i < gpWms->ucStrSMSCount[st]; i++)
      {
         if (gpWms->strSMSMsgList[st][i] == Xlate_2_NativeTag(mt))
{
            nCount++;

            if (*pdwSize >= nCount*sizeof(uint32))
   {
               *pdwIndex++ = i;
            }
         }
      }
   }

   *pdwSize = nCount*sizeof(uint32);
   
   return nErr;
}

/*===========================================================================

   Sets message ack status for specified message type

===========================================================================*/
void OEMSMS_SetMsgAckStatus( uint32 cs, uint32 mt)
{
   if (!gpWms)
      return;

   switch (mt)
   {
      case AEESMS_TYPE_TEXT:
         gpWms->dwTextStatus = cs;
         break;

      case AEESMS_TYPE_VOICE_MAIL_NOTIFICATION:
         gpWms->dwVMStatus = cs;
         break;

      case AEESMS_TYPE_PAGE:
         gpWms->dwPageStatus = cs;
         break;

      case AEESMS_TYPE_WAP:
         gpWms->dwWapStatus = cs;
         break;

      case AEESMS_TYPE_EMS:
         gpWms->dwEMSStatus = cs;
         break;
   }
}

/*===========================================================================

   Gets message ack status for specified teleservice ID

===========================================================================*/
static wms_status_e_type OEMSMS_GetMsgAckStatus(uint32 ts)
{
   wms_status_e_type eStatus = WMS_TL_INVALID_TELESERVICE_ID_S;

   if (!gpWms)
      return(eStatus);

   switch (ts)
   {
      case SMS_TELESERVICE_CMT_95:
      case SMS_TELESERVICE_IS91_SHORT_MESSAGE:
         eStatus = (gpWms->dwTextStatus == AEESMS_CS_OK ? WMS_OK_S : WMS_TL_DESTINATION_RESOURCE_SHORTAGE_S);
         break;

      case SMS_TELESERVICE_MWI:
      case SMS_TELESERVICE_VMN_95:
      case SMS_TELESERVICE_IS91_VOICE_MAIL:
         eStatus = (gpWms->dwVMStatus == AEESMS_CS_OK ? WMS_OK_S : WMS_TL_DESTINATION_RESOURCE_SHORTAGE_S);
         break;

      case SMS_TELESERVICE_CPT_95:
      case SMS_TELESERVICE_IS91_PAGE:
         eStatus = (gpWms->dwPageStatus == AEESMS_CS_OK ? WMS_OK_S : WMS_TL_DESTINATION_RESOURCE_SHORTAGE_S);
         break;

      case SMS_TELESERVICE_WAP:
         eStatus = (gpWms->dwWapStatus == AEESMS_CS_OK ? WMS_OK_S : WMS_TL_DESTINATION_RESOURCE_SHORTAGE_S);
         break;

      case SMS_TELESERVICE_WEMT:
         eStatus = (gpWms->dwEMSStatus == AEESMS_CS_OK ? WMS_OK_S : WMS_TL_DESTINATION_RESOURCE_SHORTAGE_S);
         break;

      default:
         eStatus = WMS_OK_S;
         break;
   }
   return(eStatus);
}

/*===========================================================================

   Gets UDH data

===========================================================================*/
void OEMSMS_GetUDHData(SMSCacheEntry * pce, int * pnBytes, byte * pBuffer)
{   
   wms_client_ts_data_s_type * pctsdata = NULL;

   FARF(SMS, ("==> OEMSMS_GetUDHData"));   

   if (!pnBytes)
      return;

   pctsdata = (wms_client_ts_data_s_type *)pce->data;

   if (pctsdata->format == WMS_FORMAT_CDMA)
   {
      wms_client_bd_s_type * pcd = &pctsdata->u.cdma;

      if (pcd->message_id.udh_present &&
          (pcd->mask & WMS_MASK_BD_USER_DATA) &&
          pcd->user_data.num_headers)
      {
         int nUDHSize = OEMWMS_GetUDHSize(pcd->user_data.num_headers, pcd->user_data.headers);
         if (pBuffer && (*pnBytes >= nUDHSize))
         {
            OEMWMS_GetUDHData(pcd->user_data.num_headers, pcd->user_data.headers, pBuffer);
         }
         *pnBytes = nUDHSize;
      }
      else
      {
         if (*pnBytes)
         {
            MEMSET(pBuffer, 0, *pnBytes);
         }
         *pnBytes = 0;
      }
   }

   if (pctsdata->format == WMS_FORMAT_GW_PP)
   {
      wms_gw_deliver_s_type * pcd = &pctsdata->u.gw_pp.u.deliver;

      if (pcd->user_data_header_present &&
          pcd->user_data.num_headers)
      {
         int nUDHSize = OEMWMS_GetUDHSize(pcd->user_data.num_headers, pcd->user_data.headers);
         if (pBuffer && (*pnBytes >= nUDHSize))
         {
            OEMWMS_GetUDHData(pcd->user_data.num_headers, pcd->user_data.headers, pBuffer);
         }
         *pnBytes = nUDHSize;
      }
      else
      {
         if (*pnBytes)
         {
            MEMSET(pBuffer, 0, *pnBytes);
         }
         *pnBytes = 0;
      }
   }
}

/*===========================================================================

   Calculates size required for UDH data

===========================================================================*/
static int OEMWMS_GetUDHSize(int nNumHeaders, wms_udh_s_type udh[])
{
   int i = 0, nSize = 0;

   for (i = 0; i < nNumHeaders; i++)
   {
      switch (udh[i].header_id)
      {
         case WMS_UDH_CONCAT_8:
         case WMS_UDH_CONCAT_16:
         case WMS_UDH_PORT_8:
         case WMS_UDH_PORT_16:
            nSize += 7;          // length + data; (2 + n)
            break;

         case WMS_UDH_SPECIAL_SM:
         case WMS_UDH_TEXT_FORMATING:
            nSize += 6;          // length + data; (2 + n)
            break;

         case WMS_UDH_PRE_DEF_SOUND:
         case WMS_UDH_PRE_DEF_ANIM:
            nSize += 5;          // length + data; (2 + n)
            break;
         
         case WMS_UDH_LARGE_ANIM:
         case WMS_UDH_LARGE_PICTURE:
            nSize += 133;        // length + data; (2 + n)
            break;
         
         case WMS_UDH_SMALL_ANIM:
         case WMS_UDH_SMALL_PICTURE:
            nSize += 37;         // length + data; (2 + n)
            break;

         case WMS_UDH_RFC822:
            nSize += 4;          // length + data; (2 + n)
            break;

         case WMS_UDH_VAR_PICTURE:
            nSize += (6 + ((udh[i].u.var_picture.width*udh[i].u.var_picture.height) + 7)/8);
            break;

         case WMS_UDH_USER_DEF_SOUND:
            nSize += (2 + 3 + udh[i].u.user_def_sound.data_length);
            break;

         default:
            nSize += (2 + 3 + udh[i].u.other.header_length);
            break;
      }
   }
   return nSize;
}

/*===========================================================================

   Gets UDH data in specified buffer

===========================================================================*/
static void OEMWMS_GetUDHData(int nNumHeaders, wms_udh_s_type udh[], byte * pBuffer)
{
   int i = 0;

   for (i = 0; i < nNumHeaders; i++)
   {
      switch (udh[i].header_id)
      {
         case WMS_UDH_CONCAT_8:
            MSGOPT_SETUDHCONCAT8BUFFER(pBuffer,udh[i].u.concat_8.seq_num, udh[i].u.concat_8.total_sm, udh[i].u.concat_8.msg_ref);
            pBuffer += 7;          // length + data; (2 + n)
            break;

         case WMS_UDH_CONCAT_16:
            MSGOPT_SETUDHCONCAT16BUFFER(pBuffer,udh[i].u.concat_16.seq_num, udh[i].u.concat_16.total_sm, udh[i].u.concat_16.msg_ref);
            pBuffer += 7;          // length + data; (2 + n)
            break;

         case WMS_UDH_PORT_8:
            MSGOPT_SETUDHPORT8BUFFER(pBuffer,udh[i].u.wap_8.dest_port, udh[i].u.wap_8.orig_port);
            pBuffer += 7;          // length + data; (2 + n)
            break;

         case WMS_UDH_PORT_16:
            MSGOPT_SETUDHPORT16BUFFER(pBuffer, udh[i].u.wap_16.dest_port, udh[i].u.wap_16.orig_port);
            pBuffer += 7;          // length + data; (2 + n)
            break;

         case WMS_UDH_SPECIAL_SM:
            MSGOPT_SETUDHSPECIALSMBUFFER(pBuffer, Xlate_MsgWaitingType(udh[i].u.special_sm.msg_waiting), Xlate_MsgWaitingKind(udh[i].u.special_sm.msg_waiting_kind), udh[i].u.special_sm.message_count);
            pBuffer += 6;          // length + data; (2 + n)
            break;

         case WMS_UDH_TEXT_FORMATING:
            MSGOPT_SETUDHTEXTFORMATBUFFER(pBuffer, 
                                          udh[i].u.text_formating.start_position, 
                                          udh[i].u.text_formating.text_formatting_length, 
                                          (byte)(udh[i].u.text_formating.alignment_type|
                                                (udh[i].u.text_formating.font_size << 2)|
                                                (udh[i].u.text_formating.style_bold << 4)|
                                                (udh[i].u.text_formating.style_italic << 5)|
                                                (udh[i].u.text_formating.style_underlined << 6)|
                                                (udh[i].u.text_formating.style_strikethrough << 7)));
            pBuffer += 6;          // length + data; (2 + n)
            break;

         case WMS_UDH_PRE_DEF_SOUND:
            MSGOPT_SETUDHPREDEFSOUNDBUFFER(pBuffer, udh[i].u.pre_def_sound.position, udh[i].u.pre_def_sound.snd_number);
            pBuffer += 5;          // length + data; (2 + n)
            break;

         case WMS_UDH_PRE_DEF_ANIM:
            MSGOPT_SETUDHPREDEFANIMBUFFER(pBuffer, udh[i].u.pre_def_anim.position, udh[i].u.pre_def_anim.animation_number);
            pBuffer += 5;          // length + data; (2 + n)
            break;
         
         case WMS_UDH_LARGE_ANIM:
            MSGOPT_SETUDHLARGEANIMBUFFER(pBuffer, udh[i].u.large_anim.position, udh[i].u.large_anim.data);
            pBuffer += 133;        // length + data; (2 + n)
            break;

         case WMS_UDH_LARGE_PICTURE:
            MSGOPT_SETUDHLARGEPICBUFFER(pBuffer, udh[i].u.large_picture.position, udh[i].u.large_picture.data);
            pBuffer += 133;        // length + data; (2 + n)
            break;
         
         case WMS_UDH_SMALL_ANIM:
            MSGOPT_SETUDHSMALLANIMBUFFER(pBuffer, udh[i].u.small_anim.position, udh[i].u.small_anim.data);
            pBuffer += 37;         // length + data; (2 + n)
            break;

         case WMS_UDH_SMALL_PICTURE:
            MSGOPT_SETUDHSMALLPICBUFFER(pBuffer, udh[i].u.small_picture.position, udh[i].u.small_picture.data);
            pBuffer += 37;         // length + data; (2 + n)
            break;

         case WMS_UDH_RFC822:
            MSGOPT_SETRFC822BUFFER(pBuffer, udh[i].u.rfc822.header_length);
            pBuffer += 4;          // length + data; (2 + n)
            break;

         case WMS_UDH_VAR_PICTURE:
            MSGOPT_SETUDHVARPICBUFFER(pBuffer, udh[i].u.var_picture.position, udh[i].u.var_picture.width, udh[i].u.var_picture.height, udh[i].u.var_picture.data);
            pBuffer += (2 + 4 + ((udh[i].u.var_picture.width*udh[i].u.var_picture.height) + 7)/8);
            break;

         case WMS_UDH_USER_DEF_SOUND:
            MSGOPT_SETUDHUSERDEFSOUNDBUFFER(pBuffer, udh[i].u.user_def_sound.position, udh[i].u.user_def_sound.data_length, udh[i].u.user_def_sound.user_def_sound);
            pBuffer += (2 + 3 + udh[i].u.user_def_sound.data_length);
            break;

         default:
            MSGOPT_SETUDHOTHERBUFFER(pBuffer, udh[i].u.other.header_id, udh[i].u.other.header_length, udh[i].u.other.data);
            pBuffer += (2 + 3 + udh[i].u.other.header_length);
            break;
      }
   }
}

/*===========================================================================

   Translation of Message Waiting Types DMSS to AEE

===========================================================================*/
static AEESMSMsgWaitingType Xlate_MsgWaitingType(wms_gw_msg_waiting_e_type dt)
{
   MsgWaitTypeMap * pt;
   int i,nEntries = sizeof(gsMsgWaitTypeMap)/sizeof(MsgWaitTypeMap);

   for(i = 0, pt = (MsgWaitTypeMap *)gsMsgWaitTypeMap; i < nEntries; pt++,i++)
   {
      if(pt->DMSS_MsgWaitType == dt)
         return(pt->AEE_MsgWaitType);
   }

   return(AEESMS_MSGWAITINGTYPE_NONE); // Default   
}

/*===========================================================================

   Translation of Message Waiting Kinds DMSS to AEE

===========================================================================*/
static AEESMSMsgWaitingKind Xlate_MsgWaitingKind(wms_gw_msg_waiting_kind_e_type dk)
{
   MsgWaitKindMap * pk;
   int i,nEntries = sizeof(gsMsgWaitKindMap)/sizeof(MsgWaitKindMap);

   for(i = 0, pk = (MsgWaitKindMap *)gsMsgWaitKindMap; i < nEntries; pk++,i++)
   {
      if(pk->DMSS_MsgWaitKind == dk)
         return(pk->AEE_MsgWaitKind);
   }

   return(AEESMS_MSGWAITINGKIND_OTHER); // Default   
}

/*===========================================================================

   Processed UDH data

===========================================================================*/
static void OEMWMS_ProcessUDHData(wms_client_ts_data_s_type * pctsdata, byte * pBuffer, int nBytes)
{
   FARF(SMS, ("==> OEMSMS_SetUDHData"));   

   if (!pctsdata || !pBuffer || !nBytes)
      return;

   if (pctsdata->format == WMS_FORMAT_CDMA)
   {
      wms_client_bd_s_type * pcd = &pctsdata->u.cdma;

      if ((pcd->user_data.num_headers = OEMWMS_SetUDHData(sizeof(pcd->user_data.headers)/sizeof(wms_udh_s_type), pcd->user_data.headers, pBuffer, nBytes)) != 0)
      {      
         pcd->message_id.udh_present = TRUE;
         pcd->mask |= WMS_MASK_BD_USER_DATA;
      }
   }

   if (pctsdata->format == WMS_FORMAT_GW_PP)
   {
      wms_gw_deliver_s_type * pcd = &pctsdata->u.gw_pp.u.deliver;
      
      if ((pcd->user_data.num_headers = OEMWMS_SetUDHData(sizeof(pcd->user_data.headers)/sizeof(wms_udh_s_type), pcd->user_data.headers, pBuffer, nBytes)) != 0)
      {      
         pcd->user_data_header_present = TRUE;
      }
   }
}

/*===========================================================================

   Sets UDH data from specified buffer and returns number of headers set

===========================================================================*/
static int OEMWMS_SetUDHData(int nMaxHeaders, wms_udh_s_type udh[], byte * pBytes, int nBytes)
{
   int nProcessed = 0, i = 0;

   while (nProcessed < nBytes)
   {
      if (i >= nMaxHeaders)
         break;

      udh[i].header_id = Xlate_2_NativeUDHId(*(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed))));

      switch (udh[i].header_id)
      {
         case WMS_UDH_CONCAT_8:
            udh[i].u.concat_8.seq_num = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            udh[i].u.concat_8.total_sm = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2);
            udh[i].u.concat_8.msg_ref = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3) + 
                                       (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 4) << 8);
            break;

         case WMS_UDH_CONCAT_16:
            udh[i].u.concat_16.seq_num = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            udh[i].u.concat_16.total_sm = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2);
            udh[i].u.concat_16.msg_ref = (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3) + 
                                         (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 4) << 8));
            break;

         case WMS_UDH_PORT_8:
            udh[i].u.wap_8.dest_port = (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1) + 
                                       (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2) << 8));
            udh[i].u.wap_8.orig_port = (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3) + 
                                       (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 4) << 8));
            break;

         case WMS_UDH_PORT_16:
            udh[i].u.wap_16.dest_port = (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1) + 
                                       (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2) << 8));
            udh[i].u.wap_16.orig_port = (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3) + 
                                       (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 4) << 8));         // length + data; (2 + n)
            break;

         case WMS_UDH_SPECIAL_SM:
            udh[i].u.special_sm.msg_waiting = Xlate_2_NativeMsgWaitingType(*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1));
            udh[i].u.special_sm.msg_waiting_kind = Xlate_2_NativeMsgWaitingKind(*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2));
            udh[i].u.special_sm.message_count = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3);
            break;

         case WMS_UDH_TEXT_FORMATING:
            udh[i].u.text_formating.start_position = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            udh[i].u.text_formating.text_formatting_length = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2);
            udh[i].u.text_formating.alignment_type = (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3)) & 3;
            udh[i].u.text_formating.font_size = (((*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3)) & 12) >> 2);
            udh[i].u.text_formating.style_bold = (((*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3)) & 16) >> 4);
            udh[i].u.text_formating.style_italic = (((*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3)) & 32) >> 5);
            udh[i].u.text_formating.style_underlined = (((*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3)) & 64) >> 6);
            udh[i].u.text_formating.style_strikethrough = (((*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3)) & 128) >> 7);
            break;

         case WMS_UDH_PRE_DEF_SOUND:
            udh[i].u.pre_def_sound.position = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            udh[i].u.pre_def_sound.snd_number = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2);
            break;

         case WMS_UDH_PRE_DEF_ANIM:
            udh[i].u.pre_def_anim.position = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            udh[i].u.pre_def_anim.animation_number = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2);
            break;
         
         case WMS_UDH_LARGE_ANIM:
            udh[i].u.large_anim.position = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            MEMCPY(udh[i].u.large_anim.data, (byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3), 128);
            break;

         case WMS_UDH_LARGE_PICTURE:
            udh[i].u.large_picture.position = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            MEMCPY(udh[i].u.large_picture.data, (byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3), 128);
            break;
         
         case WMS_UDH_SMALL_ANIM:
            udh[i].u.small_anim.position = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            MEMCPY(udh[i].u.small_anim.data, (byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3), 32);
            break;

         case WMS_UDH_SMALL_PICTURE:
            udh[i].u.small_picture.position = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            MEMCPY(udh[i].u.small_picture.data, (byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3), 32);
            break;

         case WMS_UDH_RFC822:
            udh[i].u.rfc822.header_length = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            break;

         case WMS_UDH_VAR_PICTURE:
            udh[i].u.var_picture.position = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            udh[i].u.var_picture.width = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2);
            udh[i].u.var_picture.height= *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3);
            MEMCPY(udh[i].u.var_picture.data, (byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 4), ((udh[i].u.var_picture.width*udh[i].u.var_picture.height) + 7)/8);
            break;

         case WMS_UDH_USER_DEF_SOUND:
            udh[i].u.user_def_sound.position = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1);
            udh[i].u.user_def_sound.data_length = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2);
            MEMCPY(udh[i].u.user_def_sound.user_def_sound, (byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3), udh[i].u.user_def_sound.data_length);
            break;

         default:
            udh[i].u.other.header_id = *(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)));
            udh[i].u.other.header_length = (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 1) + 
                                           (*(byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 2) << 8));
            MEMCPY(udh[i].u.other.data, (byte*)(MSGOPT_GETUDHBUFFERDATA((byte*)(pBytes + nProcessed)) + 3), udh[i].u.other.header_length);
            break;
      }
      nProcessed += (2 + MSGOPT_GETUDHBUFFERLENGTH((byte*)(pBytes + nProcessed)));
      i++;
   }
   return i;
}

/*===========================================================================

  A Callback function for WMS functions called for ISMSStorage

===========================================================================*/
static void OEMWSMS_CommandCallback 
(
   wms_cmd_id_e_type cmd, 
   void * user_data, 
   wms_cmd_err_e_type cmd_err 
)
{
   int nErr = SUCCESS;

   FARF(SMS, ("==>  OEMWSMS_CommandCallback"));

   nErr = Xlate_wms_cmd_err_2_AEEErrorCode(cmd_err);

   if (gpWms && (nErr != SUCCESS))
   {
      if (gpWms->pCurMOSMS)
      {
         AEESMS_SETERROR(*gpWms->pCurMOSMS->pdwStatus, AEESMS_ERRORTYPE_TEMP, AEESMS_ERROR_GENERAL_PROBLEM);
         AEE_SVC_RESUME(gpWms->pCurMOSMS->pcb);
         OEMSMS_DeleteMessage(gpWms->pCurMOSMS);
      }

      if (gpWms->pCurDeleteSMS)
      {
         *gpWms->pCurDeleteSMS->pdwStatus = nErr;
         AEE_SVC_RESUME(gpWms->pCurDeleteSMS->pcb);
         OEMWMS_DeleteDeleteSMS(gpWms->pCurDeleteSMS);
      }
      
      if (gpWms->pCurReadSMS)
      {
         *gpWms->pCurReadSMS->pdwStatus = nErr;
         AEE_SVC_RESUME(gpWms->pCurReadSMS->pcb);
         OEMWMS_DeleteReadSMS(gpWms->pCurReadSMS);
      }

      if (gpWms->pCurStoreSMS)
      {
         *gpWms->pCurStoreSMS->pdwStatus = nErr;
         AEE_SVC_RESUME(gpWms->pCurStoreSMS->pcb);
         OEMWMS_DeleteStoreSMS(gpWms->pCurStoreSMS);
      }
   }
}

/*===========================================================================

  Translates AEE UDH ID to DMSS UDH ID

===========================================================================*/
static wms_udh_id_e_type Xlate_2_NativeUDHId(AEESMSUDHId id)
{
   int i;

   for(i = 0; i < sizeof(gsUDHIDMap)/sizeof(UDHIDMap); i++)
   {
      if (gsUDHIDMap[i].AEE_UDHID == id)
      {
         return gsUDHIDMap[i].DMSS_UDHID;
      }
   }

   // Assume DMSS uses standard UDH IDs so that we dont need a mapping table and 
   // we can return the same UDH ID
   return(id); 
}

/*===========================================================================

  Translates DMSS message wait type to AEE message wait type

===========================================================================*/
static wms_gw_msg_waiting_e_type Xlate_2_NativeMsgWaitingType(AEESMSMsgWaitingType at)
{
   int i;

   for (i = 0; i < sizeof(gsMsgWaitTypeMap)/sizeof(MsgWaitTypeMap); i++)
   {
      if (gsMsgWaitTypeMap[i].AEE_MsgWaitType == at)
      {
         return gsMsgWaitTypeMap[i].DMSS_MsgWaitType;
      }
   }
   return WMS_GW_MSG_WAITING_NONE;
}

/*===========================================================================

  Translates DMSS message wait kind to AEE message wait kind

===========================================================================*/
static wms_gw_msg_waiting_kind_e_type Xlate_2_NativeMsgWaitingKind(AEESMSMsgWaitingKind ak)
{
   int i;

   for (i = 0; i < sizeof(gsMsgWaitKindMap)/sizeof(MsgWaitKindMap); i++)
   {
      if (gsMsgWaitKindMap[i].AEE_MsgWaitKind == ak)
      {
         return gsMsgWaitKindMap[i].DMSS_MsgWaitKind;
      }
   }
   return WMS_GW_MSG_WAITING_OTHER;
}

/*===========================================================================
Function: Xlate_wms_status_2_AEEErrorCode
Description:
   Translates the WMS Status Codes to AEE Error Codes
Return Value:
   AEE Error Code
===========================================================================*/
static int Xlate_wms_status_2_AEEErrorCode(wms_status_e_type st)
{
   int nErr = EFAILED;

   FARF(SMS, ("==>  Xlate_wms_status_2_AEEErrorCode"));

   switch(st)
   {
      case WMS_OK_S:
         nErr = SUCCESS;
         break;

      case WMS_UNSUPPORTED_S:
         nErr = EUNSUPPORTED;
         break;

      case WMS_INVALID_PARM_VALUE_S:
         nErr = EBADPARM;
         break;

      // Add more codes here to be more specific

      default:
         nErr = EFAILED;
         break;
   }
   return (nErr);
}

/*===========================================================================
Function: Xlate_wms_cmd_err_2_AEEErrorCode
Description:
   Translates the WMS Command Error Codes to AEE Error Codes
Return Value:
   AEE Error Code
===========================================================================*/
static int Xlate_wms_cmd_err_2_AEEErrorCode(wms_cmd_err_e_type cmd_err)
{
   int nErr = EFAILED;

   FARF(SMS, ("==>  Xlate_wms_cmd_err_2_AEEErrorCode"));

   switch(cmd_err)
   {
      case WMS_CMD_ERR_NONE:
         nErr = SUCCESS;
         break;

      // Add more codes here to be more specific

      default:
         nErr = EFAILED;
         break;
   }
   return (nErr);
}

#ifdef FEATURE_BREW_BROADCAST_SMS
/*===========================================================================
Function: OEMSMSBCConfig_GetBCConfig
Description:
   Returns carrier's broadcast configuration
Return Value:
   None
===========================================================================*/
void OEMSMSBCConfig_GetBCConfig(AEESMSMode mode, AEECallback *pcb, AEESMSBCConfig * pConfig, uint32 * pnErr)
{
   int nErr = EUNSUPPORTED;
   wms_status_e_type st = WMS_UNSUPPORTED_S;

   FARF(SMS, ("==>  OEMSMSBCConfig_GetBCConfig"));

   if (gpWms->sBcCfg.bBroadcastInUse != TRUE)
   {
#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
      if (mode == AEESMS_MODE_CDMA)
      {
#ifdef FEATURE_CDSMS_BROADCAST 
         st = wms_bc_mm_get_config((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, Xlate_AEESMSMode_2_wms_message_mode(mode));
#else // FEATURE_CDSMS_BROADCAST
         st = wms_bc_get_config((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL);
#endif // FEATURE_CDSMS_BROADCAST
      }
      else if (mode == AEESMS_MODE_GW)
      {
         st = wms_bc_mm_get_config((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, Xlate_AEESMSMode_2_wms_message_mode(mode));
      }
      else
      {
         FARF(SMS, ("Request Rejected - Unsupported SMS Mode"));
         st = WMS_UNSUPPORTED_S;
      }
#else // FEATURE_BROADCAST_SMS_MULTIMODE
      st = wms_bc_get_config((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL);
#endif // FEATURE_BROADCAST_SMS_MULTIMODE

      if (st == WMS_OK_S)
      {
         // Fill up the Current BC Configuration
         gpWms->sBcCfg.bBroadcastInUse = TRUE;                
         gpWms->sBcCfg.eCurRequest     = OEMSMSBCConfig_GetBCConfigRequest;
         gpWms->sBcCfg.nNumCommands    = 1;
         gpWms->sBcCfg.dwMode         = mode;
         gpWms->sBcCfg.pcb            = pcb;
         gpWms->sBcCfg.pConfig        = pConfig;
         gpWms->sBcCfg.pnErr          = pnErr; 

         // Return Success to client
         nErr = SUCCESS;
      }
      else
      {
         // Return Error Code to Client
         nErr = Xlate_wms_status_2_AEEErrorCode(st);
      }
   }
   else
   {
      FARF(SMS, ("Request Rejected - Broadcast In Use"));
      nErr = EITEMBUSY;
   }

   if (nErr != SUCCESS)
   {
      // Fill up the Data
      *pnErr = nErr;

      // Call the Kernel Callback
      AEE_SVC_RESUME(pcb);
   }
}

/*===========================================================================
Function: OEMSMSBCConfig_GetBCPref
Description:
   Returns user's broadcast preference
Return Value:
   None
===========================================================================*/
void OEMSMSBCConfig_GetBCPref(AEESMSMode mode, AEECallback *pcb, AEESMSBCPref * pPref, uint32 * pnErr)
{
   int nErr = EUNSUPPORTED;
   wms_status_e_type st = WMS_UNSUPPORTED_S;

   FARF(SMS, ("==>  OEMSMSBCConfig_GetBCPref"));

   if (gpWms->sBcCfg.bBroadcastInUse != TRUE)
   {
#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
      if (mode == AEESMS_MODE_CDMA)
      {
#ifdef FEATURE_CDSMS_BROADCAST 
         st = wms_bc_mm_get_pref((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode);
#else // FEATURE_CDSMS_BROADCAST 
         st = wms_bc_get_pref((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL);
#endif // FEATURE_CDSMS_BROADCAST
      }
      else if (mode == AEESMS_MODE_GW)
      {
         st = wms_bc_mm_get_pref((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode);
      }
      else
      {
         FARF(SMS, ("Request Rejected - Unsupported SMS Mode"));
         st = WMS_UNSUPPORTED_S;
      }      
#else // FEATURE_BROADCAST_SMS_MULTIMODE      
      st = wms_bc_get_pref((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL);
#endif // FEATURE_BROADCAST_SMS_MULTIMODE

      if (st == WMS_OK_S)
      {
         // Fill up the Current BC Configuration
         gpWms->sBcCfg.bBroadcastInUse = TRUE;                
         gpWms->sBcCfg.eCurRequest     = OEMSMSBCConfig_GetBCPrefRequest;
         gpWms->sBcCfg.nNumCommands    = 1;
         gpWms->sBcCfg.dwMode         = mode;
         gpWms->sBcCfg.pcb            = pcb;
         gpWms->sBcCfg.pPref          = pPref;
         gpWms->sBcCfg.pnErr          = pnErr;  
         
         // Return Success to client
         nErr = SUCCESS;
      }
      else
      {
         // Return Error Code to Client
         nErr = Xlate_wms_status_2_AEEErrorCode(st);
      }
   }
   else
   {
      FARF(SMS, ("Request Rejected - Broadcast In Use"));
      nErr = EITEMBUSY;
   }
   
   if (nErr != SUCCESS)
   {
      // Fill up the Data
      *pnErr = nErr;

      // Call the Kernel Callback
      AEE_SVC_RESUME(pcb);
   }
}

/*===========================================================================
Function: OEMSMSBCConfig_SetBCPref
Description:
   Sets user's broadcast preference
Return Value:
   None
===========================================================================*/
void OEMSMSBCConfig_SetBCPref(AEESMSMode mode, AEESMSBCPref nPref, AEECallback *pcb, uint32 * pnErr)
{
   int nErr = EUNSUPPORTED;
   wms_status_e_type st = WMS_UNSUPPORTED_S;
     
   FARF(SMS, ("==>  OEMSMSBCConfig_SetBCPref"));

   if (gpWms->sBcCfg.bBroadcastInUse != TRUE)
   {
#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
      if (mode == AEESMS_MODE_CDMA)
      {
#ifdef FEATURE_CDSMS_BROADCAST 
         st = wms_bc_mm_set_pref((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode, nPref);
#else // FEATURE_CDSMS_BROADCAST
         st = wms_bc_set_pref((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, nPref);
#endif // FEATURE_CDSMS_BROADCAST 
      }
      else if (mode == AEESMS_MODE_GW)
      {
         st = wms_bc_mm_set_pref((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode, nPref);
      }
      else
      {
         FARF(SMS, ("Request Rejected - Unsupported SMS Mode"));
         st = WMS_UNSUPPORTED_S;
      }
#else // FEATURE_BROADCAST_SMS_MULTIMODE
      st = wms_bc_set_pref((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, nPref);
#endif // FEATURE_BROADCAST_SMS_MULTIMODE

      if (st == WMS_OK_S)
      {
         // Fill up the Current BC Configuration
         gpWms->sBcCfg.bBroadcastInUse = TRUE;                
         gpWms->sBcCfg.eCurRequest     = OEMSMSBCConfig_SetBCPrefRequest;
         gpWms->sBcCfg.nNumCommands    = 1;
         gpWms->sBcCfg.dwMode         = mode;
         gpWms->sBcCfg.pcb            = pcb;
         gpWms->sBcCfg.pnErr          = pnErr;  

         // Return Success to client
         nErr = SUCCESS;
      }
      else
      {
         // Return Error Code to Client
         nErr = Xlate_wms_status_2_AEEErrorCode(st);
      }
   }
   else
   {
      FARF(SMS, ("Request Rejected - Broadcast In Use"));
      nErr = EITEMBUSY;
   }

   if (nErr != SUCCESS)
   {
      // Fill up the Data
      *pnErr = nErr;

      // Call the Kernel Callback
      AEE_SVC_RESUME(pcb);
   }
}

/*===========================================================================
Function: OEMSMSBCConfig_GetNumberOfServiceIDs
Description:
   Returns service IDs currently configured in the table.
Return Value:
   None
===========================================================================*/
void OEMSMSBCConfig_GetNumberOfServiceIDs(AEESMSMode mode, AEECallback *pcb, uint32 * pnCount, uint32 * pnErr)
{
   int nErr = EUNSUPPORTED;
   wms_status_e_type st = WMS_UNSUPPORTED_S;

   FARF(SMS, ("==>  OEMSMSBCConfig_GetNumberOfServiceIDs"));

   if (gpWms->sBcCfg.bBroadcastInUse != TRUE)
   {
#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
      if (mode == AEESMS_MODE_CDMA)
      {
#ifdef FEATURE_CDSMS_BROADCAST 
         st = wms_bc_mm_get_all_service_ids((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode);
#else // FEATURE_CDSMS_BROADCAST
         st = wms_bc_get_all_service_ids((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL);
#endif // FEATURE_CDSMS_BROADCAST
      }
      else if (mode == AEESMS_MODE_GW)
      {
         st = wms_bc_mm_get_all_service_ids((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode);
      }
      else
      {
         FARF(SMS, ("Request Rejected - Unsupported SMS Mode"));
         st = WMS_UNSUPPORTED_S;
      }
#else // FEATURE_BROADCAST_SMS_MULTIMODE
      st = wms_bc_get_all_service_ids((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL);
#endif // FEATURE_BROADCAST_SMS_MULTIMODE
           
      if (st == WMS_OK_S)
      {
         // Fill up the Current BC Configuration
         gpWms->sBcCfg.bBroadcastInUse = TRUE;                
         gpWms->sBcCfg.eCurRequest     = OEMSMSBCConfig_GetNumberOfServiceIDsRequest;
         gpWms->sBcCfg.nNumCommands    = 1;
         gpWms->sBcCfg.dwMode         = mode;
         gpWms->sBcCfg.pcb            = pcb;
         gpWms->sBcCfg.pnCount        = pnCount;
         gpWms->sBcCfg.pnErr          = pnErr;  
         
         // Return Success to client
         nErr = SUCCESS;
      }
      else
      {
         // Return Error Code to Client
         nErr = Xlate_wms_status_2_AEEErrorCode(st);
      }
   }
   else
   {
      FARF(SMS, ("Request Rejected - Broadcast In Use"));
      nErr = EITEMBUSY;
   }

   if (nErr != SUCCESS)
   {
      // Fill up the Data
      *pnErr = nErr;

      // Call the Kernel Callback
      AEE_SVC_RESUME(pcb);
   }
}

/*===========================================================================
Function: OEMSMSBCConfig_GetServiceOpts
Description:
   Returns service options corresponding to the specified ID.
Return Value:
   None
===========================================================================*/
void OEMSMSBCConfig_GetServiceOpts(AEESMSMode mode, AEESMSBCSrvID *pSrvID, AEECallback *pcb, OEMSMSBCSrvInfo * pSrvInfo, uint32 * pnErr)
{
   int nErr = EUNSUPPORTED;
   wms_status_e_type st = WMS_UNSUPPORTED_S;
   
   FARF(SMS, ("==>  OEMSMSBCConfig_GetServiceOpts"));

   if (gpWms->sBcCfg.bBroadcastInUse != TRUE)
   {
#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
      if (mode == AEESMS_MODE_CDMA)
      {
#ifdef FEATURE_CDSMS_BROADCAST 
         wms_bc_mm_srv_id_type srv_id;
         MEMSET(&srv_id, 0, sizeof(wms_bc_mm_srv_id_type));
         if (ConvertAEESMSBCSrvIDToWMSBCMMSrvID(pSrvID, mode, &srv_id) == TRUE)
         {
            st = wms_bc_mm_get_service_info((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode, &srv_id);
         }
         else
         {
            st = WMS_INVALID_PARM_VALUE_S;
         }
#else // FEATURE_CDSMS_BROADCAST 
         wms_bc_service_id_s_type srv_id;
         MEMSET(&srv_id, 0, sizeof(wms_bc_service_id_s_type));
         if (ConvertAEESMSBCSrvIDToWMSBCSrvID(pSrvID, mode, &srv_id) == TRUE)
         {
            st = wms_bc_get_service_info((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, &srv_id);
         }
         else
         {
            st = WMS_INVALID_PARM_VALUE_S;
         }
#endif // FEATURE_CDSMS_BROADCAST
      }
      else if (mode == AEESMS_MODE_GW)
      {
         wms_bc_mm_srv_id_type srv_id;
         MEMSET(&srv_id, 0, sizeof(wms_bc_mm_srv_id_type));
         if (ConvertAEESMSBCSrvIDToWMSBCMMSrvID(pSrvID, mode, &srv_id) == TRUE)
         {
            st = wms_bc_mm_get_service_info((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode, &srv_id);
         }
         else
         {
            st = WMS_INVALID_PARM_VALUE_S;
         }
      }
      else
      {
         FARF(SMS, ("Request Rejected - Unsupported SMS Mode"));
         st = WMS_UNSUPPORTED_S;
      }
#else // FEATURE_BROADCAST_SMS_MULTIMODE 
      wms_bc_service_id_s_type srv_id;
      MEMSET(&srv_id, 0, sizeof(wms_bc_service_id_s_type));
      if (ConvertAEESMSBCSrvIDToWMSBCSrvID(pSrvID, mode, &srv_id) == TRUE)
      {
         st = wms_bc_get_service_info((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, &srv_id);
      }
      else
      {
         st = WMS_INVALID_PARM_VALUE_S;
      }
#endif // FEATURE_BROADCAST_SMS_MULTIMODE
 
      if (st == WMS_OK_S)
      {
         // Fill up the Current BC Configuration
         gpWms->sBcCfg.bBroadcastInUse = TRUE;                
         gpWms->sBcCfg.eCurRequest     = OEMSMSBCConfig_GetServiceOptsRequest;
         gpWms->sBcCfg.nNumCommands    = 1;
         gpWms->sBcCfg.dwMode         = mode;
         gpWms->sBcCfg.pcb            = pcb;
         gpWms->sBcCfg.psid           = pSrvID;
         gpWms->sBcCfg.pcb            = pcb;
         gpWms->sBcCfg.pSrvInfo       = pSrvInfo;
         gpWms->sBcCfg.pnErr          = pnErr;

         // Return Success to client
         nErr = SUCCESS;
      }
      else
      {
         // Return Error Code to Client
         nErr = Xlate_wms_status_2_AEEErrorCode(st);
      }
   }
   else
   {
      FARF(SMS, ("Request Rejected - Broadcast In Use"));
      nErr = EITEMBUSY;
   }
  
   if (nErr != SUCCESS)
   {
      // Fill up the Data
      *pnErr = nErr;

      // Call the Kernel Callback
      AEE_SVC_RESUME(pcb);
   }
}

/*===========================================================================
Function: OEMSMSBCConfig_SetServiceOpts
Description:
   Sets service options corresponding to the specified ID.
Return Value:
   None
===========================================================================*/
void OEMSMSBCConfig_SetServiceOpts(AEESMSMode mode, OEMSMSBCSrvInfo *pSrvInfo, AEECallback *pcb, uint32 * pnErr)
{
   int nErr = EUNSUPPORTED;
   wms_status_e_type st = WMS_UNSUPPORTED_S;

   FARF(SMS, ("==>  OEMSMSBCConfig_SetServiceOpts"));

   if (gpWms->sBcCfg.bBroadcastInUse != TRUE)
   {
#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
      if (mode == AEESMS_MODE_CDMA)
      {
#ifdef FEATURE_CDSMS_BROADCAST 
         wms_bc_mm_service_info_s_type srv_info;
         MEMSET(&srv_info, 0, sizeof(wms_bc_mm_service_info_s_type));
         if (ConvertOEMSMSBCSrvInfoToWMSBCMMSrvInfo(pSrvInfo, mode, &srv_info) == TRUE)
         {
            st = wms_bc_mm_change_service_info((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode, &srv_info);
            
            if (st == WMS_OK_S)
            {
               gpWms->sBcCfg.nNumCommands    = 1;
            }
         }
         else
         {
            st = WMS_INVALID_PARM_VALUE_S;
         }
#else // FEATURE_CDSMS_BROADCAST 
         wms_bc_service_info_s_type srv_info;
         MEMSET(&srv_info, 0, sizeof(wms_bc_service_info_s_type));
         if (ConvertOEMSMSBCSrvInfoToWMSBCSrvInfo(pSrvInfo, mode, &srv_info) == TRUE)
         {
            st = wms_bc_select_service((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, &srv_info.srv_id, srv_info.selected, srv_info.priority);
            
            if (st == WMS_OK_S)
            {
               st = wms_bc_change_label((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, &srv_info.srv_id, srv_info.label);

               if (st == WMS_OK_S)
               {
                  gpWms->sBcCfg.nNumCommands    = 2;
               }
            }
         }
         else
         {
            st = WMS_INVALID_PARM_VALUE_S;
         }
#endif // FEATURE_CDSMS_BROADCAST
      }
      else if (mode == AEESMS_MODE_GW)
      {
         wms_bc_mm_service_info_s_type srv_info;
         MEMSET(&srv_info, 0, sizeof(wms_bc_mm_service_info_s_type));
         if (ConvertOEMSMSBCSrvInfoToWMSBCMMSrvInfo(pSrvInfo, mode, &srv_info) == TRUE)
         {
            st = wms_bc_mm_change_service_info((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode, &srv_info);
            
            if (st == WMS_OK_S)
            {
               gpWms->sBcCfg.nNumCommands    = 1;
            }
         }
         else
         {
            st = WMS_INVALID_PARM_VALUE_S;
         }
      }
      else
      {
         FARF(SMS, ("Request Rejected - Unsupported SMS Mode"));
         st = WMS_UNSUPPORTED_S;
      }
#else // FEATURE_BROADCAST_SMS_MULTIMODE
      wms_bc_service_info_s_type srv_info;
      MEMSET(&srv_info, 0, sizeof(wms_bc_service_info_s_type));
      if (ConvertOEMSMSBCSrvInfoToWMSBCSrvInfo(pSrvInfo, mode, &srv_info) == TRUE)
      {
         st = wms_bc_select_service((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, &srv_info.srv_id, srv_info.selected, srv_info.priority);
            
         if (st == WMS_OK_S)
         {
            st = wms_bc_change_label((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, &srv_info.srv_id, srv_info.label);

            if (st == WMS_OK_S)
            {
               gpWms->sBcCfg.nNumCommands    = 2;
            }
         }
      }
      else
      {
         st = WMS_INVALID_PARM_VALUE_S;
      }
#endif // FEATURE_BROADCAST_SMS_MULTIMODE
           
      if (st == WMS_OK_S)
      {
         if ((gpWms->sBcCfg.pSrvInfo = MALLOC(sizeof(OEMSMSBCSrvInfo))) != NULL)
         {
            gpWms->sBcCfg.bSrvInfoAlloc = TRUE;

            MEMCPY(gpWms->sBcCfg.pSrvInfo, pSrvInfo, sizeof(OEMSMSBCSrvInfo));
         
            // Fill up the Current BC Configuration
            gpWms->sBcCfg.bBroadcastInUse = TRUE;                
            gpWms->sBcCfg.eCurRequest     = OEMSMSBCConfig_SetServiceOptsRequest;
            gpWms->sBcCfg.dwMode         = mode;
            gpWms->sBcCfg.pcb            = pcb;
            gpWms->sBcCfg.pnErr          = pnErr;            
            
            // Return Success to client
            nErr = SUCCESS;
         }
         else
         {
            nErr = ENOMEMORY;
         }
      }
      else
      {
         // Return Error Code to Client
         nErr = Xlate_wms_status_2_AEEErrorCode(st);
      }
   }
   else
   {
      FARF(SMS, ("Request Rejected - Broadcast In Use"));
      nErr = EITEMBUSY;
   }
   
   if (nErr != SUCCESS)
   {
      // Fill up the Data
      *pnErr = nErr;

      // Call the Kernel Callback
      AEE_SVC_RESUME(pcb);
   }
}

/*===========================================================================
Function: OEMSMSBCConfig_GetNumberOfServiceOpts
Description:
   Returns all the service options corresponding to the specified mode
Return Value:
   None
===========================================================================*/
void OEMSMSBCConfig_GetNumberOfServiceOpts(AEESMSMode mode, AEECallback *pcb, uint32 *pnCount, uint32 * pnErr)
{
   int nErr = EUNSUPPORTED;
   wms_status_e_type st = WMS_UNSUPPORTED_S;
   
   FARF(SMS, ("==>  OEMSMSBCConfig_GetNumberOfServiceOpts"));

   if (gpWms->sBcCfg.bBroadcastInUse != TRUE)
   {
#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
      if (mode == AEESMS_MODE_CDMA)
      {
#ifdef FEATURE_CDSMS_BROADCAST 
         st = wms_bc_mm_get_table((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode);
#else // FEATURE_CDSMS_BROADCAST 
         st = wms_bc_get_table((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL);
#endif // FEATURE_CDSMS_BROADCAST 
      }
      else if (mode == AEESMS_MODE_GW)
      {
         st = wms_bc_mm_get_table((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode);
      }
      else
      {
         FARF(SMS, ("Request Rejected - Unsupported SMS Mode"));
         st = WMS_UNSUPPORTED_S;
      }
#else // FEATURE_BROADCAST_SMS_MULTIMODE 
      st = wms_bc_get_table((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL);
#endif // FEATURE_BROADCAST_SMS_MULTIMODE

      if (st == WMS_OK_S)
      {
         // Fill up the Current BC Configuration
         gpWms->sBcCfg.bBroadcastInUse = TRUE;                
         gpWms->sBcCfg.eCurRequest     = OEMSMSBCConfig_GetNumberOfServiceOptsRequest;
         gpWms->sBcCfg.nNumCommands    = 1;
         gpWms->sBcCfg.dwMode         = mode;
         gpWms->sBcCfg.pcb            = pcb;
         gpWms->sBcCfg.pnCount        = pnCount;
         gpWms->sBcCfg.pnErr          = pnErr;               

         // Return Success to client
         nErr = SUCCESS;
      }
      else
      {
         // Return Error Code to Client
         nErr = Xlate_wms_status_2_AEEErrorCode(st);
      }
   }
   else
   {
      FARF(SMS, ("Request Rejected - Broadcast In Use"));
      nErr = EITEMBUSY;
   }
   
   if (nErr != SUCCESS)
   {
      // Fill up the Data
      *pnErr = nErr;

      // Call the Kernel Callback
      AEE_SVC_RESUME(pcb);
   }
}

/*===========================================================================
Function: OEMSMSBCConfig_DeleteService
Description:
   Removes a service from the device service table.
Return Value:
   None
===========================================================================*/
void OEMSMSBCConfig_DeleteService(AEESMSMode mode, AEESMSBCSrvID *pSrvID, AEECallback *pcb, uint32 * pnErr)
{
   int nErr = EUNSUPPORTED;
   wms_status_e_type st = WMS_UNSUPPORTED_S;
   
   FARF(SMS, ("==>  OEMSMSBCConfig_DeleteService"));

   if (gpWms->sBcCfg.bBroadcastInUse != TRUE)
   {
#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
      if (mode == AEESMS_MODE_CDMA)
      {
#ifdef FEATURE_CDSMS_BROADCAST 
         wms_bc_mm_srv_id_type srv_id;
         MEMSET(&srv_id, 0, sizeof(wms_bc_mm_srv_id_type));
         if (ConvertAEESMSBCSrvIDToWMSBCMMSrvID(pSrvID, mode, &srv_id) == TRUE)
         {
            st = wms_bc_mm_delete_services((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode, 1, &srv_id);
         }
         else
         {
            st = WMS_INVALID_PARM_VALUE_S;
         }
#else // FEATURE_CDSMS_BROADCAST
         wms_bc_service_id_s_type srv_id;
         MEMSET(&srv_id, 0, sizeof(wms_bc_service_id_s_type));
         if (ConvertAEESMSBCSrvIDToWMSBCSrvID(pSrvID, mode, &srv_id) == TRUE)
         {
            st = wms_bc_delete_service((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, &srv_id);
         }
         else
         {
            st = WMS_INVALID_PARM_VALUE_S;
         }
#endif // FEATURE_CDSMS_BROADCAST
      }
      else if (mode == AEESMS_MODE_GW)
      {
         wms_bc_mm_srv_id_type srv_id;
         MEMSET(&srv_id, 0, sizeof(wms_bc_mm_srv_id_type));
         if (ConvertAEESMSBCSrvIDToWMSBCMMSrvID(pSrvID, mode, &srv_id) == TRUE)
         {
            st = wms_bc_mm_delete_services((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, (wms_message_mode_e_type)mode, 1, &srv_id);
         }
         else
         {
            st = WMS_INVALID_PARM_VALUE_S;
         }
      }
      else
      {
         FARF(SMS, ("Request Rejected - Unsupported SMS Mode"));
         st = WMS_UNSUPPORTED_S;
      }
#else // FEATURE_BROADCAST_SMS_MULTIMODE
      wms_bc_service_id_s_type srv_id;
      MEMSET(&srv_id, 0, sizeof(wms_bc_service_id_s_type));
      if (ConvertAEESMSBCSrvIDToWMSBCSrvID(pSrvID, mode, &srv_id) == TRUE)
      {
         st = wms_bc_delete_service((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, NULL, &srv_id);
      }
      else
      {
         st = WMS_INVALID_PARM_VALUE_S;
      }
#endif // FEATURE_BROADCAST_SMS_MULTIMODE
      
      if (st == WMS_OK_S)
      {
         // Fill up the Current BC Configuration
         gpWms->sBcCfg.bBroadcastInUse = TRUE;                
         gpWms->sBcCfg.eCurRequest     = OEMSMSBCConfig_DeleteServiceRequest;
         gpWms->sBcCfg.nNumCommands    = 1;
         gpWms->sBcCfg.dwMode         = mode;
         gpWms->sBcCfg.pcb            = pcb;
         gpWms->sBcCfg.pnErr          = pnErr;
         
         // Return Success to client
         nErr = SUCCESS;
      }
      else
      {
         // Return Error Code to Client
         nErr = Xlate_wms_status_2_AEEErrorCode(st);
      }
   }
   else
   {
      FARF(SMS, ("Request Rejected - Broadcast In Use"));
      nErr = EITEMBUSY;
   }
   
   if (nErr != SUCCESS)
   {
      // Fill up the Data
      *pnErr = nErr;

      // Call the Kernel Callback
      AEE_SVC_RESUME(pcb);
   }
}

/*===========================================================================
Function: OEMSMSBCConfig_CleanOpInfo
Description:
   Cleans up information about current broadcast operation from gpUasms
Return Value:
   None
===========================================================================*/
static void OEMSMSBCConfig_CleanOpInfo(void)
{
   if (gpWms->sBcCfg.bSrvIDAlloc)
      FREEIF(gpWms->sBcCfg.psid);

   if (gpWms->sBcCfg.bSrvInfoAlloc)
      FREEIF(gpWms->sBcCfg.pSrvInfo);

   MEMSET(&gpWms->sBcCfg, 0, sizeof(gpWms->sBcCfg));
}


/*===========================================================================
Function: OEMSMSBCConfig_FillServiceIDs
Description:
   Fills the Service IDs
Return Value:
   None
===========================================================================*/
void OEMSMSBCConfig_FillServiceIDs( AEESMSBCSrvID *psid, uint32 dwBytes )
{
   FARF(SMS, ("==>  OEMSMSBCConfig_FillServiceIDs"));

   if ((psid != NULL) && 
       (gpWms->sBcCfg.psid != NULL) &&
       (dwBytes >= *gpWms->sBcCfg.pnCount*sizeof(AEESMSBCSrvID)))
   {
      MEMCPY(psid, gpWms->sBcCfg.psid, *gpWms->sBcCfg.pnCount*sizeof(AEESMSBCSrvID));
   }

   OEMSMSBCConfig_CleanOpInfo();
}

/*===========================================================================
Function: OEMSMSBCConfig_FillServiceInfo
Description:
   Fills the Service Info
Return Value:
   None
===========================================================================*/
void OEMSMSBCConfig_FillServiceInfo(OEMSMSBCSrvInfo *pSrvInfo, uint32 dwBytes)
{
   FARF(SMS, ("==>  OEMSMSBCConfig_FillServiceIDs"));

   if ((pSrvInfo != NULL) && 
       (gpWms->sBcCfg.pSrvInfo != NULL) &&
       (dwBytes >= *gpWms->sBcCfg.pnCount*sizeof(OEMSMSBCSrvInfo)))
   {
      MEMCPY(pSrvInfo, gpWms->sBcCfg.pSrvInfo, *gpWms->sBcCfg.pnCount*sizeof(OEMSMSBCSrvInfo));
   }

   OEMSMSBCConfig_CleanOpInfo();
}

#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
/*===========================================================================
Function: Xlate_AEESMSMode_2_wms_message_mode
Description:
   Translates the AEE SMS Mode to WMS Message Mode
Return Value:
   WMS Message Mode
===========================================================================*/
static wms_message_mode_e_type Xlate_AEESMSMode_2_wms_message_mode(AEESMSMode mode)
{
   wms_message_mode_e_type wmsMode;

   FARF(SMS, ("==>  Xlate_AEESMSMode_2_wms_message_mode"));

   switch(mode)
   {
      case AEESMS_MODE_CDMA:
         wmsMode = WMS_MESSAGE_MODE_CDMA;
         break;

      case AEESMS_MODE_GW:
         wmsMode = WMS_MESSAGE_MODE_GW;
         break;

      default:
         FARF(SMS, ("Invalid AEESMS Mode"));
         wmsMode = WMS_MESSAGE_MODE_MAX;
         break;
   }

   return wmsMode;
}

/*===========================================================================
Function: OEMWSMSBCMMConfig_EventCallback
Description:
   OEMWSMS Event Callback for Multimode Broadcast  
Return Value:
   None
===========================================================================*/
static void OEMWSMSBCMMConfig_EventCallback(wms_bc_mm_event_e_type event, wms_bc_mm_event_info_s_type *info_ptr)
{
   int i = 0;
   boolean bEventHandled = FALSE;

   FARF(SMS, ("==>  OEMWSMSBCMMConfig_EventCallback"));
       
   if ((event == WMS_BC_MM_EVENT_CONFIG) &&
       (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_GetBCConfigRequest))
   {   
      *gpWms->sBcCfg.pnErr = SUCCESS;
      *gpWms->sBcCfg.pConfig = info_ptr->u.bc_config;
      bEventHandled = TRUE;
   }
   else if ((event == WMS_BC_MM_EVENT_PREF) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_GetBCPrefRequest))
   {
      *gpWms->sBcCfg.pnErr = SUCCESS;
      *gpWms->sBcCfg.pPref = info_ptr->u.bc_pref;
      bEventHandled = TRUE;
   }
   else if((event == WMS_BC_MM_EVENT_PREF) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_SetBCPrefRequest))
   {
      *gpWms->sBcCfg.pnErr = SUCCESS;
      bEventHandled = TRUE;
   }
   else if ((event == WMS_BC_MM_EVENT_SRV_IDS) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_GetNumberOfServiceIDsRequest))
   {
      if ((gpWms->sBcCfg.psid = MALLOC(sizeof(AEESMSBCSrvID)*info_ptr->u.bc_mm_srv_ids.size)) != NULL)
      {
         gpWms->sBcCfg.bSrvIDAlloc = TRUE;
         *gpWms->sBcCfg.pnErr = SUCCESS;
         *gpWms->sBcCfg.pnCount = info_ptr->u.bc_mm_srv_ids.size;
         for (i = 0; i < (*gpWms->sBcCfg.pnCount); i++)
         {
            ConvertWMSBCMMSrvIDToAEESMSBCSrvID(&info_ptr->u.bc_mm_srv_ids.entries[i], info_ptr->message_mode, &gpWms->sBcCfg.psid[i]);
         }
      }
      else
      {
         *gpWms->sBcCfg.pnErr = ENOMEMORY;
      }
      bEventHandled = TRUE;
   }
   else if ((event == WMS_BC_MM_EVENT_SRV_INFO) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_GetServiceOptsRequest))
   {
      *gpWms->sBcCfg.pnErr = SUCCESS;
      ConvertWMSBCMMSrvInfoToOEMSMSBCSrvInfo(&info_ptr->u.bc_mm_srv_info, info_ptr->message_mode, gpWms->sBcCfg.pSrvInfo);
      bEventHandled = TRUE;
   }
   else if (((event == WMS_BC_MM_EVENT_ADD_SRVS) || (event == WMS_BC_MM_EVENT_SRV_UPDATED)) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_SetServiceOptsRequest))
   {
      *gpWms->sBcCfg.pnErr = SUCCESS;
      bEventHandled = TRUE;
   }
   else if ((event == WMS_BC_MM_EVENT_TABLE) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_GetNumberOfServiceOptsRequest))
   {
      if ((gpWms->sBcCfg.pSrvInfo = MALLOC(sizeof(OEMSMSBCSrvInfo)*info_ptr->u.bc_mm_table.size)) != NULL)
      {
         gpWms->sBcCfg.bSrvInfoAlloc = TRUE;
         *gpWms->sBcCfg.pnErr = SUCCESS;
         *gpWms->sBcCfg.pnCount = info_ptr->u.bc_mm_table.size;
         for (i = 0; i < (*gpWms->sBcCfg.pnCount); i++)
         {
            ConvertWMSBCMMSrvInfoToOEMSMSBCSrvInfo(&info_ptr->u.bc_mm_table.entries[i], info_ptr->message_mode, &gpWms->sBcCfg.pSrvInfo[i]);
         }
      }
      else
      {
         *gpWms->sBcCfg.pnErr = ENOMEMORY;
      }
      bEventHandled = TRUE;
   }
   else if ((event == WMS_BC_MM_EVENT_DELETE_SRVS) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_DeleteServiceRequest))
   {
      *gpWms->sBcCfg.pnErr = SUCCESS;
      bEventHandled = TRUE;
   }
   else
   {
      // Not Handled Event
      bEventHandled = FALSE;
   }
   
   if (bEventHandled)
   {
      // Call the Kernel Callback
      AEE_SVC_RESUME(gpWms->sBcCfg.pcb);

      // Broadcast In Use Flag will be reset later on 
      if ((event != WMS_BC_MM_EVENT_TABLE) &&
          (event != WMS_BC_MM_EVENT_SRV_IDS))
      {
         OEMSMSBCConfig_CleanOpInfo();
      }
   }
}

/*===========================================================================
Function: ConvertAEESMSBCSrvIDToWMSBCMMSrvID
Description:
   Convert AEESMS Service ID to WMS BC MM Service ID
Return Value:
  Indicates successful/ unsuccessful conversion
===========================================================================*/
static boolean ConvertAEESMSBCSrvIDToWMSBCMMSrvID( AEESMSBCSrvID *pSrvID, wms_message_mode_e_type mode, wms_bc_mm_srv_id_type *service_id)
{
   boolean bRetVal = TRUE;

   FARF(SMS, ("==>  ConvertAEESMSBCSrvIDToWMSBCMMSrvID"));

   if ( pSrvID == NULL || service_id == NULL)
   {
      bRetVal = FALSE;
   }
   else
   {
      if (mode == AEESMS_MODE_CDMA)
      {
         service_id->bc_srv_id.service  = (wms_service_e_type)pSrvID->srvType;
         service_id->bc_srv_id.language = (wms_language_e_type)pSrvID->dwLang;
      }
      else if (mode == AEESMS_MODE_GW)
      {
         service_id->gw_cb_range.from = pSrvID->fromService;
         service_id->gw_cb_range.to   = pSrvID->toService;
      }
      else
      {
         bRetVal = FALSE;
      }
   }
   return bRetVal;
}

/*===========================================================================
Function: ConvertWMSBCSrvIDToAEESMSBCMMSrvID
Description:
   Convert WMS BC MM Service ID to AEESMS Service ID
Return Value:
  Indicates successful/ unsuccessful conversion
===========================================================================*/
static boolean ConvertWMSBCMMSrvIDToAEESMSBCSrvID(wms_bc_mm_srv_id_type *service_id, wms_message_mode_e_type msg_mode,AEESMSBCSrvID *pSrvID)
{
   boolean bRetVal = TRUE;

   FARF(SMS, ("==>  ConvertWMSBCMMSrvIDToAEESMSBCSrvID"));
     
   if ( pSrvID == NULL || service_id == NULL)
   {
      bRetVal = FALSE;
   }
   else
   {
      if (msg_mode == WMS_MESSAGE_MODE_CDMA)
      {
         pSrvID->srvType = (AEESMSBCType)service_id->bc_srv_id.service;
         pSrvID->dwLang  = (uint32)service_id->bc_srv_id.language;
      }
      else if (msg_mode == WMS_MESSAGE_MODE_GW)
      {
         pSrvID->fromService = service_id->gw_cb_range.from;
         pSrvID->toService   = service_id->gw_cb_range.to;
      }
      else
      {
         bRetVal = FALSE;
      }
   }
   return bRetVal;
}

/*===========================================================================
Function: ConvertOEMSMSBCSrvInfoToWMSBCMMSrvInfo
Description:
   Convert OEMSMS Service Info to WMS BC MM Service Info
Return Value:
  Indicates successful/ unsuccessful conversion
===========================================================================*/
static boolean ConvertOEMSMSBCSrvInfoToWMSBCMMSrvInfo(OEMSMSBCSrvInfo *pSrvInfo, wms_message_mode_e_type mode, wms_bc_mm_service_info_s_type *srv_info)
{
   boolean bRetVal = TRUE;

   FARF(SMS, ("==>  ConvertOEMSMSBCSrvInfoToWMSBCMMSrvInfo"));

   if ( pSrvInfo == NULL || srv_info == NULL)
   {
      bRetVal = FALSE;
   }
   else
   {
      // Service ID
      if (ConvertAEESMSBCSrvIDToWMSBCMMSrvID(&pSrvInfo->sSrvID, mode, &srv_info->srv_id) == FALSE)
      {
         bRetVal = FALSE;
      }

      // Selected
      srv_info->selected = pSrvInfo->bSelected;

      // Priority
      srv_info->priority = pSrvInfo->nPriority;

      // Label
      MEMCPY(srv_info->label, pSrvInfo->szLabel, WMS_BC_SRV_LABEL_SIZE);

      // Label Encoding
      switch (pSrvInfo->nLabelEncoding)
      {
         case AEE_ENC_GSM_7_BIT_DEFAULT:
         case AEE_ENC_ISOLATIN1:
            srv_info->label_encoding = WMS_ENCODING_GSM_7_BIT_DEFAULT;
            break;

         case AEE_ENC_UTF8:
            srv_info->label_encoding = WMS_ENCODING_OCTET;
            break;

         case AEE_ENC_UNICODE:
            srv_info->label_encoding = WMS_ENCODING_UNICODE;
            break;

         default:
            bRetVal = FALSE;
            break;
      }

      // Alert
      srv_info->alert = pSrvInfo->nAlert;

      // Max Messages
      srv_info->max_messages = pSrvInfo->nMaxMessages;
   }
   return bRetVal;
}

/*===========================================================================
Function: ConvertWMSBCMMSrvInfoToOEMSMSBCSrvInfo
Description:
   Convert WMS BC MM Service Info to OEMSMS Service Info
Return Value:
  Indicates successful/ unsuccessful conversion
===========================================================================*/
static boolean ConvertWMSBCMMSrvInfoToOEMSMSBCSrvInfo(wms_bc_mm_service_info_s_type *srv_info, wms_message_mode_e_type msg_mode, OEMSMSBCSrvInfo *pSrvInfo)
{
   boolean bRetVal = TRUE;

   FARF(SMS, ("==>  ConvertWMSBCMMSrvInfoToOEMSMSBCSrvInfo"));

   if ( pSrvInfo == NULL || srv_info == NULL)
   {
      bRetVal = FALSE;
   }
   else
   {
      // Service ID
      if (ConvertWMSBCMMSrvIDToAEESMSBCSrvID(&srv_info->srv_id, msg_mode, &pSrvInfo->sSrvID) == FALSE)
      {
         bRetVal = FALSE;
      }

      // Selected
      pSrvInfo->bSelected = srv_info->selected;

      // Priority
      pSrvInfo->nPriority = srv_info->priority;

      // Label
      MEMSET(pSrvInfo->szLabel, 0, sizeof(pSrvInfo->szLabel));
      MEMCPY(pSrvInfo->szLabel, srv_info->label, WMS_BC_SRV_LABEL_SIZE);

      // Label Encoding
      pSrvInfo->nLabelEncoding = Xlate_Encoding(srv_info->label_encoding);
       
      // Alert
      pSrvInfo->nAlert          = srv_info->alert;

      // Max Messages
      pSrvInfo->nMaxMessages   = srv_info->max_messages;
   }

   return bRetVal;
}
#endif // FEATURE_BROADCAST_SMS_MULTIMODE

/*===========================================================================
Function: OEMWSMSBCConfig_CommandCallback
Description:
   OEMWSMS Command Callback 
Return Value:
   None
===========================================================================*/
static void OEMWSMSBCConfig_CommandCallback(wms_cmd_id_e_type cmd, void *user_data, wms_cmd_err_e_type cmd_err)
{
   int nErr = SUCCESS;

   FARF(SMS, ("==>  OEMWSMSBCConfig_CommandCallback"));

#ifdef FEATURE_BROADCAST_SMS_MULTIMODE
   // Special Handling for Add Service
   if ((cmd == WMS_CMD_BC_MM_CHANGE_SRV_INFO) &&
       (cmd_err == WMS_CMD_ERR_BC_BAD_SRV_ID))
   {
      wms_status_e_type st = WMS_INVALID_PARM_VALUE_S;

      if (gpWms->sBcCfg.dwMode == WMS_MESSAGE_MODE_CDMA)
      {
#ifdef FEATURE_CDSMS_BROADCAST 
         wms_bc_mm_service_info_s_type  srv_info;
         MEMSET(&srv_info, 0, sizeof(wms_bc_mm_service_info_s_type));
         // Service not Found ; Hence Add it
         if (ConvertOEMSMSBCSrvInfoToWMSBCMMSrvInfo(gpWms->sBcCfg.pSrvInfo, gpWms->sBcCfg.dwMode, &srv_info) == TRUE)
         {
            st = wms_bc_mm_add_services((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, user_data, gpWms->sBcCfg.dwMode, 1, &srv_info);
         }
#else // FEATURE_CDSMS_BROADCAST 
         wms_bc_service_info_s_type  srv_info;
         MEMSET(&srv_info, 0, sizeof(wms_bc_service_info_s_type));
         // Service not Found ; Hence Add it
         if (ConvertOEMSMSBCSrvInfoToWMSBCSrvInfo(gpWms->sBcCfg.pSrvInfo, gpWms->sBcCfg.dwMode, &srv_info) == TRUE)
         {
            st = wms_bc_add_service((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, user_data, &srv_info);
         }

         if (st == WMS_OK_S)
         {
            gpWms->sBcCfg.nNumCommands = 1;
         }
#endif // FEATURE_CDSMS_BROADCAST
      }
      else // GW Mode
      {
         wms_bc_mm_service_info_s_type  srv_info;
         MEMSET(&srv_info, 0, sizeof(wms_bc_mm_service_info_s_type));
         // Service not Found ; Hence Add it
         if (ConvertOEMSMSBCSrvInfoToWMSBCMMSrvInfo(gpWms->sBcCfg.pSrvInfo, gpWms->sBcCfg.dwMode, &srv_info) == TRUE)
         {
            st = wms_bc_mm_add_services((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, user_data, gpWms->sBcCfg.dwMode, 1, &srv_info);
         }
      }
     
      if (st != WMS_OK_S)
      {
         nErr = Xlate_wms_status_2_AEEErrorCode(st);
      }
   }
#else // FEATURE_BROADCAST_SMS_MULTIMODE
   // Special Handling for Add Service
   if ((cmd == WMS_CMD_BC_SELECT_SRV) &&
       (cmd_err == WMS_CMD_ERR_BC_BAD_SRV_ID))
   {
      wms_status_e_type st = WMS_INVALID_PARM_VALUE_S;
      wms_bc_service_info_s_type  srv_info;
      MEMSET(&srv_info, 0, sizeof(wms_bc_service_info_s_type));

      // Service not Found ; Hence Add it
      if (ConvertOEMSMSBCSrvInfoToWMSBCSrvInfo(gpWms->sBcCfg.pSrvInfo, gpWms->sBcCfg.dwMode, &srv_info) == TRUE)
      {
         st = wms_bc_add_service((wms_client_id_type)WMS_CLIENT_TYPE_BREW, OEMWSMSBCConfig_CommandCallback, user_data, &srv_info);
      }

      if (st == WMS_OK_S)
      {
         gpWms->sBcCfg.nNumCommands = 1;
      }
      else
      {
         nErr = Xlate_wms_status_2_AEEErrorCode(st);
      }
   }
#endif // FEATURE_BROADCAST_SMS_MULTIMODE
   else
   {
      nErr = Xlate_wms_cmd_err_2_AEEErrorCode(cmd_err);
   }

   if (nErr != SUCCESS)
   {
      // Fill up the Data
      if (gpWms->sBcCfg.pnErr)
      *gpWms->sBcCfg.pnErr = nErr;

      // Call the Kernel Callback
      if (gpWms->sBcCfg.pcb)
      AEE_SVC_RESUME(gpWms->sBcCfg.pcb);

      OEMSMSBCConfig_CleanOpInfo();
   }
}

/*===========================================================================
Function: OEMWSMSBCConfig_EventCallback
Description:
   OEMWSMS Event Callback for 1x Broadcast  
Return Value:
   None
===========================================================================*/
static void OEMWSMSBCConfig_EventCallback(wms_bc_event_e_type event, wms_bc_event_info_s_type *info_ptr)
{
   int i = 0;
   boolean bEventHandled = FALSE;

   FARF(SMS, ("==>  OEMWSMSBCConfig_EventCallback"));
       
   if ((event == WMS_BC_EVENT_CONFIG) &&
       (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_GetBCConfigRequest))
   {   
      *gpWms->sBcCfg.pnErr = SUCCESS;
      *gpWms->sBcCfg.pConfig = info_ptr->bc_config;
      bEventHandled = TRUE;
   }
   else if ((event == WMS_BC_EVENT_PREF) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_GetBCPrefRequest))
   {
      *gpWms->sBcCfg.pnErr = SUCCESS;
      *gpWms->sBcCfg.pPref = info_ptr->bc_pref;
      bEventHandled = TRUE;
   }
   else if((event == WMS_BC_EVENT_PREF) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_SetBCPrefRequest))
   {
      *gpWms->sBcCfg.pnErr = SUCCESS;
      bEventHandled = TRUE;
   }
   else if ((event == WMS_BC_EVENT_SRV_IDS) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_GetNumberOfServiceIDsRequest))
   {
      if ((gpWms->sBcCfg.psid = MALLOC(sizeof(AEESMSBCSrvID)*info_ptr->bc_srv_ids.size)) != NULL)
      {
         gpWms->sBcCfg.bSrvIDAlloc = TRUE;
         *gpWms->sBcCfg.pnErr = SUCCESS;
         *gpWms->sBcCfg.pnCount = info_ptr->bc_srv_ids.size;
         for (i = 0; i < (*gpWms->sBcCfg.pnCount); i++)
         {
            ConvertWMSBCSrvIDToAEESMSBCSrvID(&info_ptr->bc_srv_ids.entries[i], gpWms->sBcCfg.dwMode, &gpWms->sBcCfg.psid[i]);
         }
      }
      else
      {
         *gpWms->sBcCfg.pnErr = ENOMEMORY;
      }
      bEventHandled = TRUE;
   }
   else if ((event == WMS_BC_EVENT_SRV_INFO) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_GetServiceOptsRequest))
   {
      *gpWms->sBcCfg.pnErr = SUCCESS;
      ConvertWMSBCSrvInfoToOEMSMSBCSrvInfo(&info_ptr->bc_srv_info, gpWms->sBcCfg.dwMode, gpWms->sBcCfg.pSrvInfo);
      bEventHandled = TRUE;
   }
   else if (((event == WMS_BC_EVENT_SRV_ADDED) || (event == WMS_BC_EVENT_SRV_UPDATED)) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_SetServiceOptsRequest))
   {
      *gpWms->sBcCfg.pnErr = SUCCESS;
      bEventHandled = TRUE;
   }
   else if ((event == WMS_BC_EVENT_TABLE) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_GetNumberOfServiceOptsRequest))
   {
      if ((gpWms->sBcCfg.pSrvInfo = MALLOC(sizeof(OEMSMSBCSrvInfo)*info_ptr->bc_table.size)) != NULL)
      {
         gpWms->sBcCfg.bSrvInfoAlloc = TRUE;
         *gpWms->sBcCfg.pnErr = SUCCESS;
         *gpWms->sBcCfg.pnCount = info_ptr->bc_table.size;
         for (i = 0; i < (*gpWms->sBcCfg.pnCount); i++)
         {
            ConvertWMSBCSrvInfoToOEMSMSBCSrvInfo(&info_ptr->bc_table.entries[i], gpWms->sBcCfg.dwMode, &gpWms->sBcCfg.pSrvInfo[i]);
         }
      }
      else
      {
         *gpWms->sBcCfg.pnErr = ENOMEMORY;
      }
      bEventHandled = TRUE;
   }
   else if ((event == WMS_BC_EVENT_SRV_DELETED) &&
            (gpWms->sBcCfg.eCurRequest == OEMSMSBCConfig_DeleteServiceRequest))
   {
      *gpWms->sBcCfg.pnErr = SUCCESS;
      bEventHandled = TRUE;
   }
   else
   {
      // Not Handled Event
      bEventHandled = FALSE;
   }
   
   if (bEventHandled)
   {
      if (gpWms->sBcCfg.nNumCommands == 1)
      {
         // Call the Kernel Callback
         AEE_SVC_RESUME(gpWms->sBcCfg.pcb);

         // Broadcast In Use Flag will be reset later on 
         if ((event != WMS_BC_EVENT_TABLE) &&
             (event != WMS_BC_EVENT_SRV_IDS))
         {
            OEMSMSBCConfig_CleanOpInfo();
         }
      }
      else
      {
         // Decrement Num Commands 
         gpWms->sBcCfg.nNumCommands -= 1;
      }
   }
}

/*===========================================================================
Function: ConvertAEESMSBCSrvIDToWMSBCSrvID
Description:
   Convert AEESMS Service ID to WMS BC Service ID
Return Value:
  Indicates successful/ unsuccessful conversion
===========================================================================*/
static boolean ConvertAEESMSBCSrvIDToWMSBCSrvID( AEESMSBCSrvID *pSrvID, wms_message_mode_e_type mode, wms_bc_service_id_s_type *service_id)
{
   boolean bRetVal = TRUE;

   FARF(SMS, ("==>  ConvertAEESMSBCSrvIDToWMSBCSrvID"));

   if ( pSrvID == NULL || service_id == NULL)
   {
      bRetVal = FALSE;
   }
   else
   {
      if (mode == AEESMS_MODE_CDMA)
      {
         service_id->service  = (wms_service_e_type)pSrvID->srvType;
         service_id->language = (wms_language_e_type)pSrvID->dwLang;
      }
      else
      {
         bRetVal = FALSE;
      }
   }
   return bRetVal;
}

/*===========================================================================
Function: ConvertWMSBCSrvIDToAEESMSBCSrvID
Description:
   Convert WMS BC Service ID to AEESMS Service ID
Return Value:
  Indicates successful/ unsuccessful conversion
===========================================================================*/
static boolean ConvertWMSBCSrvIDToAEESMSBCSrvID(wms_bc_service_id_s_type *service_id, wms_message_mode_e_type msg_mode, AEESMSBCSrvID *pSrvID)
{
   boolean bRetVal = TRUE;

   FARF(SMS, ("==>  ConvertWMSBCSrvIDToAEESMSBCSrvID"));
     
   if ( pSrvID == NULL || service_id == NULL)
   {
      bRetVal = FALSE;
   }
   else
   {
      if (msg_mode == WMS_MESSAGE_MODE_CDMA)
      {
         pSrvID->srvType = (AEESMSBCType)service_id->service;
         pSrvID->dwLang  = (uint32)service_id->language;
      }
      else
      {
         bRetVal = FALSE;
      }
   }
   return bRetVal;
}

/*===========================================================================
Function: ConvertOEMSMSBCSrvInfoToWMSBCSrvInfo
Description:
   Convert OEMSMS Service Info to WMS BC Service Info
Return Value:
  Indicates successful/ unsuccessful conversion
===========================================================================*/
static boolean ConvertOEMSMSBCSrvInfoToWMSBCSrvInfo(OEMSMSBCSrvInfo *pSrvInfo, wms_message_mode_e_type mode, wms_bc_service_info_s_type *srv_info)
{
   boolean bRetVal = TRUE;

   FARF(SMS, ("==>  ConvertOEMSMSBCSrvInfoToWMSBCSrvInfo"));

   if ( pSrvInfo == NULL || srv_info == NULL)
   {
      bRetVal = FALSE;
   }
   else
   {
      // Service ID
      if (ConvertAEESMSBCSrvIDToWMSBCSrvID(&pSrvInfo->sSrvID, mode, &srv_info->srv_id) == FALSE)
      {
         bRetVal = FALSE;
      }

      // Selected
      srv_info->selected = pSrvInfo->bSelected;

      // Priority
      srv_info->priority = pSrvInfo->nPriority;

      // Label
      MEMCPY(srv_info->label, pSrvInfo->szLabel, WMS_BC_SRV_LABEL_SIZE);

      // Label Encoding
      switch (pSrvInfo->nLabelEncoding)
      {
         case AEE_ENC_GSM_7_BIT_DEFAULT:
         case AEE_ENC_ISOLATIN1:
            srv_info->label_encoding = WMS_ENCODING_GSM_7_BIT_DEFAULT;
            break;

         case AEE_ENC_UTF8:
            srv_info->label_encoding = WMS_ENCODING_OCTET;
            break;

         case AEE_ENC_UNICODE:
            srv_info->label_encoding = WMS_ENCODING_UNICODE;
            break;

         default:
            bRetVal = FALSE;
            break;
      }

      // Alert
      srv_info->alert = pSrvInfo->nAlert;

      // Max Messages
      srv_info->max_messages = pSrvInfo->nMaxMessages;
   }
   return bRetVal;
}

/*===========================================================================
Function: ConvertWMSBCSrvInfoToOEMSMSBCSrvInfo
Description:
   Convert WMS BC Service Info to OEMSMS Service Info
Return Value:
  Indicates successful/ unsuccessful conversion
===========================================================================*/
static boolean ConvertWMSBCSrvInfoToOEMSMSBCSrvInfo(wms_bc_service_info_s_type *srv_info, wms_message_mode_e_type msg_mode, OEMSMSBCSrvInfo *pSrvInfo)
{
   boolean bRetVal = TRUE;

   FARF(SMS, ("==>  ConvertWMSBCSrvInfoToOEMSMSBCSrvInfo"));

   if ( pSrvInfo == NULL || srv_info == NULL)
   {
      bRetVal = FALSE;
   }
   else
   {
      // Service ID
      if (ConvertWMSBCSrvIDToAEESMSBCSrvID(&srv_info->srv_id, msg_mode, &pSrvInfo->sSrvID) == FALSE)
      {
         bRetVal = FALSE;
      }

      // Selected
      pSrvInfo->bSelected = srv_info->selected;

      // Priority
      pSrvInfo->nPriority = srv_info->priority;

      // Label
      MEMSET(pSrvInfo->szLabel, 0, sizeof(pSrvInfo->szLabel));
      MEMCPY(pSrvInfo->szLabel, srv_info->label, WMS_BC_SRV_LABEL_SIZE);

      // Label Encoding
      pSrvInfo->nLabelEncoding = Xlate_Encoding(srv_info->label_encoding);
       
      // Alert
      pSrvInfo->nAlert          = srv_info->alert;

      // Max Messages
      pSrvInfo->nMaxMessages   = srv_info->max_messages;
   }

   return bRetVal;
}
#else // FEATURE_BREW_BROADCAST_SMS
/*===========================================================================
   Stub
===========================================================================*/
void OEMSMSBCConfig_GetBCConfig(AEESMSMode mode, AEECallback *pcb, AEESMSBCConfig * pConfig, uint32 * pnErr)
{   
   FARF(SMS, ("==>  OEMSMSBCConfig_GetBCConfig - Not Supported"));
   *pnErr = EUNSUPPORTED;
   AEE_SVC_RESUME(pcb);
}

/*===========================================================================
   Stub
===========================================================================*/
void OEMSMSBCConfig_GetBCPref(AEESMSMode mode, AEECallback *pcb, AEESMSBCPref * pPref, uint32 * pnErr)
{   
   FARF(SMS, ("==>  OEMSMSBCConfig_GetBCPref - Not Supported"));
   *pnErr = EUNSUPPORTED;
   AEE_SVC_RESUME(pcb);
}

/*===========================================================================
   Stub
===========================================================================*/
void OEMSMSBCConfig_SetBCPref(AEESMSMode mode, AEESMSBCPref nPref, AEECallback *pcb, uint32 * pnErr)
{   
   FARF(SMS, ("==>  OEMSMSBCConfig_SetBCPref - Not Supported"));
   *pnErr = EUNSUPPORTED;
   AEE_SVC_RESUME(pcb);
}

/*===========================================================================
   Stub
===========================================================================*/
void OEMSMSBCConfig_GetNumberOfServiceIDs(AEESMSMode mode, AEECallback *pcb, uint32 * pnCount, uint32 * pnErr)
{   
   FARF(SMS, ("==>  OEMSMSBCConfig_GetNumberOfServiceIDs - Not Supported"));
   *pnErr = EUNSUPPORTED;
   AEE_SVC_RESUME(pcb);
}

/*===========================================================================
   Stub
===========================================================================*/
void OEMSMSBCConfig_GetServiceOpts(AEESMSMode mode, AEESMSBCSrvID *pSrvID, AEECallback *pcb, OEMSMSBCSrvInfo * pSrvInfo, uint32 * pnErr)
{   
   FARF(SMS, ("==>  OEMSMSBCConfig_GetServiceOpts - Not Supported"));
   *pnErr = EUNSUPPORTED;
   AEE_SVC_RESUME(pcb);
}

/*===========================================================================
   Stub
===========================================================================*/
void OEMSMSBCConfig_SetServiceOpts(AEESMSMode mode, OEMSMSBCSrvInfo * pSrvInfo, AEECallback *pcb, uint32 * pnErr)
{   
   FARF(SMS, ("==>  OEMSMSBCConfig_SetServiceOpts - Not Supported"));
   *pnErr = EUNSUPPORTED;
   AEE_SVC_RESUME(pcb);
}

/*===========================================================================
   Stub
===========================================================================*/
void OEMSMSBCConfig_GetNumberOfServiceOpts(AEESMSMode mode, AEECallback *pcb, uint32 * pnCount, uint32 * pnErr)
{   
   FARF(SMS, ("==>  OEMSMSBCConfig_GetNumberOfServiceOpts - Not Supported"));
   *pnErr = EUNSUPPORTED;
   AEE_SVC_RESUME(pcb);
}

/*===========================================================================
   Stub
===========================================================================*/
void OEMSMSBCConfig_DeleteService(AEESMSMode mode, AEESMSBCSrvID *pSrvID, AEECallback *pcb, uint32 * pnErr)
{   
   FARF(SMS, ("==>  OEMSMSBCConfig_DeleteService - Not Supported"));
   *pnErr = EUNSUPPORTED;
   AEE_SVC_RESUME(pcb);
}

/*===========================================================================
   Stub
===========================================================================*/
void OEMSMSBCConfig_FillServiceIDs(AEESMSBCSrvID *psid, uint32 dwBytes)
{   
   FARF(SMS, ("==>  OEMSMSBCConfig_FillServiceIDs - Not Supported"));
}

/*===========================================================================
   Stub
===========================================================================*/
void OEMSMSBCConfig_FillServiceInfo(OEMSMSBCSrvInfo *pSrvInfo, uint32 dwBytes)
{   
   FARF(SMS, ("==>  OEMSMSBCConfig_FillServiceInfo - Not Supported"));
}
#endif // FEATURE_BREW_BROADCAST_SMS
#endif /*FEATURE_WMS*/
