FreeCalypso > hg > fc-magnetite
view src/aci2/aci/phb_sim.c @ 662:8cd8fd15a095
SIM speed enhancement re-enabled and made configurable
TI's original code supported SIM speed enhancement, but Openmoko had it
disabled, and OM's disabling of speed enhancement somehow caused certain
SIM cards to start working which didn't work before (OM's bug #666).
Because our FC community is much smaller in year 2020 than OM's community
was in their day, we are not able to find one of those #666-affected SIMs,
thus the real issue they had encountered remains elusive. Thus our
solution is to re-enable SIM speed enhancement and simply wait for if
and when someone runs into a #666-affected SIM once again. We provide
a SIM_allow_speed_enhancement global variable that allows SIM speed
enhancement to be enabled or disabled per session, and an /etc/SIM_spenh
file in FFS that allows it to enabled or disabled on a non-volatile
basis. SIM speed enhancement is now enabled by default.
author | Mychaela Falconia <falcon@freecalypso.org> |
---|---|
date | Sun, 24 May 2020 05:02:28 +0000 |
parents | 93999a60b835 |
children |
line wrap: on
line source
/* +----------------------------------------------------------------------------- | Project : MMI-Framework (8417) | Modul : PHB +----------------------------------------------------------------------------- | Copyright 2002 Texas Instruments Berlin, AG | All rights reserved. | | This file is confidential and a trade secret of Texas | Instruments Berlin, AG | The receipt of or possession of this file does not convey | any rights to reproduce or disclose its contents or to | manufacture, use, or sell anything it may describe, in | whole, or in part, without the specific written consent of | Texas Instruments Berlin, AG. +----------------------------------------------------------------------------- | Purpose : This modul contains the functions to establish the phone book. +----------------------------------------------------------------------------- */ #ifdef TI_PS_FFS_PHB #include "aci_all.h" #include "aci_cmh.h" #include "aci_mem.h" #include "phb_sim.h" #include "phb_aci.h" #include "ffs/ffs.h" #ifdef SIM_TOOLKIT #include "psa.h" #include "psa_sim.h" #include "psa_cc.h" #include "psa_sat.h" #endif /* #ifdef SIM_TOOLKIT */ #include "cmh.h" #include "cmh_phb.h" #include "pcm.h" /* * Constants and enumerations */ #define MAX_ECC_RCD 5 #define FFS_IMSI_SIZE 8 #define MAX_EXTNS_PER_RECORD 9 #define MAX_ELEM_FILES 15 #define SIM_MAX_RECORD_SIZE 256 /* Maximum size of a SIM record */ #define RDM_DATA_FILE_ID (0xff04) /* File ID to store data related to LDN, LMN and LRN Phonebooks */ #define SIZE_DATA_DATE_TIME 12 #define MAX_EXT_RECORDS 10 typedef enum { DECREMENT = -1, INCREMENT } T_PHB_EXT_REF_TYPE; /* * Type definitions */ typedef struct { /* Handle for the Database */ int db_handle; /* Maximum number of records */ UBYTE max_record[MAX_PHONEBOOK]; /* Number of used records */ UBYTE used_record[MAX_PHONEBOOK]; /* Records sizes */ USHORT record_size[MAX_PHONEBOOK]; } T_PHB_SIM_DATA; #define RDM_PHB_DATA_SIZE 6 /* ECC records */ T_PHB_ECC_RECORD phb_ecc_element[MAX_ECC_RCD]; LOCAL T_PHB_SIM_DATA pbs_data; /* Global arrays to hold Reference count for Extension records. */ UBYTE ext1_ref_count[MAX_EXT_RECORDS], ext2_ref_count[MAX_EXT_RECORDS]; UBYTE ext3_ref_count[MAX_EXT_RECORDS], ext4_ref_count[MAX_EXT_RECORDS]; UBYTE ext5_ref_count[MAX_EXT_RECORDS]; UBYTE ext_lmn_ref_count[MAX_EXT_RECORDS], ext_lrn_ref_count[MAX_EXT_RECORDS]; /* Prototypes for search and compare functions */ int pb_sim_search_alpha_func(ULONG flags, const UBYTE *key, int db_handle, USHORT field_id, USHORT rec_num); int pb_sim_search_num_func(ULONG flags, const UBYTE *key, int db_handle, USHORT field_id, USHORT rec_num); int pb_sim_alpha_cmp (int db_handle, USHORT field_id, USHORT recno_1, USHORT recno_2, ULONG flags); int pb_sim_number_cmp (int db_handle, USHORT field_id,USHORT recno_1,USHORT recno_2, ULONG flags); /* * Prototypes for local functions */ LOCAL void pb_sim_read_eeprom_ecc (void); LOCAL int pb_sim_nibblecopy (UBYTE dest[], int destlen, UBYTE src[], int count); LOCAL void pb_sim_revString(char *); LOCAL void pb_sim_read_ext(UBYTE *buffer, T_PHB_RECORD *entry); LOCAL void pb_sim_prepare_ext_data(UBYTE *ext_data, int ext_count, UBYTE *number, UBYTE no_len, UBYTE *subaddr); LOCAL USHORT pb_sim_get_field_id (T_PHB_TYPE type); LOCAL USHORT pb_sim_get_ext_file (T_PHB_TYPE type); LOCAL USHORT pb_sim_get_ext_file_id (USHORT field_id); LOCAL USHORT pb_sim_get_size_except_tag (USHORT field_id); LOCAL int pb_sim_cmpString ( UBYTE* cur_tag, UBYTE* check_tag, UBYTE cmpLen ); LOCAL void pb_sim_cvt_alpha_for_cmp ( UBYTE* entry_tag, UBYTE* cur_tag, UBYTE len ); LOCAL int pb_sim_cmp2Bytes(UBYTE *s1, UBYTE *s2, UBYTE len, UBYTE flag); LOCAL T_PHB_RETURN pb_sim_update_extn_records(USHORT ext_field_id, USHORT rec_num, T_PHB_EXT_REF_TYPE ref_type); LOCAL T_PHB_RETURN pb_sim_read_ext_record_for_delete(T_PHB_TYPE type, USHORT field_id, USHORT db_recno); /* +----------------------------------------------------------------------+ | PROJECT: MMI-Framework MODULE : PHB | | STATE : code ROUTINE: pb_sim_init | +----------------------------------------------------------------------+ PURPOSE : Initializes internal data structures for SIM Phonebook. */ void pb_sim_init (void) { USHORT i; TRACE_FUNCTION ("pb_sim_init()"); db_init(); /* Initialise the data structures. */ /* Initialise ECC Phonebook to contain no records. */ for(i = 0; i < MAX_ECC_RCD; i++) phb_ecc_element[i].phy_idx = 0; return; } /* +----------------------------------------------------------------------+ | PROJECT: MMI-Framework MODULE : PHB | | STATE : code ROUTINE: pb_sim_exit | +----------------------------------------------------------------------+ PURPOSE : This function is called by pb_exit() to inform the SIM part of the phonebook to shut down. */ void pb_sim_exit (void) { TRACE_FUNCTION ("pb_sim_exit()"); db_exit(); return; } /* +----------------------------------------------------------------------+ | PROJECT: MMI-Framework MODULE : PHB | | STATE : code ROUTINE: pb_sim_set_ecc | +----------------------------------------------------------------------+ PURPOSE : The emergency call numbers are read from SIM card and written to FFS. */ T_PHB_RETURN pb_sim_set_ecc (UBYTE ecc_len, const UBYTE *sim_ecc) { USHORT ecc_rec_num; UBYTE *data_ptr; TRACE_FUNCTION ("pb_sim_set_ecc()"); /* Initialise used records for ECC. */ pbs_data.used_record[ECC] = 0; /* if SIM ECC data is not empty, copy SIM ECC data to phonebook */ if ( ecc_len NEQ 0) { data_ptr = ( UBYTE *) sim_ecc; pbs_data.max_record[ECC] = (SHORT)((ecc_len/ECC_NUM_LEN) > MAX_ECC_RCD)? MAX_ECC_RCD: ecc_len/ECC_NUM_LEN; pbs_data.record_size[ECC] = ECC_NUM_LEN; /* Store ECC into RAM, since ECC records will be less in number. */ for (ecc_rec_num = 0; ecc_rec_num < MAX_ECC_RCD; ecc_rec_num++) { if(*data_ptr NEQ 0xff) { memset(&phb_ecc_element[ecc_rec_num],0,sizeof(T_PHB_ECC_RECORD)); phb_ecc_element[ecc_rec_num].phy_idx = ecc_rec_num + 1; memcpy(phb_ecc_element[ecc_rec_num].number, data_ptr, ECC_NUM_LEN); data_ptr += ECC_NUM_LEN; (pbs_data.used_record[ECC])++; } } } else { pb_sim_read_eeprom_ecc(); } return PHB_OK; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_create_ef | +--------------------------------------------------------------------+ PURPOSE : Creates a SIM elementary file. */ T_PHB_RETURN pb_sim_create_ef (USHORT ef, USHORT record_size, USHORT records) { T_DB_INFO_FIELD field_info; T_DB_TYPE db_type; int db_result; TRACE_FUNCTION ("pb_sim_create_ef()"); TRACE_EVENT_P1("Elementary file ID = %x",ef); db_result = db_info_field(pbs_data.db_handle, ef, &field_info); /* Check whether file already exists. */ if(db_result EQ DB_OK) { /* Check for Record size and No. of records in the present field. */ if((field_info.record_size EQ record_size) AND (field_info.num_records EQ records)) return PHB_OK; /* Preserve the existing field. */ else { if(pb_sim_remove_ef(ef) EQ PHB_FAIL) /* Remove the existing file and recreate the field. */ return PHB_FAIL; } } /* Set DB_TYPE depending on the Elementary file. */ switch(ef) { case SIM_ADN: case SIM_FDN: case SIM_BDN: case SIM_SDN: case SIM_EXT1: case SIM_EXT2: case SIM_EXT3: case SIM_EXT4: case SIM_LND: case SIM_OCI: //case SIM_ICI: case FFS_LRN: case FFS_LMN: case FFS_EXT_LRN: case FFS_EXT_LMN: case SIM_EXT5: db_type = DB_FREELIST; break; case SIM_MSISDN: case SIM_IMSI: db_type = DB_UNMANAGED; break; default: TRACE_ERROR("Invalid ef passed to pb_sim_create_ef()"); return PHB_FAIL; } db_result = db_create_field(pbs_data.db_handle, db_type, ef, record_size, records); if(db_result EQ DB_OK) return PHB_OK; /* Return PHB_FAIL since DB has failed to create File. */ return PHB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_write_ef | +--------------------------------------------------------------------+ PURPOSE : Writes entry_size bytes content of buffer at index to the elementary file ef. */ T_PHB_RETURN pb_sim_write_ef (USHORT ef, USHORT phy_recno, USHORT entry_size, const UBYTE *buffer, BOOL *changed, USHORT *ext_record_ef, UBYTE *ext_record_no) { int i; T_DB_CHANGED records_affected; TRACE_FUNCTION ("pb_sim_write_ef()"); /* Initialise changed to FALSE. */ *changed = FALSE; /* Check for extension records. */ switch (ef) { case SIM_ADN: case SIM_MSISDN: case SIM_LND: *ext_record_ef = SIM_EXT1; *ext_record_no = buffer[entry_size - 1]; break; case SIM_FDN: *ext_record_ef = SIM_EXT2; *ext_record_no = buffer[entry_size - 1]; break; case SIM_SDN: *ext_record_ef = SIM_EXT3; *ext_record_no = buffer[entry_size - 1]; break; case SIM_BDN: *ext_record_ef = SIM_EXT4; *ext_record_no = buffer[entry_size - 1]; break; case FFS_LRN: case FFS_LMN: case SIM_OCI: /* Release 1999 and above 31.102 clause 4.2.34 */ *ext_record_ef = SIM_EXT5; *ext_record_no = buffer[entry_size - 15]; // Jirli, please check, 14 instead of 15? break; case SIM_EXT1: /* Extension records can reference other extension records */ case SIM_EXT2: case SIM_EXT3: case SIM_EXT4: case SIM_EXT5: case FFS_EXT_LRN: case FFS_EXT_LMN: *ext_record_ef = ef; *ext_record_no = buffer[entry_size - 1]; break; default: *ext_record_ef = 0; *ext_record_no = 0; } /* Record is not referring any extensions. So set ef and record_no to ZERO. */ if (*ext_record_no EQ 0xff) { *ext_record_ef = 0; *ext_record_no = 0; } if (buffer[0] NEQ 0xFF) { /* Write record into FFS */ if(db_write_record(pbs_data.db_handle, ef, phy_recno, 0, entry_size, buffer) > DB_OK) { if(db_read_change_log(pbs_data.db_handle, &records_affected) EQ DB_OK) { for(i = 0; i < records_affected.entries; i++) { /* Checking whether Elementary file in the database is changed. */ if((records_affected.field_id[i] EQ ef) AND (records_affected.record[i] EQ phy_recno)) { *changed = TRUE; return PHB_OK; } } /* Write operation has not changed File in the database. So returning PHB_OK */ return PHB_OK; } else /* Unable to read change log from DB. So returning PHB_FAIL. */ return PHB_FAIL; } else /* Write failure in DB. So returning PHB_FAIL */ return PHB_FAIL; } else { /* Empty record */ if (db_delete_record (pbs_data.db_handle, ef, phy_recno) NEQ DB_OK) return PHB_FAIL; if(db_read_change_log (pbs_data.db_handle, &records_affected) NEQ DB_OK) return PHB_FAIL; *changed = (records_affected.entries NEQ 0); return PHB_OK; } } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_open | +--------------------------------------------------------------------+ PURPOSE : Opens the SIM phonebook for the given SIM determined by the IMSI. */ T_PHB_RETURN pb_sim_open (const T_imsi_field *imsi_field, BOOL *changed) { T_DB_INFO database_info; UBYTE ffsIMSI[MAX_IMSI_LEN+1]; UBYTE simIMSI[MAX_IMSI_LEN+1]; UBYTE imsi[FFS_IMSI_SIZE]; int db_result; UBYTE buffer[RDM_PHB_DATA_SIZE]; TRACE_FUNCTION("pb_sim_open()"); /* Initially set SIM changed as TRUE. */ *changed = TRUE; /* Open the database. */ db_result = db_open(FFS_PHB_DIR); TRACE_EVENT_P1("DB handle is %d",db_result); if(db_result >= DB_OK) { pbs_data.db_handle = db_result; /* Get database info. */ db_result = db_info(pbs_data.db_handle, &database_info); /* Read IMSI from the FFS if Database is clean. */ if((db_result EQ DB_OK) AND (database_info.clean EQ TRUE)) { db_result = db_read_record(pbs_data.db_handle, SIM_IMSI, 1, 0, FFS_IMSI_SIZE, imsi); /* Compare IMSI read from FFS with IMSI got from SIM. */ if(db_result > DB_OK) { psaSIM_decodeIMSI ((UBYTE*) imsi_field->field,(UBYTE)imsi_field->c_field, (char *)simIMSI); psaSIM_decodeIMSI (imsi, FFS_IMSI_SIZE, (char *)ffsIMSI); if (!strcmp((char *)simIMSI, (char *)ffsIMSI)) { *changed = FALSE; return PHB_OK; } } else { /* Unable to read IMSI, regenerate database */ *changed = TRUE; } } /* Remove database whenever database is Inconsistent and SIM is changed. */ if(db_close(pbs_data.db_handle) NEQ DB_OK) return PHB_FAIL; if(db_remove(FFS_PHB_DIR) NEQ DB_OK) return PHB_FAIL; }/* if(db_result >= DB_OK) */ /* Create database: For the first time, whenever SIM is changed and whenever database is Inconsistent. */ db_result = db_create(FFS_PHB_DIR, MAX_ELEM_FILES, TRUE); TRACE_EVENT_P1("DB handle is %d",db_result); /* Creating DB is successful and valid db_handle is returned */ if(db_result >= DB_OK) { if(db_create_field(pbs_data.db_handle, DB_UNMANAGED, SIM_IMSI, imsi_field->c_field, 1) NEQ DB_OK) return PHB_FAIL; if(db_write_record(pbs_data.db_handle, SIM_IMSI, 1, 0, imsi_field->c_field, imsi_field->field) < DB_OK) return PHB_FAIL; /* Create Elementary file to store RDM Phonebook data */ if(db_create_field(pbs_data.db_handle, DB_UNMANAGED, RDM_DATA_FILE_ID,RDM_PHB_DATA_SIZE,1) NEQ DB_OK) return PHB_FAIL; memset(buffer,0x00, RDM_PHB_DATA_SIZE); if(db_write_record(pbs_data.db_handle, RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, buffer) < DB_OK) return PHB_FAIL; return PHB_OK; } /* Unable to create Database. So returning PHB_FAIL. */ return PHB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_read_ef | +--------------------------------------------------------------------+ PURPOSE : Reads *buffer from elementary file ef at index. */ T_PHB_RETURN pb_sim_read_ef (USHORT ef, USHORT recno, USHORT *entry_size, UBYTE *buffer) { int db_result; T_DB_INFO_FIELD field_info; TRACE_FUNCTION("pb_sim_read_ef()"); if(db_info_field(pbs_data.db_handle, ef, &field_info) EQ DB_OK) { *entry_size = field_info.record_size; db_result = db_read_record (pbs_data.db_handle, ef, recno, 0, field_info.record_size, buffer); if (db_result > DB_OK) return PHB_OK; /* Successfully read */ if (db_result EQ DB_EMPTY_RECORD) { /* Return a deleted record content */ memset (buffer, 0xff, *entry_size); return PHB_OK; } return PHB_FAIL; /* Some problem reading record */ } /* Returning PHB_FAIL, since DB has failed to give Info about the field. */ return PHB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_remove_ef | +--------------------------------------------------------------------+ PURPOSE : Removes elementary file. */ T_PHB_RETURN pb_sim_remove_ef (USHORT ef) { TRACE_FUNCTION("pb_sim_remove_ef()"); if(db_remove_field(pbs_data.db_handle, ef) EQ DB_OK) return PHB_OK; return PHB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_build_index | +--------------------------------------------------------------------+ PURPOSE : Builds index for the given phonebook. */ T_PHB_RETURN pb_sim_build_index (T_PHB_TYPE type) { USHORT field_id; TRACE_FUNCTION("pb_sim_build_index()"); field_id = pb_sim_get_field_id(type); if(db_update_index(pbs_data.db_handle, field_id, NAME_IDX, &pb_sim_alpha_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK) return PHB_FAIL; if(db_update_index(pbs_data.db_handle, field_id, NUMBER_IDX, &pb_sim_number_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK) return PHB_FAIL; return PHB_OK; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_flush_data | +--------------------------------------------------------------------+ PURPOSE : This function informs the SIM phonebook that SIM reading has become finished and we reached a consistent state. */ T_PHB_RETURN pb_sim_flush_data (void) { TRACE_FUNCTION("pb_sim_flush_data()"); if(db_flush(pbs_data.db_handle) EQ DB_OK) return PHB_OK; return PHB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_add_record | +--------------------------------------------------------------------+ PURPOSE : Add a given record at index to the given phonebook. */ T_PHB_RETURN pb_sim_add_record (T_PHB_TYPE type, USHORT phy_recno, const T_PHB_RECORD *entry, T_DB_CHANGED *rec_affected) { USHORT field_id, ext_file_id; UBYTE tag_len, max_tag_len; UBYTE data[SIM_MAX_RECORD_SIZE]; UBYTE buffer[RDM_PHB_DATA_SIZE]; T_DB_INFO_FIELD info_field; UBYTE ext_rec_cnt = 0; UBYTE ext_rec_num1, ext_rec_num2; int db_result,i; TRACE_FUNCTION("pb_sim_add_record()"); /* Handling of ECC Phonebook */ if(type EQ ECC) { if((phy_recno > 0 ) AND (phy_recno <= MAX_ECC_RCD)) { phb_ecc_element[phy_recno - 1].phy_idx = phy_recno; memcpy(phb_ecc_element[phy_recno - 1].number,entry->number, ECC_NUM_LEN); return PHB_OK; } else return PHB_FAIL; } /* Get Elementary file ID for the Phonebook type. */ field_id = pb_sim_get_field_id(type); TRACE_EVENT_P1("pb_sim_get_field_id->Field_id: %x", field_id); /* Get Extension file for the Phonebook type. */ ext_file_id = pb_sim_get_ext_file(type); TRACE_EVENT_P1("Ext_Field_id: %x", ext_file_id); db_result = db_info_field(pbs_data.db_handle, field_id, &info_field); /* Get record size to calculate alpha_len for the entry */ if(db_result NEQ DB_OK) { TRACE_EVENT_P1("db_result = %d",db_result); return PHB_FAIL; } /* Handling of LDN, LMN and LRN Phonebook records. */ if((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN)) { if(phy_recno NEQ 1) return PHB_FAIL; /* Read data related to LDN,LMN and LRN Phonebooks from FFS */ db_result = db_read_record(pbs_data.db_handle, RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, buffer); /* Check for DB Failure. */ if(db_result < DB_OK) return PHB_FAIL; /* Information for handling Cyclic RDM Records ---------------------------------------- buffer[0] ---> Most Recent in LDN buffer[1] ---> Oldest in LDN buffer[2] ---> Most Recent in LMN buffer[3] ---> Oldest in LMN buffer[4] ---> Most Recent in LRN buffer[5] ---> Oldest in LRN ---------------------------------------- */ if(type EQ LDN) /* Circular entry handling for LDN */ { buffer[0] ++; if(buffer[0] > info_field.num_records) buffer[0] = 1; if(buffer[0] EQ buffer[1]) { buffer[1]++; if(buffer[1] > info_field.num_records) buffer[1] = 1; } phy_recno = buffer[0]; if(buffer[1] EQ 0) buffer[1] = 1; } if(type EQ LMN) /* Circular entry handling for LMN */ { buffer[2]++; if(buffer[2] > info_field.num_records) buffer[2] = 1; if(buffer[2] EQ buffer[3]) { buffer[3]++; if(buffer[3] > info_field.num_records) buffer[3] = 1; } phy_recno = buffer[2]; if(buffer[3] EQ 0) buffer[3] = 1; } if(type EQ LRN) /* Circular entry handling for LRN */ { buffer[4]++; if(buffer[4] > info_field.num_records) buffer[4] = 1; if(buffer[4] EQ buffer[5]) { buffer[5]++; if(buffer[5] > info_field.num_records) buffer[5] = 1; } phy_recno = buffer[4]; if(buffer[5] EQ 0) buffer[5] = 1; } TRACE_EVENT_P3("%d %d %d", buffer[0], buffer[1],buffer[2]); TRACE_EVENT_P3("%d %d %d", buffer[3], buffer[4],buffer[5]); /* Write data related to LDN,LMN and LRN Phonebooks to FFS */ db_result = db_write_record(pbs_data.db_handle, RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, buffer); /* Check for DB Failure. */ if(db_result < DB_OK) return PHB_FAIL; }/* if((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN)) */ /* Convert T_PHB_TYPE into data structures as described in ETSI 11.11 */ /* Bytes Description M/O Length | ---------------------------------------------------------------------- 1 to X Alpha Identifier O X bytes X+1 Length of BCD number/SSC contents M 1 byte X+2 TON and NPI M 1 byte X+3 to X+12 Dialling Number/SSC String M 10 bytes X+13 Capability/Configuration Identifier M 1 byte X+14 Extension Record Identifier M 1 byte ------------------------------------------------------- Extra fields for LDN, LMN, and LMN Phonebook records (As per 31.102) ------------------------------------------------------- X+15 to X+21 Outgoing call date and time M 7 bytes X+22 to X+24 Outgoing call duration M 3 bytes X+26 Line of the call M 1 byte (New field added to store line of call) ----------------------------------------------------------------------*/ tag_len = pb_sim_get_entry_len(entry->tag, PHB_MAX_TAG_LEN); max_tag_len = info_field.record_size - pb_sim_get_size_except_tag(field_id); if(tag_len > max_tag_len) return PHB_TAG_EXCEEDED; memset(data, 0xFF, sizeof(data)); memcpy(data, entry->tag, tag_len); if(entry->number[10] NEQ 0xFF) { data[max_tag_len] = 11; /* max. length */ } else { data[max_tag_len] = entry->len + 1; } data[max_tag_len+1] = entry->ton_npi; memcpy((char *)&data[max_tag_len+2], (char *)entry->number, 10); data[max_tag_len+12] = entry->cc_id; /* Copy data specific to records of Phonebook Types (LRN, LDN and LMN). */ if((type EQ LDN) OR (type EQ LRN) OR (type EQ LMN)) { if(entry->v_time) { data[max_tag_len+14] = entry->time.year; data[max_tag_len+15] = entry->time.month; data[max_tag_len+16] = entry->time.day; data[max_tag_len+17] = entry->time.hour; data[max_tag_len+18] = entry->time.minute; data[max_tag_len+19] = entry->time.second; data[max_tag_len+20] = entry->time.time_zone; data[max_tag_len+21] = (UBYTE)((entry->time.duration >> 16) & 0xff); data[max_tag_len+22] = (UBYTE)((entry->time.duration >> 8) & 0xff); data[max_tag_len+23] = (UBYTE)((entry->time.duration) & 0xff); } if(entry->v_line) { data[max_tag_len+24] = entry->line; } } TRACE_EVENT_P1("Number = %s",entry->number); /* Check if extension records are needed */ /* Check how many extension records are needed for number */ if(entry->number[10] NEQ 0xFF) { ext_rec_cnt = entry ->len - 10; if(ext_rec_cnt % 10) ext_rec_cnt = (ext_rec_cnt / 10) + 1; else ext_rec_cnt = (ext_rec_cnt / 10); } /* Check how many extension records are needed for subaddress */ if(entry->subaddr[0] NEQ 0xFF) { ext_rec_cnt++; } if(entry->subaddr[11] NEQ 0xFF) { ext_rec_cnt++; } TRACE_EVENT_P1("phy_recno = %d",phy_recno); TRACE_EVENT_P2("no_rec = %d, used_rec = %d",info_field.num_records,info_field.used_records); /* If record number is not mentioned, search for the free record and add the entry. */ if(phy_recno EQ 0) { db_result = db_find_free_record( pbs_data.db_handle, field_id); /* Database is unable to find the free record. So returning PHB_FULL. */ if(db_result EQ DB_RECORD_NOT_FOUND) return PHB_FULL; if(db_result < DB_OK) return PHB_FAIL; /* Database has returned the free record number. */ phy_recno = db_result; } /* Write record if entry does not require extension records */ if(ext_rec_cnt EQ 0) { /* Write record into FFS */ if(db_write_record(pbs_data.db_handle, field_id, phy_recno, 0, info_field.record_size, data) < DB_OK) return PHB_FAIL; /* For LDN record also write to SIM_LDN (without date and time Details */ if(type EQ LDN) { memset(&data[max_tag_len + pb_sim_get_size_except_tag(field_id)], 0xFF, SIZE_DATA_DATE_TIME); /* if(db_info_field(pbs_data.db_handle, SIM_LND, &info_field) NEQ DB_OK) return PHB_FAIL; if(db_write_record(pbs_data.db_handle, SIM_LND, phy_recno, 0, info_field.record_size, data) < DB_OK) return PHB_FAIL;*/ } } else /* We need to find free extension record. */ { TRACE_EVENT_P1("Extension records = %d",ext_rec_cnt); /* Search for free extension records */ /* Check whether extension file has required no. of free records. */ db_result = db_info_field(pbs_data.db_handle, ext_file_id, &info_field); if((info_field.num_records - info_field.used_records) < ext_rec_cnt) return PHB_FAIL; /* Required no. of free extension records are found */ ext_rec_num1= db_find_free_record( pbs_data.db_handle,ext_file_id); /* DB has returned non-zero positive number. (Valid record number which is free). */ if(ext_rec_num1 > DB_OK) { /* Set Extension record Identifier */ data[max_tag_len+13] = ext_rec_num1; db_result = db_info_field(pbs_data.db_handle, field_id, &info_field); /* Write record into FFS */ if(db_write_record(pbs_data.db_handle, field_id, phy_recno, 0, info_field.record_size, data) < DB_OK) return PHB_FAIL; } else return PHB_FAIL; db_result = db_info_field(pbs_data.db_handle, ext_file_id, &info_field); /* Prepare extension data and write into Extension file after finding the free records. */ for(i = 0; i < ext_rec_cnt; i++) { pb_sim_prepare_ext_data(data, i, (UBYTE*)entry->number, entry->len, (UBYTE*)entry->subaddr); /* Find next free record to chain the extension records. */ ext_rec_num2 = db_find_free_record( pbs_data.db_handle,ext_file_id); /* Chain extension records and set last link to "FF" */ if(i NEQ (ext_rec_cnt - 1)) data[12] = ext_rec_num2; /* Write extension record into FFS */ if(db_write_record(pbs_data.db_handle, ext_file_id, ext_rec_num1, 0, info_field.record_size, data) < DB_OK) return PHB_FAIL; if(pb_sim_update_extn_records(ext_file_id, ext_rec_num1, INCREMENT) EQ PHB_FAIL) return PHB_FAIL; /* Preserve the previous free record number. */ ext_rec_num1 = ext_rec_num2; } } /* Get information about changed records from the database. */ if(db_read_change_log(pbs_data.db_handle, rec_affected) NEQ DB_OK) return PHB_FAIL; if((type NEQ LDN) AND (type NEQ LMN) AND (type NEQ LRN)) { /* Update the sorted indexes. */ if(db_update_index(pbs_data.db_handle, field_id, NAME_IDX, &pb_sim_alpha_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK) return PHB_FAIL; if(db_update_index(pbs_data.db_handle, field_id, NUMBER_IDX, &pb_sim_number_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK) return PHB_FAIL; } else { /* Remove RDM data record from the list */ if(rec_affected->entries NEQ 0) { rec_affected->entries -= 2; /* Remove the record from the list */ memmove (&rec_affected->field_id[0], &rec_affected->field_id[1], sizeof (USHORT) * (DB_MAX_AFFECTED - 1)); memmove (&rec_affected->record[0], &rec_affected->record[1], sizeof (USHORT) * (DB_MAX_AFFECTED - 1)); /* Remove the record from the list */ memmove (&rec_affected->field_id[0], &rec_affected->field_id[1], sizeof (USHORT) * (DB_MAX_AFFECTED - 1)); memmove (&rec_affected->record[0], &rec_affected->record[1], sizeof (USHORT) * (DB_MAX_AFFECTED - 1)); /* Remove extension record from the list. */ if(ext_rec_cnt NEQ 0) { rec_affected->entries --; /* Remove the record from the list */ memmove (&rec_affected->field_id[0], &rec_affected->field_id[1], sizeof (USHORT) * (DB_MAX_AFFECTED - 1)); memmove (&rec_affected->record[0], &rec_affected->record[1], sizeof (USHORT) * (DB_MAX_AFFECTED - 1)); } } } return PHB_OK; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_del_record | +--------------------------------------------------------------------+ PURPOSE : Delete a given record at phy_recno from the given phonebook. */ T_PHB_RETURN pb_sim_del_record (T_PHB_TYPE type, USHORT phy_recno, T_DB_CHANGED *rec_affected) { USHORT field_id, ext_file_id, db_recno; UBYTE buffer[RDM_PHB_DATA_SIZE], rec_cnt; T_DB_INFO_FIELD info_field; UBYTE data[SIM_MAX_RECORD_SIZE]; TRACE_FUNCTION("pb_sim_del_record()"); /* Handling of ECC Phonebook */ if(type EQ ECC) { if((phy_recno > 0 ) AND (phy_recno <= MAX_ECC_RCD)) { phb_ecc_element[phy_recno - 1].phy_idx = 0; memset(phb_ecc_element[phy_recno - 1].number, 0, ECC_NUM_LEN); return PHB_OK; } else return PHB_FAIL; } TRACE_EVENT_P1("phy_recno = %d", phy_recno); /* Get Elementary file ID for the Phonebook type. */ field_id = pb_sim_get_field_id(type); /* Get Extension file for the Phonebook type. */ ext_file_id = pb_sim_get_ext_file(type); /* Get no. of records in the field */ if(db_info_field(pbs_data.db_handle, field_id, &info_field) NEQ DB_OK) return PHB_FAIL; /* Information for handling Cyclic RDM Records ---------------------------------------- buffer[0] ---> Most Recent in LDN buffer[1] ---> Oldest in LDN buffer[2] ---> Most Recent in LMN buffer[3] ---> Oldest in LMN buffer[4] ---> Most Recent in LRN buffer[5] ---> Oldest in LRN ---------------------------------------- */ /* Handling of LDN, LMN and LRN Phonebook records. */ if((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN)) { /* Read data related to LDN,LMN and LRN Phonebooks from FFS */ if(db_read_record(pbs_data.db_handle, RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, (UBYTE *) buffer) < DB_OK) return PHB_FAIL; if(type EQ LDN) /* Circular entry handling for LDN */ { db_recno = buffer[0]; if(phy_recno NEQ 1) { for(rec_cnt = 0; rec_cnt < (phy_recno - 1) ; rec_cnt++) { db_recno--; if(db_recno EQ 0) db_recno = (UBYTE)info_field.num_records; while(db_read_record(pbs_data.db_handle, field_id, db_recno, 0, info_field.record_size, data) < DB_OK) { db_recno--; if(db_recno EQ 0) db_recno = (UBYTE)info_field.num_records; } } } if(buffer[0] EQ buffer[1]) buffer[0] = buffer[1] = 0; if(buffer[0] EQ db_recno) { buffer[0]--; if(buffer[0] EQ 0) buffer[0] = (UBYTE)info_field.num_records; while(db_read_record(pbs_data.db_handle, field_id, buffer[0], 0, info_field.record_size, data) < DB_OK) { buffer[0]--; if(buffer[0] EQ 0) buffer[0] = (UBYTE)info_field.num_records; } } if(buffer[1] EQ db_recno) { buffer[1]++; if(buffer[1] EQ info_field.num_records) buffer[1] = 1; while(db_read_record(pbs_data.db_handle, field_id, buffer[1], 0, info_field.record_size, data) < DB_OK) { buffer[1]++; if(buffer[1] EQ info_field.num_records) buffer[1] = 1; } } } if(type EQ LMN) /* Circular entry handling for LMN */ { db_recno = buffer[2]; if(phy_recno NEQ 1) { for(rec_cnt = 0; rec_cnt < (phy_recno - 1) ; rec_cnt++) { db_recno--; if(db_recno EQ 0) db_recno = (UBYTE)info_field.num_records; while(db_read_record(pbs_data.db_handle, field_id, db_recno, 0, info_field.record_size, data) < DB_OK) { db_recno--; if(db_recno EQ 0) db_recno = (UBYTE)info_field.num_records; } } } if(buffer[2] EQ buffer[3]) buffer[2] = buffer[3] = 0; if(buffer[2] EQ db_recno) { buffer[2]--; if(buffer[2] EQ 0) buffer[2] = (UBYTE)info_field.num_records; while(db_read_record(pbs_data.db_handle, field_id, buffer[2], 0, info_field.record_size, data) < DB_OK) { buffer[2]--; if(buffer[2] EQ 0) buffer[2] = (UBYTE)info_field.num_records; } } if(buffer[3] EQ db_recno) { buffer[3]++; if(buffer[3] EQ info_field.num_records) buffer[3] = 1; while(db_read_record(pbs_data.db_handle, field_id, buffer[3], 0, info_field.record_size, data) < DB_OK) { buffer[3]++; if(buffer[3] EQ info_field.num_records) buffer[3] = 1; } } } if(type EQ LRN) /* Circular entry handling for LRN */ { db_recno = buffer[4]; if(phy_recno NEQ 1) { for(rec_cnt = 0; rec_cnt < (phy_recno - 1) ; rec_cnt++) { db_recno--; if(db_recno EQ 0) db_recno = (UBYTE)info_field.num_records; while(db_read_record(pbs_data.db_handle, field_id, db_recno, 0, info_field.record_size, data) < DB_OK) { db_recno--; if(db_recno EQ 0) db_recno = (UBYTE)info_field.num_records; } } } if(buffer[4] EQ buffer[5]) buffer[4] = buffer[5] = 0; if(buffer[4] EQ db_recno) { buffer[4]--; if(buffer[4] EQ 0) buffer[4] = (UBYTE)info_field.num_records; while(db_read_record(pbs_data.db_handle, field_id, buffer[4], 0, info_field.record_size, data) < DB_OK) { buffer[4]--; if(buffer[4] EQ 0) buffer[4] = (UBYTE)info_field.num_records; } } if(buffer[5] EQ db_recno) { buffer[5]++; if(buffer[5] EQ info_field.num_records) buffer[5] = 1; while(db_read_record(pbs_data.db_handle, field_id, buffer[5], 0, info_field.record_size, data) < DB_OK) { buffer[5]++; if(buffer[5] EQ info_field.num_records) buffer[5] = 1; } } } TRACE_EVENT_P1("db_recno = %d ", db_recno); TRACE_EVENT_P3("%d %d %d", buffer[0], buffer[1],buffer[2]); TRACE_EVENT_P3("%d %d %d", buffer[3], buffer[4],buffer[5]); /* Write data related to LDN,LMN and LRN Phonebooks to FFS */ if(db_write_record(pbs_data.db_handle, RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, (UBYTE *) buffer) < DB_OK) return PHB_FAIL; } else { db_recno = phy_recno; } /* Delete extension records if not referenced. */ if(pb_sim_read_ext_record_for_delete(type, field_id, db_recno) EQ PHB_FAIL) return PHB_FAIL; /* Delete record from FFS. */ if(db_delete_record(pbs_data.db_handle, field_id,db_recno) NEQ DB_OK) return PHB_FAIL; /* Get information about changed records from the database. */ if(db_read_change_log(pbs_data.db_handle, rec_affected) NEQ DB_OK) return PHB_FAIL; if((type NEQ LDN) AND (type NEQ LMN) AND (type NEQ LRN)) { /* Update the sorted indexes. */ if(db_update_index(pbs_data.db_handle, field_id, NAME_IDX, &pb_sim_alpha_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK) return PHB_FAIL; if(db_update_index(pbs_data.db_handle, field_id, NUMBER_IDX, &pb_sim_number_cmp, PHB_MATCH_PARTIAL) NEQ DB_OK) return PHB_FAIL; } else { if(rec_affected->entries NEQ 0) { /* Remove RDM data record from the list */ rec_affected->entries -= 2; /* Remove the record from the list */ memmove (&rec_affected->field_id[0], &rec_affected->field_id[1], sizeof (USHORT) * (DB_MAX_AFFECTED - 1)); memmove (&rec_affected->record[0], &rec_affected->record[1], sizeof (USHORT) * (DB_MAX_AFFECTED - 1)); /* Remove the record from the list */ memmove (&rec_affected->field_id[0], &rec_affected->field_id[1], sizeof (USHORT) * (DB_MAX_AFFECTED - 1)); memmove (&rec_affected->record[0], &rec_affected->record[1], sizeof (USHORT) * (DB_MAX_AFFECTED - 1)); } TRACE_EVENT_P1("rec-affected = %d", rec_affected->entries); } return PHB_OK; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_read_record | +--------------------------------------------------------------------+ PURPOSE : Read a given physical record from the flash based phonebook. */ T_PHB_RETURN pb_sim_read_record (T_PHB_TYPE type, USHORT phy_recno, T_PHB_RECORD *entry) { USHORT field_id, ext_file_id; USHORT db_recno; T_DB_INFO_FIELD info_field; UBYTE buffer[RDM_PHB_DATA_SIZE]; UBYTE data[SIM_MAX_RECORD_SIZE], *ptr; UBYTE max_tag_len; UBYTE ext_rcd_num; TRACE_FUNCTION("pb_sim_read_record()"); /* Handling of ECC Phonebook */ if(type EQ ECC) { if((phy_recno > 0 ) AND (phy_recno <= MAX_ECC_RCD)) { entry->phy_recno = phy_recno; memcpy(entry->number, phb_ecc_element[phy_recno - 1].number, ECC_NUM_LEN); return PHB_OK; } else return PHB_FAIL; } /* Get Elementary file ID for the Phonebook type. */ field_id = pb_sim_get_field_id(type); /* Get Extension file for the Phonebook type. */ ext_file_id = pb_sim_get_ext_file(type); /* Read record from the database. */ if(db_info_field(pbs_data.db_handle, field_id, &info_field) NEQ DB_OK) return PHB_FAIL; /* Information for handling Cyclic RDM Records ---------------------------------------- buffer[0] ---> Most Recent in LDN buffer[1] ---> Oldest in LDN buffer[2] ---> Most Recent in LMN buffer[3] ---> Oldest in LMN buffer[4] ---> Most Recent in LRN buffer[5] ---> Oldest in LRN ---------------------------------------- */ /* Handling of LDN, LMN and LRN Phonebook records. */ if((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN)) { /* Read data related to LDN,LMN and LRN Phonebooks from FFS */ if(db_read_record(pbs_data.db_handle, RDM_DATA_FILE_ID, 1, 0, RDM_PHB_DATA_SIZE, (UBYTE *) buffer) < DB_OK) return PHB_FAIL; /* Since LDN, LMN and LRN records are circular entries, most recent will be the 1st record and entries increase towards the oldest one for Reading. */ if(type EQ LDN) { if(buffer[0] EQ 0) buffer[0] = 1; db_recno = buffer[0] - phy_recno + 1; db_recno = db_recno % (info_field.num_records); if(db_recno EQ 0) db_recno = (info_field.num_records); } if(type EQ LMN) { if(buffer[2] EQ 0) buffer[2] = 1; db_recno = buffer[2] - phy_recno + 1; db_recno = db_recno % (info_field.num_records); if(db_recno EQ 0) db_recno = (info_field.num_records); } if(type EQ LRN) { if(buffer[4] EQ 0) buffer[4] = 1; db_recno = buffer[4] - phy_recno + 1; db_recno = db_recno % (info_field.num_records); if(db_recno EQ 0) db_recno = (info_field.num_records); } } else db_recno = phy_recno; TRACE_EVENT_P2("db_recno = %d phy_recno = %d",db_recno, phy_recno); TRACE_EVENT_P3("%d %d %d", buffer[0], buffer[1],buffer[2]); TRACE_EVENT_P3("%d %d %d", buffer[3], buffer[4],buffer[5]); if(db_read_record(pbs_data.db_handle, field_id, db_recno, 0, info_field.record_size, data) < DB_OK) return PHB_FAIL; /* Convert SIM data to the type T_PHB_RECORD. */ ptr = data; max_tag_len = MINIMUM ((info_field.record_size) - pb_sim_get_size_except_tag(field_id), PHB_MAX_TAG_LEN); entry->phy_recno = phy_recno; entry->tag_len = (UBYTE)pb_sim_get_entry_len(ptr, max_tag_len); memset(entry->tag, 0xFF, PHB_MAX_TAG_LEN); /* init the tag value */ memcpy ( (char*)entry->tag, (char*)ptr, entry->tag_len ); ptr += (info_field.record_size) - pb_sim_get_size_except_tag(field_id); max_tag_len = (info_field.record_size) - pb_sim_get_size_except_tag(field_id); entry->len = *ptr - 1; ++ptr; entry->ton_npi = *ptr; ++ptr; memset(entry->number, 0xFF, PHB_PACKED_NUM_LEN); memcpy( (char*)entry->number, (char*)ptr, entry->len ); ptr += 10; entry->cc_id = *ptr; ++ptr; /* Copy data specific to records of LDN, LMN, and LRN phonebook types. */ if((type EQ LDN) OR (type EQ LMN) OR (type EQ LRN)) { entry->v_time = 1; entry->time.year=data[max_tag_len+14] ; entry->time.month=data[max_tag_len+15]; entry->time.day=data[max_tag_len+16]; entry->time.hour=data[max_tag_len+17] ; entry->time.minute= data[max_tag_len+18]; entry->time.second=data[max_tag_len+19] ; entry->time.time_zone=data[max_tag_len+20]; entry->time.duration = (data[max_tag_len+21] << 16) + (data[max_tag_len+22] << 8) + (data[max_tag_len+23] ); entry->v_line = 1; entry->line=data[max_tag_len+24]; } if (*ptr NEQ 0xFF) /* check for extention records */ { ext_rcd_num =(UBYTE)*ptr; if(db_info_field(pbs_data.db_handle, ext_file_id, &info_field) NEQ DB_OK) return PHB_FAIL; /* Reset pointer to start location. */ ptr = data; memset(ptr, 0xFF, info_field.record_size); if(db_read_record(pbs_data.db_handle, ext_file_id, ext_rcd_num, 0, info_field.record_size, ptr) < DB_OK) return PHB_FAIL; pb_sim_read_ext(ptr, entry); while(*(ptr + 12) NEQ 0xFF) /* check if a further EXT entry exists */ { memset(ptr, 0xFF, info_field.record_size); db_read_record(pbs_data.db_handle, ext_file_id, (USHORT)*(ptr+12), 0, info_field.record_size,ptr); pb_sim_read_ext(ptr, entry); } } return PHB_OK; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_read_alpha_record | +--------------------------------------------------------------------+ PURPOSE : Read a given physical record from the flash based phonebook in alphabetical order. */ T_PHB_RETURN pb_sim_read_alpha_record (T_PHB_TYPE type, USHORT order_num, T_PHB_RECORD *entry) { int db_result; USHORT field_id, ext_file_id; TRACE_FUNCTION("pb_sim_read_alpha_record()"); /* Get Elementary file ID for the Phonebook type. */ field_id = pb_sim_get_field_id(type); /* Get Extension file for the Phonebook type. */ ext_file_id = pb_sim_get_ext_file(type); /* Read record from the FFS. */ db_result = db_get_phy_from_idx(pbs_data.db_handle, field_id, NAME_IDX, order_num); if(db_result > DB_OK) { return pb_sim_read_record(type, (USHORT)db_result, entry) ; } /* Check whether index is vaild. */ if(db_result EQ DB_INVALID_INDEX) return PHB_INVALID_IDX; /* Unable to get record from the database. Hence returning PHB_FAIL. */ return PHB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_read_number_record | +--------------------------------------------------------------------+ PURPOSE : Read a given physical record from the flash based phonebook in number sorted order. */ T_PHB_RETURN pb_sim_read_number_record (T_PHB_TYPE type, USHORT order_num, T_PHB_RECORD *entry) { int db_result; USHORT field_id, ext_file_id; TRACE_FUNCTION("pb_sim_read_number_record()"); /* Get Elementary file ID for the Phonebook type. */ field_id = pb_sim_get_field_id(type); /* Get Extension file for the Phonebook type. */ ext_file_id = pb_sim_get_ext_file(type); /* Read record from the FFS. */ db_result = db_get_phy_from_idx(pbs_data.db_handle, field_id, NUMBER_IDX, order_num); if(db_result > DB_OK) { return pb_sim_read_record(type, (USHORT)db_result, entry) ; } else if(db_result EQ DB_INVALID_INDEX) return PHB_INVALID_IDX; else return PHB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_search_name | +--------------------------------------------------------------------+ PURPOSE : Finds the first entry matching the search tag. */ T_PHB_RETURN pb_sim_search_name (T_PHB_TYPE type, T_PHB_MATCH match, const T_ACI_PB_TEXT *search_tag, SHORT *order_num) { T_ACI_PB_TEXT key; int res; USHORT field_id, ext_file_id; TRACE_FUNCTION("pb_sim_search_name()"); /* Get Elementary file ID for the Phonebook type. */ field_id = pb_sim_get_field_id(type); /* Get Extension file for the Phonebook type. */ ext_file_id = pb_sim_get_ext_file(type); key.len = search_tag->len; key.cs = search_tag->cs; pb_sim_cvt_alpha_for_cmp ((UBYTE*) search_tag->data, (UBYTE*) key.data, search_tag->len); res = db_search(pbs_data.db_handle, field_id, NAME_IDX, (UBYTE*) order_num, pb_sim_search_alpha_func, match, (const UBYTE*)&key); if(res > DB_OK) { return PHB_OK; } return PHB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_search_number | +--------------------------------------------------------------------+ PURPOSE : Finds the first entry matching the number. */ T_PHB_RETURN pb_sim_search_number (T_PHB_TYPE type, const UBYTE *number, SHORT *order_num) { int res, i; CHAR cur_number[MAX_PHB_NUM_LEN]; CHAR rev_number[MAX_PHB_NUM_LEN]; int cmpLen, cmp_res; USHORT field_id, ext_file_id; TRACE_FUNCTION("pb_sim_search_number()"); /* Handling for ECC Phonebook. */ if(type EQ ECC) { for(i = 0; i < pbs_data.max_record[ECC]; i++) { cmhPHB_getAdrStr(cur_number, MAX_PHB_NUM_LEN - 1,phb_ecc_element[i].number,pbs_data.record_size[ECC]); pb_sim_revString(cur_number); strcpy( rev_number,(const char*)number); pb_sim_revString(rev_number); cmpLen = MINIMUM(strlen((const char*) cur_number), strlen((const char*)number)); cmp_res = pb_sim_cmpString((UBYTE*)cur_number, (UBYTE*)rev_number, cmpLen); if(cmp_res NEQ 0) return PHB_FAIL; else { return PHB_OK; } } } /* Get Elementary file ID for the Phonebook type. */ field_id = pb_sim_get_field_id(type); TRACE_EVENT_P2("type = %d field_id = %x", type, field_id); /* Get Extension file for the Phonebook type. */ ext_file_id = pb_sim_get_ext_file(type); res = db_search(pbs_data.db_handle, field_id, NUMBER_IDX, (UBYTE*)order_num, &pb_sim_search_num_func, PHB_MATCH_PARTIAL, number); if(res > DB_OK) { return PHB_OK; } return PHB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_read_sizes | +--------------------------------------------------------------------+ PURPOSE : Reads the sizes of a given phonebook. */ T_PHB_RETURN pb_sim_read_sizes (T_PHB_TYPE type, SHORT *max_rcd, SHORT *used_rcd, UBYTE *tag_len) { T_DB_INFO_FIELD info_field; USHORT field_id; int db_result; TRACE_FUNCTION("pb_sim_read_sizes()"); /* Handling for ECC Phonebook */ if(type EQ ECC) { *max_rcd = pbs_data.max_record[ECC]; *used_rcd = pbs_data.used_record[ECC]; *tag_len = 0; /* To Do:Alpha tag will not be there for ECC. So assigning zero here */ return PHB_OK; } /* Get Elementary file ID for the Phonebook type. */ field_id = pb_sim_get_field_id(type); db_result = db_info_field(pbs_data.db_handle, field_id, &info_field); TRACE_EVENT_P1("db_result = %d", db_result); if(db_result EQ DB_OK) { *max_rcd = info_field.num_records; *used_rcd = info_field.used_records; *tag_len = info_field.record_size - pb_sim_get_size_except_tag(field_id); return PHB_OK; } return PHB_FAIL; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_get_entry_len | +--------------------------------------------------------------------+ PURPOSE : Used to get the length in bytes of a given entry which is coded as given in 11.11 Annex B. */ int pb_sim_get_entry_len (const UBYTE *pb_tag, UBYTE max_pb_len) { int pb_len = 0; UBYTE inc_count = 1; BOOL ucs2 = FALSE; UBYTE chars = 0; TRACE_FUNCTION("pb_sim_get_entry_len()"); if (*pb_tag EQ 0x80) { ucs2 = TRUE; inc_count = 2; /* check two bytes */ pb_len = 1; /* skip the 0x80 */ } else if (*pb_tag EQ 0x81 OR *pb_tag EQ 0x82) { if (*pb_tag EQ 0x81) pb_len = 3; /* 0x80 + len + pointer */ else pb_len = 4; /* 0x80 + len + 2xpointer */ chars = pb_tag[1]; pb_tag += pb_len; /* go to data */ while (chars) { if (*pb_tag++ & 0x80) pb_len+=2; else pb_len+=1; pb_tag++; chars--; } return MINIMUM(pb_len,max_pb_len); } while (pb_len < max_pb_len) { if (ucs2 EQ TRUE) { if (!(pb_len+1 < max_pb_len)) /* Check also if we traverse the upper bound */ break; /* so only a "half" UCS2 element is remaining */ } if (pb_tag[pb_len] EQ 0xFF) { /* one 0xFF indicates the end of a non UCS2 string */ if (ucs2 EQ FALSE) { break; } /* two 0xFF indicates the end of a UCS2 string */ if (pb_tag[pb_len + 1] EQ 0xFF) { break; } } pb_len += inc_count; } return (pb_len); } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_alpha_cmp | +--------------------------------------------------------------------+ PURPOSE : Compares alpha identifier of two records. */ int pb_sim_alpha_cmp (int db_handle, USHORT field_id, USHORT recno_1, USHORT recno_2, ULONG flags) { T_PHB_RECORD entry_1,entry_2; UBYTE cmpLen = 0; UBYTE *buffer; UBYTE max_tag_len; UBYTE cur_tag[PHB_MAX_TAG_LEN], check_tag[PHB_MAX_TAG_LEN]; int cmp_res; T_DB_INFO_FIELD info_field; TRACE_FUNCTION("pb_sim_alpha_cmp()"); db_info_field(db_handle, field_id, &info_field); MALLOC(buffer, info_field.record_size); /* Read the first record. */ db_read_record(db_handle, field_id, recno_1, 0, info_field.record_size, buffer); /* Unpack record 1 to do a string comparison on the alpha identifier field */ max_tag_len = MINIMUM ( (info_field.record_size) - pb_sim_get_size_except_tag(field_id), PHB_MAX_TAG_LEN); entry_1.tag_len = (UBYTE)pb_sim_get_entry_len(buffer, max_tag_len); memset(entry_1.tag, 0xFF, PHB_MAX_TAG_LEN); /* init the tag value */ memcpy ( (char*)entry_1.tag, (char*)buffer, entry_1.tag_len ); pb_sim_cvt_alpha_for_cmp ( entry_1.tag, cur_tag, entry_1.tag_len ); memset(buffer, 0, info_field.record_size); /* Read the second record. */ db_read_record(db_handle, field_id, recno_2, 0, info_field.record_size, buffer); /* Unpack record 2 to do a string comparison on the alpha identifier field */ max_tag_len = MINIMUM ((info_field.record_size) - pb_sim_get_size_except_tag(field_id), PHB_MAX_TAG_LEN); entry_2.tag_len = (UBYTE)pb_sim_get_entry_len(buffer, max_tag_len); memset(entry_2.tag, 0xFF, PHB_MAX_TAG_LEN); /* init the tag value */ memcpy ( (char*)entry_2.tag, (char*)buffer, entry_2.tag_len ); pb_sim_cvt_alpha_for_cmp ( entry_2.tag, check_tag, entry_2.tag_len ); cmpLen = MINIMUM ( entry_1.tag_len, entry_2.tag_len ); TRACE_EVENT_P1("%d", cmpLen); cmp_res = pb_sim_cmpString ( cur_tag, check_tag, cmpLen ); if (cmp_res EQ 0) { /* Correct result when length was different, ACIPHB201 */ if (entry_1.tag_len < entry_2.tag_len) cmp_res = -1; else if (entry_1.tag_len > entry_2.tag_len) cmp_res = 1; } MFREE(buffer); return cmp_res; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_number_cmp | +--------------------------------------------------------------------+ PURPOSE : Compares two numbers of two records. */ int pb_sim_number_cmp (int db_handle, USHORT field_id, USHORT recno_1, USHORT recno_2, ULONG flags) { T_PHB_RECORD entry_1,entry_2; T_DB_INFO_FIELD info_field; UBYTE cmpLen = 0; UBYTE *buffer, *tmp_buffer; UBYTE ext_rcd_num; UBYTE max_tag_len; CHAR cur_number[MAX_PHB_NUM_LEN]; CHAR ref_number[MAX_PHB_NUM_LEN]; int cmp_res; USHORT file_id; TRACE_FUNCTION("pb_sim_number_cmp()"); MALLOC(buffer, sizeof(T_PHB_RECORD)); /* Store pointer to free the memory allocation. */ tmp_buffer = buffer; memset(buffer,0xFF,sizeof(T_PHB_RECORD)); db_info_field(db_handle, field_id, &info_field); /* Read record recno_1 from the database using db_read_record() */ db_read_record(db_handle, field_id, recno_1, 0, info_field.record_size, buffer); /* Read only number from the buffer. */ buffer += (info_field.record_size) - pb_sim_get_size_except_tag(field_id); entry_1.len = *(buffer++) - 1; entry_1.ton_npi = *buffer++; memset(entry_1.number, 0xFF, PHB_PACKED_NUM_LEN); memcpy( (char*)entry_1.number, (char*)buffer, entry_1.len ); buffer += 10; entry_1.cc_id = *buffer++; if (*buffer != 0xFF) /* check for extention records */ { file_id = pb_sim_get_ext_file_id(field_id); if (file_id != 0xFFFF) { ext_rcd_num = (UBYTE)*buffer; db_info_field(db_handle, file_id, &info_field); /* Set the buffer to starting location. */ buffer = tmp_buffer; memset(buffer, 0xFF, info_field.record_size); db_read_record(db_handle, file_id, ext_rcd_num, 0, info_field.record_size,buffer); pb_sim_read_ext(buffer, &entry_1); while(*(buffer + 12) NEQ 0xFF) { memset(buffer, 0xFF, info_field.record_size); db_read_record(db_handle, file_id, *(buffer + 12), 0, info_field.record_size,buffer); pb_sim_read_ext(buffer, &entry_1); } } } /* Set the buffer to starting location. */ buffer = tmp_buffer; memset(buffer, 0xFF, sizeof(T_PHB_RECORD)); /* Read record recno_2 from the database using db_read_record() */ db_read_record(db_handle, field_id, recno_2, 0, info_field.record_size, buffer); max_tag_len = info_field.record_size - pb_sim_get_size_except_tag(field_id); /* Read only number from the buffer. */ buffer += max_tag_len; entry_2.len = *(buffer++) - 1; entry_2.ton_npi = *buffer++; memset(entry_2.number, 0xFF, PHB_PACKED_NUM_LEN); memcpy( (char*)entry_2.number, (char*)buffer, entry_2.len ); buffer += 10; entry_2.cc_id = *buffer++; if (*buffer != 0xFF) /* check for extention records */ { if (file_id != 0xFFFF) { ext_rcd_num = (UBYTE)*buffer; /* Set the buffer to starting location. */ buffer = tmp_buffer; memset(buffer, 0xFF,info_field.record_size); db_read_record(db_handle, file_id, ext_rcd_num, 0, info_field.record_size,buffer); pb_sim_read_ext(buffer, &entry_2); while(*(buffer + 12) NEQ 0xFF) { memset(buffer, 0xFF,info_field.record_size); db_read_record(db_handle, file_id, *(buffer + 12), 0, info_field.record_size,buffer); pb_sim_read_ext(buffer, &entry_2); } } } cmhPHB_getAdrStr(cur_number, MAX_PHB_NUM_LEN - 1, entry_1.number, entry_1.len); cmhPHB_getAdrStr(ref_number, MAX_PHB_NUM_LEN - 1, entry_2.number, entry_2.len); /* Reverse the first number to compare number from right. */ pb_sim_revString(cur_number); /* Reverse the second number to compare number from right. */ pb_sim_revString(ref_number); cmp_res = strcmp((char *)cur_number, (char *)ref_number); MFREE(tmp_buffer); return cmp_res; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_read_ext | +--------------------------------------------------------------------+ PURPOSE : Reads extension records from the database and copies them to number. */ /* Extesion records will be stored as per 11.11. Bytes Description M/O Length -------------------------------------- 1 Record type M 1 byte 2 to 12 Extension data M 11 bytes 13 Identifier M 1 byte --------------------------------------*/ void pb_sim_read_ext(UBYTE *buffer, T_PHB_RECORD *entry) { UBYTE data_len; UBYTE data_type; UBYTE *data; TRACE_FUNCTION("pb_sim_read_ext()"); /* If this extension record is not empty, it is written in phonebook. */ data = buffer; data_type = *data; data_len = *(data+1); switch (data_type) { case 1: /* Called Party Subaddress */ { int sa_len = 0; while (sa_len<PHB_PACKED_NUM_LEN) /* get length of possible already stored subaddr if more than one EXT is used */ { if (entry->subaddr[sa_len] EQ 0xFF) break; else if ((entry->subaddr[sa_len] & 0xF0) EQ 0xF0) { sa_len++; break; } else sa_len++; } pb_sim_nibblecopy (entry->subaddr, sa_len, data + 2, data_len); } break; case 2: /* Additional data */ entry->len = pb_sim_nibblecopy (entry->number, entry->len, data + 2, data_len); break; default: /* unknown type */ break; } return; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_revString | +--------------------------------------------------------------------+ PURPOSE : Reverses a string within the same variable. */ void pb_sim_revString(char *str) { UBYTE i, j,str_len; char ch; TRACE_FUNCTION("pb_sim_revString()"); str_len = strlen(str); for(i = 0, j = str_len - 1;i < (str_len / 2); i++, j--) { ch = *(str + i); *(str + i) = *(str + j); *(str + j) = ch; } } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_search_alpha_func | +--------------------------------------------------------------------+ PURPOSE : Searches for a given alpha key in the database. */ int pb_sim_search_alpha_func(ULONG flags, const UBYTE *key, int db_handle, USHORT field_id, USHORT rec_num) { T_ACI_PB_TEXT *search_key; T_PHB_RECORD entry; UBYTE cmpLen = 0; T_PHB_TYPE phb_type; UBYTE cur_tag[PHB_MAX_TAG_LEN]; int cmp_res; TRACE_FUNCTION("pb_sim_search_alpha_func()"); /* Cast search key to appropriate data structure */ search_key = (T_ACI_PB_TEXT *)key; /* Get PHB type from field ID using PHB_ACI function. */ phb_type = pb_get_phb_type_from_ef(field_id); /* Read record from the database. */ pb_sim_read_record(phb_type, rec_num, &entry); pb_sim_cvt_alpha_for_cmp ( entry.tag, cur_tag, entry.tag_len ); cmpLen = search_key->len; if(flags EQ PHB_MATCH_PARTIAL) cmpLen = MINIMUM ( entry.tag_len, cmpLen); TRACE_EVENT_P1( "cmpLen=%d", cmpLen ); cmp_res = pb_sim_cmpString ( cur_tag, search_key->data, cmpLen ); return cmp_res; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_search_num_func | +--------------------------------------------------------------------+ PURPOSE : Searches for a given number key in the database. */ int pb_sim_search_num_func(ULONG flags, const UBYTE *key, int db_handle, USHORT field_id, USHORT rec_num) { T_PHB_RECORD entry; UBYTE cmpLen = 0; T_PHB_TYPE phb_type; CHAR cur_number[MAX_PHB_NUM_LEN]; CHAR rev_key[MAX_PHB_NUM_LEN]; int cmp_res; TRACE_FUNCTION("pb_sim_search_num_func()"); /* Get PHB type from field ID using PHB_ACI function. */ phb_type = pb_get_phb_type_from_ef(field_id); /* Read record from the database. */ if(pb_sim_read_record(phb_type, rec_num, &entry) NEQ PHB_OK) return -1; cmhPHB_getAdrStr(cur_number, MAX_PHB_NUM_LEN - 1, entry.number, entry.len); /* Reverse the first number to compare number from right. */ pb_sim_revString(cur_number); /* Reverse the second number to compare number from right. */ strcpy (rev_key, (const char*) key); pb_sim_revString(rev_key); cmpLen = strlen(rev_key); if(flags EQ PHB_MATCH_PARTIAL) cmpLen = MINIMUM(strlen(cur_number), cmpLen); TRACE_EVENT_P1("Number to be compared: %s", cur_number); TRACE_EVENT_P1("Number to be searched: %s", rev_key); cmp_res = pb_sim_cmpString((UBYTE*)cur_number, (UBYTE*)rev_key, 7); TRACE_EVENT_P1("Result of the comparison: %d", cmp_res); return cmp_res; } /* +--------------------------------------------------------------------+ | PROJECT: MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE: pb_sim_nibblecopy | +--------------------------------------------------------------------+ PURPOSE : Used to convert BCD nibbles to string. */ LOCAL int pb_sim_nibblecopy (UBYTE dest[], int destlen, UBYTE src[], int count) { int i; int nibble; int destnibble=destlen*2; TRACE_FUNCTION("pb_sim_nibblecopy()"); if (destnibble) { if ((dest[destlen-1] & 0xF0) == 0xF0) /* check if there is space in last nibble */ destnibble--; } for ( i=0; i<count*2; i++ ) { /* check if we access out of bounds */ if (destnibble/2 >= PHB_PACKED_NUM_LEN) return PHB_PACKED_NUM_LEN; /* get nibble */ if (i%2 == 0) nibble = src[i/2] & 0x0F; else nibble = (src[i/2] & 0xF0) >> 4; if (nibble == 0xF) /* end of number detected */ break; /* put nibble */ if (destnibble%2 == 0) { dest[destnibble/2] &= 0xF0; dest[destnibble/2] |= nibble; } else { dest[destnibble/2] &= 0x0F; dest[destnibble/2] |= nibble << 4; } destnibble++; } return destnibble/2 + destnibble%2; /* round up */ } /* +------------------------------------------------------------------------+ | PROJECT : MMI-Framework (8417) MODULE: PHB | | STATE : code ROUTINE : pb_sim_read_eeprom_ecc | +------------------------------------------------------------------------+ PURPOSE : Read EC number from EEPROM. */ LOCAL void pb_sim_read_eeprom_ecc (void) { EF_ECC efecc; UBYTE *data_ptr; UBYTE version; int rec_ctr; TRACE_FUNCTION("pb_sim_read_eeprom_ecc()"); /* Initialise ECC Phonebook Info. */ pbs_data.max_record[ECC] = MAX_ECC_RCD; pbs_data.used_record[ECC] = 0; if (pcm_ReadFile((UBYTE *)EF_ECC_ID, SIZE_EF_ECC, (UBYTE *)&efecc, &version) EQ DRV_OK) { { /* workaround when invalid data stored on PCM */ CHAR ecc_number[MAX_PHB_NUM_LEN]; int num_len; data_ptr = efecc.ecc1; for (rec_ctr=0; rec_ctr < pbs_data.max_record[ECC]; rec_ctr++) { if (*data_ptr NEQ 0xFF) { cmhPHB_getAdrStr (ecc_number, MAX_PHB_NUM_LEN - 1, data_ptr, ECC_NUM_LEN); for (num_len = 0; num_len < ECC_NUM_LEN; num_len++) { if (!isdigit (ecc_number[num_len])) { TRACE_EVENT_P2 ("[ERR] pb_read_eeprom_ecc(): invalid character found %c (%d)", ecc_number[num_len], rec_ctr); return; } } } data_ptr += ECC_NUM_LEN; } } /* workaround end */ data_ptr = &efecc.ecc1[0]; memset( phb_ecc_element,0, (pbs_data.max_record[ECC] * sizeof(T_PHB_ECC_RECORD)) ); for (rec_ctr=0; rec_ctr < pbs_data.max_record[ECC]; rec_ctr++) { if(*data_ptr NEQ 0xff) { phb_ecc_element[rec_ctr].phy_idx = rec_ctr + 1; memcpy(phb_ecc_element[rec_ctr].number, data_ptr, ECC_NUM_LEN); data_ptr += ECC_NUM_LEN; (pbs_data.used_record[ECC])++; } } } } /* +----------------------------------------------------------------------+ | PROJECT : MODULE : PHB | | STATE : code ROUTINE : pb_sim_prepare_ext_data | +----------------------------------------------------------------------+ PURPOSE : Prepare the data for the extention record. If NULL pointer is given for number and subaddress then the extention record will marked as unused */ /* Extesion records will be stored as per 11.11. Bytes Description M/O Length -------------------------------------- 1 Record type M 1 byte 2 to 12 Extension data M 11 bytes 13 Identifier M 1 byte --------------------------------------*/ LOCAL void pb_sim_prepare_ext_data(UBYTE *ext_data, int ext_count, UBYTE *number, UBYTE no_len, UBYTE *subaddr) { UBYTE *data_num = NULL; UBYTE *data_subadd = NULL; TRACE_FUNCTION("pb_sim_prepare_ext_data()"); if(number[10] NEQ 0xFF) data_num = number + ((ext_count + 1) * 10); data_subadd = subaddr + (ext_count * 11); memset(ext_data, 0xFF, sizeof(ext_data)); if ((data_num NEQ NULL) AND (*data_num NEQ 0xFF)) { /* Set record type to 2 which corresponds to Additional data. Record type as per 11.11 */ ext_data[0] = 2; ext_data[1] = no_len - ((ext_count + 1) * 10); memcpy (ext_data + 2, data_num, 10); } else if ((data_subadd NEQ NULL) AND (*data_subadd NEQ 0xFF)) { TRACE_EVENT ("SUBADDRESS EXTENTION"); /* Set record type to 1 which corresponds to Called Party Subaddress. Record type as per 11.11 */ ext_data[0] = 1; memcpy (ext_data + 1, data_subadd, 11); } } /* +----------------------------------------------------------------------+ | PROJECT : MODULE : PHB | | STATE : code ROUTINE : pb_sim_get_field_id | +----------------------------------------------------------------------+ PURPOSE : Returns field ID for the corresponding Phonebook type. */ LOCAL USHORT pb_sim_get_field_id (T_PHB_TYPE type) { USHORT field_id; TRACE_FUNCTION("pb_sim_get_field_id()"); /* Get Elementary file ID for the Phonebook type. */ switch(type) { case ADN: field_id = SIM_ADN; break; case LDN: field_id = SIM_OCI; break; case LRN: field_id = FFS_LRN; break; case LMN: field_id = FFS_LMN; break; case UPN: field_id = SIM_MSISDN; break; case FDN: field_id = SIM_FDN; break; case SDN: field_id = SIM_SDN; break; case BDN: field_id = SIM_BDN; break; default: TRACE_ERROR ("No such field"); field_id = 0; break; } return field_id; } /* +----------------------------------------------------------------------+ | PROJECT : MODULE : PHB | | STATE : code ROUTINE : pb_sim_get_ext_file | +----------------------------------------------------------------------+ PURPOSE : Returns field ID for the corresponding Phonebook type. */ LOCAL USHORT pb_sim_get_ext_file (T_PHB_TYPE type) { USHORT ext_file_id; TRACE_FUNCTION("pb_sim_get_ext_file()"); /* Get Extension Elementary file ID for the Phonebook type. */ switch(type) { case ADN: case UPN: ext_file_id = SIM_EXT1; break; case FDN: ext_file_id = SIM_EXT2; break; case SDN: ext_file_id = SIM_EXT3; break; case BDN: ext_file_id = SIM_EXT4; break; case LDN: ext_file_id = SIM_EXT5; break; case LRN: ext_file_id = FFS_EXT_LRN; break; case LMN: ext_file_id = FFS_EXT_LMN; break; default: ext_file_id = 0; /* Avoid lint warning */ break; } return ext_file_id; } /* +---------------------------------------------------------------------+ | PROJECT : MMI-Framework (8417) MODULE : PHB | | STATE : code ROUTINE : pb_sim_cvt_alpha_for_cmp | +---------------------------------------------------------------------+ PURPOSE : convert alpha to lower case when not unicode */ LOCAL void pb_sim_cvt_alpha_for_cmp ( UBYTE *src, UBYTE *dst, UBYTE len ) { int i; TRACE_FUNCTION("pb_sim_cvt_alpha_for_cmp()"); if (*src NEQ 0x80) /* 11.11 Annex B 0x80 is the UCS2 indicator */ { for ( i = 0; i < len; i++ ) dst[i] = (UBYTE)tolower((int)src[i]); } else { memcpy (dst, src, len); } } /* +----------------------------------------------------------------------+ | PROJECT : MODULE : PHB | | STATE : code ROUTINE : pb_sim_get_ext_file_id | +----------------------------------------------------------------------+ PURPOSE : Returns Extension field ID for the corresponding field ID of a Phonebook. */ LOCAL USHORT pb_sim_get_ext_file_id (USHORT field_id) { USHORT ext_file_id; TRACE_FUNCTION("pb_sim_get_ext_file_id()"); /* Get Extension Elementary file ID for the Phonebook type. */ switch(field_id) { case SIM_ADN: case SIM_LND: case SIM_MSISDN: ext_file_id = SIM_EXT1; break; case SIM_FDN: ext_file_id = SIM_EXT2; break; case SIM_SDN: ext_file_id = SIM_EXT3; break; case SIM_BDN: ext_file_id = SIM_EXT4; break; case SIM_OCI: ext_file_id = SIM_EXT5; break; case FFS_LRN: ext_file_id = FFS_EXT_LRN; break; case FFS_LMN: ext_file_id = FFS_EXT_LMN; break; default: ext_file_id = 0; /* Avoid lint warning */ break; } return ext_file_id; } /* +----------------------------------------------------------------------+ | PROJECT : MODULE : PHB | | STATE : code ROUTINE : pb_sim_find_free_record | +----------------------------------------------------------------------+ PURPOSE : Returns free record number for the Phonebook type. */ GLOBAL int pb_sim_find_free_record (T_PHB_TYPE type) { int db_result; unsigned i; USHORT field_id; TRACE_FUNCTION("pb_sim_find_free_record()"); switch (type) { case ECC: /* ECC not stored in DB, special handling */ for (i = 0; i < pbs_data.max_record[ECC]; i++) { if (phb_ecc_element[i].phy_idx EQ 0) return i + 1; } return 0; /* No free record found */ case LDN: case LRN: case LMN: return 1; /* For cyclic entries always the first */ default: /* Get Elementary file ID for the Phonebook type. */ field_id = pb_sim_get_field_id(type); db_result = db_find_free_record(pbs_data.db_handle, field_id); if (db_result <= 0) return 0; /* No free record */ return db_result; } } /* +-------------------------------------------------------------------------------+ | PROJECT : MMI-Framework (8417) MODULE : PHB | | STATE : code ROUTINE : pb_sim_get_size_except_tag | +-------------------------------------------------------------------------------+ PURPOSE : Returns size of data excluding length of tag (alpha identifier) */ USHORT pb_sim_get_size_except_tag (USHORT field_id) { TRACE_FUNCTION("pb_sim_get_size_except_tag()"); switch(field_id) { case SIM_ADN: case SIM_FDN: case SIM_BDN: case SIM_MSISDN: case SIM_SDN: return 14; /* 11.11 */ case FFS_LRN: case FFS_LMN: case SIM_OCI: return 27; /* Using EF_OCI, 31.102 4.2.34 */ //case SIM_ICI: // return 28; /* Using EF_ICI, 31.102 4.2.33 */ default: TRACE_ERROR("Invalid field ID passed !"); return 0; } } /* +--------------------------------------------------------------------+ | PROJECT : MMI-Framework (8417) MODULE : PHB | | STATE : code ROUTINE : pb_sim_cmpString | +--------------------------------------------------------------------+ PURPOSE : compare two strings. if s1 < s2 return value < 0 if s1 = s2 return value = 0 if s1 > s2 return value > 0 */ static int pb_sim_cmpString ( UBYTE *s1, UBYTE *s2, UBYTE len ) { int n = 0; /* TRACE_FUNCTION("pb_sim_cmpString()"); */ /* Called too often to trace */ if ((*s1 EQ 0x80) AND (*s2 NEQ 0x80) ) { s1++; len--; return pb_sim_cmp2Bytes(s1, s2, len, 1); } else if ((*s1 NEQ 0x80) AND (*s2 EQ 0x80) ) { s2++; len--; return pb_sim_cmp2Bytes(s1, s2, len, 2); } else { while (*s1 EQ *s2) { if (*s1 EQ 0xff) return 0; s1++; s2++; n++; if (n EQ len) return 0; } if ((*s1 > *s2) AND (*s1 NEQ 0xff)) return 1; return -1; } } /* +--------------------------------------------------------------------+ | PROJECT : MMI-Framework (8417) MODULE : PHB | | STATE : code ROUTINE : pb_sim_cmp2Bytes | +--------------------------------------------------------------------+ PURPOSE : compare two strings. if s1 < s2 return value < 0 if s1 = s2 return value = 0 if s1 > s2 return value > 0 flag = 1, s1 is unicode flag = 2, s2 is unicode */ LOCAL int pb_sim_cmp2Bytes(UBYTE *s1, UBYTE *s2, UBYTE len, UBYTE flag) { int n = 0; /* TRACE_FUNCTION("pb_sim_cmp2Bytes()"); */ if (flag EQ 1) { while ( (*s1 EQ 0x00 OR *s1 EQ 0xFF ) AND ( *(s1+1) EQ *s2) ) { if (*s1 EQ 0xff AND *(s1+1) EQ 0xFF) return 0; s1 += 2; s2++; n += 2; if (n >= len) return 0; } if ( ( *s1 > 0 AND *s1 NEQ 0xff ) OR ( !*s1 AND ( *(s1+1) > *s2 ) ) ) return 1; return -1; } if (flag EQ 2) { while ((*s2 EQ 0x00 OR *s2 EQ 0xFF) AND (*s1 EQ *(s2+1))) { if (*s2 EQ 0xff AND *(s2+1) EQ 0xFF) return 0; s1++; s2 += 2; n += 2; if (n >= len) return 0; } if ((*s2 > 0 AND *s2 NEQ 0xff) OR (!*s2 AND (*(s2+1) > *s1)) ) return -1; return 1; } return -1; } /* +--------------------------------------------------------------------+ | PROJECT : MMI-Framework (8417) MODULE : PHB | | STATE : code ROUTINE : pb_sim_update_extn_records | +--------------------------------------------------------------------+ PURPOSE : Update reference count for extension record and delete if record is not referenced at all. */ LOCAL T_PHB_RETURN pb_sim_update_extn_records(USHORT ext_field_id, USHORT rec_num, T_PHB_EXT_REF_TYPE ref_type) { BOOL delete_record = FALSE; int db_result; /* Depending on the Extension file update the corresponding array. */ if(ref_type EQ DECREMENT) { switch(ext_field_id) { case SIM_EXT1: ext1_ref_count[rec_num]--; if(ext1_ref_count[rec_num] EQ 0) delete_record = TRUE; break; case SIM_EXT2: ext2_ref_count[rec_num]--; if(ext2_ref_count[rec_num] EQ 0) delete_record = TRUE; break; case SIM_EXT3: ext3_ref_count[rec_num]--; if(ext3_ref_count[rec_num] EQ 0) delete_record = TRUE; break; case SIM_EXT4: ext4_ref_count[rec_num]--; if(ext4_ref_count[rec_num] EQ 0) delete_record = TRUE; break; case SIM_EXT5: ext5_ref_count[rec_num]--; if(ext5_ref_count[rec_num] EQ 0) delete_record = TRUE; break; case FFS_EXT_LRN: ext_lrn_ref_count[rec_num]--; if(ext_lrn_ref_count[rec_num] EQ 0) delete_record = TRUE; break; case FFS_EXT_LMN: ext_lmn_ref_count[rec_num]--; if(ext_lmn_ref_count[rec_num] EQ 0) delete_record = TRUE; break; default: return PHB_FAIL; } } if(ref_type EQ INCREMENT) { switch(ext_field_id) { case SIM_EXT1: ext1_ref_count[rec_num]++; break; case SIM_EXT2: ext2_ref_count[rec_num]++; break; case SIM_EXT3: ext3_ref_count[rec_num]++; break; case SIM_EXT4: ext4_ref_count[rec_num]++; break; case SIM_EXT5: ext5_ref_count[rec_num]++; break; case FFS_EXT_LRN: ext_lrn_ref_count[rec_num]++; break; case FFS_EXT_LMN: ext_lmn_ref_count[rec_num]++; break; default: return PHB_FAIL; } } /* Delete the extension record if it is not referenced. */ if(delete_record EQ TRUE) { db_result = db_delete_record(pbs_data.db_handle, ext_field_id, rec_num); if(db_result < DB_OK) return PHB_FAIL; } return PHB_OK; } /* +--------------------------------------------------------------------+ | PROJECT : MMI-Framework (8417) MODULE : PHB | | STATE : code ROUTINE : pb_sim_read_ext_record_for_delete | +--------------------------------------------------------------------+ PURPOSE : Read extension records and update the records. */ LOCAL T_PHB_RETURN pb_sim_read_ext_record_for_delete(T_PHB_TYPE type, USHORT field_id, USHORT db_recno) { USHORT ext_file_id; T_DB_INFO_FIELD info_field; UBYTE buffer[RDM_PHB_DATA_SIZE]; UBYTE data[SIM_MAX_RECORD_SIZE], *ptr; UBYTE max_tag_len; UBYTE ext_rcd_num; T_PHB_RECORD entry; TRACE_FUNCTION("pb_sim_read_ext_record_for_delete()"); /* Get Extension file for the Phonebook type. */ ext_file_id = pb_sim_get_ext_file(type); /* Read record from the database. */ if(db_info_field(pbs_data.db_handle, field_id, &info_field) NEQ DB_OK) return PHB_FAIL; if(db_read_record(pbs_data.db_handle, field_id, db_recno, 0, info_field.record_size, data) < DB_OK) return PHB_FAIL; /* Convert SIM data to the type T_PHB_RECORD. */ ptr = data; max_tag_len = MINIMUM ((info_field.record_size) - pb_sim_get_size_except_tag(field_id), PHB_MAX_TAG_LEN); ptr += (info_field.record_size) - pb_sim_get_size_except_tag(field_id); max_tag_len = (info_field.record_size) - pb_sim_get_size_except_tag(field_id); ++ptr; ++ptr; ptr += 10; ++ptr; if (*ptr NEQ 0xFF) /* check for extention records */ { ext_rcd_num =(UBYTE)*ptr; if(db_info_field(pbs_data.db_handle, ext_file_id, &info_field) NEQ DB_OK) return PHB_FAIL; /* Reset pointer to start location. */ ptr = data; memset(ptr, 0xFF, info_field.record_size); if(db_read_record(pbs_data.db_handle, ext_file_id, ext_rcd_num, 0, info_field.record_size, ptr) < DB_OK) return PHB_FAIL; if(pb_sim_update_extn_records(ext_file_id, ext_rcd_num, DECREMENT) EQ PHB_FAIL) return PHB_FAIL; pb_sim_read_ext(ptr, &entry); while(*(ptr + 12) NEQ 0xFF) /* check if a further EXT entry exists */ { memset(ptr, 0xFF, info_field.record_size); db_read_record(pbs_data.db_handle, ext_file_id, (USHORT)*(ptr+12), 0, info_field.record_size,ptr); if(pb_sim_update_extn_records(ext_file_id, (USHORT)*(ptr+12), DECREMENT) EQ PHB_FAIL) return PHB_FAIL; pb_sim_read_ext(ptr, &entry); } } return PHB_OK; } #endif /* #ifdef TI_PS_FFS_PHB */