From 8d47b8f36d6f02fd48ee75023f0ccd3717af50d1 Mon Sep 17 00:00:00 2001 From: Denis Kenzior Date: Thu, 16 Jul 2009 17:17:54 -0500 Subject: [PATCH] Refactor phonebook code --- drivers/atmodem/phonebook.c | 569 +++++++++++++++++------------------- 1 file changed, 264 insertions(+), 305 deletions(-) diff --git a/drivers/atmodem/phonebook.c b/drivers/atmodem/phonebook.c index c2fd21bb..d5befc63 100644 --- a/drivers/atmodem/phonebook.c +++ b/drivers/atmodem/phonebook.c @@ -46,23 +46,14 @@ #define CHARSET_SUPPORT (CHARSET_UTF8 | CHARSET_UCS2) static const char *none_prefix[] = { NULL }; -static const char *entries_prefix[] = { "+CPBR:", NULL }; -static const char *charset_prefix[] = { "+CSCS:", NULL }; - -static void at_select_storage(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); -static void at_select_charset(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data); +static const char *cpbr_prefix[] = { "+CPBR:", NULL }; +static const char *cscs_prefix[] = { "+CSCS:", NULL }; +static const char *cpbs_prefix[] = { "+CPBS:", NULL }; struct pb_data { - const char *storage; int index_min, index_max; - int charset_origin; - const char *charset_origin_str; - int charset_current; - int charset_list; - int charset_need_restore; - int has_charset_info; + char *old_charset; + int supported; }; static struct pb_data *phonebook_create() @@ -73,28 +64,51 @@ static struct pb_data *phonebook_create() static void phonebook_destroy(struct pb_data *data) { - g_free((char *)data->charset_origin_str); + if (data->old_charset) + g_free(data->old_charset); g_free(data); } -static const char *ucs2_to_utf8(const char *str) +static char *ucs2_to_utf8(const char *str) { long len; unsigned char *ucs2; - const char *utf8; + char *utf8; ucs2 = decode_hex(str, -1, &len, 0); - utf8 = g_convert(ucs2, len, "UTF-8//TRANSLIT", "UCS-2BE", + utf8 = g_convert((char *)ucs2, len, "UTF-8//TRANSLIT", "UCS-2BE", NULL, NULL, NULL); g_free(ucs2); return utf8; } +static const char *best_charset(int supported) +{ + const char *charset = "Invalid"; + + if (supported & CHARSET_UCS2) + charset = "UCS2"; + + if (supported & CHARSET_UTF8) + charset = "UTF-8"; + + return charset; +} + static void at_cpbr_notify(GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; struct ofono_modem *modem = cbd->modem; struct at_data *at = ofono_modem_userdata(modem); GAtResultIter iter; + int current; + + dump_response("at_cbpr_notify", 1, result); + + if (at->pb->supported & CHARSET_UCS2) + current = CHARSET_UCS2; + + if (at->pb->supported & CHARSET_UTF8) + current = CHARSET_UTF8; g_at_result_iter_init(&iter, result); @@ -103,20 +117,14 @@ static void at_cpbr_notify(GAtResult *result, gpointer user_data) const char *number; int type; const char *text; - const char *text_utf8; int hidden = -1; const char *group = NULL; - const char *group_utf8 = NULL; const char *adnumber = NULL; int adtype = -1; const char *secondtext = NULL; - const char *secondtext_utf8 = NULL; const char *email = NULL; - const char *email_utf8 = NULL; const char *sip_uri = NULL; - const char *sip_uri_utf8 = NULL; const char *tel_uri = NULL; - const char *tel_uri_utf8 = NULL; if (!g_at_result_iter_next_number(&iter, &index)) continue; @@ -140,7 +148,14 @@ static void at_cpbr_notify(GAtResult *result, gpointer user_data) g_at_result_iter_next_string(&iter, &tel_uri); /* charset_current is either CHARSET_UCS2 or CHARSET_UTF8 */ - if (at->pb->charset_current & CHARSET_UCS2) { + if (current == CHARSET_UCS2) { + char *text_utf8; + char *group_utf8 = NULL; + char *secondtext_utf8 = NULL; + char *email_utf8 = NULL; + char *sip_uri_utf8 = NULL; + char *tel_uri_utf8 = NULL; + text_utf8 = ucs2_to_utf8(text); if (group) group_utf8 = ucs2_to_utf8(group); @@ -152,31 +167,47 @@ static void at_cpbr_notify(GAtResult *result, gpointer user_data) sip_uri_utf8 = ucs2_to_utf8(sip_uri); if (tel_uri) tel_uri_utf8 = ucs2_to_utf8(tel_uri); - } else { - text_utf8 = text; - group_utf8 = group; - secondtext_utf8 = secondtext; - email_utf8 = email; - sip_uri_utf8 = sip_uri; - tel_uri_utf8 = tel_uri; - } - ofono_phonebook_entry(cbd->modem, index, number, type, + ofono_phonebook_entry(cbd->modem, index, number, type, text_utf8, hidden, group_utf8, adnumber, adtype, secondtext_utf8, email_utf8, sip_uri_utf8, tel_uri_utf8); - if (at->pb->charset_current & CHARSET_UCS2) { - g_free((char *)text_utf8); - g_free((char *)group_utf8); - g_free((char *)secondtext_utf8); - g_free((char *)email_utf8); - g_free((char *)sip_uri_utf8); - g_free((char *)tel_uri_utf8); + g_free(text_utf8); + g_free(group_utf8); + g_free(secondtext_utf8); + g_free(email_utf8); + g_free(sip_uri_utf8); + g_free(tel_uri_utf8); + } else { + ofono_phonebook_entry(cbd->modem, index, number, type, + text, hidden, group, adnumber, + adtype, secondtext, email, + sip_uri, tel_uri); + } } } +static void export_failed(struct cb_data *cbd) +{ + struct ofono_modem *modem = cbd->modem; + struct at_data *at = ofono_modem_userdata(modem); + ofono_generic_cb_t cb = cbd->cb; + + { + DECLARE_FAILURE(error); + cb(&error, cbd->data); + } + + g_free(cbd); + + if (at->pb->old_charset) { + g_free(at->pb->old_charset); + at->pb->old_charset = NULL; + } +} + static void at_read_entries_cb(gboolean ok, GAtResult *result, gpointer user_data) { @@ -184,102 +215,94 @@ static void at_read_entries_cb(gboolean ok, GAtResult *result, struct ofono_modem *modem = cbd->modem; struct at_data *at = ofono_modem_userdata(modem); ofono_generic_cb_t cb = cbd->cb; - - if (at->pb->charset_current != at->pb->charset_origin) - at_select_charset(modem, cb, modem); - else { - struct ofono_error error; - decode_at_error(&error, g_at_result_final_response(result)); - cb(&error, cbd->data); - } -} - -static void at_read_entries(struct ofono_modem *modem, ofono_generic_cb_t cb, - void *data) -{ - struct at_data *at = ofono_modem_userdata(modem); - struct cb_data *cbd = cb_data_new(modem, cb, data); + const char *charset; + struct ofono_error error; char buf[32]; - if (!cbd) - goto error; + decode_at_error(&error, g_at_result_final_response(result)); + cb(&error, cbd->data); + g_free(cbd); - sprintf(buf, "AT+CPBR=%d,%d", at->pb->index_min, at->pb->index_max); - if (g_at_chat_send_listing(at->parser, buf, entries_prefix, - at_cpbr_notify, at_read_entries_cb, - cbd, g_free) > 0) - return; + charset = best_charset(at->pb->supported); -error: - if (cbd) - g_free(cbd); - - if (at->pb->charset_origin != at->pb->charset_current) - /* restore the charset */ - at_select_charset(modem, cb, modem); - else { - DECLARE_FAILURE(error); - cb(&error, data); + if (strcmp(at->pb->old_charset, charset)) { + sprintf(buf, "AT+CSCS=\"%s\"", at->pb->old_charset); + g_at_chat_send(at->parser, buf, none_prefix, NULL, NULL, NULL); } + + g_free(at->pb->old_charset); + at->pb->old_charset = NULL; } -static void at_select_charset_cb(gboolean ok, GAtResult *result, +static void at_read_entries(struct cb_data *cbd) +{ + struct ofono_modem *modem = cbd->modem; + struct at_data *at = ofono_modem_userdata(modem); + char buf[32]; + + sprintf(buf, "AT+CPBR=%d,%d", at->pb->index_min, at->pb->index_max); + if (g_at_chat_send_listing(at->parser, buf, cpbr_prefix, + at_cpbr_notify, at_read_entries_cb, + cbd, NULL) > 0) + return; + + /* If we get here, then most likely connection to the modem dropped + * and we can't really restore the charset anyway + */ + export_failed(cbd); +} + +static void at_set_charset_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct cb_data *cbd = user_data; + + if (!ok) { + export_failed(cbd); + return; + } + + at_read_entries(cbd); +} + +static void at_read_charset_cb(gboolean ok, GAtResult *result, gpointer user_data) { struct cb_data *cbd = user_data; struct ofono_modem *modem = cbd->modem; struct at_data *at = ofono_modem_userdata(modem); - ofono_generic_cb_t cb = cbd->cb; - struct ofono_error error; + GAtResultIter iter; + const char *charset; + char buf[32]; + + dump_response("at_read_charset_cb", ok, result); if (!ok) - goto out; + goto error; - at->pb->charset_need_restore ^= 1; - if (at->pb->charset_need_restore) { - at_read_entries(modem, cb, modem); + g_at_result_iter_init(&iter, result); + + if (!g_at_result_iter_next(&iter, "+CSCS:")) + goto error; + + g_at_result_iter_next_string(&iter, &charset); + + at->pb->old_charset = g_strdup(charset); + + charset = best_charset(at->pb->supported); + + if (!strcmp(at->pb->old_charset, charset)) { + at_read_entries(cbd); return; } -out: - decode_at_error(&error, g_at_result_final_response(result)); - cb(&error, cbd->data); - return; -} - -static void at_select_charset(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data) -{ - struct at_data *at = ofono_modem_userdata(modem); - struct cb_data *cbd = cb_data_new(modem, cb, data); - char buf[32]; - const char *charset; - - if (!cbd) - goto error; - - if (at->pb->charset_need_restore) - charset = at->pb->charset_origin_str; - else if (at->pb->charset_current == CHARSET_UTF8) - charset = "UTF-8"; - else - charset = "UCS2"; - - sprintf(buf, "AT+CSCS=%s", charset); + sprintf(buf, "AT+CSCS=\"%s\"", charset); if (g_at_chat_send(at->parser, buf, none_prefix, - at_select_charset_cb, cbd, g_free) > 0) + at_set_charset_cb, cbd, NULL) > 0) return; error: - if (cbd) - g_free(cbd); - - { - DECLARE_FAILURE(error); - if (at->pb->charset_need_restore) - ofono_error("Phonebook: character can't be restored!"); - cb(&error, data); - } + export_failed(cbd); } static void at_list_indices_cb(gboolean ok, GAtResult *result, @@ -288,7 +311,6 @@ static void at_list_indices_cb(gboolean ok, GAtResult *result, struct cb_data *cbd = user_data; struct ofono_modem *modem = cbd->modem; struct at_data *at = ofono_modem_userdata(modem); - ofono_generic_cb_t cb = cbd->cb; GAtResultIter iter; if (!ok) @@ -311,41 +333,12 @@ static void at_list_indices_cb(gboolean ok, GAtResult *result, if (!g_at_result_iter_close_list(&iter)) goto error; - if (at->pb->charset_origin != at->pb->charset_current) - at_select_charset(modem, cb, modem); - else - at_read_entries(modem, cb, modem); - - return; - -error: - { - DECLARE_FAILURE(e); - cb(&e, cbd->data); - } -} - -static void at_list_indices(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data) -{ - struct at_data *at = ofono_modem_userdata(modem); - struct cb_data *cbd = cb_data_new(modem, cb, data); - - if (!cbd) - goto error; - - if (g_at_chat_send(at->parser, "AT+CPBR=?", entries_prefix, - at_list_indices_cb, cbd, g_free) > 0) + if (g_at_chat_send(at->parser, "AT+CSCS?", cscs_prefix, + at_read_charset_cb, cbd, NULL) > 0) return; error: - if (cbd) - g_free(cbd); - - { - DECLARE_FAILURE(error); - cb(&error, data); - } + export_failed(cbd); } static void at_select_storage_cb(gboolean ok, GAtResult *result, @@ -353,18 +346,22 @@ static void at_select_storage_cb(gboolean ok, GAtResult *result, { struct cb_data *cbd = user_data; struct ofono_modem *modem = cbd->modem; - ofono_generic_cb_t cb = cbd->cb; + struct at_data *at = ofono_modem_userdata(modem); - if (!ok) { - DECLARE_FAILURE(error); - cb(&error, cbd->data); + dump_response("at_select_storage_cb", ok, result); + + if (!ok) + goto error; + + if (g_at_chat_send(at->parser, "AT+CPBR=?", cpbr_prefix, + at_list_indices_cb, cbd, NULL) > 0) return; - } - at_list_indices(modem, cb, modem); +error: + export_failed(cbd); } -static void at_select_storage(struct ofono_modem *modem, +static void at_export_entries(struct ofono_modem *modem, const char *storage, ofono_generic_cb_t cb, void *data) { struct at_data *at = ofono_modem_userdata(modem); @@ -374,162 +371,15 @@ static void at_select_storage(struct ofono_modem *modem, if (!cbd) goto error; - sprintf(buf, "AT+CPBS=%s", at->pb->storage); + sprintf(buf, "AT+CPBS=\"%s\"", storage); if (g_at_chat_send(at->parser, buf, none_prefix, - at_select_storage_cb, cbd, g_free) > 0) + at_select_storage_cb, cbd, NULL) > 0) return; error: if (cbd) g_free(cbd); - { - DECLARE_FAILURE(error); - cb(&error, cbd->data); - } -} - -static void at_read_charset_cb(gboolean ok, GAtResult *result, - gpointer user_data) -{ - struct cb_data *cbd = user_data; - struct ofono_modem *modem = cbd->modem; - struct at_data *at = ofono_modem_userdata(modem); - ofono_generic_cb_t cb = cbd->cb; - GAtResultIter iter; - const char *charset; - - if (!ok) - goto error; - - g_at_result_iter_init(&iter, result); - - if (!g_at_result_iter_next(&iter, "+CSCS:")) - goto error; - - g_at_result_iter_next_string(&iter, &charset); - at->pb->charset_origin_str = g_strdup(charset); - if (!strcmp(charset, "UCS2")) - at->pb->charset_origin = CHARSET_UCS2; - else if (!strcmp(charset, "UTF-8")) - at->pb->charset_origin = CHARSET_UTF8; - - if (at->pb->charset_origin & CHARSET_SUPPORT) - at->pb->charset_current = at->pb->charset_origin; - else if (at->pb->charset_list & CHARSET_UTF8) - at->pb->charset_current = CHARSET_UTF8; - else - at->pb->charset_current = CHARSET_UCS2; - - at_select_storage(modem, cb, modem); - return; - -error: - ofono_error("Phonebook: at_read_charset_cb failed"); - { - DECLARE_FAILURE(error); - cb(&error, cbd->data); - } -} - -static void at_read_charset(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data) -{ - struct at_data *at = ofono_modem_userdata(modem); - struct cb_data *cbd = cb_data_new(modem, cb, data); - - if (g_at_chat_send(at->parser, "AT+CSCS?", charset_prefix, - at_read_charset_cb, cbd, g_free) > 0) - return; - - { - DECLARE_FAILURE(error); - cb(&error, data); - } -} - -static gboolean is_valid_charset_list(struct pb_data *pb) -{ - if (!(pb->charset_list & CHARSET_SUPPORT)) { - ofono_error("Phonebook: not a valid charset_list"); - return FALSE; - } - - return TRUE; -} - -static void at_list_charsets_cb(gboolean ok, GAtResult *result, - gpointer user_data) -{ - struct cb_data *cbd = user_data; - struct ofono_modem *modem = cbd->modem; - struct at_data *at = ofono_modem_userdata(modem); - ofono_generic_cb_t cb = cbd->cb; - GAtResultIter iter; - const char *charset; - - if (!ok) - goto error; - - g_at_result_iter_init(&iter, result); - if (!g_at_result_iter_next(&iter, "+CSCS:")) - goto error; - - while (g_at_result_iter_next_string(&iter, &charset)) { - if (!strcmp(charset, "UTF-8")) - at->pb->charset_list |= CHARSET_UTF8; - else if (!strcmp(charset, "UCS2")) - at->pb->charset_list |= CHARSET_UCS2; - } - - if (!is_valid_charset_list(at->pb)) - goto error; - - at_read_charset(modem, cb, modem); - return; - -error: - ofono_error("Phonebook: at_list_charsets_cb failed"); - { - DECLARE_FAILURE(error); - cb(&error, cbd->data); - } -} - -static void at_list_charsets(struct ofono_modem *modem, - ofono_generic_cb_t cb, void *data) -{ - struct at_data *at = ofono_modem_userdata(modem); - struct cb_data *cbd = cb_data_new(modem, cb, data); - - if (g_at_chat_send(at->parser, "AT+CSCS=?", charset_prefix, - at_list_charsets_cb, cbd, g_free) > 0) - return; - - { - DECLARE_FAILURE(error); - cb(&error, data); - } -} - -static void at_export_entries(struct ofono_modem *modem, const char *storage, - ofono_generic_cb_t cb, void *data) -{ - struct at_data *at = ofono_modem_userdata(modem); - - at->pb->storage = storage; - - if (at->pb->has_charset_info) { - if (!is_valid_charset_list(at->pb)) - goto error; - at_select_storage(modem, cb, modem); - } else { - at->pb->has_charset_info = 1; - at_list_charsets(modem, cb, data); - } - return; - -error: { DECLARE_FAILURE(error); cb(&error, data); @@ -540,12 +390,121 @@ static struct ofono_phonebook_ops ops = { .export_entries = at_export_entries }; +static void phonebook_not_supported(struct ofono_modem *modem) +{ + struct at_data *at = ofono_modem_userdata(modem); + + ofono_error("Phonebook not supported by this modem. If this is in " + "error please submit patches to support this hardware"); + if (at->pb) { + phonebook_destroy(at->pb); + at->pb = NULL; + } +} + +static void at_list_storages_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct ofono_modem *modem = user_data; + gboolean sm_supported = FALSE; + gboolean me_supported = FALSE; + gboolean in_list = FALSE; + GAtResultIter iter; + const char *storage; + + dump_response("at_list_storages_cb", ok, result); + + if (!ok) + goto error; + + g_at_result_iter_init(&iter, result); + if (!g_at_result_iter_next(&iter, "+CPBS:")) + goto error; + + /* Some modems don't report CPBS in a proper list */ + if (g_at_result_iter_open_list(&iter)) + in_list = TRUE; + + while (g_at_result_iter_next_string(&iter, &storage)) { + if (!strcmp(storage, "ME")) + me_supported = TRUE; + else if (!strcmp(storage, "SM")) + sm_supported = TRUE; + } + + if (in_list && !g_at_result_iter_close_list(&iter)) + goto error; + + if (!me_supported && !sm_supported) + goto error; + + ofono_phonebook_register(modem, &ops); + return; + +error: + phonebook_not_supported(modem); +} + +static void at_list_charsets_cb(gboolean ok, GAtResult *result, + gpointer user_data) +{ + struct ofono_modem *modem = user_data; + struct at_data *at = ofono_modem_userdata(modem); + gboolean in_list = FALSE; + GAtResultIter iter; + const char *charset; + + dump_response("at_list_charsets_cb", ok, result); + + if (!ok) + goto error; + + g_at_result_iter_init(&iter, result); + if (!g_at_result_iter_next(&iter, "+CSCS:")) + goto error; + + /* Some modems don't report CPBS in a proper list */ + if (g_at_result_iter_open_list(&iter)) + in_list = TRUE; + + while (g_at_result_iter_next_string(&iter, &charset)) { + if (!strcmp(charset, "UTF-8")) + at->pb->supported |= CHARSET_UTF8; + else if (!strcmp(charset, "UCS2")) + at->pb->supported |= CHARSET_UCS2; + } + + if (in_list && g_at_result_iter_close_list(&iter)) + goto error; + + if (!(at->pb->supported & CHARSET_SUPPORT)) + goto error; + + if (g_at_chat_send(at->parser, "AT+CPBS=?", cpbs_prefix, + at_list_storages_cb, modem, NULL) > 0) + return; + +error: + phonebook_not_supported(modem); +} + +static void at_list_charsets(struct ofono_modem *modem) +{ + struct at_data *at = ofono_modem_userdata(modem); + + if (g_at_chat_send(at->parser, "AT+CSCS=?", cscs_prefix, + at_list_charsets_cb, modem, NULL) > 0) + return; + + phonebook_not_supported(modem); +} + void at_phonebook_init(struct ofono_modem *modem) { struct at_data *at = ofono_modem_userdata(modem); - ofono_phonebook_register(modem, &ops); at->pb = phonebook_create(); + at_list_charsets(modem); } void at_phonebook_exit(struct ofono_modem *modem)