From: Jessica Nilsson <jessica.j.nilsson(a)stericsson.com>
---
drivers/isimodem/phonebook.c | 1241 ++++++++++++++++++++++++++++++++++++++++-
1 files changed, 1210 insertions(+), 31 deletions(-)
diff --git a/drivers/isimodem/phonebook.c b/drivers/isimodem/phonebook.c
index 1f92d37..dfb76ed 100644
--- a/drivers/isimodem/phonebook.c
+++ b/drivers/isimodem/phonebook.c
@@ -3,6 +3,7 @@
* oFono - Open Source Telephony
*
* Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies).
+ * Copyright (C) ST-Ericsson SA 2011.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -36,16 +37,40 @@
#include <ofono/log.h>
#include <ofono/modem.h>
#include <ofono/phonebook.h>
+#include <ofono/sim.h>
#include "util.h"
#include "isimodem.h"
#include "isiutil.h"
#include "sim.h"
+#include "simutil.h"
#include "debug.h"
+#include "uicc.h"
-struct pb_data {
- GIsiClient *client;
-};
+/* File info parameters */
+#define FCP_TEMPLATE 0x62
+#define FCP_FILE_SIZE 0x80
+#define FCP_FILE_DESC 0x82
+#define FCP_FILE_ID 0x83
+#define FCP_FILE_LIFECYCLE 0x8A
+#define FCP_FILE_SECURITY_ARR 0x8B
+#define FCP_FILE_SECURITY_COMPACT 0x8C
+#define FCP_FILE_SECURITY_EXPANDED 0xAB
+
+#define UNUSED 0xFF
+
+#define EXT1_CP_SUBADDRESS 1
+#define EXT1_ADDITIONAL_DATA 2
+
+#define NAME_SIZE 64
+#define NUMBER_SIZE 256
+#define EMAIL_SIZE 128
+#define EXT_NUMBER_SIZE 24
+#define SNE_SIZE 64
+
+/* TON (Type Of Number) See TS 24.008 */
+#define TON_MASK 0x70
+#define TON_INTERNATIONAL 0x10
struct read_resp {
uint8_t service_type;
@@ -53,6 +78,82 @@ struct read_resp {
uint8_t data[];
};
+enum constructed_tag {
+ TYPE_1_TAG = 0xA8,
+ TYPE_2_TAG = 0xA9,
+ TYPE_3_TAG = 0xAA
+};
+
+enum file_type_tag {
+ TYPE_ADN = 0xC0,
+ TYPE_IAD = 0xC1,
+ TYPE_EXT1 = 0xC2,
+ TYPE_SNE = 0xC3,
+ TYPE_ANR = 0xC4,
+ TYPE_PBC = 0xC5,
+ TYPE_GPR = 0xC6,
+ TYPE_AAS = 0xC7,
+ TYPE_GAS = 0xC8,
+ TYPE_UID = 0xC9,
+ TYPE_EMAIL = 0xCA,
+ TYPE_CCP1 = 0xCB
+};
+
+struct pb_file_info {
+ int file_id;
+ uint8_t file_type;
+ uint8_t structure;
+ int file_length;
+ int record_length;
+ int record;
+ gboolean handled;
+};
+
+struct file_info {
+ int fileid;
+ int length;
+ int structure;
+ int record_length;
+ unsigned char access[3];
+};
+
+struct phonebook_entry {
+ int entry;
+ char *name;
+ char *number;
+ char *email;
+ char *anr;
+ char *sne;
+};
+
+struct pb_data {
+ GIsiClient *client;
+ GIsiClient *primary;
+ GIsiClient *secondary;
+ struct ofono_sim_driver *sim_func;
+ gint pb_entry;
+ struct pb_file_info pb_reference_file_info;
+ struct pb_file_info *extension_file_info;
+ uint8_t ext1_to_type;
+ uint8_t ext1_to_entry;
+};
+
+static GSList *pb_files;
+static GSList *pb_next;
+
+static GSList *phonebook_entry_start;
+static GSList *phonebook_entry_current;
+
+static void pb_reference_info_cb(const struct ofono_error *error,
+ int filelength,
+ enum ofono_sim_file_structure structure,
+ int recordlength,
+ const unsigned char access[3],
+ unsigned char file_status, void *data);
+static void pb_content_data_read(struct pb_data *pbd,
+ struct pb_file_info *file_info,
+ struct isi_cb_data *cbd);
+
static gboolean parse_adn(GIsiSubBlockIter *iter, uint16_t *location,
char **name, char **number)
{
@@ -194,6 +295,405 @@ error:
return success;
}
+static void handle_ext1(struct pb_data *pbd, const unsigned char *msg);
+
+static void handle_ext1(struct pb_data *pbd, const unsigned char *msg)
+{
+ uint8_t number_length = 0, i, next_extension_record;
+ static const char digit_to_utf8[] = "0123456789*#pwe\0";
+ struct pb_file_info *next_file = NULL;
+
+ char *ext_number = g_try_malloc0(EXT_NUMBER_SIZE);
+ if (ext_number != NULL) {
+ number_length = msg[1];
+ for (i = 0; i < number_length; i++) {
+ ext_number[2 * i] = digit_to_utf8[msg[2 + i] & 0x0f];
+ ext_number[2 * i + 1] =
+ digit_to_utf8[(msg[2 + i] >> 4) &
+ 0x0f];
+
+ }
+ }
+ next_extension_record = msg[number_length + 2];
+
+ DBG("Number extension %s number length %d extension_record %d",
+ ext_number,
+ number_length,
+ next_extension_record);
+
+ /* pb_entry is already incremented & g_slist_nth counts from 0 */
+ if (pbd->ext1_to_type == TYPE_ADN) {
+ GSList *list_entry = g_slist_nth(phonebook_entry_start,
+ pbd->ext1_to_entry -
+ 1);
+ DBG("Looking for ADN entry %d", pbd->ext1_to_entry);
+
+ if (list_entry != NULL) {
+ struct phonebook_entry *entry = list_entry->data;
+
+ if (entry != NULL)
+ strcat(entry->number, ext_number);
+ else if (pbd->ext1_to_type == TYPE_ANR) {
+ GSList *list_entry = g_slist_nth(
+ phonebook_entry_start,
+ pbd->ext1_to_entry - 1);
+ DBG("Looking for ANR entry %d",
+ pbd->ext1_to_entry);
+
+ if (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ if (entry != NULL)
+ strcat(entry->anr, ext_number);
+ }
+ }
+ g_free(ext_number);
+ /* Check if there is more extension data */
+ if (next_extension_record != UNUSED) {
+ next_file = g_try_new0(struct pb_file_info,
+ 1);
+
+ if (next_file != NULL) {
+ if (pbd->extension_file_info) {
+ memmove(next_file,
+ pbd->extension_file_info,
+ sizeof(struct pb_file_info));
+ } else {
+ next_file->file_type =
+ TYPE_EXT1;
+ next_file->file_id =
+ SIM_EFEXT1_FILEID;
+ }
+ next_file->record =
+ next_extension_record;
+ }
+ }
+ }
+ }
+}
+
+static struct pb_file_info *decode_read_response(
+ struct pb_file_info *file_info,
+ const unsigned char *msg,
+ size_t len,
+ struct ofono_phonebook *pb)
+{
+ char *name = NULL;
+ char *number = NULL;
+ char *email = NULL;
+ char *sne = NULL;
+ char *anr = NULL;
+
+ static const char digit_to_utf8[] = "0123456789*#pwe\0";
+
+ struct pb_file_info *next_file = NULL;
+ int type = file_info->file_type;
+ struct pb_data *pbd = ofono_phonebook_get_data(pb);
+
+ switch (type) {
+ case TYPE_ADN:{
+ const uint8_t name_length = len - 14;
+ const uint8_t number_start = name_length;
+ uint8_t number_length = 0;
+ uint8_t extension_record = UNUSED;
+ uint8_t i, prefix;
+ name = sim_string_to_utf8(msg, name_length);
+ /* Length contains also TON&NPI */
+ number_length = msg[number_start];
+
+ if ((number_length != UNUSED) && (number_length != 0)) {
+ number = g_try_malloc0(NUMBER_SIZE);
+ number_length--;
+
+ if (number) {
+ prefix = 0;
+
+ if ((msg[number_start + 1] & TON_MASK)
+ == TON_INTERNATIONAL) {
+ number[0] = '+';
+ prefix = 1;
+ }
+
+ for (i = 0; i < number_length; i++) {
+
+ number[2 * i + prefix] =
+ digit_to_utf8[msg
+ [number_start
+ + 2 +
+ i] & 0x0f];
+
+ number[2 * i + 1 + prefix] =
+ digit_to_utf8[(msg
+ [number_start
+ + 2 +
+ i] >> 4) &
+ 0x0f];
+ }
+ extension_record = msg[len - 1];
+ }
+ }
+ DBG("ADN name %s, number %s number \
+ length %d extension_record %d",
+ name, number, number_length, extension_record);
+
+ if (extension_record != UNUSED) {
+ next_file = g_try_new0(struct pb_file_info, 1);
+
+ if (next_file != NULL) {
+ if (pbd->extension_file_info) {
+ memmove(next_file,
+ pbd->
+ extension_file_info,
+ sizeof(struct
+ pb_file_info));
+ } else {
+ next_file->file_type =
+ TYPE_EXT1;
+ next_file->file_id =
+ SIM_EFEXT1_FILEID;
+ }
+
+ next_file->record = extension_record;
+ pbd->ext1_to_type = TYPE_ADN;
+ pbd->ext1_to_entry = pbd->pb_entry;
+ }
+ }
+
+ if (name || number) {
+ struct phonebook_entry *new_entry =
+ g_try_new0(struct phonebook_entry, 1);
+
+ if (new_entry != NULL) {
+ new_entry->name = name;
+ new_entry->number = number;
+
+ DBG("Creating PB entry %d with \
+ name %s and number %s",
+ pbd->pb_entry,
+ new_entry->name,
+ new_entry->number);
+
+ phonebook_entry_current =
+ g_slist_insert
+ (phonebook_entry_start,
+ new_entry,
+ pbd->pb_entry);
+
+ if (!phonebook_entry_start)
+ phonebook_entry_start =
+ phonebook_entry_current;
+
+ pbd->pb_entry++;
+ }
+ }
+ break;
+ }
+ case TYPE_SNE:{
+ uint8_t sne_end = 0;
+ const uint8_t sne_length = len - 2;
+ uint8_t i = 0;
+ uint8_t phonebook_entry_nbr = msg[len - 1];
+
+ DBG("SNE");
+ for (i = 0; (msg[i] != UNUSED) && (i < sne_length);
+ i++)
+ ;
+
+ sne_end = i;
+ sne = sim_string_to_utf8(msg, sne_length);
+
+ if (sne != NULL) {
+ /*
+ * GSlist nth counts from 0,
+ * PB entries from 1
+ */
+ GSList *list_entry =
+ g_slist_nth(phonebook_entry_start,
+ phonebook_entry_nbr -
+ 1);
+
+ DBG("SNE \'%s\' to PB entry %d", sne,
+ phonebook_entry_nbr);
+
+ if (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ if (entry != NULL) {
+ /*
+ * If one already exists,
+ * delete it
+ */
+ if (entry->sne != NULL)
+ g_free(entry->sne);
+
+ DBG("Adding SNE to entry %d,\
+ name %s",
+ phonebook_entry_nbr,
+ entry->name);
+
+ entry->sne = sne;
+ } else {
+ g_free(sne);
+ }
+ }
+ }
+
+ break;
+ }
+ case TYPE_ANR:{
+ uint8_t number_length = 0;
+ uint8_t extension_record = UNUSED;
+ uint8_t aas_record = UNUSED;
+ uint8_t i, prefix;
+ uint8_t phonebook_entry_nbr = msg[len - 1];
+ GSList *list_entry;
+
+ DBG("ANR");
+ if (msg[0] == UNUSED)
+ break;
+
+ aas_record = msg[0];
+ /* Length contains also TON&NPI */
+ number_length = msg[1];
+
+ if (number_length) {
+ number_length--;
+ anr = g_try_malloc0(NUMBER_SIZE);
+
+ if (anr != NULL) {
+ prefix = 0;
+
+ if ((msg[2] & TON_MASK) ==
+ TON_INTERNATIONAL) {
+ anr[0] = '+';
+ prefix = 1;
+ }
+
+ for (i = 0; i < number_length; i++) {
+ anr[2 * i + prefix] =
+ digit_to_utf8[
+ msg[3 + i] &
+ 0x0f];
+ anr[2 * i + 1 + prefix] =
+ digit_to_utf8[
+ (msg[3 + i] >>
+ 4) & 0x0f];
+ }
+
+ extension_record = msg[len - 3];
+ }
+ }
+
+ DBG("ANR to entry %d number %s number length %d\
+ extension_record %d aas %d",
+ phonebook_entry_nbr, anr, number_length,
+ extension_record, aas_record);
+
+ if (extension_record != UNUSED) {
+ next_file = g_try_new0(struct pb_file_info, 1);
+
+ if (next_file != NULL) {
+ if (pbd->extension_file_info) {
+ memmove(next_file,
+ pbd->
+ extension_file_info,
+ sizeof(struct
+ pb_file_info));
+ } else {
+ next_file->file_type =
+ TYPE_EXT1;
+ next_file->file_id =
+ SIM_EFEXT1_FILEID;
+ }
+
+ next_file->record = extension_record;
+ pbd->ext1_to_type = TYPE_ANR;
+ pbd->ext1_to_entry =
+ phonebook_entry_nbr;
+ }
+ }
+
+ /* GSlist nth counts from 0, PB entries from 1 */
+ list_entry =
+ g_slist_nth(phonebook_entry_start,
+ phonebook_entry_nbr - 1);
+
+ if (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ if (entry != NULL) {
+ /* if one already exists, delete it */
+ if (entry->anr)
+ g_free(entry->anr);
+
+ DBG("Adding ANR to entry %d, name %s",
+ phonebook_entry_nbr,
+ entry->name);
+ entry->anr = anr;
+ }
+ } else {
+ g_free(anr);
+ }
+
+ break;
+ }
+ case TYPE_AAS:{
+ DBG("AAS");
+ break;
+ }
+ case TYPE_EMAIL:{
+ uint8_t phonebook_entry_nbr = msg[len - 1];
+ email = sim_string_to_utf8(msg, len - 2);
+
+ /* GSlist nth counts from 0, PB entries from 1 */
+ if (email != NULL) {
+ GSList *list_entry =
+ g_slist_nth(phonebook_entry_start,
+ phonebook_entry_nbr - 1);
+
+ DBG("Email \'%s\' to PB entry %d", email,
+ phonebook_entry_nbr);
+ if (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ /* if one already exists, delete it */
+ if (entry != NULL) {
+ if (entry->email)
+ g_free(entry->email);
+
+ DBG("Adding email to entry %d,\
+ name %s",
+ phonebook_entry_nbr,
+ entry->name);
+
+ entry->email = email;
+ }
+ } else {
+ g_free(email);
+ }
+ }
+
+ break;
+ }
+ case TYPE_EXT1:{
+ if (msg[0] == EXT1_ADDITIONAL_DATA)
+ handle_ext1(pbd, msg);
+ break;
+
+ }
+ default:{
+ DBG("Skipping type %02X", type);
+ break;
+ }
+ }
+
+ return next_file;
+}
+
static void read_next_entry(GIsiClient *client, uint16_t location,
GIsiNotifyFunc notify, void *data)
{
@@ -254,50 +754,711 @@ static void read_resp_cb(const GIsiMessage *msg, void *data)
g_free(cbd);
}
+struct pb_file_info *extension_file_info;
+
+static void pb_adn_sim_data_cb(const struct ofono_error *error,
+ const unsigned char *sdata,
+ int length, void *data)
+{
+ struct isi_cb_data *cbd_outer = data;
+ struct isi_cb_data *cbd = NULL;
+ struct pb_file_info *file_info;
+ struct ofono_phonebook *pb;
+ ofono_phonebook_cb_t cb;
+ struct pb_data *pbd;
+
+ if (cbd_outer == NULL)
+ goto out;
+
+ file_info = cbd_outer->user;
+ cbd = cbd_outer->data;
+
+ if (cbd == NULL)
+ goto out;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (extension_file_info != NULL)
+ file_info =
+ decode_read_response(extension_file_info, sdata,
+ length, pb);
+ else
+ file_info = decode_read_response(file_info, sdata, length, pb);
+
+ if (file_info != NULL) {
+ DBG("Reading extension file %04X, record %d",
+ file_info->file_id, file_info->record);
+ pbd->sim_func->read_file_linear(get_sim(), file_info->file_id,
+ file_info->record,
+ file_info->record_length,
+ pb_adn_sim_data_cb, cbd_outer);
+
+ /* Delete if there is a previous one */
+ g_free(extension_file_info);
+ extension_file_info = file_info;
+ return;
+ } else {
+ g_free(extension_file_info);
+ extension_file_info = NULL;
+ file_info = cbd_outer->user;
+
+ if (file_info->record <
+ (file_info->file_length / file_info->record_length)) {
+
+ file_info->record++;
+ DBG("Same file, next record %d", file_info->record);
+ pbd->sim_func->read_file_linear(get_sim(),
+ file_info->file_id,
+ file_info->record,
+ file_info->
+ record_length,
+ pb_adn_sim_data_cb,
+ cbd_outer);
+ } else {
+ GSList *list_entry =
+ g_slist_nth(phonebook_entry_start, 0);
+ DBG("All data requested, start vCard creation");
+ g_free(file_info);
+
+ while (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ if (entry != NULL) {
+ DBG("vCard:\nname=%s\nnumber=%s\n\
+ email=%s\nanr=%s\nsne=%s",
+ entry->name, entry->number,
+ entry->email, entry->anr,
+ entry->sne);
+
+ ofono_phonebook_entry(pb, -1,
+ entry->number,
+ -1,
+ entry->name,
+ -1,
+ NULL,
+ entry->anr, -1,
+ entry->sne,
+ entry->email,
+ NULL, NULL);
+ g_free(entry->number);
+ g_free(entry->name);
+ g_free(entry->anr);
+ g_free(entry->sne);
+ g_free(entry->email);
+ g_free(entry);
+ }
+
+ list_entry = g_slist_next(list_entry);
+ }
+
+ g_slist_free(phonebook_entry_start);
+ g_slist_free(pb_files);
+ g_free(cbd_outer);
+ DBG("Finally all PB data read");
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ goto out;
+ }
+ }
+
+ return;
+out:
+ g_free(cbd);
+}
+
+static void pb_adn_sim_info_cb(const struct ofono_error *error,
+ int filelength,
+ enum ofono_sim_file_structure structure,
+ int recordlength,
+ const unsigned char access[3],
+ unsigned char file_status, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_phonebook *pb = cbd->user;
+ ofono_phonebook_cb_t cb = cbd->cb;
+ struct pb_data *pbd = ofono_phonebook_get_data(pb);
+ struct pb_file_info *file_info = NULL;
+ struct isi_cb_data *cbd_outer;
+ int records = 0;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+ file_info = NULL;
+
+ if (pbd || error->type != OFONO_ERROR_TYPE_NO_ERROR ||
+ structure != OFONO_SIM_FILE_STRUCTURE_FIXED ||
+ pbd->sim_func->read_file_linear == NULL)
+ goto error;
+
+ records = filelength / recordlength;
+
+ if (records == 0)
+ goto error;
+
+ file_info = g_try_new0(struct pb_file_info, 1);
+
+ if (file_info == NULL)
+ goto error;
+
+ file_info->file_id = SIM_EFADN_FILEID;
+ file_info->file_type = TYPE_ADN;
+ file_info->structure = structure;
+ file_info->file_length = filelength;
+ file_info->record_length = recordlength;
+ file_info->record = 1;
+ /* Regenerate cbd (include file_info) */
+ cbd_outer = isi_cb_data_new(file_info, cb, cbd);
+ pbd->sim_func->read_file_linear(get_sim(),
+ file_info->file_id,
+ file_info->record,
+ file_info->record_length,
+ pb_adn_sim_data_cb, cbd_outer);
+ return;
+error:
+
+ if (cbd != NULL)
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+ g_free(cbd);
+}
+
+static gboolean is_reading_required(uint8_t file_type)
+{
+ switch (file_type) {
+ case TYPE_ADN:
+ case TYPE_EMAIL:
+ case TYPE_SNE:
+ case TYPE_ANR:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static void pb_content_data_cb(const struct ofono_error *error,
+ const unsigned char *sdata,
+ int length, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_phonebook *pb;
+ ofono_phonebook_cb_t cb;
+ struct pb_data *pbd;
+ struct pb_file_info *file_info = NULL;
+
+ if (cbd == NULL)
+ goto out;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (extension_file_info != NULL)
+ file_info = decode_read_response(extension_file_info, sdata,
+ length, pb);
+ else
+ file_info =
+ decode_read_response(pb_next->data, sdata, length, pb);
+
+ if (file_info != NULL) {
+ DBG("Reading extension file %04X, record %d, structure %d",
+ file_info->file_id, file_info->record,
+ file_info->structure);
+ pb_content_data_read(pbd, file_info, cbd);
+ /* Delete if there is a previous one */
+ g_free(extension_file_info);
+ extension_file_info = file_info;
+ return;
+ } else {
+ g_free(extension_file_info);
+ extension_file_info = NULL;
+ file_info = pb_next->data;
+
+ if (((file_info->structure ==
+ OFONO_SIM_FILE_STRUCTURE_FIXED) ||
+ (file_info->structure ==
+ OFONO_SIM_FILE_STRUCTURE_CYCLIC))
+ && (file_info->record <
+ (file_info->file_length / file_info->record_length))) {
+
+ file_info->record++;
+ DBG("Same file, next record %d", file_info->record);
+ } else {
+ g_free(file_info);
+ pb_next = g_slist_next(pb_next);
+ DBG("Next file in list");
+
+ if (pb_next != NULL) {
+ file_info = pb_next->data;
+
+ while ((pb_next != NULL) &&
+ (!is_reading_required(
+ file_info->file_type))) {
+ DBG("Skipping file type %02X",
+ file_info->file_type);
+ g_free(file_info);
+ pb_next = g_slist_next(pb_next);
+
+ if (pb_next)
+ file_info = pb_next->data;
+ }
+ }
+
+ if (pb_next == NULL) {
+ GSList *list_entry =
+ g_slist_nth(phonebook_entry_start, 0);
+
+ DBG("All data requested, start vCard creation");
+ while (list_entry != NULL) {
+ struct phonebook_entry *entry =
+ list_entry->data;
+
+ if (entry != NULL) {
+ DBG("vCard:\nname=%s\n \
+ number=%s\nemail=%s\n \
+ anr=%s\nsne=%s",
+ entry->name,
+ entry->number,
+ entry->email,
+ entry->anr,
+ entry->sne);
+
+ ofono_phonebook_entry(pb, -1,
+ entry->number,
+ -1,
+ entry->name,
+ -1,
+ NULL,
+ entry->anr,
+ -1,
+ entry->sne,
+ entry->email,
+ NULL,
+ NULL);
+
+ g_free(entry->number);
+ g_free(entry->name);
+ g_free(entry->anr);
+ g_free(entry->sne);
+ g_free(entry->email);
+ g_free(entry);
+ }
+
+ list_entry = g_slist_next(list_entry);
+ }
+
+ g_slist_free(phonebook_entry_start);
+ g_slist_free(pb_files);
+ DBG("Finally all PB data read");
+ CALLBACK_WITH_SUCCESS(cb, cbd->data);
+ goto out;
+ }
+
+ file_info = pb_next->data;
+ }
+ }
+
+ pb_content_data_read(pbd, file_info, cbd);
+ return;
+out:
+ g_free(cbd);
+}
+
+static void pb_content_data_read(struct pb_data *pbd,
+ struct pb_file_info *file_info,
+ struct isi_cb_data *cbd)
+{
+ ofono_phonebook_cb_t cb;
+
+ if (pbd == NULL || file_info == NULL || cbd == NULL)
+ return;
+
+ cb = cbd->cb;
+ DBG("Reading content of file type=%02X, file ID=%04X, structure=%d",
+ file_info->file_type, file_info->file_id, file_info->structure);
+
+ switch (file_info->structure) {
+ case OFONO_SIM_FILE_STRUCTURE_FIXED:
+
+ if (pbd->sim_func->read_file_linear == NULL)
+ goto error;
+
+ pbd->sim_func->read_file_linear(get_sim(), file_info->file_id,
+ file_info->record,
+ file_info->record_length,
+ pb_content_data_cb, cbd);
+ break;
+ case OFONO_SIM_FILE_STRUCTURE_CYCLIC:
+
+ if (pbd->sim_func->read_file_cyclic == NULL)
+ goto error;
+
+ pbd->sim_func->read_file_cyclic(get_sim(), file_info->file_id,
+ file_info->record,
+ file_info->record_length,
+ pb_content_data_cb, cbd);
+ break;
+ case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT:
+
+ if (pbd->sim_func->read_file_transparent == NULL)
+ goto error;
+
+ pbd->sim_func->read_file_transparent(get_sim(),
+ file_info->file_id, 0,
+ file_info->file_length,
+ pb_content_data_cb,
+ cbd);
+ break;
+ }
+
+ return;
+error:
+ if (cbd != NULL)
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+}
+
+static void pb_content_info_cb(const struct ofono_error *error,
+ int filelength,
+ enum ofono_sim_file_structure structure,
+ int recordlength,
+ const unsigned char access[3],
+ unsigned char file_status, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_phonebook *pb;
+ ofono_phonebook_cb_t cb;
+ struct pb_data *pbd;
+ struct pb_file_info *file_info = NULL;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (pbd == NULL)
+ goto error;
+
+ file_info = pb_next->data;
+
+ if (file_info == NULL)
+ goto error;
+
+ file_info->structure = structure;
+ file_info->file_length = filelength;
+ file_info->record_length = recordlength;
+ file_info->record = 1;
+
+ DBG("File type=%02X, File ID=%04X, Struct=%d, File len=%d, Rec len=%d",
+ file_info->file_type, file_info->file_id, file_info->structure,
+ file_info->file_length, file_info->record_length);
+
+ if (file_info->file_type == TYPE_EXT1)
+ /* Save for quick access */
+ pbd->extension_file_info = file_info;
+
+ pb_next = g_slist_next(pb_next);
+
+ if (pb_next == NULL) {
+ DBG("All info requested, start content reading");
+
+ /* Re-start from beginning */
+ pb_next = g_slist_nth(pb_files, 0);
+ file_info = pb_next->data;
+
+ DBG("Calling pb_content_data_read pb=%p, list=%p, type=%02X",
+ cbd->user, pb_next, file_info->file_type);
+
+ pb_content_data_read(pbd, file_info, cbd);
+ return;
+ }
+
+ file_info = pb_next->data;
+
+ DBG("Reading next content info %04X", file_info->file_id);
+ pbd->sim_func->read_file_info(get_sim(), file_info->file_id,
+ pb_content_info_cb, cbd);
+ return;
+error:
+
+ if (cbd != NULL) {
+ DBG("Error cbd=%p, pbd=%p, file_info=%p", cbd, pbd, file_info);
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+ }
+
+ g_free(cbd);
+}
+
+static void pb_reference_data_cb(const struct ofono_error *error,
+ const unsigned char *sdata,
+ int length, void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_phonebook *pb;
+ ofono_phonebook_cb_t cb;
+ struct pb_data *pbd;
+ const unsigned char *ptr = sdata;
+ int typelen = 0;
+ int i = 0;
+ int file_id = 0;
+ gboolean finished = FALSE;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+
+ if (cb == NULL || pb == NULL)
+ goto out;
+
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (pbd == NULL)
+ goto error;
+
+ while ((ptr < sdata + length) && (finished == FALSE)) {
+ switch (*ptr) {
+ case TYPE_1_TAG:
+ case TYPE_2_TAG:
+ case TYPE_3_TAG:
+ typelen = *(ptr + 1);
+ DBG("File type=%02X, len=%d", *ptr, typelen);
+ ptr += 2;
+ i = 0;
+
+ while (i < typelen) {
+ struct pb_file_info *file_info =
+ g_try_new0(struct pb_file_info, 1);
+ file_id = (ptr[i + 2] << 8) + ptr[i + 3];
+
+ DBG("creating file info for File type=%02X,\
+ File ID=%04X",
+ ptr[i],
+ file_id);
+
+ if (file_info == NULL)
+ goto error;
+
+ file_info->file_type = ptr[i];
+ file_info->file_id = file_id;
+ pb_files =
+ g_slist_append(pb_files,
+ (void *)file_info);
+ i += ptr[i + 1] + 2;
+ }
+
+ ptr += typelen;
+ break;
+ default:
+ DBG("All handled %02x", *ptr);
+ finished = TRUE;
+ break;
+ }
+ }
+
+ if (pbd->pb_reference_file_info.record <
+ (pbd->pb_reference_file_info.file_length /
+ pbd->pb_reference_file_info.record_length)) {
+ pbd->pb_reference_file_info.record++;
+ DBG("Next EFpbr record %d", pbd->pb_reference_file_info.record);
+ pbd->sim_func->read_file_linear(get_sim(),
+ pbd->pb_reference_file_info.
+ file_id,
+ pbd->pb_reference_file_info.
+ record,
+ pbd->pb_reference_file_info.
+ record_length,
+ pb_reference_data_cb, cbd);
+ } else {
+ struct pb_file_info *file_info;
+ DBG("All EFpbr records read");
+ pb_next = g_slist_nth(pb_files, 0);
+
+ if (pb_next == NULL)
+ goto error;
+
+ file_info = pb_next->data;
+
+ if ((file_info == NULL) || !pbd->sim_func)
+ goto error;
+
+ pbd->sim_func->read_file_info(get_sim(), file_info->file_id,
+ pb_content_info_cb, cbd);
+ }
+
+ return;
+error:
+ if (cbd != NULL)
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+out:
+ g_free(cbd);
+}
+
+static void pb_reference_info_cb(const struct ofono_error *error,
+ int filelength,
+ enum ofono_sim_file_structure structure,
+ int recordlength,
+ const unsigned char access[3],
+ unsigned char file_status,
+ void *data)
+{
+ struct isi_cb_data *cbd = data;
+ struct ofono_phonebook *pb;
+ ofono_phonebook_cb_t cb;
+ struct pb_data *pbd;
+ int records = 0;
+
+ if (cbd == NULL)
+ goto error;
+
+ pb = cbd->user;
+ cb = cbd->cb;
+ pbd = ofono_phonebook_get_data(pb);
+
+ if (pbd == NULL)
+ goto error;
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR)
+ goto error;
+
+ if (structure != OFONO_SIM_FILE_STRUCTURE_FIXED)
+ goto error;
+
+ if (pbd->sim_func->read_file_linear == NULL)
+ goto error;
+
+ records = filelength / recordlength;
+
+ if (records == 0)
+ goto error;
+
+ DBG("EFpbr size %d, record length %d, records %d",
+ filelength, recordlength, records);
+ pbd->pb_reference_file_info.file_id = SIM_EFPBR_FILEID;
+ pbd->pb_reference_file_info.file_length = filelength;
+ pbd->pb_reference_file_info.record_length = recordlength;
+ pbd->pb_reference_file_info.record = 1; /* Current record, not amount */
+ pbd->pb_reference_file_info.structure = OFONO_SIM_FILE_STRUCTURE_FIXED;
+ pbd->sim_func->read_file_linear(get_sim(), SIM_EFPBR_FILEID,
+ 1, recordlength,
+ pb_reference_data_cb, cbd);
+ return;
+error:
+
+ if ((cb != NULL) && (cbd != NULL))
+ CALLBACK_WITH_FAILURE(cb, cbd->data);
+
+ g_free(cbd);
+}
+
static void isi_export_entries(struct ofono_phonebook *pb, const char *storage,
ofono_phonebook_cb_t cb, void *data)
{
struct pb_data *pbd = ofono_phonebook_get_data(pb);
struct isi_cb_data *cbd = isi_cb_data_new(pb, cb, data);
- const uint8_t msg[] = {
- SIM_PB_REQ_SIM_PB_READ,
- SIM_PB_READ,
- 2, /* number of subblocks */
- 0, SIM_PB_LOCATION, /* subblock id */
- 0, 8, /* subblock size */
- 0, SIM_PB_ADN,
- 0xFF, 0xFF, /* read first entry in pb */
- 0, SIM_PB_INFO_REQUEST, /* subblock id */
- 0, 16, /* subblock size */
- 4, /* number of tags */
- 0, /* filler */
- 0, SIM_PB_ADN, /* tags */
- 0, SIM_PB_SNE,
- 0, SIM_PB_ANR,
- 0, SIM_PB_EMAIL,
- 0, 0 /* filler */
- };
- size_t len = sizeof(msg);
- if (cbd == NULL || pbd == NULL || strcmp(storage, "SM") != 0)
+ if (cbd == NULL || pbd == NULL)
goto error;
- if (g_isi_client_send(pbd->client, msg, len, read_resp_cb, cbd, NULL))
- return;
-
+ if (g_isi_client_resource(pbd->client) == PN_UICC) {
+ pbd->pb_entry = 1;
+ pb_files = NULL;
+ pb_next = NULL;
+ phonebook_entry_current = NULL;
+ phonebook_entry_start = NULL;
+
+ switch (get_app_type()) {
+ case UICC_APPL_TYPE_ICC_SIM:
+ DBG("SIM application");
+ pbd->sim_func->read_file_info(get_sim(),
+ SIM_EFADN_FILEID,
+ pb_adn_sim_info_cb,
+ cbd);
+ break;
+ case UICC_APPL_TYPE_UICC_USIM:
+ DBG("USIM application");
+ pbd->sim_func->read_file_info(get_sim(),
+ SIM_EFPBR_FILEID,
+ pb_reference_info_cb,
+ cbd);
+ break;
+ default:
+ DBG("UICC application type not unknown or supported");
+ goto error;
+ break;
+ }
+ } else {
+
+ const uint8_t msg[] = {
+ SIM_PB_REQ_SIM_PB_READ,
+ SIM_PB_READ,
+ 2, /* number of subblocks */
+ 0, SIM_PB_LOCATION, /* subblock id */
+ 0, 8, /* subblock size */
+ 0, SIM_PB_ADN,
+ 0xFF, 0xFF, /* read first entry in pb */
+ 0, SIM_PB_INFO_REQUEST, /* subblock id */
+ 0, 16, /* subblock size */
+ 4, /* number of tags */
+ 0, /* filler */
+ 0, SIM_PB_ADN, /* tags */
+ 0, SIM_PB_SNE,
+ 0, SIM_PB_ANR,
+ 0, SIM_PB_EMAIL,
+ 0, 0 /* filler */
+ };
+ size_t len = sizeof(msg);
+
+ if (strcmp(storage, "SM") != 0)
+ goto error;
+
+ if (g_isi_client_send(pbd->client, msg, len, read_resp_cb,
+ cbd, NULL))
+ return;
+ }
+ return;
error:
CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
}
-static void reachable_cb(const GIsiMessage *msg, void *data)
+static void primary_reachable_cb(const GIsiMessage *msg, void *data)
{
struct ofono_phonebook *pb = data;
+ struct pb_data *pd = ofono_phonebook_get_data(pb);
if (g_isi_msg_error(msg) < 0)
return;
ISI_VERSION_DBG(msg);
+ pd->client = pd->primary;
+
+ g_isi_client_destroy(pd->secondary);
+
+ ofono_phonebook_register(pb);
+}
+
+static void secondary_reachable_cb(const GIsiMessage *msg, void *data)
+{
+ struct ofono_phonebook *pb = data;
+ struct pb_data *pd = ofono_phonebook_get_data(pb);
+
+ if (g_isi_msg_error(msg) < 0)
+ return;
+
+ ISI_VERSION_DBG(msg);
+
+ pd->client = pd->secondary;
+
+ g_isi_client_destroy(pd->primary);
ofono_phonebook_register(pb);
}
@@ -312,15 +1473,25 @@ static int isi_phonebook_probe(struct ofono_phonebook *pb, unsigned
int vendor,
if (data == NULL)
return -ENOMEM;
- data->client = g_isi_client_create(modem, PN_SIM);
- if (data->client == NULL) {
+ data->primary = get_pn_uicc_client(modem, PN_UICC);
+ if (data->primary == NULL) {
+ g_free(data);
+ return -ENOMEM;
+ }
+
+ data->sim_func = get_sim_driver_func();
+
+ data->secondary = g_isi_client_create(modem, PN_SIM);
+ if (data->secondary == NULL) {
+ g_isi_client_destroy(data->primary);
g_free(data);
return -ENOMEM;
}
ofono_phonebook_set_data(pb, data);
- g_isi_client_verify(data->client, reachable_cb, pb, NULL);
+ g_isi_client_verify(data->primary, primary_reachable_cb, pb, NULL);
+ g_isi_client_verify(data->secondary, secondary_reachable_cb, pb, NULL);
return 0;
}
@@ -329,12 +1500,20 @@ static void isi_phonebook_remove(struct ofono_phonebook *pb)
{
struct pb_data *data = ofono_phonebook_get_data(pb);
+ pb_files = NULL;
+ pb_next = NULL;
+ phonebook_entry_start = NULL;
+ phonebook_entry_current = NULL;
+
ofono_phonebook_set_data(pb, NULL);
if (data == NULL)
return;
+ if (g_isi_client_resource(data->client) == PN_UICC)
+ pn_uicc_client_destroy(data->client);
+ else
+ g_isi_client_destroy(data->client);
- g_isi_client_destroy(data->client);
g_free(data);
}
--
1.7.3.5