All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/3] icon support
@ 2010-08-27 16:19 Kristen Carlson Accardi
  2010-08-27 16:19 ` [PATCH 1/3] sim: read EFiidf Kristen Carlson Accardi
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Kristen Carlson Accardi @ 2010-08-27 16:19 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 544 bytes --]

Changes from last version:

* changed caching algorithm for EFiidf files - now store all 256 byte
	blocks in a single file
* made ofono_sim_read_bytes a public function
* various bug fixes

Kristen Carlson Accardi (3):
  sim: read EFiidf
  sim: Implement GetIcon
  test: add get-icon script

 include/sim.h |    4 +
 src/sim.c     |  525 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 test/get-icon |   25 +++
 3 files changed, 542 insertions(+), 12 deletions(-)
 create mode 100755 test/get-icon

-- 
1.7.2.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/3] sim: read EFiidf
  2010-08-27 16:19 [PATCH 0/3] icon support Kristen Carlson Accardi
@ 2010-08-27 16:19 ` Kristen Carlson Accardi
  2010-09-09 14:10   ` Denis Kenzior
  2010-08-27 16:19 ` [PATCH 2/3] sim: Implement GetIcon Kristen Carlson Accardi
  2010-08-27 16:19 ` [PATCH 3/3] test: add get-icon script Kristen Carlson Accardi
  2 siblings, 1 reply; 6+ messages in thread
From: Kristen Carlson Accardi @ 2010-08-27 16:19 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 11409 bytes --]

EFiidf can be larger than 256 bytes, so allow callers to read
portions of the EFiidf from a specified offset.  Cache EFiidf
files as blocks of 256 bytes so that it's not necessary to
read the entire (potentially large) file.
---
 include/sim.h |    4 +
 src/sim.c     |  305 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 297 insertions(+), 12 deletions(-)

diff --git a/include/sim.h b/include/sim.h
index 36a99b9..67f8a6e 100644
--- a/include/sim.h
+++ b/include/sim.h
@@ -202,6 +202,10 @@ int ofono_sim_write(struct ofono_sim *sim, int id,
 			ofono_sim_file_write_cb_t cb,
 			enum ofono_sim_file_structure structure, int record,
 			const unsigned char *data, int length, void *userdata);
+
+int ofono_sim_read_bytes(struct ofono_sim *sim, int id,
+			unsigned short offset, int num_bytes,
+			ofono_sim_file_read_cb_t cb, void *data);
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/sim.c b/src/sim.c
index f8884a2..bbcf609 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -46,7 +46,8 @@
 #define SIM_CACHE_MODE 0600
 #define SIM_CACHE_PATH STORAGEDIR "/%s-%i/%04x"
 #define SIM_CACHE_PATH_LEN(imsilen) (strlen(SIM_CACHE_PATH) - 3 + imsilen)
-#define SIM_CACHE_HEADER_SIZE 6
+#define SIM_CACHE_HEADER_SIZE 38
+#define SIM_FILE_INFO_SIZE 6
 
 static GSList *g_drivers = NULL;
 
@@ -55,11 +56,14 @@ static gboolean sim_op_retrieve_next(gpointer user);
 static void sim_own_numbers_update(struct ofono_sim *sim);
 static void sim_pin_check(struct ofono_sim *sim);
 static void sim_set_ready(struct ofono_sim *sim);
+static gboolean sim_op_read_block(gpointer user_data);
 
 struct sim_file_op {
 	int id;
 	gboolean cache;
 	enum ofono_sim_file_structure structure;
+	unsigned short offset;
+	int num_bytes;
 	int length;
 	int record_length;
 	int current;
@@ -1517,23 +1521,45 @@ static void sim_op_error(struct ofono_sim *sim)
 }
 
 static gboolean cache_record(const char *path, int current, int record_len,
-				const unsigned char *data)
+				const unsigned char *data, int num_bytes,
+				enum ofono_sim_file_structure type)
 {
 	int r = 0;
 	int fd;
 
-	fd = TFR(open(path, O_WRONLY));
+	fd = TFR(open(path, O_RDWR));
 
 	if (fd == -1)
 		return FALSE;
 
 	if (lseek(fd, (current - 1) * record_len +
 				SIM_CACHE_HEADER_SIZE, SEEK_SET) != (off_t) -1)
-		r = TFR(write(fd, data, record_len));
+		r = TFR(write(fd, data, num_bytes));
+
+	/* update present bit for this block if we are a transparent file */
+	if (type == OFONO_SIM_FILE_STRUCTURE_TRANSPARENT) {
+		/* figure out which byte the right bit location is */
+		int byte = (current - 1) / 8;
+		int bit = (current - 1) % 8;
+		guint8 cache;
+
+		/* lseek to correct byte (skip file info) */
+		lseek(fd, byte + SIM_FILE_INFO_SIZE, SEEK_SET);
+
+		/* read byte */
+		TFR(read(fd, &cache, 1));
+
+		/* set present bit */
+		cache |= (1 << bit);
+
+		/* write back */
+		lseek(fd, byte + SIM_FILE_INFO_SIZE, SEEK_SET);
+		TFR(write(fd, &cache, 1));
+	}
 
 	TFR(close(fd));
 
-	if (r < record_len) {
+	if (r < num_bytes) {
 		unlink(path);
 		return FALSE;
 	}
@@ -1562,7 +1588,8 @@ static void sim_op_retrieve_cb(const struct ofono_error *error,
 						imsi, sim->phase, op->id);
 
 		op->cache = cache_record(path, op->current, op->record_length,
-						data);
+						data, op->record_length,
+						op->structure);
 		g_free(path);
 	}
 
@@ -1667,12 +1694,17 @@ static void sim_op_info_cb(const struct ofono_error *error, int length,
 	else
 		op->record_length = record_length;
 
-	op->current = 1;
-
-	sim->simop_source = g_timeout_add(0, sim_op_retrieve_next, sim);
+	if (op->num_bytes > 0)
+		sim->simop_source = g_timeout_add(0, sim_op_read_block, sim);
+	else {
+		op->current = 1;
+		sim->simop_source = g_timeout_add(0, sim_op_retrieve_next, sim);
+	}
 
 	if (op->cache && imsi) {
-		unsigned char fileinfo[6];
+		unsigned char fileinfo[SIM_CACHE_HEADER_SIZE];
+
+		memset(fileinfo, 0, SIM_CACHE_HEADER_SIZE);
 
 		fileinfo[0] = error->type;
 		fileinfo[1] = length >> 8;
@@ -1681,8 +1713,9 @@ static void sim_op_info_cb(const struct ofono_error *error, int length,
 		fileinfo[4] = record_length >> 8;
 		fileinfo[5] = record_length & 0xff;
 
-		if (write_file(fileinfo, 6, SIM_CACHE_MODE, SIM_CACHE_PATH,
-					imsi, sim->phase, op->id) != 6)
+		if (write_file(fileinfo, SIM_CACHE_HEADER_SIZE, SIM_CACHE_MODE,
+					SIM_CACHE_PATH, imsi, sim->phase,
+					op->id) != SIM_CACHE_HEADER_SIZE)
 			op->cache = FALSE;
 	}
 }
@@ -1751,6 +1784,12 @@ static gboolean sim_op_check_cached(struct ofono_sim *sim)
 	structure = fileinfo[3];
 	record_length = (fileinfo[4] << 8) | fileinfo[5];
 
+	if (op->num_bytes > 0) {
+		op->length = file_length;
+		ret = TRUE;
+		goto cleanup;
+	}
+
 	if (structure == OFONO_SIM_FILE_STRUCTURE_TRANSPARENT)
 		record_length = file_length;
 
@@ -1790,6 +1829,199 @@ cleanup:
 	return ret;
 }
 
+static void sim_op_read_block_cb(const struct ofono_error *error,
+				const unsigned char *data, int len, void *user)
+{
+	struct ofono_sim *sim = user;
+	struct sim_file_op *op = g_queue_peek_head(sim->simop_q);
+	char *imsi = sim->imsi;
+	int start_block, end_block;
+	int start, length;
+	unsigned char *buf;
+
+	if ((error->type != OFONO_ERROR_TYPE_NO_ERROR) || (len == 0)) {
+		sim_op_error(sim);
+		return;
+	}
+
+	/* buffer this block */
+	start_block = op->offset / 256;
+	end_block = (op->offset + (op->num_bytes - 1)) / 256;
+
+	if (op->current == start_block) {
+		start = op->offset % 256;
+		buf = op->buffer;
+	} else {
+		start = 0;
+		buf = op->buffer + (op->current * 256);
+	}
+
+	length = op->num_bytes % 256;
+
+	if ((length == 0) || (op->current != end_block))
+		length = 256;
+
+	memcpy(buf, &data[start], length);
+
+	/* cache this block */
+	if (op->cache && imsi) {
+		char *path = g_strdup_printf(SIM_CACHE_PATH,
+						sim->imsi, sim->phase, op->id);
+		op->cache = cache_record(path, op->current + 1, 256, data,
+						length, op->structure);
+
+		g_free(path);
+	}
+
+	op->current++;
+
+	sim->simop_source = g_timeout_add(0, sim_op_read_block, sim);
+}
+
+static gboolean sim_op_check_cached_block(struct ofono_sim *sim)
+{
+	struct sim_file_op *op = g_queue_peek_head(sim->simop_q);
+	char *path;
+	int fd;
+	char *imsi = sim->imsi;
+	int start_block, end_block;
+	int start, length, len;
+	unsigned char *buf;
+	int bit, byte;
+	guint8 cache;
+	gboolean ret;
+
+	if (!imsi)
+		return FALSE;
+
+	path = g_strdup_printf(SIM_CACHE_PATH, sim->imsi, sim->phase, op->id);
+
+	if (path == NULL)
+		return FALSE;
+
+	fd = TFR(open(path, O_RDONLY));
+	g_free(path);
+
+	if (fd == -1) {
+		if (errno != ENOENT)
+			DBG("Error %i opening cache file for "
+					"fileid %04x, IMSI %s",
+					errno, op->id, imsi);
+
+		return FALSE;
+	}
+
+	/* read cache header to see if current block is present */
+	byte = op->current / 8;
+	bit = op->current % 8;
+
+	lseek(fd, SIM_FILE_INFO_SIZE + byte, SEEK_SET);
+
+	len = TFR(read(fd, &cache, 1));
+
+	if ((len != 1) || ((cache & (1 << bit)) == FALSE)) {
+		ret = FALSE;
+		goto cleanup;
+	}
+
+	/* figure out where we should start reading from */
+	start_block = op->offset / 256;
+	end_block = (op->offset + (op->num_bytes - 1)) / 256;
+
+	if (op->current == start_block) {
+		start = op->offset % 256;
+		buf = op->buffer;
+	} else {
+		start = 0;
+		buf = op->buffer + (op->current * 256);
+	}
+
+	length = op->num_bytes % 256;
+
+	if ((length == 0) || (op->current != end_block))
+		length = 256;
+
+	/* lseek to the right place in the file */
+	TFR(lseek(fd, start + SIM_CACHE_HEADER_SIZE, SEEK_SET));
+
+	len = TFR(read(fd, buf, length));
+
+	if (len != length) {
+		ret = FALSE;
+		goto cleanup;
+	}
+
+	ret = TRUE;
+
+	op->current++;
+
+	sim->simop_source = g_timeout_add(0, sim_op_read_block, sim);
+
+cleanup:
+	TFR(close(fd));
+
+	return ret;
+}
+
+static gboolean sim_op_read_block(gpointer user_data)
+{
+	struct ofono_sim *sim = user_data;
+	struct sim_file_op *op = g_queue_peek_head(sim->simop_q);
+	int end_block;
+	ofono_sim_file_read_cb_t cb = op->cb;
+	int read_bytes;
+
+	end_block = (op->offset + (op->num_bytes - 1)) / 256;
+
+	if (op->current > end_block) {
+		cb(1, op->num_bytes, op->current, op->buffer,
+				op->record_length, op->userdata);
+
+		op = g_queue_pop_head(sim->simop_q);
+
+		g_free(op->buffer);
+
+		sim_file_op_free(op);
+
+		if (g_queue_get_length(sim->simop_q) > 0)
+			sim->simop_source = g_timeout_add(0, sim_op_next, sim);
+
+		return FALSE;
+	}
+
+	/* see if this block is cached */
+	if (sim_op_check_cached_block(sim) == TRUE)
+		return FALSE;
+
+	if (op->length < ((op->current + 1) * 256))
+		read_bytes = op->length % 256;
+	else
+		read_bytes = 256;
+
+	sim->driver->read_file_transparent(sim, op->id,
+						op->current * 256,
+						read_bytes,
+						sim_op_read_block_cb, sim);
+	return FALSE;
+}
+
+static void sim_op_get_blocks(struct ofono_sim *sim)
+{
+	struct sim_file_op *op = g_queue_peek_head(sim->simop_q);
+
+	/* allocate space to buffer the data till we've collected it all */
+	op->buffer = g_try_malloc0(op->num_bytes);
+
+	/* initialize current */
+	op->current = op->offset / 256;
+
+	/* need to get the length of the file */
+	if (sim_op_check_cached(sim) == FALSE)
+		sim->driver->read_file_info(sim, op->id, sim_op_info_cb, sim);
+	else
+		sim->simop_source = g_timeout_add(0, sim_op_read_block, sim);
+}
+
 static gboolean sim_op_next(gpointer user_data)
 {
 	struct ofono_sim *sim = user_data;
@@ -1802,6 +2034,11 @@ static gboolean sim_op_next(gpointer user_data)
 
 	op = g_queue_peek_head(sim->simop_q);
 
+	if (op->num_bytes > 0) {
+		sim_op_get_blocks(sim);
+		return FALSE;
+	}
+
 	if (op->is_read == TRUE) {
 		if (sim_op_check_cached(sim)) {
 			op = g_queue_pop_head(sim->simop_q);
@@ -1844,6 +2081,49 @@ static gboolean sim_op_next(gpointer user_data)
 	return FALSE;
 }
 
+int ofono_sim_read_bytes(struct ofono_sim *sim, int id,
+			unsigned short offset, int num_bytes,
+			ofono_sim_file_read_cb_t cb, void *data)
+{
+	struct sim_file_op *op;
+
+	if (!cb)
+		return -1;
+
+	if (sim == NULL)
+		return -1;
+
+	if (!sim->driver)
+		return -1;
+
+	if (!sim->driver->read_file_info)
+		return -1;
+
+	/* TODO: We must first check the EFust table to see whether
+	 * this file can be read at all
+	 */
+
+	if (!sim->simop_q)
+		sim->simop_q = g_queue_new();
+
+	op = g_new0(struct sim_file_op, 1);
+
+	op->id = id;
+	op->structure = OFONO_SIM_FILE_STRUCTURE_TRANSPARENT;
+	op->cb = cb;
+	op->userdata = data;
+	op->is_read = TRUE;
+	op->offset = offset;
+	op->num_bytes = num_bytes;
+
+	g_queue_push_tail(sim->simop_q, op);
+
+	if (g_queue_get_length(sim->simop_q) == 1)
+		sim->simop_source = g_timeout_add(0, sim_op_next, sim);
+
+	return 0;
+}
+
 int ofono_sim_read(struct ofono_sim *sim, int id,
 			enum ofono_sim_file_structure expected_type,
 			ofono_sim_file_read_cb_t cb, void *data)
@@ -1876,6 +2156,7 @@ int ofono_sim_read(struct ofono_sim *sim, int id,
 	op->cb = cb;
 	op->userdata = data;
 	op->is_read = TRUE;
+	op->num_bytes = -1;
 
 	g_queue_push_tail(sim->simop_q, op);
 
-- 
1.7.2.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/3] sim: Implement GetIcon
  2010-08-27 16:19 [PATCH 0/3] icon support Kristen Carlson Accardi
  2010-08-27 16:19 ` [PATCH 1/3] sim: read EFiidf Kristen Carlson Accardi
@ 2010-08-27 16:19 ` Kristen Carlson Accardi
  2010-09-09 14:16   ` Denis Kenzior
  2010-08-27 16:19 ` [PATCH 3/3] test: add get-icon script Kristen Carlson Accardi
  2 siblings, 1 reply; 6+ messages in thread
From: Kristen Carlson Accardi @ 2010-08-27 16:19 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 6860 bytes --]

---
 src/sim.c |  220 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 220 insertions(+), 0 deletions(-)

diff --git a/src/sim.c b/src/sim.c
index bbcf609..d8c0d37 100644
--- a/src/sim.c
+++ b/src/sim.c
@@ -42,12 +42,14 @@
 #include "smsutil.h"
 #include "simutil.h"
 #include "storage.h"
+#include "stkutil.h"
 
 #define SIM_CACHE_MODE 0600
 #define SIM_CACHE_PATH STORAGEDIR "/%s-%i/%04x"
 #define SIM_CACHE_PATH_LEN(imsilen) (strlen(SIM_CACHE_PATH) - 3 + imsilen)
 #define SIM_CACHE_HEADER_SIZE 38
 #define SIM_FILE_INFO_SIZE 6
+#define SIM_IMAGE_CACHE_PATH STORAGEDIR "/%s-%i/images/%d.xpm"
 
 static GSList *g_drivers = NULL;
 
@@ -58,6 +60,11 @@ static void sim_pin_check(struct ofono_sim *sim);
 static void sim_set_ready(struct ofono_sim *sim);
 static gboolean sim_op_read_block(gpointer user_data);
 
+typedef void (*sim_get_image_cb_t)(int ok, const char *xpm, int xpm_len,
+						void *user_data);
+static void sim_get_image(struct ofono_sim *sim, unsigned char id,
+			sim_get_image_cb_t cb, gpointer user_data);
+
 struct sim_file_op {
 	int id;
 	gboolean cache;
@@ -93,6 +100,7 @@ struct ofono_sim {
 	unsigned char *efli;
 	unsigned char efli_length;
 	unsigned char *efimg;
+	unsigned short image_cache[256];
 	int efimg_length;
 	enum ofono_sim_cphs_phase cphs_phase;
 	unsigned char cphs_service_table[2];
@@ -736,6 +744,50 @@ static DBusMessage *sim_enter_pin(DBusConnection *conn, DBusMessage *msg,
 	return NULL;
 }
 
+static void sim_get_image_cb(int ok, const char *xpm, int xpm_len,
+					void *userdata)
+{
+	struct ofono_sim *sim = userdata;
+	DBusMessage *reply;
+
+	if (!ok)
+		reply = __ofono_error_failed(sim->pending);
+	else {
+		reply = dbus_message_new_method_return(sim->pending);
+		dbus_message_append_args(reply, DBUS_TYPE_STRING, &xpm,
+					DBUS_TYPE_INVALID);
+	}
+
+	__ofono_dbus_pending_reply(&sim->pending, reply);
+}
+
+static DBusMessage *sim_get_icon(DBusConnection *conn,
+					DBusMessage *msg, void *data)
+{
+	struct ofono_sim *sim = data;
+	unsigned char id;
+
+	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_BYTE, &id,
+					DBUS_TYPE_INVALID) == FALSE)
+		return __ofono_error_invalid_args(msg);
+
+	/* zero means no icon */
+	if (id == 0)
+		return __ofono_error_invalid_args(msg);
+
+	if (sim->pending)
+		return __ofono_error_busy(msg);
+
+	if (sim->efimg == NULL)
+		return __ofono_error_not_implemented(msg);
+
+	sim->pending = dbus_message_ref(msg);
+
+	sim_get_image(sim, id, sim_get_image_cb, sim);
+
+	return NULL;
+}
+
 static DBusMessage *sim_reset_pin(DBusConnection *conn, DBusMessage *msg,
 					void *data)
 {
@@ -788,6 +840,8 @@ static GDBusMethodTable sim_methods[] = {
 							G_DBUS_METHOD_FLAG_ASYNC },
 	{ "UnlockPin",		"ss",	"",		sim_unlock_pin,
 							G_DBUS_METHOD_FLAG_ASYNC },
+	{ "GetIcon",		"y",	"s",		sim_get_icon,
+							G_DBUS_METHOD_FLAG_ASYNC },
 	{ }
 };
 
@@ -2549,3 +2603,169 @@ void *ofono_sim_get_data(struct ofono_sim *sim)
 {
 	return sim->driver_data;
 }
+
+struct image_data {
+	struct ofono_sim *sim;
+	unsigned char width;
+	unsigned char height;
+	enum stk_img_scheme scheme;
+	unsigned short iidf_id;
+	unsigned short iidf_offset;
+	unsigned short iid_len;
+	void *image;
+	unsigned short clut_len;
+	gboolean need_clut;
+	sim_get_image_cb_t user_cb;
+	gpointer user_data;
+	unsigned char id;
+};
+
+static void sim_iidf_read_cb(int ok, int length, int record,
+				const unsigned char *data,
+				int record_length, void *userdata)
+{
+	struct image_data *image = userdata;
+	unsigned short offset;
+	unsigned short num_entries;
+	char *xpm;
+	struct ofono_sim *sim = image->sim;
+
+	if (!ok) {
+		image->user_cb(ok, NULL, 0, image->user_data);
+		goto iidf_read_out;
+	}
+
+	if (image->need_clut == FALSE) {
+		if (image->scheme == STK_IMG_SCHEME_BASIC) {
+			xpm = stk_image_to_xpm(data, image->iid_len,
+						image->scheme, NULL, 0);
+		} else {
+			xpm = stk_image_to_xpm(image->image, image->iid_len,
+						image->scheme, data,
+						image->clut_len);
+		}
+
+		if (sim->imsi) {
+			write_file((const unsigned char *) xpm, strlen(xpm),
+					SIM_CACHE_MODE, SIM_IMAGE_CACHE_PATH,
+					sim->imsi, sim->phase, image->id);
+
+			sim->image_cache[image->id] = strlen(xpm);
+		}
+
+		image->user_cb(ok, xpm, strlen(xpm), image->user_data);
+
+		g_free(xpm);
+
+		goto iidf_read_out;
+	}
+
+	offset = data[4] << 8 | data[5];
+	num_entries = data[3];
+
+	if (num_entries == 0)
+		num_entries = 256;
+
+	/* indicate that we're on our second read */
+	image->need_clut = FALSE;
+
+	image->clut_len = num_entries * 3;
+
+	image->image = g_memdup(data, length);
+
+	/* read the clut data */
+	ofono_sim_read_bytes(image->sim, image->iidf_id,
+				offset, image->clut_len,
+				sim_iidf_read_cb, image);
+
+	return;
+
+iidf_read_out:
+	g_free(image->image);
+	g_free(image);
+}
+
+static void sim_get_image(struct ofono_sim *sim, unsigned char id,
+			sim_get_image_cb_t cb, gpointer user_data)
+{
+	struct image_data *data;
+	unsigned char *efimg;
+	unsigned short image_length;
+
+	/* icon ids should start at 1, our array starts at zero */
+	if (id == 0) {
+		cb(-1, NULL, 0, user_data);
+		return;
+	}
+
+	id--;
+
+	/* check the image cache to see if we've already got this one */
+	image_length = sim->image_cache[id];
+
+	if (image_length > 0) {
+		int fd;
+		char *imsi = sim->imsi;
+		char *buffer;
+		char *path = g_strdup_printf(SIM_IMAGE_CACHE_PATH, imsi,
+						sim->phase,
+						id);
+		int len;
+
+		fd = TFR(open(path, O_RDONLY));
+
+		g_free(path);
+
+		if (fd < 0)
+			goto read_image;
+
+		buffer = g_try_malloc0(image_length + 1);
+
+		len = TFR(read(fd, buffer, image_length));
+
+		if (len == image_length)
+			cb(1, buffer, image_length, user_data);
+		else {
+			g_free(buffer);
+			goto read_image;
+		}
+
+		g_free(buffer);
+
+		return;
+	}
+
+read_image:
+
+	if (sim->efimg_length < (id * 9)) {
+		cb(-1, NULL, 0, user_data);
+		return;
+	}
+
+	efimg = &sim->efimg[id * 9];
+
+	data = g_try_new0(struct image_data, 1);
+	if (data == NULL)
+		return;
+
+	data->width = efimg[0];
+	data->height = efimg[1];
+	data->scheme = efimg[2];
+	data->iidf_id = efimg[3] << 8 | efimg[4];
+	data->iidf_offset = efimg[5] << 8 | efimg[6];
+	data->iid_len = efimg[7] << 8 | efimg[8];
+	data->user_cb = cb;
+	data->user_data = user_data;
+	data->sim = sim;
+	data->id = id;
+
+	if (data->scheme == STK_IMG_SCHEME_BASIC)
+		data->need_clut = FALSE;
+	else
+		data->need_clut = TRUE;
+
+	/* read the image data */
+	ofono_sim_read_bytes(sim, data->iidf_id,
+				data->iidf_offset, data->iid_len,
+				sim_iidf_read_cb, data);
+}
-- 
1.7.2.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 3/3] test: add get-icon script
  2010-08-27 16:19 [PATCH 0/3] icon support Kristen Carlson Accardi
  2010-08-27 16:19 ` [PATCH 1/3] sim: read EFiidf Kristen Carlson Accardi
  2010-08-27 16:19 ` [PATCH 2/3] sim: Implement GetIcon Kristen Carlson Accardi
@ 2010-08-27 16:19 ` Kristen Carlson Accardi
  2 siblings, 0 replies; 6+ messages in thread
From: Kristen Carlson Accardi @ 2010-08-27 16:19 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 906 bytes --]

---
 test/get-icon |   25 +++++++++++++++++++++++++
 1 files changed, 25 insertions(+), 0 deletions(-)
 create mode 100755 test/get-icon

diff --git a/test/get-icon b/test/get-icon
new file mode 100755
index 0000000..680ae13
--- /dev/null
+++ b/test/get-icon
@@ -0,0 +1,25 @@
+#!/usr/bin/python
+
+import dbus
+import sys
+
+bus = dbus.SystemBus()
+
+if len(sys.argv) == 3:
+	path = sys.argv[1]
+	id = int(sys.argv[2], 16)
+elif len(sys.argv) == 2:
+	manager = dbus.Interface(bus.get_object('org.ofono', '/'),
+				 'org.ofono.Manager')
+	properties = manager.GetProperties()
+	path = properties["Modems"][0]
+	id = int(sys.argv[1], 16)
+else:
+	print "%s [PATH] icon_id" % (sys.argv[0])
+
+simmanager = dbus.Interface(bus.get_object('org.ofono', path),
+			    'org.ofono.SimManager')
+
+xpm = simmanager.GetIcon(id)
+
+print "Received xpm: %s" % (xpm)
-- 
1.7.2.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/3] sim: read EFiidf
  2010-08-27 16:19 ` [PATCH 1/3] sim: read EFiidf Kristen Carlson Accardi
@ 2010-09-09 14:10   ` Denis Kenzior
  0 siblings, 0 replies; 6+ messages in thread
From: Denis Kenzior @ 2010-09-09 14:10 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 501 bytes --]

Hi Kristen,

On 08/27/2010 11:19 AM, Kristen Carlson Accardi wrote:
> EFiidf can be larger than 256 bytes, so allow callers to read
> portions of the EFiidf from a specified offset.  Cache EFiidf
> files as blocks of 256 bytes so that it's not necessary to
> read the entire (potentially large) file.

This patch has been applied.  I refactored sim file system writing into
a separate source file afterwards.  It was getting a bit too large to be
contained inside sim.c

Regards,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/3] sim: Implement GetIcon
  2010-08-27 16:19 ` [PATCH 2/3] sim: Implement GetIcon Kristen Carlson Accardi
@ 2010-09-09 14:16   ` Denis Kenzior
  0 siblings, 0 replies; 6+ messages in thread
From: Denis Kenzior @ 2010-09-09 14:16 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 7917 bytes --]

Hi Kristen,

On 08/27/2010 11:19 AM, Kristen Carlson Accardi wrote:
> ---
>  src/sim.c |  220 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 220 insertions(+), 0 deletions(-)
> 
> diff --git a/src/sim.c b/src/sim.c
> index bbcf609..d8c0d37 100644
> --- a/src/sim.c
> +++ b/src/sim.c
> @@ -42,12 +42,14 @@
>  #include "smsutil.h"
>  #include "simutil.h"
>  #include "storage.h"
> +#include "stkutil.h"
>  
>  #define SIM_CACHE_MODE 0600
>  #define SIM_CACHE_PATH STORAGEDIR "/%s-%i/%04x"
>  #define SIM_CACHE_PATH_LEN(imsilen) (strlen(SIM_CACHE_PATH) - 3 + imsilen)
>  #define SIM_CACHE_HEADER_SIZE 38
>  #define SIM_FILE_INFO_SIZE 6
> +#define SIM_IMAGE_CACHE_PATH STORAGEDIR "/%s-%i/images/%d.xpm"
>  
>  static GSList *g_drivers = NULL;
>  
> @@ -58,6 +60,11 @@ static void sim_pin_check(struct ofono_sim *sim);
>  static void sim_set_ready(struct ofono_sim *sim);
>  static gboolean sim_op_read_block(gpointer user_data);
>  
> +typedef void (*sim_get_image_cb_t)(int ok, const char *xpm, int xpm_len,
> +						void *user_data);
> +static void sim_get_image(struct ofono_sim *sim, unsigned char id,
> +			sim_get_image_cb_t cb, gpointer user_data);
> +

I'd like to get rid of the typedef and the forward declaration.  The
typedef is not necessary since only 1 client will ever need this, so
hardcoding it is fine for now.

>  struct sim_file_op {
>  	int id;
>  	gboolean cache;
> @@ -93,6 +100,7 @@ struct ofono_sim {
>  	unsigned char *efli;
>  	unsigned char efli_length;
>  	unsigned char *efimg;
> +	unsigned short image_cache[256];

Let us get rid of this part.  You can easily stat() the file to figure
out whether it has been cached.

>  	int efimg_length;
>  	enum ofono_sim_cphs_phase cphs_phase;
>  	unsigned char cphs_service_table[2];
> @@ -736,6 +744,50 @@ static DBusMessage *sim_enter_pin(DBusConnection *conn, DBusMessage *msg,
>  	return NULL;
>  }
>  
> +static void sim_get_image_cb(int ok, const char *xpm, int xpm_len,
> +					void *userdata)

Please use gboolean ok instead of int

> +{
> +	struct ofono_sim *sim = userdata;
> +	DBusMessage *reply;
> +
> +	if (!ok)
> +		reply = __ofono_error_failed(sim->pending);
> +	else {
> +		reply = dbus_message_new_method_return(sim->pending);
> +		dbus_message_append_args(reply, DBUS_TYPE_STRING, &xpm,
> +					DBUS_TYPE_INVALID);
> +	}
> +
> +	__ofono_dbus_pending_reply(&sim->pending, reply);
> +}
> +
> +static DBusMessage *sim_get_icon(DBusConnection *conn,
> +					DBusMessage *msg, void *data)
> +{
> +	struct ofono_sim *sim = data;
> +	unsigned char id;
> +
> +	if (dbus_message_get_args(msg, NULL, DBUS_TYPE_BYTE, &id,
> +					DBUS_TYPE_INVALID) == FALSE)
> +		return __ofono_error_invalid_args(msg);
> +
> +	/* zero means no icon */
> +	if (id == 0)
> +		return __ofono_error_invalid_args(msg);
> +
> +	if (sim->pending)
> +		return __ofono_error_busy(msg);
> +
> +	if (sim->efimg == NULL)
> +		return __ofono_error_not_implemented(msg);
> +
> +	sim->pending = dbus_message_ref(msg);
> +
> +	sim_get_image(sim, id, sim_get_image_cb, sim);
> +
> +	return NULL;
> +}
> +
>  static DBusMessage *sim_reset_pin(DBusConnection *conn, DBusMessage *msg,
>  					void *data)
>  {
> @@ -788,6 +840,8 @@ static GDBusMethodTable sim_methods[] = {
>  							G_DBUS_METHOD_FLAG_ASYNC },
>  	{ "UnlockPin",		"ss",	"",		sim_unlock_pin,
>  							G_DBUS_METHOD_FLAG_ASYNC },
> +	{ "GetIcon",		"y",	"s",		sim_get_icon,
> +							G_DBUS_METHOD_FLAG_ASYNC },
>  	{ }
>  };
>  
> @@ -2549,3 +2603,169 @@ void *ofono_sim_get_data(struct ofono_sim *sim)
>  {
>  	return sim->driver_data;
>  }
> +
> +struct image_data {
> +	struct ofono_sim *sim;
> +	unsigned char width;
> +	unsigned char height;
> +	enum stk_img_scheme scheme;
> +	unsigned short iidf_id;
> +	unsigned short iidf_offset;
> +	unsigned short iid_len;
> +	void *image;
> +	unsigned short clut_len;
> +	gboolean need_clut;
> +	sim_get_image_cb_t user_cb;
> +	gpointer user_data;
> +	unsigned char id;
> +};
> +
> +static void sim_iidf_read_cb(int ok, int length, int record,
> +				const unsigned char *data,
> +				int record_length, void *userdata)
> +{
> +	struct image_data *image = userdata;
> +	unsigned short offset;
> +	unsigned short num_entries;
> +	char *xpm;
> +	struct ofono_sim *sim = image->sim;
> +
> +	if (!ok) {
> +		image->user_cb(ok, NULL, 0, image->user_data);
> +		goto iidf_read_out;
> +	}
> +
> +	if (image->need_clut == FALSE) {
> +		if (image->scheme == STK_IMG_SCHEME_BASIC) {
> +			xpm = stk_image_to_xpm(data, image->iid_len,
> +						image->scheme, NULL, 0);
> +		} else {
> +			xpm = stk_image_to_xpm(image->image, image->iid_len,
> +						image->scheme, data,
> +						image->clut_len);
> +		}
> +
> +		if (sim->imsi) {
> +			write_file((const unsigned char *) xpm, strlen(xpm),
> +					SIM_CACHE_MODE, SIM_IMAGE_CACHE_PATH,
> +					sim->imsi, sim->phase, image->id);
> +
> +			sim->image_cache[image->id] = strlen(xpm);
> +		}
> +
> +		image->user_cb(ok, xpm, strlen(xpm), image->user_data);
> +
> +		g_free(xpm);
> +
> +		goto iidf_read_out;
> +	}
> +
> +	offset = data[4] << 8 | data[5];
> +	num_entries = data[3];
> +
> +	if (num_entries == 0)
> +		num_entries = 256;
> +
> +	/* indicate that we're on our second read */
> +	image->need_clut = FALSE;
> +
> +	image->clut_len = num_entries * 3;
> +
> +	image->image = g_memdup(data, length);
> +
> +	/* read the clut data */
> +	ofono_sim_read_bytes(image->sim, image->iidf_id,
> +				offset, image->clut_len,
> +				sim_iidf_read_cb, image);
> +
> +	return;
> +
> +iidf_read_out:
> +	g_free(image->image);
> +	g_free(image);
> +}
> +
> +static void sim_get_image(struct ofono_sim *sim, unsigned char id,
> +			sim_get_image_cb_t cb, gpointer user_data)
> +{
> +	struct image_data *data;
> +	unsigned char *efimg;
> +	unsigned short image_length;
> +
> +	/* icon ids should start at 1, our array starts at zero */
> +	if (id == 0) {
> +		cb(-1, NULL, 0, user_data);

-1 is actually wrong here, it should be 0.

> +		return;
> +	}
> +
> +	id--;
> +
> +	/* check the image cache to see if we've already got this one */
> +	image_length = sim->image_cache[id];
> +
> +	if (image_length > 0) {
> +		int fd;
> +		char *imsi = sim->imsi;
> +		char *buffer;
> +		char *path = g_strdup_printf(SIM_IMAGE_CACHE_PATH, imsi,
> +						sim->phase,
> +						id);
> +		int len;
> +
> +		fd = TFR(open(path, O_RDONLY));
> +
> +		g_free(path);
> +
> +		if (fd < 0)
> +			goto read_image;
> +
> +		buffer = g_try_malloc0(image_length + 1);
> +
> +		len = TFR(read(fd, buffer, image_length));
> +
> +		if (len == image_length)
> +			cb(1, buffer, image_length, user_data);
> +		else {
> +			g_free(buffer);
> +			goto read_image;
> +		}
> +
> +		g_free(buffer);
> +
> +		return;
> +	}
> +
> +read_image:
> +
> +	if (sim->efimg_length < (id * 9)) {
> +		cb(-1, NULL, 0, user_data);
> +		return;
> +	}
> +
> +	efimg = &sim->efimg[id * 9];
> +
> +	data = g_try_new0(struct image_data, 1);
> +	if (data == NULL)
> +		return;
> +
> +	data->width = efimg[0];
> +	data->height = efimg[1];
> +	data->scheme = efimg[2];
> +	data->iidf_id = efimg[3] << 8 | efimg[4];
> +	data->iidf_offset = efimg[5] << 8 | efimg[6];
> +	data->iid_len = efimg[7] << 8 | efimg[8];
> +	data->user_cb = cb;
> +	data->user_data = user_data;
> +	data->sim = sim;
> +	data->id = id;
> +
> +	if (data->scheme == STK_IMG_SCHEME_BASIC)
> +		data->need_clut = FALSE;
> +	else
> +		data->need_clut = TRUE;
> +
> +	/* read the image data */
> +	ofono_sim_read_bytes(sim, data->iidf_id,
> +				data->iidf_offset, data->iid_len,
> +				sim_iidf_read_cb, data);
> +}

Otherwise patch looks good.  Can you rebase and resubmit?

Thanks,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-09-09 14:16 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-27 16:19 [PATCH 0/3] icon support Kristen Carlson Accardi
2010-08-27 16:19 ` [PATCH 1/3] sim: read EFiidf Kristen Carlson Accardi
2010-09-09 14:10   ` Denis Kenzior
2010-08-27 16:19 ` [PATCH 2/3] sim: Implement GetIcon Kristen Carlson Accardi
2010-09-09 14:16   ` Denis Kenzior
2010-08-27 16:19 ` [PATCH 3/3] test: add get-icon script Kristen Carlson Accardi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.