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

