isimodem: Adapt and refactor phonebook driver

This commit is contained in:
Aki Niemi 2010-11-14 18:34:15 +02:00
parent 90f31a1cb9
commit 332afc9cbc
1 changed files with 135 additions and 136 deletions

View File

@ -30,6 +30,7 @@
#include <glib.h>
#include <gisi/client.h>
#include <gisi/message.h>
#include <gisi/iter.h>
#include <ofono/log.h>
@ -46,9 +47,80 @@ struct pb_data {
GIsiClient *client;
};
static int decode_read_response(const unsigned char *msg, size_t len,
struct ofono_phonebook *pb)
struct read_resp {
uint8_t service_type;
uint8_t sb_count;
uint8_t data[];
};
static gboolean parse_adn(GIsiSubBlockIter *iter, uint16_t *location,
char **name, char **number)
{
uint8_t namelen;
uint8_t numlen;
if (!g_isi_sb_iter_get_word(iter, location, 4) ||
!g_isi_sb_iter_get_byte(iter, &namelen, 6) ||
!g_isi_sb_iter_get_byte(iter, &numlen, 7))
return FALSE;
if (!g_isi_sb_iter_get_alpha_tag(iter, name, namelen * 2, 8))
return FALSE;
if (!g_isi_sb_iter_get_alpha_tag(iter, number, numlen * 2,
8 + namelen * 2)) {
g_free(*name);
return FALSE;
}
return TRUE;
}
static gboolean parse_sne(GIsiSubBlockIter *iter, char **sne)
{
uint8_t len;
if (!g_isi_sb_iter_get_byte(iter, &len, 6))
return FALSE;
if (!g_isi_sb_iter_get_alpha_tag(iter, sne, len * 2, 8))
return FALSE;
return TRUE;
}
static gboolean parse_anr(GIsiSubBlockIter *iter, char **anr)
{
uint8_t len;
if (!g_isi_sb_iter_get_byte(iter, &len, 6))
return FALSE;
if (!g_isi_sb_iter_get_alpha_tag(iter, anr, len * 2, 8))
return FALSE;
return TRUE;
}
static gboolean parse_email(GIsiSubBlockIter *iter, char **email)
{
uint8_t len;
if (!g_isi_sb_iter_get_byte(iter, &len, 6))
return FALSE;
if (!g_isi_sb_iter_get_alpha_tag(iter, email, len * 2, 8))
return FALSE;
return TRUE;
}
static gboolean decode_response(const GIsiMessage *msg, uint16_t *location,
void *data)
{
struct ofono_phonebook *pb = data;
const struct read_resp *resp = g_isi_msg_data(msg);
size_t len = g_isi_msg_data_len(msg);
GIsiSubBlockIter iter;
char *name = NULL;
@ -57,84 +129,48 @@ static int decode_read_response(const unsigned char *msg, size_t len,
char *anr = NULL;
char *email = NULL;
int location = -1;
guint8 status = 0;
uint8_t status = 0;
gboolean success = FALSE;
if (len < 3 || msg[0] != SIM_PB_RESP_SIM_PB_READ)
goto error;
if (g_isi_msg_id(msg) != SIM_PB_RESP_SIM_PB_READ ||
resp == NULL || len < sizeof(struct read_resp) ||
resp->service_type != SIM_PB_READ)
return FALSE;
if (msg[1] != SIM_PB_READ)
goto error;
for (g_isi_sb_iter_init_full(&iter, msg, len, 3, TRUE, msg[2]);
g_isi_sb_iter_is_valid(&iter);
g_isi_sb_iter_next(&iter)) {
for (g_isi_sb_iter_init_full(&iter, msg, 2, TRUE, resp->sb_count);
g_isi_sb_iter_is_valid(&iter);
g_isi_sb_iter_next(&iter)) {
switch (g_isi_sb_iter_get_id(&iter)) {
case SIM_PB_ADN:
case SIM_PB_ADN: {
guint16 loc;
guint8 namelen;
guint8 numberlen;
if (!g_isi_sb_iter_get_word(&iter, &loc, 4) ||
!g_isi_sb_iter_get_byte(&iter, &namelen, 6) ||
!g_isi_sb_iter_get_byte(&iter, &numberlen, 7))
if (!parse_adn(&iter, location, &name, &number))
goto error;
if (!g_isi_sb_iter_get_alpha_tag(&iter, &name,
namelen * 2, 8))
goto error;
if (!g_isi_sb_iter_get_alpha_tag(&iter, &number,
numberlen * 2, 8 + namelen * 2))
goto error;
location = loc;
success = TRUE;
break;
}
case SIM_PB_SNE: {
guint8 snelen;
case SIM_PB_SNE:
if (!g_isi_sb_iter_get_byte(&iter, &snelen, 6))
goto error;
if (!g_isi_sb_iter_get_alpha_tag(&iter, &sne,
snelen * 2, 8))
if (!parse_sne(&iter, &sne))
goto error;
break;
}
case SIM_PB_ANR: {
guint8 anrlen;
case SIM_PB_ANR:
if (!g_isi_sb_iter_get_byte(&iter, &anrlen, 6))
goto error;
if (!g_isi_sb_iter_get_alpha_tag(&iter, &anr,
anrlen * 2, 8))
if (!parse_anr(&iter, &anr))
goto error;
break;
}
case SIM_PB_EMAIL: {
guint8 emaillen;
case SIM_PB_EMAIL:
if (!g_isi_sb_iter_get_byte(&iter, &emaillen, 6))
goto error;
if (!g_isi_sb_iter_get_alpha_tag(&iter, &email,
emaillen * 2, 8))
if (!parse_email(&iter, &email))
goto error;
break;
}
case SIM_PB_STATUS:
if (!g_isi_sb_iter_get_byte(&iter, &status, 4))
goto error;
break;
default:
@ -145,15 +181,9 @@ static int decode_read_response(const unsigned char *msg, size_t len,
}
}
if (status != SIM_SERV_OK) {
DBG("Request failed: %s (0x%02X)",
sim_isi_cause_name(status), status);
goto error;
}
ofono_phonebook_entry(pb, -1, number, -1, name, -1, NULL,
anr, -1, sne, email, NULL, NULL);
if (status == SIM_SERV_OK)
ofono_phonebook_entry(pb, -1, number, -1, name, -1, NULL,
anr, -1, sne, email, NULL, NULL);
error:
g_free(name);
g_free(number);
@ -161,15 +191,15 @@ error:
g_free(anr);
g_free(email);
return location;
return success;
}
static void read_next_entry(GIsiClient *client, int location,
GIsiResponseFunc read_cb,
struct isi_cb_data *cbd)
static void read_next_entry(GIsiClient *client, uint16_t location,
GIsiNotifyFunc notify, void *data)
{
struct isi_cb_data *cbd = data;
ofono_phonebook_cb_t cb = cbd->cb;
const unsigned char msg[] = {
const uint8_t msg[] = {
SIM_PB_REQ_SIM_PB_READ,
SIM_PB_READ,
2, /* number of subblocks */
@ -195,8 +225,8 @@ static void read_next_entry(GIsiClient *client, int location,
if (cbd == NULL)
goto error;
if (g_isi_request_make(client, msg, sizeof(msg), SIM_TIMEOUT,
read_cb, cbd))
if (g_isi_client_send(client, msg, sizeof(msg), SIM_TIMEOUT,
notify, cbd, NULL))
return;
error:
@ -204,35 +234,28 @@ error:
g_free(cbd);
}
static gboolean read_resp_cb(GIsiClient *client,
const void *restrict data, size_t len,
uint16_t object, void *opaque)
static void read_resp_cb(const GIsiMessage *msg, void *data)
{
const unsigned char *msg = data;
struct isi_cb_data *cbd = opaque;
ofono_phonebook_cb_t cb = cbd->cb;
int location;
struct isi_cb_data *cbd = data;
struct ofono_phonebook *pb = cbd->user;
struct pb_data *pbd = ofono_phonebook_get_data(pb);
if (!msg) {
DBG("ISI client error: %d", g_isi_client_error(client));
goto error;
ofono_phonebook_cb_t cb = cbd->cb;
uint16_t location;
if (g_isi_msg_error(msg) < 0) {
CALLBACK_WITH_FAILURE(cb, cbd->data);
g_free(cbd);
return;
}
location = decode_read_response(data, len, cbd->user);
if (location != -1) {
read_next_entry(client, location, read_resp_cb, cbd);
return TRUE;
if (decode_response(msg, &location, cbd->user)) {
read_next_entry(pbd->client, location, read_resp_cb, cbd);
return;
}
CALLBACK_WITH_SUCCESS(cb, cbd->data);
goto out;
error:
CALLBACK_WITH_FAILURE(cb, cbd->data);
out:
g_free(cbd);
return TRUE;
}
static void isi_export_entries(struct ofono_phonebook *pb, const char *storage,
@ -240,7 +263,7 @@ static void isi_export_entries(struct ofono_phonebook *pb, const char *storage,
{
struct pb_data *pbd = ofono_phonebook_get_data(pb);
struct isi_cb_data *cbd = isi_cb_data_new(pb, cb, data);
const unsigned char msg[] = {
const uint8_t msg[] = {
SIM_PB_REQ_SIM_PB_READ,
SIM_PB_READ,
2, /* number of subblocks */
@ -259,65 +282,41 @@ static void isi_export_entries(struct ofono_phonebook *pb, const char *storage,
0, 0 /* filler */
};
if (cbd == NULL || pbd == NULL)
if (cbd == NULL || pbd == NULL || strcmp(storage, "SM") != 0)
goto error;
if (strcmp(storage, "SM"))
goto error;
if (g_isi_request_make(pbd->client, msg, sizeof(msg), SIM_TIMEOUT,
read_resp_cb, cbd))
if (g_isi_client_send(pbd->client, msg, sizeof(msg), SIM_TIMEOUT,
read_resp_cb, cbd, NULL))
return;
error:
if (cbd)
g_free(cbd);
CALLBACK_WITH_FAILURE(cb, data);
g_free(cbd);
}
static gboolean isi_phonebook_register(gpointer user)
static void reachable_cb(const GIsiMessage *msg, void *data)
{
struct ofono_phonebook *pb = user;
struct ofono_phonebook *pb = data;
if (g_isi_msg_error(msg) < 0)
return;
ISI_VERSION_DBG(msg);
ofono_phonebook_register(pb);
return FALSE;
}
static void reachable_cb(GIsiClient *client, gboolean alive, uint16_t object,
void *opaque)
{
struct ofono_phonebook *pb = opaque;
const char *debug = NULL;
if (!alive) {
DBG("Unable to bootstrap phonebook driver");
return;
}
DBG("%s (v%03d.%03d) reachable",
pn_resource_name(g_isi_client_resource(client)),
g_isi_version_major(client),
g_isi_version_minor(client));
debug = getenv("OFONO_ISI_DEBUG");
if (debug && (strcmp(debug, "all") == 0 || strcmp(debug, "sim") == 0))
g_isi_client_set_debug(client, sim_debug, NULL);
g_idle_add(isi_phonebook_register, pb);
}
static int isi_phonebook_probe(struct ofono_phonebook *pb, unsigned int vendor,
void *user)
{
GIsiModem *idx = user;
struct pb_data *data = g_try_new0(struct pb_data, 1);
GIsiModem *modem = user;
struct pb_data *data;
data = g_try_new0(struct pb_data, 1);
if (data == NULL)
return -ENOMEM;
data->client = g_isi_client_create(idx, PN_SIM);
data->client = g_isi_client_create(modem, PN_SIM);
if (data->client == NULL) {
g_free(data);
return -ENOMEM;
@ -325,8 +324,7 @@ static int isi_phonebook_probe(struct ofono_phonebook *pb, unsigned int vendor,
ofono_phonebook_set_data(pb, data);
if (!g_isi_verify(data->client, reachable_cb, pb))
DBG("Unable to verify reachability");
g_isi_client_verify(data->client, reachable_cb, pb, NULL);
return 0;
}
@ -335,10 +333,11 @@ static void isi_phonebook_remove(struct ofono_phonebook *pb)
{
struct pb_data *data = ofono_phonebook_get_data(pb);
ofono_phonebook_set_data(pb, NULL);
if (data == NULL)
return;
ofono_phonebook_set_data(pb, NULL);
g_isi_client_destroy(data->client);
g_free(data);
}