view src/aci2/aci/phb_sim.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 :  MMI-Framework (8417)
|  Modul   :  PHB
+----------------------------------------------------------------------------- 
|  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 modul contains the functions to establish the phone book.
+----------------------------------------------------------------------------- 
*/ 

#ifdef TI_PS_FFS_PHB

#include "aci_all.h"
#include "aci_cmh.h"
#include "aci_mem.h"

#include "phb_sim.h"
#include "phb_aci.h"

#include "ffs/ffs.h"

#ifdef SIM_TOOLKIT
#include "psa.h"
#include "psa_sim.h"
#include "psa_cc.h"
#include "psa_sat.h"
#endif /* #ifdef SIM_TOOLKIT */

#include "cmh.h"
#include "cmh_phb.h"
#include "pcm.h"

/*
 * Constants and enumerations
 */
 
#define MAX_ECC_RCD                    5
#define FFS_IMSI_SIZE                  8
#define MAX_EXTNS_PER_RECORD  9
#define MAX_ELEM_FILES               15
#define SIM_MAX_RECORD_SIZE   256 /* Maximum size of a SIM record */
#define RDM_DATA_FILE_ID          (0xff04)          /* File ID to store data related to LDN, LMN and LRN Phonebooks */
#define SIZE_DATA_DATE_TIME   12
#define MAX_EXT_RECORDS           10

typedef enum
{
  DECREMENT = -1,
  INCREMENT
} T_PHB_EXT_REF_TYPE;
  
/*
 * Type definitions
 */
 
typedef struct
{
	/* Handle for the Database */ 
  int db_handle;

  /* Maximum number of records */
  UBYTE max_record[MAX_PHONEBOOK];

  /* Number of used records */
  UBYTE used_record[MAX_PHONEBOOK];

  /* Records sizes */
  USHORT record_size[MAX_PHONEBOOK];
 
} T_PHB_SIM_DATA;

#define RDM_PHB_DATA_SIZE 6

/* ECC records */
T_PHB_ECC_RECORD phb_ecc_element[MAX_ECC_RCD];

LOCAL T_PHB_SIM_DATA pbs_data;

/* Global arrays to hold Reference count for Extension records. */
UBYTE ext1_ref_count[MAX_EXT_RECORDS], ext2_ref_count[MAX_EXT_RECORDS];
UBYTE ext3_ref_count[MAX_EXT_RECORDS], ext4_ref_count[MAX_EXT_RECORDS];
UBYTE ext5_ref_count[MAX_EXT_RECORDS];
UBYTE ext_lmn_ref_count[MAX_EXT_RECORDS], ext_lrn_ref_count[MAX_EXT_RECORDS];

/* Prototypes for search and compare functions */
int pb_sim_search_alpha_func(ULONG flags, const UBYTE *key, int db_handle, USHORT field_id, USHORT rec_num);
int pb_sim_search_num_func(ULONG flags, const UBYTE *key, int db_handle, USHORT field_id, USHORT rec_num);
int pb_sim_alpha_cmp (int db_handle, USHORT field_id, USHORT recno_1, USHORT recno_2, ULONG flags);
int pb_sim_number_cmp (int db_handle, USHORT field_id,USHORT recno_1,USHORT recno_2, ULONG flags);
/* 
 * Prototypes for local functions
 */

LOCAL void pb_sim_read_eeprom_ecc (void);
LOCAL int pb_sim_nibblecopy (UBYTE dest[], int destlen, UBYTE src[], int count);
LOCAL void pb_sim_revString(char *);
LOCAL void pb_sim_read_ext(UBYTE *buffer, T_PHB_RECORD *entry);
LOCAL void pb_sim_prepare_ext_data(UBYTE *ext_data, int ext_count, UBYTE *number, UBYTE no_len, UBYTE *subaddr);
LOCAL USHORT pb_sim_get_field_id (T_PHB_TYPE type);
LOCAL USHORT pb_sim_get_ext_file (T_PHB_TYPE type);
LOCAL USHORT pb_sim_get_ext_file_id (USHORT field_id);
LOCAL USHORT pb_sim_get_size_except_tag (USHORT field_id);

LOCAL int pb_sim_cmpString ( UBYTE* cur_tag, UBYTE* check_tag, UBYTE cmpLen );
LOCAL void pb_sim_cvt_alpha_for_cmp ( UBYTE* entry_tag, UBYTE* cur_tag, UBYTE len );
LOCAL int pb_sim_cmp2Bytes(UBYTE *s1, UBYTE *s2, UBYTE len, UBYTE flag);
LOCAL T_PHB_RETURN pb_sim_update_extn_records(USHORT ext_field_id, USHORT rec_num, T_PHB_EXT_REF_TYPE ref_type);  
LOCAL T_PHB_RETURN pb_sim_read_ext_record_for_delete(T_PHB_TYPE type, USHORT field_id, USHORT db_recno);

/*
+----------------------------------------------------------------------+
| PROJECT: MMI-Framework                MODULE : PHB                   |
| STATE  : code                         ROUTINE: pb_sim_init       |
+----------------------------------------------------------------------+

  PURPOSE :   Initializes internal data structures for SIM Phonebook.
*/

void pb_sim_init (void)
{
  USHORT i;
  
  TRACE_FUNCTION ("pb_sim_init()");
  db_init();

  /* Initialise the data structures. */

  /* Initialise ECC Phonebook to contain no records. */
  for(i = 0; i < MAX_ECC_RCD; i++)
    phb_ecc_element[i].phy_idx = 0;
  
  return;
}

/*
+----------------------------------------------------------------------+
| PROJECT: MMI-Framework                MODULE : PHB                   |
| STATE  : code                         ROUTINE: pb_sim_exit       |
+----------------------------------------------------------------------+

  PURPOSE :   This function is called by pb_exit() to inform the SIM part 
              of the phonebook to shut down.
*/
void pb_sim_exit (void)
{
  TRACE_FUNCTION ("pb_sim_exit()");

  db_exit();

  return;
}

/*
+----------------------------------------------------------------------+
| PROJECT: MMI-Framework                MODULE : PHB                   |
| STATE  : code                         ROUTINE: pb_sim_set_ecc       |
+----------------------------------------------------------------------+

  PURPOSE :   The emergency call numbers are read from SIM card and 
              written to FFS.
*/
T_PHB_RETURN pb_sim_set_ecc (UBYTE ecc_len, const UBYTE *sim_ecc)
{
  USHORT ecc_rec_num;
  UBYTE  *data_ptr;
  
  TRACE_FUNCTION ("pb_sim_set_ecc()");

  /* Initialise used records for ECC. */ 
  pbs_data.used_record[ECC] = 0;
  
  /* if SIM ECC data is not empty, copy SIM ECC data to phonebook */
  if ( ecc_len NEQ 0)
  {
    data_ptr         = ( UBYTE *) sim_ecc;
    pbs_data.max_record[ECC] = (SHORT)((ecc_len/ECC_NUM_LEN) > MAX_ECC_RCD)? MAX_ECC_RCD: ecc_len/ECC_NUM_LEN;
    pbs_data.record_size[ECC] = ECC_NUM_LEN;

    /* Store ECC into RAM, since ECC records will be less in number. */
    for (ecc_rec_num = 0; ecc_rec_num < MAX_ECC_RCD; ecc_rec_num++)
    {
      if(*data_ptr NEQ 0xff)
      {
        memset(&phb_ecc_element[ecc_rec_num],0,sizeof(T_PHB_ECC_RECORD));
        phb_ecc_element[ecc_rec_num].phy_idx = ecc_rec_num + 1;
        memcpy(phb_ecc_element[ecc_rec_num].number, data_ptr, ECC_NUM_LEN);
        data_ptr += ECC_NUM_LEN;
        (pbs_data.used_record[ECC])++;
      }
    }
  }
  else
  {
    pb_sim_read_eeprom_ecc();
  }

  return PHB_OK;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_create_ef          |
+--------------------------------------------------------------------+

    PURPOSE : Creates a SIM elementary file. 

*/
T_PHB_RETURN pb_sim_create_ef  (USHORT ef, USHORT record_size, USHORT records)
{
  T_DB_INFO_FIELD field_info;
  T_DB_TYPE db_type;
  int db_result;

  TRACE_FUNCTION ("pb_sim_create_ef()");

  TRACE_EVENT_P1("Elementary file ID = %x",ef);
  db_result = db_info_field(pbs_data.db_handle, ef, &field_info);

  /* Check whether file already exists. */
  if(db_result EQ DB_OK)
  {
    /* Check for Record size and No. of records in the present field. */
    if((field_info.record_size EQ record_size) AND (field_info.num_records EQ records))
      return PHB_OK;  /* Preserve the existing field. */
    else
    {  
      if(pb_sim_remove_ef(ef) EQ PHB_FAIL)  /* Remove the existing file and recreate the field. */
				return PHB_FAIL;
    }
  }
  
	/* Set DB_TYPE depending on the Elementary file. */ 
  switch(ef)
  {
    case SIM_ADN:
    case SIM_FDN:          
    case SIM_BDN:  
    case SIM_SDN:
    case SIM_EXT1:
    case SIM_EXT2:
    case SIM_EXT3:
    case SIM_EXT4:
    case SIM_LND:         
    case SIM_OCI:
    //case SIM_ICI:
    case FFS_LRN:
    case FFS_LMN:
    case FFS_EXT_LRN:
    case FFS_EXT_LMN:
    case SIM_EXT5:
      db_type = DB_FREELIST;
      break;
        
    case SIM_MSISDN:          
    case SIM_IMSI:
      db_type = DB_UNMANAGED;
      break;

    default:
      TRACE_ERROR("Invalid ef passed to pb_sim_create_ef()");
      return PHB_FAIL;        
  }

  db_result = db_create_field(pbs_data.db_handle, db_type, ef, record_size, records);

  if(db_result EQ DB_OK)
    return PHB_OK;

  /* Return PHB_FAIL since DB has failed to create File.  */
  return PHB_FAIL;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_write_ef          |
+--------------------------------------------------------------------+

    PURPOSE : Writes entry_size bytes content of buffer at index to the elementary file ef.

*/
T_PHB_RETURN pb_sim_write_ef (USHORT ef, USHORT phy_recno,
                                         USHORT entry_size, const UBYTE *buffer,
                                         BOOL *changed, USHORT *ext_record_ef, UBYTE  *ext_record_no)
{
  int i;
  T_DB_CHANGED records_affected;

  TRACE_FUNCTION ("pb_sim_write_ef()");

  /* Initialise changed to FALSE. */
  *changed = FALSE;

  /* Check for extension records. */
  switch (ef)
  {
    case SIM_ADN:
    case SIM_MSISDN:
    case SIM_LND:
      *ext_record_ef = SIM_EXT1;
      *ext_record_no = buffer[entry_size - 1];
      break;

    case SIM_FDN:
      *ext_record_ef = SIM_EXT2;
      *ext_record_no = buffer[entry_size - 1];
      break;

    case SIM_SDN:
      *ext_record_ef = SIM_EXT3;
      *ext_record_no = buffer[entry_size - 1];
      break;

    case SIM_BDN:
      *ext_record_ef = SIM_EXT4;
      *ext_record_no = buffer[entry_size - 1];
      break;

    case FFS_LRN:
    case FFS_LMN:
    case SIM_OCI: /* Release 1999 and above 31.102 clause 4.2.34 */
      *ext_record_ef = SIM_EXT5;
      *ext_record_no = buffer[entry_size - 15]; // Jirli, please check, 14 instead of 15?
      break;

    case SIM_EXT1:  /* Extension records can reference other extension records */
    case SIM_EXT2:
    case SIM_EXT3:
    case SIM_EXT4:
    case SIM_EXT5:
    case FFS_EXT_LRN:
    case FFS_EXT_LMN:
      *ext_record_ef = ef;
      *ext_record_no = buffer[entry_size - 1];
      break;

    default:
      *ext_record_ef = 0;
      *ext_record_no = 0;
  }

  /* Record is not referring any extensions. So set ef and record_no to ZERO. */ 
  if (*ext_record_no EQ 0xff)
  {
    *ext_record_ef = 0;
    *ext_record_no = 0;
  }

  if (buffer[0] NEQ 0xFF)
  {
    /* Write record into FFS */
    if(db_write_record(pbs_data.db_handle, ef, phy_recno, 0, entry_size, buffer) > DB_OK)
    {
      if(db_read_change_log(pbs_data.db_handle, &records_affected) EQ DB_OK)
      {
        for(i = 0; i < records_affected.entries; i++)
        {
          /* Checking whether Elementary file in the database is changed. */
          if((records_affected.field_id[i] EQ ef) AND (records_affected.record[i] EQ  phy_recno))
          {
            *changed = TRUE;
            return PHB_OK;
          }
        }

        /* Write operation has not changed File in the database. So returning PHB_OK */
        return PHB_OK;
      }
      else    /* Unable to read change log from DB. So returning PHB_FAIL. */
        return PHB_FAIL;
    }
    else   /* Write failure in DB. So returning PHB_FAIL */
      return PHB_FAIL;
  }
  else
  {
    /* Empty record */
    if (db_delete_record (pbs_data.db_handle, ef, phy_recno) NEQ DB_OK)
      return PHB_FAIL;

    if(db_read_change_log (pbs_data.db_handle, &records_affected) NEQ DB_OK)
      return PHB_FAIL;

    *changed = (records_affected.entries NEQ 0);
    return PHB_OK;
  }
}


/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_open          |
+--------------------------------------------------------------------+

    PURPOSE : Opens the SIM phonebook for the given SIM determined by the IMSI.
*/
T_PHB_RETURN pb_sim_open (const T_imsi_field *imsi_field, BOOL *changed)
{
  T_DB_INFO database_info;
  UBYTE ffsIMSI[MAX_IMSI_LEN+1];
  UBYTE simIMSI[MAX_IMSI_LEN+1];
  UBYTE imsi[FFS_IMSI_SIZE];
  int db_result;
  UBYTE buffer[RDM_PHB_DATA_SIZE];

  TRACE_FUNCTION("pb_sim_open()");

  /* Initially set SIM changed as TRUE. */
  *changed = TRUE;
   
  /* Open the database. */
  db_result = db_open(FFS_PHB_DIR);

  TRACE_EVENT_P1("DB handle is %d",db_result);

  if(db_result >= DB_OK)
  {
    pbs_data.db_handle = db_result;

    /* Get database info. */
    db_result = db_info(pbs_data.db_handle, &database_info);

    /* Read IMSI from the FFS if Database is clean. */
    if((db_result EQ DB_OK) AND (database_info.clean EQ TRUE))
    {
      db_result = db_read_record(pbs_data.db_handle, SIM_IMSI, 1, 0, FFS_IMSI_SIZE, imsi);

      /* Compare IMSI read from FFS with IMSI got from SIM. */
      if(db_result > DB_OK)
      { 
        psaSIM_decodeIMSI ((UBYTE*) imsi_field->field,(UBYTE)imsi_field->c_field, (char *)simIMSI);

        psaSIM_decodeIMSI (imsi, FFS_IMSI_SIZE, (char *)ffsIMSI);

        if (!strcmp((char *)simIMSI, (char *)ffsIMSI))
        { 
          *changed = FALSE;
          return PHB_OK;
        }
      }
      else
      {
        /* Unable to read IMSI, regenerate database */
        *changed = TRUE;
      }
    }

    /* Remove database whenever database is Inconsistent and SIM is changed. */
    if(db_close(pbs_data.db_handle) NEQ DB_OK)
      return PHB_FAIL;

    if(db_remove(FFS_PHB_DIR) NEQ DB_OK)
      return PHB_FAIL;
  }/*   if(db_result >= DB_OK) */

  /* Create database: For the first time, whenever SIM is changed 
              and whenever database is Inconsistent. */
  db_result = db_create(FFS_PHB_DIR, MAX_ELEM_FILES, TRUE);

  TRACE_EVENT_P1("DB handle is %d",db_result);

  /* Creating DB is successful and valid db_handle is returned */
  if(db_result >= DB_OK)  
  {
    if(db_create_field(pbs_data.db_handle, DB_UNMANAGED, SIM_IMSI, imsi_field->c_field, 1) NEQ DB_OK)
      return PHB_FAIL;  

    if(db_write_record(pbs_data.db_handle, SIM_IMSI, 1, 0, imsi_field->c_field, imsi_field->field) < DB_OK)
      return PHB_FAIL;

    /* Create Elementary file to store RDM Phonebook data */
    if(db_create_field(pbs_data.db_handle, DB_UNMANAGED, RDM_DATA_FILE_ID,RDM_PHB_DATA_SIZE,1) NEQ DB_OK)
      return PHB_FAIL;
    
    memset(buffer,0x00, RDM_PHB_DATA_SIZE); 

    if(db_write_record(pbs_data.db_handle, RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, buffer) < DB_OK)
      return PHB_FAIL;
      
    return PHB_OK;
  }

  /* Unable to create Database. So returning PHB_FAIL. */ 
  return PHB_FAIL;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_read_ef          |
+--------------------------------------------------------------------+

    PURPOSE : Reads *buffer from elementary file ef at index.
*/
T_PHB_RETURN pb_sim_read_ef (USHORT ef, USHORT recno, USHORT *entry_size, UBYTE *buffer)
{
  int db_result;
  T_DB_INFO_FIELD field_info;

  TRACE_FUNCTION("pb_sim_read_ef()");

  if(db_info_field(pbs_data.db_handle, ef, &field_info) EQ DB_OK)
  {
    *entry_size = field_info.record_size;

    db_result = db_read_record (pbs_data.db_handle,
                                ef,
                                recno,
                                0,
                                field_info.record_size,
                                buffer);

    if (db_result > DB_OK)
      return PHB_OK;  /* Successfully read */

    if (db_result EQ DB_EMPTY_RECORD)
    {
      /* Return a deleted record content */
      memset (buffer, 0xff, *entry_size);
      return PHB_OK;
    }
    return PHB_FAIL; /* Some problem reading record */
  }

  /* Returning PHB_FAIL, since DB has failed to give Info about the field. */ 
  return PHB_FAIL;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_remove_ef          |
+--------------------------------------------------------------------+

    PURPOSE : Removes elementary file.
*/
T_PHB_RETURN pb_sim_remove_ef (USHORT ef)
{
  TRACE_FUNCTION("pb_sim_remove_ef()");

  if(db_remove_field(pbs_data.db_handle, ef) EQ DB_OK)
    return PHB_OK;

  return PHB_FAIL;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_build_index          |
+--------------------------------------------------------------------+

    PURPOSE : Builds index for the given phonebook.
*/

T_PHB_RETURN pb_sim_build_index (T_PHB_TYPE type)
{
  USHORT field_id;
  
  TRACE_FUNCTION("pb_sim_build_index()");

  field_id = pb_sim_get_field_id(type);

  if(db_update_index(pbs_data.db_handle, field_id, NAME_IDX, &pb_sim_alpha_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK)
    return PHB_FAIL;

  if(db_update_index(pbs_data.db_handle, field_id, NUMBER_IDX, &pb_sim_number_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK)
    return PHB_FAIL;
  
  return PHB_OK;
}
  
/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_flush_data          |
+--------------------------------------------------------------------+

    PURPOSE : This function informs the SIM phonebook that SIM reading has become finished and we reached a consistent state.
*/

T_PHB_RETURN pb_sim_flush_data  (void)
{

  TRACE_FUNCTION("pb_sim_flush_data()");

  if(db_flush(pbs_data.db_handle) EQ DB_OK)
    return PHB_OK;

  return PHB_FAIL;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_add_record          |
+--------------------------------------------------------------------+

    PURPOSE : Add a given record at index to the given phonebook.
*/

T_PHB_RETURN pb_sim_add_record  (T_PHB_TYPE type, USHORT phy_recno, const T_PHB_RECORD *entry, T_DB_CHANGED *rec_affected)
{
  USHORT field_id, ext_file_id;
  UBYTE    tag_len, max_tag_len;
  UBYTE   data[SIM_MAX_RECORD_SIZE];
  UBYTE   buffer[RDM_PHB_DATA_SIZE];
  T_DB_INFO_FIELD info_field;
  UBYTE ext_rec_cnt = 0;
  UBYTE ext_rec_num1, ext_rec_num2;
  int db_result,i;
  
  
  TRACE_FUNCTION("pb_sim_add_record()");

  /* Handling of ECC Phonebook */
  if(type EQ ECC)
  {
    if((phy_recno > 0 ) AND (phy_recno <= MAX_ECC_RCD))
    {
      phb_ecc_element[phy_recno - 1].phy_idx = phy_recno;
      memcpy(phb_ecc_element[phy_recno - 1].number,entry->number, ECC_NUM_LEN);

      return PHB_OK;
    }
    else
      return PHB_FAIL;
  }
  
  /* Get Elementary file ID for the Phonebook type. */
  field_id = pb_sim_get_field_id(type);
  TRACE_EVENT_P1("pb_sim_get_field_id->Field_id: %x", field_id);

  /* Get Extension file for the Phonebook type. */
  ext_file_id = pb_sim_get_ext_file(type);

  TRACE_EVENT_P1("Ext_Field_id: %x", ext_file_id);

  db_result = db_info_field(pbs_data.db_handle, field_id, &info_field);
  
  /* Get record size to calculate alpha_len for the entry */
  if(db_result NEQ DB_OK)
  {
    TRACE_EVENT_P1("db_result = %d",db_result);
    return PHB_FAIL;
  }

  /* Handling of LDN, LMN and LRN Phonebook records.  */
  if((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN))
  {
    if(phy_recno NEQ 1)
      return PHB_FAIL;
    
    /* Read data related to LDN,LMN and LRN Phonebooks from FFS */
    db_result = db_read_record(pbs_data.db_handle, 
                         RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, buffer);

    /* Check for DB Failure. */
    if(db_result < DB_OK)
      return PHB_FAIL;


    /* Information for handling Cyclic RDM Records 
    ----------------------------------------
          buffer[0] ---> Most Recent in LDN
          buffer[1] ---> Oldest in LDN
          buffer[2] ---> Most Recent in LMN
          buffer[3] ---> Oldest in LMN
          buffer[4] ---> Most Recent in LRN
          buffer[5] ---> Oldest in LRN
    ---------------------------------------- */
   
    if(type EQ LDN)               /* Circular entry handling for LDN */
    {
      buffer[0] ++;
             
      if(buffer[0] > info_field.num_records)
				buffer[0] = 1;

      if(buffer[0] EQ buffer[1])
      { 
        buffer[1]++;

				if(buffer[1] >  info_field.num_records)
					buffer[1] = 1;
      }

      phy_recno = buffer[0];

      if(buffer[1] EQ 0)
        buffer[1] = 1;
    }

    if(type EQ LMN)          /* Circular entry handling for LMN */
    {
      buffer[2]++;
              
      if(buffer[2] > info_field.num_records)
				buffer[2] = 1;

      if(buffer[2] EQ buffer[3])
      {  
        buffer[3]++;

				if(buffer[3] >  info_field.num_records)
					buffer[3] = 1;  
      }

      phy_recno = buffer[2];

      if(buffer[3] EQ 0)
        buffer[3] = 1;
    }

    if(type EQ LRN)         /* Circular entry handling for LRN */
    {
      buffer[4]++;

      if(buffer[4] > info_field.num_records)
        buffer[4] = 1;

      if(buffer[4] EQ buffer[5])
      { 
				buffer[5]++;

				if(buffer[5] >  info_field.num_records)
					buffer[5] = 1;  
      }

      phy_recno = buffer[4];

      if(buffer[5] EQ 0)
        buffer[5] = 1;
    }

    TRACE_EVENT_P3("%d %d %d", buffer[0], buffer[1],buffer[2]);
    TRACE_EVENT_P3("%d %d %d", buffer[3], buffer[4],buffer[5]);
    /* Write data related to LDN,LMN and LRN Phonebooks to FFS */
    db_result = db_write_record(pbs_data.db_handle, 
                         RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, buffer);

    /* Check for DB Failure. */
    if(db_result < DB_OK)
      return PHB_FAIL;
  }/* if((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN)) */
  
  /* Convert T_PHB_TYPE into data structures as described in ETSI 11.11                  */
  /*  Bytes        Description                                      M/O   Length            |
  ----------------------------------------------------------------------
       1 to X          Alpha Identifier                                O       X bytes
       X+1                Length of BCD number/SSC contents    M       1 byte
       X+2                TON and NPI                                         M    1 byte
       X+3 to X+12  Dialling Number/SSC String                   M     10 bytes
       X+13        Capability/Configuration Identifier          M      1 byte
       X+14        Extension Record Identifier                   M     1 byte
       -------------------------------------------------------
       Extra fields for LDN, LMN, and LMN Phonebook records (As per 31.102)
       -------------------------------------------------------
       X+15 to X+21 Outgoing call date and time                  M     7 bytes
       X+22 to X+24 Outgoing call duration                          M      3 bytes 
       X+26              Line of the call                                      M    1 byte (New field added to 
                                                                                                         store line of call)
  ----------------------------------------------------------------------*/

  tag_len = pb_sim_get_entry_len(entry->tag, PHB_MAX_TAG_LEN);

  max_tag_len = info_field.record_size - pb_sim_get_size_except_tag(field_id);

  if(tag_len > max_tag_len)
    return PHB_TAG_EXCEEDED;

  memset(data, 0xFF, sizeof(data));
  memcpy(data, entry->tag, tag_len);

  if(entry->number[10] NEQ 0xFF)
  {
    data[max_tag_len] = 11; /* max. length */
  }
  else
  {
    data[max_tag_len] = entry->len + 1;
  }

  data[max_tag_len+1] = entry->ton_npi;
  memcpy((char *)&data[max_tag_len+2], 
           (char *)entry->number, 10);
  data[max_tag_len+12] = entry->cc_id;

  /* Copy data specific to records of Phonebook Types (LRN, LDN and LMN). */  
  if((type EQ LDN) OR (type EQ LRN) OR (type EQ LMN))
  {
    if(entry->v_time)
    {
      data[max_tag_len+14] = entry->time.year;
      data[max_tag_len+15] = entry->time.month;
      data[max_tag_len+16] = entry->time.day;
      data[max_tag_len+17] = entry->time.hour;
      data[max_tag_len+18] = entry->time.minute;
      data[max_tag_len+19] = entry->time.second;
      data[max_tag_len+20] = entry->time.time_zone;

      data[max_tag_len+21] = (UBYTE)((entry->time.duration >> 16) & 0xff);
      data[max_tag_len+22] = (UBYTE)((entry->time.duration >> 8) & 0xff);
      data[max_tag_len+23] = (UBYTE)((entry->time.duration) & 0xff);

    }

    if(entry->v_line)
    {
      data[max_tag_len+24] = entry->line;
    }
    
  }

  TRACE_EVENT_P1("Number = %s",entry->number);
  /* Check if extension records are needed */

  /* Check how many extension records are needed for number */ 
  if(entry->number[10] NEQ 0xFF)
  {
    ext_rec_cnt = entry ->len - 10;

    if(ext_rec_cnt % 10)
      ext_rec_cnt = (ext_rec_cnt  / 10) + 1;
    else
      ext_rec_cnt = (ext_rec_cnt  / 10);
  }

  /* Check how many extension records are needed for subaddress */ 
  if(entry->subaddr[0] NEQ 0xFF)
  {
    ext_rec_cnt++;
  }

  if(entry->subaddr[11] NEQ 0xFF)
  {
    ext_rec_cnt++;
  } 

  TRACE_EVENT_P1("phy_recno = %d",phy_recno);

  TRACE_EVENT_P2("no_rec = %d, used_rec = %d",info_field.num_records,info_field.used_records);

  /* If record number is not mentioned, search for the free record and add the entry. */
  if(phy_recno EQ 0)
  {
    db_result = db_find_free_record( pbs_data.db_handle, field_id);

    /* Database is unable to find the free record. So returning PHB_FULL. */
    if(db_result EQ DB_RECORD_NOT_FOUND)
      return PHB_FULL;

    if(db_result < DB_OK)
      return PHB_FAIL;

    /* Database has returned the free record number. */
    phy_recno = db_result;
  }
  
  /* Write record if entry does not require extension records */
  if(ext_rec_cnt EQ 0)              
  {
    /* Write record into FFS  */
    if(db_write_record(pbs_data.db_handle, field_id, phy_recno, 0, info_field.record_size, data) < DB_OK)
      return PHB_FAIL;

    /* For LDN record also write to SIM_LDN (without date and time Details */
    if(type EQ LDN)
    {
      memset(&data[max_tag_len + pb_sim_get_size_except_tag(field_id)], 0xFF, 
        SIZE_DATA_DATE_TIME);

     /* if(db_info_field(pbs_data.db_handle, SIM_LND, &info_field) NEQ DB_OK)
        return PHB_FAIL;

      if(db_write_record(pbs_data.db_handle, SIM_LND, phy_recno, 0, info_field.record_size, data) < DB_OK)
        return PHB_FAIL;*/
    }

  }
  else        /* We need to find free extension record. */
  {
    TRACE_EVENT_P1("Extension records = %d",ext_rec_cnt);
    /* Search for free extension records */

		/* Check whether extension file has required no. of free records. */
		db_result = db_info_field(pbs_data.db_handle, ext_file_id, &info_field);

		if((info_field.num_records - info_field.used_records) < ext_rec_cnt)
			return PHB_FAIL;
		
		/* Required no. of free extension records are found */
    ext_rec_num1= db_find_free_record( pbs_data.db_handle,ext_file_id);

    /* DB has returned non-zero positive number. 
            (Valid record number which is free). */ 
    if(ext_rec_num1 > DB_OK) 
    {  /* Set Extension record Identifier */
      data[max_tag_len+13] = ext_rec_num1;    

      db_result = db_info_field(pbs_data.db_handle, field_id, &info_field);

      /* Write record into FFS */
      if(db_write_record(pbs_data.db_handle, 
        field_id, phy_recno, 0, info_field.record_size, data) < DB_OK)
				return PHB_FAIL;
        
    }
    else
			return PHB_FAIL;

		db_result = db_info_field(pbs_data.db_handle, ext_file_id, &info_field);

		/* Prepare extension data and write into Extension file after finding the free records. */
    for(i = 0; i < ext_rec_cnt; i++)
    {
      pb_sim_prepare_ext_data(data, i, (UBYTE*)entry->number, entry->len, (UBYTE*)entry->subaddr);

      /* Find next free record to chain the extension records. */
		  ext_rec_num2 = db_find_free_record( pbs_data.db_handle,ext_file_id);
		 
      /* Chain extension records and set last link to "FF" */
      if(i NEQ (ext_rec_cnt - 1))
        data[12] =  ext_rec_num2;
          
      /* Write extension record into FFS */
      if(db_write_record(pbs_data.db_handle, ext_file_id, ext_rec_num1, 0, info_field.record_size, data) < DB_OK)
        return PHB_FAIL;

			if(pb_sim_update_extn_records(ext_file_id, ext_rec_num1, INCREMENT) EQ PHB_FAIL)
				return PHB_FAIL;

		  /* Preserve the previous free record number. */ 
		  ext_rec_num1 = ext_rec_num2;
    }
    
  }  

  /* Get information about changed records from the database. */
  if(db_read_change_log(pbs_data.db_handle, rec_affected) NEQ DB_OK)
    return PHB_FAIL;

  if((type NEQ LDN) AND (type NEQ LMN) AND (type NEQ LRN))
  {
    /* Update the sorted indexes. */
    if(db_update_index(pbs_data.db_handle, field_id, NAME_IDX, &pb_sim_alpha_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK)
      return PHB_FAIL;

    if(db_update_index(pbs_data.db_handle, field_id, NUMBER_IDX, &pb_sim_number_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK)
      return PHB_FAIL;
  }
  else
  {
    /* Remove RDM data record from the list */
    if(rec_affected->entries NEQ 0)
    {
      rec_affected->entries -= 2;
  
      /* Remove the record from the list */
      memmove (&rec_affected->field_id[0],
           &rec_affected->field_id[1],
           sizeof (USHORT) * (DB_MAX_AFFECTED - 1));
      memmove (&rec_affected->record[0],
           &rec_affected->record[1],
           sizeof (USHORT) * (DB_MAX_AFFECTED - 1));

			/* Remove the record from the list */
      memmove (&rec_affected->field_id[0],
           &rec_affected->field_id[1],
           sizeof (USHORT) * (DB_MAX_AFFECTED - 1));
      memmove (&rec_affected->record[0],
           &rec_affected->record[1],
           sizeof (USHORT) * (DB_MAX_AFFECTED - 1));
    
			/* Remove extension record from the list. */
			if(ext_rec_cnt NEQ 0)
			{
				rec_affected->entries --;
  
        /* Remove the record from the list */
        memmove (&rec_affected->field_id[0],
           &rec_affected->field_id[1],
           sizeof (USHORT) * (DB_MAX_AFFECTED - 1));

				memmove (&rec_affected->record[0],
           &rec_affected->record[1],
           sizeof (USHORT) * (DB_MAX_AFFECTED - 1));
			}
    }
  }

  return PHB_OK;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_del_record         |
+--------------------------------------------------------------------+

    PURPOSE : Delete a given record at phy_recno from the given phonebook.
*/

T_PHB_RETURN pb_sim_del_record  (T_PHB_TYPE type, USHORT phy_recno, T_DB_CHANGED *rec_affected)
{
  USHORT field_id, ext_file_id, db_recno;
  UBYTE   buffer[RDM_PHB_DATA_SIZE], rec_cnt;
  T_DB_INFO_FIELD info_field;
  UBYTE   data[SIM_MAX_RECORD_SIZE];


  TRACE_FUNCTION("pb_sim_del_record()");

  /* Handling of ECC Phonebook */
  if(type EQ ECC)
  {
    if((phy_recno > 0 ) AND (phy_recno <= MAX_ECC_RCD))
    {
      phb_ecc_element[phy_recno - 1].phy_idx = 0;
      memset(phb_ecc_element[phy_recno - 1].number, 0, ECC_NUM_LEN);

      return PHB_OK;
    }
    else
      return PHB_FAIL;
  }

  TRACE_EVENT_P1("phy_recno = %d", phy_recno);

  /* Get Elementary file ID for the Phonebook type. */
  field_id = pb_sim_get_field_id(type);

  /* Get Extension file for the Phonebook type. */
  ext_file_id = pb_sim_get_ext_file(type);

  /* Get no. of records in the field */
  if(db_info_field(pbs_data.db_handle, field_id, &info_field) NEQ DB_OK)
    return PHB_FAIL;
  
	/* Information for handling Cyclic RDM Records 
    ----------------------------------------
          buffer[0] ---> Most Recent in LDN
          buffer[1] ---> Oldest in LDN
          buffer[2] ---> Most Recent in LMN
          buffer[3] ---> Oldest in LMN
          buffer[4] ---> Most Recent in LRN
          buffer[5] ---> Oldest in LRN
    ---------------------------------------- */

  /* Handling of LDN, LMN and LRN Phonebook records.  */
  if((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN))
  {
    /* Read data related to LDN,LMN and LRN Phonebooks from FFS */
    if(db_read_record(pbs_data.db_handle, RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, (UBYTE *) buffer) < DB_OK)
      return PHB_FAIL;

    if(type EQ LDN)               /* Circular entry handling for LDN */
    {
      db_recno = buffer[0];

      if(phy_recno NEQ 1)
	  {
		for(rec_cnt = 0; rec_cnt < (phy_recno - 1) ; rec_cnt++)
		{
		  db_recno--;

		  if(db_recno EQ 0)
			db_recno = (UBYTE)info_field.num_records;

		  while(db_read_record(pbs_data.db_handle, field_id, db_recno, 0, info_field.record_size, data) < DB_OK)
		  {  
			db_recno--;

			if(db_recno EQ 0)
			  db_recno = (UBYTE)info_field.num_records;
		  }
		}
	  }

	  if(buffer[0] EQ buffer[1])
        buffer[0] = buffer[1] = 0;

	  if(buffer[0] EQ db_recno)
      {  
		buffer[0]--;

        if(buffer[0] EQ 0)
		  buffer[0] = (UBYTE)info_field.num_records;

        while(db_read_record(pbs_data.db_handle, field_id, buffer[0], 0, info_field.record_size, data) < DB_OK)
		{  
		  buffer[0]--;

		  if(buffer[0] EQ 0)
		    buffer[0] = (UBYTE)info_field.num_records;
		}
      }

	  if(buffer[1] EQ db_recno)
      {  
	    buffer[1]++;

		if(buffer[1] EQ info_field.num_records)
		  buffer[1] = 1;

		while(db_read_record(pbs_data.db_handle, field_id, buffer[1], 0, info_field.record_size, data) < DB_OK)
		{  
		  buffer[1]++;

		  if(buffer[1] EQ info_field.num_records)
		    buffer[1] = 1;
		}
	  }
    }

    if(type EQ LMN)          /* Circular entry handling for LMN */
    {
      db_recno = buffer[2];

      if(phy_recno NEQ 1)
	  {
		for(rec_cnt = 0; rec_cnt < (phy_recno - 1) ; rec_cnt++)
		{
		  db_recno--;

		  if(db_recno EQ 0)
			db_recno = (UBYTE)info_field.num_records;

		  while(db_read_record(pbs_data.db_handle, field_id, db_recno, 0, info_field.record_size, data) < DB_OK)
		  {  
			db_recno--;

			if(db_recno EQ 0)
			  db_recno = (UBYTE)info_field.num_records;
		  }
		}
	  }

	  if(buffer[2] EQ buffer[3])
        buffer[2] = buffer[3] = 0;

	  if(buffer[2] EQ db_recno)
      {  
	    buffer[2]--;

        if(buffer[2] EQ 0)
		  buffer[2] = (UBYTE)info_field.num_records;

        while(db_read_record(pbs_data.db_handle, field_id, buffer[2], 0, info_field.record_size, data) < DB_OK)
		{  
		  buffer[2]--;

		  if(buffer[2] EQ 0)
		     buffer[2] = (UBYTE)info_field.num_records;
		}
      }

	  if(buffer[3] EQ db_recno)
      {  
	    buffer[3]++;

		if(buffer[3] EQ info_field.num_records)
		  buffer[3] = 1;

		while(db_read_record(pbs_data.db_handle, field_id, buffer[3], 0, info_field.record_size, data) < DB_OK)
		{  
		  buffer[3]++;

		  if(buffer[3] EQ info_field.num_records)
		    buffer[3] = 1;
		}
	  }
    }

    if(type EQ LRN)         /* Circular entry handling for LRN */
    {
      db_recno = buffer[4];

      if(phy_recno NEQ 1)
	  {
	    for(rec_cnt = 0; rec_cnt < (phy_recno - 1) ; rec_cnt++)
		{
		  db_recno--;

		  if(db_recno EQ 0)
			db_recno = (UBYTE)info_field.num_records;

		  while(db_read_record(pbs_data.db_handle, field_id, db_recno, 0, info_field.record_size, data) < DB_OK)
		  {  
		    db_recno--;

			if(db_recno EQ 0)
			  db_recno = (UBYTE)info_field.num_records;
		  }
		}
	  }

	  if(buffer[4] EQ buffer[5])
        buffer[4] = buffer[5] = 0;

	  if(buffer[4] EQ db_recno)
      {  
		buffer[4]--;

        if(buffer[4] EQ 0)
		  buffer[4] = (UBYTE)info_field.num_records;

        while(db_read_record(pbs_data.db_handle, field_id, buffer[4], 0, info_field.record_size, data) < DB_OK)
		{  
		  buffer[4]--;

		  if(buffer[4] EQ 0)
		    buffer[4] = (UBYTE)info_field.num_records;
		}
      }

	  if(buffer[5] EQ db_recno)
      {  
	    buffer[5]++;

		if(buffer[5] EQ info_field.num_records)
		  buffer[5] = 1;

		while(db_read_record(pbs_data.db_handle, field_id, buffer[5], 0, info_field.record_size, data) < DB_OK)
		{  
		  buffer[5]++;

		  if(buffer[5] EQ info_field.num_records)
		    buffer[5] = 1;
		}
	  }
    }

    TRACE_EVENT_P1("db_recno = %d ", db_recno);
    TRACE_EVENT_P3("%d %d %d", buffer[0], buffer[1],buffer[2]);
    TRACE_EVENT_P3("%d %d %d", buffer[3], buffer[4],buffer[5]);
    /* Write data related to LDN,LMN and LRN Phonebooks to FFS */
    if(db_write_record(pbs_data.db_handle, RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, (UBYTE *) buffer) < DB_OK)
      return PHB_FAIL;
  }
	else
  {
		db_recno = phy_recno;
	}
  
  
  /* Delete extension records if not referenced. */
  if(pb_sim_read_ext_record_for_delete(type, field_id, db_recno) EQ PHB_FAIL)
	 return PHB_FAIL;

  /* Delete record from FFS. */
  if(db_delete_record(pbs_data.db_handle, field_id,db_recno) NEQ DB_OK)
    return PHB_FAIL;

  /* Get information about changed records from the database. */
  if(db_read_change_log(pbs_data.db_handle, rec_affected) NEQ DB_OK)
    return PHB_FAIL;

  if((type NEQ LDN) AND (type NEQ LMN) AND (type NEQ LRN))
  {
    /* Update the sorted indexes. */
    if(db_update_index(pbs_data.db_handle, field_id, NAME_IDX, &pb_sim_alpha_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK)
      return PHB_FAIL;

    if(db_update_index(pbs_data.db_handle, field_id, NUMBER_IDX, &pb_sim_number_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK)
      return PHB_FAIL;
  }
  else
  {
    
    if(rec_affected->entries NEQ 0)
    {
      /* Remove RDM data record from the list */
      rec_affected->entries -= 2;
  
      /* Remove the record from the list */
      memmove (&rec_affected->field_id[0],
           &rec_affected->field_id[1],
           sizeof (USHORT) * (DB_MAX_AFFECTED - 1));
      memmove (&rec_affected->record[0],
           &rec_affected->record[1],
           sizeof (USHORT) * (DB_MAX_AFFECTED - 1));

    /* Remove the record from the list */
      memmove (&rec_affected->field_id[0],
           &rec_affected->field_id[1],
           sizeof (USHORT) * (DB_MAX_AFFECTED - 1));
      memmove (&rec_affected->record[0],
           &rec_affected->record[1],
           sizeof (USHORT) * (DB_MAX_AFFECTED - 1));
    }   

    TRACE_EVENT_P1("rec-affected = %d", rec_affected->entries);
  }
  
  return PHB_OK;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_read_record  |
+--------------------------------------------------------------------+

    PURPOSE : Read a given physical record from the flash based phonebook.
*/

T_PHB_RETURN pb_sim_read_record (T_PHB_TYPE type, USHORT phy_recno, T_PHB_RECORD *entry)
{
  USHORT field_id, ext_file_id;
  USHORT db_recno;
  T_DB_INFO_FIELD info_field;
  UBYTE   buffer[RDM_PHB_DATA_SIZE];
  UBYTE data[SIM_MAX_RECORD_SIZE], *ptr;
  UBYTE max_tag_len;
  UBYTE ext_rcd_num;

  TRACE_FUNCTION("pb_sim_read_record()");

  /* Handling of ECC Phonebook */
  if(type EQ ECC)
  {
    if((phy_recno > 0 ) AND (phy_recno <= MAX_ECC_RCD))
    {
      entry->phy_recno = phy_recno;
      memcpy(entry->number, phb_ecc_element[phy_recno - 1].number, ECC_NUM_LEN);  
      return PHB_OK;
    }
    else
      return PHB_FAIL;
  }

  /* Get Elementary file ID for the Phonebook type. */
  field_id = pb_sim_get_field_id(type);

  /* Get Extension file for the Phonebook type. */
  ext_file_id = pb_sim_get_ext_file(type);

  /* Read record from the database. */
  if(db_info_field(pbs_data.db_handle, field_id, &info_field) NEQ DB_OK)
    return PHB_FAIL;
  
	/* Information for handling Cyclic RDM Records 
    ----------------------------------------
          buffer[0] ---> Most Recent in LDN
          buffer[1] ---> Oldest in LDN
          buffer[2] ---> Most Recent in LMN
          buffer[3] ---> Oldest in LMN
          buffer[4] ---> Most Recent in LRN
          buffer[5] ---> Oldest in LRN
    ---------------------------------------- */

  /* Handling of LDN, LMN and LRN Phonebook records.  */
  if((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN))
  {
    /* Read data related to LDN,LMN and LRN Phonebooks from FFS */
    if(db_read_record(pbs_data.db_handle, 
        RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, (UBYTE *) buffer) < DB_OK)
      return PHB_FAIL;

    /* Since LDN, LMN and LRN records are circular entries, 
           most recent will be the 1st record and 
              entries increase towards the oldest one for Reading.   */
    if(type EQ LDN)
    {
      if(buffer[0] EQ 0)
        buffer[0] = 1; 

      db_recno =  buffer[0] - phy_recno + 1;
      db_recno = db_recno % (info_field.num_records);

      if(db_recno EQ 0)
        db_recno = (info_field.num_records);
    }

    if(type EQ LMN)
    {
      if(buffer[2] EQ 0)
        buffer[2] = 1; 

      db_recno =  buffer[2] - phy_recno + 1;
      db_recno = db_recno % (info_field.num_records);

      if(db_recno EQ 0)
        db_recno = (info_field.num_records);
    }

    if(type EQ LRN)
    {
      if(buffer[4] EQ 0)
        buffer[4] = 1; 

      db_recno =  buffer[4] - phy_recno + 1;
      db_recno = db_recno % (info_field.num_records);

      if(db_recno EQ 0)
        db_recno = (info_field.num_records);
    }
  }
  else
    db_recno = phy_recno;

  TRACE_EVENT_P2("db_recno = %d phy_recno = %d",db_recno, phy_recno);
  TRACE_EVENT_P3("%d %d %d", buffer[0], buffer[1],buffer[2]);
  TRACE_EVENT_P3("%d %d %d", buffer[3], buffer[4],buffer[5]);
    

  if(db_read_record(pbs_data.db_handle, field_id, db_recno, 0, info_field.record_size, data) < DB_OK)
    return PHB_FAIL;

  /* Convert SIM data to the type T_PHB_RECORD. */
  ptr = data;
  max_tag_len = MINIMUM ((info_field.record_size) - pb_sim_get_size_except_tag(field_id), PHB_MAX_TAG_LEN);

  entry->phy_recno = phy_recno;
  entry->tag_len = (UBYTE)pb_sim_get_entry_len(ptr, max_tag_len);

  memset(entry->tag, 0xFF, PHB_MAX_TAG_LEN); /* init the tag value */
  memcpy ( (char*)entry->tag, (char*)ptr, entry->tag_len );

  ptr += (info_field.record_size) - pb_sim_get_size_except_tag(field_id);

  max_tag_len = (info_field.record_size) - pb_sim_get_size_except_tag(field_id);
  
  entry->len     = *ptr - 1;
  ++ptr;
  entry->ton_npi = *ptr;
  ++ptr;
  
  memset(entry->number, 0xFF, PHB_PACKED_NUM_LEN);
  memcpy( (char*)entry->number, (char*)ptr, entry->len );
  ptr += 10;
  entry->cc_id     = *ptr;
  ++ptr;

  /* Copy data specific to records of LDN, LMN, and LRN phonebook types. */ 
  if((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN))
  {
    entry->v_time = 1;
    
    entry->time.year=data[max_tag_len+14] ;
    entry->time.month=data[max_tag_len+15];
    entry->time.day=data[max_tag_len+16];
    entry->time.hour=data[max_tag_len+17] ;
    entry->time.minute= data[max_tag_len+18];
    entry->time.second=data[max_tag_len+19] ;
    entry->time.time_zone=data[max_tag_len+20];

    entry->time.duration = (data[max_tag_len+21] << 16) +
                           (data[max_tag_len+22] << 8) +
                           (data[max_tag_len+23] );

    entry->v_line = 1;
    entry->line=data[max_tag_len+24];

  }

  if (*ptr NEQ 0xFF) /* check for extention records */
  {
    ext_rcd_num =(UBYTE)*ptr;

    if(db_info_field(pbs_data.db_handle, ext_file_id, &info_field) NEQ DB_OK)
      return PHB_FAIL;

    /* Reset pointer to start location. */
    ptr = data;

    memset(ptr, 0xFF, info_field.record_size);

    if(db_read_record(pbs_data.db_handle, ext_file_id, ext_rcd_num, 0, info_field.record_size, ptr) < DB_OK) 
      return PHB_FAIL;
    
    pb_sim_read_ext(ptr, entry);

    while(*(ptr + 12) NEQ 0xFF) /* check if a further EXT entry exists */
    {
      memset(ptr, 0xFF, info_field.record_size);

      db_read_record(pbs_data.db_handle, ext_file_id, (USHORT)*(ptr+12), 0, info_field.record_size,ptr); 

      pb_sim_read_ext(ptr, entry);     
    }
  }
  
  return PHB_OK;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_read_alpha_record      |
+--------------------------------------------------------------------+

    PURPOSE : Read a given physical record from the flash based phonebook in alphabetical order.
*/

T_PHB_RETURN pb_sim_read_alpha_record   (T_PHB_TYPE type, USHORT order_num, T_PHB_RECORD *entry)
{
  int db_result;
  USHORT field_id, ext_file_id;
  
  TRACE_FUNCTION("pb_sim_read_alpha_record()");

  /* Get Elementary file ID for the Phonebook type. */
  field_id = pb_sim_get_field_id(type);

  /* Get Extension file for the Phonebook type. */
  ext_file_id = pb_sim_get_ext_file(type);

  /* Read record from the FFS. */
  db_result = db_get_phy_from_idx(pbs_data.db_handle, field_id, NAME_IDX, order_num);

  if(db_result > DB_OK)
  {
    return pb_sim_read_record(type, (USHORT)db_result, entry) ;
  }

  /* Check whether index is vaild. */
  if(db_result EQ DB_INVALID_INDEX)
    return PHB_INVALID_IDX;

  /* Unable to get record from the database. Hence returning PHB_FAIL. */
  return PHB_FAIL;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_read_number_record       |
+--------------------------------------------------------------------+

    PURPOSE : Read a given physical record from the flash based phonebook in number sorted order.
*/

T_PHB_RETURN pb_sim_read_number_record  (T_PHB_TYPE type, USHORT order_num, T_PHB_RECORD *entry)
{
  int db_result;
  USHORT field_id, ext_file_id;
  
  TRACE_FUNCTION("pb_sim_read_number_record()");

  /* Get Elementary file ID for the Phonebook type. */
  field_id = pb_sim_get_field_id(type);

  /* Get Extension file for the Phonebook type. */
  ext_file_id = pb_sim_get_ext_file(type);

  /* Read record from the FFS. */
  db_result = db_get_phy_from_idx(pbs_data.db_handle, field_id, NUMBER_IDX, order_num);

  if(db_result > DB_OK)
  {
    return pb_sim_read_record(type, (USHORT)db_result, entry) ;
  }
  else if(db_result EQ DB_INVALID_INDEX)
    return PHB_INVALID_IDX;
  else
    return PHB_FAIL;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_search_name        |
+--------------------------------------------------------------------+

    PURPOSE : Finds the first entry matching the search tag.
*/

T_PHB_RETURN pb_sim_search_name (T_PHB_TYPE type, T_PHB_MATCH match, const T_ACI_PB_TEXT *search_tag, SHORT *order_num)
{
  T_ACI_PB_TEXT key;
  int res;
  USHORT field_id, ext_file_id;
  
  TRACE_FUNCTION("pb_sim_search_name()");

  /* Get Elementary file ID for the Phonebook type. */
  field_id = pb_sim_get_field_id(type);

  /* Get Extension file for the Phonebook type. */
  ext_file_id = pb_sim_get_ext_file(type);

  key.len = search_tag->len;
  key.cs  = search_tag->cs;
  pb_sim_cvt_alpha_for_cmp ((UBYTE*) search_tag->data, (UBYTE*) key.data, search_tag->len);

  res = db_search(pbs_data.db_handle, field_id, NAME_IDX, (UBYTE*) order_num, pb_sim_search_alpha_func, match, (const UBYTE*)&key);

  if(res > DB_OK)
  {
    return PHB_OK;
  }

  return PHB_FAIL;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_search_number         |
+--------------------------------------------------------------------+

    PURPOSE : Finds the first entry matching the number.
*/

T_PHB_RETURN pb_sim_search_number   (T_PHB_TYPE type, const UBYTE *number, SHORT *order_num)
{
  int res, i;
  CHAR  cur_number[MAX_PHB_NUM_LEN];
  CHAR  rev_number[MAX_PHB_NUM_LEN];
  int cmpLen, cmp_res;
  USHORT field_id, ext_file_id;
   
  TRACE_FUNCTION("pb_sim_search_number()");

  /* Handling for ECC Phonebook. */
  if(type EQ ECC)
  {
    for(i = 0; i < pbs_data.max_record[ECC]; i++)
    {

      cmhPHB_getAdrStr(cur_number, MAX_PHB_NUM_LEN - 1,phb_ecc_element[i].number,pbs_data.record_size[ECC]);
  
      pb_sim_revString(cur_number);

      strcpy( rev_number,(const char*)number);

      pb_sim_revString(rev_number);

      cmpLen = MINIMUM(strlen((const char*) cur_number), strlen((const char*)number));

      cmp_res = pb_sim_cmpString((UBYTE*)cur_number, (UBYTE*)rev_number, cmpLen);

      if(cmp_res NEQ 0)
        return PHB_FAIL;
      else
      {
				return PHB_OK;
      }
    }
  }

  /* Get Elementary file ID for the Phonebook type. */
  field_id = pb_sim_get_field_id(type);


  TRACE_EVENT_P2("type = %d field_id = %x", type, field_id);

  /* Get Extension file for the Phonebook type. */
  ext_file_id = pb_sim_get_ext_file(type);

  res = db_search(pbs_data.db_handle, field_id, NUMBER_IDX, (UBYTE*)order_num, &pb_sim_search_num_func, PHB_MATCH_PARTIAL, number);

  if(res > DB_OK)
  {
    return PHB_OK;
  }

  return PHB_FAIL;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_read_sizes          |
+--------------------------------------------------------------------+

    PURPOSE : Reads the sizes of a given phonebook.
*/

T_PHB_RETURN pb_sim_read_sizes  (T_PHB_TYPE type, SHORT      *max_rcd, SHORT      *used_rcd, UBYTE      *tag_len)
{
  T_DB_INFO_FIELD info_field;
  USHORT field_id;
  int db_result;

  TRACE_FUNCTION("pb_sim_read_sizes()");

  /* Handling for ECC Phonebook */
  if(type EQ ECC)
  {
    *max_rcd = pbs_data.max_record[ECC];
    *used_rcd = pbs_data.used_record[ECC];
    *tag_len = 0; /* To Do:Alpha tag will not be there for ECC. So assigning zero here */
    return PHB_OK;
  }
  

  /* Get Elementary file ID for the Phonebook type. */
  field_id = pb_sim_get_field_id(type);

  db_result = db_info_field(pbs_data.db_handle, field_id, &info_field);
  
  TRACE_EVENT_P1("db_result = %d", db_result);

  if(db_result EQ DB_OK)
  {
    *max_rcd  = info_field.num_records;
    *used_rcd = info_field.used_records;
    *tag_len  = info_field.record_size - pb_sim_get_size_except_tag(field_id);
    return PHB_OK;
  }

  return PHB_FAIL;
  
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_get_entry_len          |
+--------------------------------------------------------------------+

    PURPOSE : Used to get the length in bytes of a given entry which is coded as given in 11.11 Annex B.
*/

int pb_sim_get_entry_len    (const UBYTE *pb_tag, UBYTE max_pb_len)
{
  
  int   pb_len    = 0;
  UBYTE inc_count = 1;
  BOOL  ucs2      = FALSE;
  UBYTE chars = 0;

  TRACE_FUNCTION("pb_sim_get_entry_len()");

  if (*pb_tag EQ 0x80)
  {
    ucs2 = TRUE;
    inc_count = 2;              /* check two bytes */
    pb_len = 1;                 /* skip the 0x80 */
  }
  else if (*pb_tag EQ 0x81 OR *pb_tag EQ 0x82)
  {
    if (*pb_tag EQ 0x81)
      pb_len = 3;                 /* 0x80 + len + pointer */
    else
      pb_len = 4;                 /* 0x80 + len + 2xpointer */

    chars = pb_tag[1];
    pb_tag += pb_len;                  /* go to data */
    while (chars)
    {
      if (*pb_tag++ & 0x80)
        pb_len+=2;
      else
        pb_len+=1;

      pb_tag++;
      chars--;
    }
    return MINIMUM(pb_len,max_pb_len);
  }

  while (pb_len < max_pb_len)
  {
    if (ucs2 EQ TRUE)
    {
      if (!(pb_len+1 < max_pb_len)) /* Check also if we traverse the upper bound */
        break;                      /* so only a "half" UCS2 element is remaining */
    }
    if (pb_tag[pb_len] EQ 0xFF)
    { 
      /* one 0xFF indicates the end of a non UCS2 string */
      if (ucs2 EQ FALSE)
      {
        break;
      }
      /* two 0xFF indicates the end of a UCS2 string */
      if (pb_tag[pb_len + 1] EQ 0xFF)
      {
        break;
      }
    }
    pb_len += inc_count;
  }

  return (pb_len);
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_alpha_cmp           |
+--------------------------------------------------------------------+

    PURPOSE : Compares alpha identifier of two records.
*/
int pb_sim_alpha_cmp (int db_handle, USHORT field_id, USHORT recno_1, USHORT recno_2, ULONG flags)
{
  T_PHB_RECORD entry_1,entry_2;
  UBYTE cmpLen = 0;
  UBYTE *buffer;
  UBYTE max_tag_len;
  UBYTE cur_tag[PHB_MAX_TAG_LEN], check_tag[PHB_MAX_TAG_LEN];
  int   cmp_res;
  T_DB_INFO_FIELD info_field;
  
  TRACE_FUNCTION("pb_sim_alpha_cmp()");

  
  db_info_field(db_handle, field_id, &info_field);

  MALLOC(buffer, info_field.record_size);

  /* Read the first record. */
  db_read_record(db_handle, field_id, recno_1, 0, info_field.record_size, buffer);

  /* Unpack record 1 to do a string comparison on the alpha identifier field */
  max_tag_len = MINIMUM ( (info_field.record_size) - pb_sim_get_size_except_tag(field_id), 
                                            PHB_MAX_TAG_LEN);
  entry_1.tag_len = (UBYTE)pb_sim_get_entry_len(buffer, max_tag_len);
  
  memset(entry_1.tag, 0xFF, PHB_MAX_TAG_LEN); /* init the tag value */
  memcpy ( (char*)entry_1.tag, (char*)buffer, entry_1.tag_len );

  pb_sim_cvt_alpha_for_cmp ( entry_1.tag, cur_tag, entry_1.tag_len );

  memset(buffer, 0, info_field.record_size);

  /* Read the second record. */
  db_read_record(db_handle, field_id, recno_2, 0, info_field.record_size, buffer);

  /* Unpack record 2 to do a string comparison on the alpha identifier field */
  max_tag_len = MINIMUM ((info_field.record_size) - pb_sim_get_size_except_tag(field_id), 
                                           PHB_MAX_TAG_LEN);
  entry_2.tag_len = (UBYTE)pb_sim_get_entry_len(buffer, max_tag_len);
  
  memset(entry_2.tag, 0xFF, PHB_MAX_TAG_LEN); /* init the tag value */
  memcpy ( (char*)entry_2.tag, (char*)buffer, entry_2.tag_len );

  pb_sim_cvt_alpha_for_cmp ( entry_2.tag, check_tag, entry_2.tag_len );

  cmpLen = MINIMUM ( entry_1.tag_len,
                           entry_2.tag_len );

  TRACE_EVENT_P1("%d", cmpLen);
      
  cmp_res = pb_sim_cmpString ( cur_tag, check_tag, cmpLen );

	if (cmp_res EQ 0) 
  {
    /* Correct result when length was different, ACIPHB201 */
    if (entry_1.tag_len < entry_2.tag_len)
      cmp_res = -1;
    else if (entry_1.tag_len > entry_2.tag_len)
      cmp_res = 1;
  }

  MFREE(buffer);

  return cmp_res;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_number_cmp     |
+--------------------------------------------------------------------+

    PURPOSE : Compares two numbers of two records.
*/
int pb_sim_number_cmp (int db_handle,
                                USHORT field_id, 
                                USHORT recno_1, 
                                USHORT recno_2,
                        ULONG  flags)
{
  T_PHB_RECORD entry_1,entry_2;
  T_DB_INFO_FIELD info_field;
  UBYTE cmpLen = 0;
  UBYTE *buffer, *tmp_buffer;
  UBYTE ext_rcd_num;
  UBYTE max_tag_len;
  CHAR           cur_number[MAX_PHB_NUM_LEN];
  CHAR           ref_number[MAX_PHB_NUM_LEN];
  int   cmp_res;
  USHORT file_id;

  TRACE_FUNCTION("pb_sim_number_cmp()");

  MALLOC(buffer, sizeof(T_PHB_RECORD));

  /* Store pointer to free the memory allocation. */
  tmp_buffer = buffer;

  memset(buffer,0xFF,sizeof(T_PHB_RECORD));

  db_info_field(db_handle, field_id, &info_field);
  
  /* Read record recno_1 from the database using db_read_record() */
  db_read_record(db_handle, field_id, recno_1, 0, info_field.record_size, buffer);

  /* Read only number from the buffer. */
  
  buffer += (info_field.record_size) - pb_sim_get_size_except_tag(field_id);
  entry_1.len     = *(buffer++) - 1;
  entry_1.ton_npi = *buffer++;
  
  memset(entry_1.number, 0xFF, PHB_PACKED_NUM_LEN);
  memcpy( (char*)entry_1.number, (char*)buffer, entry_1.len );
  buffer += 10; 
  entry_1.cc_id     = *buffer++;

  if (*buffer != 0xFF) /* check for extention records */
  {
    file_id = pb_sim_get_ext_file_id(field_id);
    if (file_id != 0xFFFF)
    {
      ext_rcd_num = (UBYTE)*buffer;

      db_info_field(db_handle, file_id, &info_field);
      
      /* Set the buffer to starting location. */
      buffer = tmp_buffer;

      memset(buffer, 0xFF, info_field.record_size);

      db_read_record(db_handle, file_id, ext_rcd_num, 0, info_field.record_size,buffer);

      pb_sim_read_ext(buffer, &entry_1);

      while(*(buffer + 12) NEQ 0xFF)
      {
        memset(buffer, 0xFF, info_field.record_size);
        db_read_record(db_handle, file_id, *(buffer + 12), 0, info_field.record_size,buffer);
        pb_sim_read_ext(buffer, &entry_1);
      }
    }
  }

  /* Set the buffer to starting location. */
  buffer = tmp_buffer;

  memset(buffer, 0xFF, sizeof(T_PHB_RECORD));
   
  /* Read record recno_2 from the database using db_read_record() */
  db_read_record(db_handle, field_id, recno_2, 0, info_field.record_size, buffer);

  max_tag_len = info_field.record_size - pb_sim_get_size_except_tag(field_id);
  /* Read only number from the buffer. */
  buffer += max_tag_len;
  entry_2.len     = *(buffer++) - 1;
  entry_2.ton_npi = *buffer++;
  
  memset(entry_2.number, 0xFF, PHB_PACKED_NUM_LEN);
  memcpy( (char*)entry_2.number, (char*)buffer, entry_2.len );
  buffer += 10; 
  entry_2.cc_id     = *buffer++;

  if (*buffer != 0xFF) /* check for extention records */
  {
    if (file_id != 0xFFFF)
    {
      ext_rcd_num = (UBYTE)*buffer;
      
      /* Set the buffer to starting location. */
      buffer = tmp_buffer;

      memset(buffer, 0xFF,info_field.record_size);
      
      db_read_record(db_handle, file_id, ext_rcd_num, 0, info_field.record_size,buffer); 

      pb_sim_read_ext(buffer, &entry_2);

      while(*(buffer + 12) NEQ 0xFF)
      {
        memset(buffer, 0xFF,info_field.record_size);
        db_read_record(db_handle, file_id, *(buffer + 12), 0, info_field.record_size,buffer);
        pb_sim_read_ext(buffer, &entry_2);
      }
    }
  }
 
  cmhPHB_getAdrStr(cur_number,
        MAX_PHB_NUM_LEN - 1,
        entry_1.number,
        entry_1.len);
  cmhPHB_getAdrStr(ref_number,
        MAX_PHB_NUM_LEN - 1,
        entry_2.number,
        entry_2.len);

  /* Reverse the first number to compare number from right. */
  pb_sim_revString(cur_number);

  /* Reverse the second number to compare number from right. */
  pb_sim_revString(ref_number);
  
  cmp_res = strcmp((char *)cur_number, (char *)ref_number);

  MFREE(tmp_buffer);
  return cmp_res;
  
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_read_ext     |
+--------------------------------------------------------------------+

    PURPOSE : Reads extension records from the database and copies them to number.
*/
/* Extesion records will be stored as per 11.11.
          Bytes         Description      M/O    Length
          --------------------------------------
              1        Record type         M    1 byte
           2 to 12  Extension data  M   11 bytes
             13        Identifier                 M 1 byte
          --------------------------------------*/

void pb_sim_read_ext(UBYTE *buffer, T_PHB_RECORD *entry)
{
  UBYTE data_len;
  UBYTE data_type;
  UBYTE *data;
  
  TRACE_FUNCTION("pb_sim_read_ext()");

  /* If this extension record is not empty, it is written in phonebook. */
  data = buffer;
 
  data_type = *data;
  data_len = *(data+1);

  switch (data_type)
  {
   
    case 1: /* Called Party Subaddress */
    {
			int sa_len = 0;
      while (sa_len<PHB_PACKED_NUM_LEN)  /* get length of possible already stored subaddr if more than one EXT is used */
      {
        if (entry->subaddr[sa_len] EQ 0xFF)
					break;
        else if ((entry->subaddr[sa_len] & 0xF0) EQ 0xF0)
        {
          sa_len++;
          break;
        }
        else
          sa_len++;
      }

      pb_sim_nibblecopy (entry->subaddr,
                         sa_len,
                         data + 2,
                         data_len);
    }
    break;
        
    case 2: /* Additional data */
      entry->len =
      pb_sim_nibblecopy (entry->number,
                         entry->len,
                         data + 2,
                         data_len);
      break;

      default: /* unknown type */
        break;
  }

  return;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_revString                      |
+--------------------------------------------------------------------+

    PURPOSE : Reverses a string within the same variable.
*/

void pb_sim_revString(char *str)
{
  UBYTE i, j,str_len;
  char ch;

  TRACE_FUNCTION("pb_sim_revString()");

  str_len = strlen(str);
  
  for(i = 0, j = str_len - 1;i < (str_len / 2); i++, j--)
  {
    ch = *(str + i);
    *(str + i) = *(str + j);
    *(str + j) = ch;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_search_alpha_func                      |
+--------------------------------------------------------------------+

    PURPOSE : Searches for a given alpha key in the database.
*/

int pb_sim_search_alpha_func(ULONG flags, const UBYTE *key, int db_handle, USHORT field_id, USHORT rec_num)
{
  T_ACI_PB_TEXT *search_key;
  T_PHB_RECORD entry;
  UBYTE cmpLen = 0;
  T_PHB_TYPE phb_type;
  UBYTE cur_tag[PHB_MAX_TAG_LEN];
  int   cmp_res;

  TRACE_FUNCTION("pb_sim_search_alpha_func()");

  /* Cast search key to appropriate data structure */
  search_key = (T_ACI_PB_TEXT *)key;

  /* Get PHB type from field ID using PHB_ACI function. */ 
  phb_type = pb_get_phb_type_from_ef(field_id);

  /* Read record from the database. */
  pb_sim_read_record(phb_type, rec_num, &entry);
	
  pb_sim_cvt_alpha_for_cmp ( entry.tag, cur_tag, entry.tag_len );

  cmpLen = search_key->len;
  
  if(flags EQ PHB_MATCH_PARTIAL)
    cmpLen = MINIMUM ( entry.tag_len, cmpLen);

  TRACE_EVENT_P1( "cmpLen=%d", cmpLen );
      
  cmp_res = pb_sim_cmpString ( cur_tag, search_key->data, cmpLen );
  
  return cmp_res;
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_search_num_func                      |
+--------------------------------------------------------------------+

    PURPOSE : Searches for a given number key in the database.
*/
int pb_sim_search_num_func(ULONG flags, const UBYTE *key, int db_handle, USHORT field_id, USHORT rec_num)
{
  T_PHB_RECORD entry;
  UBYTE cmpLen = 0;
  T_PHB_TYPE phb_type;
  CHAR  cur_number[MAX_PHB_NUM_LEN];
  CHAR  rev_key[MAX_PHB_NUM_LEN];
  int   cmp_res;
   
  TRACE_FUNCTION("pb_sim_search_num_func()");

  /* Get PHB type from field ID using PHB_ACI function. */ 
  phb_type = pb_get_phb_type_from_ef(field_id);

  /* Read record from the database. */
  if(pb_sim_read_record(phb_type, rec_num, &entry) NEQ PHB_OK)
    return -1;
	
  cmhPHB_getAdrStr(cur_number,
        MAX_PHB_NUM_LEN - 1,
        entry.number,
        entry.len);
  
  /* Reverse the first number to compare number from right. */
  pb_sim_revString(cur_number);

  /* Reverse the second number to compare number from right. */
  
  strcpy (rev_key, (const char*) key);
  
  pb_sim_revString(rev_key);

  cmpLen = strlen(rev_key);

  if(flags EQ PHB_MATCH_PARTIAL)
    cmpLen = MINIMUM(strlen(cur_number), cmpLen);
  
  TRACE_EVENT_P1("Number to be compared: %s", cur_number);
  TRACE_EVENT_P1("Number to be searched: %s", rev_key);
    
  cmp_res = pb_sim_cmpString((UBYTE*)cur_number, (UBYTE*)rev_key, 7);

  TRACE_EVENT_P1("Result of the comparison: %d", cmp_res);

  return cmp_res;
  
}

/*
+--------------------------------------------------------------------+
| PROJECT: MMI-Framework (8417)         MODULE: PHB                  |
| STATE  : code                         ROUTINE: pb_sim_nibblecopy                      |
+--------------------------------------------------------------------+

    PURPOSE : Used to convert BCD nibbles to string.
*/
    
LOCAL int pb_sim_nibblecopy (UBYTE dest[], int destlen, UBYTE src[], int count)
{

  int i;
  int nibble;

  int destnibble=destlen*2;

  TRACE_FUNCTION("pb_sim_nibblecopy()");

  if (destnibble)
  {
    if ((dest[destlen-1] & 0xF0) == 0xF0)    /* check if there is space in last nibble */
      destnibble--;
  }

  for ( i=0; i<count*2; i++ )
  {
    /* check if we access out of bounds */
    if (destnibble/2 >= PHB_PACKED_NUM_LEN)
      return PHB_PACKED_NUM_LEN;

    /* get nibble */
    if (i%2 == 0)
      nibble = src[i/2] & 0x0F;
    else
      nibble = (src[i/2] & 0xF0) >> 4;

    if (nibble == 0xF)      /* end of number detected */
      break;

    /* put nibble */
    if (destnibble%2 == 0)
    {
      dest[destnibble/2] &= 0xF0;
      dest[destnibble/2] |= nibble;
    }
    else
    {
      dest[destnibble/2] &= 0x0F;
      dest[destnibble/2] |= nibble << 4;
    }

    destnibble++;
  }
  return destnibble/2 + destnibble%2; /* round up */
}

/*
+------------------------------------------------------------------------+
| PROJECT : MMI-Framework (8417)         MODULE: PHB                     |
| STATE   : code                         ROUTINE : pb_sim_read_eeprom_ecc    |
+------------------------------------------------------------------------+

  PURPOSE : Read EC number from EEPROM.

*/
LOCAL void pb_sim_read_eeprom_ecc (void)
{
  EF_ECC       efecc;
  UBYTE        *data_ptr;
  UBYTE        version;
  int          rec_ctr;

  TRACE_FUNCTION("pb_sim_read_eeprom_ecc()");

  /* Initialise ECC Phonebook Info. */
  pbs_data.max_record[ECC] = MAX_ECC_RCD;
  pbs_data.used_record[ECC] = 0;

  if (pcm_ReadFile((UBYTE *)EF_ECC_ID,
                    SIZE_EF_ECC,
                    (UBYTE *)&efecc,
                    &version) EQ DRV_OK)
  {   
    { /* workaround when invalid data stored on PCM */
      CHAR  ecc_number[MAX_PHB_NUM_LEN];
      int   num_len;

      data_ptr = efecc.ecc1;
      
      for (rec_ctr=0; rec_ctr < pbs_data.max_record[ECC]; rec_ctr++)
      {
        if (*data_ptr NEQ 0xFF)
        {
          cmhPHB_getAdrStr (ecc_number,
                            MAX_PHB_NUM_LEN - 1,
                            data_ptr,
                            ECC_NUM_LEN);
          for (num_len = 0; num_len < ECC_NUM_LEN; num_len++)
          {
            if (!isdigit (ecc_number[num_len]))
            {
              TRACE_EVENT_P2 ("[ERR] pb_read_eeprom_ecc(): invalid character found %c (%d)",
                              ecc_number[num_len], rec_ctr);
              return;
            }
          }
        }
        data_ptr += ECC_NUM_LEN;
      }
    } /* workaround end */  
    
    data_ptr = &efecc.ecc1[0];

    memset( phb_ecc_element,0, (pbs_data.max_record[ECC] * sizeof(T_PHB_ECC_RECORD)) );

    for (rec_ctr=0; rec_ctr < pbs_data.max_record[ECC]; rec_ctr++)
    {
      if(*data_ptr NEQ 0xff)
      {
        phb_ecc_element[rec_ctr].phy_idx = rec_ctr + 1;
        memcpy(phb_ecc_element[rec_ctr].number, data_ptr, ECC_NUM_LEN);
        data_ptr += ECC_NUM_LEN;
        (pbs_data.used_record[ECC])++;
      }
    }
  }
}

/*
+----------------------------------------------------------------------+
| PROJECT :                              MODULE  : PHB                 |
| STATE   : code                         ROUTINE : pb_sim_prepare_ext_data |
+----------------------------------------------------------------------+


    PURPOSE :   Prepare the data for the extention record.
                If NULL pointer is given for number and subaddress
                then the extention record will marked as unused

*/
/* Extesion records will be stored as per 11.11.
          Bytes         Description      M/O    Length
          --------------------------------------
              1        Record type         M    1 byte
           2 to 12  Extension data  M   11 bytes
             13        Identifier                 M 1 byte
          --------------------------------------*/

LOCAL void pb_sim_prepare_ext_data(UBYTE *ext_data, int ext_count, UBYTE *number, UBYTE no_len, UBYTE *subaddr)
{
  UBYTE *data_num = NULL;
  UBYTE *data_subadd = NULL;

  TRACE_FUNCTION("pb_sim_prepare_ext_data()");

  if(number[10] NEQ 0xFF)
    data_num = number + ((ext_count + 1) * 10);
  
  data_subadd = subaddr + (ext_count * 11);
  
  memset(ext_data, 0xFF, sizeof(ext_data));

  if ((data_num NEQ NULL) AND (*data_num NEQ 0xFF))
  {
    /* Set record type to 2 which corresponds to Additional data.  Record type as per 11.11 */
    ext_data[0] = 2;
    ext_data[1] = no_len - ((ext_count + 1) * 10);
    memcpy (ext_data + 2, data_num, 10);
  }
  else if ((data_subadd NEQ NULL) AND (*data_subadd NEQ 0xFF))
  {
    TRACE_EVENT ("SUBADDRESS EXTENTION");
	 /* Set record type to 1 which corresponds to Called Party Subaddress. Record type as per 11.11 */
    ext_data[0] = 1;
    memcpy (ext_data + 1, data_subadd, 11);
  }
}

/*
+----------------------------------------------------------------------+
| PROJECT :                              MODULE  : PHB                 |
| STATE   : code                         ROUTINE : pb_sim_get_field_id |
+----------------------------------------------------------------------+


    PURPOSE :   Returns field ID for the corresponding Phonebook type.

*/
LOCAL USHORT pb_sim_get_field_id (T_PHB_TYPE type)
{
  USHORT field_id;

  TRACE_FUNCTION("pb_sim_get_field_id()");

  /* Get Elementary file ID for the Phonebook type. */
  switch(type)
  {
    case ADN:
      field_id = SIM_ADN;
      break;

    case LDN:
      field_id = SIM_OCI;
      break;

    case LRN:
      field_id = FFS_LRN;
      break;

    case LMN:
      field_id = FFS_LMN;
      break;

    case UPN:
      field_id = SIM_MSISDN;
      break;

    case FDN:
      field_id = SIM_FDN;
      break;

    case SDN:
      field_id = SIM_SDN;
      break;

    case BDN:
      field_id = SIM_BDN;
      break;

    default:
      TRACE_ERROR ("No such field");
      field_id = 0;
      break;
  }

  return field_id;
}

/*
+----------------------------------------------------------------------+
| PROJECT :                              MODULE  : PHB                 |
| STATE   : code                         ROUTINE : pb_sim_get_ext_file |
+----------------------------------------------------------------------+


    PURPOSE :   Returns field ID for the corresponding Phonebook type.

*/
LOCAL USHORT pb_sim_get_ext_file (T_PHB_TYPE type)
{
  USHORT ext_file_id;

  TRACE_FUNCTION("pb_sim_get_ext_file()");

  /* Get Extension Elementary file ID for the Phonebook type. */
  switch(type)
  {
    case ADN:
    case UPN:
      ext_file_id = SIM_EXT1;
      break;

    case FDN:
      ext_file_id = SIM_EXT2;
      break;

    case SDN:
      ext_file_id = SIM_EXT3;
      break;

    case BDN:
      ext_file_id = SIM_EXT4;
      break;

    case LDN:
      ext_file_id = SIM_EXT5;
      break;

    case LRN:
      ext_file_id = FFS_EXT_LRN;
      break;

    case LMN:
      ext_file_id = FFS_EXT_LMN;
      break;

    default:
      ext_file_id = 0; /* Avoid lint warning */
      break;
  }

  return ext_file_id;
}

/*
+---------------------------------------------------------------------+
| PROJECT : MMI-Framework (8417)       MODULE  : PHB                  |
| STATE   : code                       ROUTINE : pb_sim_cvt_alpha_for_cmp |
+---------------------------------------------------------------------+

  PURPOSE : convert alpha to lower case when not unicode

*/
LOCAL void pb_sim_cvt_alpha_for_cmp ( UBYTE *src,
                                      UBYTE *dst,
                                      UBYTE len )
{
  int i;

  TRACE_FUNCTION("pb_sim_cvt_alpha_for_cmp()");

  if (*src NEQ 0x80) /* 11.11 Annex B 0x80 is the UCS2 indicator */
  {
    for ( i = 0; i < len; i++ )
      dst[i] = (UBYTE)tolower((int)src[i]);
  }
  else
  {
    memcpy (dst, src, len);
  }
}

/*
+----------------------------------------------------------------------+
| PROJECT :                              MODULE  : PHB                 |
| STATE   : code                         ROUTINE : pb_sim_get_ext_file_id                           |
+----------------------------------------------------------------------+


    PURPOSE :   Returns Extension field ID for the corresponding field ID of a Phonebook.

*/
LOCAL USHORT pb_sim_get_ext_file_id (USHORT field_id)
{
  USHORT ext_file_id;

  TRACE_FUNCTION("pb_sim_get_ext_file_id()");

  /* Get Extension Elementary file ID for the Phonebook type. */
  switch(field_id)
  {
    case SIM_ADN:
    case SIM_LND:
    case SIM_MSISDN:
      ext_file_id = SIM_EXT1;
      break;

    case SIM_FDN:
      ext_file_id = SIM_EXT2;
      break;

    case SIM_SDN:
      ext_file_id = SIM_EXT3;
      break;

    case SIM_BDN:
      ext_file_id = SIM_EXT4;
      break;

    case SIM_OCI:
      ext_file_id = SIM_EXT5;
      break;

    case FFS_LRN:
      ext_file_id = FFS_EXT_LRN;
      break;

    case FFS_LMN:
      ext_file_id = FFS_EXT_LMN;
      break;

    default:
      ext_file_id = 0; /* Avoid lint warning */
      break;
  }

  return ext_file_id;
}

/*
+----------------------------------------------------------------------+
| PROJECT :                              MODULE  : PHB                 |
| STATE   : code                         ROUTINE : pb_sim_find_free_record                        |
+----------------------------------------------------------------------+


    PURPOSE :   Returns free record number for the Phonebook type.

*/
GLOBAL int  pb_sim_find_free_record   (T_PHB_TYPE type)
{
  int db_result;
  unsigned i;
  USHORT field_id;

  TRACE_FUNCTION("pb_sim_find_free_record()");

  switch (type)
  {
    case ECC: /* ECC not stored in DB, special handling */
      for (i = 0; i < pbs_data.max_record[ECC]; i++)
      {
        if (phb_ecc_element[i].phy_idx EQ 0)
          return i + 1;
      }
      return 0; /* No free record found */

    case LDN:
    case LRN:
    case LMN:
      return 1; /* For cyclic entries always the first */

    default:
      /* Get Elementary file ID for the Phonebook type. */
      field_id = pb_sim_get_field_id(type);

      db_result = db_find_free_record(pbs_data.db_handle, field_id);
      
			if (db_result <= 0)
        return 0; /* No free record */
      
			return db_result;
  }
}

/*
+-------------------------------------------------------------------------------+
| PROJECT : MMI-Framework (8417)        MODULE  : PHB                           |
| STATE   : code                        ROUTINE : pb_sim_get_size_except_tag    |
+-------------------------------------------------------------------------------+

  PURPOSE : Returns size of data excluding length of tag (alpha identifier)
*/
USHORT pb_sim_get_size_except_tag (USHORT field_id)
{

  TRACE_FUNCTION("pb_sim_get_size_except_tag()");
  switch(field_id)
  {
    case SIM_ADN:
    case SIM_FDN:
    case SIM_BDN:
    case SIM_MSISDN:
    case SIM_SDN:
      return 14; /* 11.11 */

    case FFS_LRN:
    case FFS_LMN:
    case SIM_OCI:
      return 27; /* Using EF_OCI, 31.102 4.2.34 */

    //case SIM_ICI:
    //  return 28; /* Using EF_ICI, 31.102 4.2.33 */

    default:
      TRACE_ERROR("Invalid field ID passed !");
      return 0;
  }
}
/*
+--------------------------------------------------------------------+
| PROJECT : MMI-Framework (8417)        MODULE  : PHB                |
| STATE   : code                        ROUTINE : pb_sim_cmpString          |
+--------------------------------------------------------------------+

  PURPOSE : compare two strings.
            if s1 < s2 return value < 0
            if s1 = s2 return value = 0
            if s1 > s2 return value > 0
*/

static int pb_sim_cmpString ( UBYTE *s1, UBYTE *s2, UBYTE len )
{
  int n = 0;

  /* TRACE_FUNCTION("pb_sim_cmpString()"); */ /* Called too often to trace */

  if ((*s1 EQ 0x80) AND
      (*s2 NEQ 0x80)    )
  {
    s1++;
    len--;
    return pb_sim_cmp2Bytes(s1, s2, len, 1);
  }
  else if ((*s1 NEQ 0x80) AND
           (*s2 EQ 0x80)     )
  {
    s2++;
    len--;
    return pb_sim_cmp2Bytes(s1, s2, len, 2);
  }
  else
  {
    while (*s1 EQ *s2)
    {
      if (*s1 EQ 0xff)
        return 0;
      s1++;
      s2++;
      n++;
      if (n EQ len)
        return 0;
    }

    if ((*s1 > *s2) AND (*s1 NEQ 0xff))
      return 1;

    return -1;
  }
}

/*
+--------------------------------------------------------------------+
| PROJECT : MMI-Framework (8417)        MODULE  : PHB                |
| STATE   : code                        ROUTINE : pb_sim_cmp2Bytes       |
+--------------------------------------------------------------------+

  PURPOSE : compare two strings.
            if s1 < s2 return value < 0
            if s1 = s2 return value = 0
            if s1 > s2 return value > 0

            flag = 1, s1 is unicode
            flag = 2, s2 is unicode
*/

LOCAL int pb_sim_cmp2Bytes(UBYTE *s1, UBYTE *s2, UBYTE len, UBYTE flag)
{
  int n = 0;

  /*  TRACE_FUNCTION("pb_sim_cmp2Bytes()"); */

  if (flag EQ 1)
  {
    while ( (*s1 EQ 0x00 OR *s1 EQ 0xFF ) AND ( *(s1+1) EQ *s2) )
    {
      if (*s1 EQ 0xff AND *(s1+1) EQ 0xFF)
        return 0;
      
			s1 += 2;
      s2++;
      n += 2;

      if (n >= len)
        return 0;
    }

    if ( ( *s1 > 0 AND *s1 NEQ 0xff ) OR
         ( !*s1 AND ( *(s1+1) > *s2 ) ) )
      return 1;

    return -1;
  }

  if (flag EQ 2)
  {
    while ((*s2 EQ 0x00 OR *s2 EQ 0xFF) AND (*s1 EQ *(s2+1)))
    {
      if (*s2 EQ 0xff AND *(s2+1) EQ 0xFF)
        return 0;
      
			s1++;
      s2 += 2;
      n += 2;

      if (n >= len)
        return 0;
    }

    if ((*s2 > 0 AND *s2 NEQ 0xff) OR
        (!*s2 AND (*(s2+1) > *s1))    )
      return -1;

    return 1;
  }
  return -1;
}

/*
+--------------------------------------------------------------------+
| PROJECT : MMI-Framework (8417)        MODULE  : PHB                                       |
| STATE   : code                       ROUTINE : pb_sim_update_extn_records                |
+--------------------------------------------------------------------+

  PURPOSE : Update reference count for extension record and 
                   delete if record is not referenced at all.
*/
LOCAL T_PHB_RETURN pb_sim_update_extn_records(USHORT ext_field_id, USHORT rec_num, T_PHB_EXT_REF_TYPE ref_type)
{
	BOOL delete_record = FALSE;
	int db_result;

  /* Depending on the Extension file update the corresponding array. */
  if(ref_type EQ DECREMENT)
  {
    switch(ext_field_id)
    {
      case SIM_EXT1:
				ext1_ref_count[rec_num]--;

				if(ext1_ref_count[rec_num] EQ 0)
					delete_record = TRUE;

				break;
				
	    case SIM_EXT2:
				ext2_ref_count[rec_num]--;

				if(ext2_ref_count[rec_num] EQ 0)
					delete_record = TRUE;

				break;

	    case SIM_EXT3:
				ext3_ref_count[rec_num]--;

				if(ext3_ref_count[rec_num] EQ 0)
					delete_record = TRUE;

				break;
			
			case SIM_EXT4:
				ext4_ref_count[rec_num]--;

				if(ext4_ref_count[rec_num] EQ 0)
					delete_record = TRUE;

				break;

			case SIM_EXT5:
				ext5_ref_count[rec_num]--;

				if(ext5_ref_count[rec_num] EQ 0)
					delete_record = TRUE;

				break;

			case FFS_EXT_LRN:
				ext_lrn_ref_count[rec_num]--;

				if(ext_lrn_ref_count[rec_num] EQ 0)
					delete_record = TRUE;

				break;

			case FFS_EXT_LMN:
				ext_lmn_ref_count[rec_num]--;

				if(ext_lmn_ref_count[rec_num] EQ 0)
					delete_record = TRUE;

				break;
						
			default:
				return PHB_FAIL;
    }
  }	

	if(ref_type EQ INCREMENT)
  {
    switch(ext_field_id)
    {
      case SIM_EXT1:
				ext1_ref_count[rec_num]++;
				break;
				
	    case SIM_EXT2:
				ext2_ref_count[rec_num]++;
				break;

	    case SIM_EXT3:
				ext3_ref_count[rec_num]++;
				break;
			
			case SIM_EXT4:
				ext4_ref_count[rec_num]++;
				break;

			case SIM_EXT5:
				ext5_ref_count[rec_num]++;
				break;

			case FFS_EXT_LRN:
				ext_lrn_ref_count[rec_num]++;
				break;

			case FFS_EXT_LMN:
				ext_lmn_ref_count[rec_num]++;
				break;
						
			default:
				return PHB_FAIL;
    }
  }	

  /* Delete the extension record if it is not referenced. */
  if(delete_record EQ TRUE)
	{
		db_result = db_delete_record(pbs_data.db_handle, ext_field_id, rec_num);

		if(db_result < DB_OK)
			return PHB_FAIL;
  }

	return PHB_OK;

	
}

/*
+--------------------------------------------------------------------+
| PROJECT : MMI-Framework (8417)        MODULE  : PHB                                       |
| STATE   : code                       ROUTINE : pb_sim_read_ext_record_for_delete       |
+--------------------------------------------------------------------+

  PURPOSE : Read extension records and update the records.
  
*/
LOCAL T_PHB_RETURN pb_sim_read_ext_record_for_delete(T_PHB_TYPE type, USHORT field_id, USHORT db_recno)
{
  USHORT ext_file_id;
  T_DB_INFO_FIELD info_field;
  UBYTE   buffer[RDM_PHB_DATA_SIZE];
  UBYTE data[SIM_MAX_RECORD_SIZE], *ptr;
  UBYTE max_tag_len;
  UBYTE ext_rcd_num;
	T_PHB_RECORD entry;

  TRACE_FUNCTION("pb_sim_read_ext_record_for_delete()");

  
  /* Get Extension file for the Phonebook type. */
  ext_file_id = pb_sim_get_ext_file(type);

  /* Read record from the database. */
  if(db_info_field(pbs_data.db_handle, field_id, &info_field) NEQ DB_OK)
    return PHB_FAIL;
  
  if(db_read_record(pbs_data.db_handle, field_id, db_recno, 0, info_field.record_size, data) < DB_OK)
    return PHB_FAIL;

  /* Convert SIM data to the type T_PHB_RECORD. */
  ptr = data;
  max_tag_len = MINIMUM ((info_field.record_size) - pb_sim_get_size_except_tag(field_id), PHB_MAX_TAG_LEN);

  ptr += (info_field.record_size) - pb_sim_get_size_except_tag(field_id);

  max_tag_len = (info_field.record_size) - pb_sim_get_size_except_tag(field_id);
  
  ++ptr;
  ++ptr;
  
  ptr += 10;
  ++ptr;

  if (*ptr NEQ 0xFF) /* check for extention records */
  {
    ext_rcd_num =(UBYTE)*ptr;

    if(db_info_field(pbs_data.db_handle, ext_file_id, &info_field) NEQ DB_OK)
      return PHB_FAIL;

    /* Reset pointer to start location. */
    ptr = data;

    memset(ptr, 0xFF, info_field.record_size);

    if(db_read_record(pbs_data.db_handle, ext_file_id, ext_rcd_num, 0, info_field.record_size, ptr) < DB_OK) 
      return PHB_FAIL;

	if(pb_sim_update_extn_records(ext_file_id, ext_rcd_num, DECREMENT) EQ PHB_FAIL)
	  return PHB_FAIL;
	
    pb_sim_read_ext(ptr, &entry);

    while(*(ptr + 12) NEQ 0xFF) /* check if a further EXT entry exists */
    {
      memset(ptr, 0xFF, info_field.record_size);

      db_read_record(pbs_data.db_handle, ext_file_id, (USHORT)*(ptr+12), 0, info_field.record_size,ptr);

      if(pb_sim_update_extn_records(ext_file_id, (USHORT)*(ptr+12), DECREMENT) EQ PHB_FAIL)
	    return PHB_FAIL;

      pb_sim_read_ext(ptr, &entry);     
    }
  }
  
  return PHB_OK;
}
#endif /* #ifdef TI_PS_FFS_PHB */