summaryrefslogtreecommitdiffstats
path: root/src/sim.c
diff options
context:
space:
mode:
authorOleg Zhurakivskyy <oleg.zhurakivskyy@intel.com>2012-01-09 12:30:42 +0200
committerDenis Kenzior <denkenz@gmail.com>2012-01-15 19:55:58 -0600
commitef658e92f31ee5fc6466c82c31973b3b95f6b657 (patch)
tree00714116c77c0fe7d34a1c7ce329b2b022df8d23 /src/sim.c
parent3272397ad90e3d0aede75ecc301cd30b9984f35d (diff)
downloadofono-ef658e92f31ee5fc6466c82c31973b3b95f6b657.tar.bz2
sim: Add SPN watch capability
Diffstat (limited to 'src/sim.c')
-rw-r--r--src/sim.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/src/sim.c b/src/sim.c
index 4ef14e39..93b36556 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -46,7 +46,11 @@
#include "simfs.h"
#include "stkutil.h"
+#define SIM_FLAG_READING_SPN 0x1
+
struct ofono_sim {
+ int flags;
+
/* Contents of the SIM file system, in rough initialization order */
char *iccid;
@@ -91,6 +95,13 @@ struct ofono_sim {
enum ofono_sim_state state;
struct ofono_watchlist *state_watches;
+ char *spn;
+ char *spn_dc;
+ struct ofono_watchlist *spn_watches;
+ unsigned int ef_spn_watch;
+ unsigned int cphs_spn_watch;
+ unsigned int cphs_spn_short_watch;
+
struct sim_fs *simfs;
struct ofono_sim_context *context;
struct ofono_sim_context *early_context;
@@ -2358,6 +2369,234 @@ enum ofono_sim_state ofono_sim_get_state(struct ofono_sim *sim)
return sim->state;
}
+static void spn_watch_cb(gpointer data, gpointer user_data)
+{
+ struct ofono_watchlist_item *item = data;
+ struct ofono_sim *sim = user_data;
+
+ if (item->notify)
+ ((ofono_sim_spn_cb_t) item->notify)(sim->spn, sim->spn_dc,
+ item->notify_data);
+}
+
+static inline void spn_watches_notify(struct ofono_sim *sim)
+{
+ if (sim->spn_watches->items)
+ g_slist_foreach(sim->spn_watches->items, spn_watch_cb, sim);
+
+ sim->flags &= ~SIM_FLAG_READING_SPN;
+}
+
+static void sim_spn_set(struct ofono_sim *sim, const void *data, int length,
+ const unsigned char *dc)
+{
+ char *spn;
+
+ /*
+ * TS 31.102 says:
+ *
+ * the string shall use:
+ *
+ * - either the SMS default 7-bit coded alphabet as defined in
+ * TS 23.038 [5] with bit 8 set to 0. The string shall be left
+ * justified. Unused bytes shall be set to 'FF'.
+ *
+ * - or one of the UCS2 code options defined in the annex of TS
+ * 31.101 [11].
+ *
+ * 31.101 has no such annex though. 51.101 refers to Annex B of
+ * itself which is not there either. 11.11 contains the same
+ * paragraph as 51.101 and has an Annex B which we implement.
+ */
+ spn = sim_string_to_utf8(data, length);
+ if (spn == NULL) {
+ ofono_error("EFspn read successfully, but couldn't parse");
+ goto notify;
+ }
+
+ if (strlen(spn) == 0) {
+ g_free(spn);
+ goto notify;
+ }
+
+ sim->spn = spn;
+
+ if (dc)
+ sim->spn_dc = g_memdup(dc, 1);
+
+notify:
+ spn_watches_notify(sim);
+}
+
+static void sim_cphs_spn_short_read_cb(int ok, int length, int record,
+ const unsigned char *data,
+ int record_length, void *user_data)
+{
+ struct ofono_sim *sim = user_data;
+
+ if (!ok) {
+ spn_watches_notify(sim);
+ return;
+ }
+
+ sim_spn_set(sim, data, length, NULL);
+}
+
+static void sim_cphs_spn_read_cb(int ok, int length, int record,
+ const unsigned char *data,
+ int record_length, void *user_data)
+{
+ struct ofono_sim *sim = user_data;
+
+ if (!ok) {
+ if (__ofono_sim_cphs_service_available(sim,
+ SIM_CPHS_SERVICE_SHORT_SPN))
+ ofono_sim_read(sim->context,
+ SIM_EF_CPHS_SPN_SHORT_FILEID,
+ OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ sim_cphs_spn_short_read_cb, sim);
+ else
+ spn_watches_notify(sim);
+
+ return;
+ }
+
+ sim_spn_set(sim, data, length, NULL);
+}
+
+static void sim_spn_read_cb(int ok, int length, int record,
+ const unsigned char *data,
+ int record_length, void *user_data)
+{
+ struct ofono_sim *sim = user_data;
+
+ if (!ok) {
+ ofono_sim_read(sim->context, SIM_EF_CPHS_SPN_FILEID,
+ OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ sim_cphs_spn_read_cb, sim);
+
+ return;
+ }
+
+ sim_spn_set(sim, data + 1, length - 1, data);
+}
+
+static void sim_spn_changed(int id, void *userdata)
+{
+ struct ofono_sim *sim = userdata;
+
+ if (sim->flags & SIM_FLAG_READING_SPN)
+ return;
+
+ g_free(sim->spn);
+ sim->spn = NULL;
+
+ g_free(sim->spn_dc);
+ sim->spn_dc = NULL;
+
+ sim->flags |= SIM_FLAG_READING_SPN;
+ ofono_sim_read(sim->context, SIM_EFSPN_FILEID,
+ OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ sim_spn_read_cb, sim);
+}
+
+static void sim_spn_init(struct ofono_sim *sim)
+{
+ sim->ef_spn_watch = ofono_sim_add_file_watch(sim->context,
+ SIM_EFSPN_FILEID, sim_spn_changed, sim,
+ NULL);
+
+ sim->cphs_spn_watch = ofono_sim_add_file_watch(sim->context,
+ SIM_EF_CPHS_SPN_FILEID,
+ sim_spn_changed, sim, NULL);
+
+ if (__ofono_sim_cphs_service_available(sim,
+ SIM_CPHS_SERVICE_SHORT_SPN))
+ sim->cphs_spn_short_watch = ofono_sim_add_file_watch(
+ sim->context, SIM_EF_CPHS_SPN_SHORT_FILEID,
+ sim_spn_changed, sim, NULL);
+}
+
+static void sim_spn_close(struct ofono_sim *sim)
+{
+ __ofono_watchlist_free(sim->spn_watches);
+ sim->spn_watches = NULL;
+
+ ofono_sim_remove_file_watch(sim->context, sim->ef_spn_watch);
+ sim->ef_spn_watch = 0;
+
+ ofono_sim_remove_file_watch(sim->context, sim->cphs_spn_watch);
+ sim->cphs_spn_watch = 0;
+
+ if (sim->cphs_spn_short_watch) {
+ ofono_sim_remove_file_watch(sim->context,
+ sim->cphs_spn_short_watch);
+ sim->cphs_spn_short_watch = 0;
+ }
+
+ sim->flags &= ~SIM_FLAG_READING_SPN;
+
+ g_free(sim->spn);
+ sim->spn = NULL;
+
+ g_free(sim->spn_dc);
+ sim->spn_dc = NULL;
+}
+
+gboolean ofono_sim_add_spn_watch(struct ofono_sim *sim, unsigned int *id,
+ ofono_sim_spn_cb_t cb, void *data,
+ ofono_destroy_func destroy)
+{
+ struct ofono_watchlist_item *item;
+ unsigned int watch_id;
+
+ DBG("%p", sim);
+
+ if (sim == NULL)
+ return 0;
+
+ item = g_new0(struct ofono_watchlist_item, 1);
+
+ item->notify = cb;
+ item->destroy = destroy;
+ item->notify_data = data;
+
+ watch_id = __ofono_watchlist_add_item(sim->spn_watches, item);
+ if (watch_id == 0)
+ return FALSE;
+
+ *id = watch_id;
+
+ if (sim->ef_spn_watch == 0) {
+ sim_spn_init(sim);
+ sim_spn_changed(0, sim);
+ return TRUE;
+ }
+
+ if (sim->flags & SIM_FLAG_READING_SPN)
+ return TRUE;
+
+ ((ofono_sim_spn_cb_t) item->notify)(sim->spn, sim->spn_dc,
+ item->notify_data);
+ return TRUE;
+}
+
+gboolean ofono_sim_remove_spn_watch(struct ofono_sim *sim, unsigned int *id)
+{
+ gboolean ret;
+
+ DBG("%p", sim);
+
+ if (sim == NULL)
+ return FALSE;
+
+ ret = __ofono_watchlist_remove_item(sim->spn_watches, *id);
+ if (ret == TRUE)
+ *id = 0;
+
+ return ret;
+}
+
static void sim_pin_query_cb(const struct ofono_error *error,
enum ofono_sim_password_type pin_type,
void *data)
@@ -2477,6 +2716,8 @@ static void sim_unregister(struct ofono_atom *atom)
__ofono_watchlist_free(sim->state_watches);
sim->state_watches = NULL;
+ sim_spn_close(sim);
+
g_dbus_unregister_interface(conn, path, OFONO_SIM_MANAGER_INTERFACE);
ofono_modem_remove_interface(modem, OFONO_SIM_MANAGER_INTERFACE);
}
@@ -2606,6 +2847,7 @@ void ofono_sim_register(struct ofono_sim *sim)
ofono_modem_add_interface(modem, OFONO_SIM_MANAGER_INTERFACE);
sim->state_watches = __ofono_watchlist_new(g_free);
+ sim->spn_watches = __ofono_watchlist_new(g_free);
sim->simfs = sim_fs_new(sim, sim->driver);
__ofono_atom_register(sim->atom, sim_unregister);