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); }