diff options
-rw-r--r-- | include/dbus.h | 9 | ||||
-rw-r--r-- | src/dbus.c | 80 | ||||
-rw-r--r-- | src/sim.c | 144 | ||||
-rw-r--r-- | src/simutil.h | 1 |
4 files changed, 227 insertions, 7 deletions
diff --git a/include/dbus.h b/include/dbus.h index 1d9f59f3..5a421199 100644 --- a/include/dbus.h +++ b/include/dbus.h @@ -52,6 +52,9 @@ void ofono_dbus_dict_append(DBusMessageIter *dict, const char *key, int type, void ofono_dbus_dict_append_array(DBusMessageIter *dict, const char *key, int type, void *val); +void ofono_dbus_dict_append_dict(DBusMessageIter *dict, const char *key, + int type, void *val); + int ofono_dbus_signal_property_changed(DBusConnection *conn, const char *path, const char *interface, const char *name, int type, void *value); @@ -62,6 +65,12 @@ int ofono_dbus_signal_array_property_changed(DBusConnection *conn, const char *name, int type, void *value); +int ofono_dbus_signal_dict_property_changed(DBusConnection *conn, + const char *path, + const char *interface, + const char *name, int type, + void *value); + #ifdef __cplusplus } #endif @@ -112,6 +112,59 @@ void ofono_dbus_dict_append_array(DBusMessageIter *dict, const char *key, dbus_message_iter_close_container(dict, &entry); } +static void append_dict_variant(DBusMessageIter *iter, int type, void *val) +{ + DBusMessageIter variant, array, entry; + char typesig[5]; + char arraysig[6]; + const void **val_array = *(const void ***)val; + int i; + + arraysig[0] = DBUS_TYPE_ARRAY; + arraysig[1] = typesig[0] = DBUS_DICT_ENTRY_BEGIN_CHAR; + arraysig[2] = typesig[1] = DBUS_TYPE_STRING; + arraysig[3] = typesig[2] = type; + arraysig[4] = typesig[3] = DBUS_DICT_ENTRY_END_CHAR; + arraysig[5] = typesig[4] = '\0'; + + dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, + arraysig, &variant); + + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, + typesig, &array); + + for (i = 0; val_array[i]; i += 2) { + dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, + &(val_array[i + 0])); + dbus_message_iter_append_basic(&entry, type, + &(val_array[i + 1])); + + dbus_message_iter_close_container(&array, &entry); + } + + dbus_message_iter_close_container(&variant, &array); + + dbus_message_iter_close_container(iter, &variant); +} + +void ofono_dbus_dict_append_dict(DBusMessageIter *dict, const char *key, + int type, void *val) +{ + DBusMessageIter entry; + + dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, + NULL, &entry); + + dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); + + append_dict_variant(&entry, type, val); + + dbus_message_iter_close_container(dict, &entry); +} + int ofono_dbus_signal_property_changed(DBusConnection *conn, const char *path, const char *interface, @@ -165,6 +218,33 @@ int ofono_dbus_signal_array_property_changed(DBusConnection *conn, return g_dbus_send_message(conn, signal); } +int ofono_dbus_signal_dict_property_changed(DBusConnection *conn, + const char *path, + const char *interface, + const char *name, + int type, void *value) + +{ + DBusMessage *signal; + DBusMessageIter iter; + + signal = dbus_message_new_signal(path, interface, "PropertyChanged"); + + if (!signal) { + ofono_error("Unable to allocate new %s.PropertyChanged signal", + interface); + return -1; + } + + dbus_message_iter_init_append(signal, &iter); + + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); + + append_dict_variant(&iter, type, value); + + return g_dbus_send_message(conn, signal); +} + DBusMessage *__ofono_error_invalid_args(DBusMessage *msg) { return g_dbus_create_error(msg, DBUS_GSM_ERROR_INTERFACE @@ -79,6 +79,7 @@ struct ofono_sim { unsigned char mnc_length; GSList *own_numbers; GSList *new_numbers; + GSList *service_numbers; gboolean ready; GQueue *simop_q; gint simop_source; @@ -105,6 +106,11 @@ struct sim_ready_watch { ofono_destroy_func destroy; }; +struct service_number { + char *id; + struct ofono_phone_number ph; +}; + static char **get_own_numbers(GSList *own_numbers) { int nelem = 0; @@ -127,11 +133,39 @@ static char **get_own_numbers(GSList *own_numbers) return ret; } +static char **get_service_numbers(GSList *service_numbers) +{ + int nelem; + GSList *l; + struct service_number *num; + char **ret; + + nelem = g_slist_length(service_numbers) * 2; + + ret = g_new0(char *, nelem + 1); + + nelem = 0; + for (l = service_numbers; l; l = l->next) { + num = l->data; + + ret[nelem++] = g_strdup(num->id); + ret[nelem++] = g_strdup(phone_number_to_string(&num->ph)); + } + + return ret; +} + static void sim_file_op_free(struct sim_file_op *node) { g_free(node); } +static void service_number_free(struct service_number *num) +{ + g_free(num->id); + g_free(num); +} + static DBusMessage *sim_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -140,6 +174,7 @@ static DBusMessage *sim_get_properties(DBusConnection *conn, DBusMessageIter iter; DBusMessageIter dict; char **own_numbers; + char **service_numbers; reply = dbus_message_new_method_return(msg); if (!reply) @@ -165,6 +200,15 @@ static DBusMessage *sim_get_properties(DBusConnection *conn, DBUS_TYPE_STRING, &own_numbers); g_strfreev(own_numbers); + if (sim->service_numbers) { + service_numbers = get_service_numbers(sim->service_numbers); + + ofono_dbus_dict_append_dict(&dict, "ServiceDiallingNumbers", + DBUS_TYPE_STRING, + &service_numbers); + g_strfreev(service_numbers); + } + dbus_message_iter_close_container(&iter, &dict); return reply; @@ -444,16 +488,91 @@ static void sim_ad_read_cb(int ok, } } -static void sim_own_numbers_update(struct ofono_sim *sim) +static gint service_number_compare(gconstpointer a, gconstpointer b) { - ofono_sim_read(sim, SIM_EFMSISDN_FILEID, - sim_msisdn_read_cb, sim); + const struct service_number *sdn = a; + const char *id = b; + + return strcmp(sdn->id, id); } -static void sim_mnc_length_update(struct ofono_sim *sim) +static void sim_sdn_read_cb(int ok, + enum ofono_sim_file_structure structure, + int length, int record, + const unsigned char *data, + int record_length, void *userdata) { - ofono_sim_read(sim, SIM_EFAD_FILEID, - sim_ad_read_cb, sim); + struct ofono_sim *sim = userdata; + int total; + struct ofono_phone_number ph; + char *alpha; + char **service_numbers; + DBusConnection *conn = ofono_dbus_get_connection(); + const char *path = __ofono_atom_get_path(sim->atom); + + if (!ok) + goto check; + + if (structure != OFONO_SIM_FILE_STRUCTURE_FIXED) + return; + + if (record_length < 14 || length < record_length) + return; + + total = length / record_length; + + if (sim_adn_parse(data, record_length, &ph, &alpha) == TRUE) { + struct service_number *sdn; + + if (!alpha || alpha[0] == '\0') { + if (alpha) + g_free(alpha); + + /* Use phone number if Id is unavailable */ + alpha = g_strdup(phone_number_to_string(&ph)); + } + + if (sim->service_numbers && + g_slist_find_custom(sim->service_numbers, + alpha, service_number_compare)) { + ofono_error("Duplicate EFsdn entries for `%s'\n", + alpha); + g_free(alpha); + + goto check; + } + + sdn = g_new(struct service_number, 1); + sdn->id = alpha; + memcpy(&sdn->ph, &ph, sizeof(struct ofono_phone_number)); + + sim->service_numbers = + g_slist_prepend(sim->service_numbers, sdn); + } + + if (record != total) + return; + +check: + /* All records retrieved */ + if (sim->service_numbers) { + sim->service_numbers = g_slist_reverse(sim->service_numbers); + + service_numbers = get_service_numbers(sim->service_numbers); + + ofono_dbus_signal_dict_property_changed(conn, path, + SIM_MANAGER_INTERFACE, + "ServiceDiallingNumbers", + DBUS_TYPE_STRING, + &service_numbers); + g_strfreev(service_numbers); + } +} + +static void sim_own_numbers_update(struct ofono_sim *sim) +{ + ofono_sim_read(sim, SIM_EFMSISDN_FILEID, + sim_msisdn_read_cb, sim); } static void sim_ready(void *user) @@ -461,7 +580,11 @@ static void sim_ready(void *user) struct ofono_sim *sim = user; sim_own_numbers_update(sim); - sim_mnc_length_update(sim); + + ofono_sim_read(sim, SIM_EFAD_FILEID, + sim_ad_read_cb, sim); + ofono_sim_read(sim, SIM_EFSDN_FILEID, + sim_sdn_read_cb, sim); } static void sim_imsi_cb(const struct ofono_error *error, const char *imsi, @@ -1150,6 +1273,13 @@ static void sim_remove(struct ofono_atom *atom) sim->own_numbers = NULL; } + if (sim->service_numbers) { + g_slist_foreach(sim->service_numbers, + (GFunc)service_number_free, NULL); + g_slist_free(sim->service_numbers); + sim->service_numbers = NULL; + } + if (sim->simop_source) { g_source_remove(sim->simop_source); sim->simop_source = 0; diff --git a/src/simutil.h b/src/simutil.h index dccbe7bc..de3e55e6 100644 --- a/src/simutil.h +++ b/src/simutil.h @@ -22,6 +22,7 @@ enum sim_fileid { SIM_EFMSISDN_FILEID = 0x6f40, SIM_EFSPN_FILEID = 0x6f46, + SIM_EFSDN_FILEID = 0x6f49, SIM_EFAD_FILEID = 0x6fad, SIM_EFPNN_FILEID = 0x6fc5, SIM_EFOPL_FILEID = 0x6fc6, |