---
include/history.h | 1 +
src/sms.c | 132 ++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 106 insertions(+), 27 deletions(-)
diff --git a/include/history.h b/include/history.h
index c1c4aa1..756097e 100644
--- a/include/history.h
+++ b/include/history.h
@@ -35,6 +35,7 @@ enum ofono_history_sms_status {
OFONO_HISTORY_SMS_STATUS_PENDING,
OFONO_HISTORY_SMS_STATUS_SUBMITTED,
OFONO_HISTORY_SMS_STATUS_SUBMIT_FAILED,
+ OFONO_HISTORY_SMS_STATUS_SUBMIT_CANCELLED,
OFONO_HISTORY_SMS_STATUS_DELIVERED,
OFONO_HISTORY_SMS_STATUS_DELIVER_FAILED,
};
diff --git a/src/sms.c b/src/sms.c
index 9bb5c93..13acbcf 100644
--- a/src/sms.c
+++ b/src/sms.c
@@ -53,9 +53,11 @@ static gboolean tx_next(gpointer user_data);
static GSList *g_drivers = NULL;
enum message_state {
- MESSAGE_STATE_PENDING = 0,
+ MESSAGE_STATE_IDLE = 0,
+ MESSAGE_STATE_PENDING,
MESSAGE_STATE_SENT,
- MESSAGE_STATE_FAILED
+ MESSAGE_STATE_FAILED,
+ MESSAGE_STATE_CANCELLED
};
struct message {
@@ -111,6 +113,7 @@ struct tx_queue_entry {
ofono_sms_txq_submit_cb_t cb;
void *data;
ofono_destroy_func destroy;
+ enum message_state state;
};
static gboolean uuid_equal(gconstpointer v1, gconstpointer v2)
@@ -166,12 +169,16 @@ static int sms_bearer_from_string(const char *str)
static const char *message_state_to_string(enum message_state s)
{
switch (s) {
+ case MESSAGE_STATE_IDLE:
+ return "idle";
case MESSAGE_STATE_PENDING:
return "pending";
case MESSAGE_STATE_SENT:
return "sent";
case MESSAGE_STATE_FAILED:
return "failed";
+ case MESSAGE_STATE_CANCELLED:
+ return "cancelled";
}
return "invalid";
@@ -324,6 +331,14 @@ const char *__ofono_sms_message_path_from_uuid(struct ofono_sms
*sms,
return path;
}
+static void uuid_from_message_path(const char *path,
+ struct ofono_uuid *uuid)
+{
+ long len_uuid;
+ decode_hex_own_buf(path + strlen(path) - OFONO_SHA1_UUID_LEN * 2,
+ -1, &len_uuid, 0, uuid->uuid);
+}
+
static gboolean message_dbus_register(struct ofono_sms *sms, struct message *m)
{
DBusConnection *conn = ofono_dbus_get_connection();
@@ -424,7 +439,8 @@ static void message_set_state(struct ofono_sms *sms,
&state);
if (m->state == MESSAGE_STATE_SENT ||
- m->state == MESSAGE_STATE_FAILED) {
+ m->state == MESSAGE_STATE_FAILED ||
+ m->state == MESSAGE_STATE_CANCELLED) {
m->entry = NULL;
g_hash_table_remove(sms->messages, uuid);
@@ -737,10 +753,42 @@ static void tx_queue_entry_destroy_foreach(gpointer _entry, gpointer
unused)
tx_queue_entry_destroy(_entry);
}
+static void tx_queue_remove_entry(struct ofono_sms *sms,
+ struct tx_queue_entry *entry)
+{
+ struct ofono_modem *modem = __ofono_atom_get_modem(sms->atom);
+
+ if (entry->flags & OFONO_SMS_SUBMIT_FLAG_RECORD_HISTORY) {
+ enum ofono_history_sms_status hs;
+
+ switch (entry->state) {
+ case MESSAGE_STATE_SENT:
+ hs = OFONO_HISTORY_SMS_STATUS_SUBMITTED;
+ break;
+ case MESSAGE_STATE_FAILED:
+ hs = OFONO_HISTORY_SMS_STATUS_SUBMIT_FAILED;
+ break;
+ case MESSAGE_STATE_CANCELLED:
+ hs = OFONO_HISTORY_SMS_STATUS_SUBMIT_CANCELLED;
+ break;
+ default:
+ ofono_error("Unexpected state when removing sms entry");
+ return;
+ }
+
+ __ofono_history_sms_send_status(modem, &entry->uuid,
+ time(NULL), hs);
+ }
+
+ if (entry->flags & OFONO_SMS_SUBMIT_FLAG_EXPOSE_DBUS)
+ message_set_state(sms, &entry->uuid, entry->state);
+
+ tx_queue_entry_destroy(entry);
+}
+
static void tx_finished(const struct ofono_error *error, int mr, void *data)
{
struct ofono_sms *sms = data;
- struct ofono_modem *modem = __ofono_atom_get_modem(sms->atom);
struct tx_queue_entry *entry = g_queue_peek_head(sms->txq);
gboolean ok = error->type == OFONO_ERROR_TYPE_NO_ERROR;
@@ -755,6 +803,7 @@ static void tx_finished(const struct ofono_error *error, int mr, void
*data)
if (entry->retry < TXQ_MAX_RETRIES) {
DBG("Sending failed, retry in %d secs",
entry->retry * 5);
+ entry->state = MESSAGE_STATE_IDLE;
sms->tx_source = g_timeout_add_seconds(entry->retry * 5,
tx_next, sms);
return;
@@ -775,6 +824,7 @@ static void tx_finished(const struct ofono_error *error, int mr, void
*data)
entry->num_pdus);
if (entry->cur_pdu < entry->num_pdus) {
+ entry->state = MESSAGE_STATE_IDLE;
sms->tx_source = g_timeout_add(0, tx_next, sms);
return;
}
@@ -785,30 +835,12 @@ next_q:
if (entry->cb)
entry->cb(ok, entry->data);
- if (entry->flags & OFONO_SMS_SUBMIT_FLAG_RECORD_HISTORY) {
- enum ofono_history_sms_status hs;
-
- if (ok)
- hs = OFONO_HISTORY_SMS_STATUS_SUBMITTED;
- else
- hs = OFONO_HISTORY_SMS_STATUS_SUBMIT_FAILED;
-
- __ofono_history_sms_send_status(modem, &entry->uuid,
- time(NULL), hs);
- }
-
- if (entry->flags & OFONO_SMS_SUBMIT_FLAG_EXPOSE_DBUS) {
- enum message_state ms;
-
- if (ok)
- ms = MESSAGE_STATE_SENT;
- else
- ms = MESSAGE_STATE_FAILED;
-
- message_set_state(sms, &entry->uuid, ms);
- }
+ if (ok)
+ entry->state = MESSAGE_STATE_SENT;
+ else
+ entry->state = MESSAGE_STATE_FAILED;
- tx_queue_entry_destroy(entry);
+ tx_queue_remove_entry(sms, entry);
if (g_queue_peek_head(sms->txq)) {
DBG("Scheduling next");
@@ -837,6 +869,7 @@ static gboolean tx_next(gpointer user_data)
|| (entry->num_pdus - entry->cur_pdu) > 1)
send_mms = 1;
+ entry->state = MESSAGE_STATE_PENDING;
sms->driver->submit(sms, pdu->pdu, pdu->pdu_len, pdu->tpdu_len,
send_mms, tx_finished, sms);
@@ -1068,6 +1101,50 @@ static DBusMessage *sms_get_messages(DBusConnection *conn,
DBusMessage *msg,
return reply;
}
+static gint entry_compare_by_uuid(gconstpointer a, gconstpointer b)
+{
+ const struct tx_queue_entry *entry = a;
+ const char *uuid = b;
+
+ return strcmp((const char *) entry->uuid.uuid, uuid);
+}
+
+static DBusMessage *sms_cancel_message(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct ofono_sms *sms = data;
+ char *path;
+ struct ofono_uuid uuid;
+ GList *l;
+ struct tx_queue_entry *entry;
+ struct tx_queue_entry *entry_head;
+
+ if (sms->pending)
+ return __ofono_error_busy(msg);
+
+ if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID) == FALSE)
+ return __ofono_error_invalid_args(msg);
+
+ uuid_from_message_path(path, &uuid);
+
+ l = g_queue_find_custom(sms->txq, uuid.uuid, entry_compare_by_uuid);
+ if (l == NULL)
+ return __ofono_error_failed(msg);
+
+ entry = l->data;
+ entry_head = g_queue_peek_head(sms->txq);
+
+ if (entry == entry_head &&
+ entry_head->state != MESSAGE_STATE_IDLE)
+ return __ofono_error_failed(msg);
+
+ entry->state = MESSAGE_STATE_CANCELLED;
+ g_queue_remove(sms->txq, entry);
+ tx_queue_remove_entry(sms, entry);
+ return dbus_message_new_method_return(msg);
+}
+
static GDBusMethodTable sms_manager_methods[] = {
{ "GetProperties", "", "a{sv}",
sms_get_properties,
G_DBUS_METHOD_FLAG_ASYNC },
@@ -1076,6 +1153,7 @@ static GDBusMethodTable sms_manager_methods[] = {
{ "SendMessage", "ss", "o",
sms_send_message,
G_DBUS_METHOD_FLAG_ASYNC },
{ "GetMessages", "", "a(oa{sv})",
sms_get_messages },
+ { "CancelMessage", "o", "", sms_cancel_message
},
{ }
};
--
1.7.1