aboutsummaryrefslogtreecommitdiff
path: root/src/mm-base-sms.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mm-base-sms.c')
-rw-r--r--src/mm-base-sms.c1060
1 files changed, 190 insertions, 870 deletions
diff --git a/src/mm-base-sms.c b/src/mm-base-sms.c
index 0e7c7527..4f67d5ea 100644
--- a/src/mm-base-sms.c
+++ b/src/mm-base-sms.c
@@ -27,12 +27,8 @@
#include <libmm-glib.h>
#include "mm-base-sms.h"
-#include "mm-broadband-modem.h"
-#include "mm-iface-modem.h"
-#include "mm-iface-modem-messaging.h"
+#include "mm-auth-provider.h"
#include "mm-sms-part-3gpp.h"
-#include "mm-base-modem-at.h"
-#include "mm-base-modem.h"
#include "mm-log-object.h"
#include "mm-modem-helpers.h"
#include "mm-error-helpers.h"
@@ -51,19 +47,36 @@ enum {
PROP_PATH,
PROP_CONNECTION,
PROP_BIND_TO,
- PROP_MODEM,
PROP_IS_MULTIPART,
PROP_MAX_PARTS,
PROP_MULTIPART_REFERENCE,
+ PROP_IS_3GPP,
+ PROP_DEFAULT_STORAGE,
+ PROP_SUPPORTED_STORAGES,
PROP_LAST
};
static GParamSpec *properties[PROP_LAST];
+enum {
+ SIGNAL_SET_LOCAL_MULTIPART_REFERENCE,
+ SIGNAL_LAST
+};
+
+static guint signals[SIGNAL_LAST] = { 0 };
+
struct _MMBaseSmsPrivate {
+ gboolean initialized;
+
/* The connection to the system bus */
GDBusConnection *connection;
guint dbus_id;
+ /* Object to which our connection property should be bound */
+ GObject *connection_parent;
+ /* GObject property name of the parent's connection property to
+ * which this SMS"s connection should be bound.
+ */
+ gchar *connection_parent_property_name;
/* The authorization provider */
MMAuthProvider *authp;
@@ -72,8 +85,6 @@ struct _MMBaseSmsPrivate {
/* The object this SMS is bound to */
GObject *bind_to;
- /* The modem which owns this SMS */
- MMBaseModem *modem;
/* The path where the SMS object is exported */
gchar *path;
@@ -88,6 +99,13 @@ struct _MMBaseSmsPrivate {
/* Set to true when all needed parts were received,
* parsed and assembled */
gboolean is_assembled;
+
+ /* TRUE for 3GPP SMS; FALSE for CDMA */
+ gboolean is_3gpp;
+
+ /* SMS storage */
+ MMSmsStorage default_storage;
+ GArray *supported_storages;
};
/*****************************************************************************/
@@ -310,25 +328,7 @@ static gboolean
generate_submit_pdus (MMBaseSms *self,
GError **error)
{
- MMBaseModem *modem;
- gboolean is_3gpp;
-
- /* First; decide which kind of PDU we'll generate, based on the current modem caps */
-
- g_object_get (self,
- MM_BASE_SMS_MODEM, &modem,
- NULL);
- g_assert (modem != NULL);
-
- is_3gpp = mm_iface_modem_is_3gpp (MM_IFACE_MODEM (modem));
- g_object_unref (modem);
-
- /* On a 3GPP-capable modem, create always a 3GPP SMS (even if the modem is 3GPP+3GPP2) */
- if (is_3gpp)
- return generate_3gpp_submit_pdus (self, error);
-
- /* Otherwise, create a 3GPP2 SMS */
- return generate_cdma_submit_pdus (self, error);
+ return self->priv->is_3gpp ? generate_3gpp_submit_pdus (self, error) : generate_cdma_submit_pdus (self, error);
}
/*****************************************************************************/
@@ -390,26 +390,22 @@ prepare_sms_to_be_stored (MMBaseSms *self,
* when storing locally, as we could collide with the references used
* in other existing messages. */
if (self->priv->is_multipart) {
- GList *l;
- guint8 reference;
-
- /* 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) {
- g_prefix_error (error, "Cannot get local multipart reference: ");
+ const gchar *number;
+
+ number = mm_gdbus_sms_get_number (MM_GDBUS_SMS (self));
+ g_signal_emit (self,
+ signals[SIGNAL_SET_LOCAL_MULTIPART_REFERENCE],
+ 0,
+ number);
+ if (self->priv->multipart_reference == 0) {
+ 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 FALSE;
}
-
- 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;
@@ -421,6 +417,7 @@ handle_store_auth_ready (MMAuthProvider *authp,
HandleStoreContext *ctx)
{
GError *error = NULL;
+ gboolean storage_supported = FALSE;
if (!mm_auth_provider_authorize_finish (authp, res, &error)) {
mm_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -452,18 +449,24 @@ handle_store_auth_ready (MMAuthProvider *authp,
}
/* Check if the requested storage is allowed for storing */
- if (!mm_iface_modem_messaging_is_storage_supported_for_storing (MM_IFACE_MODEM_MESSAGING (ctx->self->priv->modem),
- ctx->storage,
- &error)) {
- mm_obj_warn (ctx->self, "failed storing SMS message: %s", error->message);
- mm_dbus_method_invocation_take_error (ctx->invocation, error);
- handle_store_context_free (ctx);
- return;
+ if (ctx->self->priv->supported_storages) {
+ guint i;
+
+ for (i = 0; i < ctx->self->priv->supported_storages->len; i++) {
+ if (ctx->storage == g_array_index (ctx->self->priv->supported_storages, MMSmsStorage, i)) {
+ storage_supported = TRUE;
+ break;
+ }
+ }
}
- /* Prepare the SMS to be stored, creating the PDU list if required */
- if (!prepare_sms_to_be_stored (ctx->self, &error)) {
- mm_obj_warn (ctx->self, "failed preparing SMS message to be stored: %s", error->message);
+ if (!storage_supported) {
+ g_set_error (&error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "Storage '%s' is not supported for storing",
+ mm_sms_storage_get_string (ctx->storage));
+ mm_obj_warn (ctx->self, "failed storing SMS message: %s", error->message);
mm_dbus_method_invocation_take_error (ctx->invocation, error);
handle_store_context_free (ctx);
return;
@@ -479,6 +482,14 @@ handle_store_auth_ready (MMAuthProvider *authp,
return;
}
+ /* Prepare the SMS to be stored, creating the PDU list if required */
+ if (!prepare_sms_to_be_stored (ctx->self, &error)) {
+ mm_obj_warn (ctx->self, "failed preparing SMS message to be stored: %s", error->message);
+ mm_dbus_method_invocation_take_error (ctx->invocation, error);
+ handle_store_context_free (ctx);
+ return;
+ }
+
MM_BASE_SMS_GET_CLASS (ctx->self)->store (ctx->self,
ctx->storage,
(GAsyncReadyCallback)handle_store_ready,
@@ -499,9 +510,7 @@ handle_store (MMBaseSms *self,
if (ctx->storage == MM_SMS_STORAGE_UNKNOWN) {
/* We'll set now the proper storage, taken from the default mem2 one */
- g_object_get (self->priv->modem,
- MM_IFACE_MODEM_MESSAGING_SMS_DEFAULT_STORAGE, &ctx->storage,
- NULL);
+ ctx->storage = self->priv->default_storage;
g_assert (ctx->storage != MM_SMS_STORAGE_UNKNOWN);
}
@@ -581,7 +590,7 @@ prepare_sms_to_be_sent (MMBaseSms *self,
* multipart reference. When sending a message which wasn't stored
* yet, we can just get a random multipart reference. */
if (self->priv->is_multipart) {
- self->priv->multipart_reference = g_random_int_range (1,255);
+ 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);
@@ -756,6 +765,23 @@ mm_base_sms_get_multipart_reference (MMBaseSms *self)
return self->priv->multipart_reference;
}
+void
+mm_base_sms_set_multipart_reference (MMBaseSms *self, guint reference)
+{
+ GList *l;
+
+ g_return_if_fail (self->priv->is_multipart);
+ g_return_if_fail (reference > 0);
+ g_return_if_fail (reference <= 255);
+ g_return_if_fail (self->priv->multipart_reference == 0);
+
+ 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);
+ }
+}
+
gboolean
mm_base_sms_multipart_is_complete (MMBaseSms *self)
{
@@ -794,740 +820,6 @@ mm_base_sms_get_parts (MMBaseSms *self)
/*****************************************************************************/
-static gboolean
-sms_get_store_or_send_command (MMBaseSms *self,
- MMSmsPart *part,
- gboolean text_or_pdu, /* TRUE for PDU */
- gboolean store_or_send, /* TRUE for send */
- gchar **out_cmd,
- gchar **out_msg_data,
- GError **error)
-{
- g_assert (out_cmd != NULL);
- g_assert (out_msg_data != NULL);
-
- if (!text_or_pdu) {
- /* Text mode */
- *out_cmd = g_strdup_printf ("+CMG%c=\"%s\"",
- store_or_send ? 'S' : 'W',
- mm_sms_part_get_number (part));
- *out_msg_data = g_strdup_printf ("%s\x1a", mm_sms_part_get_text (part));
- } else {
- g_autofree gchar *hex = NULL;
- g_autofree guint8 *pdu = NULL;
- guint pdulen = 0;
- guint msgstart = 0;
-
- /* AT+CMGW=<length>[, <stat>]<CR> PDU can be entered. <CTRL-Z>/<ESC> */
-
- pdu = mm_sms_part_3gpp_get_submit_pdu (part, &pdulen, &msgstart, self, error);
- if (!pdu)
- /* 'error' should already be set */
- return FALSE;
-
- /* Convert PDU to hex */
- hex = mm_utils_bin2hexstr (pdu, pdulen);
- if (!hex) {
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Not enough memory to send SMS PDU");
- return FALSE;
- }
-
- /* CMGW/S length is the size of the PDU without SMSC information */
- *out_cmd = g_strdup_printf ("+CMG%c=%d",
- store_or_send ? 'S' : 'W',
- pdulen - msgstart);
- *out_msg_data = g_strdup_printf ("%s\x1a", hex);
- }
-
- return TRUE;
-}
-
-/*****************************************************************************/
-/* Store the SMS */
-
-typedef struct {
- MMBaseModem *modem;
- MMIfacePortAt *port;
- MMSmsStorage storage;
- gboolean need_unlock;
- gboolean use_pdu_mode;
- GList *current;
- gchar *msg_data;
-} SmsStoreContext;
-
-static void
-sms_store_context_free (SmsStoreContext *ctx)
-{
- /* Unlock mem2 storage if we had the lock */
- if (ctx->need_unlock)
- mm_broadband_modem_unlock_sms_storages (MM_BROADBAND_MODEM (ctx->modem), FALSE, TRUE);
- g_object_unref (ctx->port);
- g_object_unref (ctx->modem);
- g_free (ctx->msg_data);
- g_slice_free (SmsStoreContext, ctx);
-}
-
-static gboolean
-sms_store_finish (MMBaseSms *self,
- GAsyncResult *res,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (res), error);
-}
-
-static void sms_store_next_part (GTask *task);
-
-static void
-store_msg_data_ready (MMBaseModem *modem,
- GAsyncResult *res,
- GTask *task)
-{
- SmsStoreContext *ctx;
- const gchar *response;
- GError *error = NULL;
- gint rv;
- gint idx;
-
- response = mm_base_modem_at_command_full_finish (modem, res, &error);
- if (error) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* Read the new part index from the reply */
- rv = sscanf (response, "+CMGW: %d", &idx);
- if (rv != 1 || idx < 0) {
- g_task_return_new_error (task,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Couldn't read index of already stored part: "
- "%d fields parsed",
- rv);
- g_object_unref (task);
- return;
- }
-
- ctx = g_task_get_task_data (task);
-
- /* Set the index in the part we hold */
- mm_sms_part_set_index ((MMSmsPart *)ctx->current->data, (guint)idx);
-
- ctx->current = g_list_next (ctx->current);
- sms_store_next_part (task);
-}
-
-static void
-store_ready (MMBaseModem *modem,
- GAsyncResult *res,
- GTask *task)
-{
- SmsStoreContext *ctx;
- GError *error = NULL;
-
- mm_base_modem_at_command_full_finish (modem, res, &error);
- if (error) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- ctx = g_task_get_task_data (task);
-
- /* Send the actual message data.
- * We send the data as 'raw' data because we do NOT want it to
- * be treated as an AT command (i.e. we don't want it prefixed
- * with AT+ and suffixed with <CR><LF>), plus, we want it to be
- * sent right away (not queued after other AT commands). */
- mm_base_modem_at_command_full (ctx->modem,
- ctx->port,
- ctx->msg_data,
- 10,
- FALSE,
- TRUE, /* raw */
- NULL,
- (GAsyncReadyCallback)store_msg_data_ready,
- task);
-}
-
-static void
-sms_store_next_part (GTask *task)
-{
- MMBaseSms *self;
- SmsStoreContext *ctx;
- GError *error = NULL;
- g_autofree gchar *cmd = NULL;
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- if (!ctx->current) {
- /* Done we are */
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
- return;
- }
-
- g_clear_pointer (&ctx->msg_data, g_free);
-
- if (!sms_get_store_or_send_command (self,
- (MMSmsPart *)ctx->current->data,
- ctx->use_pdu_mode,
- FALSE,
- &cmd,
- &ctx->msg_data,
- &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- g_assert (cmd != NULL);
- g_assert (ctx->msg_data != NULL);
-
- mm_base_modem_at_command_full (ctx->modem,
- ctx->port,
- cmd,
- 10,
- FALSE,
- FALSE, /* raw */
- NULL,
- (GAsyncReadyCallback)store_ready,
- task);
-}
-
-static void
-store_lock_sms_storages_ready (MMBroadbandModem *modem,
- GAsyncResult *res,
- GTask *task)
-{
- MMBaseSms *self;
- SmsStoreContext *ctx;
- GError *error = NULL;
-
- if (!mm_broadband_modem_lock_sms_storages_finish (modem, res, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- /* We are now locked. Whatever result we have here, we need to make sure
- * we unlock the storages before finishing. */
- ctx->need_unlock = TRUE;
-
- /* Go on to store the parts */
- ctx->current = self->priv->parts;
- sms_store_next_part (task);
-}
-
-static void
-sms_store (MMBaseSms *self,
- MMSmsStorage storage,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SmsStoreContext *ctx;
- GTask *task;
- MMIfacePortAt *port;
- GError *error = NULL;
-
- task = g_task_new (self, NULL, callback, user_data);
-
- /* Select port for the operation */
- port = mm_base_modem_peek_best_at_port (self->priv->modem, &error);
- if (!port) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* Setup the context */
- ctx = g_slice_new0 (SmsStoreContext);
- ctx->modem = g_object_ref (self->priv->modem);
- ctx->port = g_object_ref (port);
- ctx->storage = storage;
-
- /* Different ways to do it if on PDU or text mode */
- g_object_get (self->priv->modem,
- MM_IFACE_MODEM_MESSAGING_SMS_PDU_MODE, &ctx->use_pdu_mode,
- NULL);
- g_task_set_task_data (task, ctx, (GDestroyNotify)sms_store_context_free);
-
- /* First, lock storage to use */
- g_assert (MM_IS_BROADBAND_MODEM (self->priv->modem));
- mm_broadband_modem_lock_sms_storages (
- MM_BROADBAND_MODEM (self->priv->modem),
- MM_SMS_STORAGE_UNKNOWN, /* none required for mem1 */
- ctx->storage,
- (GAsyncReadyCallback)store_lock_sms_storages_ready,
- task);
-}
-
-/*****************************************************************************/
-/* Send the SMS */
-
-typedef struct {
- MMBaseModem *modem;
- MMIfacePortAt *port;
- gboolean need_unlock;
- gboolean from_storage;
- gboolean use_pdu_mode;
- GList *current;
- gchar *msg_data;
-} SmsSendContext;
-
-static void
-sms_send_context_free (SmsSendContext *ctx)
-{
- /* Unlock mem2 storage if we had the lock */
- if (ctx->need_unlock)
- mm_broadband_modem_unlock_sms_storages (MM_BROADBAND_MODEM (ctx->modem), FALSE, TRUE);
- g_object_unref (ctx->port);
- g_object_unref (ctx->modem);
- g_free (ctx->msg_data);
- g_slice_free (SmsSendContext, ctx);
-}
-
-static gboolean
-sms_send_finish (MMBaseSms *self,
- GAsyncResult *res,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (res), error);
-}
-
-static void sms_send_next_part (GTask *task);
-
-static gint
-read_message_reference_from_reply (const gchar *response,
- GError **error)
-{
- gint rv = 0;
- gint idx = -1;
-
- if (strstr (response, "+CMGS"))
- rv = sscanf (strstr (response, "+CMGS"), "+CMGS: %d", &idx);
- else if (strstr (response, "+CMSS"))
- rv = sscanf (strstr (response, "+CMSS"), "+CMSS: %d", &idx);
-
- if (rv != 1 || idx < 0) {
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Couldn't read message reference: "
- "%d fields parsed from response '%s'",
- rv, response);
- return -1;
- }
-
- return idx;
-}
-
-static void
-send_generic_msg_data_ready (MMBaseModem *modem,
- GAsyncResult *res,
- GTask *task)
-{
- SmsSendContext *ctx;
- GError *error = NULL;
- const gchar *response;
- gint message_reference;
-
- response = mm_base_modem_at_command_full_finish (modem, res, &error);
- if (error) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- message_reference = read_message_reference_from_reply (response, &error);
- if (error) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- ctx = g_task_get_task_data (task);
-
- mm_sms_part_set_message_reference ((MMSmsPart *)ctx->current->data,
- (guint)message_reference);
-
- ctx->current = g_list_next (ctx->current);
- sms_send_next_part (task);
-}
-
-static void
-send_generic_ready (MMBaseModem *modem,
- GAsyncResult *res,
- GTask *task)
-{
- SmsSendContext *ctx;
- GError *error = NULL;
-
- mm_base_modem_at_command_full_finish (modem, res, &error);
- if (error) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- ctx = g_task_get_task_data (task);
-
- /* Send the actual message data.
- * We send the data as 'raw' data because we do NOT want it to
- * be treated as an AT command (i.e. we don't want it prefixed
- * with AT+ and suffixed with <CR><LF>), plus, we want it to be
- * sent right away (not queued after other AT commands). */
- mm_base_modem_at_command_full (ctx->modem,
- ctx->port,
- ctx->msg_data,
- MM_BASE_SMS_DEFAULT_SEND_TIMEOUT,
- FALSE,
- TRUE, /* raw */
- NULL,
- (GAsyncReadyCallback)send_generic_msg_data_ready,
- task);
-}
-
-static void
-send_from_storage_ready (MMBaseModem *modem,
- GAsyncResult *res,
- GTask *task)
-{
- MMBaseSms *self;
- SmsSendContext *ctx;
- GError *error = NULL;
- const gchar *response;
- gint message_reference;
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- response = mm_base_modem_at_command_full_finish (modem, res, &error);
- if (error) {
- if (g_error_matches (error, MM_SERIAL_ERROR, MM_SERIAL_ERROR_RESPONSE_TIMEOUT)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- mm_obj_dbg (self, "couldn't send SMS from storage: %s; trying generic send...", error->message);
- g_error_free (error);
-
- ctx->from_storage = FALSE;
- sms_send_next_part (task);
- return;
- }
-
- message_reference = read_message_reference_from_reply (response, &error);
- if (error) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- mm_sms_part_set_message_reference ((MMSmsPart *)ctx->current->data,
- (guint)message_reference);
-
- ctx->current = g_list_next (ctx->current);
- sms_send_next_part (task);
-}
-
-static void
-sms_send_next_part (GTask *task)
-{
- MMBaseSms *self;
- SmsSendContext *ctx;
- GError *error = NULL;
- g_autofree gchar *cmd = NULL;
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- if (!ctx->current) {
- /* Done we are */
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
- return;
- }
-
- /* Send from storage */
- if (ctx->from_storage) {
- cmd = g_strdup_printf ("+CMSS=%d", mm_sms_part_get_index ((MMSmsPart *)ctx->current->data));
- mm_base_modem_at_command_full (ctx->modem,
- ctx->port,
- cmd,
- MM_BASE_SMS_DEFAULT_SEND_TIMEOUT,
- FALSE,
- FALSE,
- NULL,
- (GAsyncReadyCallback)send_from_storage_ready,
- task);
- return;
- }
-
- /* Generic send */
-
- g_clear_pointer (&ctx->msg_data, g_free);
-
- if (!sms_get_store_or_send_command (self,
- (MMSmsPart *)ctx->current->data,
- ctx->use_pdu_mode,
- TRUE,
- &cmd,
- &ctx->msg_data,
- &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- g_assert (cmd != NULL);
- g_assert (ctx->msg_data != NULL);
-
- /* no network involved in this initial AT command, so lower timeout */
- mm_base_modem_at_command_full (ctx->modem,
- ctx->port,
- cmd,
- 10,
- FALSE,
- FALSE, /* raw */
- NULL,
- (GAsyncReadyCallback)send_generic_ready,
- task);
-}
-
-static void
-send_lock_sms_storages_ready (MMBroadbandModem *modem,
- GAsyncResult *res,
- GTask *task)
-{
- MMBaseSms *self;
- SmsSendContext *ctx;
- GError *error = NULL;
-
- if (!mm_broadband_modem_lock_sms_storages_finish (modem, res, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- /* We are now locked. Whatever result we have here, we need to make sure
- * we unlock the storages before finishing. */
- ctx->need_unlock = TRUE;
-
- /* Go on to send the parts */
- ctx->current = self->priv->parts;
- sms_send_next_part (task);
-}
-
-static void
-sms_send (MMBaseSms *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SmsSendContext *ctx;
- GTask *task;
- MMIfacePortAt *port;
- GError *error = NULL;
-
- task = g_task_new (self, NULL, callback, user_data);
-
- /* Select port for the operation */
- port = mm_base_modem_peek_best_at_port (self->priv->modem, &error);
- if (!port) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- /* Setup the context */
- ctx = g_slice_new0 (SmsSendContext);
- ctx->modem = g_object_ref (self->priv->modem);
- ctx->port = g_object_ref (port);
- g_task_set_task_data (task, ctx, (GDestroyNotify)sms_send_context_free);
-
- /* If the SMS is STORED, try to send from storage */
- ctx->from_storage = (mm_base_sms_get_storage (self) != MM_SMS_STORAGE_UNKNOWN);
- if (ctx->from_storage) {
- /* When sending from storage, first lock storage to use */
- g_assert (MM_IS_BROADBAND_MODEM (self->priv->modem));
- mm_broadband_modem_lock_sms_storages (
- MM_BROADBAND_MODEM (self->priv->modem),
- MM_SMS_STORAGE_UNKNOWN, /* none required for mem1 */
- mm_base_sms_get_storage (self),
- (GAsyncReadyCallback)send_lock_sms_storages_ready,
- task);
- return;
- }
-
- /* Different ways to do it if on PDU or text mode */
- g_object_get (self->priv->modem,
- MM_IFACE_MODEM_MESSAGING_SMS_PDU_MODE, &ctx->use_pdu_mode,
- NULL);
- ctx->current = self->priv->parts;
- sms_send_next_part (task);
-}
-
-/*****************************************************************************/
-
-typedef struct {
- MMBaseModem *modem;
- gboolean need_unlock;
- GList *current;
- guint n_failed;
-} SmsDeletePartsContext;
-
-static void
-sms_delete_parts_context_free (SmsDeletePartsContext *ctx)
-{
- /* Unlock mem1 storage if we had the lock */
- if (ctx->need_unlock)
- mm_broadband_modem_unlock_sms_storages (MM_BROADBAND_MODEM (ctx->modem), TRUE, FALSE);
- g_object_unref (ctx->modem);
- g_slice_free (SmsDeletePartsContext, ctx);
-}
-
-static gboolean
-sms_delete_finish (MMBaseSms *self,
- GAsyncResult *res,
- GError **error)
-{
- return g_task_propagate_boolean (G_TASK (res), error);
-}
-
-static void delete_next_part (GTask *task);
-
-static void
-delete_part_ready (MMBaseModem *modem,
- GAsyncResult *res,
- GTask *task)
-{
- MMBaseSms *self;
- SmsDeletePartsContext *ctx;
- g_autoptr(GError) error = NULL;
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- mm_base_modem_at_command_finish (modem, res, &error);
- if (error) {
- ctx->n_failed++;
- mm_obj_dbg (self, "couldn't delete SMS part with index %u: %s",
- mm_sms_part_get_index ((MMSmsPart *)ctx->current->data),
- error->message);
- }
-
- /* We reset the index, as there is no longer that part */
- mm_sms_part_set_index ((MMSmsPart *)ctx->current->data, SMS_PART_INVALID_INDEX);
-
- ctx->current = g_list_next (ctx->current);
- delete_next_part (task);
-}
-
-static void
-delete_next_part (GTask *task)
-{
- SmsDeletePartsContext *ctx;
- g_autofree gchar *cmd = NULL;
-
- ctx = g_task_get_task_data (task);
-
- /* Skip non-stored parts */
- while (ctx->current && (mm_sms_part_get_index ((MMSmsPart *)ctx->current->data) == SMS_PART_INVALID_INDEX))
- ctx->current = g_list_next (ctx->current);
-
- /* If all removed, we're done */
- if (!ctx->current) {
- if (ctx->n_failed > 0)
- g_task_return_new_error (task,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Couldn't delete %u parts from this SMS",
- ctx->n_failed);
- else
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
- return;
- }
-
- cmd = g_strdup_printf ("+CMGD=%d", mm_sms_part_get_index ((MMSmsPart *)ctx->current->data));
- mm_base_modem_at_command (ctx->modem,
- cmd,
- 10,
- FALSE,
- (GAsyncReadyCallback)delete_part_ready,
- task);
-}
-
-static void
-delete_lock_sms_storages_ready (MMBroadbandModem *modem,
- GAsyncResult *res,
- GTask *task)
-{
- MMBaseSms *self;
- SmsDeletePartsContext *ctx;
- GError *error = NULL;
-
- if (!mm_broadband_modem_lock_sms_storages_finish (modem, res, &error)) {
- g_task_return_error (task, error);
- g_object_unref (task);
- return;
- }
-
- self = g_task_get_source_object (task);
- ctx = g_task_get_task_data (task);
-
- /* We are now locked. Whatever result we have here, we need to make sure
- * we unlock the storages before finishing. */
- ctx->need_unlock = TRUE;
-
- /* Go on deleting parts */
- ctx->current = self->priv->parts;
- delete_next_part (task);
-}
-
-static void
-sms_delete (MMBaseSms *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- SmsDeletePartsContext *ctx;
- GTask *task;
-
- ctx = g_slice_new0 (SmsDeletePartsContext);
- ctx->modem = g_object_ref (self->priv->modem);
-
- task = g_task_new (self, NULL, callback, user_data);
- g_task_set_task_data (task, ctx, (GDestroyNotify)sms_delete_parts_context_free);
-
- if (mm_base_sms_get_storage (self) == MM_SMS_STORAGE_UNKNOWN) {
- mm_obj_dbg (self, "not removing parts from non-stored SMS");
- g_task_return_boolean (task, TRUE);
- g_object_unref (task);
- return;
- }
-
- /* Select specific storage to delete from */
- mm_broadband_modem_lock_sms_storages (
- MM_BROADBAND_MODEM (self->priv->modem),
- mm_base_sms_get_storage (self),
- MM_SMS_STORAGE_UNKNOWN, /* none required for mem2 */
- (GAsyncReadyCallback)delete_lock_sms_storages_ready,
- task);
-}
-
-/*****************************************************************************/
-
gboolean
mm_base_sms_delete_finish (MMBaseSms *self,
GAsyncResult *res,
@@ -1800,28 +1092,15 @@ mm_base_sms_multipart_take_part (MMBaseSms *self,
return TRUE;
}
-MMBaseSms *
-mm_base_sms_new (MMBaseModem *modem)
-{
- return MM_BASE_SMS (g_object_new (MM_TYPE_BASE_SMS,
- MM_BASE_SMS_MODEM, modem,
- MM_BIND_TO, modem,
- NULL));
-}
-
-MMBaseSms *
-mm_base_sms_singlepart_new (MMBaseModem *modem,
- MMSmsState state,
- MMSmsStorage storage,
- MMSmsPart *part,
- GError **error)
+gboolean
+mm_base_sms_singlepart_init (MMBaseSms *self,
+ MMSmsState state,
+ MMSmsStorage storage,
+ MMSmsPart *part,
+ GError **error)
{
- MMBaseSms *self;
-
- g_assert (MM_IS_IFACE_MODEM_MESSAGING (modem));
+ g_assert (self->priv->initialized == FALSE);
- /* 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", state,
"storage", storage,
@@ -1837,34 +1116,31 @@ mm_base_sms_singlepart_new (MMBaseModem *modem,
/* Note: we need to remove the part from the list, as we really didn't
* take it, and therefore the caller is responsible for freeing it. */
self->priv->parts = g_list_remove (self->priv->parts, part);
- g_clear_object (&self);
- } else
- /* Only export once properly created */
- mm_base_sms_export (self);
+ return FALSE;
+ }
- return self;
+ /* Only export once properly created */
+ self->priv->initialized = TRUE;
+ mm_base_sms_export (self);
+ return TRUE;
}
-MMBaseSms *
-mm_base_sms_multipart_new (MMBaseModem *modem,
- MMSmsState state,
- MMSmsStorage storage,
- guint reference,
- guint max_parts,
- MMSmsPart *first_part,
- GError **error)
+gboolean
+mm_base_sms_multipart_init (MMBaseSms *self,
+ MMSmsState state,
+ MMSmsStorage storage,
+ guint reference,
+ guint max_parts,
+ MMSmsPart *first_part,
+ GError **error)
{
- MMBaseSms *self;
-
- g_assert (MM_IS_IFACE_MODEM_MESSAGING (modem));
+ g_assert (self->priv->initialized == FALSE);
/* If this is the first part of a RECEIVED SMS, we overwrite the state
* as RECEIVING, to indicate that it is not completed yet. */
if (state == MM_SMS_STATE_RECEIVED)
state = MM_SMS_STATE_RECEIVING;
- /* 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,
MM_BASE_SMS_IS_MULTIPART, TRUE,
MM_BASE_SMS_MAX_PARTS, max_parts,
@@ -1878,29 +1154,28 @@ mm_base_sms_multipart_new (MMBaseModem *modem,
NULL);
if (!mm_base_sms_multipart_take_part (self, first_part, error))
- g_clear_object (&self);
+ return FALSE;
/* We do export incomplete multipart messages, in order to be able to
* request removal of all parts of those multipart SMS that will never
* get completed.
* Only the STATE of the SMS object will be valid in the exported DBus
* interface.*/
- if (self)
- mm_base_sms_export (self);
+ self->priv->initialized = TRUE;
+ mm_base_sms_export (self);
- return self;
+ return TRUE;
}
-MMBaseSms *
-mm_base_sms_new_from_properties (MMBaseModem *modem,
- MMSmsProperties *props,
- GError **error)
+gboolean
+mm_base_sms_init_from_properties (MMBaseSms *self,
+ MMSmsProperties *props,
+ GError **error)
{
- MMBaseSms *self;
const gchar *text;
GByteArray *data;
- g_assert (MM_IS_IFACE_MODEM_MESSAGING (modem));
+ g_assert (self->priv->initialized == FALSE);
text = mm_sms_properties_get_text (props);
data = mm_sms_properties_peek_data_bytearray (props);
@@ -1914,7 +1189,7 @@ mm_base_sms_new_from_properties (MMBaseModem *modem,
"Cannot create SMS: mandatory parameter '%s' is missing",
(!mm_sms_properties_get_number (props)?
"number" : "text' or 'data"));
- return NULL;
+ return FALSE;
}
/* Don't create SMS from properties if both text and data are given */
@@ -1923,11 +1198,9 @@ mm_base_sms_new_from_properties (MMBaseModem *modem,
MM_CORE_ERROR,
MM_CORE_ERROR_INVALID_ARGS,
"Cannot create SMS: both 'text' and 'data' given");
- return NULL;
+ return FALSE;
}
- /* 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,
@@ -1955,10 +1228,11 @@ mm_base_sms_new_from_properties (MMBaseModem *modem,
g_variant_new ("(uv)", MM_SMS_VALIDITY_TYPE_UNKNOWN, g_variant_new_boolean (FALSE))),
NULL);
- /* Only export once properly created */
+ /* Only export once properly initialized */
+ self->priv->initialized = TRUE;
mm_base_sms_export (self);
- return self;
+ return TRUE;
}
/*****************************************************************************/
@@ -1974,6 +1248,19 @@ log_object_build_id (MMLogObject *_self)
/*****************************************************************************/
+/* FIXME: use g_array_copy() when glib min version is >= 2.62 */
+static GArray *
+copy_storage_array (GArray *orig)
+{
+ GArray *copy = NULL;
+
+ if (orig) {
+ copy = g_array_sized_new (FALSE, FALSE, sizeof (MMSmsStorage), orig->len);
+ g_array_append_vals (copy, orig->data, orig->len);
+ }
+ return copy;
+}
+
static void
set_property (GObject *object,
guint prop_id,
@@ -2008,10 +1295,6 @@ set_property (GObject *object,
self->priv->bind_to = g_value_dup_object (value);
mm_bind_to (MM_BIND (self), MM_BASE_SMS_CONNECTION, self->priv->bind_to);
break;
- case PROP_MODEM:
- g_clear_object (&self->priv->modem);
- self->priv->modem = g_value_dup_object (value);
- break;
case PROP_IS_MULTIPART:
self->priv->is_multipart = g_value_get_boolean (value);
break;
@@ -2021,6 +1304,17 @@ set_property (GObject *object,
case PROP_MULTIPART_REFERENCE:
self->priv->multipart_reference = g_value_get_uint (value);
break;
+ case PROP_IS_3GPP:
+ self->priv->is_3gpp = g_value_get_boolean (value);
+ break;
+ case PROP_DEFAULT_STORAGE:
+ self->priv->default_storage = g_value_get_enum (value);
+ break;
+ case PROP_SUPPORTED_STORAGES:
+ /* Copy the array rather than just ref-ing it */
+ g_clear_pointer (&self->priv->supported_storages, (GDestroyNotify)g_array_unref);
+ self->priv->supported_storages = copy_storage_array (g_value_get_boxed (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2045,9 +1339,6 @@ get_property (GObject *object,
case PROP_BIND_TO:
g_value_set_object (value, self->priv->bind_to);
break;
- case PROP_MODEM:
- g_value_set_object (value, self->priv->modem);
- break;
case PROP_IS_MULTIPART:
g_value_set_boolean (value, self->priv->is_multipart);
break;
@@ -2057,6 +1348,15 @@ get_property (GObject *object,
case PROP_MULTIPART_REFERENCE:
g_value_set_uint (value, self->priv->multipart_reference);
break;
+ case PROP_IS_3GPP:
+ g_value_set_boolean (value, self->priv->is_3gpp);
+ break;
+ case PROP_DEFAULT_STORAGE:
+ g_value_set_enum (value, self->priv->default_storage);
+ break;
+ case PROP_SUPPORTED_STORAGES:
+ g_value_set_boxed (value, copy_storage_array (self->priv->supported_storages));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2104,10 +1404,10 @@ dispose (GObject *object)
g_clear_object (&self->priv->connection);
}
- g_clear_object (&self->priv->modem);
g_clear_object (&self->priv->bind_to);
g_cancellable_cancel (self->priv->authp_cancellable);
g_clear_object (&self->priv->authp_cancellable);
+ g_clear_pointer (&self->priv->supported_storages, (GDestroyNotify)g_array_unref);
G_OBJECT_CLASS (mm_base_sms_parent_class)->dispose (object);
}
@@ -2136,13 +1436,6 @@ mm_base_sms_class_init (MMBaseSmsClass *klass)
object_class->finalize = finalize;
object_class->dispose = dispose;
- klass->store = sms_store;
- klass->store_finish = sms_store_finish;
- klass->send = sms_send;
- klass->send_finish = sms_send_finish;
- klass->delete = sms_delete;
- klass->delete_finish = sms_delete_finish;
-
properties[PROP_CONNECTION] =
g_param_spec_object (MM_BASE_SMS_CONNECTION,
"Connection",
@@ -2161,14 +1454,6 @@ mm_base_sms_class_init (MMBaseSmsClass *klass)
g_object_class_override_property (object_class, PROP_BIND_TO, MM_BIND_TO);
- properties[PROP_MODEM] =
- g_param_spec_object (MM_BASE_SMS_MODEM,
- "Modem",
- "The Modem which owns this SMS",
- MM_TYPE_BASE_MODEM,
- G_PARAM_READWRITE);
- g_object_class_install_property (object_class, PROP_MODEM, properties[PROP_MODEM]);
-
properties[PROP_IS_MULTIPART] =
g_param_spec_boolean (MM_BASE_SMS_IS_MULTIPART,
"Is multipart",
@@ -2192,4 +1477,39 @@ mm_base_sms_class_init (MMBaseSmsClass *klass)
0, G_MAXUINT, 0,
G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_MULTIPART_REFERENCE, properties[PROP_MULTIPART_REFERENCE]);
+
+ properties[PROP_IS_3GPP] =
+ g_param_spec_boolean (MM_BASE_SMS_IS_3GPP,
+ "Is 3GPP",
+ "Whether the SMS is a 3GPP one or a CDMA one",
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_IS_3GPP, properties[PROP_IS_3GPP]);
+
+ properties[PROP_DEFAULT_STORAGE] =
+ g_param_spec_enum (MM_BASE_SMS_DEFAULT_STORAGE,
+ "Default storage",
+ "Default SMS storage",
+ MM_TYPE_SMS_STORAGE,
+ MM_SMS_STORAGE_UNKNOWN,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_DEFAULT_STORAGE, properties[PROP_DEFAULT_STORAGE]);
+
+ properties[PROP_SUPPORTED_STORAGES] =
+ g_param_spec_boxed (MM_BASE_SMS_SUPPORTED_STORAGES,
+ "Supported storages",
+ "Array of MMSmsStorage indicating supported storages for storing the SMS",
+ G_TYPE_ARRAY,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_SUPPORTED_STORAGES, properties[PROP_SUPPORTED_STORAGES]);
+
+ /* Signals */
+ signals[SIGNAL_SET_LOCAL_MULTIPART_REFERENCE] =
+ g_signal_new (MM_BASE_SMS_SET_LOCAL_MULTIPART_REFERENCE,
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (MMBaseSmsClass, set_local_multipart_reference),
+ NULL, NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_NONE, 0);
}