FreeCalypso > hg > fc-magnetite
diff src/aci2/aci/phb_sim.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_sim.c Mon Sep 26 00:29:36 2016 +0000 @@ -0,0 +1,2998 @@ +/* ++----------------------------------------------------------------------------- +| 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 */ +