summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenis Kenzior <denkenz@gmail.com>2009-06-19 21:11:32 -0500
committerDenis Kenzior <denkenz@gmail.com>2009-06-19 21:15:02 -0500
commit130f18a0b6e903125bc20adf6a0c24d0c783fb04 (patch)
tree7e0a4fa90075f08b45e6222ca4f22d295c2ec125
parentc91ae28018ee40c8d46e3450b0a3c53647c43060 (diff)
downloadofono-130f18a0b6e903125bc20adf6a0c24d0c783fb04.tar.bz2
Add SMS Sending Support
-rw-r--r--src/driver.h5
-rw-r--r--src/sms.c177
2 files changed, 182 insertions, 0 deletions
diff --git a/src/driver.h b/src/driver.h
index e48717d6..3eade284 100644
--- a/src/driver.h
+++ b/src/driver.h
@@ -174,6 +174,8 @@ typedef void (*ofono_imsi_cb_t)(const struct ofono_error *error,
typedef void (*ofono_sca_query_cb_t)(const struct ofono_error *error,
const struct ofono_phone_number *ph,
void *data);
+typedef void (*ofono_sms_submit_cb_t)(const struct ofono_error *error, int mr,
+ void *data);
struct ofono_modem_attribute_ops {
void (*query_manufacturer)(struct ofono_modem *modem,
@@ -396,6 +398,9 @@ struct ofono_sms_ops {
void (*sca_set)(struct ofono_modem *modem,
const struct ofono_phone_number *sca,
ofono_generic_cb_t cb, void *data);
+ void (*submit)(struct ofono_modem *modem, unsigned char *pdu,
+ int pdu_len, int tpdu_len, gboolean mms,
+ ofono_sms_submit_cb_t cb, void *data);
};
int ofono_sms_manager_register(struct ofono_modem *modem,
diff --git a/src/sms.c b/src/sms.c
index 717b4f2f..54e5db2b 100644
--- a/src/sms.c
+++ b/src/sms.c
@@ -44,12 +44,23 @@
#define SMS_MANAGER_FLAG_CACHED 0x1
+static gboolean tx_next(gpointer user_data);
+
struct sms_manager_data {
struct ofono_sms_ops *ops;
int flags;
DBusMessage *pending;
struct ofono_phone_number sca;
struct sms_assembly *assembly;
+ guint ref;
+ GQueue *txq;
+ time_t last_mms;
+};
+
+struct pending_pdu {
+ unsigned char pdu[176];
+ int tpdu_len;
+ int pdu_len;
};
static struct sms_manager_data *sms_manager_create()
@@ -59,8 +70,10 @@ static struct sms_manager_data *sms_manager_create()
sms = g_new0(struct sms_manager_data, 1);
sms->sca.type = 129;
+ sms->ref = 1;
sms->assembly = sms_assembly_new();
+ sms->txq = g_queue_new();
return sms;
}
@@ -75,6 +88,12 @@ static void sms_manager_destroy(gpointer userdata)
data->assembly = NULL;
}
+ if (data->txq) {
+ g_queue_foreach(data->txq, (GFunc)g_free, NULL);
+ g_queue_free(data->txq);
+ data->txq = NULL;
+ }
+
g_free(data);
}
@@ -263,11 +282,169 @@ static DBusMessage *sms_set_property(DBusConnection *conn, DBusMessage *msg,
return dbus_gsm_invalid_args(msg);
}
+static void tx_finished(const struct ofono_error *error, int mr, void *data)
+{
+ struct ofono_modem *modem = data;
+ struct sms_manager_data *sms = modem->sms_manager;
+ struct pending_pdu *pdu;
+
+ ofono_debug("tx_finished");
+
+ if (error->type != OFONO_ERROR_TYPE_NO_ERROR) {
+ ofono_debug("Sending failed, retrying in 5 seconds...");
+ g_timeout_add_seconds(5, tx_next, data);
+ return;
+ }
+
+ pdu = g_queue_pop_head(sms->txq);
+ g_free(pdu);
+
+ ofono_debug("Peeking in the queue");
+
+ if (g_queue_peek_head(sms->txq)) {
+ ofono_debug("Scheduling next");
+ g_timeout_add(0, tx_next, sms);
+ }
+}
+
+static gboolean tx_next(gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct sms_manager_data *sms = modem->sms_manager;
+ time_t ts;
+ gboolean send_mms = FALSE;
+ struct pending_pdu *pdu = g_queue_peek_head(sms->txq);
+ char *encoded_pdu;
+ struct ofono_error error;
+
+ error.type = OFONO_ERROR_TYPE_NO_ERROR;
+
+ ofono_debug("tx_next: %p", pdu);
+
+ if (!pdu)
+ return FALSE;
+
+ ts = time(NULL);
+
+ if ((g_queue_get_length(sms->txq) > 1) &&
+ ((ts - sms->last_mms) > 60))
+ send_mms = TRUE;
+
+ sms->ops->submit(modem, pdu->pdu, pdu->pdu_len, pdu->tpdu_len, send_mms,
+ tx_finished, modem);
+
+ return FALSE;
+}
+
+static void set_ref_and_to(GSList *msg_list, guint16 ref, int offset,
+ const char *to)
+{
+ GSList *l;
+ struct sms *sms;
+
+ for (l = msg_list; l; l = l->next) {
+ sms = l->data;
+
+ if (offset != 0) {
+ sms->submit.ud[offset] = (ref & 0xf0) >> 8;
+ sms->submit.ud[offset+1] = (ref & 0x0f);
+ }
+
+ sms_address_from_string(&sms->submit.daddr, to);
+ }
+}
+
+static void append_tx_queue(struct ofono_modem *modem, GSList *msg_list)
+{
+ struct sms_manager_data *sms = modem->sms_manager;
+ struct sms *s;
+ GSList *l;
+ struct pending_pdu *pdu;
+ gboolean start = FALSE;
+
+ if (g_queue_peek_head(sms->txq) == NULL)
+ start = TRUE;
+
+ for (l = msg_list; l; l = l->next) {
+ s = l->data;
+
+ pdu = g_new(struct pending_pdu, 1);
+
+ sms_encode(s, &pdu->pdu_len, &pdu->tpdu_len, pdu->pdu);
+
+ ofono_debug("pdu_len: %d, tpdu_len: %d",
+ pdu->pdu_len, pdu->tpdu_len);
+
+ g_queue_push_tail(sms->txq, pdu);
+ }
+
+ if (start)
+ g_timeout_add(0, tx_next, modem);
+}
+
+static DBusMessage *sms_send_message(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct ofono_modem *modem = data;
+ struct sms_manager_data *sms = modem->sms_manager;
+ char **tos;
+ int num_to;
+ char *text;
+ int i;
+ GSList *msg_list;
+ int ref_offset;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_ARRAY, DBUS_TYPE_STRING,
+ &tos, &num_to, DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INVALID))
+ return dbus_gsm_invalid_args(msg);
+
+ if (num_to == 0) {
+ dbus_free_string_array(tos);
+ return dbus_gsm_invalid_format(msg);
+ }
+
+ ofono_debug("Got %d recipients", num_to);
+
+ for (i = 0; i < num_to; i++) {
+ if (valid_phone_number_format(tos[i]))
+ continue;
+
+ dbus_free_string_array(tos);
+ return dbus_gsm_invalid_format(msg);
+ }
+
+ msg_list = sms_text_prepare(text, 0, TRUE, &ref_offset);
+
+ if (!msg_list) {
+ dbus_free_string_array(tos);
+ return dbus_gsm_invalid_format(msg);
+ }
+
+ for (i = 0; i < num_to; i++) {
+ ofono_debug("ref: %d, offset: %d", sms->ref, ref_offset);
+ set_ref_and_to(msg_list, sms->ref, ref_offset, tos[i]);
+ append_tx_queue(modem, msg_list);
+
+ if (sms->ref == 65536)
+ sms->ref = 1;
+ else
+ sms->ref = sms->ref + 1;
+ }
+
+ dbus_free_string_array(tos);
+ g_slist_foreach(msg_list, (GFunc)g_free, NULL);
+ g_slist_free(msg_list);
+
+ return dbus_message_new_method_return(msg);
+}
+
static GDBusMethodTable sms_manager_methods[] = {
{ "GetProperties", "", "a{sv}", sms_get_properties,
G_DBUS_METHOD_FLAG_ASYNC },
{ "SetProperty", "sv", "", sms_set_property,
G_DBUS_METHOD_FLAG_ASYNC },
+ { "SendMessage", "ass", "", sms_send_message },
{ }
};