create an interface to allow a caller to request an icon by id
via dbus. Convert iidf files to xpm format and cache.
---
src/sim.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 216 insertions(+), 0 deletions(-)
diff --git a/src/sim.c b/src/sim.c
index d79c5e1..f24c40f 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 6
#define SIM_IIDF_CACHE_PATH SIM_CACHE_PATH ".%02x"
+#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 (*ofono_sim_get_image_cb_t)(int ok, const char *xpm, int xpm_len,
+ void *user_data);
+static void ofono_sim_get_image(struct ofono_sim *sim, unsigned char id,
+ ofono_sim_get_image_cb_t cb, gpointer user_data);
+
struct sim_file_op {
int id;
gboolean cache;
@@ -94,6 +101,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];
@@ -733,6 +741,50 @@ static DBusMessage *sim_enter_pin(DBusConnection *conn, DBusMessage
*msg,
return NULL;
}
+static void ofono_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);
+
+ ofono_sim_get_image(sim, id, ofono_sim_get_image_cb, sim);
+
+ return NULL;
+}
+
static DBusMessage *sim_reset_pin(DBusConnection *conn, DBusMessage *msg,
void *data)
{
@@ -785,6 +837,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 },
{ }
};
@@ -2392,3 +2446,165 @@ 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;
+ ofono_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,
+ OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ offset, image->clut_len,
+ sim_iidf_read_cb, image);
+
+ return;
+
+iidf_read_out:
+ g_free(image->image);
+ g_free(image);
+}
+
+static void ofono_sim_get_image(struct ofono_sim *sim, unsigned char id,
+ ofono_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);
+
+ fd = TFR(open(path, O_RDONLY));
+
+ g_free(path);
+
+ if (fd < 0)
+ goto read_image;
+
+ buffer = g_try_malloc0(image_length);
+
+ TFR(read(fd, buffer, image_length));
+
+ cb(1, buffer, image_length, user_data);
+
+ 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,
+ OFONO_SIM_FILE_STRUCTURE_TRANSPARENT,
+ data->iidf_offset, data->iid_len,
+ sim_iidf_read_cb, data);
+}
--
1.7.2.1