aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-09-13 12:00:37 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-09-14 07:05:26 +0200
commite212f6b6edcd2b5678372bd0b05c70209c516f05 (patch)
treef28a596d95ed494ca667a351b78f42c50b60ab3a
parent2da9474d0c0e22044d7ab636e3336cab1a75bc22 (diff)
sms: create SMS parts only when storing or sending
When a user creates an SMS object, we will expose all its properties in DBus properly, but we will not create the internal list of SMS parts. The list of SMS parts will be created when the SMS is stored or sent, whatever comes first. When the message is sent and it was previously stored, the list of parts is not re-created. If the message requires multiple parts, the multipart reference is computed as follows: * If the SMS was not stored and is being sent, we just use a random number. * If the SMS is being stored, we will use a multipart reference which is not being used already in another SMS to the same destination.
-rw-r--r--src/mm-iface-modem-messaging.c48
-rw-r--r--src/mm-iface-modem-messaging.h5
-rw-r--r--src/mm-sms-list.c29
-rw-r--r--src/mm-sms-list.h4
-rw-r--r--src/mm-sms-part.c19
-rw-r--r--src/mm-sms-part.h3
-rw-r--r--src/mm-sms.c357
7 files changed, 320 insertions, 145 deletions
diff --git a/src/mm-iface-modem-messaging.c b/src/mm-iface-modem-messaging.c
index 7a4c1f31..5861b373 100644
--- a/src/mm-iface-modem-messaging.c
+++ b/src/mm-iface-modem-messaging.c
@@ -31,6 +31,54 @@ static GQuark storage_context_quark;
/*****************************************************************************/
+guint8
+mm_iface_modem_messaging_get_local_multipart_reference (MMIfaceModemMessaging *self,
+ const gchar *number,
+ GError **error)
+{
+ MMSmsList *list = NULL;
+ guint8 reference;
+ guint8 first;
+
+ /* Start by looking for a random number */
+ reference = g_random_int_range (1,255);
+
+ /* Then, look for the given reference in user-created messages */
+ g_object_get (self,
+ MM_IFACE_MODEM_MESSAGING_SMS_LIST, &list,
+ NULL);
+ if (!list)
+ return reference;
+
+ first = reference;
+ do {
+ if (!mm_sms_list_has_local_multipart_reference (list, number, reference)) {
+ g_object_unref (list);
+ return reference;
+ }
+
+ if (reference == 255)
+ reference = 1;
+ else
+ reference++;
+ }
+ while (reference != first);
+
+ g_object_unref (list);
+
+ /* We were not able to find a new valid multipart reference :/
+ * return an error */
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_TOO_MANY,
+ "Cannot create multipart SMS: No valid multipart reference "
+ "available for destination number '%s'",
+ number);
+ return 0;
+}
+
+/*****************************************************************************/
+
void
mm_iface_modem_messaging_bind_simple_status (MMIfaceModemMessaging *self,
MMSimpleStatus *status)
diff --git a/src/mm-iface-modem-messaging.h b/src/mm-iface-modem-messaging.h
index c2b5d859..0cbe16c8 100644
--- a/src/mm-iface-modem-messaging.h
+++ b/src/mm-iface-modem-messaging.h
@@ -176,4 +176,9 @@ gboolean mm_iface_modem_messaging_is_storage_supported_for_receiving (MMIfaceMod
/* SMS creation */
MMSms *mm_iface_modem_messaging_create_sms (MMIfaceModemMessaging *self);
+/* Look for a new valid multipart reference */
+guint8 mm_iface_modem_messaging_get_local_multipart_reference (MMIfaceModemMessaging *self,
+ const gchar *number,
+ GError **error);
+
#endif /* MM_IFACE_MODEM_MESSAGING_H */
diff --git a/src/mm-sms-list.c b/src/mm-sms-list.c
index 393101ba..a34bd679 100644
--- a/src/mm-sms-list.c
+++ b/src/mm-sms-list.c
@@ -54,6 +54,35 @@ struct _MMSmsListPrivate {
/*****************************************************************************/
+gboolean
+mm_sms_list_has_local_multipart_reference (MMSmsList *self,
+ const gchar *number,
+ guint8 reference)
+{
+ GList *l;
+
+ /* No one should look for multipart reference 0, which isn't valid */
+ g_assert (reference != 0);
+
+ for (l = self->priv->list; l; l = g_list_next (l)) {
+ MMSms *sms = MM_SMS (l->data);
+
+ if (mm_sms_is_multipart (sms) &&
+ mm_gdbus_sms_get_pdu_type (MM_GDBUS_SMS (sms)) == MM_SMS_PDU_TYPE_SUBMIT &&
+ mm_sms_get_storage (sms) != MM_SMS_STORAGE_UNKNOWN &&
+ mm_sms_get_multipart_reference (sms) == reference &&
+ g_str_equal (mm_gdbus_sms_get_number (MM_GDBUS_SMS (sms)), number)) {
+ /* Yes, the SMS list has an SMS with the same destination number
+ * and multipart reference */
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
guint
mm_sms_list_get_count (MMSmsList *self)
{
diff --git a/src/mm-sms-list.h b/src/mm-sms-list.h
index 16f39e51..b98e71fb 100644
--- a/src/mm-sms-list.h
+++ b/src/mm-sms-list.h
@@ -82,4 +82,8 @@ gboolean mm_sms_list_delete_sms_finish (MMSmsList *self,
GAsyncResult *res,
GError **error);
+gboolean mm_sms_list_has_local_multipart_reference (MMSmsList *self,
+ const gchar *number,
+ guint8 reference);
+
#endif /* MM_SMS_LIST_H */
diff --git a/src/mm-sms-part.c b/src/mm-sms-part.c
index c779f235..7cac9b88 100644
--- a/src/mm-sms-part.c
+++ b/src/mm-sms-part.c
@@ -1255,7 +1255,8 @@ mm_sms_part_util_split_text (const gchar *text,
}
GByteArray **
-mm_sms_part_util_split_data (const GByteArray *data)
+mm_sms_part_util_split_data (const guint8 *data,
+ gsize data_len)
{
GByteArray **out;
@@ -1267,25 +1268,25 @@ mm_sms_part_util_split_data (const GByteArray *data)
* bytes each, as we need place for the UDH header.
*/
- if (data->len <= 140) {
+ if (data_len <= 140) {
out = g_new0 (GByteArray *, 2);
- out[0] = g_byte_array_append (g_byte_array_sized_new (data->len),
- data->data,
- data->len);
+ out[0] = g_byte_array_append (g_byte_array_sized_new (data_len),
+ data,
+ data_len);
} else {
guint n_chunks;
guint i;
guint j;
- n_chunks = data->len / 134;
- if (data->len % 134 != 0)
+ n_chunks = data_len / 134;
+ if (data_len % 134 != 0)
n_chunks ++;
out = g_new0 (GByteArray *, n_chunks + 1);
for (i = 0, j = 0; i < n_chunks; i++, j+= 134) {
out[i] = g_byte_array_append (g_byte_array_sized_new (134),
- &data->data[j],
- MIN (data->len - j, 134));
+ &data[j],
+ MIN (data_len - j, 134));
}
}
diff --git a/src/mm-sms-part.h b/src/mm-sms-part.h
index 9b75ef14..4517a7a7 100644
--- a/src/mm-sms-part.h
+++ b/src/mm-sms-part.h
@@ -138,6 +138,7 @@ guint mm_sms_part_encode_address (const gchar *address,
gchar **mm_sms_part_util_split_text (const gchar *text,
MMSmsEncoding *encoding);
-GByteArray **mm_sms_part_util_split_data (const GByteArray *data);
+GByteArray **mm_sms_part_util_split_data (const guint8 *data,
+ gsize data_len);
#endif /* MM_SMS_PART_H */
diff --git a/src/mm-sms.c b/src/mm-sms.c
index 20ed2f90..26a6eadc 100644
--- a/src/mm-sms.c
+++ b/src/mm-sms.c
@@ -71,6 +71,128 @@ struct _MMSmsPrivate {
};
/*****************************************************************************/
+
+static gboolean
+generate_submit_pdus (MMSms *self,
+ GError **error)
+{
+ guint i;
+ guint n_parts;
+
+ const gchar *text;
+ GVariant *data_variant;
+ const guint8 *data;
+ gsize data_len = 0;
+
+ MMSmsEncoding encoding;
+ gchar **split_text = NULL;
+ GByteArray **split_data = NULL;
+
+ g_assert (self->priv->parts == NULL);
+
+ text = mm_gdbus_sms_get_text (MM_GDBUS_SMS (self));
+ data_variant = mm_gdbus_sms_get_data (MM_GDBUS_SMS (self));
+ data = (data_variant ?
+ g_variant_get_fixed_array (data_variant,
+ &data_len,
+ sizeof (guchar)) :
+ NULL);
+
+ g_assert (text != NULL || data != NULL);
+ g_assert (!(text != NULL && data != NULL));
+
+ if (text) {
+ split_text = mm_sms_part_util_split_text (text, &encoding);
+ if (!split_text) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create SMS: cannot process input text");
+ return FALSE;
+ }
+ n_parts = g_strv_length (split_text);
+ } else if (data) {
+ encoding = MM_SMS_ENCODING_8BIT;
+ split_data = mm_sms_part_util_split_data (data, data_len);
+ g_assert (split_data != NULL);
+ /* noop within the for */
+ for (n_parts = 0; split_data[n_parts]; n_parts++);
+ } else
+ g_assert_not_reached ();
+
+ g_assert (split_text != NULL || split_data != NULL);
+ g_assert (!(split_text != NULL && split_data != NULL));
+
+ /* Loop text/data chunks */
+ i = 0;
+ while (1) {
+ MMSmsPart *part;
+ gchar *part_text = NULL;
+ GByteArray *part_data = NULL;
+
+ if (split_text) {
+ if (!split_text[i])
+ break;
+ part_text = split_text[i];
+ mm_dbg (" Processing chunk '%u' of text with '%u' bytes",
+ i, (guint) strlen (part_text));
+ } else if (split_data) {
+ if (!split_data[i])
+ break;
+ part_data = split_data[i];
+ mm_dbg (" Processing chunk '%u' of data with '%u' bytes",
+ i, part_data->len);
+
+ } else
+ g_assert_not_reached ();
+
+ /* Create new part */
+ part = mm_sms_part_new (SMS_PART_INVALID_INDEX, MM_SMS_PDU_TYPE_SUBMIT);
+ mm_sms_part_take_text (part, part_text);
+ mm_sms_part_take_data (part, part_data);
+ mm_sms_part_set_encoding (part, encoding);
+ mm_sms_part_set_number (part, mm_gdbus_sms_get_number (MM_GDBUS_SMS (self)));
+ mm_sms_part_set_smsc (part, mm_gdbus_sms_get_smsc (MM_GDBUS_SMS (self)));
+ mm_sms_part_set_validity (part, mm_gdbus_sms_get_validity (MM_GDBUS_SMS (self)));
+ mm_sms_part_set_class (part, mm_gdbus_sms_get_class (MM_GDBUS_SMS (self)));
+ mm_sms_part_set_delivery_report_request (part, mm_gdbus_sms_get_delivery_report_request (MM_GDBUS_SMS (self)));
+
+ if (n_parts > 1) {
+ mm_sms_part_set_concat_reference (part, 0); /* We don't set a concat reference here */
+ mm_sms_part_set_concat_sequence (part, i + 1);
+ mm_sms_part_set_concat_max (part, n_parts);
+
+ mm_dbg ("Created SMS part '%u' for multipart SMS ('%u' parts expected)",
+ i + 1, n_parts);
+ } else {
+ mm_dbg ("Created SMS part for singlepart SMS");
+ }
+
+ /* Add to the list of parts */
+ self->priv->parts = g_list_append (self->priv->parts, part);
+
+ i++;
+ }
+
+ /* Free array (not contents, which were taken for the part) */
+ if (split_text)
+ g_free (split_text);
+ if (split_data)
+ g_free (split_data);
+
+ /* Set additional multipart specific properties */
+ if (n_parts > 1) {
+ self->priv->is_multipart = TRUE;
+ self->priv->max_parts = n_parts;
+ }
+
+ /* No more parts are expected */
+ self->priv->is_assembled = TRUE;
+
+ return TRUE;
+}
+
+/*****************************************************************************/
/* Store SMS (DBus call handling) */
typedef struct {
@@ -111,6 +233,40 @@ handle_store_ready (MMSms *self,
handle_store_context_free (ctx);
}
+static gboolean
+prepare_sms_to_be_stored (MMSms *self,
+ GError **error)
+{
+ GList *l;
+ guint8 reference;
+
+ g_assert (self->priv->parts == NULL);
+
+ /* Look for a valid multipart reference to use. When storing, we need to
+ * check whether we have already stored multipart SMS with the same
+ * reference and destination number */
+ reference = (mm_iface_modem_messaging_get_local_multipart_reference (
+ MM_IFACE_MODEM_MESSAGING (self->priv->modem),
+ mm_gdbus_sms_get_number (MM_GDBUS_SMS (self)),
+ error));
+ if (!reference ||
+ !generate_submit_pdus (self, error)) {
+ g_prefix_error (error, "Cannot prepare SMS to be stored: ");
+ return FALSE;
+ }
+
+ /* If the message is a multipart message, we need to set a proper
+ * multipart reference. When sending a message which wasn't stored
+ * yet, we can just get a random multipart reference. */
+ self->priv->multipart_reference = reference;
+ for (l = self->priv->parts; l; l = g_list_next (l)) {
+ mm_sms_part_set_concat_reference ((MMSmsPart *)l->data,
+ self->priv->multipart_reference);
+ }
+
+ return TRUE;
+}
+
static void
handle_store_auth_ready (MMBaseModem *modem,
GAsyncResult *res,
@@ -151,6 +307,13 @@ handle_store_auth_ready (MMBaseModem *modem,
return;
}
+ /* Prepare the SMS to be stored, creating the PDU list if required */
+ if (!prepare_sms_to_be_stored (ctx->self, &error)) {
+ g_dbus_method_invocation_take_error (ctx->invocation, error);
+ handle_store_context_free (ctx);
+ return;
+ }
+
/* If not stored, check if we do support doing it */
if (!MM_SMS_GET_CLASS (ctx->self)->store ||
!MM_SMS_GET_CLASS (ctx->self)->store_finish) {
@@ -245,6 +408,32 @@ handle_send_ready (MMSms *self,
handle_send_context_free (ctx);
}
+static gboolean
+prepare_sms_to_be_sent (MMSms *self,
+ GError **error)
+{
+ GList *l;
+
+ if (self->priv->parts)
+ return TRUE;
+
+ if (!generate_submit_pdus (self, error)) {
+ g_prefix_error (error, "Cannot prepare SMS to be sent: ");
+ return FALSE;
+ }
+
+ /* If the message is a multipart message, we need to set a proper
+ * multipart reference. When sending a message which wasn't stored
+ * yet, we can just get a random multipart reference. */
+ self->priv->multipart_reference = g_random_int_range (1,255);
+ for (l = self->priv->parts; l; l = g_list_next (l)) {
+ mm_sms_part_set_concat_reference ((MMSmsPart *)l->data,
+ self->priv->multipart_reference);
+ }
+
+ return TRUE;
+}
+
static void
handle_send_auth_ready (MMBaseModem *modem,
GAsyncResult *res,
@@ -281,6 +470,13 @@ handle_send_auth_ready (MMBaseModem *modem,
return;
}
+ /* Prepare the SMS to be sent, creating the PDU list if required */
+ if (!prepare_sms_to_be_sent (ctx->self, &error)) {
+ g_dbus_method_invocation_take_error (ctx->invocation, error);
+ handle_send_context_free (ctx);
+ return;
+ }
+
/* Check if we do support doing it */
if (!MM_SMS_GET_CLASS (ctx->self)->send ||
!MM_SMS_GET_CLASS (ctx->self)->send_finish) {
@@ -1439,13 +1635,11 @@ mm_sms_new_from_properties (MMBaseModem *modem,
MMSmsProperties *properties,
GError **error)
{
- MMSmsPart *part;
- guint n_parts;
+ MMSms *self;
const gchar *text;
- MMSmsEncoding encoding;
- gchar **split_text = NULL;
GByteArray *data;
- GByteArray **split_data = NULL;
+
+ g_assert (MM_IS_IFACE_MODEM_MESSAGING (modem));
text = mm_sms_properties_get_text (properties);
data = mm_sms_properties_peek_data_bytearray (properties);
@@ -1471,138 +1665,31 @@ mm_sms_new_from_properties (MMBaseModem *modem,
return NULL;
}
- if (text) {
- split_text = mm_sms_part_util_split_text (text, &encoding);
- if (!split_text) {
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_INVALID_ARGS,
- "Cannot create SMS: cannot process input text");
- return NULL;
- }
- n_parts = g_strv_length (split_text);
- } else if (data) {
- encoding = MM_SMS_ENCODING_8BIT;
- split_data = mm_sms_part_util_split_data (data);
- g_assert (split_data != NULL);
- /* noop within the for */
- for (n_parts = 0; split_data[n_parts]; n_parts++);
- } else
- g_assert_not_reached ();
-
- if (n_parts > 1) {
- MMSms *sms = NULL;
- guint i = 0;
- /* wtf... is this really the way to go? */
- guint reference = g_random_int_range (1,255);
-
- g_assert (split_text != NULL || split_data != NULL);
- g_assert (!(split_text != NULL && split_data != NULL));
-
- /* Loop text/data chunks */
- while (1) {
- gchar *part_text = NULL;
- GByteArray *part_data = NULL;
-
- if (split_text) {
- if (!split_text[i])
- break;
- part_text = split_text[i];
- split_text[i] = NULL;
- mm_dbg (" Processing chunk '%u' of text with '%u' bytes",
- i, (guint) strlen (part_text));
- } else if (split_data) {
- if (!split_data[i])
- break;
- part_data = split_data[i];
- split_data[i] = NULL;
- mm_dbg (" Processing chunk '%u' of data with '%u' bytes",
- i, part_data->len);
-
- } else
- g_assert_not_reached ();
-
- /* Create new part */
- part = mm_sms_part_new (SMS_PART_INVALID_INDEX,
- MM_SMS_PDU_TYPE_SUBMIT);
- mm_sms_part_take_text (part, part_text);
- mm_sms_part_take_data (part, part_data);
- mm_sms_part_set_encoding (part, encoding);
- mm_sms_part_set_number (part, mm_sms_properties_get_number (properties));
- mm_sms_part_set_smsc (part, mm_sms_properties_get_smsc (properties));
- mm_sms_part_set_validity (part, mm_sms_properties_get_validity (properties));
- mm_sms_part_set_class (part, mm_sms_properties_get_class (properties));
- mm_sms_part_set_delivery_report_request (part, mm_sms_properties_get_delivery_report_request (properties));
- mm_sms_part_set_concat_reference (part, reference);
- mm_sms_part_set_concat_sequence (part, i + 1);
- mm_sms_part_set_concat_max (part, n_parts);
-
- if (!sms) {
- mm_dbg ("Building user-created multipart SMS... (%u parts expected)", n_parts);
- sms = mm_sms_multipart_new (
- modem,
- MM_SMS_STATE_UNKNOWN,
- MM_SMS_STORAGE_UNKNOWN, /* not stored anywhere yet */
- reference,
- n_parts,
- part,
- error);
- if (!sms)
- break;
- } else if (!mm_sms_multipart_take_part (sms, part, error)) {
- g_clear_object (&sms);
- break;
- }
-
- mm_dbg (" Added part '%u' to multipart SMS...", i + 1);
- i++;
- }
-
- /* Rewalk the arrays and remove any remaining text/data not set after an error */
- if (split_text) {
- for (i = 0; i < n_parts; i++) {
- if (split_text[i])
- g_free (split_text[i]);
- }
-
- g_free (split_text);
- }
- else if (split_data) {
- for (i = 0; i < n_parts; i++) {
- if (split_data[i])
- g_byte_array_unref (split_data[i]);
- }
- g_free (split_data);
- }
-
- return sms;
- }
-
- /* Single part it will be */
- part = mm_sms_part_new (SMS_PART_INVALID_INDEX,
- MM_SMS_PDU_TYPE_SUBMIT);
+ /* Create an SMS object as defined by the interface */
+ self = mm_iface_modem_messaging_create_sms (MM_IFACE_MODEM_MESSAGING (modem));
+ g_object_set (self,
+ "state", MM_SMS_STATE_UNKNOWN,
+ "storage", MM_SMS_STORAGE_UNKNOWN,
+ "number", mm_sms_properties_get_number (properties),
+ "pdu-type", MM_SMS_PDU_TYPE_SUBMIT,
+ "text", text,
+ "data", (data ?
+ g_variant_new_from_data (G_VARIANT_TYPE ("ay"),
+ data->data,
+ data->len * sizeof (guint8),
+ TRUE,
+ (GDestroyNotify) g_byte_array_unref,
+ g_byte_array_ref (data)) :
+ NULL),
+ "smsc", mm_sms_properties_get_smsc (properties),
+ "class", mm_sms_properties_get_class (properties),
+ "delivery-report-request", mm_sms_properties_get_delivery_report_request (properties),
+ NULL);
- if (split_text) {
- mm_sms_part_take_text (part, split_text[0]);
- g_free (split_text);
- } else if (split_data) {
- mm_sms_part_take_data (part, split_data[0]);
- g_free (split_data);
- } else
- g_assert_not_reached ();
+ /* Only export once properly created */
+ mm_sms_export (self);
- mm_sms_part_set_encoding (part, encoding);
- mm_sms_part_set_number (part, mm_sms_properties_get_number (properties));
- mm_sms_part_set_smsc (part, mm_sms_properties_get_smsc (properties));
- mm_sms_part_set_validity (part, mm_sms_properties_get_validity (properties));
- mm_sms_part_set_class (part, mm_sms_properties_get_class (properties));
- mm_sms_part_set_delivery_report_request (part, mm_sms_properties_get_delivery_report_request (properties));
-
- return mm_sms_singlepart_new (modem,
- MM_SMS_STATE_UNKNOWN,
- MM_SMS_STORAGE_UNKNOWN, /* not stored anywhere yet */
- part,
- error);
+ return self;
}
/*****************************************************************************/