2009/9/16 Andrzej Zaborowski <[email protected]>:
> So here's another version generated on top of HEAD and with an attempt
> to detect when the card uses EFlp format instead of EFli.

Sorry, I sent the wrong file, here's the *actual* new version.

Regards
From c652820f5faf01288ac1a7caf340aefe2cba37dd Mon Sep 17 00:00:00 2001
From: Andrzej Zaborowski <[email protected]>
Date: Thu, 17 Sep 2009 15:58:29 +0200
Subject: [PATCH 1/2] 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.
---
 src/sim.c     |  216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/simutil.h |    2 +
 2 files changed, 218 insertions(+), 0 deletions(-)

diff --git a/src/sim.c b/src/sim.c
index 46cac40..3f26678 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -77,10 +77,14 @@ struct ofono_sim {
 	GSList *service_numbers;
 	gboolean sdn_ready;
 	gboolean ready;
+	char **language_prefs;
 	GQueue *simop_q;
 	gint simop_source;
 	unsigned char efmsisdn_length;
 	unsigned char efmsisdn_records;
+	unsigned char *efli;
+	unsigned char efli_length;
+	unsigned int next_ready_watch_id;
 	struct ofono_watchlist *ready_watches;
 	const struct ofono_sim_driver *driver;
 	void *driver_data;
@@ -197,6 +201,11 @@ static DBusMessage *sim_get_properties(DBusConnection *conn,
 		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);
 
 	return reply;
@@ -604,6 +613,207 @@ static void sim_retrieve_imsi(struct ofono_sim *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)
 {
 	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;
 	}
 
+	if (sim->language_prefs) {
+		g_strfreev(sim->language_prefs);
+		sim->language_prefs = NULL;
+	}
+
 	if (sim->simop_source) {
 		g_source_remove(sim->simop_source);
 		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
 	 * in the EFust
 	 */
+	sim_retrieve_efli(sim);
 	sim_retrieve_imsi(sim);
 }
 
diff --git a/src/simutil.h b/src/simutil.h
index 90fc37b..2cd3b73 100644
--- a/src/simutil.h
+++ b/src/simutil.h
@@ -20,6 +20,8 @@
  */
 
 enum sim_fileid {
+	SIM_EFPL_FILEID = 0x2f05,
+	SIM_EFLI_FILEID = 0x6f05,
 	SIM_EFMSISDN_FILEID = 0x6f40,
 	SIM_EFSPN_FILEID = 0x6f46,
 	SIM_EFSDN_FILEID = 0x6f49,
-- 
1.6.1

_______________________________________________
ofono mailing list
[email protected]
http://lists.ofono.org/listinfo/ofono

Reply via email to