view src/aci2/aci/cmh_smsf.c @ 662:8cd8fd15a095

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

/*
+-----------------------------------------------------------------------------
|  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 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

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

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

/*==== 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_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;
}

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

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

  switch (dcs & 0xF0)
  {
    case( 0x10 ):
      if (dcs EQ 0x11)
        alphabet = 2;
      break;

    case( 0x70 ):
    case( 0x60 ):
    case( 0x50 ):
    case( 0x40 ):
      alphabet = (dcs & 0x0C) >> 2;
      /* According to 03.38, "Any reserved codings shall be assumed 
       * to be the GSM 7 bit default alphabet by a receiving entity".
       */
      if (alphabet EQ 3)
        alphabet = 0;
      break;

    case( 0xF0 ):
      alphabet = (dcs & 0x04) >> 2;
      break;
  }

  return alphabet;
}

/*
+--------------------------------------------------------------------+
| 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 = cmhSMS_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 & 0xFF)); /* 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()");

  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, 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(!cmh_IsVldCmdSrc (srcId) AND (srcId NEQ OWN_SAT))
  {
    ACI_ERR_DESC( ACI_ERR_CLASS_Ext, EXT_ERR_Parameter );
    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_RET         ffs_ret;
  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_MAX;
        for (i=0; i < OWN_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;
  T_FFS_SIZE        ffs_size;
#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.smsEntStat.entOwn = smsShrdPrm.owner = 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;
    if (access NEQ 0)
      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,
                                  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,
                                  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,
                                  SIM_CBMI, 0, 255,
                                  NULL, cmhSMS_InitSMSP);
    }
#ifdef SIM_TOOLKIT
    else if ((psaSIM_ChkSIMSrvSup( SRV_DtaDownlCB )) AND 
             smsShrdPrm.owner EQ OWN_SAT )
    {
      smsShrdPrm.prmRdSeq = SMS_READ_SIM_CBMID;
      ret = cmhSIM_ReadTranspEF (CMD_SRC_NONE, cmd,
                                  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;
    if (access NEQ 0)
      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, 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, 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, SIM_CBMI,
                                  0, smsShrdPrm.cbmPrm.cbmSIMmaxId,
                                  NULL, cmhSMS_RdCnfCRES);
    }
  }
  if (ret NEQ AT_EXCT)
  {
    smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE;
    smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_NONE;

    smsShrdPrm.cbmPrm.cbchOwner = srcId;
    psaMMI_Cbch();
    smsShrdPrm.cbmPrm.cbchOwner = OWN_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.smsEntStat.entOwn = smsShrdPrm.owner = 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;
  if (access NEQ 0)
    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, 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, 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, SIM_CBMI,
                                 0, (UBYTE)(smsShrdPrm.cbmPrm.cbmSIMmaxId * 2),
                                 data, cmhSMS_WrCnfCSAS);
  }
  if (ret NEQ AT_EXCT)
  {
    smsShrdPrm.smsEntStat.curCmd = AT_CMD_NONE;
    smsShrdPrm.smsEntStat.entOwn = smsShrdPrm.owner = OWN_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)
    {
      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));
      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_
   
        /*
         * 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
        {
          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));

          smsShrdPrm.cbmPrm.cbmFoundIds = 0;
          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)
    {
      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));
      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_
         /*
          * 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 mid
          AND smsShrdPrm.cbmPrm.msgId[smsShrdPrm.cbmPrm.cbmFoundIds * 2 + 1] EQ mid)
        {
          smsShrdPrm.cbmPrm.cbmFoundIds++;
        }
        else
        {
          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));

          smsShrdPrm.cbmPrm.cbmFoundIds = 0;
          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_id[i] EQ SIM_SMSP OR
         fu->file_id[i] EQ SIM_CBMI OR
         fu->file_id[i] EQ SIM_CBMIR OR
         fu->file_id[i] EQ SIM_CBMID))
    {
      found = TRUE;
    }
    if (fu->file_id[i] 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 (OWN_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 */
        char  *errstr;

        switch (ccd_err)
        {
          case ERR_NO_MORE_ERROR:   errstr= "the end of the error list is reached";break;
          case ERR_INVALID_CALC:    errstr= "calculation of the element repeat value failed";break;
          case ERR_PATTERN_MISMATCH:errstr= "a bit pattern was not expected";break;
          case ERR_COMPREH_REQUIRED:errstr= "check for comprehension required failed";break;
          case ERR_IE_NOT_EXPECTED: errstr= "an information element was not expected";break;
          case ERR_IE_SEQUENCE:     errstr= "wrong sequence of information elements";break;
          case ERR_MAX_IE_EXCEED:   errstr= "maximum amount of repeatable information elements has exceeded";break;
          case ERR_MAX_REPEAT:      errstr= "a repeatable element occurs too often in the message";break;
          case ERR_MAND_ELEM_MISS:  errstr= "a mandatory information element is missing";break;
          case ERR_INVALID_MID:     errstr= "the message ID is not correct";break;
          case ERR_INVALID_TYPE:    errstr= "the information element is not a spare padding";break;
          case ERR_EOC_TAG_MISSING: errstr= "indefinite length is specified for the ASN.1-BER but the end tag is missing";break;
          case ERR_INTERNAL_ERROR:  errstr= "an internal CCD error occured ";break;
          default:                  errstr= "unknown error";break;
        }
        if (ccdRet EQ ccdError)
        {
          TRACE_EVENT_P2 ("ERR: %u %s", ccd_err, errstr);
        }
        else if (ccdRet EQ ccdWarning)
        {
          TRACE_EVENT_P2 ("WRN: %u %s", ccd_err, errstr);
        }
#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;
      sim_buf.l_tpdu = (sizeof(BUF_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
   *-----------------------------------------------------------------
   */
  if (sms_deliver->tp_oa.ton EQ SMS_TON_ALPHANUMERIC)
  {
    UBYTE i,j = 0;
    UBYTE dest_len;
    CHAR address_buf[MAX_SMS_ADDR_DIG/2];

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

    dest_len = utl_cvt7To8 ( (UBYTE*)address_buf, j, (UBYTE*)sm->adress, 0);
    sm -> adress[dest_len] = '\0';
  }
  else
    cmhSMS_getAdrStr ( sm -> adress,
                       MAX_SMS_NUM_LEN - 1,
                       sms_deliver->tp_oa.num,
                       sms_deliver->tp_oa.digits );

  sm -> toa.ton = cmhSMS_getTon ( sms_deliver->tp_oa.ton );
  sm -> toa.npi = cmhSMS_getNpi ( sms_deliver->tp_oa.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 );

  /*
   *-----------------------------------------------------------------
   * 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
   *-----------------------------------------------------------------
   */
  if (sms_submit->tp_da.ton EQ SMS_TON_ALPHANUMERIC)
  {
    UBYTE i,j = 0;
    UBYTE dest_len;
    CHAR address_buf[MAX_SMS_ADDR_DIG/2];

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

    dest_len = utl_cvt7To8 ( (UBYTE*)address_buf, j, (UBYTE*)sm->adress, 0);
    sm -> adress[dest_len] = '\0';
  }
  else
    cmhSMS_getAdrStr ( sm -> adress,
                       MAX_SMS_NUM_LEN - 1,
                       sms_submit->tp_da.num,
                       sms_submit->tp_da.digits );

  sm -> toa.ton = cmhSMS_getTon ( sms_submit->tp_da.ton );
  sm -> toa.npi = cmhSMS_getNpi ( sms_submit->tp_da.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 );

  /*
   *-----------------------------------------------------------------
   * 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);
}


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

  PURPOSE : handles a message indication

*/
GLOBAL BOOL cmhSMS_cpyMsgInd ( T_ACI_CMGL_SM  * sm, 
                        T_MNSMS_MESSAGE_IND * mnsms_message_ind)
{
  BOOL ret = FALSE;
  TRACE_FUNCTION("cmhSMS_cpyMsgInd()");

  /*
   *-----------------------------------------------------------------
   * 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( &mnsms_message_ind->status );  
   
  switch (mnsms_message_ind->status)
  {
    case SMS_RECORD_REC_UNREAD:
    case SMS_RECORD_REC_READ:
      ret = cmhSMS_cpyDeliver ( sm, &mnsms_message_ind->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, &mnsms_message_ind->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 ( mnsms_message_ind->status, &sm -> stat );
  }

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

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


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

  PURPOSE : handles a read confirmation

*/
GLOBAL BOOL cmhSMS_cpyReadCnf ( T_ACI_CMGL_SM  * sm, T_MNSMS_READ_CNF * mnsms_read_cnf )
{
  BOOL ret = FALSE;
  TRACE_FUNCTION("cmhSMS_cpyReadCnf()");

  /* 
   * 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( &mnsms_read_cnf->status );

  switch (mnsms_read_cnf->status)
  {
    case SMS_RECORD_REC_UNREAD:
    case SMS_RECORD_REC_READ:
      ret = cmhSMS_cpyDeliver ( sm, &mnsms_read_cnf->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, &mnsms_read_cnf->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 (PSA format -> CMH format)
   *-----------------------------------------------------------------
   */
  if (sm->stat NEQ SMS_STAT_Invalid)
  {
     cmhSMS_getStatCmh ( mnsms_read_cnf->status, &sm -> stat );
  }

  /*
   *-----------------------------------------------------------------
   * process message reference
   *-----------------------------------------------------------------
   */
  sm -> msg_ref = mnsms_read_cnf->rec_num;
  
  /*
   *-----------------------------------------------------------------
   * process tp_status 
   *-----------------------------------------------------------------
   */
  sm ->tp_status = -1;
  
  return (ret);
}


/*
+--------------------------------------------------------------------+
| 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 GSM originating address.
     the originating address of T_TP_DELIVER is allready decoded
     so that this information is to be found in byte 3 of the
     originating address number */

  if (sms_deliver->tp_oa.num[2] & 0x1)
  {
    *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 = 0;
    smsShrdPrm.CNMIds = 0;
    { /* 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 = FALSE;
      mnsms_configure_req->v_tmms_val = FALSE;

      PSENDX (SMS, mnsms_configure_req);
    }
}

/*
+-------------------------------------------------------------------+
| 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.smsEntStat.entOwn    = smsShrdPrm.owner = 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;
}

/*==== EOF ========================================================*/