diff options
Diffstat (limited to 'src/mm-sms.c')
-rw-r--r-- | src/mm-sms.c | 357 |
1 files changed, 222 insertions, 135 deletions
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; } /*****************************************************************************/ |