aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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;
}
/*****************************************************************************/