diff src/aci2/aci/phb_aci.c @ 3:93999a60b835

src/aci2, src/condat2: import of g23m/condat source pieces from TCS211
author Mychaela Falconia <falcon@freecalypso.org>
date Mon, 26 Sep 2016 00:29:36 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/aci2/aci/phb_aci.c	Mon Sep 26 00:29:36 2016 +0000
@@ -0,0 +1,2799 @@
+/* 
++----------------------------------------------------------------------------- 
+|  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_aci.h"
+
+#ifdef _SIMULATION_
+  /*
+   * Unfortunately we have a double definition of some preprocessor definitions
+   * within windows.h and within the protocol stack, so we undefine here.
+   */
+  #undef PARITY_NONE
+  #undef PARITY_ODD
+  #undef PARITY_EVEN
+  #undef DRV_OK
+  #include "ffs_pc_api.h"
+  #undef PARITY_NONE
+  #undef PARITY_ODD
+  #undef PARITY_EVEN
+  #undef DRV_OK
+#else
+  #include "ffs/ffs.h"
+#endif
+
+#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"
+
+#ifdef DTI
+#include "dti_conn_mng.h"
+#endif
+#include "cmh_sim.h"
+
+
+/*
+ * Constants and enumerations
+ */
+//#define NR_EF_ICI             20  /* LRN, LMN */
+//#define SIZE_EF_ICI           (28+16)  /* alpha id 16 bytes, 31.102 clause 4.2.33 */
+
+#define NR_EF_OCI             10  /* Arbitrary, LDN */
+#define SIZE_EF_OCI           (27+16)  /* alpha id 16 bytes, 31.102 clause 4.2.34 */
+
+#define NR_EF_EXT5            10  /* Arbitrary */
+#define SIZE_EF_EXT5          13  /* 31.102 clause 4.2.37 */
+
+#define NR_EF_LRN             10  /* Arbitrary, LRN */
+#define SIZE_EF_LRN           SIZE_EF_OCI
+
+#define NR_EF_LMN             10  /* Arbitrary, LMN */
+#define SIZE_EF_LMN           SIZE_EF_OCI
+
+#define NR_EF_EXT_LRN         10  /* Arbitrary */
+#define SIZE_EF_EXT_LRN       SIZE_EF_EXT5
+
+#define NR_EF_EXT_LMN         10  /* Arbitrary */
+#define SIZE_EF_EXT_LMN       SIZE_EF_EXT5
+
+#define PHB_MAX_QUEUE         4   /* Queued LDN entries */
+#define SIM_MAX_RECORD_SIZE   256 /* Maximum size of a SIM record */
+
+#define PHB_STATE_NULL        0   /* NULL state before reading phonebook    */
+#define PHB_STATE_IDLE        1   /* IDLE state, phonebook has been read    */
+#define PHB_STATE_VERIFY      2   /* Verify SIM (Initialization, SAT)       */
+#define PHB_STATE_READ        3   /* Reading from SIM (Initialization, SAT) */
+#define PHB_STATE_WRITE       4   /* Write/Delete single record to SIM      */
+#define PHB_STATE_DELETE_BOOK 5   /* Delete a whole SIM phonebook           */
+
+#define SET_PHB_STATE(n)  pba_data.state = n;
+#define GET_PHB_STATE()   pba_data.state
+
+typedef enum
+{
+  INVALID_EXT = -1,
+  EXT1,             /* ADN, LDN phonebook Extention */
+  EXT2,             /* FDN phonebook Extention      */
+  EXT3,
+  EXT4,
+  EXT5,             /* Release 1999+ for EF_ICI, EF_OCI */
+  EXT_LRN,          /* Extension for LRN */
+  EXT_LMN,          /* Extension for LMN */
+  MAX_PHB_EXT
+} T_EXT_TYPE; 
+
+typedef struct 
+{
+  USHORT        index;
+  T_PHB_RECORD  entry;
+} T_PHB_QUEUE;
+
+/*
+ * Type definitions
+ */
+typedef struct
+{
+  /* Fixed Dialling Numbers mode */
+  T_PHB_FDN_MODE fdn_mode;
+
+  /* Fixed Dialling Number class type */
+  T_ACI_CLASS fdn_classtype;
+
+  /* T_PHB_STATE of the phonebook */
+  T_PHB_STAT phb_stat;
+  
+  /* Current state of the phonebook PHB_STATE_XXX */
+  UBYTE state;
+
+  /* SIM data */
+  UBYTE *data;
+  
+  /* SIM service table */
+  UBYTE sim_service_table[MAX_SRV_TBL];
+
+  /* Database has to be recreated (IMSI changed or DB unclean) */
+  BOOL db_recreate;
+
+  /* Paused elementary file if reading extension record, otherwise 0 */
+  USHORT paused_ef;
+
+  /* Paused record number if reading extension record, otherwise 0 */
+  UBYTE paused_no;
+
+  /* Delete all: Book to delete, Read: Current book reading */
+  T_PHB_TYPE current_book;
+  
+  /* Delete all: current record */
+  UBYTE del_record;
+
+  /* Book created */
+  BOOL book_created[MAX_PHONEBOOK];
+
+  /* Extension created */
+  BOOL ext_created[MAX_PHB_EXT];
+
+  /* We are reading the 1st ext record only to get the number of records */
+  BOOL ext_dummy_read;
+
+  /* Read flags for SIM phonebooks. Set to TRUE when reading has started */
+  BOOL book_read[MAX_PHONEBOOK];
+
+  /* Maximum number of phonebook records */
+  UBYTE phb_record_max[MAX_PHONEBOOK];
+  /* Maximum number of extension records */
+  UBYTE ext_record_max[MAX_PHB_EXT];
+
+  /* Record sizes of phonebook records */
+  UBYTE phb_record_len[MAX_PHONEBOOK];
+  /* Record sizes of extension records */
+  UBYTE ext_record_len[MAX_PHB_EXT];
+
+  /* Queued LDN entries during startup */
+  UBYTE c_queued;
+  T_PHB_QUEUE *queued[PHB_MAX_QUEUE];
+  
+  /* Records to be synchronized to the SIM */
+  T_DB_CHANGED records_changed;
+} T_PHB_ACI_DATA;
+
+/* We pack all internal data into one data structure */
+LOCAL T_PHB_ACI_DATA pba_data;
+
+
+/* 
+ * Prototypes for local functions
+ */
+LOCAL UBYTE pb_get_max_num_len          (T_PHB_TYPE type);
+LOCAL BOOL pb_sim_service               (UBYTE nr);
+LOCAL BOOL pb_read_sim_record           (USHORT data_id,
+                                         UBYTE rcd_num,
+                                         UBYTE len);
+LOCAL BOOL pb_read_sim (USHORT data_id, UBYTE len, UBYTE max_length);
+LOCAL void pb_read_next_sim_book        (void);
+LOCAL void pb_read_sim_record_cb        (SHORT table_id);
+LOCAL void pb_read_sim_cb               (SHORT table_id);
+LOCAL void pb_sat_update_reset          (USHORT ef);
+LOCAL T_PHB_RETURN pb_sync_next_sim_record (BOOL first);
+LOCAL T_PHB_RETURN pb_write_sim_record  (USHORT ef,
+                                         UBYTE phy_recno,
+                                         UBYTE entry_size,
+                                   const UBYTE *buffer);
+LOCAL void pb_write_sim_record_cb       (SHORT table_id);
+T_PHB_TYPE pb_get_phb_type_from_ef      (USHORT ef);
+T_EXT_TYPE pb_get_ext_type_from_ef      (USHORT ef);
+LOCAL void pb_status_ind                (T_PHB_STAT phb_stat,
+                                         SHORT cmeError);
+LOCAL T_PHB_RETURN pb_write_queue       (const T_PHB_RECORD *entry);
+LOCAL void pb_clear_queue               (void);
+LOCAL T_PHB_RETURN pb_read_queue        (void);
+
+/*
+ * Functions - Interface functions to external modules
+ */
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_init                            |
++----------------------------------------------------------------------------+
+
+  PURPOSE : Power-on initialization of the phonebook module. This function
+            is called at a point in time by pei_init() when it cannot be 
+            expected that the protocol stack has been booted up completely,
+            so it is undesirable to do anything here which might rely on
+            a module still not started up like the PCM or the FFS.
+  
+*/
+GLOBAL void pb_init (void)
+{
+  TRACE_FUNCTION ("pb_init()");
+
+  memset (&pba_data, 0, sizeof (T_PHB_ACI_DATA));
+
+  pba_data.fdn_mode = NO_OPERATION;
+  pba_data.fdn_classtype = CLASS_VceDatFaxSms;
+
+  pb_sim_init();
+
+#ifdef SIM_TOOLKIT
+  simShrdPrm.fuRef= - 1;
+  psaSAT_FURegister (pb_update);
+#endif /* #ifdef SIM_TOOLKIT */
+
+  SET_PHB_STATE (PHB_STATE_NULL);
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_exit_phb                        |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function synchronizes, if necessary, all unwritten data,
+            shuts down the SIM phonebook layer and deallocates all 
+            resources. The SIM itself is not deactivated here.
+            
+
+*/
+LOCAL void pb_exit_phb (void)
+{
+  TRACE_FUNCTION ("pb_exit_phb()");
+
+  /* 
+   * Flush everything which has not yet been written.
+   * Note: It's a good idea if everything is written immediately
+   * so that we don't need to flush anything here. Competitor phones
+   * do the job in this way, this has the advantage that even after
+   * a phone crash immediately after dialling a number or missing
+   * a call nothing is lost.
+   */
+  (void)pb_sim_flush_data ();
+
+  /* Shutdown the lower layers */
+  pb_sim_exit ();
+
+  /*
+   * Free all allocated resources
+   */
+  if (pba_data.data NEQ NULL)
+  {
+    ACI_MFREE (pba_data.data);
+    pba_data.data = NULL;
+  }
+
+  pb_clear_queue ();
+
+  /*
+   * Set phonebook to no operation 
+   */
+  pba_data.fdn_mode = NO_OPERATION;
+  pba_data.phb_stat = PHB_UNKNOWN;  
+  SET_PHB_STATE (PHB_STATE_NULL);
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_exit                            |
++----------------------------------------------------------------------------+
+
+  PURPOSE : Shutdown phonebook and the SIM itself also.
+
+*/
+GLOBAL void pb_exit (void)
+{
+  TRACE_FUNCTION ("pb_exit()");
+
+  /* Shutdown SIM phonebook */
+  pb_exit_phb ();
+
+  /* Shutdown the SIM itself */
+  simShrdPrm.synCs = SYNC_DEACTIVATE;
+  psaSIM_SyncSIM();
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_reset                           |
++----------------------------------------------------------------------------+
+
+  PURPOSE : Resets the phonebook, basically pb_exit() / pb_init().
+  
+*/
+GLOBAL void pb_reset (void)
+{
+  TRACE_FUNCTION ("pb_reset()");
+
+  if (GET_PHB_STATE() EQ PHB_STATE_NULL)
+    return;
+
+  pb_exit_phb();
+  pb_init();
+}
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_set_sim_ecc                     |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function set's the emergency call numbers.
+            This can only happen at startup time when the SIM when
+            a SIM_ACTIVATE_CNF / SIM_ACTIVATE_IND is received.
+            At this point in time the entering of PIN may be outstanding,
+            the only information we may have gotten are the emergency call
+            numbers.
+
+*/
+GLOBAL void pb_set_sim_ecc (USHORT cause,
+                            UBYTE ecc_len,
+                            const UBYTE *sim_ecc)
+{
+  TRACE_FUNCTION ("pb_set_sim_ecc()");
+
+  if (pba_data.fdn_mode NEQ NO_OPERATION)
+  {
+     /* 
+      * Setting of the emergency call numbers after having gotten the
+      * IMSI of the SIM is ignored.
+      */
+    return;
+  }
+
+  if ((cause EQ SIM_CAUSE_OTHER_ERROR) OR
+      (cause EQ SIM_CAUSE_CARD_REMOVED) OR
+      (cause >= SIM_CAUSE_PARAM_WRONG AND cause <= SIM_CAUSE_DRV_TEMPFAIL))
+  {
+    /* 
+     * Some error from the SIM. Indicate a fallback to the PCM/FFS.
+     */
+    (void)pb_sim_set_ecc (0, NULL);
+  }
+  else
+  {
+    (void)pb_sim_set_ecc (ecc_len, sim_ecc);
+  }
+
+
+
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_inserted_sim                    |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function is called when the PIN has been entered and we have
+            the IMSI and full access on the SIM phonebook. Reading/Verifying
+            of phonebook data is not started at this point except for the 
+            ECC phonebook.
+
+*/
+GLOBAL void pb_inserted_sim (UBYTE c_sim_serv,
+                             UBYTE *sim_serv,
+                             const T_imsi_field *imsi_field,
+                             UBYTE adn_bdn_fdn_func,
+                             UBYTE phase)       // For further study
+{
+  T_FFS_SIZE ffs_size;                /* FFS result code */
+  T_ACI_CLASS classFDN;               /* FDN class */
+  UBYTE ub_class = (UBYTE)CLASS_None; /* T_ACI_CLASS */
+
+  TRACE_FUNCTION ("pb_inserted_sim()");
+
+  /* Store SIM service table */
+  if (c_sim_serv > MAX_SRV_TBL)
+    c_sim_serv = MAX_SRV_TBL; /* Garbage protection */
+  memcpy (pba_data.sim_service_table, sim_serv, c_sim_serv);
+
+  /* 
+   * Open SIM phonebook. Remember whether the database has to be recreated 
+   * for some reason (SIM changed, database unclean).
+   */
+  if (pb_sim_open (imsi_field, &pba_data.db_recreate) NEQ PHB_OK)
+  {
+    /* We're here in really big trouble and can do nothing about it */
+    TRACE_ERROR ("Fatal: pb_sim_open() NEQ PHB_OK");
+  }
+
+  /*
+   * Update ECC phonebook
+   */
+  pba_data.book_read[ECC] = TRUE;
+  if (!pb_read_sim (SIM_ECC, NOT_PRESENT_8BIT, (UBYTE)SIM_MAX_RECORD_SIZE))
+  {
+    /* Unexpected problem. Live with previously read values */
+    TRACE_ERROR ("Unexpected: No free SIM slot");
+  }
+
+  switch (adn_bdn_fdn_func)
+  {
+    case SIM_ADN_ENABLED:
+    case SIM_ADN_BDN_ENABLED:
+      pba_data.fdn_mode = FDN_DISABLE;
+      break;
+
+    case SIM_FDN_ENABLED:
+    case SIM_FDN_BDN_ENABLED:
+      pba_data.fdn_mode = FDN_ENABLE;
+
+      /* read last fdn_classtype from FFS */
+      ffs_size = ffs_file_read ("/mmi/fdnClassType", &ub_class, sizeof(ub_class));
+      
+      if (ffs_size EQ sizeof(ub_class)) /* successful read */
+      {
+        classFDN = (T_ACI_CLASS)ub_class;
+        
+        /* only these two classes are currently supported */
+        if (classFDN EQ CLASS_VceDatFax OR 
+            classFDN EQ CLASS_VceDatFaxSms)
+        {
+          pba_data.fdn_classtype = classFDN;
+        }
+      }
+      break;
+
+    default: /* SIM_NO_OPERATION or trash */
+      pba_data.fdn_mode = NO_OPERATION;
+      break;
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_start_build                     |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function is called when the flash phonebook has to be 
+            read/verified from/against the phonebook stored on the SIM card.
+            This is triggered by the reception of the 
+            MNSMS_REPORT_IND (SMS_STATE_READY) primitive.
+
+*/
+GLOBAL void pb_start_build (BOOL unchanged)
+{
+  TRACE_FUNCTION ("pb_start_build()");
+  
+  if (pba_data.db_recreate)
+  {
+    /* 
+     * Indicate a busy phonebook. We have to re-read all from scratch 
+     */
+    pb_status_ind (PHB_BUSY, CME_ERR_NotPresent);
+    SET_PHB_STATE (PHB_STATE_READ);
+  }
+  else
+  {
+    /* 
+     * SIM (IMSI) not changed and database clean,
+     * allow reading from the SIM phonebook by the MMI.
+     */
+    pb_status_ind (PHB_READY, CME_ERR_NotPresent);
+    SET_PHB_STATE (PHB_STATE_VERIFY);
+  }
+
+  pba_data.ext_dummy_read = FALSE;
+
+#ifdef _SIMULATION_
+  TRACE_EVENT_P1 ("SRV_ADN: %s",  pb_sim_service (SRV_ADN)  ? "YES" : "NO");
+  TRACE_EVENT_P1 ("SRV_FDN: %s",  pb_sim_service (SRV_FDN)  ? "YES" : "NO");
+  TRACE_EVENT_P1 ("SRV_CCP: %s",  pb_sim_service (SRV_CCP)  ? "YES" : "NO");
+  TRACE_EVENT_P1 ("SRV_MSISDN: %s",pb_sim_service (SRV_MSISDN) ? "YES" : "NO");
+  TRACE_EVENT_P1 ("SRV_EXT1: %s", pb_sim_service (SRV_EXT1) ? "YES" : "NO");
+  TRACE_EVENT_P1 ("SRV_EXT2: %s", pb_sim_service (SRV_EXT2) ? "YES" : "NO");
+  TRACE_EVENT_P1 ("SRV_LDN: %s",  pb_sim_service (SRV_LDN)  ? "YES" : "NO");
+  TRACE_EVENT_P1 ("SRV_SDN: %s",  pb_sim_service (SRV_SDN)  ? "YES" : "NO");
+  TRACE_EVENT_P1 ("SRV_EXT3: %s", pb_sim_service (SRV_EXT3) ? "YES" : "NO");
+  TRACE_EVENT_P1 ("SRV_BDN: %s",  pb_sim_service (SRV_BDN)  ? "YES" : "NO");
+  TRACE_EVENT_P1 ("SRV_EXT4: %s", pb_sim_service (SRV_EXT4) ? "YES" : "NO");
+#endif
+
+  pb_read_next_sim_book();
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_update                          |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function is called when the SIM wants to inform the 
+            phonebook that some elementary files have been changed.
+            Returns TRUE if no files aere changed affecting the phonebook,
+            otherwise FALSE.
+
+*/
+GLOBAL BOOL pb_update (int ref,
+                       T_SIM_FILE_UPDATE_IND *fu)
+{
+  unsigned i;           /* Index variable */
+  T_PHB_TYPE phb_type;  /* Phonebook type */ 
+  T_EXT_TYPE ext_type;  /* Extension type */ 
+  USHORT ef;            /* Elementary file number */
+
+  TRACE_FUNCTION ("pb_update()");
+
+  simShrdPrm.fuRef = -1;  /* Assume phonebook is not affected */
+
+  for (i = 0; i < fu->val_nr; i++)
+  {
+    ef = fu->file_id[i];
+
+    if (ef EQ SIM_SST)
+    {
+      /*
+       * When SIM service table is changed, then all SIM phonebooks
+       * will be updated.
+       */
+
+      /* Mark all phonebooks as unread */
+      pb_sat_update_reset (SIM_ECC);
+      pb_sat_update_reset (SIM_ADN);
+      pb_sat_update_reset (SIM_FDN);
+      pb_sat_update_reset (SIM_BDN);
+#ifdef SIM_LND_SUPPORT
+      pb_sat_update_reset (SIM_LND);
+#endif
+      pb_sat_update_reset (SIM_MSISDN);
+      pb_sat_update_reset (SIM_SDN);
+
+      /* Mark all extensions as unread */
+      pb_sat_update_reset (EXT1);
+      pb_sat_update_reset (EXT2);
+      pb_sat_update_reset (EXT3);
+      pb_sat_update_reset (EXT4);
+
+      if (!pb_read_sim (SIM_SST, NOT_PRESENT_8BIT, (UBYTE)SIM_MAX_RECORD_SIZE))
+      {
+        /*
+         * We could not get an empty slot and are in trouble now as there is
+         * no good error handling possible here. On the other hand, it is 
+         * not expected ever that an error occurs here.
+         */
+        TRACE_ERROR ("Internal problem getting a SIM slot");
+        return TRUE;  /* No update in progress */
+      }
+
+      simShrdPrm.fuRef = ref;   /* Something to do */
+
+      SET_PHB_STATE (PHB_STATE_READ);
+      return FALSE; /* Update in progress */
+    }
+  }
+
+  /*
+   * At least the SIM service table has not been changed, check now for
+   * single phonebooks and extension records.
+   */
+  
+  for (i = 0; i < fu->val_nr; i++)
+  {
+    ef = fu->file_id[i];
+    phb_type = pb_get_phb_type_from_ef (ef);
+    ext_type = pb_get_ext_type_from_ef (ef);
+
+    if (phb_type NEQ INVALID_PHB)
+    {
+      /* Phonebook affected by change */
+      simShrdPrm.fuRef = ref;
+
+      /* Reset respective field */
+      pb_sat_update_reset (ef);
+
+      switch (phb_type)
+      {
+        case ADN:
+          pb_sat_update_reset (SIM_FDN);
+          break;
+
+        case FDN:
+          pb_sat_update_reset (SIM_ADN);
+          break;
+        
+        default:
+          break;
+      }
+    } 
+    else if (ext_type NEQ INVALID_EXT)
+    {
+      /* Phonebook affected by change */
+      simShrdPrm.fuRef = ref;
+
+      /* Reset respective field */
+      pb_sat_update_reset (ef);
+
+      /* Mark also the appropriate book itself as unread */
+      switch (ext_type)
+      {
+        case EXT1:
+          pb_sat_update_reset (SIM_ADN);
+          pb_sat_update_reset (SIM_MSISDN);
+#ifdef SIM_LND_SUPPORT
+          pb_sat_update_reset (SIM_LND);
+#endif
+          break;
+
+        case EXT2:
+          pb_sat_update_reset (SIM_FDN);
+          break;
+
+        case EXT3:
+          pb_sat_update_reset (SIM_SDN);
+          break;
+
+        case EXT4:
+          pb_sat_update_reset (SIM_EXT4);
+          break;
+
+        default:
+          TRACE_ERROR ("Unexpected default"); /* Everything caught */
+          break;
+      }
+    }
+  }
+
+  if (simShrdPrm.fuRef NEQ -1)
+  {
+    pb_start_build (FALSE);
+    return FALSE; /* FALSE means update in progress */
+  }
+
+  return TRUE; /* TRUE means nothing to do */
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_flush_data                      |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function is called when someone wants to flush some pending
+            data to persistent memory. Probably a bad concept, it's always
+            better to flush always internally if some operation is finished
+            and to synchronize also to the SIM immediately. This has the
+            advantage that even after a crash nothing is lost.
+
+*/
+T_PHB_RETURN pb_flush_data (void)
+{
+  TRACE_FUNCTION ("pb_flush_data()");
+
+  /* This function is empty, and this should remain this way if possible */
+  return PHB_OK;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_add_record                      |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function adds or replaces a phonebook entry.
+
+*/
+GLOBAL T_PHB_RETURN pb_add_record (T_PHB_TYPE type,
+                                   USHORT phy_recno,
+                                   const T_PHB_RECORD *entry)
+{
+  T_PHB_RETURN phb_result;
+  T_DB_CHANGED dummy_changed;
+
+  TRACE_FUNCTION ("pb_add_record()");
+
+#ifdef _SIMULATION_
+  {
+    char name [PHB_MAX_TAG_LEN + 1];
+    char number[MAX_PHB_NUM_LEN];
+
+    memset (name, 0, PHB_MAX_TAG_LEN + 1);
+    memcpy (name, entry->tag, entry->tag_len);
+    cmhPHB_getAdrStr (number,
+                      MAX_PHB_NUM_LEN - 1,
+                      entry->number,
+                      entry->len);
+    if ((UBYTE)(name[0]) >= 0x80)
+      strcpy (name, "<Some UCS2 coding>");
+
+    TRACE_EVENT_P4 ("Adding number %s with name '%s' to book %d record %d",
+                    number, name, type, phy_recno);
+  }
+#endif
+
+  /* Fix phy_recno parameter for circular books */
+  if ((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN))
+  {
+    if (phy_recno EQ 0)
+      phy_recno = 1;
+  }
+
+  switch (GET_PHB_STATE())
+  {
+    case PHB_STATE_IDLE:
+
+      /* Add the data in the database */
+      phb_result = pb_sim_add_record (type, 
+                                      phy_recno, 
+                                      entry, 
+                                      &pba_data.records_changed);
+      if (phb_result NEQ PHB_OK)
+        return phb_result;  /* Record could not be added to the database */
+
+      if (pba_data.records_changed.entries NEQ 0)
+      {
+        SET_PHB_STATE (PHB_STATE_WRITE);
+      }
+
+      /* Start synchronizing record(s) to the SIM */
+      return pb_sync_next_sim_record (TRUE);
+
+    case PHB_STATE_VERIFY:
+    case PHB_STATE_READ:
+      if ((type EQ LRN) OR (type EQ LMN))
+      {
+        /* 
+         * In Release 1998- there is no counterpart on the SIM here,
+         * we can write immediately as we don't have to synch to the SIM.
+         */
+        return (pb_sim_add_record (type, 
+                                   phy_recno, 
+                                   entry, 
+                                   &dummy_changed));
+      }
+      else if (type EQ LDN)
+      {
+        /* We have to queue the LDN entry and will write later */
+        return pb_write_queue (entry);
+      }
+      return PHB_FAIL;
+
+    default:
+      return PHB_FAIL;
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_del_record                      |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function deletes a phonebook entry.
+
+*/
+GLOBAL T_PHB_RETURN pb_del_record (T_PHB_TYPE type,
+                                   USHORT phy_recno)
+{
+  T_PHB_RETURN phb_result;
+
+  TRACE_FUNCTION ("pb_del_record()");
+
+  if (GET_PHB_STATE() NEQ PHB_STATE_IDLE)
+    return PHB_FAIL;
+
+  /* Delete the data in the database */
+  phb_result = pb_sim_del_record (type,
+                                  phy_recno,
+                                  &pba_data.records_changed);
+  if (phb_result NEQ PHB_OK)
+    return phb_result;  /* Record could not be deleted from the database */
+
+  if (pba_data.records_changed.entries NEQ 0)
+  {
+    SET_PHB_STATE (PHB_STATE_WRITE);
+  }
+
+  /* Start synchronizing record(s) to the SIM */
+  return pb_sync_next_sim_record (TRUE);
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_check_fdn                       |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function checks whether a phone number is in FDN phonebook.
+
+*/
+#define RETURN(x) { retVal = x; goto cleanup_exit; }
+/*lint -e{801} Use of goto*/
+GLOBAL T_PHB_RETURN pb_check_fdn (UBYTE toa,
+                                  const UBYTE *number)
+{
+  T_PHB_RETURN retVal;
+  T_PHB_RECORD *phb_record;
+  size_t cmp_len;
+  CHAR cur_number[MAX_PHB_NUM_LEN];
+  USHORT phy_recno;
+  SHORT max_rcd;
+  SHORT dummy_used_rcd;
+  UBYTE dummy_tag_len;
+
+  ACI_MALLOC (phb_record, sizeof (T_PHB_RECORD));
+
+  TRACE_FUNCTION ("pb_check_fdn()");
+
+  retVal = pb_sim_read_sizes (FDN, 
+                              &max_rcd, 
+                              &dummy_used_rcd, 
+                              &dummy_tag_len);
+  if (retVal NEQ PHB_OK)
+  {
+    TRACE_ERROR ("Unexpected return from pb_sim_read_sizes()");
+    RETURN (retVal)
+  }
+  
+  /* 
+   * Do a linear search through all the records applying the number comparision
+   * rules which make us pass 51.010 test case 27.18.1.1.4.2.
+   * Those rules are different from those which are to be applied if a matching
+   * record has to be found for an incoming call, therefore we cannot use 
+   * pb_sim_search_number() here.
+   * As normally FDN phonebooks have not more than 10 entries (max_rcd) a 
+   * simple linear search will fulfill here all timing requirements.
+   */
+  
+  for (phy_recno = 1; phy_recno <= max_rcd; phy_recno++)
+  {
+    retVal = pb_sim_read_record (FDN, phy_recno, phb_record);
+    if (retVal EQ PHB_OK)
+    {
+      cmhPHB_getAdrStr (cur_number,
+                        MAX_PHB_NUM_LEN - 1,
+                        phb_record->number,
+                        phb_record->len);
+      cmp_len = strlen (cur_number);
+      if (strncmp ((char *)number, cur_number, cmp_len) EQ 0)
+      {
+        /* Number matches. ACI-SPR-11927: check type of address */ 
+        if ((toa EQ 0) OR
+            (toa EQ phb_record->ton_npi) OR
+            (phb_record->ton_npi EQ 0xFF))
+        {
+          RETURN (PHB_OK)
+        }
+      }
+    }
+  }
+  RETURN (PHB_FAIL) /* Not found */
+
+cleanup_exit:
+  ACI_MFREE (phb_record);
+  return retVal;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_switch_adn_fdn                  |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function switches FDN and ADN phonebooks (sAT_PlusCLCK()).
+
+*/
+GLOBAL T_PHB_RETURN pb_switch_adn_fdn (T_PHB_FDN_MODE mode,
+                                       T_ACI_CLASS classFDN)
+{
+  TRACE_FUNCTION ("pb_switch_adn_fdn()");
+
+  if (GET_PHB_STATE() NEQ PHB_STATE_IDLE)
+    return PHB_FAIL;
+
+  /* Check parameters */
+  switch (mode)
+  {
+    case FDN_DISABLE:
+    case FDN_ENABLE:
+      break;
+
+    default:
+      return PHB_FAIL;
+  }
+
+  if (classFDN NEQ pba_data.fdn_classtype)
+  {
+    UBYTE ub_class;
+    
+    ub_class = (UBYTE)classFDN;
+    pba_data.fdn_classtype = classFDN;
+
+#ifndef _SIMULATION_
+    if (ffs_fwrite("/mmi/fdnClassType", &classFDN, sizeof(ub_class)) < 1)
+    {
+      TRACE_ERROR ("sAT_PlusCLCK: failed to write /mmi/fdnClassType");
+    }
+#endif /* #ifndef _SIMULATION_ */
+  }
+
+#if 1
+
+  pba_data.fdn_mode = mode;
+
+  /* Remove ADN from database */
+  (void)pb_sim_remove_ef (SIM_ADN);
+  pba_data.book_created[ADN] = FALSE;
+  pba_data.book_read[ADN] = FALSE;
+
+  /* Remove FDN from database */
+  (void)pb_sim_remove_ef (SIM_FDN);
+  pba_data.book_created[FDN] = FALSE;
+  pba_data.book_read[FDN] = FALSE;
+
+  /* Remove EXT2 from database */
+  (void)pb_sim_remove_ef (SIM_EXT2);
+  pba_data.ext_created[EXT2] = FALSE;
+
+  /* Force cmhPHB_StatIndication (PHB_BUSY, CME_ERR_NotPresent) */
+  pba_data.db_recreate = TRUE;
+
+  SET_PHB_STATE (PHB_STATE_READ);
+
+  /* Start reading changed books */
+  pb_start_build (FALSE);
+#else
+  // This optimization does not comply with current test cases,
+  // not understood perfectly whether the test cases can be
+  // changed, so kept old behaviour.
+  if (pba_data.fdn_mode NEQ mode)
+  {
+    pba_data.fdn_mode = mode;
+
+    if (mode EQ FDN_ENABLE)
+    {
+      /* Remove ADN from database */
+      (void)pb_sim_remove_ef (SIM_ADN);
+      pba_data.book_created[ADN] = FALSE;
+      pba_data.book_read[ADN] = FALSE;
+    }
+    else
+    {
+      /* Remove FDN from database */
+      (void)pb_sim_remove_ef (SIM_FDN);
+      pba_data.book_created[FDN] = FALSE;
+      pba_data.book_read[FDN] = FALSE;
+
+      /* Remove EXT2 from database */
+      (void)pb_sim_remove_ef (SIM_EXT2);
+      pba_data.ext_created[EXT2] = FALSE;
+    }
+
+    /* Force cmhPHB_StatIndication (PHB_BUSY, CME_ERR_NotPresent) */
+    pba_data.db_recreate = TRUE;
+
+    SET_PHB_STATE (PHB_STATE_READ);
+
+    /* Start reading changed books */
+    pb_start_build (FALSE);
+  }
+#endif
+  return PHB_OK;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_del_book                        |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function deletes a whole SIM phonebook
+
+*/
+GLOBAL T_PHB_RETURN pb_del_book (T_PHB_TYPE book)
+{
+  T_PHB_RETURN phb_result;
+  UBYTE max_record;
+
+  TRACE_FUNCTION ("pb_del_book()");
+
+  if (GET_PHB_STATE() NEQ PHB_STATE_IDLE)
+    return PHB_FAIL;
+
+  /* Remember book to delete, initialize record to delete */
+  pba_data.current_book = book;
+  pba_data.del_record = 1;
+  max_record = pba_data.phb_record_max[pba_data.current_book];
+
+  do
+  {
+    /* Delete the record in the database */
+    phb_result = pb_sim_del_record (pba_data.current_book, 
+                                    pba_data.del_record,
+                                    &pba_data.records_changed);
+    if (phb_result NEQ PHB_OK)
+      return phb_result;
+    pba_data.del_record++;
+  } 
+  while ((pba_data.del_record <= max_record) AND
+         (pba_data.records_changed.entries EQ 0));
+
+  if (pba_data.records_changed.entries NEQ 0)
+  {
+    /* Synchronize to SIM */
+    SET_PHB_STATE (PHB_STATE_DELETE_BOOK);
+  
+    /* Start synchronizing record(s) to the SIM */
+    return pb_sync_next_sim_record (TRUE);
+  }
+
+  return PHB_OK;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_get_fdn_classtype               |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function gets the FDN class type
+
+*/
+GLOBAL T_ACI_CLASS pb_get_fdn_classtype (void)
+{
+  TRACE_FUNCTION ("pb_get_fdn_classtype()");
+
+  return pba_data.fdn_classtype;
+
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_get_fdn_mode                    |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function gets the FDN mode
+
+*/
+GLOBAL T_PHB_FDN_MODE pb_get_fdn_mode (void)
+{
+  TRACE_FUNCTION ("pb_get_fdn_mode()");
+
+  return pba_data.fdn_mode;
+
+}
+
+
+/*
+ * Wrapper functions. Wrapper functions don't define own functionality 
+ * except of routing to a different block which is the SIM part of 
+ * the phonebook here. For a description of these functions have
+ * a look into the SIM part of the phonebook.
+ */
+
+GLOBAL T_PHB_RETURN pb_read_record (T_PHB_TYPE type,
+                                    SHORT phy_recno,
+                                    T_PHB_RECORD *entry)
+{
+  T_PHB_RETURN phb_result;
+
+  TRACE_FUNCTION ("pb_read_record()");
+
+  if (phy_recno EQ 0)
+    return PHB_FAIL;
+
+  switch (GET_PHB_STATE())
+  {
+    case PHB_STATE_VERIFY:
+      /* 
+       * For LDN records, first have a look into the queue
+       */
+      if ((type EQ LDN) AND (phy_recno - 1 < pba_data.c_queued))
+      {
+        /* Entry freshly dialled and still in the queue */
+        *entry = pba_data.queued[phy_recno - 1]->entry;
+        return PHB_OK;
+      }
+      phb_result = pb_sim_read_record (type, 
+                                       (USHORT)(phy_recno - pba_data.c_queued),
+                                       entry);
+      TRACE_EVENT_P3 ("type = %d, phy_recno = %d, phb_result = %d",
+                      type, phy_recno, phb_result);
+      return phb_result;
+
+    case PHB_STATE_READ:
+      /* 
+       * For LDN records, first have a look into the queue
+       */
+      if ((type EQ LDN) AND (phy_recno - 1 < pba_data.c_queued))
+      {
+        /* Entry freshly dialled and still in the queue */
+        *entry = pba_data.queued[phy_recno - 1]->entry;
+        return PHB_OK;
+      }
+      return PHB_FAIL; /* We already know the SIM was changed */
+
+    case PHB_STATE_IDLE:
+      phb_result = pb_sim_read_record (type, phy_recno, entry);
+      TRACE_EVENT_P3 ("type = %d, phy_recno = %d, phb_result = %d",
+                      type, phy_recno, phb_result);
+      return phb_result;
+
+    default:
+      return PHB_FAIL;
+  }
+}
+
+
+GLOBAL T_PHB_RETURN pb_read_alpha_record (T_PHB_TYPE type,
+                                          SHORT order_num,
+                                          T_PHB_RECORD *entry)
+{
+  TRACE_FUNCTION ("pb_read_alpha_record()");
+
+  switch (GET_PHB_STATE())
+  {
+    case PHB_STATE_IDLE:
+    case PHB_STATE_VERIFY:
+      return pb_sim_read_alpha_record (type, order_num, entry);
+    default:
+      return PHB_FAIL;
+  }
+}
+
+
+GLOBAL T_PHB_RETURN pb_read_number_record (T_PHB_TYPE type,
+                                           SHORT order_num,
+                                           T_PHB_RECORD *entry)
+{
+  TRACE_FUNCTION ("pb_read_number_record()");
+
+  switch (GET_PHB_STATE())
+  {
+    case PHB_STATE_IDLE:
+    case PHB_STATE_VERIFY:
+      return pb_sim_read_number_record (type, order_num, entry);
+    default:
+      return PHB_FAIL;
+  }
+}
+
+
+GLOBAL T_PHB_RETURN pb_search_name (T_PHB_TYPE type,
+                                    T_PHB_MATCH match,
+                                    const T_ACI_PB_TEXT *search_tag,
+                                    SHORT *order_num)
+{
+  T_PHB_RETURN phb_result;
+
+  TRACE_FUNCTION ("pb_search_name()");
+
+  switch (GET_PHB_STATE())
+  {
+    case PHB_STATE_IDLE:
+    case PHB_STATE_VERIFY:
+      TRACE_EVENT_P1 ("order_num = %d", *order_num);
+      phb_result = pb_sim_search_name (type, match, search_tag, order_num);
+      if (phb_result EQ PHB_OK)         // #HM# Remove before production
+      {
+        TRACE_EVENT ("Entry found");
+      }
+      else
+      {
+        TRACE_EVENT ("Entry not found");
+      }
+      return phb_result;
+
+    default:
+      return PHB_FAIL;
+  }
+}
+
+
+GLOBAL T_PHB_RETURN pb_search_number (T_PHB_TYPE type,
+                                      const UBYTE *number,
+                                      SHORT *order_num)
+{
+  TRACE_FUNCTION ("pb_search_number()");
+
+  switch (GET_PHB_STATE())
+  {
+    case PHB_STATE_IDLE:
+    case PHB_STATE_VERIFY:
+      return pb_sim_search_number (type, number, order_num);
+    default:
+      return PHB_FAIL;
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_get_max_num_len                 |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function gets the maximum length of a number within a
+            given phonebook. The length depends on the given phonebook and
+            the availability of extension records (SIM service table).
+            
+            Question: From an architectural point of view, belongs this into
+            the ACI part of the phonebook or more into the SIM part of the 
+            phonebook? SIM part until now has no information about SIM service
+            table.
+
+*/
+LOCAL UBYTE pb_get_max_num_len (T_PHB_TYPE type)
+{
+  TRACE_FUNCTION ("pb_get_max_num_len()");
+
+  switch (type)
+  {
+    case ECC:
+      return 3;
+
+    case ADN:
+    case UPN:
+    case ADN_ME:
+      if (pb_sim_service (SRV_EXT1))
+        return 2 * PHB_PACKED_NUM_LEN;
+      break;
+
+    case FDN:
+      if (pb_sim_service (SRV_EXT2))
+        return 2 * PHB_PACKED_NUM_LEN;
+      break;
+
+    case SDN:
+      if (pb_sim_service (SRV_EXT3))
+        return 2 * PHB_PACKED_NUM_LEN;
+      break;
+    
+    case BDN:
+      if (pb_sim_service (SRV_EXT4))
+        return 2 * PHB_PACKED_NUM_LEN;
+      break;
+
+    case LDN:
+    case LRN:
+    case LMN:
+    case ME:
+      return 2 * PHB_PACKED_NUM_LEN;
+    
+    default:
+      TRACE_ERROR ("Invalid phonebook type");
+      return 0;
+  }
+  return 20; /* Default according to 11.11 if no EXT records and not ECC */
+}
+
+
+GLOBAL T_PHB_RETURN pb_read_sizes (T_PHB_TYPE type, /* IN */
+                                   SHORT *max_rcd,  /* OUT */
+                                   SHORT *used_rcd, /* OUT */
+                                   UBYTE *num_len,  /* OUT */
+                                   UBYTE *tag_len)  /* OUT */
+{
+  T_PHB_RETURN phb_result;
+
+  TRACE_FUNCTION ("pb_read_sizes()");
+
+  switch (GET_PHB_STATE())
+  {
+    case PHB_STATE_IDLE:
+    case PHB_STATE_VERIFY:
+
+      /* 
+       * For a valid phonebook type, set all parameters to zero instead of 
+       * reporting an error.
+       */
+      switch (type)
+      {
+        case ECC:
+        case ADN:
+        case FDN:
+        case BDN:
+        case LDN:
+        case LRN:
+        case SDN:
+        case LMN:
+        case UPN:
+      /*case ME:
+        case ADN_ME:*/
+          *num_len = pb_get_max_num_len (type);
+          phb_result = pb_sim_read_sizes (type, max_rcd, used_rcd, tag_len);
+          if (phb_result NEQ PHB_OK)
+          {
+            *max_rcd  = 0;
+            *used_rcd = 0;
+            *num_len  = 0;
+            *tag_len  = 0;
+          }
+          return PHB_OK;
+
+        default: 
+          break;
+      }
+      return PHB_FAIL;  /* Invalid phonebook */
+
+    default:
+      return PHB_FAIL;  /* Invalid state */
+  }
+}
+
+
+GLOBAL int pb_get_entry_len (const UBYTE *pb_tag,
+                             UBYTE max_pb_len)
+{
+  TRACE_FUNCTION ("pb_get_entry_len()");
+
+  return pb_sim_get_entry_len (pb_tag, max_pb_len);
+}
+
+
+GLOBAL int pb_find_free_record (T_PHB_TYPE type)
+{
+  /* 
+   * This function finds the number of the first free record in 
+   * a given phonebook. This is new functionality as from S621.
+   */
+  TRACE_FUNCTION ("pb_find_free_record()");
+
+  switch (GET_PHB_STATE())
+  {
+    case PHB_STATE_IDLE:
+    case PHB_STATE_VERIFY:
+      return pb_sim_find_free_record (type);
+    default:
+      return PHB_FAIL;
+  }
+}
+
+
+/* 
+ * Internal functions, not part of the interface
+ */
+
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_sim_service                     |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function checks whether a given service is
+            "allocated and activated" on the SIM, if so TRUE is returned, 
+            otherwise the function returns FALSE.
+
+            No, using psaSIM_ChkSIMSrvSup() is not a good alternative here
+            as we may have to handle the situation where the SIM service 
+            table itself has been changed, in this case we are not signalled
+            by the ACI when we have again a valid SIM service table, therefore
+            this function exist here within the phonebook.
+
+*/
+LOCAL BOOL pb_sim_service (UBYTE nr)
+{
+  UBYTE byte_offset;
+  UBYTE bit_offset;
+  UBYTE service;
+
+  TRACE_FUNCTION ("pb_sim_service()");
+
+  if (nr > MAX_SRV_TBL * 4)
+    return FALSE; /* Table overflow */
+
+  byte_offset =  (nr - 1) / 4;
+  bit_offset  = ((nr - 1) & 0x03) * 2;
+  service = (pba_data.sim_service_table[byte_offset] >> bit_offset) & 0x03;
+  return (service EQ ALLOCATED_AND_ACTIVATED);
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_read_sim_record                 |
++----------------------------------------------------------------------------+
+
+    PURPOSE : This function sends a SIM_READ_RECORD_REQ to the SIM card.
+              On success this function returns TRUE, otherwise FALSE.
+
+*/
+LOCAL BOOL pb_read_sim_record (USHORT data_id, UBYTE rcd_num, UBYTE len)
+{
+  SHORT table_id;
+
+  TRACE_FUNCTION ("pb_read_sim_record()");
+
+  table_id = psaSIM_atbNewEntry();
+
+  if (table_id NEQ NO_ENTRY)
+  {
+    /* Allocate room for the SIM data */
+    if (pba_data.data EQ NULL)
+    {
+      ACI_MALLOC (pba_data.data, SIM_MAX_RECORD_SIZE);
+    }
+    simShrdPrm.atb[table_id].ntryUsdFlg = TRUE;
+    simShrdPrm.atb[table_id].accType    = ACT_RD_REC;
+    simShrdPrm.atb[table_id].reqDataFld = data_id;
+    simShrdPrm.atb[table_id].recNr      = rcd_num;
+    if (rcd_num EQ 1)
+      simShrdPrm.atb[table_id].dataLen    = NOT_PRESENT_8BIT;
+    else
+      simShrdPrm.atb[table_id].dataLen    = len;
+    simShrdPrm.atb[table_id].exchData   = pba_data.data;
+    simShrdPrm.atb[table_id].rplyCB     = pb_read_sim_record_cb;
+
+    simShrdPrm.aId = table_id;
+
+    if (psaSIM_AccessSIMData() < 0)
+    {
+      TRACE_EVENT("FATAL ERROR");
+      return FALSE;
+    }
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_read_sim                        |
++----------------------------------------------------------------------------+
+
+    PURPOSE : This function sends a SIM_READ_REQ to the SIM card.
+              On success this function returns TRUE, otherwise FALSE.
+
+*/
+LOCAL BOOL pb_read_sim (USHORT data_id, UBYTE len, UBYTE max_length)
+{
+  SHORT table_id;
+
+  TRACE_FUNCTION ("pb_read_sim()");
+
+  table_id = psaSIM_atbNewEntry();
+
+  if (table_id NEQ NO_ENTRY)
+  {
+    /* Allocate room for the SIM data */
+    if (pba_data.data EQ NULL)
+    {
+      ACI_MALLOC (pba_data.data, SIM_MAX_RECORD_SIZE);
+    }
+
+    simShrdPrm.atb[table_id].ntryUsdFlg = TRUE;
+    simShrdPrm.atb[table_id].accType    = ACT_RD_DAT;
+    simShrdPrm.atb[table_id].reqDataFld = data_id;
+    simShrdPrm.atb[table_id].dataOff    = 0;
+    simShrdPrm.atb[table_id].dataLen    = len;
+    simShrdPrm.atb[table_id].recMax     = max_length;
+    simShrdPrm.atb[table_id].exchData   = NULL;
+    simShrdPrm.atb[table_id].rplyCB     = pb_read_sim_cb;
+
+    simShrdPrm.aId = table_id;
+
+    if (psaSIM_AccessSIMData() < 0)
+    {
+      TRACE_EVENT("FATAL ERROR");
+      return FALSE;
+    }
+    return TRUE;
+  }
+  return FALSE;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_read_next_sim_book              |
++----------------------------------------------------------------------------+
+
+    PURPOSE : This function starts reading the phonebooks based on the 
+              information whether the phonebook is activated and allocated
+              and still has to be read at all.
+
+*/
+LOCAL void pb_read_next_sim_book (void)
+{
+  TRACE_FUNCTION("pb_read_next_sim_book()");
+
+  /*
+   * The next three phonebooks ADN, MSISDN and LND share EXT1 records
+   */
+  if ((pba_data.fdn_mode NEQ FDN_ENABLE) AND
+      pb_sim_service (SRV_ADN) AND !pba_data.book_read[ADN])
+  {
+    /* Read ADN from SIM card */
+    pba_data.current_book = ADN;
+    pba_data.book_read[ADN] = TRUE;
+    pb_read_sim_record (SIM_ADN, 1, NOT_PRESENT_8BIT);
+    return;
+  }
+
+  if (pb_sim_service (SRV_MSISDN) AND !pba_data.book_read[UPN])
+  {
+    /* Read MSISDN from SIM card */
+    pba_data.current_book = UPN;
+    pba_data.book_read[UPN] = TRUE;
+    pb_read_sim_record (SIM_MSISDN, 1, NOT_PRESENT_8BIT);
+    return;
+  }
+
+#ifdef SIM_LND_SUPPORT
+  if (pb_sim_service (SRV_LDN) AND !pba_data.book_read[LDN])
+  {
+    /* Read LND from SIM card */
+    pba_data.current_book = LDN;
+    pba_data.book_read[LDN] = TRUE;
+    pb_read_sim_record (SIM_LND, 1, NOT_PRESENT_8BIT);
+    return;
+  }
+#endif
+
+#ifdef SIM_LND_SUPPORT
+  if (!pb_sim_service (SRV_LDN) AND !pba_data.book_read[LDN])
+#else
+  if (!pba_data.book_read[LDN])
+#endif
+  {
+    /* 
+     * SIM card without LDN service. Create SIM_ICI and SIM_OCI here.
+     * Don't create obsolete SIM_LND
+     */
+    pba_data.book_read[LDN] = TRUE;
+
+    /* Create now also some helper elementary files as of R99+ */
+    //(void)pb_sim_create_ef (SIM_ICI, SIZE_EF_ICI, NR_EF_ICI);
+    (void)pb_sim_create_ef (FFS_LRN, SIZE_EF_LRN, NR_EF_LRN);
+    (void)pb_sim_create_ef (FFS_EXT_LRN, SIZE_EF_EXT_LRN, NR_EF_EXT_LRN);
+    (void)pb_sim_create_ef (FFS_LMN, SIZE_EF_LMN, NR_EF_LMN);
+    (void)pb_sim_create_ef (FFS_EXT_LMN, SIZE_EF_EXT_LMN, NR_EF_EXT_LMN);
+
+    (void)pb_sim_create_ef (SIM_OCI, SIZE_EF_OCI, NR_EF_OCI);
+    (void)pb_sim_create_ef (SIM_EXT5, SIZE_EF_EXT5, NR_EF_EXT5);
+
+    pba_data.phb_record_max[LDN] = NR_EF_OCI;
+    pba_data.phb_record_len[LDN] = SIZE_EF_OCI;
+    pba_data.book_created[LDN] = TRUE;
+
+    //pba_data.phb_record_max[LRN] = NR_EF_ICI; /* Shared! */
+    //pba_data.phb_record_len[LRN] = SIZE_EF_ICI;
+    pba_data.phb_record_max[LRN] = NR_EF_LRN;
+    pba_data.phb_record_len[LRN] = SIZE_EF_LRN;
+    pba_data.book_created[LRN] = TRUE;
+
+    //pba_data.phb_record_max[LMN] = NR_EF_ICI; /* Shared! */
+    //pba_data.phb_record_len[LMN] = SIZE_EF_ICI;
+    pba_data.phb_record_max[LMN] = NR_EF_LMN;
+    pba_data.phb_record_len[LMN] = SIZE_EF_LMN;
+    pba_data.book_created[LMN] = TRUE;
+
+    pba_data.ext_record_max[EXT5]    = NR_EF_EXT5;
+    pba_data.ext_record_max[EXT_LRN] = NR_EF_EXT_LRN;
+    pba_data.ext_record_max[EXT_LMN] = NR_EF_EXT_LMN;
+
+    pba_data.ext_record_max[EXT5]    = SIZE_EF_EXT5;
+    pba_data.ext_record_max[EXT_LRN] = SIZE_EF_EXT_LRN;
+    pba_data.ext_record_max[EXT_LMN] = SIZE_EF_EXT_LMN;
+  }
+
+#ifdef SIM_LND_SUPPORT
+  if (pba_data.book_read[ADN] OR
+      pba_data.book_read[UPN] OR
+      pba_data.book_read[LDN])
+#else
+  if (pba_data.book_read[ADN] OR
+      pba_data.book_read[UPN])
+#endif
+  {
+    /* At least one of the books referencing EXT1 has been read */
+    if (!pba_data.ext_created[EXT1] AND
+        pb_sim_service (SRV_EXT1))
+    {
+      /* Reading to get the number of records only */
+      pba_data.ext_dummy_read = TRUE;
+      pb_read_sim_record (SIM_EXT1, 1, NOT_PRESENT_8BIT);
+      return;
+    }
+  }
+
+  /*
+   * FDN phonebook only to be read if ADN is blocked
+   */
+  if ((pba_data.fdn_mode EQ FDN_ENABLE) AND 
+      pb_sim_service (SRV_FDN) AND !pba_data.book_read[FDN])
+  {
+    /* Read FDN from SIM card */
+    pba_data.current_book = FDN;
+    pba_data.book_read[FDN] = TRUE;
+    pb_read_sim_record (SIM_FDN, 1, NOT_PRESENT_8BIT);
+    return;
+  }
+
+  if (pba_data.book_read[FDN] AND
+      !pba_data.ext_created[EXT2] AND
+      pb_sim_service (SRV_EXT2))
+  {
+    /* Reading to get the number of records only */
+    pba_data.ext_dummy_read = TRUE;
+    pb_read_sim_record (SIM_EXT2, 1, NOT_PRESENT_8BIT);
+    return;
+  }
+
+  if (pb_sim_service (SRV_BDN) AND !pba_data.book_read[BDN])
+  {
+    /* Read BDN from SIM card */
+    pba_data.current_book = BDN;
+    pba_data.book_read[BDN] = TRUE;
+    pb_read_sim_record (SIM_BDN, 1, NOT_PRESENT_8BIT);
+    return;
+  }
+
+  if (pba_data.book_read[BDN] AND 
+      !pba_data.ext_created[EXT4] AND
+      pb_sim_service (SRV_EXT4))
+  {
+    /* Reading to get the number of records only */
+    pba_data.ext_dummy_read = TRUE;
+    pb_read_sim_record (SIM_EXT4, 1, NOT_PRESENT_8BIT);
+    return;
+  }
+
+  if (pb_sim_service (SRV_SDN) AND !pba_data.book_read[SDN])
+  {
+    /* Read SDN from SIM card */
+    pba_data.current_book = SDN;
+    pba_data.book_read[SDN] = TRUE;
+    pb_read_sim_record (SIM_SDN, 1, NOT_PRESENT_8BIT);
+    return;
+  }
+
+  if (pba_data.book_read[SDN] AND
+      !pba_data.ext_created[EXT3] AND
+      pb_sim_service (SRV_EXT3))
+  {
+    /* Reading to get the number of records only */
+    pba_data.ext_dummy_read = TRUE;
+    pb_read_sim_record (SIM_EXT3, 1, NOT_PRESENT_8BIT);
+    return;
+  }
+
+  /*
+   * For the phonebook entries which reside on SIM but don't have 
+   * timestamps some checks could be done here.
+   * For example, we could read based on EF_LDN, subsequently we
+   * could read the informations solely stored in the flash and
+   * then we could decide whether we through away the last dialled 
+   * numbers or don't.
+   * Probably this is overkill, old Nokia 5110 and more recent Nokia 6330i 
+   * simply does not support EF_LND at all but stores the last dialled 
+   * numbers in the flash.
+   */
+
+#ifdef SIM_TOOLKIT
+  if (simShrdPrm.fuRef >= 0)
+  {
+    psaSAT_FUConfirm (simShrdPrm.fuRef, SIM_FU_SUCC_ADD);
+  }
+#endif
+
+  /* Free SIM exchange data */
+  if (pba_data.data NEQ NULL)
+  {
+    ACI_MFREE (pba_data.data);
+    pba_data.data = NULL;
+  }
+
+  SET_PHB_STATE (PHB_STATE_IDLE);
+
+  if (pb_read_queue() EQ PHB_EXCT)
+    return; /* Queued LDN entry is written */
+
+  /* Finished reading phonebooks. Flush data. */
+  (void)pb_sim_flush_data ();
+
+  /* Inform ACI that we're ready */
+  pb_status_ind (PHB_READY, CME_ERR_NotPresent);
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_read_sim_record_cb              |
++----------------------------------------------------------------------------+
+
+    PURPOSE : This function is the callback when a SIM record has been read
+              (SIM_READ_RECORD_CNF).
+
+*/
+
+LOCAL void pb_read_sim_record_cb (SHORT table_id)
+{
+  T_PHB_RETURN phb_result;  /* Phonebook result code */
+  T_PHB_TYPE phb_type;      /* Phonebook type */
+  T_EXT_TYPE ext_type;      /* Extension record type */
+  T_PHB_TYPE next_phb_type; /* Phonebook type of record to read */
+  T_EXT_TYPE next_ext_type; /* Extension record type of record to read */
+  USHORT  reqDataFld;       /* requested datafield identifier */
+  UBYTE   recNr;            /* record number */
+  UBYTE   dataLen;          /* Length of data */
+  UBYTE   recMax;           /* Maximum number of records */
+  USHORT  errCode;          /* Error code from the SIM */
+  USHORT  ext_record_ef;    /* Extension record elementary file id */
+  UBYTE   ext_record_no;    /* Extension record number */
+  BOOL    changed;          /* Record changed by pb_sim_write_ef() */
+  BOOL    write_record;     /* Write the record */
+
+  TRACE_FUNCTION ("pb_read_sim_record_cb()");
+
+  /* 
+   * Currently we have a limitation of 254 records in the code.
+   * This is because there is a note in 11.11 version 8.3.0 clause 6.4.2
+   * that there is a limit of 254 records for linear fixed.
+   * Same for USIM looking into 31.102 Annex G.
+   * However this constraint is not valid for cyclic, and also this
+   * note has not been present in 11.11 version 7.4.0 clause 6.2.4, 
+   * there is a limit of 255 records mentioned.
+   * Not supporting the 255th record is a minor issue for now.
+   * To avoid crashing, we have to limit here for now to 254.
+   * This is not a theoretical issue only as there exists SIMs
+   * which have 255 ADN entries.
+   */
+  if (simShrdPrm.atb[table_id].recMax EQ 255)
+    simShrdPrm.atb[table_id].recMax = 254;
+
+  /* Get the important information from the read record from T_SIM_ACC_PRM */
+  reqDataFld = simShrdPrm.atb[table_id].reqDataFld;
+  recNr      = simShrdPrm.atb[table_id].recNr;
+  dataLen    = simShrdPrm.atb[table_id].dataLen;
+  recMax     = simShrdPrm.atb[table_id].recMax;
+  errCode    = simShrdPrm.atb[table_id].errCode;
+
+  phb_type = pb_get_phb_type_from_ef (reqDataFld);
+  ext_type = pb_get_ext_type_from_ef (reqDataFld);
+
+  if (phb_type EQ INVALID_PHB AND
+      ext_type EQ INVALID_EXT)
+  {
+    TRACE_ERROR ("Invalid reqDataFld!");
+    simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+    return;
+  }
+
+  /* We assume we write the record until we have certain errors */
+  write_record = TRUE;
+
+  if (errCode NEQ SIM_NO_ERROR)
+  {
+    TRACE_EVENT_P1 ("SIM indicated problem code %04x", errCode);
+    /* 
+     * At least use cleanly deleted data instead of trash.
+     */
+    memset (pba_data.data, 0xff, SIM_MAX_RECORD_SIZE);
+  }
+
+  if (ext_type NEQ INVALID_EXT) 
+  {
+    /*
+     * Got an extension record. 
+     */
+    if (!pba_data.ext_created[ext_type])
+    {
+      if (errCode NEQ SIM_NO_ERROR)
+      {
+        /* We won't create a field on invalid data and won't write */
+        write_record = FALSE;
+        pba_data.ext_dummy_read = FALSE;
+      }
+      else
+      {
+        pba_data.ext_record_max[ext_type] = recMax;
+        pba_data.ext_record_len[ext_type] = dataLen;
+
+        /* Shadow field for extension record not yet created */
+        (void)pb_sim_create_ef (reqDataFld, dataLen, recMax);
+        pba_data.ext_created[ext_type] = TRUE;
+      }
+
+      if (pba_data.ext_dummy_read)
+      {
+        /* 
+         * We are reading the first extension record which is assumed 
+         * to be not used just to get the number of respective extension 
+         * records.
+         */
+        write_record = FALSE;
+        pba_data.ext_dummy_read = FALSE;
+      }
+    }
+  }
+  else
+  {
+    /*
+     * Got a normal phonebook record
+     */
+    if (!pba_data.book_created[phb_type])
+    {
+      if (errCode NEQ SIM_NO_ERROR)
+      {
+        /* We won't create a field on invalid data */
+        write_record = FALSE;
+      }
+      else
+      {
+        pba_data.phb_record_max[phb_type] = recMax;
+        pba_data.phb_record_len[phb_type] = dataLen;
+
+        /* Shadow field for normal phonebook record not yet created */
+        (void)pb_sim_create_ef (reqDataFld, dataLen, recMax);
+        pba_data.book_created[phb_type] = TRUE;
+
+#ifdef SIM_LND_SUPPORT
+        if (phb_type EQ LDN)
+        {
+          /* Create now also some helper elementary files as of R99+ */
+          (void)pb_sim_create_ef (SIM_OCI, (USHORT)(dataLen + 14), recMax);
+          pba_data.phb_record_max[LDN] = recMax;
+          pba_data.phb_record_len[LDN] = dataLen;
+          pba_data.book_created[LDN] = TRUE;
+
+          (void)pb_sim_create_ef (SIM_ICI, (USHORT)(dataLen + 14), recMax);
+          pba_data.phb_record_max[LRN] = recMax;
+          pba_data.phb_record_len[LRN] = dataLen;
+          pba_data.book_created[LRN] = TRUE;
+
+          pba_data.phb_record_max[LMN] = recMax;
+          pba_data.phb_record_len[LMN] = dataLen;
+          pba_data.book_created[LMN] = TRUE;
+        }
+#endif
+      }
+    }
+  }
+
+  /* 
+   * Write raw record. The SIM layer is aware about the data structures
+   * and gives us the information whether we have to read an/another
+   * extension record now or whether we can continue reading normal
+   * phonebook entries.
+   */
+  if (write_record)
+  {
+    phb_result = pb_sim_write_ef(reqDataFld,
+                                 recNr,
+                                 dataLen,
+                                 pba_data.data,
+                                 &changed,
+                                 &ext_record_ef,
+                                 &ext_record_no);
+  }
+  else
+  {
+    /*
+     * New field, record was trash, don't write it, continue reading
+     * phonebook entries.
+     */
+    TRACE_EVENT ("Record not written (trash/dummy ext)");
+
+    phb_result = PHB_OK;
+    changed = FALSE;
+    ext_record_ef = 0;
+    ext_record_no = 0;
+  }
+
+  /* Mark SIM table as free now */
+  simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+
+  if ((GET_PHB_STATE() EQ PHB_STATE_VERIFY) AND
+      (phb_result EQ PHB_OK) AND changed)
+  {
+    /* We have a change detected. Prevent further reading until all read */
+    SET_PHB_STATE (PHB_STATE_READ);
+  }
+
+  /*
+   * Here an optimization is possible. This is, if an extension record
+   * and already has been read we could skip reading the extension record
+   * here. The optimization is not worth the effort, so we simply don't do
+   * it.
+   */
+
+  /*
+   * Do some protection against garbage
+   */
+  if (ext_record_ef NEQ 0)
+  {
+    /* Current record references an extension record */
+    next_ext_type = pb_get_ext_type_from_ef (ext_record_ef);
+
+    if ((next_ext_type EQ INVALID_EXT) OR
+        (ext_record_no < 1) OR
+        (ext_record_no > 245))
+    {
+      TRACE_ERROR ("pb_sim_write_ef() for ext delivered garbage EXT record");
+      ext_record_ef = 0; /* Try to proceed without this garbage */
+    }
+  }
+  
+  if (ext_record_ef NEQ 0)
+  {
+    /* Current record references an extension record */
+    next_ext_type = pb_get_ext_type_from_ef (ext_record_ef);
+
+    /* 
+     * We have to read an extension record.
+     */
+    if (ext_type NEQ INVALID_EXT)
+    {
+      /*
+       * It's the first extension record. Remember the paused phonebook.
+       */
+      TRACE_EVENT_P4 ("PHB EF %04x record %d references EXT EF %04x record %d",
+                      reqDataFld,
+                      recNr,
+                      ext_record_ef,
+                      ext_record_ef);
+      pba_data.paused_ef = reqDataFld;
+      pba_data.paused_no = recNr;
+    }
+
+    /* Read the extension record. */
+    if (pba_data.ext_created[next_ext_type])
+    {
+      (void)pb_read_sim_record (ext_record_ef,
+                                ext_record_no, 
+                                pba_data.ext_record_len[next_ext_type]);
+    }
+    else
+    {
+      (void)pb_read_sim_record (ext_record_ef,
+                                ext_record_no, 
+                                NOT_PRESENT_8BIT);
+    }
+  }
+  else if (ext_type NEQ INVALID_EXT)
+  {
+    /* 
+     * The record read was the last extension record in the chain.
+     * Come back reading normal phonebook entries.
+     */
+
+    next_phb_type = pb_get_phb_type_from_ef (pba_data.paused_ef);
+    //////(void)pb_sim_build_index (next_phb_type);
+    if (pba_data.paused_no < pba_data.phb_record_max[next_phb_type])
+    {
+      /* Continue reading the current phonebook */
+      (void)pb_read_sim_record (pba_data.paused_ef,
+                                (UBYTE)(pba_data.paused_no + 1),
+                                pba_data.phb_record_len[next_phb_type]);
+    }
+    else
+    {
+      ////// Update index - for now here
+      (void)pb_sim_build_index (phb_type);
+
+      /* Next book */
+      pb_read_next_sim_book ();
+    }
+    pba_data.paused_ef  = 0;
+    pba_data.paused_no  = 0;
+
+  }
+  else if (simShrdPrm.atb[table_id].recNr < simShrdPrm.atb[table_id].recMax)
+  {
+    /*
+     * Normal phonebook record read, no extension referenced and not
+     * finished. Continue reading the current phonebook 
+     */
+    //////(void)pb_sim_build_index (phb_type);
+
+    (void)pb_read_sim_record (simShrdPrm.atb[table_id].reqDataFld,
+                              (UBYTE)(simShrdPrm.atb[table_id].recNr + 1),
+                              simShrdPrm.atb[table_id].dataLen);
+  }
+  else
+  {
+    /*
+     * Normal phonebook record read, no extension referenced and finished
+     * reading this book. Continue reading the next book.
+     */
+    (void)pb_sim_build_index (phb_type);
+
+    /* Next book */
+    pb_read_next_sim_book ();
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_sat_update_reset                |
++----------------------------------------------------------------------------+
+
+    PURPOSE : This function marks the given elementary file as unread.
+    
+*/
+LOCAL void pb_sat_update_reset (USHORT ef)
+{
+  T_PHB_TYPE phb_type;
+
+  TRACE_FUNCTION ("pb_sat_update_reset()");
+
+  phb_type = pb_get_phb_type_from_ef (ef);
+
+  if (phb_type NEQ INVALID_PHB)
+  {
+    /* Mark book as unread */
+    pba_data.book_read[phb_type] = FALSE;
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_read_sim_cb                     |
++----------------------------------------------------------------------------+
+
+    PURPOSE : This function is the callback when a SIM elementary file has 
+              been read (SIM_READ_CNF).
+              There are two fields which can have been read here, those are
+              the emergency call numbers and the SIM service table.
+
+*/
+
+
+LOCAL void pb_read_sim_cb (SHORT table_id)
+{
+  TRACE_FUNCTION ("pb_read_sim_cb()");
+
+  switch (simShrdPrm.atb[table_id].reqDataFld)
+  {
+    case SIM_ECC:
+      if (simShrdPrm.atb[table_id].errCode EQ SIM_NO_ERROR)
+      {
+        (void)pb_sim_set_ecc (simShrdPrm.atb[table_id].dataLen,
+                              simShrdPrm.atb[table_id].exchData);
+
+#ifdef SIM_TOOLKIT
+        if (simShrdPrm.fuRef >= 0)
+        {
+          psaSAT_FUConfirm (simShrdPrm.fuRef, SIM_FU_SUCCESS);
+        }
+#endif /* #ifdef SIM_TOOLKIT */
+
+      }        
+      else
+      {
+        /* 
+         * Some error from the SIM. Indicate a fallback to the PCM/FFS.
+         */
+        (void)pb_sim_set_ecc (0, NULL);
+
+#ifdef SIM_TOOLKIT
+        if (simShrdPrm.fuRef >= 0)
+        {
+          psaSAT_FUConfirm (simShrdPrm.fuRef, SIM_FU_ERROR);
+        }
+#endif
+
+      }
+
+      if (pba_data.data NEQ NULL)
+      {
+        ACI_MFREE (pba_data.data);
+        pba_data.data = NULL;
+      }
+      break;
+
+    case SIM_SST:
+      if (simShrdPrm.atb[table_id].errCode EQ SIM_NO_ERROR)
+      {
+        /* copy SIM service table */
+        memset(pba_data.sim_service_table, 0, MAX_SRV_TBL);
+        memcpy(pba_data.sim_service_table, 
+               simShrdPrm.atb[table_id].exchData, 
+               MINIMUM(MAX_SRV_TBL, simShrdPrm.atb[table_id].dataLen));
+
+        /* start reading SIM phonebook */
+        simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+        pb_start_build (FALSE);
+      }
+      else
+      {
+        TRACE_ERROR ("Cannot read SIM service table, using old table");
+
+#ifdef SIM_TOOLKIT
+        if (simShrdPrm.fuRef >= 0)
+        {
+          psaSAT_FUConfirm (simShrdPrm.fuRef, SIM_FU_ERROR);
+        }
+#endif
+
+        /* start reading SIM phonebook (fallback action, best effort) */
+        simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+        pb_start_build (FALSE);
+      }
+      break;
+
+    default:
+      TRACE_ERROR ("Unexpected SIM_READ_CNF");
+      break;
+  }
+  simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_is_sim_field                    |
++----------------------------------------------------------------------------+
+
+    PURPOSE : This function determines wheter an elementary file has to 
+              be synchronized to the SIM or only exists locally in the FFS.
+
+*/
+LOCAL BOOL pb_is_sim_field (USHORT ef)
+{
+  TRACE_FUNCTION ("pb_is_sim_field()");
+
+  switch (ef)
+  {
+    //case SIM_ICI:
+    case FFS_LRN:
+    case FFS_LMN:
+    case FFS_EXT_LRN:
+    case FFS_EXT_LMN:
+    case SIM_OCI:
+    case SIM_EXT5:
+      return FALSE; /* Only in FFS */
+
+    default:
+      return TRUE;  /* Counterpart in SIM exists */
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_sync_next_sim_record            |
++----------------------------------------------------------------------------+
+
+    PURPOSE : This function synchronizes a changed record to the SIM.
+              
+              The first parameter is given to determine whether it's the first
+              record to be synchronized, in this case ACI has to be informed.
+  
+              If there was no record to synchronize, PHB_OK is returned.
+              If there is a record to synchronize, PHB_EXCT is returned.
+              If there was an internal failure we get PHB_FAIL 
+              (which is unexpected).
+
+*/
+
+LOCAL T_PHB_RETURN pb_sync_next_sim_record (BOOL first)
+{
+  T_PHB_RETURN phb_result;
+  USHORT field_id;
+  USHORT record;
+  USHORT entry_size;
+
+  TRACE_FUNCTION ("pb_sync_next_sim_record()");
+
+  do
+  {
+    if (pba_data.records_changed.entries EQ 0)
+    {
+      SET_PHB_STATE (PHB_STATE_IDLE);
+
+      if (pb_read_queue() EQ PHB_EXCT)
+        return PHB_EXCT; /* Queued LDN entry is written */
+
+      /* Inform SIM layer we're done synchronizing */
+      (void)pb_sim_flush_data ();
+
+      /* Inform ACI that we're ready */
+      pb_status_ind (PHB_READY, CME_ERR_NotPresent);
+
+      return PHB_OK; /* No record to synchronize to the SIM */
+    }
+
+    /* Get the next record from the list */
+    pba_data.records_changed.entries--;
+    field_id = pba_data.records_changed.field_id[0];
+    record   = pba_data.records_changed.record[0];
+
+    /* Remove the record from the list */
+    memmove (&pba_data.records_changed.field_id[0],
+             &pba_data.records_changed.field_id[1],
+             sizeof (USHORT) * (DB_MAX_AFFECTED - 1));
+    memmove (&pba_data.records_changed.record[0],
+             &pba_data.records_changed.record[1],
+             sizeof (USHORT) * (DB_MAX_AFFECTED - 1));
+  } 
+  while (!pb_is_sim_field(field_id));
+
+  TRACE_EVENT_P3 ("Synch ef %04X record %d, still %d entries to do",
+                  field_id, record, pba_data.records_changed.entries);
+
+  /* Allocate room for the SIM data */ // #HM# Check for free
+  if (pba_data.data EQ NULL)
+  {
+    ACI_MALLOC (pba_data.data, SIM_MAX_RECORD_SIZE);
+  }
+
+  /* Fetch record in raw form from the database */
+  phb_result = pb_sim_read_ef (field_id,
+                               record,
+                               &entry_size,
+                               pba_data.data);
+
+  if (phb_result EQ PHB_OK)
+  {
+    /* And write it to the SIM */
+    phb_result = pb_write_sim_record (field_id,
+                                      (UBYTE)record, 
+                                      (UBYTE)entry_size,
+                                      pba_data.data);
+
+    if (phb_result NEQ PHB_EXCT)
+    {
+      /* Inform ACI that we've had a problem */
+      pb_status_ind ( PHB_WRITE_FAIL, CME_ERR_NotPresent );
+      return phb_result; /* Some unexpected internal failure */
+    }
+
+    if (first)
+    {
+      /* Inform ACI that we're busy synchronizing SIM entries */
+      pb_status_ind ( PHB_BUSY, CME_ERR_NotPresent );
+    }
+
+    return PHB_EXCT;
+  }
+  return phb_result;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_write_sim_record                |
++----------------------------------------------------------------------------+
+
+    PURPOSE : This function writes a SIM record to the SIM.
+
+*/
+
+LOCAL T_PHB_RETURN pb_write_sim_record (USHORT ef,
+                                        UBYTE phy_recno,
+                                        UBYTE entry_size,
+                                  const UBYTE *buffer)
+{
+  SHORT           table_id;
+
+
+  TRACE_FUNCTION("pb_write_sim_record()");
+
+  table_id = psaSIM_atbNewEntry();
+  if (table_id EQ NO_ENTRY)
+  {
+    TRACE_ERROR ("pb_write_sim_record(): no more table entries");
+    return (PHB_FAIL);
+  }
+
+  simShrdPrm.atb[table_id].ntryUsdFlg = TRUE;
+  simShrdPrm.atb[table_id].accType    = ACT_WR_REC;
+  simShrdPrm.atb[table_id].reqDataFld = ef;
+  simShrdPrm.atb[table_id].recNr      = phy_recno;
+  simShrdPrm.atb[table_id].dataLen    = entry_size;
+  simShrdPrm.atb[table_id].exchData   = (UBYTE *)buffer;
+  simShrdPrm.atb[table_id].rplyCB     = pb_write_sim_record_cb;
+
+  simShrdPrm.aId = table_id;
+
+  if (psaSIM_AccessSIMData() < 0)
+  {
+    TRACE_EVENT("pb_write_sim_record(): psaSIM_AccessSIMData() failed");
+    return (PHB_FAIL);
+  }
+
+  return (PHB_EXCT);
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_write_sim_record_cb             |
++----------------------------------------------------------------------------+
+
+    PURPOSE : This function is the callback when a SIM record has been
+              written to the SIM.
+
+*/
+
+LOCAL void pb_write_sim_record_cb (SHORT table_id)
+{
+  UBYTE max_record;
+
+  TRACE_FUNCTION("pb_write_sim_record_cb()");
+
+  simShrdPrm.atb[table_id].ntryUsdFlg = FALSE;
+
+  if (simShrdPrm.atb[table_id].errCode NEQ SIM_NO_ERROR)
+  {
+    /* 
+     * Data in the database and on the SIM probably now differ,
+     * we can do not much about this.
+     */
+    TRACE_ERROR("pb_write_cb(): error for writing");
+    pb_status_ind (PHB_WRITE_FAIL,
+                   (SHORT)cmhSIM_GetCmeFromSim (simShrdPrm.atb[table_id].errCode));
+    return;
+  }
+
+  switch (GET_PHB_STATE())
+  {
+    case PHB_STATE_WRITE:
+      /* Synchronize next SIM record */
+      switch (pb_sync_next_sim_record (FALSE))
+      {
+        case PHB_OK: /* All done */
+          /* Inform the ACI that we're done */
+          pb_status_ind (PHB_READY, CME_ERR_NotPresent);
+          break;
+
+        case PHB_EXCT:
+          break; /* Next record => SIM */
+
+        case PHB_FAIL:
+        default:
+          TRACE_ERROR ("Unexpected phb_result");      
+          break;
+      }
+      break;
+
+    case PHB_STATE_DELETE_BOOK:
+      /* Synchronize next SIM record */
+      switch (pb_sync_next_sim_record (FALSE))
+      {
+        case PHB_OK:
+          /* 
+           * Record synched. Delete next record of phonebook, if available
+           */
+          max_record = pba_data.phb_record_max[pba_data.current_book];
+          while ((pba_data.del_record <= max_record) AND
+                 (pba_data.records_changed.entries EQ 0))
+          {
+            /* Delete the record in the database */
+            if (pb_sim_del_record (pba_data.current_book, 
+                                   pba_data.del_record,
+                                   &pba_data.records_changed) NEQ PHB_OK)
+            {
+              TRACE_ERROR ("Unexpected problem from pb_sim_del_record()");
+
+              /* Inform SIM layer we're done synchronizing.
+               * Should we indicate also there was a problem? */
+              (void)pb_sim_flush_data ();
+
+              pb_status_ind (PHB_WRITE_FAIL, CME_ERR_NotPresent);
+
+              SET_PHB_STATE (PHB_STATE_IDLE);
+              return;
+            }
+            pba_data.del_record++;
+          } 
+
+          if (pba_data.records_changed.entries NEQ 0)
+          {
+            /* Synchronizing record(s) to the SIM */
+            if (pb_sync_next_sim_record (FALSE) NEQ PHB_EXCT)
+            {
+              TRACE_ERROR ("Unexpected problem from pb_sync_next_sim_record()");
+
+              /* Inform SIM layer we're done synchronizing.
+               * Should we indicate also there was a problem? */
+              (void)pb_sim_flush_data ();
+
+              pb_status_ind (PHB_WRITE_FAIL, CME_ERR_NotPresent);
+
+              SET_PHB_STATE (PHB_STATE_IDLE);
+              return;
+            }
+          }
+
+          /* 
+           * We're through
+           */
+
+          (void)pb_sim_flush_data ();
+
+          /* Inform the ACI that we're done */
+          pb_status_ind (PHB_READY, CME_ERR_NotPresent);
+
+          SET_PHB_STATE (PHB_STATE_IDLE);
+          break;
+
+        case PHB_EXCT:
+          break; /* Next record => SIM */
+
+        case PHB_FAIL:
+        default:
+          TRACE_ERROR ("Unexpected problem synching SIM");      
+
+          (void)pb_sim_flush_data ();
+
+          pb_status_ind (PHB_WRITE_FAIL, CME_ERR_NotPresent);
+          /* Inform SIM layer we're done synchronizing.
+           * Should we indicate also there was a problem? */
+
+          SET_PHB_STATE (PHB_STATE_IDLE);
+          break;
+      }
+      break;
+
+    default:
+      TRACE_ERROR ("Unexpected default");
+      break;
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_get_phb_type_from_ef            |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function converts a SIM elementary file number to the 
+            appropriate constant of type T_PHB_TYPE, if applicable.
+            Non applicable => INVALID_PHB
+
+*/
+T_PHB_TYPE pb_get_phb_type_from_ef (USHORT ef)
+{
+  TRACE_FUNCTION ("pb_get_phb_type_from_ef()");
+
+  switch (ef)
+  {
+    case SIM_ECC:
+      return ECC;
+
+    case SIM_ADN:
+      return ADN;
+
+    case SIM_FDN:
+      return FDN;
+
+    case SIM_BDN:
+      return BDN;
+
+    case SIM_LND:
+      return LDN;
+
+    case SIM_MSISDN:
+      return UPN;
+
+    case SIM_SDN:
+      return SDN;
+
+    default:
+      return INVALID_PHB;
+  }
+}
+
+ 
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_get_ext_type_from_ef            |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function converts a SIM elementary file number to the
+            appropriate constant of T_PHB_EXT_TYPE, if applicable.
+            Non applicable => INVALID_EXT
+
+*/
+T_EXT_TYPE pb_get_ext_type_from_ef (USHORT ef)
+{
+  TRACE_FUNCTION ("pb_get_ext_type_from_ef()");
+
+  switch (ef)
+  {
+    case SIM_EXT1:
+      return EXT1;
+
+    case SIM_EXT2:
+      return EXT2;
+
+    case SIM_EXT3:
+      return EXT3;
+
+    case SIM_EXT4:
+      return EXT4;
+
+    case SIM_EXT5:
+      return EXT5;
+
+    default:
+      return INVALID_EXT;
+  }
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_search_number_ex                |
++----------------------------------------------------------------------------+
+
+  PURPOSE : At some places a more sohisticated number searching function 
+            is desirable which can be based on existing phonebook 
+            functionality.
+
+*/
+GLOBAL T_PHB_RETURN pb_search_number_ex (T_PHB_TYPE type,
+                                         const UBYTE *number,
+                                         SHORT *order_num,
+                                         SHORT *found,
+                                         T_PHB_RECORD *entry)
+{
+  T_PHB_RETURN phb_result;
+  SHORT index;
+
+  TRACE_FUNCTION ("pb_search_number_ex()");
+
+  /* Search for first entry */
+  phb_result = pb_search_number (type,
+                                 number,
+                                 order_num);
+  if (phb_result NEQ PHB_OK)
+    return phb_result;
+
+  /* 
+   * Determine number of found entries. We are doing a linear algorithm, 
+   * a binary algorithm is possible here to speed up things.
+   */
+  if (found NEQ NULL)
+  {
+    *found = 1;
+    index = *order_num;
+
+    while (pb_search_number (type, number, &index) EQ PHB_OK)
+    { 
+      ++(*found);
+      /* index should not be incremented as lower layer (DB) will take
+         care of it */
+    }
+  }
+
+  /* Read the first found entry, if desired */
+  if (entry NEQ NULL)
+    return (pb_read_number_record (type, *order_num, entry));
+  return PHB_OK;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_search_name_ex                  |
++----------------------------------------------------------------------------+
+
+  PURPOSE : At some places a more sohisticated name searching function 
+            is desirable which can be based on existing phonebook 
+            functionality.
+
+*/
+GLOBAL T_PHB_RETURN pb_search_name_ex (T_PHB_TYPE type,
+                                       T_PHB_MATCH match,
+                                       const T_ACI_PB_TEXT *search_tag,
+                                       SHORT *order_num,
+                                       SHORT *found,
+                                       T_PHB_RECORD *entry)
+{
+  T_PHB_RETURN phb_result;
+  SHORT index;
+
+  TRACE_FUNCTION ("pb_search_name_ex()");
+
+  /* Search for first entry */
+  phb_result = pb_search_name (type,
+                               match,
+                               search_tag,
+                               order_num);
+  if (phb_result NEQ PHB_OK)
+    return phb_result;
+
+  /* 
+   * Determine number of found entries. We are doing a linear algorithm, 
+   * a binary algorithm is possible here to speed up things.
+   */
+  if (found NEQ NULL)
+  {
+    *found = 1;
+    index = *order_num;
+
+    while (pb_search_name (type, match, search_tag, &index) EQ PHB_OK)
+    { 
+      ++(*found);
+      /* index should not be incremented as lower layer (DB) will take
+         care of it */
+    }
+      
+  }
+
+  /* Read the first found entry, if desired */
+  if (entry NEQ NULL)
+    return (pb_read_alpha_record (type, *order_num, entry));
+  return PHB_OK;
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_status_ind                      |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function indicates the new phonebook status to the ACI 
+            preventing we're indication twice PHB_READY or PHB_BUSY.
+
+*/
+LOCAL void pb_status_ind (T_PHB_STAT phb_stat, SHORT cmeError)
+{
+  TRACE_FUNCTION ("pb_status_ind()");
+
+  /* Avoid to indicate twice busy or ready */
+  if ((pba_data.phb_stat NEQ phb_stat) OR
+      ((phb_stat NEQ PHB_READY) AND
+       (phb_stat NEQ PHB_BUSY)))
+  {
+    cmhPHB_StatIndication ((UBYTE)phb_stat, cmeError,TRUE);
+    pba_data.phb_stat = phb_stat;
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_write_queue                     |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function writes a LDN entry to the queue if the SIM is busy.
+
+*/
+LOCAL T_PHB_RETURN pb_write_queue (const T_PHB_RECORD *entry)
+{
+  TRACE_FUNCTION ("pb_write_queue()");
+
+  if (pba_data.c_queued < PHB_MAX_QUEUE)
+  {
+    memmove (&pba_data.queued[1],
+             &pba_data.queued[0],
+             pba_data.c_queued * sizeof (T_PHB_QUEUE *));
+    ACI_MALLOC (pba_data.queued[pba_data.c_queued], 
+                sizeof (T_PHB_QUEUE));
+    pba_data.queued[0]->entry = *entry;
+    pba_data.c_queued++;
+    return PHB_EXCT;
+  }
+  
+  return PHB_FAIL; /* Queue full */
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_clear_queue                     |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function clears the LDN queue.
+
+*/
+LOCAL void pb_clear_queue (void)
+{
+  TRACE_FUNCTION ("pb_clear_queue()");
+
+  while (pba_data.c_queued NEQ 0)
+  {
+    pba_data.c_queued--;
+    ACI_MFREE (pba_data.queued[pba_data.c_queued]);
+    pba_data.queued[pba_data.c_queued] = NULL;
+  }
+}
+
+
+/*
++----------------------------------------------------------------------------+
+| PROJECT : GSM-PS (6147)       MODULE  : PHB                                |
+| STATE   : code                ROUTINE : pb_read_queue                      |
++----------------------------------------------------------------------------+
+
+  PURPOSE : This function reads the queue and adds the queued phonebook 
+            entries.
+
+*/
+LOCAL T_PHB_RETURN pb_read_queue (void)
+{
+  T_PHB_RETURN phb_result;
+
+  TRACE_FUNCTION ("pb_write_queue()");
+
+  while (pba_data.c_queued NEQ 0)
+  {
+    /*
+     * LDN entries have been queued. Write them now.
+     */
+    pba_data.c_queued--;
+    phb_result = pb_add_record (LDN,
+                                pba_data.queued[pba_data.c_queued]->index,
+                                &pba_data.queued[pba_data.c_queued]->entry);
+    ACI_MFREE (pba_data.queued[pba_data.c_queued]);
+    pba_data.queued[pba_data.c_queued] = NULL;
+    switch (phb_result)
+    {
+      case PHB_EXCT:
+        return phb_result;
+      case PHB_OK:
+        break;
+      default:
+        pb_clear_queue();
+        return phb_result;
+    }
+  }
+  return PHB_OK;
+}
+
+#endif /* #ifdef TI_PS_FFS_PHB */