view src/g23m-aci/aci/cmh_smsf.c @ 296:a927f030a4e0

add AT@VIBR and AT@VIBS commands for testing VIBR SWE
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 28 Mar 2022 00:43:11 +0000
parents fa8dc04885d8
children
line wrap: on
line source

/*
+-----------------------------------------------------------------------------
|  Project :  GSM-PS (6147)
|  Modul   :  CMH_SMSF
+-----------------------------------------------------------------------------
|  Copyright 2002 Texas Instruments Berlin, AG
|                 All rights reserved.
|
|                 This file is confidential and a trade secret of Texas
|                 Instruments Berlin, AG
|                 The receipt of or possession of this file does not convey
|                 any rights to reproduce or disclose its contents or to
|                 manufacture, use, or sell anything it may describe, in
|                 whole, or in part, without the specific written consent of
|                 Texas Instruments Berlin, AG.
+-----------------------------------------------------------------------------
|  Purpose :  This module defines the functions used by the command
|             handler for the short message service.
+-----------------------------------------------------------------------------
*/

#ifndef CMH_SMSF_C 
#define CMH_SMSF_C
#endif

#include "aci_all.h"
/*==== INCLUDES ===================================================*/
#include "aci_cmh.h"
#include "ati_cmd.h"
#include "aci_cmd.h"

#ifdef FAX_AND_DATA
#include "aci_fd.h"
#endif    /* of #ifdef FAX_AND_DATA */

#include "aci.h"
#include "aci_lst.h"
#include "aci_mem.h"
#include "psa.h"
#include "psa_cc.h"
#ifdef SIM_TOOLKIT
#include "psa_sat.h"
#endif
#include "psa_sms.h"
#include "psa_sim.h"
#include "psa_mmi.h"
#include "psa_util.h"
#include "phb.h"
#include "cmh.h"
#include "cmh_sms.h"
#include "pcm.h"

#include "aci_lst.h"

#if (defined (MFW) AND !defined (FF_MMI_RIV)) OR defined (_CONC_TESTING_)
#include "conc_sms.h"
#endif /* ##if (defined (MFW) AND !defined (FF_MMI_RIV)) OR defined (_CONC_TESTING_)*/


#ifdef UART
#include "dti_conn_mng.h"
#endif

#include "cmh_sim.h"
#ifndef _SIMULATION_

/* temporary solution to get ffs.h included without GPRS to be set ! */
#ifdef GPRS
#include "ffs/ffs.h"
#else
#include "ffs/ffs.h"
#undef GPRS
#endif /* GPRS */

#include "ffs_coat.h"

#endif /* !_SIMULATION_ */

#ifdef FF_CPHS
#include "cphs.h"
#endif /* FF_CPHS */

/*==== CONSTANTS ==================================================*/
#define CMMS_MODE_TIMER_VAL (5000)
#define SMS_CMH_YEAR_MAX   (99) /* maximum value for year in   */
                                /* absolute validity period    */
#define SMS_CMH_YEAR_MIN   (0)  /* minimum value for year in   */
                                /* absolute  validity period   */
#define SMS_CMH_MONTH_MAX  (12) /* maximum value for month in  */
                                /* absolute validity period    */
#define SMS_CMH_MONTH_MIN  (1)  /* minimum value for month in  */
                                /* absolute  validity period   */
#define SMS_CMH_DAY_MAX    (31) /* maximum value for day in    */
                                /* absolute validity period    */
#define SMS_CMH_DAY_MIN    (1)  /* minimum value for day in    */
                                /* absolute  validity period   */
#define SMS_CMH_HOUR_MAX   (23) /* maximum value for hour in   */
                                /* absolute validity period    */
#define SMS_CMH_HOUR_MIN   (0)  /* minimum value for hour in   */
                                /* absolute  validity period   */
#define SMS_CMH_MINUTE_MAX (59) /* maximum value for minute in */
                                /* absolute validity period    */
#define SMS_CMH_MINUTE_MIN (0)  /* minimum value for minute in */
                                /* absolute  validity period   */
#define SMS_CMH_SECOND_MAX (59) /* maximum value for second in */
                                /* absolute validity period    */
#define SMS_CMH_SECOND_MIN (0)  /* minimum value for second in */
                                /* absolute  validity period   */

#define SMS_CMH_TZ_MAX    (47)  /* maximum value for a time  */
                                /* zone in absolute validity */
                                /* period                    */
#define SMS_CMH_TZ_MIN    (-47) /* minimum value for a time  */
                                /* zone in absolute validity */
                                /* period                    */


/* macro for converting a two digit BCD into an UBYTE */
#define BCD2UBYTE(bcd) (UBYTE)(10 * bcd[0] + bcd[1])

/* macro for testing whether any digit of a two digit */
/* BCD lies outside of a predefined value range       */
#define NOTBCD(bcd) (bcd[0] > 9 OR\
                     bcd[1] > 9 )


#define L_MAX_UD      140
#define L_MAX_UD_CONC 134

#ifdef FF_CPHS_REL4
typedef enum 
{
  MSG_WAITING_TYPE_INVALID = -1,
  MSG_WAITING_TYPE_VOICE,
  MSG_WAITING_TYPE_FAX,
  MSG_WAITING_TYPE_EMAIL,
  MSG_WAITING_TYPE_OTHER
} T_MSG_WAITING_TYPE;
#endif

/*==== TYPES ======================================================*/

/*==== EXPORT =====================================================*/
EXTERN T_ACI_LIST *set_prm_list;

/*==== PROTOTYPES==================================================*/
/* Implements Measure # 73 */
LOCAL BOOL cmhSMS_findMessageIds (USHORT lower_mid, USHORT upper_mid);
/* Implements Measure # 126 */
LOCAL void cmhSMS_processOrigDestAddr (T_ACI_CMGL_SM  *sm, 
                                       T_rp_addr      *rp_addr,
                                       T_tp_da        *tp_addr );
/* Implements Measure # 9 */
LOCAL void cmhSMS_clearCbmPrm (void);


/*==== VARIABLES ==================================================*/

const char * const ffs_smsprfl_fname[] = { FFS_SMSPRFL_FNAME01,
                                    FFS_SMSPRFL_FNAME02,
                                    FFS_SMSPRFL_FNAME03,
                                    FFS_SMSPRFL_FNAME04 };

/*==== FUNCTIONS ==================================================*/

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : ACI_CMD            |
| STATE   : code                        ROUTINE : aci_encodeVpenh    |
+--------------------------------------------------------------------+

  PURPOSE : This function encodes a given T_ACI_VP_ENH type to a
            string.
*/
GLOBAL void aci_encodeVpenh ( CHAR*         vpenh_str,
                              T_ACI_VP_ENH* vpenh )
{
  UBYTE pos;

  /* functionality indicator */
  utl_binToHex (&vpenh->func_ind, 1, vpenh_str);
  pos = 2;

  /* extension octet */
  if (vpenh->func_ind & TP_VPF_ENH_EXT_BIT_MASK)
  {
    utl_binToHex (&vpenh->ext_oct, 1, vpenh_str+pos);
    pos += 2;
  }

  /* process validity period values */
  if ((vpenh->func_ind & TP_VPF_ENH_FORMAT_MASK) EQ TP_VPF_ENH_REL)
  {
    utl_binToHex (&vpenh->val.vpenh_relative, 1, vpenh_str+pos );
    pos += 2;
  }
  else if ((vpenh->func_ind & TP_VPF_ENH_FORMAT_MASK) EQ TP_VPF_ENH_SEC)
  {
    utl_binToHex (&vpenh->val.vpenh_seconds, 1, vpenh_str+pos );
    pos += 2;
  }
  else if ((vpenh->func_ind & TP_VPF_ENH_FORMAT_MASK) EQ TP_VPF_ENH_HRS)
  {
    vpenh_str[pos++] = vpenh->val.vpenh_hours.hour[1] + '0';
    vpenh_str[pos++] = vpenh->val.vpenh_hours.hour[0] + '0';

    vpenh_str[pos++] = vpenh->val.vpenh_hours.minute[1] + '0';
    vpenh_str[pos++] = vpenh->val.vpenh_hours.minute[0] + '0';

    vpenh_str[pos++] = vpenh->val.vpenh_hours.second[1] + '0';
    vpenh_str[pos++] = vpenh->val.vpenh_hours.second[0] + '0';
  }

  /* fill the rest with zeros */
  while (pos < 14)
  {
    vpenh_str[pos++] = '0';
  }

  /* string terminator */
  vpenh_str[pos] = '\0';
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_getNType         |
+-------------------------------------------------------------------+

  PURPOSE : This function calculates the 'numbering type' out of the
            current 'type of numbering'.
*/
GLOBAL UBYTE cmhSMS_getNType ( T_ACI_TOA_TON ton )
{
  switch( ton )
  {
    case( TON_International ):
    case( TON_National      ):
    case( TON_NetSpecific   ):
    case( TON_DedAccess     ):
    case( TON_Alphanumeric  ):
    case( TON_Abbreviated   ): return (UBYTE)ton;
    default:                   return SMS_TON_UNKNOWN;
  }
}


GLOBAL BOOL cmhSMS_findPrflId ( UBYTE critrerium, void* elem )
{
  T_SMS_SET_PRM *compared = (T_SMS_SET_PRM*)elem;
  if ( compared->prflId == critrerium )
    return TRUE;
  else
    return FALSE;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_getTon           |
+-------------------------------------------------------------------+

  PURPOSE : This function calculates the 'type of numbering' out of
            the current 'numbering type'.
*/
GLOBAL T_ACI_TOA_TON cmhSMS_getTon ( UBYTE ntype )
{
  switch( ntype )
  {
    case( SMS_TON_UNKNOWN       ):
    case( SMS_TON_INTERNATIONAL ):
    case( SMS_TON_NATIONAL      ):
    case( SMS_TON_NETWORK_SPEC  ):
    case( SMS_TON_SUBSCRIBER    ):
    case( SMS_TON_ALPHANUMERIC  ):
    case( SMS_TON_ABBREVIATED   ): return (T_ACI_TOA_TON)ntype;
    default:                       return TON_NotPresent;
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_getNPlan         |
+-------------------------------------------------------------------+

  PURPOSE : This function calculates the 'numbering plan' out of the
            current 'numbering plan identification'.
*/
GLOBAL UBYTE cmhSMS_getNPlan ( T_ACI_TOA_NPI npi )
{
  switch( npi )
  {
    case( NPI_IsdnTelephony ):
    case( NPI_Data          ):
    case( NPI_Telex         ):
    case( NPI_National      ):
    case( NPI_Private       ): return (UBYTE)npi;
    default:                   return NPI_Unknown;
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_getNpi           |
+-------------------------------------------------------------------+

  PURPOSE : This function calculates the 'numbering plan
            identification' out of the current 'numbering plan'.
*/
GLOBAL T_ACI_TOA_NPI cmhSMS_getNpi ( UBYTE nplan )
{
  switch( nplan )
  {
    case( SMS_TON_UNKNOWN  ):
    case( SMS_NPI_ISDN     ):
    case( SMS_NPI_X121     ):
    case( SMS_NPI_F69      ):
    case( SMS_NPI_NATIONAL ):
    case( SMS_NPI_PRIVATE  ): return (T_ACI_TOA_NPI)nplan;
    default:                  return NPI_NotPresent;
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_getStatCmh       |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the message status from
            PSA type to CMH type.
*/
GLOBAL void cmhSMS_getStatCmh ( UBYTE           inStat,
                                T_ACI_SMS_STAT* outStat )
{
  switch( inStat & STAT_MASK )
  {
    case( REC_UNREAD ): *outStat = SMS_STAT_RecUnread; break;
    case( REC_READ   ): *outStat = SMS_STAT_RecRead;   break;
    case( STO_UNSENT ): *outStat = SMS_STAT_StoUnsent; break;
    case( STO_SENT   ): *outStat = SMS_STAT_StoSent;   break;
    default:            *outStat = SMS_STAT_NotPresent;
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_getStatPsa       |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the message status from
            CMH type to PSA type.
*/
GLOBAL BOOL cmhSMS_getStatPsa ( T_ACI_SMS_STAT inStat,
                                UBYTE*         outStat )
{
  switch( inStat )
  {
    case( SMS_STAT_RecUnread ): *outStat = REC_UNREAD; break;
    case( SMS_STAT_RecRead   ): *outStat = REC_READ;   break;
    case( SMS_STAT_StoUnsent ): *outStat = STO_UNSENT; break;
    case( SMS_STAT_StoSent   ): *outStat = STO_SENT;   break;
    default                   : return (FALSE);
  }

  return ( TRUE );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_isVpabsVld       |
+-------------------------------------------------------------------+

  PURPOSE : This function is used to process whether the given
            absolute validity period is valid.

            Note: This function checks whether every individual
                  time value is within a valid range. It does not
                  check whether the whole expression is valid.
*/
GLOBAL BOOL cmhSMS_isVpabsVld ( T_ACI_VP_ABS* vpabs )
{
  if ( BCD2UBYTE ( vpabs -> year   ) > SMS_CMH_YEAR_MAX   OR
       BCD2UBYTE ( vpabs -> month  ) < SMS_CMH_MONTH_MIN  OR
       BCD2UBYTE ( vpabs -> month  ) > SMS_CMH_MONTH_MAX  OR
       BCD2UBYTE ( vpabs -> day    ) < SMS_CMH_DAY_MIN    OR
       BCD2UBYTE ( vpabs -> day    ) > SMS_CMH_DAY_MAX    OR
       BCD2UBYTE ( vpabs -> hour   ) > SMS_CMH_HOUR_MAX   OR
       BCD2UBYTE ( vpabs -> minute ) > SMS_CMH_MINUTE_MAX OR
       BCD2UBYTE ( vpabs -> second ) > SMS_CMH_SECOND_MAX OR
       vpabs -> timezone             < SMS_CMH_TZ_MIN     OR
       vpabs -> timezone             > SMS_CMH_TZ_MAX     OR
       NOTBCD ( vpabs -> year   )                         OR
       NOTBCD ( vpabs -> month  )                         OR
       NOTBCD ( vpabs -> day    )                         OR
       NOTBCD ( vpabs -> hour   )                         OR
       NOTBCD ( vpabs -> minute )                         OR
       NOTBCD ( vpabs -> second )                            )

        return ( FALSE );

  return ( TRUE );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_isVpenhVld       |
+-------------------------------------------------------------------+

  PURPOSE : This function is used to process whether the given
            enhanced validity period is valid.

            Note: This function checks whether every individual
                  time value is within a valid range. It does not
                  check whether the whole expression is valid.
*/
GLOBAL BOOL cmhSMS_isVpenhVld ( T_ACI_VP_ENH* vpenh )
{
  if ((vpenh->func_ind & TP_VPF_ENH_FORMAT_MASK) > TP_VPF_ENH_HRS)
  {
    return FALSE;
  }

  if ((vpenh->func_ind & TP_VPF_ENH_FORMAT_MASK) EQ TP_VPF_ENH_HRS)
  {
    if ( BCD2UBYTE ( vpenh->val.vpenh_hours.minute ) > SMS_CMH_MINUTE_MAX OR
         BCD2UBYTE ( vpenh->val.vpenh_hours.second ) > SMS_CMH_SECOND_MAX OR
         NOTBCD ( vpenh->val.vpenh_hours.hour   )                         OR
         NOTBCD ( vpenh->val.vpenh_hours.minute )                         OR
         NOTBCD ( vpenh->val.vpenh_hours.second )                            )
    {
      return ( FALSE );
    }
  }

  return ( TRUE );
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_setVpabsPsa      |
+-------------------------------------------------------------------+

  PURPOSE : This function is used to copy the elements of the
            absolute validity period structure of the ACI to the
            corresponding structure of the PSA.

            Note: Copying of the structure elements might be
                  dangerous when array size of time elements differ
                  from MAX_VP_ABS_DIGIT due to changes in PSA
                  declaration.
*/
GLOBAL void cmhSMS_setVpabsPsa ( T_tp_vp_abs*     psaVp,
                                 T_ACI_VP_ABS* cmhVp )
{
  USHORT i; /* used for counting */

  BOOL  isNegative = ( cmhVp->timezone & 0x8000 );
  SHORT tz   = ( UBYTE ) cmhVp->timezone;

  for (i = 0; i < MAX_VP_ABS_DIGITS; i++)
  {
    psaVp -> year  [i] = cmhVp -> year  [i];
    psaVp -> month [i] = cmhVp -> month [i];
    psaVp -> day   [i] = cmhVp -> day   [i];
    psaVp -> hour  [i] = cmhVp -> hour  [i];
    psaVp -> minute[i] = cmhVp -> minute[i];
    psaVp -> second[i] = cmhVp -> second[i];
  }

  if ( isNegative )
  {
    tz = -tz;
    psaVp -> tz_sign = 1;
  }
  else
  {
    psaVp -> tz_sign = 0;
  }

  psaVp -> tz_lsb = tz & 0x000F;
  psaVp -> tz_msb = tz & 0x00F0;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_setVpenhPsa      |
+-------------------------------------------------------------------+

  PURPOSE : This function is used to copy the elements of the
            enhanced validity period structure of the ACI to the
            corresponding structure of the PSA.
*/
GLOBAL void cmhSMS_setVpenhPsa ( T_tp_vp_enh*  psaVp,
                                 T_ACI_VP_ENH* cmhVp )
{
  memset(psaVp, 0, sizeof(T_tp_vp_enh));

  if (cmhVp->func_ind & TP_VPF_ENH_EXT_BIT_MASK)
  {
    psaVp->tp_ext = SMS_EXT_INCLUDED;
    psaVp->v_tp_rsrvd = 1;
    psaVp->tp_rsrvd = cmhVp->ext_oct;
  }

  if (cmhVp->func_ind & TP_VPF_ENH_SINGLE_SHOT_MASK)
  {
    psaVp->tp_ss = SMS_SS_SET;
  }

  if ((cmhVp->func_ind & TP_VPF_ENH_FORMAT_MASK) EQ TP_VPF_ENH_NOT_PRESENT)
  {
    psaVp->tvpf = SMS_TVPF_NOT_PRESENT;
  }
  else if ((cmhVp->func_ind & TP_VPF_ENH_FORMAT_MASK) EQ TP_VPF_ENH_REL)
  {
    psaVp->tvpf = SMS_TVPF_RELATIVE;
    psaVp->v_tp_vp_rel = 1;
    psaVp->tp_vp_rel = cmhVp->val.vpenh_relative;
  }
  else if ((cmhVp->func_ind & TP_VPF_ENH_FORMAT_MASK) EQ TP_VPF_ENH_SEC)
  {
    psaVp->tvpf = SMS_TVPF_SECONDS;
    psaVp->v_tp_vp_sec = 1;
    psaVp->tp_vp_sec = cmhVp->val.vpenh_seconds;
  }
  else if ((cmhVp->func_ind & TP_VPF_ENH_FORMAT_MASK) EQ TP_VPF_ENH_HRS)
  {
    psaVp->tvpf = SMS_TVPF_HOURS;
    psaVp->v_hour = 1;
    psaVp->hour[0] = cmhVp->val.vpenh_hours.hour[0];
    psaVp->hour[1] = cmhVp->val.vpenh_hours.hour[1];
    psaVp->v_minute = 1;
    psaVp->minute[0] = cmhVp->val.vpenh_hours.minute[0];
    psaVp->minute[1] = cmhVp->val.vpenh_hours.minute[1];
    psaVp->v_second = 1;
    psaVp->second[0] = cmhVp->val.vpenh_hours.second[0];
    psaVp->second[1] = cmhVp->val.vpenh_hours.second[1];
  }
  else
  {
    TRACE_EVENT("[ERR] cmhSMS_setVpenhPsa: wrong type of validity period format");
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_setVpabsCmh      |
+-------------------------------------------------------------------+

  PURPOSE : This function is used to copy the elements of the
            absolute validity period structure of the PSA to the
            corresponding structure of the ACI.

            Note: Copying of the structure elements might be
                  dangerous when array size of time elements differ
                  from MAX_VP_ABS_DIGIT due to changes in PSA
                  declaration.
*/
GLOBAL void cmhSMS_setVpabsCmh ( T_ACI_VP_ABS* cmhVp,
                                 T_tp_vp_abs*  psaVp )
{
  USHORT i; /* used for counting */
  SHORT tz;

  for (i = 0; i < MAX_VP_ABS_DIGITS; i++)
  {
    cmhVp -> year  [i] = psaVp -> year  [i];
    cmhVp -> month [i] = psaVp -> month [i];
    cmhVp -> day   [i] = psaVp -> day   [i];
    cmhVp -> hour  [i] = psaVp -> hour  [i];
    cmhVp -> minute[i] = psaVp -> minute[i];
    cmhVp -> second[i] = psaVp -> second[i];
  }

  tz = ((psaVp->tz_msb & 0x07) * 10) +  psaVp->tz_lsb;  /* BCD */

  if (psaVp->tz_sign)
    cmhVp -> timezone = -tz;
  else
    cmhVp -> timezone = tz;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_setVpenhCmh      |
+-------------------------------------------------------------------+

  PURPOSE : This function is used to copy the elements of the
            enhanced validity period structure of the PSA to the
            corresponding structure of the ACI.

*/
GLOBAL void cmhSMS_setVpenhCmh ( T_ACI_VP_ENH* cmhVp,
                                 T_tp_vp_enh*  psaVp )
{
  memset(cmhVp, 0, sizeof(T_ACI_VP_ENH));

  cmhVp->func_ind = psaVp->tvpf;

  if ((psaVp->tp_ext EQ SMS_EXT_INCLUDED) AND (psaVp->v_tp_rsrvd))
  {
    cmhVp->func_ind |= TP_VPF_ENH_EXT_BIT_MASK;
    cmhVp->ext_oct = psaVp->tp_rsrvd;
  }

  if (psaVp->tp_ss EQ SMS_SS_SET)
  {
    cmhVp->func_ind |= TP_VPF_ENH_SINGLE_SHOT_MASK;
  }

  if (psaVp->tvpf EQ SMS_TVPF_NOT_PRESENT)
  {
    /* do nothing */
  }
  else if ((psaVp->tvpf EQ SMS_TVPF_RELATIVE) AND (psaVp->v_tp_vp_rel))
  {
    cmhVp->val.vpenh_relative = psaVp->tp_vp_rel;
  }
  else if ((psaVp->tvpf EQ SMS_TVPF_SECONDS) AND (psaVp->v_tp_vp_sec))
  {
    cmhVp->val.vpenh_seconds = psaVp->tp_vp_sec;
  }
  else if (psaVp->tvpf EQ SMS_TVPF_HOURS)
  {
    if (psaVp->v_hour)
    {
      cmhVp->val.vpenh_hours.hour[0] = psaVp->hour[0];
      cmhVp->val.vpenh_hours.hour[1] = psaVp->hour[1];
    }
    if (psaVp->v_minute)
    {
      cmhVp->val.vpenh_hours.minute[0] = psaVp->minute[0];
      cmhVp->val.vpenh_hours.minute[1] = psaVp->minute[1];
    }
    if (psaVp->v_second)
    {
      cmhVp->val.vpenh_hours.second[0] = psaVp->second[0];
      cmhVp->val.vpenh_hours.second[1] = psaVp->second[1];
    }
  }
  else
  {
    TRACE_EVENT("[ERR] cmhSMS_setVpenhCmh: wrong type of validity period format");
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                 |
| STATE   : code                  ROUTINE : cmhSMS_getAdrStr         |
+--------------------------------------------------------------------+

  PURPOSE : This function is used to convert the service center
            address in BCD to the service center address as a string.
*/
GLOBAL UBYTE cmhSMS_getAdrStr ( CHAR*  pStr,
                                UBYTE  maxIdx,
                                UBYTE* pBcd,
                                UBYTE  numDigits )
{
  UBYTE bcdIdx;
  UBYTE strIdx = 0;

  memset(pStr, 0x00, maxIdx);

  for(bcdIdx = 0; bcdIdx < numDigits AND strIdx < maxIdx; bcdIdx++)
  {
    switch (pBcd[bcdIdx])
    {
      case 0:
      case 1:
      case 2:
      case 3:
      case 4:
      case 5:
      case 6:
      case 7:
      case 8:
      case 9:
        pStr[strIdx++] = pBcd[bcdIdx] + '0';
        break;

      case BCD_ASTSK:
        pStr[strIdx++] = '*';
        break;

      case BCD_PND:
        pStr[strIdx++] = '#';
        break;

      case BCD_A:
        pStr[strIdx++] = 'A';
        break;

      case BCD_B:
        pStr[strIdx++] = 'B';
        break;

      case BCD_C:
        pStr[strIdx++] = 'C';
        break;
    }
  }

  pStr[strIdx] = '\0';

  return ( strIdx );
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                 |
| STATE   : code                  ROUTINE : cmhSMS_getAdrBcd         |
+--------------------------------------------------------------------+

  PURPOSE : This function is used to convert the service center
            address as a string to the service center address in BCD.
*/
GLOBAL void cmhSMS_getAdrBcd ( UBYTE* pBcd,
                               UBYTE* pNumDigits,
                               UBYTE  maxDigits,
                               CHAR*  pStr )
{
  UBYTE bcdIdx = 0;
  UBYTE strIdx;

  for(strIdx = 0; bcdIdx < maxDigits AND pStr[strIdx] NEQ '\0'; strIdx++)
  {
    switch (pStr[strIdx])
    {
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        pBcd[bcdIdx++] = pStr[strIdx] - '0';
        break;

      case '*':
        pBcd[bcdIdx++] = BCD_ASTSK;
        break;

      case '#':
        pBcd[bcdIdx++] = BCD_PND;
        break;

      case 'A':
        pBcd[bcdIdx++] = BCD_A;
        break;

      case 'B':
        pBcd[bcdIdx++] = BCD_B;
        break;

      case 'C':
        pBcd[bcdIdx++] = BCD_C;
        break;
    }
  }

  *pNumDigits = bcdIdx;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                 |
| STATE   : code                  ROUTINE : cmhSMS_getAdrAlphaNum    |
+--------------------------------------------------------------------+

  PURPOSE : This function is used to pack the Alphanumeric 
  Destination Adress according to 23.038
*/
GLOBAL T_ACI_RETURN cmhSMS_packAlphaNumAddr( CHAR*          da, 
                                            T_tp_da*       da_addr)
{
  UBYTE dest[((MAX_SMS_ADDR_DIG/2) * 8) / 7];
  UBYTE dest_len;
  USHORT dalen;
  
  if( (da NEQ NULL) AND (da_addr NEQ NULL) )
  {
    dalen = strlen(da);
    
    dest_len = utl_cvt8To7( (UBYTE*)da, (UBYTE)dalen, dest, 0);
    
    if( dest_len > (MAX_SMS_ADDR_DIG/2) )
    {
      TRACE_EVENT("DA length is greater then the supported length");
      ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_UnknownErr );
      return(AT_FAIL);
    }
    if( ((dalen + 3) %7) <= 3 )
    {
      da_addr->c_num = (dest_len*2) - 1;  /* odd number of usefull nibbles */
    }
    else
    {
      da_addr->c_num = dest_len*2; /* even number of usefull nibbles */
    }
    
    cmh_unpackBCD(da_addr->num, dest, dest_len );
    da_addr->digits = da_addr->c_num;
  }
  
  return(AT_CMPL);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_getMemCmh        |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the preferred memory from
            PSA type to CMH type.
*/
GLOBAL void cmhSMS_getMemCmh ( UBYTE inMem, T_ACI_SMS_STOR* outMem )
{
  switch( inMem )
  {
    case( MEM_ME ): *outMem = SMS_STOR_Me; break;
    case( MEM_SM ): *outMem = SMS_STOR_Sm; break;
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_getMemPsa        |
+-------------------------------------------------------------------+

  PURPOSE : This function converts the preferred memory from
            CMH type to PSA type.

            returns: TRUE if conversion was successfull,
                     otherwise FALSE
*/
GLOBAL BOOL cmhSMS_getMemPsa ( T_ACI_SMS_STOR inMem, UBYTE* outMem )
{
  switch( inMem )
  {
    case( SMS_STOR_Me ): *outMem = MEM_ME; break;
    case( SMS_STOR_Sm ): *outMem = MEM_SM; break;
    default            : return ( FALSE );
  }

  return ( TRUE );
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CMH_SMSF                   |
| STATE   : code                ROUTINE : cmhSMS_getAlphabetPp       |
+--------------------------------------------------------------------+

  PURPOSE : This function is used to extract the used alphabet out
            of the data coding scheme for point-to-point SMS.
*/
GLOBAL UBYTE cmhSMS_getAlphabetPp ( UBYTE dcs )
{
  UBYTE alphabet = 0;  /* means 7 bit default alphabet */

  switch (dcs & 0xF0)
  {
    case( 0x30 ):
    case( 0x20 ):
      alphabet = 0x01; /* compressed, counts as 8 bit data */
      break;
    case( 0x10 ):
    case( 0x00 ):
      alphabet = (dcs & 0x0C) >> 2;
      if (alphabet EQ 3)
        alphabet = 0;  /* reserved coding */
      break;
    case( 0xE0 ):
      alphabet = 0x02; /* UCS2 */
      break;
    case( 0xF0 ):
      alphabet = (dcs & 0x04) >> 2;
      break;
  }

  return alphabet;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_expdSmsPp        |
+-------------------------------------------------------------------+

  PURPOSE : This function expands a point-to-point SMS from
            7 to 8 bit.
*/
GLOBAL void cmhSMS_expdSmsPp ( UBYTE  byte_offset,
                               UBYTE  dcs,
                               UBYTE* source,
                               UBYTE  source_len,
                               UBYTE* dest,
                               UBYTE* dest_len )
{
  UBYTE  alphabet;
  UBYTE  bit_offset = 0;

  TRACE_FUNCTION ("cmhSMS_expdSmsPp ()");


  alphabet = cmhSMS_getAlphabetPp ( dcs );

  switch (alphabet)
  {
    case( 0 ): /* 7 bit alphabet */

      if ( byte_offset % 7 NEQ 0 )
      {
         bit_offset = 7 - ((byte_offset*8) % 7);
      }

      *dest_len = source_len - ((byte_offset*8+6)/7); /* adjust byte_offset to septets */

      /* In 7-Bit mode we get number of septets but we need octets */
      source_len = (source_len*7+7)/8; /* round up to next octet*/
      source_len -= byte_offset;

      utl_cvt7To8 ( source, source_len, dest, bit_offset);
      

      break;

    default:   /* 8 bit alphabet, UCS2, reserved */

      *dest_len = source_len-byte_offset;
      memcpy ( (CHAR*) dest, (CHAR*)source, *dest_len );
      break;
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
| STATE   : code                  ROUTINE : cmhSMS_rdcSmsPp         |
+-------------------------------------------------------------------+

  PURPOSE : This function reduces a point-to-point SMS from
            8 to 7 bit.
*/
GLOBAL void cmhSMS_rdcSmsPp ( UBYTE  byte_offset,
                              UBYTE  dcs,
                              UBYTE* source,
                              UBYTE  source_len,
                              UBYTE* dest,
                              UBYTE* dest_len )
{
  UBYTE  data_len;
  UBYTE  alphabet;
  UBYTE  bit_offset = 0;

  TRACE_FUNCTION ("cmhSMS_rdcSmsPp ()");

  if (source_len EQ 0)
  {
    *dest_len = source_len;
    return;
  }

  alphabet = cmhSMS_getAlphabetPp ( dcs );

  switch (alphabet)
  {
    case( 0 ): /* 7 bit alphabet */

      if ( byte_offset % 7 NEQ 0 )
      {
         bit_offset = 7 - ((byte_offset*8) % 7);
      }

      data_len = MINIMUM (source_len, (SMS_MSG_LEN * 8) / 7);

      data_len = utl_cvt8To7 ( source, data_len, dest, bit_offset );
      break;

    default:   /* 8 bit alphabet, UCS2, reserved */
      data_len = MINIMUM ( source_len, SMS_MSG_LEN );

      memcpy ( ( CHAR * ) dest, ( CHAR * ) source, data_len );
      break;
  }

  *dest_len = data_len;
}
/* Implements Measure 25. This function is replaced by cmh_getAlphabetCb*/
/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CMH_SMSF                   |
| STATE   : code                ROUTINE : cmhSMS_expdSmsCb           |
+--------------------------------------------------------------------+

  PURPOSE : This function expands a cell broadcast SMS from
            7 to 8 bit.
*/
GLOBAL void cmhSMS_expdSmsCb ( UBYTE      dcs,
                               UBYTE     *source,
                               UBYTE      source_len,
                               UBYTE     *dest,
                               UBYTE     *dest_len )
{
  UBYTE  alphabet;

  TRACE_FUNCTION ("cmhSMS_expdSmsCb()");
  alphabet = cmh_getAlphabetCb ( dcs );

  switch (alphabet)
  {
    case( 0 ):  /* 7 bit alphabet */
/* PATCH Add bit_offset parameter to function cvt7To8 */
/*      utl_cvt7To8 ( source, source_len, dest ); */
      utl_cvt7To8 ( source, source_len, dest, 0);
/* PATCH END */

      *dest_len = ( source_len * 8 ) / 7;
      break;

    default: /* 8 bit alphabet, UCS2, reserved */
      memcpy ( ( CHAR * ) dest, ( CHAR * ) source, source_len );

      *dest_len = source_len;
      break;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CMH_SMSF                   |
| STATE   : code                ROUTINE : cmhSMS_setToaDef           |
+--------------------------------------------------------------------+

  PURPOSE : This function sets the type of address to default values
            (when the first character of address is '+' or the first
            two characters are '0' default is 145 otherwise default
            is 129)
*/
GLOBAL CHAR* cmhSMS_setToaDef ( CHAR*  number,
                                UBYTE* ntype,
                                UBYTE* nplan )
{
  *nplan = SMS_NPI_ISDN;

  if ( *number EQ '+' )
  {
    *ntype = SMS_TON_INTERNATIONAL;
    return number+1;
  }
  else
  {
    *ntype = SMS_TON_UNKNOWN;
    return number;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CMH_SMSF                   |
| STATE   : code                ROUTINE : cmhSMS_setTimezone         |
+--------------------------------------------------------------------+

  PURPOSE : Codes the timezone format used in entity SMS.

*/
GLOBAL UBYTE cmhSMS_setTimezone (SHORT timezone)
{
  UBYTE local_tz   = ( UBYTE ) timezone;
  BOOL  isNegative = ( local_tz & 0x80 );

  if ( isNegative )
    local_tz = ~local_tz + 1;

  local_tz = ( local_tz / 10 ) + ( ( local_tz % 10 ) << 4 );

  return ( ( isNegative ) ? local_tz | 0x08 : local_tz );
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CMH_SMSF                   |
| STATE   : code                ROUTINE : cmhSMS_getTimezone         |
+--------------------------------------------------------------------+

  PURPOSE : Decodes the timezone format used in entity SMS.

*/
GLOBAL SHORT cmhSMS_getTimezone (UBYTE timezone)
{
  signed char local_tz;

  local_tz = ( timezone & 0x07 ) * 10 + ( ( timezone & 0xF0 ) >> 4 );

  return ( SHORT ) (( timezone & 0x08 ) ? -local_tz : local_tz );
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CMH_SMSF                   |
| STATE   : code                ROUTINE : cmhSMS_setStorOcc          |
+--------------------------------------------------------------------+

  PURPOSE : Fills the T_ACI_SMS_STOR_OCC structure with data from the
            shared parameter buffer.

*/
GLOBAL void cmhSMS_setStorOcc  ( T_ACI_SMS_STOR_OCC* outMem,
                                 UBYTE               inMem   )
{
  cmhSMS_getMemCmh ( inMem, &outMem -> mem );

  if ( outMem -> mem EQ SMS_STOR_Sm )
  {
    outMem -> used  = smsShrdPrm.aci_sms_parameter.simUsed;
    outMem -> total = smsShrdPrm.aci_sms_parameter.simTotal;
  }
  else
  {
    outMem -> used  = smsShrdPrm.aci_sms_parameter.meUsed;
    outMem -> total = smsShrdPrm.aci_sms_parameter.meTotal;
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
|                                 ROUTINE : cmhSMS_GetCmsFromSim    |
+-------------------------------------------------------------------+

  PURPOSE : Mapping of SIM error code to ACI error code.

*/
GLOBAL T_ACI_CMS_ERR cmhSMS_GetCmsFromSim ( USHORT errCode )
{
  switch ( errCode )
  {
    case SIM_NO_ERROR:
      return CMS_ERR_NotPresent;

    case SIM_CAUSE_PIN1_EXPECT:
      return CMS_ERR_SimPinReq;

    case SIM_CAUSE_PIN2_EXPECT:
      return CMS_ERR_SimPin2Req;

    case SIM_CAUSE_PUK1_EXPECT:
    case SIM_CAUSE_PIN1_BLOCKED:
      return CMS_ERR_SimPukReq;

    case SIM_CAUSE_PUK2_EXPECT:
    case SIM_CAUSE_PIN2_BLOCKED:
      return CMS_ERR_SimPuk2Req;

    case SIM_CAUSE_PUK1_BLOCKED:
    case SIM_CAUSE_PUK2_BLOCKED:
      return CMS_ERR_SimWrong;

    case SIM_CAUSE_UNKN_FILE_ID:
    case SIM_CAUSE_DNL_ERROR:
      return CMS_ERR_UnknownErr;

    case SIM_CAUSE_EF_INVALID:
      return CMS_ERR_OpNotSup;

    case SIM_CAUSE_ADDR_WRONG:
      return CMS_ERR_InValMemIdx;

    case SIM_CAUSE_CMD_INCONSIST:
    case SIM_CAUSE_MAX_INCREASE:
    case SIM_CAUSE_CHV_NOTSET:
    case SIM_CAUSE_CHV_VALIDATED:
    case SIM_CAUSE_ACCESS_PROHIBIT:
      return CMS_ERR_OpNotAllowed;

    case SIM_CAUSE_CARD_REMOVED:
    case SIM_CAUSE_DRV_NOCARD:
      return CMS_ERR_SimNotIns;

    case SIM_CAUSE_NO_SELECT:
    case SIM_CAUSE_CLA_WRONG:
    case SIM_CAUSE_INS_WRONG:
    case SIM_CAUSE_P1P2_WRONG:
    case SIM_CAUSE_P3_WRONG:
    case SIM_CAUSE_PARAM_WRONG:
      return CMS_ERR_MeFail;

    case SIM_CAUSE_SAT_BUSY:
      return CMS_ERR_SimBsy;

    case SIM_CAUSE_DRV_TEMPFAIL:
      return CMS_ERR_SimFail;

    default:
      if (GET_CAUSE_DEFBY(errCode) EQ DEFBY_CONDAT AND
          GET_CAUSE_ORIGSIDE(errCode) EQ ORIGSIDE_MS)
      {
        return CMS_ERR_UnknownErr;
      }
      return CMS_ERR_UnknownErr;
  }
}



/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                |
|                                 ROUTINE : cmhSMS_GetCmsFromSms    |
+-------------------------------------------------------------------+

  PURPOSE : Mapping of SMS causes (MNSMS.doc) to ACI error code.

*/
GLOBAL T_ACI_CMS_ERR cmhSMS_GetCmsFromSms ( USHORT errCode )
{
  switch ( errCode )
  {
    case SMS_NO_ERROR:              /* No error                           */
      return CMS_ERR_NotPresent;

    case SMS_CAUSE_PARAM_WRONG:     /* Wrong parameter in primitive       */

    case SMS_CAUSE_ENTITY_BUSY:     /* Entity is busy                     */
      return CMS_ERR_SimBsy;

    case SMS_CAUSE_OPER_NOT_ALLW:   /* Operation not allowed              */
      return CMS_ERR_OpNotAllowed;

    case SMS_CAUSE_OPER_NOT_SUPP:   /* Operation not supported            */
      return CMS_ERR_OpNotSup;

    case SMS_CAUSE_SIM_BUSY:        /* SIM busy                           */
      return CMS_ERR_SimBsy;
    default:
      break;
  }
      
      /*
       *    The switch must be splitted because of a compiler bug
       *    - asm files can not compiled
       *
       *    TMS470 ANSI C Compiler       Version 1.22e
       *
       *    brz, 2004.02.14
       */
      
  switch(errCode) {
    case SMS_CAUSE_MEM_FAIL:        /* Memory failure                     */
      return CMS_ERR_MemFail;

    case SMS_CAUSE_INV_INDEX:       /* Invalid memory index               */
      return CMS_ERR_InValMemIdx;

    case SMS_CAUSE_MEM_FULL:        /* Memory full                        */
      return CMS_ERR_MemFull;

    case SMS_CAUSE_NO_SERVICE:      /* No network service                 */
      return CMS_ERR_NoNetServ;

    case SMS_CAUSE_NET_TIMEOUT:     /* Network timeout                    */
      return CMS_ERR_NetTimeOut;

    case SMS_CAUSE_UNEXP_CNMA:      /* No +CNMA acknowledgement expected  */
      return CMS_ERR_NoCnmaAckExpect;

    case SMS_CAUSE_OTHER_ERROR:     /* Any other error                    */
      return CMS_ERR_UnknownErr;

    default:
      return ((T_ACI_CMS_ERR) errCode); /* cmdCmsError(errCode) will figure out other error values from the first byte of the error code */
  }
}






/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_ready                 |
+-------------------------------------------------------------------+

  PURPOSE : This function notifies SMS_READY to all sources.
*/
GLOBAL void cmhSMS_ready ( void )
{
  int idx;
  T_opl_field * ptr_opl;

  TRACE_FUNCTION ("cmhSMS_ready()");

  {
    PALLOC (sim_sync_req, SIM_SYNC_REQ);
    sim_sync_req -> synccs = SYNC_MMI_FINISHED_READING;
    simShrdPrm.synCs = SYNC_MMI_FINISHED_READING;
    PSENDX (SIM, sim_sync_req);
  }

  smsShrdPrm.accessEnabled = TRUE;
  ptr_opl = cmhSIM_GetOPL();
  ptr_opl->opl_status = FALSE;

  cmhSIM_UpdateOperatorName(NOT_PRESENT_16BIT);  /* start EF_PNN and EF_OPL reading */

  pb_start_build(FALSE);     /* start phonebook reading, no guarantees */

  percentCSTAT_indication(STATE_MSG_SMS, ENTITY_STATUS_Ready);

  for( idx = 0; idx < CMD_SRC_MAX; idx++ )
  {
    R_AT( RAT_SMS_READY, (T_ACI_CMD_SRC)idx )();
  }

}


/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_disableAccess         |
+-------------------------------------------------------------------+

  PURPOSE : This function disables access to all SMS functions.
*/
GLOBAL void cmhSMS_disableAccess (void)
{
  smsShrdPrm.accessEnabled = FALSE;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_checkSIM              |
+-------------------------------------------------------------------+

  PURPOSE : This function checks if SMS is initialized. If not, the
            SIM state is checked. AN error code dependent of the
            SIM state is stored.
*/
GLOBAL BOOL cmhSMS_checkSIM (void)
{
  if (smsShrdPrm.accessEnabled)
    return TRUE;                /* SMS is accessible*/
  /*
   *-----------------------------------------------------------------
   * check SIM status
   *-----------------------------------------------------------------
   */

  switch (simShrdPrm.SIMStat)
  {
  case NO_VLD_SS:
    ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_SimNotIns );
    break;
  case SS_INV:
    ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_SimFail );
    break;
/*  case SS_BLKD: 
    ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_SimPukReq );
    break; */
  case SS_URCHB:
    ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_SimWrong );
    break;
  case SS_OK:
    switch (simShrdPrm.PINStat)
    {
      case PS_PIN1:
        ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_SimPinReq);
        break;

      case PS_PIN2:
        ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_SimPin2Req);
        break;

      case PS_PUK1:
        ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_SimPukReq);
        break;

      case PS_PUK2:
        ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_SimPuk2Req);
        break;

      default:
        ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_SimBsy );
        break;
    }
    break;
  default:
    ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_SimBsy );
    break;
  }
  return FALSE;
}
/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_checkAccess           |
+-------------------------------------------------------------------+

  PURPOSE : This function checks if SMS is accessible. If an error
            condition is found, then *ret is set to either AT_FAIL or
            AT_BUSY, otherwise it remains unaffected. The error code
            is stored.
*/
GLOBAL BOOL cmhSMS_checkAccess (T_ACI_CMD_SRC srcId,
                                T_ACI_RETURN *ret)
{
  /*
   *-----------------------------------------------------------------
   * check command source
   *-----------------------------------------------------------------
   */
  if(srcId NEQ (T_ACI_CMD_SRC)OWN_SRC_SAT)
  {
    if(!cmh_IsVldCmdSrc (srcId))
    {
    TRACE_ERROR ("[cmhSMS_checkAccess]: Cmd Src not valid");
    *ret = AT_FAIL;
    return FALSE;
  }
  }
  /*
   *-----------------------------------------------------------------
   * check entity status
   *-----------------------------------------------------------------
   */
  if( smsShrdPrm.smsEntStat.curCmd NEQ AT_CMD_NONE )
  {
    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Internal );
    TRACE_ERROR ("[cmhSMS_checkAccess]: Entity is busy");
    *ret = AT_BUSY;
    return FALSE;
  }

  /*
   *-----------------------------------------------------------------
   * check SMS access status
   *-----------------------------------------------------------------
   */
  if (cmhSMS_checkSIM ())
    return TRUE;

  TRACE_ERROR ("[cmhSMS_checkAccess]: Wrong SIM status");

  *ret = AT_FAIL;
  return FALSE;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_getPrfRge             |
+-------------------------------------------------------------------+

  PURPOSE : This function gets the number of available profiles for
            SMS related parameters. First, the SIM is checked. If
            there is no space, then PCM ist checked.
*/
GLOBAL SHORT cmhSMS_getPrfRge ( void )
{
  /* TEMPORARY, ONLY FOR TEST PURPOSES: Pretend that the SIM has no SMSP !!! */
  /* smsShrdPrm.aci_sms_parameter.smsParamMaxRec = 0;*/

  if (smsShrdPrm.aci_sms_parameter.smsParamMaxRec > 0)
  {
    return (SHORT)smsShrdPrm.aci_sms_parameter.smsParamMaxRec;
  }
  else
  {
    return (MAX_FFS_SMSPRFLS);
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_ReadPrmFFS            |
+-------------------------------------------------------------------+

  PURPOSE : This function reads one record of EF_SMSPRFL_ID from FFS.
            The processed parameters are controlled by bits in
            'access'.
*/
static T_ACI_RETURN cmhSMS_ReadPrmFFS (T_ACI_CMD_SRC  srcId,
                                       SHORT          recNr,
                                       int            access)
{
  T_SMS_SET_PRM     *pSMSSetPrm;  /* points to SMS parameter set */
  int               i;
  T_SMS_SET_PRM     *elem;
  T_ACI_FFS_SMSPRFL smsPrfl;
#ifndef _SIMULATION_
  T_FFS_SIZE        ffs_size;
#endif

  TRACE_FUNCTION ("cmhSMS_ReadPrmFFS()");

#ifdef _SIMULATION_
  smsPrfl.vldFlag = FFS_SMSPRFL_INVLD;          /* trigger a failure since nothing can be read in simulation */
#else
  ffs_size = FFS_fread(ffs_smsprfl_fname[recNr-1], (void*)&smsPrfl, SIZE_FSS_SMSPRFL);
  /*
    Don't check FFS return for only specif ERRORS, as ACI will not know what 
    ERROR FFS may send. So, it's walyws better to check for ERROR OK
    i.e EFFS_OK  Considering this in mind the below condition is changes to 
    do the same.
  */
  if ( ffs_size < EFFS_OK )
  {
    TRACE_EVENT_P1("error when reading FFS object \"%s\"", ffs_smsprfl_fname[recNr-1]);
    ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_MemFail );
    return AT_FAIL;
  }
#endif

  if ( smsPrfl.vldFlag EQ FFS_SMSPRFL_INVLD )
  {
    ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_OpNotAllowed );
    return AT_FAIL;
  }

  if (access & ACI_PCM_ACCESS_SMSP)
  {
    if (srcId >= CMD_SRC_MAX)
    {
      ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_UnknownErr );
      return AT_FAIL;
    }
    else
    {
      if (set_prm_list EQ NULL)
      {
        set_prm_list = new_list();
      }

      elem = find_element(set_prm_list, (UBYTE)recNr, cmhSMS_findPrflId);
      if (elem EQ NULL)
      {
        ACI_MALLOC(elem, sizeof(T_SMS_SET_PRM));
        memset(elem, 0, sizeof(T_SMS_SET_PRM));
        insert_list(set_prm_list, elem);
      }
      if (srcId <= CMD_SRC_NONE)
      {
        elem->numOfRefs = OWN_SRC_MAX;
        for (i=0; i < OWN_SRC_MAX; i++)
        {
          smsShrdPrm.pSetPrm[i] = (T_SMS_SET_PRM*) elem;
        }
      }
      else
      {
        smsShrdPrm.pSetPrm[srcId] = (T_SMS_SET_PRM*) elem;
        (smsShrdPrm.pSetPrm[srcId])->numOfRefs++;
      }
    }

    pSMSSetPrm = (T_SMS_SET_PRM*) elem;
    pSMSSetPrm->prflId = (UBYTE)recNr;

#ifndef _SIMULATION_
    /*
     *-------------------------------------------------------------
     * restore the service center address
     *-------------------------------------------------------------
     */
    pSMSSetPrm->sca.c_num = MINIMUM (smsPrfl.CSCAlenSca, MAX_SMS_ADDR_DIG);
    memcpy ( pSMSSetPrm->sca.num, smsPrfl.CSCAsca, pSMSSetPrm->sca.c_num);
    pSMSSetPrm->sca.ton = smsPrfl.CSCAton;
    pSMSSetPrm->sca.npi = smsPrfl.CSCAnpi;
    pSMSSetPrm->sca.v_ton = TRUE;
    pSMSSetPrm->sca.v_npi = TRUE;

    /*
     *-------------------------------------------------------------
     * restore the text mode parameters
     *-------------------------------------------------------------
     */
    pSMSSetPrm->vpRel = smsPrfl.CSMPvprel;
    memcpy ( &pSMSSetPrm->vpAbs, smsPrfl.CSMPvpabs, SIZE_FFS_SMSPRFL_VPABS );
    memcpy ( &pSMSSetPrm->vpEnh, smsPrfl.CSMPvpenh, SIZE_FFS_SMSPRFL_VPENH );

    pSMSSetPrm->msgType = smsPrfl.CSMPfo;
    pSMSSetPrm->pid = smsPrfl.CSMPpid;
    pSMSSetPrm->dcs = smsPrfl.CSMPdcs;
#endif
  }

#ifndef _SIMULATION_
  if (access & ACI_PCM_ACCESS_CBMP)
  {
      /*
       *-------------------------------------------------------------
       * restore the cell broadcast message types and data coding
       * schemes
       *-------------------------------------------------------------
       */
      smsShrdPrm.cbmPrm.cbmMode = smsPrfl.CSCBmode;

      {                         /* default setting */
        memset (smsShrdPrm.cbmPrm.msgId, DEF_MID_RANGE, sizeof (smsShrdPrm.cbmPrm.msgId));
        memset (smsShrdPrm.cbmPrm.dcsId, DEF_DCS_RANGE, sizeof(smsShrdPrm.cbmPrm.dcsId));
      }

      for ( i = 0; i < MINIMUM(MAX_IDENTS,SIZE_FFS_SMSPRFL_MIDS/2); i++ )
      {
        smsShrdPrm.cbmPrm.msgId[i]  = ( USHORT )smsPrfl.CSCBmids[2*i] << 8;
        smsShrdPrm.cbmPrm.msgId[i] |= ( USHORT )smsPrfl.CSCBmids[2*i+1];
      }

      memcpy ( smsShrdPrm.cbmPrm.dcsId, smsPrfl.CSCBdcss,
               MINIMUM(MAX_IDENTS,SIZE_FFS_SMSPRFL_DCSS) );

      memcpy (smsShrdPrm.cbmPrm.IMSI, smsPrfl.IMSI, MAX_IMSI);
  }
#endif
  return AT_CMPL;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_WritePrmFFS           |
+-------------------------------------------------------------------+

  PURPOSE : This function writes one record of EF_SMSPRFL_ID to FFS.
            The processed parameters are controlled by bits in
            'access'.
*/
static T_ACI_RETURN cmhSMS_WritePrmFFS (T_ACI_CMD_SRC  srcId,
                                        SHORT          recNr,
                                        int            access)
{
  T_SMS_SET_PRM     *pSMSSetPrm;  /* points to SMS parameter set */
  T_ACI_FFS_SMSPRFL smsPrfl;
  int               i;
#ifndef _SIMULATION_
  T_FFS_RET         ffs_ret;
#endif

  TRACE_FUNCTION ("cmhSMS_WritePrmFFS()");

  if (access & ACI_PCM_ACCESS_SMSP)
  {
    if (srcId > CMD_SRC_NONE AND srcId < CMD_SRC_MAX)
    {
      pSMSSetPrm = smsShrdPrm.pSetPrm[srcId];

      /*
       *-------------------------------------------------------------
       * save the service center address
       *-------------------------------------------------------------
       */
      smsPrfl.CSCAlenSca = MINIMUM ( pSMSSetPrm->sca.c_num, SIZE_FFS_SMSPRFL_SCA );
      memcpy ( smsPrfl.CSCAsca, pSMSSetPrm->sca.num, smsPrfl.CSCAlenSca );

      i = (int)smsPrfl.CSCAlenSca;
      while ( i < SIZE_FFS_SMSPRFL_SCA )
        smsPrfl.CSCAsca[i++] = 0xFF;

      smsPrfl.CSCAton = pSMSSetPrm->sca.ton;
      smsPrfl.CSCAnpi = pSMSSetPrm->sca.npi;

      /*
       *-------------------------------------------------------------
       * store the text mode parameters
       *-------------------------------------------------------------
       */
      smsPrfl.CSMPfo    = pSMSSetPrm->msgType;

      smsPrfl.CSMPvprel = pSMSSetPrm->vpRel;
      memcpy ( smsPrfl.CSMPvpabs, &pSMSSetPrm->vpAbs, SIZE_FFS_SMSPRFL_VPABS );
      memcpy ( smsPrfl.CSMPvpenh, &pSMSSetPrm->vpEnh, SIZE_FFS_SMSPRFL_VPENH );

      smsPrfl.CSMPpid   = pSMSSetPrm->pid;
      smsPrfl.CSMPdcs   = pSMSSetPrm->dcs;

      /*
       *-------------------------------------------------------------
       * set the valid flag
       *-------------------------------------------------------------
       */
      smsPrfl.vldFlag = FFS_SMSPRFL_VLD;
    }
    else
    {
      ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_UnknownErr );
      return AT_FAIL;
    }
  }
  if (access & ACI_PCM_ACCESS_CBMP)
  {
      /*
       *-------------------------------------------------------------
       * save the cell broadcast message types
       *-------------------------------------------------------------
       */
      smsPrfl.CSCBmode = smsShrdPrm.cbmPrm.cbmMode;

      {                         /* default setting */
        memset (smsPrfl.CSCBmids, 0xFF, sizeof(smsPrfl.CSCBmids));
        memset (smsPrfl.CSCBdcss, 0xFF, sizeof(smsPrfl.CSCBdcss));
      }

      for ( i = 0; i < MINIMUM(MAX_IDENTS*2,SIZE_FFS_SMSPRFL_MIDS)-1; i += 2 )
      {
        smsPrfl.CSCBmids[i]   = (UBYTE)(smsShrdPrm.cbmPrm.msgId[i/2] >> 8);
        smsPrfl.CSCBmids[i+1] = (UBYTE)smsShrdPrm.cbmPrm.msgId[i/2];
      }

      memcpy ( smsPrfl.CSCBdcss, smsShrdPrm.cbmPrm.dcsId,
               MINIMUM(MAX_IDENTS,SIZE_FFS_SMSPRFL_DCSS) );

      /*
       * Save IMSI also in FFS 
       */
      memcpy (smsPrfl.IMSI, simShrdPrm.imsi.field, simShrdPrm.imsi.c_field);
      smsPrfl.vldFlag = FFS_SMSPRFL_VLD;
  }

#ifndef _SIMULATION_
  ffs_ret = FFS_mkdir(FFS_SMSPRFL_PATH);
  if (ffs_ret EQ EFFS_OK)
  {
    TRACE_EVENT_P1("FFS directory \"%s\" successfully created", FFS_SMSPRFL_PATH);
  }
  else if (ffs_ret EQ EFFS_EXISTS)
  {
    TRACE_EVENT_P1("FFS directory \"%s\" already exists", FFS_SMSPRFL_PATH);
  }
  else
  {
    TRACE_EVENT_P1("error when creating FFS directory \"%s\"", FFS_SMSPRFL_PATH);
  }

  ffs_ret = FFS_fwrite(ffs_smsprfl_fname[recNr-1], (void*)&smsPrfl, SIZE_FSS_SMSPRFL);
  if (ffs_ret NEQ EFFS_OK)
  {
    ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_MemFail );
    TRACE_EVENT_P1("error when writing FFS object \"%s\"", ffs_smsprfl_fname[recNr-1]);
    return AT_FAIL;
  }
#endif

  return AT_CMPL;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_ReadParams            |
+-------------------------------------------------------------------+

  PURPOSE : This function reads parameters from SIM and/or PCM.
            In case of AT command +CFUN the first record is read to
            be informed about storage capability of SIM.
*/
GLOBAL T_ACI_RETURN cmhSMS_ReadParams (T_ACI_CMD_SRC  srcId,
                                       T_ACI_AT_CMD   cmd,
                                       SHORT          recNr)
{
  T_ACI_RETURN ret = AT_CMPL;
  int access = 0;
  
  TRACE_FUNCTION ("cmhSMS_ReadParams()");

  smsShrdPrm.smsEntStat.curCmd = cmd;
  smsShrdPrm.owner = (T_OWN)srcId; 
  smsShrdPrm.smsEntStat.entOwn = srcId;


  if (cmd EQ AT_CMD_CFUN)
  {  
    /* initialization */
  
   /*
    * Always read CSCB params from FFS so that previously stored mode and dcss
    *  can also be restored from FFS
    */
    access |= ACI_PCM_ACCESS_CBMP;
    /*if (!psaSIM_ChkSIMSrvSup( SRV_SMS_Parms ))*/
    access |= ACI_PCM_ACCESS_SMSP;

      ret = cmhSMS_ReadPrmFFS (CMD_SRC_NONE, 1, access);

    if (psaSIM_ChkSIMSrvSup( SRV_SMS_Parms ))
    {
      smsShrdPrm.prmRdSeq = SMS_READ_SIM_SMSP;
      ret = cmhSIM_ReadRecordEF (CMD_SRC_NONE, cmd, FALSE, NULL,
                                  SIM_SMSP, 1, 255,
                                  NULL, cmhSMS_InitSMSP);
    }
    else if (psaSIM_ChkSIMSrvSup( SRV_CBMIdRnge ))
    {
      smsShrdPrm.prmRdSeq = SMS_READ_SIM_CBMIR;
      ret = cmhSIM_ReadTranspEF (CMD_SRC_NONE, cmd, FALSE, NULL,
                                  SIM_CBMIR, 0, 255,
                                  NULL, cmhSMS_InitSMSP);
    }
    else if (psaSIM_ChkSIMSrvSup( SRV_CBM_Ident ))
    {
      smsShrdPrm.prmRdSeq = SMS_READ_SIM_CBMI;
      ret = cmhSIM_ReadTranspEF (CMD_SRC_NONE, cmd, FALSE, NULL,
                                  SIM_CBMI, 0, 255,
                                  NULL, cmhSMS_InitSMSP);
    }
#ifdef SIM_TOOLKIT
    else if ((psaSIM_ChkSIMSrvSup( SRV_DtaDownlCB )) AND 
             smsShrdPrm.owner EQ OWN_SRC_SAT )
    {
      smsShrdPrm.prmRdSeq = SMS_READ_SIM_CBMID;
      ret = cmhSIM_ReadTranspEF (CMD_SRC_NONE, cmd, FALSE, NULL,
                                  SIM_CBMID, 0, 255,
                                  NULL, cmhSMS_InitSMSP);
    }
#endif /* of SIM_TOOLKIT */
  }
  else
  {

    /* TEMPORARY, ONLY FOR TEST PURPOSES: Pretend that the SIM has no SMSP !!! */
    /* smsShrdPrm.aci_sms_parameter.smsParamMaxRec = 0; */
    
    /*
     * Always read CSCB params from FFS so that previously stored mode and dcss
     *  can also be restored from FFS
     */
    /* normal operation */
    access |= ACI_PCM_ACCESS_CBMP;
   /* if (smsShrdPrm.aci_sms_parameter.smsParamMaxRec EQ 0)*/
      access |= ACI_PCM_ACCESS_SMSP;
      ret = cmhSMS_ReadPrmFFS (srcId, recNr, access);

    if (smsShrdPrm.aci_sms_parameter.smsParamMaxRec > 0)
    {
      if (recNr <= 0
          OR recNr > (SHORT)smsShrdPrm.aci_sms_parameter.smsParamMaxRec)
      {
        ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_InValMemIdx );
        ret= AT_FAIL;
      }
      else
      {
        smsShrdPrm.prmRdSeq = SMS_READ_SIM_SMSP;
        return cmhSIM_ReadRecordEF (CMD_SRC_NONE, cmd, FALSE, NULL, SIM_SMSP,
                                    (UBYTE)(recNr),
                                    smsShrdPrm.aci_sms_parameter.smsParamRecLen,
                                    NULL, cmhSMS_RdCnfCRES);
      }
    }
    if (smsShrdPrm.cbmPrm.cbmSIMmaxIdRge > 0)
    {
      smsShrdPrm.prmRdSeq = SMS_READ_SIM_CBMIR;
      return cmhSIM_ReadTranspEF (CMD_SRC_NONE, cmd, FALSE, NULL, SIM_CBMIR,
                                  0, smsShrdPrm.cbmPrm.cbmSIMmaxIdRge,
                                  NULL, cmhSMS_RdCnfCRES);
    }
    if (smsShrdPrm.cbmPrm.cbmSIMmaxId > 0)
    { 
      smsShrdPrm.prmRdSeq = SMS_READ_SIM_CBMI;
      return cmhSIM_ReadTranspEF (CMD_SRC_NONE, cmd, FALSE, NULL, SIM_CBMI,
                                  0, smsShrdPrm.cbmPrm.cbmSIMmaxId,
                                  NULL, cmhSMS_RdCnfCRES);
    }
  }
  if (ret NEQ AT_EXCT)
  {
    smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE;
    smsShrdPrm.owner             = (T_OWN)CMD_SRC_NONE;
    smsShrdPrm.smsEntStat.entOwn =CMD_SRC_NONE;

    smsShrdPrm.cbmPrm.cbchOwner = (T_OWN)srcId;
    psaMMI_Cbch();
    smsShrdPrm.cbmPrm.cbchOwner = (T_OWN)CMD_SRC_NONE;
  }
  return ret;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_WriteParams           |
+-------------------------------------------------------------------+

  PURPOSE : This function reads parameters from SIM and/or PCM.
            In case of AT command +CFUN the first record is read to
            be informed about storage capability of SIM.
*/
GLOBAL T_ACI_RETURN cmhSMS_WriteParams (T_ACI_CMD_SRC  srcId,
                                        T_ACI_AT_CMD   cmd,
                                        SHORT          recNr)
{
  T_ACI_RETURN ret = AT_CMPL;
  int access = 0;
  UBYTE data[MAX_SIM_CMD];

  TRACE_FUNCTION ("cmhSMS_WriteParams()");

  smsShrdPrm.smsEntStat.curCmd = cmd;
  smsShrdPrm.owner = (T_OWN)srcId;
  smsShrdPrm.smsEntStat.entOwn = srcId;

  /* TEMPORARY, ONLY FOR TEST PURPOSES: Pretend that the SIM has no SMSP !!! */
  /* smsShrdPrm.aci_sms_parameter.smsParamMaxRec = 0; */

  /*
   * Always write CSCB params to FFS so that mode and dcss
   *  can later be restored from FFS
   */
  access |= ACI_PCM_ACCESS_CBMP;
  /*if (smsShrdPrm.aci_sms_parameter.smsParamMaxRec EQ 0)*/
    access |= ACI_PCM_ACCESS_SMSP;

    ret = cmhSMS_WritePrmFFS (srcId, recNr, access);

  if (smsShrdPrm.aci_sms_parameter.smsParamMaxRec > 0)
  {
    if (recNr <= 0 OR recNr > (SHORT)smsShrdPrm.aci_sms_parameter.smsParamMaxRec)
    {
      ACI_ERR_DESC( ACI_ERR_CLASS_Cms, CMS_ERR_InValMemIdx );
      ret= AT_FAIL;
    }
    else
    {
      smsShrdPrm.prmRdSeq = SMS_READ_SIM_SMSP;
      cmhSMS_PutPrmSIM (srcId, data,
                        (int)smsShrdPrm.aci_sms_parameter.smsParamRecLen);
      return cmhSIM_WriteRecordEF (CMD_SRC_NONE, cmd, FALSE, NULL, SIM_SMSP,
                                   (UBYTE)(recNr),
                                   smsShrdPrm.aci_sms_parameter.smsParamRecLen,
                                   data, cmhSMS_WrCnfCSAS);
    }
  }
  if (smsShrdPrm.cbmPrm.cbmSIMmaxIdRge > 0)
  {
    smsShrdPrm.prmRdSeq = SMS_READ_SIM_CBMIR;
    cmhSMS_PutCbmirSIM (srcId, data,
                        (int)smsShrdPrm.cbmPrm.cbmSIMmaxIdRge * 4);

    return cmhSIM_WriteTranspEF (CMD_SRC_NONE, cmd, FALSE, NULL, SIM_CBMIR,
                                 0, (UBYTE)(smsShrdPrm.cbmPrm.cbmSIMmaxIdRge * 4),
                                 data, cmhSMS_WrCnfCSAS);
  }
  if (smsShrdPrm.cbmPrm.cbmSIMmaxId > 0)
  {
    smsShrdPrm.prmRdSeq = SMS_READ_SIM_CBMI;
    cmhSMS_PutCbmiSIM (srcId, data,
                       (int)smsShrdPrm.cbmPrm.cbmSIMmaxId * 2);
    
    return cmhSIM_WriteTranspEF (CMD_SRC_NONE, cmd, FALSE, NULL, SIM_CBMI,
                                 0, (UBYTE)(smsShrdPrm.cbmPrm.cbmSIMmaxId * 2),
                                 data, cmhSMS_WrCnfCSAS);
  }
  if (ret NEQ AT_EXCT)
  {
    smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE;
    smsShrdPrm.owner             = (T_OWN)CMD_SRC_NONE;
    smsShrdPrm.smsEntStat.entOwn = CMD_SRC_NONE;
  }
  return ret;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_GetPrmSIM             |
+-------------------------------------------------------------------+

  PURPOSE : This function extracts the parameters of one record of
            EF(SMSP) read from SIM.
*/
GLOBAL BOOL cmhSMS_GetPrmSIM (T_ACI_CMD_SRC srcId,
                              UBYTE         *data,
                              int           dataLen)
{
  T_SMS_SET_PRM *pSMSSetPrm;    /* points to SMS parameter set */
  T_ACI_SMS_SIM_PARAMS *smsprm;

  TRACE_FUNCTION ("cmhSMS_GetPrmSIM ()");

  if (data NEQ NULL)
  {    
    pSMSSetPrm = smsShrdPrm.pSetPrm[srcId];
    
    smsprm = (T_ACI_SMS_SIM_PARAMS *)&data[(dataLen <= MIN_SMS_PRM_LEN)?
                                            0: dataLen - MIN_SMS_PRM_LEN];

    if (smsprm->par_ind EQ NOT_PRESENT_8BIT)
    {
    
      /* ACI-SPR-16431: reset sca number */
      pSMSSetPrm->sca.c_num = 0;
      memset(pSMSSetPrm->sca.num, 0xFF, sizeof(pSMSSetPrm->sca.num)); 
      /* end of ACI-SPR-16431: reset sca number */
      
      return TRUE;              /* record is empty */
    }

    if ((smsprm->par_ind & SIM_SMSP_V_SCA) EQ 0)
    {
       cmh_demergeTOA (smsprm->sca_ton_npi, &pSMSSetPrm->sca.ton,
                      &pSMSSetPrm->sca.npi);
      pSMSSetPrm->sca.c_num = (UBYTE)cmh_unpackBCD (pSMSSetPrm->sca.num,
                                                     smsprm->sca_addr,
                                                     (USHORT)(smsprm->sca_length - 1));
      pSMSSetPrm->sca.v_ton = TRUE;
      pSMSSetPrm->sca.v_npi = TRUE;

    }
    if ((smsprm->par_ind & SIM_SMSP_V_PID) EQ 0)
      pSMSSetPrm->pid = smsprm->pid;

    if ((smsprm->par_ind & SIM_SMSP_V_DCS) EQ 0)
      pSMSSetPrm->dcs = smsprm->dcs;

    if ((smsprm->par_ind & SIM_SMSP_V_VPREL) EQ 0)
    {
      pSMSSetPrm->vpRel = smsprm->vp_rel;
      pSMSSetPrm->msgType &= ~TP_VPF_MASK;
      pSMSSetPrm->msgType |= TP_VPF_RELATIVE;
    }
    else if ((pSMSSetPrm->msgType & TP_VPF_MASK) EQ TP_VPF_RELATIVE)
      pSMSSetPrm->msgType &= ~TP_VPF_MASK;

    return TRUE;
  }
  return FALSE;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_PutPrmSIM             |
+-------------------------------------------------------------------+

  PURPOSE : This function conbiness the parameters for one record of
            EF(SMSP) to be written to SIM.
*/
GLOBAL BOOL cmhSMS_PutPrmSIM (T_ACI_CMD_SRC srcId,
                              UBYTE         *data,
                              int           maxDataLen)
{
  T_SMS_SET_PRM *pSMSSetPrm;    /* points to SMS parameter set */
  T_ACI_SMS_SIM_PARAMS *smsprm;
  size_t datalen;

  TRACE_FUNCTION ("cmhSMS_PutPrmSIM ()");

  if (data NEQ NULL)
  {
    pSMSSetPrm = smsShrdPrm.pSetPrm[srcId];

    if (maxDataLen < MIN_SMS_PRM_LEN)
    {
      datalen = MIN_SMS_PRM_LEN;
      smsprm = (T_ACI_SMS_SIM_PARAMS *)data;
    }
    else
    {
      datalen = (size_t)maxDataLen;
      smsprm = (T_ACI_SMS_SIM_PARAMS *)&data[datalen - MIN_SMS_PRM_LEN];
    }
    memset (data, NOT_PRESENT_8BIT, datalen);

  /*
   *-------------------------------------------------------------
   * set the service center address
   *-------------------------------------------------------------
   */
    if (pSMSSetPrm->sca.c_num > 0)
    {
      smsprm->sca_ton_npi = cmh_mergeTOA (pSMSSetPrm->sca.ton,
                                          pSMSSetPrm->sca.npi);
      smsprm->sca_length = (UBYTE)cmh_packBCD (smsprm->sca_addr,
                                               pSMSSetPrm->sca.num,
                                               (USHORT)MINIMUM(pSMSSetPrm->sca.c_num,
                                                MAX_SMS_ADDR_DIG)) + 1;
      smsprm->par_ind &= ~SIM_SMSP_V_SCA;
    }

  /*
   *-------------------------------------------------------------
   * set PID, DCS and VP-REL
   *-------------------------------------------------------------
   */

    smsprm->pid = pSMSSetPrm->pid;
    smsprm->par_ind &= ~SIM_SMSP_V_PID;

    smsprm->dcs = pSMSSetPrm->dcs;
    smsprm->par_ind &= ~SIM_SMSP_V_DCS;

    if ((pSMSSetPrm->msgType & TP_VPF_MASK) EQ TP_VPF_RELATIVE)
    {
      smsprm->vp_rel = pSMSSetPrm->vpRel;
      smsprm->par_ind &= ~SIM_SMSP_V_VPREL;
    }
    return TRUE;
  }
  return FALSE;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_GetCbmirSIM           |
+-------------------------------------------------------------------+

  PURPOSE : This function extracts the parameters of EF(CBMIR)
            read from SIM.
*/
GLOBAL BOOL cmhSMS_GetCbmirSIM (T_ACI_CMD_SRC srcId,
                                UBYTE         *data,
                                int           dataLen)
{
  T_ACI_CBM_SIM_MID_RANGE *mid_range;
  USHORT lower_mid, upper_mid;
  int mid_entry;

  TRACE_FUNCTION ("cmhSMS_GetCbmirSIM ()");

  if (data NEQ NULL)
  {
/* Please be aware that to keep simulation test cases as less changed as 
   possible lets assume that IMSI and CBMs stored in the FFS and from SIM 
   card are the same, since we cannot access  FFS under SIMULATION*/
#ifndef _SIMULATION_
    /*
     * The CSCB parameters read from FFS should be restored only if the same SIM
     * is inserted ( check IMSI to ensure the same SIM), otherwise reset the CSCB
     * parameters to default values
     */
    if (memcmp (smsShrdPrm.cbmPrm.IMSI, simShrdPrm.imsi.field, simShrdPrm.imsi.c_field) NEQ 0)
    {
    /* Implements Measure # 9 */
      cmhSMS_clearCbmPrm();     
      return FALSE;
    }
#endif
    mid_range = (T_ACI_CBM_SIM_MID_RANGE *)data;
    mid_entry = 0;

    while (smsShrdPrm.cbmPrm.cbmFoundIds < MAX_IDENTS/2 AND
           mid_entry < dataLen)
    {
      lower_mid = (USHORT)mid_range->lowerLSB |
                  ((USHORT)mid_range->lowerMSB << 8);
      upper_mid = (USHORT)mid_range->upperLSB |
                  ((USHORT)mid_range->upperMSB << 8);
      mid_range++;
      mid_entry += 4;

      if (lower_mid NEQ NOT_PRESENT_16BIT OR
          upper_mid NEQ NOT_PRESENT_16BIT)
      {
/* Please be aware that to keep simulation test cases as less changed as 
   possible lets assume that  CBMs stored in the FFS and from SIM 
   card are the same, since we cannot access  FFS under SIMULATION*/
#ifndef _SIMULATION_
   
        /* Implements Measure # 73 */ 
        if (!cmhSMS_findMessageIds (lower_mid, upper_mid))
        {
          return FALSE;
        }

#else /* Just for simulation - copy data, received from SIM */
      smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2] = lower_mid;
      smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2 + 1] = upper_mid;
      smsShrdPrm.cbmPrm.cbmFoundIds++;
#endif
      }
    }
    return TRUE;
  }
  return FALSE;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_PutCbmirSIM           |
+-------------------------------------------------------------------+

  PURPOSE : This function conbines the parameters of EF(CBMIR)
            to be written to SIM.
*/
GLOBAL BOOL cmhSMS_PutCbmirSIM (T_ACI_CMD_SRC srcId,
                                UBYTE         *data,
                                int           maxDataLen)
{
  T_ACI_CBM_SIM_MID_RANGE *mid_range;
  USHORT lower_mid, upper_mid;
  int mid_entry;

  TRACE_FUNCTION ("cmhSMS_PutCbmirSIM ()");

  if (data NEQ NULL)
  {
    memset (data, NOT_PRESENT_8BIT, maxDataLen);

    mid_range = (T_ACI_CBM_SIM_MID_RANGE *)data;
    mid_entry = 0;

    while (smsShrdPrm.cbmPrm.cbmFoundIds < MAX_IDENTS/2 AND
           mid_entry < maxDataLen)
    {
      lower_mid = smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2];
      upper_mid = smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2 + 1];
      smsShrdPrm.cbmPrm.cbmFoundIds++;

      if (lower_mid NEQ NOT_PRESENT_16BIT OR
          upper_mid NEQ NOT_PRESENT_16BIT)
      {
        mid_range->lowerLSB = (UBYTE)lower_mid;
        mid_range->lowerMSB = (UBYTE)(lower_mid >> 8);
        mid_range->upperLSB = (UBYTE)upper_mid;
        mid_range->upperMSB = (UBYTE)(upper_mid >> 8);
        mid_range++;
        mid_entry += 4;
      }
    }
    return TRUE;
  }
  return FALSE;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_GetCbmiSIM            |
+-------------------------------------------------------------------+

  PURPOSE : This function extracts the parameters of one record of
            EF(SMSP) read from SIM.
*/
GLOBAL BOOL cmhSMS_GetCbmiSIM  (T_ACI_CMD_SRC srcId,
                                UBYTE         *data,
                                int           dataLen)
{
  T_ACI_CBM_SIM_MID_LIST **mid_list;
  USHORT mid;
  int mid_entry;

  TRACE_FUNCTION ("cmhSMS_GetCbmiSIM ()");

  if (data NEQ NULL)
  {

  /* Please be aware that to keep simulation test cases as less changed as 
   possible lets assume that IMSI and CBMs stored in the FFS and from SIM 
   card are the same, since we cannot access  FFS under SIMULATION*/
#ifndef _SIMULATION_
    /*
     * The CSCB parameters read from FFS should be restored only if the same SIM
     * is inserted ( check IMSI to ensure the same SIM), otherwise reset the CSCB
     * parameters to default values
     */
    if (memcmp (smsShrdPrm.cbmPrm.IMSI, simShrdPrm.imsi.field, simShrdPrm.imsi.c_field) NEQ 0)
    {
    /* Implements Measure # 9 */
      cmhSMS_clearCbmPrm();     
      return FALSE;
    }
#endif
    mid_list = (T_ACI_CBM_SIM_MID_LIST **)&data;
    mid_entry = 0;

    while (smsShrdPrm.cbmPrm.cbmFoundIds < MAX_IDENTS/2 AND
           mid_entry < dataLen)
    {
      mid = (USHORT)(*mid_list)->LSB |
            ((USHORT)(*mid_list)->MSB << 8);
      data += 2;           /* overcome TI alignment problem */
      mid_entry += 2;

      if (mid NEQ NOT_PRESENT_16BIT)
      {
/* Please be aware that to keep simulation test cases as less changed as 
   possible lets assume that  CBMs stored in the FFS and from SIM 
   card are the same, since we cannot access  FFS under SIMULATION*/
#ifndef _SIMULATION_

        /* Implements Measure # 73 */
        if (!cmhSMS_findMessageIds (mid, mid))
        {
          return FALSE;
        }

#else /* Just for simulation - copy data, received from SIM */
      smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2] = 
      smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2 + 1] = mid;
      smsShrdPrm.cbmPrm.cbmFoundIds++;
#endif
      }
    }
    return TRUE;
  }
  return FALSE;
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_PutCbmiSIM            |
+-------------------------------------------------------------------+

  PURPOSE : This function conbines the parameters of EF(CBMI)
            to be written to SIM.
*/
GLOBAL BOOL cmhSMS_PutCbmiSIM (T_ACI_CMD_SRC srcId,
                               UBYTE         *data,
                               int           maxDataLen)
{
  T_ACI_CBM_SIM_MID_LIST **mid_list;
  USHORT lower_mid, upper_mid;
  UBYTE  mid_entry;

  TRACE_FUNCTION ("cmhSMS_PutCbmiSIM ()");

  if (data NEQ NULL)
  {
    memset (data, NOT_PRESENT_8BIT, maxDataLen);

    mid_list = (T_ACI_CBM_SIM_MID_LIST **)&data;
    mid_entry = 0;

    while (smsShrdPrm.cbmPrm.cbmFoundIds < MAX_IDENTS/2 AND
           mid_entry < maxDataLen)
    {
      lower_mid = smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2];
      upper_mid = smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2 + 1];
      smsShrdPrm.cbmPrm.cbmFoundIds++;

      if (lower_mid NEQ NOT_PRESENT_16BIT OR
          upper_mid NEQ NOT_PRESENT_16BIT)
      {
        while (lower_mid <= upper_mid AND mid_entry < maxDataLen)
        {
          (*mid_list)->LSB = (UBYTE)lower_mid;
          (*mid_list)->MSB = (UBYTE)(lower_mid >> 8);
          lower_mid++;
          data += 2;           /* overcome TI alignment problem */
          mid_entry += 2;
        }
      }
    }
    return TRUE;
  }
  return FALSE;
}

#ifdef SIM_TOOLKIT

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_FileUpdate            |
+-------------------------------------------------------------------+

  PURPOSE : This function processes the primitive SIM_FILE_UPDATE_IND
            to update the SMS parameters stored on the SIM.
*/
GLOBAL BOOL cmhSMS_FileUpdate (int ref, T_SIM_FILE_UPDATE_IND *fu)
{
  BOOL found = FALSE;
  int i;

  TRACE_FUNCTION ("cmhSMS_FileUpdate ()");

  for (i = 0; i < (int)fu->val_nr; i++)
  {
    if (!found AND
        (fu->file_info[i].v_path_info EQ TRUE AND
         fu->file_info[i].path_info.df_level1 EQ SIM_DF_GSM AND
         fu->file_info[i].path_info.v_df_level2 EQ FALSE AND
         (fu->file_info[i].datafield EQ SIM_CBMI OR
          fu->file_info[i].datafield EQ SIM_CBMIR OR
          fu->file_info[i].datafield EQ SIM_CBMID)) OR

         (fu->file_info[i].v_path_info EQ TRUE AND
          fu->file_info[i].path_info.df_level1 EQ SIM_DF_TELECOM AND
          fu->file_info[i].path_info.v_df_level2 EQ FALSE AND
          fu->file_info[i].datafield EQ SIM_SMSP))
    {
      found = TRUE;
    }
    if (fu->file_info[i].v_path_info EQ TRUE AND
        fu->file_info[i].path_info.df_level1   EQ SIM_DF_TELECOM AND
        fu->file_info[i].path_info.v_df_level2 EQ FALSE AND
        fu->file_info[i].datafield   EQ SIM_SMS)
    {
      smsShrdPrm.aci_sms_parameter.simTotal = 0;
      smsShrdPrm.aci_sms_parameter.simUsed  = 0;
    }
  }
  if (found)
  {
    smsShrdPrm.cbmPrm.cbmFoundIds = 0; /* new CBMI(R) */

    if (cmhSMS_ReadParams ((T_ACI_CMD_SRC)OWN_SRC_SAT, AT_CMD_CFUN, 1) EQ AT_EXCT)
    {
      smsShrdPrm.accessEnabled = FALSE;

      simShrdPrm.fuRef = ref;
      return FALSE;           /* reading files */
    }
    else
      return TRUE;            /* nothing to do */
  }
  else
  {
    simShrdPrm.fuRef = -1;    /* nothing to do */
    return TRUE;
  }
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
| STATE   : code             ROUTINE : cmhSMS_GetCbDtaDwnlSIM       |
+-------------------------------------------------------------------+

  PURPOSE : This function extracts the parameters of CBMID record of
            EF(CBMID) read from SIM.
*/
GLOBAL BOOL cmhSMS_GetCbDtaDwnlSIM  (T_ACI_CMD_SRC srcId,
                                     UBYTE         *data,
                                     int           dataLen)
{
  T_ACI_CBM_SIM_MID_LIST **mid_list;
  USHORT mid;
  int mid_entry;

  TRACE_FUNCTION ("cmhSMS_GetCbDtaDwnlSIM ()");

  if (data NEQ NULL)
  {
    smsShrdPrm.cbmPrm.CBDtaDwnlFoundIds = 0;
    memset (smsShrdPrm.cbmPrm.CBDtaDwnlIdent, NOT_PRESENT_8BIT,
            sizeof (smsShrdPrm.cbmPrm.CBDtaDwnlIdent));

    mid_list = (T_ACI_CBM_SIM_MID_LIST **)&data;
    mid_entry = 0;

    while (smsShrdPrm.cbmPrm.CBDtaDwnlFoundIds < MAX_IDENTS_SAT AND
           mid_entry < dataLen)
    {
      mid = (USHORT)(*mid_list)->LSB |
            ((USHORT)(*mid_list)->MSB << 8);
      data += 2;           /* overcome TI alignment problem */
      mid_entry += 2;

      if (mid NEQ NOT_PRESENT_16BIT)
      {
        smsShrdPrm.cbmPrm.CBDtaDwnlIdent[smsShrdPrm.cbmPrm.CBDtaDwnlFoundIds] = mid;
        smsShrdPrm.cbmPrm.CBDtaDwnlFoundIds++;
      }
    }
    return TRUE;
  }
  return FALSE;
}

#endif  /*of SIM_TOOLKIT */




/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : cmhSMS_decodeMsg   |
+--------------------------------------------------------------------+

  PURPOSE : decodes a SM in two steps

*/
GLOBAL UBYTE* cmhSMS_decodeMsg (T_sms_sdu *sms_sdu, T_rp_addr* rp_addr,
                                UBYTE vt_mti)
{
  UBYTE ccdRet;
  UBYTE direction;
  UBYTE recover_from_error;

  BUF_tpdu   sim_buf;   /* source for the second decoding */

  TRACE_FUNCTION("cmhSMS_decodeMsg ()");

  if( sms_sdu->l_buf EQ 0)
  {
    TRACE_EVENT("empty SDU: no decoding");
    return(NULL);
  }

  CCD_START;
  {

    MCAST( sim_pdu, SIM_PDU ); /* sim_pdu points to _decodedMsg */
    /*memset( sim_pdu, 0, sizeof (T_SIM_PDU) ); */

    /* decoding outer layer */
    ccdRet = ccd_decodeMsg ( CCDENT_SMS,
                             BOTH /* doesn't work with DOWNLINK!!! */,
                             (T_MSGBUF *) sms_sdu,
                             (UBYTE    *) _decodedMsg, /* target */
                             SMS_VT_SIM_PDU);

    if ( (ccdRet NEQ ccdOK) OR (!sim_pdu->v_tpdu)
         OR (_decodedMsg[0] NEQ SMS_VT_SIM_PDU) )
    {
      TRACE_EVENT_P1("CCD Decoding Error: %d", ccdRet);
      CCD_END;
      return NULL;
    }

    memcpy(rp_addr, &sim_pdu->rp_addr, sizeof(T_rp_addr) );

    memcpy(&sim_buf, &sim_pdu->tpdu, sizeof(BUF_tpdu) );

    /*memset( _decodedMsg, 0, sizeof (T_TP_SUBMIT) ); */

    if (vt_mti EQ SMS_VT_SUBMIT)
    {
      /* for decoding of SMS-SUBMIT (in response to +CMGR, +CMGL) */
      direction = UPLINK;
    }
    else
    {
      direction = DOWNLINK;
    }

    /* decoding inner layer */
    ccdRet = ccd_decodeMsg ( CCDENT_SMS,
                             direction,
                             (T_MSGBUF *) &sim_buf,
                             (UBYTE    *) _decodedMsg,  /* target */
                             vt_mti );

    if (ccdRet EQ ccdWarning)
      recover_from_error = TRUE;  /* Try to recover if a ccdWarning occoured */
    else
      recover_from_error = FALSE;

    if ((ccdRet EQ ccdError) OR (ccdRet EQ ccdWarning))
    {
      UBYTE ccd_err;
      USHORT parlist [6];

      TRACE_EVENT_P1 ("ccd_decodeMsg(): %02x", ccdRet);
      /*
       * get the first error
       */
      ccd_err = ccd_getFirstError (CCDENT_SMS, parlist);

      /*
       * Error Handling
       */
      do
      {
#ifndef NTRACE /* save some ROM */
/* Implements Measure#32: Row 1080,...,1093 */
        if (ccdRet EQ ccdError)
        {
          TRACE_EVENT_P1 ("ERR: %u ", ccd_err);
        }
        else if (ccdRet EQ ccdWarning)
        {
          TRACE_EVENT_P1 ("WRN: %u ", ccd_err);
        }
        switch (ccd_err)
        {
          case ERR_NO_MORE_ERROR:   
            TRACE_EVENT("the end of the error list is reached");
            break;
          case ERR_INVALID_CALC:    
            TRACE_EVENT("calculation of the element repeat value failed");
            break;
          case ERR_PATTERN_MISMATCH:
            TRACE_EVENT("a bit pattern was not expected");
            break;
          case ERR_COMPREH_REQUIRED:
            TRACE_EVENT("check for comprehension required failed");
            break;
          case ERR_IE_NOT_EXPECTED: 
            TRACE_EVENT("an information element was not expected");
            break;
          case ERR_IE_SEQUENCE:     
            TRACE_EVENT("wrong sequence of information elements");
            break;
          case ERR_MAX_IE_EXCEED:   
            TRACE_EVENT("maximum amount of repeatable information elements has exceeded");
            break;
          case ERR_MAX_REPEAT:      
            TRACE_EVENT("a repeatable element occurs too often in the message");
            break;
          case ERR_MAND_ELEM_MISS:  
            TRACE_EVENT("a mandatory information element is missing");
            break;
          case ERR_INVALID_MID:     
            TRACE_EVENT("the message ID is not correct");
            break;
          case ERR_INVALID_TYPE:    
            TRACE_EVENT("the information element is not a spare padding");
            break;
          case ERR_EOC_TAG_MISSING: 
            TRACE_EVENT("indefinite length is specified for the ASN.1-BER but the end tag is missing");
            break;
          case ERR_INTERNAL_ERROR:  
            TRACE_EVENT("an internal CCD error occured ");
            break;
          default:                  
            TRACE_EVENT("unknown error");
            break;
        }
#endif /* NTRACE */

        if (ccdRet EQ ccdWarning)
        {
          switch (ccd_err)
          {
            case ERR_PATTERN_MISMATCH:     /* recoverable warnings */
            case ERR_COMPREH_REQUIRED:
            case ERR_INTERNAL_ERROR:
              break;                       
            default:
              recover_from_error = FALSE;  /* in all other cases reset the recover flag */
          }
        }

        ccd_err = ccd_getNextError (CCDENT_SMS, parlist);
      }while (ccd_err NEQ ERR_NO_MORE_ERROR);
    }

    if ( (ccdRet EQ ccdError) OR
        ((ccdRet EQ ccdWarning) AND (recover_from_error EQ FALSE)) OR  /* not possible to recover */
         (_decodedMsg[0] NEQ vt_mti) )
    {
      TRACE_EVENT_P1("CCD Decoding Error Stage 2: %d", ccdRet);
      CCD_END;
      return NULL;
    }
    else if ((ccdRet EQ ccdWarning) AND (recover_from_error EQ TRUE))
    {
      TRACE_EVENT ("recovered from warning");
    }
  }
  CCD_END;

  return _decodedMsg;
}



/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : cmhSMS_codeMsg     |
+--------------------------------------------------------------------+

  PURPOSE : encodes a SM in two steps

*/
GLOBAL void cmhSMS_codeMsg (T_sms_sdu *sms_sdu, UBYTE tp_vt_mti,
                            T_rp_addr* sc_addr, UBYTE tp_mti,
                            UBYTE* decoded_pdu )
{
  BUF_tpdu  sim_buf;      /* target for first coding  */
  UBYTE direction;

  TRACE_FUNCTION ("cmhSMS_codeMsg()");


  CCD_START;
  {
    UBYTE ccdRet;

    MCAST( sim_pdu, SIM_PDU );

    /* source of outer encoding */
    memset( sim_pdu, 0, sizeof (T_SIM_PDU) );

    /* target of outer encoding */
    /* memset( sms_sdu, 0, sizeof (T_sms_sdu) ); */
    sms_sdu->o_buf = 0;
    sms_sdu->l_buf = SIM_PDU_LEN << 3;

    sim_pdu->tp_vt_mti = SMS_VT_SIM_PDU;
    sim_pdu->tp_mti    = tp_mti;

    /* service center address exists */
    if (sc_addr)
    {
      memcpy(&sim_pdu->rp_addr, sc_addr, sizeof(T_rp_addr));
      sim_pdu->rp_addr.v_ton = 1;
      sim_pdu->rp_addr.v_npi = 1;
    }

    /* pdu data exists */
    if (decoded_pdu)
    {
      /* target of inner encoding */
      /* memset(sim_buf, 0, sizeof(BUF_tpdu)); */
      sim_buf.o_tpdu = 0;
//TISH modified for MSIM
//TISH: l_tpdu should be lenth of sim_buf.b_tpdu not BUF_tpdu.
//      sim_buf.l_tpdu = (sizeof(BUF_tpdu)) << 3;
      sim_buf.l_tpdu = (sizeof(sim_buf.b_tpdu)) << 3;

      if (tp_vt_mti EQ SMS_VT_DELIVER)
      {
        /* for encoding of SMS-DELIVER (only in +CMGW) */
        direction = DOWNLINK;
      }
      else
      {
        direction = UPLINK;
      }

      /* encoding inner layer */
      ccdRet = ccd_codeMsg (CCDENT_SMS,
                            direction,
                            (T_MSGBUF *) &sim_buf,  /* target */
                            (UBYTE *) decoded_pdu,
                            tp_vt_mti);

      if ( ccdRet NEQ ccdOK )
      {
        TRACE_EVENT_P1("CCD Coding Error: %d", ccdRet);
        CCD_END;
        return;
      }
      if (sim_buf.l_tpdu EQ 0)
      {
         TRACE_EVENT("Encoded length is zero");
      }

      memcpy(&sim_pdu->tpdu, &sim_buf, sizeof(BUF_tpdu));
      sim_pdu->v_tpdu = 1; /* set validy flag */      
    }

    /* encoding outer layer */
    ccdRet = ccd_codeMsg (CCDENT_SMS,
                          UPLINK,
                          (T_MSGBUF *) sms_sdu,  /* target */
                          (UBYTE *) sim_pdu,
                          SMS_VT_SIM_PDU);

    if ( ccdRet NEQ ccdOK )
    {
      TRACE_EVENT_P1("CCD Coding Error: %d", ccdRet);
      CCD_END;
      return;
    }
    if (sms_sdu->l_buf EQ 0)
    {
       TRACE_EVENT("Encoded length is zero");
    }
  }
  CCD_END;
}



/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : cmhSMS_cpyDeliver  |
+--------------------------------------------------------------------+

  PURPOSE : converts a SMS-DELIVER message to the T_ACI_CMGL_SM 
            structure

*/
GLOBAL BOOL cmhSMS_cpyDeliver ( T_ACI_CMGL_SM * sm, T_sms_sdu * sms_sdu )
{
  T_rp_addr rp_addr;
  UBYTE* message;
  T_TP_DELIVER *sms_deliver;
  UBYTE alphabet;

  TRACE_FUNCTION("cmhSMS_cpyDeliver()");

  message = cmhSMS_decodeMsg(sms_sdu, &rp_addr, SMS_VT_DELIVER);

  if (message EQ NULL)
  {
    sm->stat = SMS_STAT_Invalid;
    return (FALSE);
  }

  if ( message[0] NEQ SMS_VT_DELIVER)
  {
    TRACE_EVENT_P1("wrong VTI = %x", message[0]);
  }

  sms_deliver = (T_TP_DELIVER*)message;

  /*
   *-----------------------------------------------------------------
   * process originator address
   *-----------------------------------------------------------------
   */
  /* Implements Measure # 126 */
  /* Since T_tp_oa and T_tp_da are of same type, there is no problem in 
     passing sms_deliver->tp_oa */
  cmhSMS_processOrigDestAddr (sm,
                              &rp_addr,
                              &sms_deliver->tp_oa);

  /*
   *-----------------------------------------------------------------
   * process first octet
   *-----------------------------------------------------------------
   */
  sm -> fo = sms_sdu->buf[sms_sdu->buf[0] + 1];

  /*
   *-----------------------------------------------------------------
   * process protocol identifier
   *-----------------------------------------------------------------
   */
  sm -> pid = sms_deliver->tp_pid;

  /*
   *-----------------------------------------------------------------
   * process data coding scheme
   *-----------------------------------------------------------------
   */
  sm -> dcs = sms_deliver->tp_dcs;


  /*
   *-----------------------------------------------------------------
   * process short message data, expanding from 7 to 8 bit
   *-----------------------------------------------------------------
   */

  if (sms_deliver->v_tp_ud)
  {
    /* user data */
    cmhSMS_expdSmsPp ( 0,
                       sms_deliver->tp_dcs,
                       sms_deliver->tp_ud.data,
                       sms_deliver->tp_ud.length,
                       sm -> data.data,
                       &sm->data.len );

    sm->udh.len = 0;
  }
  else
  {
    alphabet = cmhSMS_getAlphabetPp ( sms_deliver->tp_dcs );

    /* user data header */
    memcpy (sm->udh.data, sms_deliver->tp_udh_inc.tp_udh.data,
            sms_deliver->tp_udh_inc.tp_udh.c_data);
    sm->udh.len = sms_deliver->tp_udh_inc.tp_udh.c_data;

    /* user data (only user data can be 7bit data!!!) */
    cmhSMS_expdSmsPp ( (UBYTE)(sm->udh.len+1),
                       sms_deliver->tp_dcs,
                       sms_deliver->tp_udh_inc.data,
                       sms_deliver->tp_udh_inc.length,    /* ACI-SPR-9440 */
                       sm->data.data,
                       &sm->data.len );

    /* 7-bit data */
    if (alphabet EQ 0x00)
    {
      sm->data.len = sms_deliver->tp_udh_inc.length - ((sm->udh.len+1)*8)/7;

      /* minus space for the fill bits */
      if (((sm->udh.len+1)*8)%7 NEQ 0) sm->data.len--;
    }
    /* 8-bit data */
    else
    {
      sm->data.len = sms_deliver->tp_udh_inc.length-(sm->udh.len+1);
    }
  }

  /*
   *-----------------------------------------------------------------
   * process service center time stamp
   *-----------------------------------------------------------------
   */
  sm -> vp_rel = 0;
  memset ( &sm->vp_enh, 0, sizeof(T_ACI_VP_ENH) );

  cmhSMS_setVpabsCmh ( &sm -> scts,
                       (T_tp_vp_abs*) &sms_deliver->tp_scts );

  return (TRUE);
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : cmhSMS_cpySubmit   |
+--------------------------------------------------------------------+

  PURPOSE : converts a SMS-SUBMIT message to the T_ACI_CMGL_SM
            structure

*/
GLOBAL BOOL cmhSMS_cpySubmit ( T_ACI_CMGL_SM * sm, T_sms_sdu * sms_sdu )
{
  T_rp_addr rp_addr;
  UBYTE* message;
  T_TP_SUBMIT *sms_submit;
  UBYTE alphabet;

  TRACE_FUNCTION("cmhSMS_cpySubmit()");

  message = cmhSMS_decodeMsg(sms_sdu, &rp_addr, SMS_VT_SUBMIT);

  if (message EQ NULL)
  {
    sm->stat = SMS_STAT_Invalid;  
    return (FALSE);
  }

  if ( message[0] NEQ SMS_VT_SUBMIT)
  {
    TRACE_EVENT_P1("wrong VTI = %x", message[0]);
  }

  sms_submit = (T_TP_SUBMIT*)message;


  /*
   *-----------------------------------------------------------------
   * process recepient address
   *-----------------------------------------------------------------
   */
  /* Implements Measure # 126 */
  cmhSMS_processOrigDestAddr (sm,
                              &rp_addr,
                              &sms_submit->tp_da);

  /*
   *-----------------------------------------------------------------
   * process first octet
   *-----------------------------------------------------------------
   */
  sm -> fo = sms_sdu->buf[sms_sdu->buf[0] + 1];

  /*
   *-----------------------------------------------------------------
   * process protocol identifier
   *-----------------------------------------------------------------
   */
  sm -> pid = sms_submit->tp_pid;

  /*
   *-----------------------------------------------------------------
   * process data coding scheme
   *-----------------------------------------------------------------
   */
  sm -> dcs = sms_submit->tp_dcs;

  /*
   *-----------------------------------------------------------------
   * process short message data, expanding from 7 to 8 bit
   *-----------------------------------------------------------------
   */

  if (sms_submit->v_tp_ud)
  {
    /* user data */
    cmhSMS_expdSmsPp ( 0,
                       sms_submit->tp_dcs,
                       sms_submit->tp_ud.data,
                       sms_submit->tp_ud.length,   /* ACI-SPR-9440 */
                       sm->data.data,
                       &sm->data.len );

    sm->udh.len = 0;
  }
  else
  {
    alphabet = cmhSMS_getAlphabetPp ( sms_submit->tp_dcs );

    /* user data header */
    memcpy (sm->udh.data, sms_submit->tp_udh_inc.tp_udh.data,
            sms_submit->tp_udh_inc.tp_udh.c_data);
    sm->udh.len = sms_submit->tp_udh_inc.tp_udh.c_data;

    /* user data (only user data can be 7bit data!!!) */
    cmhSMS_expdSmsPp ( (UBYTE)(sm->udh.len+1),
                       sms_submit->tp_dcs,
                       sms_submit->tp_udh_inc.data,
                       sms_submit->tp_udh_inc.length,  /* ACI-SPR-9440 */
                       sm->data.data,
                       &sm->data.len );

    /* 7-bit data */
    if (alphabet EQ 0x00)
    {
      sm->data.len = sms_submit->tp_udh_inc.length - ((sm->udh.len+1)*8)/7;

      /* minus space for the fill bits */
      if (((sm->udh.len+1)*8)%7 NEQ 0) sm->data.len--;
    }
    /* 8-bit data */
    else
    {
      sm->data.len = sms_submit->tp_udh_inc.length-(sm->udh.len+1);
    }
  }

  /*
   *-----------------------------------------------------------------
   * process validity period
   *-----------------------------------------------------------------
   */
  if (sms_submit->v_tp_vp_abs)
  {
    cmhSMS_setVpabsCmh ( &sm->scts, &sms_submit->tp_vp_abs );
    sm -> vp_rel = 0;
    memset ( &sm->vp_enh, 0, sizeof(T_ACI_VP_ENH) );
  }
  else if (sms_submit->v_tp_vp_enh)
  {
    cmhSMS_setVpenhCmh ( &sm->vp_enh, &sms_submit->tp_vp_enh );
    sm -> vp_rel = 0;
    memset ( &sm->scts, 0, sizeof(T_ACI_VP_ABS) );
  }
  else
  {
    sm -> vp_rel = sms_submit->tp_vp_rel;
    memset ( &sm -> scts, 0, sizeof(T_ACI_VP_ABS) );
    memset ( &sm -> vp_enh, 0, sizeof(T_ACI_VP_ENH) );
  }
  return (TRUE);
}

/* Implements Measure # 110 */

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : cmhSMS_cpyStatInd  |
+--------------------------------------------------------------------+

  PURPOSE : handles a status indication

*/
GLOBAL BOOL cmhSMS_cpyStatInd ( T_ACI_CDS_SM  * sm, 
                                T_MNSMS_STATUS_IND *mnsms_status_ind )
{
  T_rp_addr rp_addr;
  UBYTE* message;
  T_TP_STATUS *sms_status;
  
  TRACE_FUNCTION("cmhSMS_cpyStatInd()");

  message = cmhSMS_decodeMsg(&mnsms_status_ind->sms_sdu, &rp_addr, SMS_VT_STATUS);

  if (message EQ NULL)
  {
    return (FALSE);
  }

  if ( message[0] NEQ SMS_VT_STATUS)
  {
    TRACE_EVENT_P1("wrong VTI = %x", message[0]);
  }

  sms_status = (T_TP_STATUS*)message;


  /*
   *-----------------------------------------------------------------
   * process message type
   *-----------------------------------------------------------------
   */
  sm -> fo = mnsms_status_ind->sms_sdu.buf[mnsms_status_ind->sms_sdu.buf[0]+1];

  /*
   *-----------------------------------------------------------------
   * process message reference
   *-----------------------------------------------------------------
   */
  sm -> msg_ref = sms_status->tp_mr;

  /*
   *-----------------------------------------------------------------
   * process recipient address
   *-----------------------------------------------------------------
   */
  cmhSMS_getAdrStr ( sm->addr,
                     MAX_SMS_ADDR_DIG - 1,
                     sms_status->tp_ra.num,
                     sms_status->tp_ra.digits);

  sm->toa.ton = cmhSMS_getTon ( sms_status->tp_ra.ton );
  sm->toa.npi = cmhSMS_getNpi ( sms_status->tp_ra.npi );

  /*
   *-----------------------------------------------------------------
   * process service center time stamp
   *-----------------------------------------------------------------
   */
  cmhSMS_setVpabsCmh ( &sm->vpabs_scts, (T_tp_vp_abs*) &sms_status->tp_scts );

  /*
   *-----------------------------------------------------------------
   * process discharge time
   *-----------------------------------------------------------------
   */
  cmhSMS_setVpabsCmh ( &sm->vpabs_dt, (T_tp_vp_abs*) &sms_status->tp_dt );

  /*
   *-----------------------------------------------------------------
   * process status
   *-----------------------------------------------------------------
   */
  sm -> tp_status = sms_status->tp_st;

  return (TRUE);
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : cmhSMS_getPhbEntry |
+--------------------------------------------------------------------+

  PURPOSE : gets phone book entry from coded SM

*/
GLOBAL void cmhSMS_getPhbEntry( UBYTE *buf,
                                T_ACI_PB_TEXT *alpha,
                                T_ACI_SMS_STAT status )
{
  UBYTE *p_data;
  UBYTE sca_len;
  UBYTE nplan;
  UBYTE no_bcd;
  UBYTE bcd[MAX_SMS_ADDR_DIG];
  CHAR  addr[MAX_SMS_ADDR_DIG+1];   /* for '\0' */
  USHORT octets;

  alpha->len = 0;

  p_data =  &buf[0];
  sca_len = buf[0];

  switch (status)
  {
    case SMS_STAT_RecUnread:
    case SMS_STAT_RecRead:
      if ((*(p_data+sca_len+1) & TP_MTI_MASK) EQ TP_MTI_SMS_STATUS_REP)
      {
        p_data++;
      }
      p_data += (sca_len+1) + 1;  /* sms-deliver */
      break;
    case SMS_STAT_StoUnsent:
    case SMS_STAT_StoSent:
      p_data += (sca_len+1) + 2;  /* sms-submit */
      break;
    default:
      return;
  }

  /* process originator/destination address */
  no_bcd = *p_data++;
  no_bcd = MINIMUM(no_bcd, MAX_SMS_ADDR_DIG);

  nplan  = *p_data++ & 0x0F; /* npi */

  octets = (no_bcd+1)/2;

  no_bcd = (UBYTE)cmh_unpackBCD (bcd, p_data, octets);

  if (nplan EQ 0x05) /* VO patch - if (patch) else ... */
  {
    UBYTE i,j = 0;
    for (i = 0 ; i < no_bcd; i=i+2)
    {
      addr[j] = (UBYTE)(bcd[i+1] << 4) + (UBYTE)(bcd[i]);
      j++;
    }
    addr[j] = '\0';
  }
  else
  {
    cmhSMS_getAdrStr ( addr,
                       MAX_SMS_ADDR_DIG,
                       bcd,
                       no_bcd );
  }

  /*
   *-----------------------------------------------------------------
   * process alphanumerical phonebook entry
   *-----------------------------------------------------------------
   */
  psaCC_phbMfwSrchNumPlnTxt ( addr, alpha );
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : cmhSMS_codeDelRep  |
+--------------------------------------------------------------------+

  PURPOSE : codes RP-ACK for SMS-DELIVER-REPORT (without PID, DCS, UD)

*/
GLOBAL void cmhSMS_codeDelRep(T_sms_sdu *sms_sdu, T_rp_addr *sc_addr)
{
  UBYTE sca_len;  /* SCA len incl. length byte and toa */
  UBYTE sca_buf[MAX_SMS_ADDR_DIG/2 + 2];

  sca_len = CodeRPAddress( sca_buf,
                           sc_addr->c_num,
                           sc_addr->ton,
                           sc_addr->npi,
                           sc_addr->num );

  sms_sdu->l_buf = (sca_len+2)<<3;
  sms_sdu->o_buf = 0;

  memcpy ( sms_sdu->buf, sca_buf, sca_len);
  memset ( sms_sdu->buf+sca_len, 0, 2);
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : CodeRPAddress      |
+--------------------------------------------------------------------+

  PURPOSE : converts address (in BCD format) to semi-octet representation
            (including address-length, ton and npi),
            for RP addresses (e.g SCA)

            returns number of octets including address-length,
            ton and npi

*/
GLOBAL UBYTE CodeRPAddress( UBYTE *buf, UBYTE  numDigits, UBYTE ton,
                      UBYTE npi,  UBYTE *bcd )
{
  UBYTE length;

  if (numDigits EQ 0)
  {
    length = 1;
    *buf = 0x00;
  }
  else
  {
    *buf++ = (numDigits+1)/2 + 1;
    *buf++ = (ton << 4) + npi + 0x80;

    length = (UBYTE)cmh_packBCD ( buf, bcd, numDigits );

    /* add length of length field, ton and npi */
    length += 2;
  }

  return length;
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : CodeTPAddress      |
+--------------------------------------------------------------------+

  PURPOSE : converts address (in BCD format) to semi-octet representation
            (including address-length, ton and npi),
            for TP addresses (e.g OA or DA)

            returns number of octets including including address-length,
            ton and npi

*/
GLOBAL UBYTE CodeTPAddress( UBYTE *buf, UBYTE  numDigits, UBYTE ton,
                      UBYTE npi,  UBYTE *bcd )
{
  UBYTE length;

  *buf++ = numDigits;
  *buf++ = (ton << 4) + npi + 0x80;

  length = (UBYTE)cmh_packBCD ( buf, bcd, numDigits );

  /* add length of length field, to and npi */
  length += 2;

  return length;
}


/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : DecodeRPAddress    |
+--------------------------------------------------------------------+

  PURPOSE : converts RP address (SC address) from semi-octet
            representation to address in BCD format (including
            address-length, ton and npi)

            returns number of processed octets in buf

*/
GLOBAL UBYTE DecodeRPAddress(UBYTE *c_num, UBYTE *ton,
                       UBYTE *npi,  UBYTE *bcd, UBYTE *buf)
{
  UBYTE sca_length;  /* sca length is lenth in bytes plus TOA-octet */
  UBYTE processed_octets;

  sca_length = *buf++;
  *ton = (*buf & 0x70)>>4;
  *npi = *buf++ & 0x0F;

  *c_num = (UBYTE)cmh_unpackBCD (bcd, buf, (USHORT)(sca_length-1));

  processed_octets = (*c_num+1)/2 + 2;

  return processed_octets;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF           |
| STATE   : code                        ROUTINE : DecodeTPAddress    |
+--------------------------------------------------------------------+

  PURPOSE : converts TP address (DA, OA)from semi-octet
            representation to address in BCD format (including
            address-length, ton and npi)

            returns number of processed octets in buf

*/
GLOBAL UBYTE DecodeTPAddress(UBYTE *c_num, UBYTE *ton,
                       UBYTE *npi,  UBYTE *bcd, UBYTE *buf)
{
  UBYTE digits;
  UBYTE processed_octets;

  digits = *buf++;
  *ton = (*buf & 0x70)>>4;
  *npi = *buf++ & 0x0F;

  *c_num = (UBYTE)cmh_unpackBCD (bcd, buf, (USHORT)((digits+1)/2));

  processed_octets = (*c_num+1)/2 + 2;

  return processed_octets;
}




/*
+--------------------------------------------------------------------+
| PROJECT :                     MODULE  : CMH_SMSF                   |
| STATE   : code                ROUTINE : cmhSMS_fillTpSubmit        |
+--------------------------------------------------------------------+

  PURPOSE : fills a T_TP_SUBMIT

*/
GLOBAL void cmhSMS_fillTpSubmit  (T_TP_SUBMIT*    tp_submit,
                                  T_ACI_CMD_SRC   srcId,
                                  UBYTE           msgType,
                                  UBYTE           mr,
                                  T_tp_da*        da_addr,
                                  T_ACI_SM_DATA*  data,
                                  UBYTE           septets,
                                  T_ACI_UDH_DATA* udh )
{
  T_SMS_SET_PRM * pSMSSetPrm; /* points to SMS parameter set     */
  UBYTE  alphabet;

  TRACE_FUNCTION ("cmhSMS_fillTpSubmit()");

  pSMSSetPrm = smsShrdPrm.pSetPrm[srcId];

  memset(tp_submit, 0, sizeof(T_TP_SUBMIT));

  tp_submit->tp_vt_mti = SMS_VT_SUBMIT;
  tp_submit->tp_rp = (msgType & TP_RP_MASK) ? 1 : 0;
  tp_submit->tp_mti = SMS_SUBMIT;
  tp_submit->tp_mr = mr;
  tp_submit->tp_srr  = (msgType & TP_SRR_MASK) ? 1 : 0;

  if (da_addr->digits NEQ 0x00)
    memcpy(&tp_submit->tp_da, da_addr, sizeof(T_tp_da));

  tp_submit->tp_pid = pSMSSetPrm -> pid;
  tp_submit->tp_dcs = pSMSSetPrm -> dcs;

  switch (msgType & VPF_MASK)
  {

    case VPF_RELATIVE:  /* validity period relative */
      tp_submit->v_tp_vp_rel = 1;
      tp_submit->tp_vpf = SMS_VPF_RELATIVE;
      tp_submit->tp_vp_rel = pSMSSetPrm -> vpRel;
      break;

    case VPF_ABSOLUTE:  /* validity period absolute */
      tp_submit->v_tp_vp_abs = 1;
      tp_submit->tp_vpf = SMS_VPF_ABSOLUTE;
      memcpy(&tp_submit->tp_vp_abs, &pSMSSetPrm -> vpAbs, sizeof(T_tp_vp_abs));
      break;

    case VPF_ENHANCED:  /* validity period enhanced */
      tp_submit->v_tp_vp_enh = 1;
      tp_submit->tp_vpf = SMS_VPF_ENHANCED;
      memcpy(&tp_submit->tp_vp_enh, &pSMSSetPrm -> vpEnh, sizeof(T_tp_vp_enh));
      break;

    default:  /* validity period not present */
      break;
  }

  
  alphabet = cmhSMS_getAlphabetPp ( pSMSSetPrm -> dcs );

  if ((udh) AND (udh->len))
  {
    tp_submit->tp_udhi = 1;
    tp_submit->v_tp_udh_inc = 1;
    tp_submit->tp_udh_inc.tp_udh.c_data = udh->len;
    memcpy(tp_submit->tp_udh_inc.tp_udh.data, udh->data, udh->len);

    /* copy user data */
    if ((data) AND (data->len))
    {
      tp_submit->tp_udh_inc.c_data = data->len;
      memcpy(tp_submit->tp_udh_inc.data, data->data, data->len);
    }

    /* 7-bit data */
    if (alphabet EQ 0x00)
    {
      tp_submit->tp_udh_inc.length = septets + (((udh->len+1)*8)/7);

      /* space for the fill bits */
      if (((udh->len+1)*8)%7 NEQ 0) 
      {
        tp_submit->tp_udh_inc.length++;
        if ((data EQ NULL) OR (data->len EQ 0))
        {
          tp_submit->tp_udh_inc.c_data = 1;
          tp_submit->tp_udh_inc.data[0] = 0; /* redundant  */
        }
      }
    }
    /* 8-bit data */
    else
    {
      tp_submit->tp_udh_inc.length = tp_submit->tp_udh_inc.c_data+udh->len+1; /* UDH length should be also added */
    }
  }
  else
  {
    /* validity flag set for both normal SMS and empty SMS */
      tp_submit->v_tp_ud = 1;

    if ((data) AND (data->len))
    {
      tp_submit->tp_ud.length = septets;
      tp_submit->tp_ud.c_data = data->len;
      memcpy(tp_submit->tp_ud.data, data->data, data->len); 
    }
    else 
    {
      /* enters when zero character SMS to be sent */
    }
  }
}



/*
+--------------------------------------------------------------------+
| PROJECT :                     MODULE  : CMH_SMSF                   |
| STATE   : code                ROUTINE : cmhSMS_fillTpDeliver       |
+--------------------------------------------------------------------+

  PURPOSE : fills a T_TP_DELIVER (only used by +CMGW)

*/
GLOBAL void cmhSMS_fillTpDeliver (T_TP_DELIVER*   tp_deliver,
                                  T_ACI_CMD_SRC   srcId,
                                  UBYTE           msgType,
                                  T_tp_oa*        oa_addr,
                                  T_ACI_SM_DATA*  data,
                                  UBYTE           septets,
                                  T_ACI_UDH_DATA* udh )
{
  T_SMS_SET_PRM * pSMSSetPrm; /* points to SMS parameter set     */
  UBYTE  alphabet;

  TRACE_FUNCTION ("cmhSMS_fillTpDeliver()");

  pSMSSetPrm = smsShrdPrm.pSetPrm[srcId];

  memset(tp_deliver, 0, sizeof(T_TP_DELIVER));

  tp_deliver->tp_vt_mti = SMS_VT_DELIVER;
  tp_deliver->tp_rp = (msgType & TP_RP_MASK) ? 1 : 0;
  tp_deliver->tp_mti = SMS_DELIVER;

  if (oa_addr->digits NEQ 0x00)
    memcpy(&tp_deliver->tp_oa, oa_addr, sizeof(T_tp_oa));

  tp_deliver->tp_pid = pSMSSetPrm -> pid;
  tp_deliver->tp_dcs = pSMSSetPrm -> dcs;

  memcpy(&tp_deliver->tp_scts, &pSMSSetPrm -> vpAbs, sizeof(T_tp_scts));

  if ((data) AND (data->len))
  {
    alphabet = cmhSMS_getAlphabetPp ( pSMSSetPrm -> dcs );

    if ((udh) AND (udh->len))
    {
      tp_deliver->tp_udhi = 1;
      tp_deliver->v_tp_udh_inc = 1;
      tp_deliver->tp_udh_inc.tp_udh.c_data = udh->len;
      memcpy(tp_deliver->tp_udh_inc.tp_udh.data, udh->data, udh->len);

      /* copy user data */
      tp_deliver->tp_udh_inc.c_data = data->len;
      memcpy(tp_deliver->tp_udh_inc.data, data->data, data->len);

      /* 7-bit data */
      if (alphabet EQ 0x00)
      {
        tp_deliver->tp_udh_inc.length = septets + (((udh->len+1)*8)/7);

        /* space for the fill bits */
        if (((udh->len+1)*8)%7 NEQ 0) tp_deliver->tp_udh_inc.length++;
      }
      /* 8-bit data */
      else
      {
        tp_deliver->tp_udh_inc.length = tp_deliver->tp_udh_inc.c_data;
      }
    }
    else
    {
      tp_deliver->v_tp_ud = 1;
      tp_deliver->tp_ud.length = septets;
      tp_deliver->tp_ud.c_data = data->len;
      memcpy(tp_deliver->tp_ud.data, data->data, data->len);
    }
  }
  else /* if ((data) AND (data->len)) */
  {
    tp_deliver->v_tp_ud = 1;
    tp_deliver->tp_ud.length = 0;
  }
}


/*
+--------------------------------------------------------------------+
| PROJECT :                     MODULE  : CMH_SMSF                   |
| STATE   : code                ROUTINE : cmhSMS_fillTpCommand       |
+--------------------------------------------------------------------+

  PURPOSE : fills a T_TP_COMMAND

*/
GLOBAL void cmhSMS_fillTpCommand ( T_TP_COMMAND*   tp_command,
                                   UBYTE           fo,
                                   UBYTE           ct,
                                   UBYTE           mr,
                                   UBYTE           pid,
                                   UBYTE           mn,
                                   T_tp_da*        da_addr,
                                   T_ACI_CMD_DATA* data,
                                   T_ACI_UDH_DATA* udh)

{
  TRACE_FUNCTION ("cmhSMS_fillTpCommand()");

  memset(tp_command, 0, sizeof(T_TP_COMMAND));

  tp_command->tp_vt_mti = SMS_VT_COMMAND;
  tp_command->tp_srr  = (fo & TP_SRR_MASK) ? 1 : 0;
  tp_command->tp_mti = SMS_COMMAND;
  tp_command->tp_mr = mr;
  tp_command->tp_pid = pid;
  tp_command->tp_ct = ct;
  tp_command->tp_mn = mn;

  if (da_addr->digits NEQ 0x00)
    memcpy(&tp_command->tp_da, da_addr, sizeof(T_tp_da));

  if ((data) AND (data->len))
  {
    if ((udh) AND (udh->len))
    {
      tp_command->tp_udhi = 1;
      tp_command->v_tp_cdh_inc = 1;
      tp_command->tp_cdh_inc.tp_udh.c_data = udh->len;
      memcpy(tp_command->tp_cdh_inc.tp_udh.data, udh->data, udh->len);
      tp_command->tp_cdh_inc.c_data = data->len;
      memcpy(tp_command->tp_cdh_inc.data, data->data, data->len);
    }
    else
    {
      tp_command->v_tp_cd = 1;
      tp_command->tp_cd.c_data = data->len;
      memcpy(tp_command->tp_cd.data, data->data, data->len);
    }
  }
  else
  {
    /* command length field must be present */
    tp_command->v_tp_cd = 1;
    tp_command->tp_cd.c_data = 0;
  }

}
#ifdef FF_CPHS

/*
+----------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                   |
|                                 ROUTINE : cmhSMS_check_voice_mail_ind|
+----------------------------------------------------------------------+

  PURPOSE : 
*/

LOCAL BOOL cmhSMS_check_voice_mail_ind( T_TP_DELIVER *sms_deliver )
{
  TRACE_FUNCTION("cmhSMS_check_voice_mail_ind()");

  if ( sms_deliver->tp_oa.digits NEQ 4 OR
       sms_deliver->tp_oa.ton NEQ SMS_TON_ALPHANUMERIC )
  {
    TRACE_EVENT_P2("no vmi -> oa... digits:%d ton:%d", 
                    sms_deliver->tp_oa.digits, sms_deliver->tp_oa.ton);
    return FALSE;
  }

  switch (sms_deliver->tp_dcs & 0xF0)
  {
    case SMS_DCS_GRP_DEF:
    case SMS_DCS_GRP_CLASS:
      if ( (sms_deliver->tp_dcs & 0xF) EQ 0 OR
           (sms_deliver->tp_dcs & 0xF) EQ 0xC )
      {
        break;            /* GSM Default Alphabet */
      }
      /* no break, if FALSE */
      /*lint -fallthrough*/
    case SMS_DCS_GRP_COMPR:
    case SMS_DCS_GRP_CLASS_COMPR:
    case SMS_DCS_GRP_MW_STORE_UCS2:
      TRACE_EVENT_P1("no vmi -> dcs: %d", sms_deliver->tp_dcs);
      return FALSE;       /* no GSM Default Alphabet */
    case SMS_DCS_DATA_CLASS:
      if (sms_deliver->tp_dcs & 0x4)
      {
        TRACE_EVENT_P1("no vmi -> dcs: %d", sms_deliver->tp_dcs);
        return FALSE;     /* no GSM Default Alphabet */
      }
  }

  if (!sms_deliver->v_tp_ud)
  {
    TRACE_EVENT("no vmi -> no ud");
    return FALSE;       /* not only text present */
  }
  if ( ( sms_deliver->tp_ud.length NEQ 1 ) OR
       ( (sms_deliver->tp_ud.data[0] & 0x7F) NEQ ' ') )
  {
    TRACE_EVENT_P2("no vmi -> ud... length:%d data[0]:%d", 
                    sms_deliver->tp_ud.length, sms_deliver->tp_ud.data[0]);
    return FALSE;       /* no single space */
  }
  
  TRACE_FUNCTION ("CPHS VWI: send to cphs module");

  return TRUE;
}


/*
+-------------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                      |
|                                 ROUTINE : cmhSMS_voice_mail_ind_get_line|
+-------------------------------------------------------------------------+

  PURPOSE : 
*/
LOCAL void cmhSMS_voice_mail_ind_get_data( T_TP_DELIVER *sms_deliver, 
                                           UBYTE        *flag_set,
                                           T_CPHS_LINES *line )
{
  TRACE_FUNCTION("cmhSMS_voice_mail_ind_get_line()");

  /* get flag set, which is send in the first bit of the first
     byte of the originating address number. Due to the decoding
     each byte of the originating address number is now splitted
     into 2 bytes, so that the first 4 bits of the former first 
     byte can be found in byte 1 */
  *flag_set = sms_deliver->tp_oa.num[0] & 0x1;

  /* line is coded in character 1 bit 1 of second byte of GSM originating 
     address based on 7bit default alphabet. In the message indication we 
     get the data in the last bit of the first byte of the orginating address.
     Due to the decoding each byte of the originating address number is now 
     splitted into 2 bytes, so that the last 4 bits of the former first 
     byte can be found in byte 2 */
     
  if (sms_deliver->tp_oa.num[1] & 0x8)

  {
    *line = CPHS_LINE2;
  }
  else
  {
    *line = CPHS_LINE1;
  }
}


/*
+----------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                   |
|                                 ROUTINE : cmhSMS_voice_mail_ind      |
+----------------------------------------------------------------------+

  PURPOSE : 
*/

GLOBAL BOOL cmhSMS_voice_mail_ind( T_sms_sdu *sms_sdu)
{
  T_TP_DELIVER *sms_deliver;
  T_rp_addr rp_addr;
  T_CPHS_LINES line;
  UBYTE flag_set;
  UBYTE *message;
  
  TRACE_FUNCTION("cmhSMS_voice_mail_ind()");

  /* check if cphs is active */
  

  /* check if indication is voice mail indication */
  if ( sms_sdu )
  {   
    message = cmhSMS_decodeMsg(sms_sdu, &rp_addr, SMS_VT_DELIVER);
                 
    if (message EQ NULL) 
      return FALSE;

    if ( message[0] NEQ SMS_VT_DELIVER)
    {
      TRACE_EVENT_P1("wrong VTI = %x", message[0]);
    }

    sms_deliver = (T_TP_DELIVER*)message;

    if ( cphs_check_status() EQ CPHS_OK )
    {
      if ( cmhSMS_check_voice_mail_ind(sms_deliver) )
      {
        cmhSMS_voice_mail_ind_get_data(sms_deliver, &flag_set, &line);

        cphs_voice_mail_ind(flag_set, line);

        return TRUE;
      }
    }
  }
  return FALSE;
}

#endif /* FF_CPHS*/


/*
+----------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)         MODULE  : CMH_SMSF                   |
|                                 ROUTINE : cmhSMS_resetMtDsCnmiParam  |
+----------------------------------------------------------------------+
  PURPOSE : this function resets the <mt> and <ds> parameter for the
            SMS acknowledge in Phase2+ mode (+CNMA).
*/
GLOBAL void cmhSMS_resetMtDsCnmiParam(void)
{
    smsShrdPrm.mtHndl = 0; /* reset <mt> and <ds> param in error case */
    smsShrdPrm.srHndl = 0;

    smsShrdPrm.CNMImt = CNMI_MT_NoSmsDeliverInd;
    smsShrdPrm.CNMIds = CNMI_DS_NoSmsStatRpt;
    /* Implements measure 149 */
    cmhSMS_sendConfigureReq (FALSE);
}

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSS                     |
| STATE   : code             ROUTINE : sAT_PlusCMGWPdu              |
+-------------------------------------------------------------------+

  PURPOSE : This is the internal function which is responsible for 
            storing messages into the mobile station or SIM card.
            AT command which is responsible for writing a short
            message to memory in PDU mode.
*/
GLOBAL BOOL cmhSMS_storePduToSim( T_ACI_CMD_SRC  srcId,
                                      UBYTE          stat,
                                      T_ACI_SM_DATA  *pdu )
{
  T_ACI_RETURN  ret;

  TRACE_FUNCTION ("cmhSMS_storePduToSim()");

  /* check if command executable */
  if(!cmhSMS_checkAccess (srcId, &ret))
  {
    return FALSE;
  }

  {
    PALLOC (mnsms_store_req, MNSMS_STORE_REQ);

    mnsms_store_req -> mem_type  = smsShrdPrm.mem2;
    mnsms_store_req -> rec_num   = CMGW_IDX_FREE_ENTRY;
    mnsms_store_req -> condx     = SMS_CONDX_OVR_NON;
    mnsms_store_req -> status    = stat;

    if ( (pdu->len > 0) AND (pdu->len <= SIM_PDU_LEN) )
    {
      mnsms_store_req->sms_sdu.l_buf = pdu->len * 8;
      mnsms_store_req->sms_sdu.o_buf = 0;
      memcpy (mnsms_store_req->sms_sdu.buf, pdu->data, pdu->len);
    }
    else
    {
      TRACE_FUNCTION ("cmhSMS_storePduToSim() : wrong PDU len");
      PFREE (mnsms_store_req);
      return FALSE;
    }

    PSENDX (SMS, mnsms_store_req);
  }

  smsShrdPrm.smsEntStat.curCmd    = AT_CMD_CMGW;
  smsShrdPrm.owner = (T_OWN)srcId;
  smsShrdPrm.smsEntStat.entOwn    = srcId;
  smsShrdPrm.uiInternalSmsStorage = srcId;

  return TRUE;
}

/*
+--------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CMH_SMSF                   |
| STATE   : code                ROUTINE : cmhSMS_removeStatusRFUBits |
+--------------------------------------------------------------------+

  PURPOSE :  ACI-SPR-17004: Method for removing of SMS RFU status 
  bits as defined by GSM 11.11 section 9.3
  
*/
GLOBAL void cmhSMS_removeStatusRFUBits  ( UBYTE* status )
{
  TRACE_FUNCTION("cmhSMS_removeStatusRFUBits()");

  /* See GSM 11.11 section 10.5.3 for position of RFU bits in status */

  /* test the pattern of the three lowest bits, match for "101" */ 
  if ((*status & 0x07) EQ 0x05)
  {
    /* set the highest three bits to 0 */
    *status &= 0x1F; 
  } 
  else
  {
    /* set the highest five bits to 0 */
    *status &= 0x07; 
  }

}

/*
+-------------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CMH_SMSF                        |
| STATE   : code                ROUTINE : cmhSMS_convertDeliverStatusToACI|
+-------------------------------------------------------------------------+

  PURPOSE :  converts the SMS delivery status to ACI CPRSM status.
  
*/
GLOBAL  T_ACI_CPRSM_MOD cmhSMS_convertDeliverStatusToACI ( UBYTE status )
{
  T_ACI_CPRSM_MOD mode;
  
  TRACE_FUNCTION("cmhSMS_convertDeliverStatusToACI()");

  switch (status)
  {
    case SMS_DELIVER_STATUS_PAUSE:
      mode = CPRSM_MOD_Pause;
      break;
    case SMS_DELIVER_STATUS_RESUME:      
      mode = CPRSM_MOD_Resume;
      break;
    default:
      mode = CPRSM_MOD_NotPresent;
  }  
  return mode;
}

#ifdef FF_CPHS_REL4
/*
+-------------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CMH_SMSF                        |
| STATE   : code                ROUTINE : cmhSMS_chk_WtngInd              |
+-------------------------------------------------------------------------+

  PURPOSE : This function expect an already decoded SMS in the T_TP_DELIVER 
            format and checks if it is a "special SMS" (refer to TS 23.040, 
            chpt. 9.2.3.24.2).

*/
LOCAL BOOL cmhSMS_chk_WtngInd( T_TP_DELIVER *pSms )
{

 TRACE_FUNCTION("cmhSMS_chk_WtngInd");
  return ( (pSms->tp_udhi)                        AND /* it is an UDH message */
           (pSms->v_tp_udh_inc)                   AND /* UDH successfuly decoded */
           (pSms->tp_udh_inc.tp_udh.c_data >= 4)  AND /* min len of special SMS */
           (pSms->tp_udh_inc.tp_udh.data[0] EQ 0x01)
         ); 
}


/*
+-------------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)       MODULE  : CMH_SMSF                        |
| STATE   : code                ROUTINE : cmhSMS_chk_SpclMsg              |
+-------------------------------------------------------------------------+

  PURPOSE : This function checks if the received SMS is a special sms which
  indicates the message waiting status.If so,the message will be  processed
  and TRUE will be returned,indicating that the message was already handled.
  If it is no special message , the function will returns FALSE causing the
  SMS to be treated in the common way.

*/

GLOBAL BOOL cmhSMS_chk_SpclMsg( T_MNSMS_MESSAGE_IND *mnsms_message_ind )
{
  BOOL res    = FALSE ;
  T_MSG_WAITING_TYPE msgType = MSG_WAITING_TYPE_INVALID;
  U8 *ptr;
  T_TP_DELIVER *smDlvr;

  TRACE_FUNCTION( "cmhSMS_chk_SpclMsg()" );

  if(!psaSIM_ChkSIMSrvSup( SRV_No_54 ))
  {
    return res;
  }

  if (&mnsms_message_ind->sms_sdu)
  {
    T_rp_addr rpAddr;
    UBYTE     *pMsg;

    pMsg = cmhSMS_decodeMsg( &mnsms_message_ind->sms_sdu, &rpAddr, SMS_VT_DELIVER );
    smDlvr = (T_TP_DELIVER *)pMsg;

    if (pMsg)
    {
      if (pMsg[0] NEQ SMS_VT_DELIVER)
      {
        TRACE_EVENT_P1( "wrong VTI = %x", (int)pMsg[0] );
      }
      
      /* Check the reqired fields in the SMS to qaulify for Special Message */

      if (cmhSMS_chk_WtngInd( smDlvr ))
      {

        /* For Loop: Decode the SMS properly as ,more than one type of message
           can   be   indicated    within   one   SMS  message. A  varible for 
           tp_udh_inc.tp_udh.data  has  been  avoided ,   therefore  For  loop 
           seems to be lengthy,
        */
        for( ptr = smDlvr->tp_udh_inc.tp_udh.data ;
             ptr < &smDlvr->tp_udh_inc.tp_udh.data[smDlvr->tp_udh_inc.tp_udh.c_data ];
             ptr +=(ptr[1] + 2 ))
             {
               /* Filling the Message Type */

               msgType  = (ptr[2] & 0x03);             /* see TS 23.040 */

               /* Update Status field in EF-MWIS according to the values already
                  present in the SIM and the current values in the recieved  SMS.
                  Also  if  the count for any type of Special SMS is  ZERO  then
                  also update the status.
               */
               if( (!(smsShrdPrm.MWISdata.mwiStat >> msgType & 1U)) OR (ptr[3] EQ 0) )
                 {
                   smsShrdPrm.MWISdata.mwiStat ^= 1U << msgType;
                 }

               /* Filling the count for specfic type of SMS  */

               switch ( msgType )
               {
                 case MSG_WAITING_TYPE_VOICE :
                   smsShrdPrm.MWISdata.mwis_count_voice = ptr[3];
                   break;
                 case MSG_WAITING_TYPE_FAX :
                   smsShrdPrm.MWISdata.mwis_count_fax = ptr[3];
                   break;
                 case MSG_WAITING_TYPE_EMAIL :
                   smsShrdPrm.MWISdata.mwis_count_email = ptr[3];
                   break;
                 case MSG_WAITING_TYPE_OTHER :
                   smsShrdPrm.MWISdata.mwis_count_other = ptr[3];
                   break;
                 default:
                   TRACE_EVENT("INVALID MESSAGE TYPE");
                   return FALSE;
               }
             }

             /* Writing decoded data to EF-MWIS  */

             if(cmhSIM_WrMwis(CMD_SRC_NONE,MWIS_MOD_Write,1,
                &smsShrdPrm.MWISdata) NEQ AT_EXCT )
             {
               TRACE_EVENT(" Error in Sending the Sim Update Request ");
             }

        /* If message was stored we need to indicate this, too */

        if (mnsms_message_ind->rec_num NEQ SMS_RECORD_NOT_EXIST) 
        {
          cmhSMS_SMSMemory( mnsms_message_ind );
        }  
        res = TRUE; /* message processed, nothing left to do */
      }
    }
  }
  return res;
}
#endif
/* Implements Measure # 73 */

/*
+-------------------------------------------------------------------+
| PROJECT : GSM-PS (6147)    MODULE  : CMH_SMSF                     |
|                            ROUTINE : cmhSMS_findMessageIds        |
+-------------------------------------------------------------------+
  PARAMETERS  : lower_mid - lower message id
                upper_mid - upper message id
  RETURN      : TRUE if message has been found, else FALSE

  PURPOSE : Find message ids based on the mids given as parameters and 
            update smsShrdPrm.cbmPrm.cbmFoundIds based on the same.

*/
LOCAL BOOL cmhSMS_findMessageIds (USHORT lower_mid, USHORT upper_mid)
{
  TRACE_FUNCTION("cmhSMS_findMessageIds()");
  /*
   * If the msg ids are same that in FFS and SIM, then restore else reset
   * to default values
   */
  if (smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2] EQ lower_mid
    AND smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2 + 1] EQ upper_mid)
  {
    smsShrdPrm.cbmPrm.cbmFoundIds++;
  }
  else
  {
    cmhSMS_clearCbmPrm();     
    return FALSE;
  }
  return TRUE;
}

/* Implements Measure # 126 */
/*
+---------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF                  |
| STATE   : code                        ROUTINE : cmhSMS_processOrigDestAddr|
+---------------------------------------------------------------------------+
  PARAMETERS  : sm - Structure into which the data is filled. 
                rp_addr - RP Address used for filling sm
                tp_addr - destination or origination address that has to be 
                          filled in sm  
  RETURN      : None

  PURPOSE : Processes originator address and converts it into 8 bit or string
            format as requried

*/
LOCAL void cmhSMS_processOrigDestAddr (T_ACI_CMGL_SM  *sm, 
                                       T_rp_addr      *rp_addr,
                                       T_tp_da        *tp_addr)
{
  TRACE_FUNCTION("cmhSMS_processOrigDestAddr()");
  /*
   *-----------------------------------------------------------------
   * process address
   *-----------------------------------------------------------------
   */
  if (tp_addr->ton EQ SMS_TON_ALPHANUMERIC)
  {
    UBYTE i,j = 0;
    UBYTE dest_len;
    CHAR address_buf[MAX_SMS_ADDR_DIG/2];

    for (i = 0 ; i < tp_addr->digits ; i=i+2)
    {
      address_buf[j] = (UBYTE)(tp_addr->num[i+1] << 4) + (UBYTE)(tp_addr->num[i]);
      j++;
    }

    if( tp_addr->digits % 2 )
    {
      address_buf[j-1] = address_buf[j-1] & 0x0f;
    }

    dest_len = utl_cvt7To8 ( (UBYTE*)address_buf, j, (UBYTE*)sm->adress, 0);
    sm -> adress[dest_len] = '\0';

    if( (tp_addr->digits % 2) AND (dest_len + 3) % 8 >= 4 )
      sm -> adress[dest_len--] = '\0';
    else
      sm -> adress[dest_len] = '\0';

  }
  else
  {
    cmhSMS_getAdrStr ( sm -> adress,
                       MAX_SMS_NUM_LEN - 1,
                       tp_addr->num,
                       tp_addr->digits );
  }
  sm -> toa.ton = cmhSMS_getTon ( tp_addr->ton );
  sm -> toa.npi = cmhSMS_getNpi ( tp_addr->npi );
  /*
   *-----------------------------------------------------------------
   * process service center address
   *-----------------------------------------------------------------
   */
  cmhSMS_getAdrStr ( sm -> sca,
                     MAX_SMS_NUM_LEN - 1,
                     rp_addr->num,
                     rp_addr->c_num);

  sm -> tosca.ton = cmhSMS_getTon ( rp_addr->ton );
  sm -> tosca.npi = cmhSMS_getNpi ( rp_addr->npi );

  /*
   *-----------------------------------------------------------------
   * process alphanumerical phonebook entry
   *-----------------------------------------------------------------
   */
  psaCC_phbMfwSrchNumPlnTxt ( sm -> adress, &sm -> alpha );
}

/* Implements Measure # 149 */
/*
+---------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF                  |
| STATE   : code                        ROUTINE : cmhSMS_sendConfigureReq   |
+---------------------------------------------------------------------------+
  PARAMETERS  : v_cmms_val - Set to TRUE if cmms_mode and tmms_val has to be 
                             filled.
  RETURN      : None

  PURPOSE : Sends mnsms_configure_req to inform the SMS entity 
            about the parameter changes. v_cmms_val is TRUE if cmms_mode and 
            tmms_val has to be filled.

*/
GLOBAL void cmhSMS_sendConfigureReq (BOOL v_cmms_val)
{
  TRACE_FUNCTION("cmhSMS_sendConfigureReq()");
  { /* inform the SMS entity about the parameter changes */
    PALLOC (mnsms_configure_req, MNSMS_CONFIGURE_REQ);

    /* fill in primitive parameter: command request */
    mnsms_configure_req -> pref_mem_3 = smsShrdPrm.mem3;
    mnsms_configure_req -> mt         = smsShrdPrm.mtHndl;
    mnsms_configure_req -> ds         = smsShrdPrm.srHndl;
    mnsms_configure_req -> mhc        = (smsShrdPrm.CSMSservice NEQ CSMS_SERV_GsmPh2Plus)
                                        ? SMS_MHC_PH2 : SMS_MHC_PH2PLUS;
    mnsms_configure_req->v_cmms_mode = mnsms_configure_req->v_tmms_val = 
                                                              v_cmms_val;
    if(v_cmms_val)
    {
      mnsms_configure_req -> cmms_mode = smsShrdPrm.CMMSmode;
      mnsms_configure_req->tmms_val = CMMS_MODE_TIMER_VAL;
    }

    PSENDX (SMS, mnsms_configure_req);
  }
}

/* Implements Measure # 110 */
/*
+---------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF                  |
| STATE   : code                        ROUTINE : cmhSMS_cpyMsgIndReadCnf   |
+---------------------------------------------------------------------------+
  PARAMETERS  : sm - Structure into which the data is filled.
                status - SMS record status
                sms_sdu - SMS SDU from which data has to be filled in sm
                rec_num - Record number of the SMS
  RETURN      : BOOL value indicating the status returned by cmhSMS_cpyDeliver 
                or cmhSMS_cpySubmit

  PURPOSE : handles a message indication or a read cnf

*/
GLOBAL BOOL cmhSMS_cpyMsgIndReadCnf (T_ACI_CMGL_SM  * sm, 
                                     UBYTE          *status, 
                                     T_sms_sdu      *sms_sdu,
                                     UBYTE          rec_num)
{
  BOOL ret = FALSE;
  TRACE_FUNCTION("cmhSMS_cpyMsgIndReadCnf()");

  /*
   *-----------------------------------------------------------------
   * decode SMS-DELIVER or SMS-SUBMIT
   *-----------------------------------------------------------------
   */

  /* 
   * ACI-SPR-17004: set RFU bits of status to 0 if present since these 
   * should be ignored in a GSM session (GSM 11.11 section 9.3)
   */
  cmhSMS_removeStatusRFUBits( status );  
   
  switch (*status)
  {
    case SMS_RECORD_REC_UNREAD:
    case SMS_RECORD_REC_READ:
      ret = cmhSMS_cpyDeliver ( sm, sms_sdu );
      break;
    case SMS_RECORD_STO_UNSENT:
    case SMS_RECORD_STO_SENT:
    /* ACI-SPR-17003: Handle unsupported statuses */  
    case SMS_RECORD_STAT_UNRCVD: 
    case SMS_RECORD_STAT_UNSTRD:
    case SMS_RECORD_STAT_STRD:            
      ret = cmhSMS_cpySubmit ( sm, sms_sdu );
      break;
    /* 21.Mar.2003 currently not used by SMS entity */
    /* 
     * case SMS_RECORD_INVALID: 
     *  ret = FALSE;
     *  break;
     */
    default:
      TRACE_EVENT("incorrect status");
  }

  /*
   *-----------------------------------------------------------------
   * process status (convert from PSA type to CMH type)
   *-----------------------------------------------------------------
   */
  if (sm->stat NEQ SMS_STAT_Invalid)
  {
     cmhSMS_getStatCmh ( *status, &sm -> stat );
  }

  /*
   *-----------------------------------------------------------------
   * process message reference
   *-----------------------------------------------------------------
   */
  sm -> msg_ref = rec_num;

  /*
   *-----------------------------------------------------------------
   * process tp_status
   *-----------------------------------------------------------------
   */
  sm ->tp_status = (UBYTE) -1;
  
  return (ret);
}

/* Implements Measure # 9 */
/*
+---------------------------------------------------------------------------+
| PROJECT : GSM-F&D (8411)              MODULE  : CMH_SMSF                  |
| STATE   : code                        ROUTINE : cmhSMS_clearCbmPrm        |
+---------------------------------------------------------------------------+
  PARAMETERS  : None
  RETURN      : None

  PURPOSE : Resets smsShrdPrm.cbmPrm to default values

*/
LOCAL void cmhSMS_clearCbmPrm (void)
{
  TRACE_FUNCTION("cmhSMS_clearCbmPrm()");

  smsShrdPrm.cbmPrm.cbmMode = CBCH_ACCEPT;
  memset (smsShrdPrm.cbmPrm.msgId, DEF_MID_RANGE,
          sizeof (smsShrdPrm.cbmPrm.msgId));
  memset (smsShrdPrm.cbmPrm.dcsId, DEF_DCS_RANGE, 
          sizeof(smsShrdPrm.cbmPrm.dcsId));
}
/*==== EOF ========================================================*/