From 36d0c8451fdd5ae6516e1d787336456cfb5f5ab7 Mon Sep 17 00:00:00 2001 From: Andrzej Zaborowski Date: Fri, 4 Sep 2009 16:48:03 +0200 Subject: [PATCH] Read messages left over in ME storage on startup. On modems that don't support +CMT (or for class 2 SMSes) the messages are stored in the modem and then read and deleted from there in two separate steps with no warranty that deletion succeeds or (more likely) power is cut before the deletion happens. Over time the memory may become full and if we don't want to deal with this condition we need to check on startup if there are messages we haven't deleted. We can't differentiate between those messages and those the user already had on the SIM / modem before installing ofono or switching phones, so we might want to deliver messages with REC READ status with some kind of indication that these are potentially old so the UI doesn't emit spurious alerts. We don't do this now and just deliver as usual. --- drivers/atmodem/sms.c | 125 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/drivers/atmodem/sms.c b/drivers/atmodem/sms.c index 2e03ff2e..11d2ff20 100644 --- a/drivers/atmodem/sms.c +++ b/drivers/atmodem/sms.c @@ -48,10 +48,12 @@ static const char *cmgf_prefix[] = { "+CMGF:", NULL }; static const char *cpms_prefix[] = { "+CPMS:", NULL }; static const char *cnmi_prefix[] = { "+CNMI:", NULL }; static const char *cmgs_prefix[] = { "+CMGS:", NULL }; +static const char *cmgl_prefix[] = { "+CMGL:", NULL }; static const char *none_prefix[] = { NULL }; static gboolean set_cmgf(gpointer user_data); static gboolean set_cpms(gpointer user_data); +static void at_cmgl_set_cpms(struct ofono_sms *sms, int store); #define MAX_CMGF_RETRIES 10 #define MAX_CPMS_RETRIES 10 @@ -499,6 +501,123 @@ err: ofono_error("Unable to parse CMTI notification"); } +static void at_cmgl_done(struct ofono_sms *sms) +{ + struct sms_data *data = ofono_sms_get_data(sms); + + if (data->incoming == MT_STORE && data->store == ME_STORE) + at_cmgl_set_cpms(sms, SM_STORE); +} + +static void at_cmgl_notify(GAtResult *result, gpointer user_data) +{ + struct ofono_sms *sms = user_data; + struct sms_data *data = ofono_sms_get_data(sms); + GAtResultIter iter; + const char *hexpdu; + unsigned char pdu[164]; + long pdu_len; + int tpdu_len; + int index; + int status; + char buf[16]; + + dump_response("at_cmgl_notify", TRUE, result); + + g_at_result_iter_init(&iter, result); + + while (g_at_result_iter_next(&iter, "+CMGL:")) { + if (!g_at_result_iter_next_number(&iter, &index)) + goto err; + + if (!g_at_result_iter_next_number(&iter, &status)) + goto err; + + if (!g_at_result_iter_skip_next(&iter)) + goto err; + + if (!g_at_result_iter_next_number(&iter, &tpdu_len)) + goto err; + + /* Only MT messages */ + if (status != 0 && status != 1) + continue; + + hexpdu = g_at_result_pdu(result); + + ofono_debug("Found an old SMS PDU: %s, with len: %d", + hexpdu, tpdu_len); + + decode_hex_own_buf(hexpdu, -1, &pdu_len, 0, pdu); + ofono_sms_deliver_notify(sms, pdu, pdu_len, tpdu_len); + + /* We don't buffer SMS on the SIM/ME, send along a CMGD */ + sprintf(buf, "AT+CMGD=%d", index); + g_at_chat_send(data->chat, buf, none_prefix, + at_cmgd_cb, NULL, NULL); + } + return; + +err: + ofono_error("Unable to parse CMGL response"); +} + +static void at_cmgl_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct ofono_sms *sms = user_data; + + if (!ok) + ofono_error("Initial listing SMS storage failed!"); + + at_cmgl_done(sms); +} + +static void at_cmgl_cpms_cb(gboolean ok, GAtResult *result, gpointer user_data) +{ + struct cpms_request *req = user_data; + struct ofono_sms *sms = req->sms; + struct sms_data *data = ofono_sms_get_data(sms); + + if (!ok) { + ofono_error("Initial CPMS request failed"); + at_cmgl_done(sms); + return; + } + + data->store = req->store; + + g_at_chat_send_pdu_listing(data->chat, "AT+CMGL=4", cmgl_prefix, + at_cmgl_notify, at_cmgl_cb, sms, NULL); +} + +static void at_cmgl_set_cpms(struct ofono_sms *sms, int store) +{ + struct sms_data *data = ofono_sms_get_data(sms); + + if (store == data->store) { + struct cpms_request req; + + req.sms = sms; + req.store = store; + + at_cmgl_cpms_cb(TRUE, NULL, &req); + } else { + char buf[128]; + const char *readwrite = storages[store]; + const char *incoming = storages[data->incoming]; + struct cpms_request *req = g_new(struct cpms_request, 1); + + req->sms = sms; + req->store = store; + + sprintf(buf, "AT+CPMS=\"%s\",\"%s\",\"%s\"", + readwrite, readwrite, incoming); + + g_at_chat_send(data->chat, buf, cpms_prefix, at_cmgl_cpms_cb, + req, g_free); + } +} + static void at_sms_initialized(struct ofono_sms *sms) { struct sms_data *data = ofono_sms_get_data(sms); @@ -516,6 +635,12 @@ static void at_sms_initialized(struct ofono_sms *sms) g_at_chat_register(data->chat, "+CMGR:", at_cmgr_notify, TRUE, sms, NULL); + /* Inspect and free the incoming SMS storage */ + if (data->incoming == MT_STORE) + at_cmgl_set_cpms(sms, ME_STORE); + else + at_cmgl_set_cpms(sms, data->incoming); + ofono_sms_register(sms); }