mirror of git://git.sysmocom.de/ofono
Present list of preferred languages on SimManager interfce.
We try to detect the old (2G / 2G+, 51.011) EFlp format and deal with the file contents accordingly.
This commit is contained in:
parent
12e77a3c70
commit
623c23c12f
216
src/sim.c
216
src/sim.c
|
@ -77,10 +77,14 @@ struct ofono_sim {
|
||||||
GSList *service_numbers;
|
GSList *service_numbers;
|
||||||
gboolean sdn_ready;
|
gboolean sdn_ready;
|
||||||
gboolean ready;
|
gboolean ready;
|
||||||
|
char **language_prefs;
|
||||||
GQueue *simop_q;
|
GQueue *simop_q;
|
||||||
gint simop_source;
|
gint simop_source;
|
||||||
unsigned char efmsisdn_length;
|
unsigned char efmsisdn_length;
|
||||||
unsigned char efmsisdn_records;
|
unsigned char efmsisdn_records;
|
||||||
|
unsigned char *efli;
|
||||||
|
unsigned char efli_length;
|
||||||
|
unsigned int next_ready_watch_id;
|
||||||
struct ofono_watchlist *ready_watches;
|
struct ofono_watchlist *ready_watches;
|
||||||
const struct ofono_sim_driver *driver;
|
const struct ofono_sim_driver *driver;
|
||||||
void *driver_data;
|
void *driver_data;
|
||||||
|
@ -197,6 +201,11 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
|
||||||
g_strfreev(service_numbers);
|
g_strfreev(service_numbers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sim->language_prefs)
|
||||||
|
ofono_dbus_dict_append_array(&dict, "PreferredLanguages",
|
||||||
|
DBUS_TYPE_STRING,
|
||||||
|
&sim->language_prefs);
|
||||||
|
|
||||||
dbus_message_iter_close_container(&iter, &dict);
|
dbus_message_iter_close_container(&iter, &dict);
|
||||||
|
|
||||||
return reply;
|
return reply;
|
||||||
|
@ -604,6 +613,207 @@ static void sim_retrieve_imsi(struct ofono_sim *sim)
|
||||||
sim->driver->read_imsi(sim, sim_imsi_cb, sim);
|
sim->driver->read_imsi(sim, sim_imsi_cb, sim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sim_efli_read_cb(int ok,
|
||||||
|
enum ofono_sim_file_structure structure,
|
||||||
|
int length, int record,
|
||||||
|
const unsigned char *data,
|
||||||
|
int record_length, void *userdata)
|
||||||
|
{
|
||||||
|
struct ofono_sim *sim = userdata;
|
||||||
|
|
||||||
|
if (!ok || structure != OFONO_SIM_FILE_STRUCTURE_TRANSPARENT)
|
||||||
|
return;
|
||||||
|
|
||||||
|
sim->efli = g_memdup(data, length);
|
||||||
|
sim->efli_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Detect whether the file is in EFli format, as opposed to 51.011 EFlp */
|
||||||
|
static gboolean sim_efli_format(const unsigned char *ef, int length)
|
||||||
|
{
|
||||||
|
if (length & 1)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
while (length) {
|
||||||
|
if (ef[0] != ef[1] && (ef[0] == 0xff || ef[1] == 0xff))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* ISO 639 country codes are each two lower-case SMS 7-bit
|
||||||
|
* characters while CB DCS language codes are in ranges
|
||||||
|
* (0 - 15) or (32 - 47), so the ranges don't overlap
|
||||||
|
*/
|
||||||
|
if (ef[0] != 0xff && (ef[0] < 'a' || ef[0] > 'z'))
|
||||||
|
return FALSE;
|
||||||
|
if (ef[1] != 0xff && (ef[1] < 'a' || ef[1] > 'z'))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
ef += 2;
|
||||||
|
length -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_language_list(char **out_list, int *count,
|
||||||
|
const unsigned char *ef, int length)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
length--;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i += 2) {
|
||||||
|
if (ef[i] == 0xff || ef[i + 1] == 0xff)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (j = 0; j < *count; j++)
|
||||||
|
if (!memcmp(out_list[j], ef + i, 2))
|
||||||
|
break;
|
||||||
|
if (j < *count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* ISO 639 codes contain only characters that are coded
|
||||||
|
* identically in SMS 7 bit charset, ASCII or UTF8 so
|
||||||
|
* no conversion.
|
||||||
|
*/
|
||||||
|
out_list[(*count)++] = g_strndup((char *) ef + i, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char* const dcs_lang_to_iso[0x30] = {
|
||||||
|
[0x00] = "de",
|
||||||
|
[0x01] = "en",
|
||||||
|
[0x02] = "it",
|
||||||
|
[0x03] = "fr",
|
||||||
|
[0x04] = "es",
|
||||||
|
[0x05] = "nl",
|
||||||
|
[0x06] = "sv",
|
||||||
|
[0x07] = "da",
|
||||||
|
[0x08] = "pt",
|
||||||
|
[0x09] = "fi",
|
||||||
|
[0x0a] = "no",
|
||||||
|
[0x0b] = "el",
|
||||||
|
[0x0c] = "tr",
|
||||||
|
[0x0d] = "hu",
|
||||||
|
[0x0e] = "pl",
|
||||||
|
[0x20] = "cs",
|
||||||
|
[0x21] = "ar",
|
||||||
|
[0x22] = "he",
|
||||||
|
[0x23] = "ar",
|
||||||
|
[0x24] = "ru",
|
||||||
|
[0x25] = "is",
|
||||||
|
};
|
||||||
|
|
||||||
|
static void parse_eflp(char **out_list, int *count,
|
||||||
|
const unsigned char *eflp, int length)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
const char *code;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
if (eflp[i] >= 0x30)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
code = dcs_lang_to_iso[eflp[i]];
|
||||||
|
if (!code)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (j = 0; j < *count; j ++)
|
||||||
|
if (!memcmp(out_list[j], code, 2))
|
||||||
|
break;
|
||||||
|
if (j < *count)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
out_list[*count++] = g_strdup(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sim_efpl_read_cb(int ok,
|
||||||
|
enum ofono_sim_file_structure structure,
|
||||||
|
int length, int record,
|
||||||
|
const unsigned char *data,
|
||||||
|
int record_length, void *userdata)
|
||||||
|
{
|
||||||
|
struct ofono_sim *sim = userdata;
|
||||||
|
unsigned char *efli = sim->efli;
|
||||||
|
const unsigned char *efpl = data;
|
||||||
|
int efli_length = sim->efli_length;
|
||||||
|
int efpl_length = length;
|
||||||
|
int count;
|
||||||
|
int maxcount;
|
||||||
|
const char *path = __ofono_atom_get_path(sim->atom);
|
||||||
|
DBusConnection *conn = ofono_dbus_get_connection();
|
||||||
|
|
||||||
|
if (!ok || structure != OFONO_SIM_FILE_STRUCTURE_TRANSPARENT ||
|
||||||
|
length < 2) {
|
||||||
|
efpl = NULL;
|
||||||
|
efpl_length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!efli || sim_efli_format(efli, efli_length)) {
|
||||||
|
maxcount = (efli_length + efpl_length) / 2;
|
||||||
|
sim->language_prefs = g_new0(char *, maxcount + 1);
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
/* Make a list of languages in both files in order of
|
||||||
|
* preference following TS 31.102.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (efli && efpl && efli[0] == 0xff && efli[1] == 0xff) {
|
||||||
|
parse_language_list(sim->language_prefs, &count,
|
||||||
|
efpl, efpl_length);
|
||||||
|
efpl = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (efli) {
|
||||||
|
parse_language_list(sim->language_prefs, &count,
|
||||||
|
efli, efli_length);
|
||||||
|
g_free(efli);
|
||||||
|
sim->efli = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (efpl)
|
||||||
|
parse_language_list(sim->language_prefs, &count,
|
||||||
|
efpl, efpl_length);
|
||||||
|
} else {
|
||||||
|
maxcount = efpl_length / 2 + efli_length;
|
||||||
|
sim->language_prefs = g_new0(char *, maxcount + 1);
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
/* Make a list of languages in both files in order of
|
||||||
|
* preference following TS 51.011.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (efpl)
|
||||||
|
parse_language_list(sim->language_prefs, &count,
|
||||||
|
efpl, efpl_length);
|
||||||
|
|
||||||
|
parse_eflp(sim->language_prefs, &count, efli, efli_length);
|
||||||
|
g_free(efli);
|
||||||
|
sim->efli = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ofono_dbus_signal_array_property_changed(conn, path,
|
||||||
|
SIM_MANAGER_INTERFACE,
|
||||||
|
"PreferredLanguages",
|
||||||
|
DBUS_TYPE_STRING,
|
||||||
|
&sim->language_prefs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sim_retrieve_efli(struct ofono_sim *sim)
|
||||||
|
{
|
||||||
|
/* According to 31.102 the EFli is read first and EFpl is then
|
||||||
|
* only read if none of the EFli languages are supported by user
|
||||||
|
* interface. 51.011 mandates the exact opposite, making EFpl/EFelp
|
||||||
|
* preferred over EFlp (same EFid as EFli, different format).
|
||||||
|
* However we don't depend on the user interface and so
|
||||||
|
* need to read both files now.
|
||||||
|
*/
|
||||||
|
ofono_sim_read(sim, SIM_EFLI_FILEID, sim_efli_read_cb, sim);
|
||||||
|
ofono_sim_read(sim, SIM_EFPL_FILEID, sim_efpl_read_cb, sim);
|
||||||
|
}
|
||||||
|
|
||||||
static void sim_op_error(struct ofono_sim *sim)
|
static void sim_op_error(struct ofono_sim *sim)
|
||||||
{
|
{
|
||||||
struct sim_file_op *op = g_queue_pop_head(sim->simop_q);
|
struct sim_file_op *op = g_queue_pop_head(sim->simop_q);
|
||||||
|
@ -1163,6 +1373,11 @@ static void sim_remove(struct ofono_atom *atom)
|
||||||
sim->service_numbers = NULL;
|
sim->service_numbers = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sim->language_prefs) {
|
||||||
|
g_strfreev(sim->language_prefs);
|
||||||
|
sim->language_prefs = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (sim->simop_source) {
|
if (sim->simop_source) {
|
||||||
g_source_remove(sim->simop_source);
|
g_source_remove(sim->simop_source);
|
||||||
sim->simop_source = 0;
|
sim->simop_source = 0;
|
||||||
|
@ -1253,6 +1468,7 @@ void ofono_sim_register(struct ofono_sim *sim)
|
||||||
* arbitrary files to be written or read, assuming their presence
|
* arbitrary files to be written or read, assuming their presence
|
||||||
* in the EFust
|
* in the EFust
|
||||||
*/
|
*/
|
||||||
|
sim_retrieve_efli(sim);
|
||||||
sim_retrieve_imsi(sim);
|
sim_retrieve_imsi(sim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum sim_fileid {
|
enum sim_fileid {
|
||||||
|
SIM_EFPL_FILEID = 0x2f05,
|
||||||
|
SIM_EFLI_FILEID = 0x6f05,
|
||||||
SIM_EFMSISDN_FILEID = 0x6f40,
|
SIM_EFMSISDN_FILEID = 0x6f40,
|
||||||
SIM_EFSPN_FILEID = 0x6f46,
|
SIM_EFSPN_FILEID = 0x6f46,
|
||||||
SIM_EFSDN_FILEID = 0x6f49,
|
SIM_EFSDN_FILEID = 0x6f49,
|
||||||
|
|
Loading…
Reference in New Issue