mirror of git://git.sysmocom.de/ofono
isimodem: Adapt and refactor phonebook driver
This commit is contained in:
parent
90f31a1cb9
commit
332afc9cbc
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue