summaryrefslogtreecommitdiffstats
path: root/src/sim.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim.c')
-rw-r--r--src/sim.c208
1 files changed, 203 insertions, 5 deletions
diff --git a/src/sim.c b/src/sim.c
index b7832f56..eb155420 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -59,6 +59,7 @@
static gboolean sim_op_next(gpointer user_data);
static gboolean sim_op_retrieve_next(gpointer user);
+static void sim_own_numbers_update(struct ofono_modem *modem);
struct sim_file_op {
int id;
@@ -80,6 +81,15 @@ struct sim_manager_data {
GSList *ready_notify;
gboolean ready;
GQueue *simop_q;
+
+ int efmsisdn_length;
+};
+
+struct msisdn_set_request {
+ struct ofono_modem *modem;
+ int pending;
+ int failed;
+ DBusMessage *msg;
};
static char **get_own_numbers(GSList *own_numbers)
@@ -172,8 +182,151 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
return reply;
}
+static void msisdn_set_done(struct msisdn_set_request *req)
+{
+ DBusMessage *reply;
+
+ if (req->failed)
+ reply = __ofono_error_failed(req->msg);
+ else
+ reply = dbus_message_new_method_return(req->msg);
+
+ __ofono_dbus_pending_reply(&req->msg, reply);
+
+ /* Re-read the numbers and emit signal if needed */
+ sim_own_numbers_update(req->modem);
+
+ g_free(req);
+}
+
+static void msisdn_set_cb(struct ofono_modem *modem, int ok, void *data)
+{
+ struct msisdn_set_request *req = data;
+
+ if (!ok)
+ req->failed++;
+
+ req->pending--;
+
+ if (!req->pending)
+ msisdn_set_done(req);
+}
+
+static void set_own_numbers(struct ofono_modem *modem,
+ GSList *new_numbers, DBusMessage *msg)
+{
+ struct sim_manager_data *sim = modem->sim_manager;
+ struct msisdn_set_request *req;
+ int record;
+ unsigned char efmsisdn[255];
+ struct ofono_phone_number *number;
+
+ if (!sim->own_numbers || g_slist_length(new_numbers) !=
+ g_slist_length(sim->own_numbers)) {
+ g_slist_foreach(new_numbers, (GFunc) g_free, 0);
+ g_slist_free(new_numbers);
+
+ msg = dbus_message_ref(msg);
+ __ofono_dbus_pending_reply(&msg,
+ __ofono_error_invalid_args(msg));
+
+ return;
+ }
+
+ req = g_new0(struct msisdn_set_request, 1);
+
+ req->modem = modem;
+ req->msg = dbus_message_ref(msg);
+
+ for (record = 1; new_numbers; record++) {
+ number = new_numbers->data;
+ new_numbers = g_slist_delete_link(new_numbers, new_numbers);
+
+ sim_adn_build(efmsisdn, sim->efmsisdn_length, number);
+ g_free(number);
+
+ if (ofono_sim_write(req->modem, SIM_EFMSISDN_FILEID,
+ msisdn_set_cb, OFONO_SIM_FILE_STRUCTURE_FIXED,
+ record++, efmsisdn,
+ sim->efmsisdn_length, req) == 0)
+ req->pending++;
+ else
+ req->failed++;
+ }
+
+ if (!req->pending)
+ msisdn_set_done(req);
+}
+
+static DBusMessage *sim_set_property(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct ofono_modem *modem = data;
+ struct sim_manager_data *sim = modem->sim_manager;
+ DBusMessageIter iter;
+ DBusMessageIter var;
+ DBusMessageIter var_elem;
+ const char *name, *value;
+ struct ofono_phone_number *own;
+ GSList *own_numbers = NULL;
+
+ if (!dbus_message_iter_init(msg, &iter))
+ return __ofono_error_invalid_args(msg);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_get_basic(&iter, &name);
+
+ if (!strcmp(name, "SubscriberNumbers")) {
+ if (sim->efmsisdn_length == 0)
+ return __ofono_error_busy(msg);
+
+ dbus_message_iter_next(&iter);
+
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&iter, &var);
+
+ if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(&var) !=
+ DBUS_TYPE_STRING)
+ return __ofono_error_invalid_args(msg);
+
+ dbus_message_iter_recurse(&var, &var_elem);
+
+ do {
+ if (dbus_message_iter_get_arg_type(&var_elem) !=
+ DBUS_TYPE_STRING)
+ goto error;
+
+ dbus_message_iter_get_basic(&var_elem, &value);
+
+ if (!valid_phone_number_format(value))
+ goto error;
+
+ own = g_new0(struct ofono_phone_number, 1);
+ string_to_phone_number(value, own);
+
+ own_numbers = g_slist_prepend(own_numbers, own);
+ } while (dbus_message_iter_next(&var_elem));
+
+ set_own_numbers(modem, g_slist_reverse(own_numbers), msg);
+ return NULL;
+ }
+
+error:
+ g_slist_foreach(own_numbers, (GFunc) g_free, 0);
+ g_slist_free(own_numbers);
+
+ return __ofono_error_invalid_args(msg);
+}
+
static GDBusMethodTable sim_manager_methods[] = {
{ "GetProperties", "", "a{sv}", sim_get_properties },
+ { "SetProperty", "sv", "", sim_set_property,
+ G_DBUS_METHOD_FLAG_ASYNC },
{ }
};
@@ -182,6 +335,27 @@ static GDBusSignalTable sim_manager_signals[] = {
{ }
};
+static gboolean numbers_list_equal(GSList *a, GSList *b)
+{
+ struct ofono_phone_number *num_a, *num_b;
+
+ while (a || b) {
+ if (!a || !b)
+ return FALSE;
+
+ num_a = a->data;
+ num_b = b->data;
+
+ if (!g_str_equal(num_a->number, num_b->number) ||
+ num_a->type != num_b->type)
+ return FALSE;
+
+ a = a->next;
+ b = b->next;
+ }
+
+ return TRUE;
+}
static void sim_msisdn_read_cb(struct ofono_modem *modem, int ok,
enum ofono_sim_file_structure structure,
@@ -192,10 +366,13 @@ static void sim_msisdn_read_cb(struct ofono_modem *modem, int ok,
struct sim_manager_data *sim = modem->sim_manager;
int total;
struct ofono_phone_number ph;
+ GSList **new_own_numbers = userdata;
if (!ok)
goto check;
+ sim->efmsisdn_length = record_length;
+
if (structure != OFONO_SIM_FILE_STRUCTURE_FIXED)
return;
@@ -209,19 +386,24 @@ static void sim_msisdn_read_cb(struct ofono_modem *modem, int ok,
own = g_new(struct ofono_phone_number, 1);
memcpy(own, &ph, sizeof(struct ofono_phone_number));
- sim->own_numbers = g_slist_prepend(sim->own_numbers, own);
+ *new_own_numbers = g_slist_prepend(*new_own_numbers, own);
}
if (record != total)
return;
check:
- if (sim->own_numbers) {
+ /* All records retrieved */
+ if (*new_own_numbers)
+ *new_own_numbers = g_slist_reverse(*new_own_numbers);
+
+ if (!numbers_list_equal(*new_own_numbers, sim->own_numbers)) {
char **own_numbers;
DBusConnection *conn = ofono_dbus_get_connection();
- /* All records retrieved */
- sim->own_numbers = g_slist_reverse(sim->own_numbers);
+ g_slist_foreach(sim->own_numbers, (GFunc) g_free, NULL);
+ g_slist_free(sim->own_numbers);
+ sim->own_numbers = *new_own_numbers;
own_numbers = get_own_numbers(sim->own_numbers);
@@ -231,12 +413,28 @@ check:
DBUS_TYPE_STRING,
&own_numbers);
g_strfreev(own_numbers);
+ } else {
+ g_slist_foreach(*new_own_numbers, (GFunc) g_free, NULL);
+ g_slist_free(*new_own_numbers);
}
+
+ g_free(new_own_numbers);
+}
+
+static void sim_own_numbers_update(struct ofono_modem *modem)
+{
+ GSList **new_own_numbers = g_new0(GSList *, 1);
+
+ if (!new_own_numbers)
+ return;
+
+ ofono_sim_read(modem, SIM_EFMSISDN_FILEID,
+ sim_msisdn_read_cb, new_own_numbers);
}
static void sim_ready(struct ofono_modem *modem)
{
- ofono_sim_read(modem, SIM_EFMSISDN_FILEID, sim_msisdn_read_cb, NULL);
+ sim_own_numbers_update(modem);
}
static void sim_imsi_cb(const struct ofono_error *error, const char *imsi,