From 541682f89d110684e404b1c3f1666d6db4862471 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Fri, 10 Jul 2009 14:34:24 -0500 Subject: [PATCH] Add sim file reading / writing utilities --- src/sim.c | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/sim.h | 23 +++++-- 2 files changed, 204 insertions(+), 4 deletions(-) diff --git a/src/sim.c b/src/sim.c index aea17b35..471a28c3 100644 --- a/src/sim.c +++ b/src/sim.c @@ -42,6 +42,19 @@ #define SIM_MANAGER_INTERFACE "org.ofono.SimManager" +static gboolean sim_op_next(gpointer user_data); +static gboolean sim_op_retrieve_next(gpointer user); + +struct sim_file_op { + int id; + enum ofono_sim_file_structure structure; + int length; + int record_length; + int current; + ofono_sim_file_read_cb_t cb; + void *userdata; +}; + struct sim_manager_data { struct ofono_sim_ops *ops; int flags; @@ -50,6 +63,7 @@ struct sim_manager_data { GSList *own_numbers; GSList *ready_notify; gboolean ready; + GQueue *simop_q; int dcbyte; @@ -97,6 +111,11 @@ struct pnn_operator { char *shortname; }; +static void sim_file_op_free(struct sim_file_op *node) +{ + g_free(node); +} + static struct sim_manager_data *sim_manager_create() { return g_try_new0(struct sim_manager_data, 1); @@ -119,6 +138,12 @@ static void sim_manager_destroy(gpointer userdata) data->own_numbers = NULL; } + if (data->simop_q) { + g_queue_foreach(data->simop_q, (GFunc)sim_file_op_free, NULL); + g_queue_free(data->simop_q); + data->simop_q = NULL; + } + if (data->spdi) { g_slist_foreach(data->spdi, (GFunc)g_free, NULL); g_slist_free(data->spdi); @@ -761,6 +786,166 @@ static gboolean sim_retrieve_pnn(void *user_data) return FALSE; } +static void sim_op_error(struct ofono_modem *modem) +{ + struct sim_manager_data *sim = modem->sim_manager; + struct sim_file_op *op = g_queue_pop_head(sim->simop_q); + + op->cb(modem, 0, 0, 0, 0, 0, 0, op->userdata); + + sim_file_op_free(op); + + if (g_queue_get_length(sim->simop_q) > 0) + g_timeout_add(0, sim_op_next, modem); +} + +static void sim_op_retrieve_cb(const struct ofono_error *error, + const unsigned char *data, int len, void *user) +{ + struct ofono_modem *modem = user; + struct sim_manager_data *sim = modem->sim_manager; + struct sim_file_op *op = g_queue_peek_head(sim->simop_q); + int total = op->length / op->record_length; + + if (error->type == OFONO_ERROR_TYPE_NO_ERROR) + op->cb(modem, 1, op->structure, op->length, op->current, + data, op->record_length, op->userdata); + + if (op->current == total) { + op = g_queue_pop_head(sim->simop_q); + + sim_file_op_free(op); + + if (g_queue_get_length(sim->simop_q) > 0) + g_timeout_add(0, sim_op_next, modem); + } else { + op->current += 1; + g_timeout_add(0, sim_op_retrieve_next, modem); + } +} + +static gboolean sim_op_retrieve_next(gpointer user) +{ + struct ofono_modem *modem = user; + struct sim_manager_data *sim = modem->sim_manager; + struct sim_file_op *op = g_queue_peek_head(sim->simop_q); + + switch (op->structure) { + case OFONO_SIM_FILE_STRUCTURE_TRANSPARENT: + if (!sim->ops->read_file_transparent) { + sim_op_error(modem); + return FALSE; + } + + sim->ops->read_file_transparent(modem, op->id, 0, op->length, + sim_op_retrieve_cb, modem); + break; + case OFONO_SIM_FILE_STRUCTURE_FIXED: + if (!sim->ops->read_file_linear) { + sim_op_error(modem); + return FALSE; + } + + sim->ops->read_file_linear(modem, op->id, op->current, + op->record_length, + sim_op_retrieve_cb, modem); + break; + case OFONO_SIM_FILE_STRUCTURE_CYCLIC: + if (!sim->ops->read_file_cyclic) { + sim_op_error(modem); + return FALSE; + } + + sim->ops->read_file_cyclic(modem, op->id, op->current, + op->record_length, + sim_op_retrieve_cb, modem); + break; + default: + ofono_error("Unrecognized file structure, this can't happen"); + } + + return FALSE; +} + +static void sim_op_info_cb(const struct ofono_error *error, int length, + enum ofono_sim_file_structure structure, + int record_length, void *data) +{ + struct ofono_modem *modem = data; + struct sim_manager_data *sim = modem->sim_manager; + struct sim_file_op *op = g_queue_peek_head(sim->simop_q); + + if (error->type != OFONO_ERROR_TYPE_NO_ERROR) { + sim_op_error(modem); + return; + } + + op->structure = structure; + op->length = length; + op->record_length = record_length; + op->current = 1; + + g_timeout_add(0, sim_op_retrieve_next, modem); +} + +static gboolean sim_op_next(gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct sim_manager_data *sim = modem->sim_manager; + struct sim_file_op *op; + + if (!sim->simop_q) + return FALSE; + + op = g_queue_peek_head(sim->simop_q); + + sim->ops->read_file_info(modem, op->id, sim_op_info_cb, modem); + + return FALSE; +} + +int ofono_sim_read(struct ofono_modem *modem, int id, + ofono_sim_file_read_cb_t cb, void *data) +{ + struct sim_manager_data *sim = modem->sim_manager; + struct sim_file_op *op; + + if (!cb) + return -1; + + if (modem->sim_manager == NULL) + return -1; + + if (!sim->ops) + return -1; + + if (!sim->ops->read_file_info) + return -1; + + if (!sim->simop_q) + sim->simop_q = g_queue_new(); + + op = g_new0(struct sim_file_op, 1); + + op->id = id; + op->cb = cb; + op->userdata = data; + + g_queue_push_tail(sim->simop_q, op); + + if (g_queue_get_length(sim->simop_q) == 1) + g_timeout_add(0, sim_op_next, modem); + + return 0; +} + +int ofono_sim_write(struct ofono_modem *modem, int id, + enum ofono_sim_file_structure structure, int record, + const unsigned char *data, int length) +{ + return -1; +} + static void initialize_sim_manager(struct ofono_modem *modem) { DBusConnection *conn = dbus_gsm_connection(); diff --git a/src/sim.h b/src/sim.h index 30d2979d..df29be29 100644 --- a/src/sim.h +++ b/src/sim.h @@ -21,10 +21,11 @@ typedef void (*ofono_sim_ready_notify_cb_t)(struct ofono_modem *modem); -typedef void (*ofono_sim_read_binary_cb_t)(struct ofono_modem *modem, - const struct ofono_error *error, - const unsigned char *data, - int len, void *userdata); +typedef void (*ofono_sim_file_read_cb_t)(struct ofono_modem *modem, int ok, + enum ofono_sim_file_structure structure, + int total_length, int record, + const unsigned char *data, + int record_length, void *userdata); void ofono_sim_manager_init(struct ofono_modem *modem); void ofono_sim_manager_exit(struct ofono_modem *modem); @@ -43,3 +44,17 @@ const char *ofono_operator_name_sim_override(struct ofono_modem *modem, const char *mnc); int ofono_sim_get_ready(struct ofono_modem *modem); void ofono_sim_set_ready(struct ofono_modem *modem); + +/* This will queue an operation to read all available records with id from the + * SIM. Callback cb will be called every time a record has been read, or once + * if an error has occurred. For transparent files, the callback will only + * be called once. + * + * Returns 0 if the request could be queued, -1 otherwise. + */ +int ofono_sim_read(struct ofono_modem *modem, int id, + ofono_sim_file_read_cb_t cb, void *data); + +int ofono_sim_write(struct ofono_modem *modem, int id, + enum ofono_sim_file_structure structure, int record, + const unsigned char *data, int length);