diff options
author | Dan Williams <dan@ioncontrol.co> | 2025-04-18 08:57:49 -0500 |
---|---|---|
committer | Dan Williams <dan@ioncontrol.co> | 2025-05-08 20:24:37 -0500 |
commit | 9830e3955a3e45ff82c1c76bcba3b53432eaa51e (patch) | |
tree | 6141fb7aeee5422c56acd7733341a85e4d0c0ed2 /src/mm-base-sms.c | |
parent | 6d0e4daf877e0600966bbf9fb34dfba14b2ccb54 (diff) |
base-sms,sms-at: split AT-specific SMS code into MMSmsAt
Simplify MMBaseSms (making it easier to use from testcases) by
splitting the AT-specific code into MMSmsAt rather than keeping
it in the base class.
Signed-off-by: Dan Williams <dan@ioncontrol.co>
Diffstat (limited to 'src/mm-base-sms.c')
-rw-r--r-- | src/mm-base-sms.c | 762 |
1 files changed, 0 insertions, 762 deletions
diff --git a/src/mm-base-sms.c b/src/mm-base-sms.c index 1b022614..d6c93d0c 100644 --- a/src/mm-base-sms.c +++ b/src/mm-base-sms.c @@ -32,8 +32,6 @@ #include "mm-iface-modem.h" #include "mm-iface-modem-messaging.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" @@ -781,749 +779,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_iface_modem_messaging_unlock_storages (MM_IFACE_MODEM_MESSAGING (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 (MMIfaceModemMessaging *messaging, - GAsyncResult *res, - GTask *task) -{ - MMBaseSms *self; - SmsStoreContext *ctx; - GError *error = NULL; - - if (!mm_iface_modem_messaging_lock_storages_finish (messaging, 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_assert (MM_IS_IFACE_MODEM_MESSAGING (self->priv->modem)); - 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 */ - mm_iface_modem_messaging_lock_storages ( - MM_IFACE_MODEM_MESSAGING (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_iface_modem_messaging_unlock_storages (MM_IFACE_MODEM_MESSAGING (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 (MMIfaceModemMessaging *messaging, - GAsyncResult *res, - GTask *task) -{ - MMBaseSms *self; - SmsSendContext *ctx; - GError *error = NULL; - - if (!mm_iface_modem_messaging_lock_storages_finish (messaging, 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_IFACE_MODEM_MESSAGING (self->priv->modem)); - mm_iface_modem_messaging_lock_storages ( - MM_IFACE_MODEM_MESSAGING (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_iface_modem_messaging_unlock_storages (MM_IFACE_MODEM_MESSAGING (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 (MMIfaceModemMessaging *messaging, - GAsyncResult *res, - GTask *task) -{ - MMBaseSms *self; - SmsDeletePartsContext *ctx; - GError *error = NULL; - - if (!mm_iface_modem_messaging_lock_storages_finish (messaging, 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_iface_modem_messaging_lock_storages ( - MM_IFACE_MODEM_MESSAGING (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, @@ -1797,16 +1052,6 @@ mm_base_sms_multipart_take_part (MMBaseSms *self, } MMBaseSms * -mm_base_sms_new (MMBaseModem *modem, gboolean is_3gpp) -{ - return MM_BASE_SMS (g_object_new (MM_TYPE_BASE_SMS, - MM_BASE_SMS_MODEM, modem, - MM_BIND_TO, modem, - MM_BASE_SMS_IS_3GPP, is_3gpp, - NULL)); -} - -MMBaseSms * mm_base_sms_singlepart_new (MMBaseModem *modem, MMSmsState state, MMSmsStorage storage, @@ -2139,13 +1384,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", |