Merge request !1341 from 'mbim-multipart-fix'
sms: always use SMS_PART_INVALID_INDEX unstored parts https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/merge_requests/1341 Closes #979
This commit is contained in:
+30
-4
@@ -210,6 +210,7 @@ libport_dep = declare_dependency(
|
||||
sources = files(
|
||||
'mm-auth-provider.c',
|
||||
'mm-context.c',
|
||||
'mm-bind.c',
|
||||
)
|
||||
|
||||
incs = [
|
||||
@@ -239,6 +240,33 @@ libauth_dep = declare_dependency(
|
||||
link_with: libauth,
|
||||
)
|
||||
|
||||
# SMS library
|
||||
sources = files(
|
||||
'mm-sms-list.c',
|
||||
'mm-base-sms.c',
|
||||
)
|
||||
|
||||
incs = [
|
||||
top_inc,
|
||||
]
|
||||
|
||||
deps = [libmm_glib_dep, libhelpers_dep, libauth_dep]
|
||||
|
||||
private_deps = []
|
||||
|
||||
libsms = static_library(
|
||||
'sms',
|
||||
sources: sources,
|
||||
include_directories: incs,
|
||||
dependencies: deps,
|
||||
)
|
||||
|
||||
libsms_dep = declare_dependency(
|
||||
include_directories: ['.'],
|
||||
dependencies: deps,
|
||||
link_with: libsms,
|
||||
)
|
||||
|
||||
# Daemon enums, required by plugins
|
||||
headers = files(
|
||||
'mm-base-bearer.h',
|
||||
@@ -297,14 +325,12 @@ sources = files(
|
||||
'mm-base-modem-at.c',
|
||||
'mm-base-modem.c',
|
||||
'mm-base-sim.c',
|
||||
'mm-base-sms.c',
|
||||
'mm-bind.c',
|
||||
'mm-sms-at.c',
|
||||
'mm-bearer-list.c',
|
||||
'mm-broadband-bearer.c',
|
||||
'mm-broadband-modem.c',
|
||||
'mm-call-list.c',
|
||||
'mm-cbm-list.c',
|
||||
'mm-context.c',
|
||||
'mm-device.c',
|
||||
'mm-dispatcher.c',
|
||||
'mm-dispatcher-connection.c',
|
||||
@@ -333,7 +359,6 @@ sources = files(
|
||||
'mm-port-probe.c',
|
||||
'mm-port-probe-at.c',
|
||||
'mm-private-boxed-types.c',
|
||||
'mm-sms-list.c',
|
||||
'mm-sleep-context.c',
|
||||
)
|
||||
|
||||
@@ -343,6 +368,7 @@ deps = [
|
||||
gmodule_dep,
|
||||
libport_dep,
|
||||
libqcdm_dep,
|
||||
libsms_dep,
|
||||
libauth_dep,
|
||||
]
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "mm-iface-modem-3gpp-profile-manager.h"
|
||||
#include "mm-iface-modem-cdma.h"
|
||||
#include "mm-base-bearer.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-base-modem.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
|
||||
+189
-869
File diff suppressed because it is too large
Load Diff
+30
-19
@@ -25,7 +25,6 @@
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-sms-part.h"
|
||||
#include "mm-base-modem.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -46,12 +45,19 @@ typedef struct _MMBaseSms MMBaseSms;
|
||||
typedef struct _MMBaseSmsClass MMBaseSmsClass;
|
||||
typedef struct _MMBaseSmsPrivate MMBaseSmsPrivate;
|
||||
|
||||
/* Properties */
|
||||
#define MM_BASE_SMS_PATH "sms-path"
|
||||
#define MM_BASE_SMS_CONNECTION "sms-connection"
|
||||
#define MM_BASE_SMS_MODEM "sms-modem"
|
||||
#define MM_BASE_SMS_IS_MULTIPART "sms-is-multipart"
|
||||
#define MM_BASE_SMS_MAX_PARTS "sms-max-parts"
|
||||
#define MM_BASE_SMS_MULTIPART_REFERENCE "sms-multipart-reference"
|
||||
#define MM_BASE_SMS_IS_3GPP "sms-is-3gpp"
|
||||
#define MM_BASE_SMS_DEFAULT_STORAGE "sms-default-storage"
|
||||
#define MM_BASE_SMS_SUPPORTED_STORAGES "sms-supported-storages"
|
||||
#define MM_BASE_SMS_CONNECTION_PARENT_PROPERTY_NAME "sms-connection-parent-property-name"
|
||||
|
||||
/* Signals */
|
||||
#define MM_BASE_SMS_SET_LOCAL_MULTIPART_REFERENCE "sms-set-local-multipart-reference"
|
||||
|
||||
struct _MMBaseSms {
|
||||
MmGdbusSmsSkeleton parent;
|
||||
@@ -85,28 +91,31 @@ struct _MMBaseSmsClass {
|
||||
gboolean (* delete_finish) (MMBaseSms *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
/* Signal */
|
||||
void (*set_local_multipart_reference) (MMBaseSms *self,
|
||||
const gchar *number);
|
||||
};
|
||||
|
||||
GType mm_base_sms_get_type (void);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMBaseSms, g_object_unref)
|
||||
|
||||
/* This one can be overridden by plugins */
|
||||
MMBaseSms *mm_base_sms_new (MMBaseModem *modem);
|
||||
MMBaseSms *mm_base_sms_new_from_properties (MMBaseModem *modem,
|
||||
MMSmsProperties *properties,
|
||||
GError **error);
|
||||
MMBaseSms *mm_base_sms_singlepart_new (MMBaseModem *modem,
|
||||
MMSmsState state,
|
||||
MMSmsStorage storage,
|
||||
MMSmsPart *part,
|
||||
GError **error);
|
||||
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_init_from_properties (MMBaseSms *self,
|
||||
MMSmsProperties *properties,
|
||||
GError **error);
|
||||
gboolean mm_base_sms_singlepart_init (MMBaseSms *self,
|
||||
MMSmsState state,
|
||||
MMSmsStorage storage,
|
||||
MMSmsPart *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);
|
||||
|
||||
gboolean mm_base_sms_multipart_take_part (MMBaseSms *self,
|
||||
MMSmsPart *part,
|
||||
GError **error);
|
||||
@@ -123,6 +132,8 @@ GList *mm_base_sms_get_parts (MMBaseSms *self);
|
||||
gboolean mm_base_sms_is_multipart (MMBaseSms *self);
|
||||
guint mm_base_sms_get_max_parts (MMBaseSms *self);
|
||||
guint mm_base_sms_get_multipart_reference (MMBaseSms *self);
|
||||
void mm_base_sms_set_multipart_reference (MMBaseSms *self,
|
||||
guint reference);
|
||||
gboolean mm_base_sms_multipart_is_complete (MMBaseSms *self);
|
||||
gboolean mm_base_sms_multipart_is_assembled (MMBaseSms *self);
|
||||
|
||||
|
||||
@@ -5840,6 +5840,7 @@ static gboolean process_pdu_messages (MMBroadbandModemMbim *self,
|
||||
guint32 messages_count,
|
||||
MbimSmsPduReadRecordArray *pdu_messages,
|
||||
guint expected_index,
|
||||
gboolean unstored,
|
||||
GError **error);
|
||||
|
||||
static void
|
||||
@@ -5864,6 +5865,7 @@ sms_notification_read_flash_sms (MMBroadbandModemMbim *self,
|
||||
messages_count,
|
||||
pdu_messages,
|
||||
SMS_PART_INVALID_INDEX,
|
||||
TRUE,
|
||||
&error))
|
||||
mm_obj_dbg (self, "flash SMS message reading failed: %s", error->message);
|
||||
}
|
||||
@@ -5943,6 +5945,7 @@ alert_sms_read_query_ready (MbimDevice *device,
|
||||
messages_count,
|
||||
pdu_messages,
|
||||
ctx->expected_index,
|
||||
FALSE,
|
||||
&error))
|
||||
mm_obj_dbg (ctx->self, "SMS message reading failed: %s", error->message);
|
||||
|
||||
@@ -9024,35 +9027,45 @@ load_initial_sms_parts_finish (MMIfaceModemMessaging *self,
|
||||
static void
|
||||
add_sms_part (MMBroadbandModemMbim *self,
|
||||
const MbimSmsPduReadRecord *pdu,
|
||||
guint part_index,
|
||||
guint expected_index)
|
||||
{
|
||||
MMSmsPart *part;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
part = mm_sms_part_3gpp_new_from_binary_pdu (pdu->message_index,
|
||||
part = mm_sms_part_3gpp_new_from_binary_pdu (part_index,
|
||||
pdu->pdu_data,
|
||||
pdu->pdu_data_size,
|
||||
self,
|
||||
FALSE,
|
||||
&error);
|
||||
if (part) {
|
||||
mm_obj_dbg (self, "correctly parsed PDU (%d)", pdu->message_index);
|
||||
if (expected_index != SMS_PART_INVALID_INDEX && (expected_index != mm_sms_part_get_index (part))) {
|
||||
/* Some Fibocom L850 modems report an invalid part index (always 1) in the response
|
||||
* message. Because we know which message part was requested, we can use that value
|
||||
* instead to workaround this bug. */
|
||||
mm_obj_dbg (self, "Expected SMS part index '%u' but device reports index '%u': using the expected one",
|
||||
expected_index, mm_sms_part_get_index (part));
|
||||
mm_sms_part_set_index (part, expected_index);
|
||||
}
|
||||
mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
part,
|
||||
mm_sms_state_from_mbim_message_status (pdu->message_status),
|
||||
MM_SMS_STORAGE_MT);
|
||||
} else {
|
||||
if (!part) {
|
||||
/* Don't treat the error as critical */
|
||||
mm_obj_dbg (self, "error parsing PDU (%d): %s",
|
||||
pdu->message_index, error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "correctly parsed PDU (%d)", pdu->message_index);
|
||||
if (expected_index != SMS_PART_INVALID_INDEX && (expected_index != mm_sms_part_get_index (part))) {
|
||||
/* Some Fibocom L850 modems report an invalid part index (always 1) in the response
|
||||
* message. Because we know which message part was requested, we can use that value
|
||||
* instead to workaround this bug. */
|
||||
mm_obj_dbg (self, "Expected SMS part index '%u' but device reports index '%u': using the expected one",
|
||||
expected_index, mm_sms_part_get_index (part));
|
||||
mm_sms_part_set_index (part, expected_index);
|
||||
}
|
||||
|
||||
if (!mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
mm_broadband_modem_create_sms (MM_BROADBAND_MODEM (self)),
|
||||
part,
|
||||
mm_sms_state_from_mbim_message_status (pdu->message_status),
|
||||
MM_SMS_STORAGE_MT,
|
||||
&error)) {
|
||||
/* Don't treat the error as critical */
|
||||
mm_obj_dbg (self, "error adding SMS (%d): %s",
|
||||
pdu->message_index, error->message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9062,6 +9075,7 @@ process_pdu_messages (MMBroadbandModemMbim *self,
|
||||
guint32 messages_count,
|
||||
MbimSmsPduReadRecordArray *pdu_messages,
|
||||
guint expected_index,
|
||||
gboolean unstored,
|
||||
GError **error)
|
||||
{
|
||||
guint i;
|
||||
@@ -9087,11 +9101,26 @@ process_pdu_messages (MMBroadbandModemMbim *self,
|
||||
|
||||
mm_obj_dbg (self, "%u SMS PDUs reported", messages_count);
|
||||
for (i = 0; i < messages_count; i++) {
|
||||
if (pdu_messages[i]) {
|
||||
mm_obj_dbg (self, "processing SMS PDU %u/%u...", i+1, messages_count);
|
||||
add_sms_part (self, pdu_messages[i], expected_index);
|
||||
} else
|
||||
guint message_index;
|
||||
|
||||
if (!pdu_messages[i]) {
|
||||
mm_obj_dbg (self, "ignoring invalid SMS PDU %u/%u...", i+1, messages_count);
|
||||
continue;
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "processing SMS PDU %u/%u...", i+1, messages_count);
|
||||
|
||||
message_index = pdu_messages[i]->message_index;
|
||||
if (unstored && message_index != 0) {
|
||||
mm_obj_warn (self,
|
||||
"processed unstored PDU with non-zero message index (%u)",
|
||||
message_index);
|
||||
}
|
||||
|
||||
add_sms_part (self,
|
||||
pdu_messages[i],
|
||||
unstored ? SMS_PART_INVALID_INDEX : message_index,
|
||||
expected_index);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
@@ -9126,6 +9155,7 @@ sms_read_query_ready (MbimDevice *device,
|
||||
messages_count,
|
||||
pdu_messages,
|
||||
SMS_PART_INVALID_INDEX,
|
||||
FALSE,
|
||||
&error))
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
@@ -9231,9 +9261,14 @@ enable_unsolicited_events_messaging (MMIfaceModemMessaging *_self,
|
||||
/* Create SMS (Messaging interface) */
|
||||
|
||||
static MMBaseSms *
|
||||
messaging_create_sms (MMIfaceModemMessaging *self)
|
||||
messaging_create_sms (MMBroadbandModem *self)
|
||||
{
|
||||
return mm_sms_mbim_new (MM_BASE_MODEM (self));
|
||||
MMSmsStorage default_storage;
|
||||
|
||||
default_storage = mm_iface_modem_messaging_get_default_storage (MM_IFACE_MODEM_MESSAGING (self));
|
||||
return mm_sms_mbim_new (MM_BASE_MODEM (self),
|
||||
mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self)),
|
||||
default_storage);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -10716,7 +10751,6 @@ iface_modem_messaging_init (MMIfaceModemMessagingInterface *iface)
|
||||
iface->enable_unsolicited_events_finish = common_enable_disable_unsolicited_events_messaging_finish;
|
||||
iface->disable_unsolicited_events = disable_unsolicited_events_messaging;
|
||||
iface->disable_unsolicited_events_finish = common_enable_disable_unsolicited_events_messaging_finish;
|
||||
iface->create_sms = messaging_create_sms;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -10786,6 +10820,7 @@ mm_broadband_modem_mbim_class_init (MMBroadbandModemMbimClass *klass)
|
||||
/* Do not initialize the MBIM modem through AT commands */
|
||||
broadband_modem_class->enabling_modem_init = NULL;
|
||||
broadband_modem_class->enabling_modem_init_finish = NULL;
|
||||
broadband_modem_class->create_sms = messaging_create_sms;
|
||||
|
||||
#if defined WITH_QMI && QMI_MBIM_QMUX_SUPPORTED
|
||||
g_object_class_install_property (object_class, PROP_QMI_UNSUPPORTED,
|
||||
|
||||
@@ -7938,8 +7938,8 @@ add_new_read_sms_part (MMIfaceModemMessaging *self,
|
||||
gboolean transfer_route,
|
||||
GArray *data)
|
||||
{
|
||||
MMSmsPart *part = NULL;
|
||||
GError *error = NULL;
|
||||
MMSmsPart *part = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
switch (format) {
|
||||
case QMI_WMS_MESSAGE_FORMAT_CDMA:
|
||||
@@ -7967,16 +7967,21 @@ add_new_read_sms_part (MMIfaceModemMessaging *self,
|
||||
break;
|
||||
}
|
||||
|
||||
if (part) {
|
||||
mm_obj_dbg (self, "correctly parsed PDU (%d)", index);
|
||||
mm_iface_modem_messaging_take_part (self,
|
||||
part,
|
||||
mm_sms_state_from_qmi_message_tag (tag),
|
||||
mm_sms_storage_from_qmi_storage_type (storage));
|
||||
} else if (error) {
|
||||
if (!part) {
|
||||
/* Don't treat the error as critical */
|
||||
mm_obj_dbg (self, "error parsing PDU (%d): %s", index, error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
mm_obj_dbg (self, "correctly parsed PDU (%d)", index);
|
||||
if (!mm_iface_modem_messaging_take_part (self,
|
||||
mm_broadband_modem_create_sms (MM_BROADBAND_MODEM (self)),
|
||||
part,
|
||||
mm_sms_state_from_qmi_message_tag (tag),
|
||||
mm_sms_storage_from_qmi_storage_type (storage),
|
||||
&error)) {
|
||||
/* Don't treat the error as critical */
|
||||
mm_obj_dbg (self, "error adding SMS (%d): %s", index, error->message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8409,7 +8414,6 @@ messaging_event_report_indication_cb (QmiClientNas *client,
|
||||
QmiWmsAckIndicator ack_ind;
|
||||
guint32 transaction_id;
|
||||
QmiWmsMessageFormat msg_format;
|
||||
QmiWmsMessageTagType tag;
|
||||
GArray *raw_data = NULL;
|
||||
|
||||
/* Handle transfer-route MT messages */
|
||||
@@ -8454,13 +8458,10 @@ messaging_event_report_indication_cb (QmiClientNas *client,
|
||||
}
|
||||
|
||||
/* Defaults for transfer-route messages, which are not stored anywhere */
|
||||
storage = QMI_WMS_STORAGE_TYPE_NONE;
|
||||
memory_index = 0;
|
||||
tag = QMI_WMS_MESSAGE_TAG_TYPE_MT_NOT_READ;
|
||||
add_new_read_sms_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
storage,
|
||||
memory_index,
|
||||
tag,
|
||||
QMI_WMS_STORAGE_TYPE_NONE,
|
||||
SMS_PART_INVALID_INDEX,
|
||||
QMI_WMS_MESSAGE_TAG_TYPE_MT_NOT_READ,
|
||||
msg_format,
|
||||
TRUE,
|
||||
raw_data);
|
||||
@@ -8870,19 +8871,23 @@ messaging_enable_unsolicited_events (MMIfaceModemMessaging *_self,
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Create SMS (Messaging interface) */
|
||||
/* Create SMS */
|
||||
|
||||
static MMBaseSms *
|
||||
messaging_create_sms (MMIfaceModemMessaging *_self)
|
||||
messaging_create_sms (MMBroadbandModem *_self)
|
||||
{
|
||||
MMBroadbandModemQmi *self = MM_BROADBAND_MODEM_QMI (_self);
|
||||
MMSmsStorage default_storage;
|
||||
|
||||
/* Handle AT URC only fallback */
|
||||
if (self->priv->messaging_fallback_at_only) {
|
||||
return iface_modem_messaging_parent->create_sms (_self);
|
||||
return MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_qmi_parent_class)->create_sms (_self);
|
||||
}
|
||||
|
||||
return mm_sms_qmi_new (MM_BASE_MODEM (self));
|
||||
default_storage = mm_iface_modem_messaging_get_default_storage (MM_IFACE_MODEM_MESSAGING (self));
|
||||
return mm_sms_qmi_new (MM_BASE_MODEM (self),
|
||||
mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self)),
|
||||
default_storage);
|
||||
}
|
||||
|
||||
|
||||
@@ -15330,7 +15335,6 @@ iface_modem_messaging_init (MMIfaceModemMessagingInterface *iface)
|
||||
iface->enable_unsolicited_events_finish = messaging_enable_unsolicited_events_finish;
|
||||
iface->disable_unsolicited_events = messaging_disable_unsolicited_events;
|
||||
iface->disable_unsolicited_events_finish = messaging_disable_unsolicited_events_finish;
|
||||
iface->create_sms = messaging_create_sms;
|
||||
iface->init_current_storages = messaging_init_current_storages;
|
||||
iface->init_current_storages_finish = messaging_init_current_storages_finish;
|
||||
}
|
||||
@@ -15469,4 +15473,5 @@ mm_broadband_modem_qmi_class_init (MMBroadbandModemQmiClass *klass)
|
||||
/* Do not initialize the QMI modem through AT commands */
|
||||
broadband_modem_class->enabling_modem_init = NULL;
|
||||
broadband_modem_class->enabling_modem_init_finish = NULL;
|
||||
broadband_modem_class->create_sms = messaging_create_sms;
|
||||
}
|
||||
|
||||
+116
-74
@@ -52,6 +52,7 @@
|
||||
#include "mm-cbm-part.h"
|
||||
#include "mm-sms-list.h"
|
||||
#include "mm-sms-part-3gpp.h"
|
||||
#include "mm-sms-at.h"
|
||||
#include "mm-call-list.h"
|
||||
#include "mm-base-sim.h"
|
||||
#include "mm-log-object.h"
|
||||
@@ -7185,11 +7186,13 @@ modem_messaging_init_current_storages (MMIfaceModemMessaging *self,
|
||||
* the default one if needed.
|
||||
*/
|
||||
|
||||
void
|
||||
mm_broadband_modem_unlock_sms_storages (MMBroadbandModem *self,
|
||||
gboolean mem1,
|
||||
gboolean mem2)
|
||||
static void
|
||||
modem_messaging_unlock_storages (MMIfaceModemMessaging *_self,
|
||||
gboolean mem1,
|
||||
gboolean mem2)
|
||||
{
|
||||
MMBroadbandModem *self = MM_BROADBAND_MODEM (_self);
|
||||
|
||||
if (mem1) {
|
||||
g_assert (self->priv->mem1_storage_locked);
|
||||
self->priv->mem1_storage_locked = FALSE;
|
||||
@@ -7201,10 +7204,10 @@ mm_broadband_modem_unlock_sms_storages (MMBroadbandModem *self,
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_broadband_modem_lock_sms_storages_finish (MMBroadbandModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
static gboolean
|
||||
modem_messaging_lock_storages_finish (MMIfaceModemMessaging *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
@@ -7246,13 +7249,14 @@ lock_storages_cpms_set_ready (MMBaseModem *_self,
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
void
|
||||
mm_broadband_modem_lock_sms_storages (MMBroadbandModem *self,
|
||||
MMSmsStorage mem1, /* reading/listing/deleting */
|
||||
MMSmsStorage mem2, /* storing/sending */
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
static void
|
||||
modem_messaging_lock_storages (MMIfaceModemMessaging *_self,
|
||||
MMSmsStorage mem1, /* reading/listing/deleting */
|
||||
MMSmsStorage mem2, /* storing/sending */
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBroadbandModem *self = MM_BROADBAND_MODEM (_self);
|
||||
LockSmsStoragesContext *ctx;
|
||||
GTask *task;
|
||||
gchar *cmd = NULL;
|
||||
@@ -7267,7 +7271,7 @@ mm_broadband_modem_lock_sms_storages (MMBroadbandModem *self,
|
||||
self,
|
||||
callback,
|
||||
user_data,
|
||||
mm_broadband_modem_lock_sms_storages,
|
||||
modem_messaging_lock_storages,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_RETRY,
|
||||
"SMS storage currently locked, try again later");
|
||||
@@ -7541,13 +7545,13 @@ sms_part_ready (MMBroadbandModem *self,
|
||||
GTask *task)
|
||||
{
|
||||
SmsPartContext *ctx;
|
||||
MMSmsPart *part;
|
||||
MM3gppPduInfo *info;
|
||||
const gchar *response;
|
||||
GError *error = NULL;
|
||||
MMSmsPart *part;
|
||||
MM3gppPduInfo *info;
|
||||
const gchar *response;
|
||||
GError *error = NULL;
|
||||
|
||||
/* Always always always unlock mem1 storage. Warned you've been. */
|
||||
mm_broadband_modem_unlock_sms_storages (self, TRUE, FALSE);
|
||||
mm_iface_modem_messaging_unlock_storages (MM_IFACE_MODEM_MESSAGING (self), TRUE, FALSE);
|
||||
|
||||
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
|
||||
if (error) {
|
||||
@@ -7570,16 +7574,22 @@ sms_part_ready (MMBroadbandModem *self,
|
||||
}
|
||||
|
||||
part = mm_sms_part_3gpp_new_from_pdu (info->index, info->pdu, self, &error);
|
||||
if (part) {
|
||||
mm_obj_dbg (self, "correctly parsed PDU (%d)", ctx->idx);
|
||||
mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
part,
|
||||
MM_SMS_STATE_RECEIVED,
|
||||
self->priv->modem_messaging_sms_default_storage);
|
||||
} else {
|
||||
if (!part) {
|
||||
/* Don't treat the error as critical */
|
||||
mm_obj_dbg (self, "error parsing PDU (%d): %s", ctx->idx, error->message);
|
||||
g_error_free (error);
|
||||
} else {
|
||||
mm_obj_dbg (self, "correctly parsed PDU (%d)", ctx->idx);
|
||||
if (!mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
mm_broadband_modem_create_sms (MM_BROADBAND_MODEM (self)),
|
||||
part,
|
||||
MM_SMS_STATE_RECEIVED,
|
||||
self->priv->modem_messaging_sms_default_storage,
|
||||
&error)) {
|
||||
/* Don't treat the error as critical */
|
||||
mm_obj_dbg (self, "error adding SMS (%d): %s", ctx->idx, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
/* All done */
|
||||
@@ -7589,15 +7599,15 @@ sms_part_ready (MMBroadbandModem *self,
|
||||
}
|
||||
|
||||
static void
|
||||
indication_lock_storages_ready (MMBroadbandModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
indication_lock_storages_ready (MMIfaceModemMessaging *messaging,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
SmsPartContext *ctx;
|
||||
gchar *command;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_broadband_modem_lock_sms_storages_finish (self, res, &error)) {
|
||||
if (!mm_iface_modem_messaging_lock_storages_finish (messaging, res, &error)) {
|
||||
/* TODO: we should either make this lock() never fail, by automatically
|
||||
* retrying after some time, or otherwise retry here. */
|
||||
g_task_return_error (task, error);
|
||||
@@ -7610,7 +7620,7 @@ indication_lock_storages_ready (MMBroadbandModem *self,
|
||||
/* Retrieve the message */
|
||||
ctx = g_task_get_task_data (task);
|
||||
command = g_strdup_printf ("+CMGR=%d", ctx->idx);
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||
mm_base_modem_at_command (MM_BASE_MODEM (messaging),
|
||||
command,
|
||||
10,
|
||||
FALSE,
|
||||
@@ -7658,11 +7668,11 @@ cmti_received (MMPortSerialAt *port,
|
||||
g_task_set_task_data (task, ctx, g_free);
|
||||
|
||||
/* First, request to set the proper storage to read from */
|
||||
mm_broadband_modem_lock_sms_storages (self,
|
||||
storage,
|
||||
MM_SMS_STORAGE_UNKNOWN,
|
||||
(GAsyncReadyCallback)indication_lock_storages_ready,
|
||||
task);
|
||||
mm_iface_modem_messaging_lock_storages (MM_IFACE_MODEM_MESSAGING (self),
|
||||
storage,
|
||||
MM_SMS_STORAGE_UNKNOWN,
|
||||
(GAsyncReadyCallback)indication_lock_storages_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -7670,10 +7680,10 @@ cds_received (MMPortSerialAt *port,
|
||||
GMatchInfo *info,
|
||||
MMBroadbandModem *self)
|
||||
{
|
||||
GError *error = NULL;
|
||||
MMSmsPart *part;
|
||||
guint length;
|
||||
gchar *pdu;
|
||||
g_autoptr(GError) error = NULL;
|
||||
MMSmsPart *part;
|
||||
guint length;
|
||||
gchar *pdu;
|
||||
|
||||
mm_obj_dbg (self, "got new non-stored message indication");
|
||||
|
||||
@@ -7685,16 +7695,20 @@ cds_received (MMPortSerialAt *port,
|
||||
return;
|
||||
|
||||
part = mm_sms_part_3gpp_new_from_pdu (SMS_PART_INVALID_INDEX, pdu, self, &error);
|
||||
if (part) {
|
||||
mm_obj_dbg (self, "correctly parsed non-stored PDU");
|
||||
mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
part,
|
||||
MM_SMS_STATE_RECEIVED,
|
||||
MM_SMS_STORAGE_UNKNOWN);
|
||||
} else {
|
||||
if (!part) {
|
||||
/* Don't treat the error as critical */
|
||||
mm_obj_dbg (self, "error parsing non-stored PDU: %s", error->message);
|
||||
g_error_free (error);
|
||||
} else {
|
||||
mm_obj_dbg (self, "correctly parsed non-stored PDU");
|
||||
if (!mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
mm_broadband_modem_create_sms (MM_BROADBAND_MODEM (self)),
|
||||
part,
|
||||
MM_SMS_STATE_RECEIVED,
|
||||
MM_SMS_STORAGE_UNKNOWN,
|
||||
&error)) {
|
||||
/* Don't treat the error as critical */
|
||||
mm_obj_dbg (self, "error adding SMS: %s", error->message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8078,10 +8092,16 @@ sms_text_part_list_ready (MMBroadbandModem *self,
|
||||
mm_sms_part_set_class (part, -1);
|
||||
|
||||
mm_obj_dbg (self, "correctly parsed SMS list entry (%d)", idx);
|
||||
mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
part,
|
||||
sms_state_from_str (stat),
|
||||
ctx->list_storage);
|
||||
if (!mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
mm_broadband_modem_create_sms (MM_BROADBAND_MODEM (self)),
|
||||
part,
|
||||
sms_state_from_str (stat),
|
||||
ctx->list_storage,
|
||||
&error)) {
|
||||
mm_obj_dbg (self, "failed to add SMS: %s", inner_error->message);
|
||||
goto next;
|
||||
}
|
||||
|
||||
next:
|
||||
g_match_info_next (match_info, NULL);
|
||||
}
|
||||
@@ -8120,7 +8140,7 @@ sms_pdu_part_list_ready (MMBroadbandModem *self,
|
||||
GList *l;
|
||||
|
||||
/* Always always always unlock mem1 storage. Warned you've been. */
|
||||
mm_broadband_modem_unlock_sms_storages (self, TRUE, FALSE);
|
||||
mm_iface_modem_messaging_unlock_storages (MM_IFACE_MODEM_MESSAGING (self), TRUE, FALSE);
|
||||
|
||||
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
|
||||
if (error) {
|
||||
@@ -8143,16 +8163,22 @@ sms_pdu_part_list_ready (MMBroadbandModem *self,
|
||||
MMSmsPart *part;
|
||||
|
||||
part = mm_sms_part_3gpp_new_from_pdu (info->index, info->pdu, self, &error);
|
||||
if (part) {
|
||||
mm_obj_dbg (self, "correctly parsed PDU (%d)", info->index);
|
||||
mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
part,
|
||||
sms_state_from_index (info->status),
|
||||
ctx->list_storage);
|
||||
} else {
|
||||
if (!part) {
|
||||
/* Don't treat the error as critical */
|
||||
mm_obj_dbg (self, "error parsing PDU (%d): %s", info->index, error->message);
|
||||
g_clear_error (&error);
|
||||
} else {
|
||||
mm_obj_dbg (self, "correctly parsed PDU (%d)", info->index);
|
||||
if (!mm_iface_modem_messaging_take_part (MM_IFACE_MODEM_MESSAGING (self),
|
||||
mm_broadband_modem_create_sms (MM_BROADBAND_MODEM (self)),
|
||||
part,
|
||||
sms_state_from_index (info->status),
|
||||
ctx->list_storage,
|
||||
&error)) {
|
||||
/* Don't treat the error as critical */
|
||||
mm_obj_dbg (self, "error adding SMS (%d): %s", info->index, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8164,13 +8190,13 @@ sms_pdu_part_list_ready (MMBroadbandModem *self,
|
||||
}
|
||||
|
||||
static void
|
||||
list_parts_lock_storages_ready (MMBroadbandModem *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
list_parts_lock_storages_ready (MMIfaceModemMessaging *self,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mm_broadband_modem_lock_sms_storages_finish (self, res, &error)) {
|
||||
if (!mm_iface_modem_messaging_lock_storages_finish (self, res, &error)) {
|
||||
/* TODO: we should either make this lock() never fail, by automatically
|
||||
* retrying after some time, or otherwise retry here. */
|
||||
g_task_return_error (task, error);
|
||||
@@ -8212,20 +8238,33 @@ modem_messaging_load_initial_sms_parts (MMIfaceModemMessaging *self,
|
||||
mm_obj_dbg (self, "listing SMS parts in storage '%s'", mm_sms_storage_get_string (storage));
|
||||
|
||||
/* First, request to set the proper storage to read from */
|
||||
mm_broadband_modem_lock_sms_storages (MM_BROADBAND_MODEM (self),
|
||||
storage,
|
||||
MM_SMS_STORAGE_UNKNOWN,
|
||||
(GAsyncReadyCallback)list_parts_lock_storages_ready,
|
||||
task);
|
||||
mm_iface_modem_messaging_lock_storages (self,
|
||||
storage,
|
||||
MM_SMS_STORAGE_UNKNOWN,
|
||||
(GAsyncReadyCallback)list_parts_lock_storages_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Create SMS (Messaging interface) */
|
||||
/* Create SMS */
|
||||
|
||||
MMBaseSms *
|
||||
mm_broadband_modem_create_sms (MMBroadbandModem *self)
|
||||
{
|
||||
g_assert (MM_BROADBAND_MODEM_GET_CLASS (self)->create_sms != NULL);
|
||||
|
||||
return MM_BROADBAND_MODEM_GET_CLASS (self)->create_sms (self);
|
||||
}
|
||||
|
||||
static MMBaseSms *
|
||||
modem_messaging_create_sms (MMIfaceModemMessaging *self)
|
||||
modem_messaging_create_sms (MMBroadbandModem *self)
|
||||
{
|
||||
return mm_base_sms_new (MM_BASE_MODEM (self));
|
||||
MMSmsStorage default_storage;
|
||||
|
||||
default_storage = mm_iface_modem_messaging_get_default_storage (MM_IFACE_MODEM_MESSAGING (self));
|
||||
return mm_sms_at_new (MM_BASE_MODEM (self),
|
||||
mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self)),
|
||||
default_storage);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -14537,9 +14576,11 @@ iface_modem_messaging_init (MMIfaceModemMessagingInterface *iface)
|
||||
iface->enable_unsolicited_events_finish = modem_messaging_enable_unsolicited_events_finish;
|
||||
iface->cleanup_unsolicited_events = modem_messaging_cleanup_unsolicited_events;
|
||||
iface->cleanup_unsolicited_events_finish = modem_messaging_setup_cleanup_unsolicited_events_finish;
|
||||
iface->create_sms = modem_messaging_create_sms;
|
||||
iface->init_current_storages = modem_messaging_init_current_storages;
|
||||
iface->init_current_storages_finish = modem_messaging_init_current_storages_finish;
|
||||
iface->lock_storages = modem_messaging_lock_storages;
|
||||
iface->lock_storages_finish = modem_messaging_lock_storages_finish;
|
||||
iface->unlock_storages = modem_messaging_unlock_storages;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -14656,6 +14697,7 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass)
|
||||
klass->disabling_stopped = disabling_stopped;
|
||||
klass->load_initial_eps_bearer_cid = load_initial_eps_bearer_cid;
|
||||
klass->load_initial_eps_bearer_cid_finish = load_initial_eps_bearer_cid_finish;
|
||||
klass->create_sms = modem_messaging_create_sms;
|
||||
|
||||
g_object_class_override_property (object_class,
|
||||
PROP_MODEM_DBUS_SKELETON,
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "mm-modem-helpers.h"
|
||||
#include "mm-charsets.h"
|
||||
#include "mm-base-modem.h"
|
||||
#include "mm-base-sms.h"
|
||||
|
||||
#define MM_TYPE_BROADBAND_MODEM (mm_broadband_modem_get_type ())
|
||||
#define MM_BROADBAND_MODEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM, MMBroadbandModem))
|
||||
@@ -105,6 +106,9 @@ struct _MMBroadbandModemClass {
|
||||
gint (* load_initial_eps_bearer_cid_finish) (MMBroadbandModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
/* Create SMS objects */
|
||||
MMBaseSms * (* create_sms) (MMBroadbandModem *self);
|
||||
};
|
||||
|
||||
GType mm_broadband_modem_get_type (void);
|
||||
@@ -126,18 +130,6 @@ gchar *mm_broadband_modem_create_device_identifier (MMBroadbandModem *self,
|
||||
const gchar *ati1,
|
||||
GError **error);
|
||||
|
||||
/* Locking/unlocking SMS storages */
|
||||
void mm_broadband_modem_lock_sms_storages (MMBroadbandModem *self,
|
||||
MMSmsStorage mem1, /* reading/listing/deleting */
|
||||
MMSmsStorage mem2, /* storing/sending */
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_broadband_modem_lock_sms_storages_finish (MMBroadbandModem *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
void mm_broadband_modem_unlock_sms_storages (MMBroadbandModem *self,
|
||||
gboolean mem1,
|
||||
gboolean mem2);
|
||||
/* Helper to update SIM hot swap */
|
||||
gboolean mm_broadband_modem_sim_hot_swap_ports_context_init (MMBroadbandModem *self,
|
||||
GError **error);
|
||||
@@ -152,4 +144,7 @@ gboolean mm_broadband_modem_get_active_multiplexed_bearers (MMBroadbandModem *s
|
||||
/* Helper to manage initial EPS bearer */
|
||||
gint mm_broadband_modem_get_initial_eps_bearer_cid (MMBroadbandModem *self);
|
||||
|
||||
/* Helper to create a new modem-specific SMS object */
|
||||
MMBaseSms *mm_broadband_modem_create_sms (MMBroadbandModem *self);
|
||||
|
||||
#endif /* MM_BROADBAND_MODEM_H */
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "mm-sms-list.h"
|
||||
#include "mm-error-helpers.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
|
||||
#define SUPPORT_CHECKED_TAG "messaging-support-checked-tag"
|
||||
#define SUPPORTED_TAG "messaging-supported-tag"
|
||||
@@ -35,54 +36,6 @@ G_DEFINE_INTERFACE (MMIfaceModemMessaging, mm_iface_modem_messaging, MM_TYPE_IFA
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
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)
|
||||
@@ -91,12 +44,45 @@ mm_iface_modem_messaging_bind_simple_status (MMIfaceModemMessaging *self,
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseSms *
|
||||
mm_iface_modem_messaging_create_sms (MMIfaceModemMessaging *self)
|
||||
void
|
||||
mm_iface_modem_messaging_lock_storages (MMIfaceModemMessaging *self,
|
||||
MMSmsStorage mem1,
|
||||
MMSmsStorage mem2,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_assert (MM_IFACE_MODEM_MESSAGING_GET_IFACE (self)->create_sms != NULL);
|
||||
g_assert (MM_IFACE_MODEM_MESSAGING_GET_IFACE (self)->lock_storages != NULL);
|
||||
|
||||
return MM_IFACE_MODEM_MESSAGING_GET_IFACE (self)->create_sms (self);
|
||||
MM_IFACE_MODEM_MESSAGING_GET_IFACE (self)->lock_storages (self,
|
||||
mem1,
|
||||
mem2,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_iface_modem_messaging_lock_storages_finish (MMIfaceModemMessaging *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
|
||||
{
|
||||
g_assert (MM_IFACE_MODEM_MESSAGING_GET_IFACE (self)->lock_storages_finish != NULL);
|
||||
|
||||
return MM_IFACE_MODEM_MESSAGING_GET_IFACE (self)->lock_storages_finish (self,
|
||||
res,
|
||||
error);
|
||||
}
|
||||
|
||||
void
|
||||
mm_iface_modem_messaging_unlock_storages (MMIfaceModemMessaging *self,
|
||||
gboolean mem1,
|
||||
gboolean mem2)
|
||||
{
|
||||
g_assert (MM_IFACE_MODEM_MESSAGING_GET_IFACE (self)->unlock_storages != NULL);
|
||||
|
||||
MM_IFACE_MODEM_MESSAGING_GET_IFACE (self)->unlock_storages (self,
|
||||
mem1,
|
||||
mem2);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -296,8 +282,8 @@ handle_create_auth_ready (MMIfaceAuth *auth,
|
||||
return;
|
||||
}
|
||||
|
||||
sms = mm_base_sms_new_from_properties (MM_BASE_MODEM (self), properties, &error);
|
||||
if (!sms) {
|
||||
sms = mm_broadband_modem_create_sms (MM_BROADBAND_MODEM (self));
|
||||
if (!mm_base_sms_init_from_properties (sms, properties, &error)) {
|
||||
mm_dbus_method_invocation_take_error (ctx->invocation, error);
|
||||
handle_create_context_free (ctx);
|
||||
return;
|
||||
@@ -399,7 +385,8 @@ handle_set_default_storage_ready (MMIfaceModemMessaging *self,
|
||||
GAsyncResult *res,
|
||||
HandleSetDefaultStorageContext *ctx)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GError *error = NULL;
|
||||
g_autoptr(MMSmsList) list = NULL;
|
||||
|
||||
if (!MM_IFACE_MODEM_MESSAGING_GET_IFACE (self)->set_default_storage_finish (self, res, &error)) {
|
||||
mm_obj_warn (self, "could not set default storage: %s", error->message);
|
||||
@@ -412,6 +399,13 @@ handle_set_default_storage_ready (MMIfaceModemMessaging *self,
|
||||
MM_IFACE_MODEM_MESSAGING_SMS_DEFAULT_STORAGE, ctx->storage,
|
||||
NULL);
|
||||
|
||||
/* Update default storage in all SMSs too */
|
||||
g_object_get (self,
|
||||
MM_IFACE_MODEM_MESSAGING_SMS_LIST, &list,
|
||||
NULL);
|
||||
if (list)
|
||||
mm_sms_list_set_default_storage (list, ctx->storage);
|
||||
|
||||
mm_obj_info (self, "set the default storage successfully");
|
||||
mm_gdbus_modem_messaging_complete_set_default_storage (ctx->skeleton, ctx->invocation);
|
||||
handle_set_default_storage_context_free (ctx);
|
||||
@@ -482,13 +476,14 @@ handle_set_default_storage (MmGdbusModemMessaging *skeleton,
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean
|
||||
mm_iface_modem_messaging_take_part (MMIfaceModemMessaging *self,
|
||||
MMSmsPart *sms_part,
|
||||
MMSmsState state,
|
||||
MMSmsStorage storage)
|
||||
mm_iface_modem_messaging_take_part (MMIfaceModemMessaging *self,
|
||||
MMBaseSms *uninitialized_sms,
|
||||
MMSmsPart *sms_part,
|
||||
MMSmsState state,
|
||||
MMSmsStorage storage,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(MMSmsList) list = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
gboolean added = FALSE;
|
||||
|
||||
g_object_get (self,
|
||||
@@ -496,15 +491,20 @@ mm_iface_modem_messaging_take_part (MMIfaceModemMessaging *self,
|
||||
NULL);
|
||||
|
||||
if (list) {
|
||||
added = mm_sms_list_take_part (list, sms_part, state, storage, &error);
|
||||
added = mm_sms_list_take_part (list, uninitialized_sms, sms_part, state, storage, error);
|
||||
if (!added)
|
||||
mm_obj_dbg (self, "couldn't take part in SMS list: %s", error->message);
|
||||
g_prefix_error (error, "couldn't take part in SMS list: ");
|
||||
}
|
||||
|
||||
/* If part wasn't taken, we need to free the part ourselves */
|
||||
/* If part wasn't taken, we need to free the part and SMS ourselves */
|
||||
if (!added)
|
||||
mm_sms_part_free (sms_part);
|
||||
|
||||
/* Always drop original ref to the uninialized SMS, as MMSmsList will have
|
||||
* taken a reference to the SMS if it wants to keep it around.
|
||||
*/
|
||||
g_object_unref (uninitialized_sms);
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
@@ -558,6 +558,18 @@ mm_iface_modem_messaging_is_storage_supported_for_receiving (MMIfaceModemMessagi
|
||||
error);
|
||||
}
|
||||
|
||||
MMSmsStorage
|
||||
mm_iface_modem_messaging_get_default_storage (MMIfaceModemMessaging *self)
|
||||
{
|
||||
MMSmsStorage storage = MM_SMS_STORAGE_UNKNOWN;
|
||||
|
||||
g_object_get (self,
|
||||
MM_IFACE_MODEM_MESSAGING_SMS_DEFAULT_STORAGE, &storage,
|
||||
NULL);
|
||||
g_assert (storage != MM_SMS_STORAGE_UNKNOWN);
|
||||
return storage;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
@@ -1008,7 +1020,7 @@ interface_enabling_step (GTask *task)
|
||||
case ENABLING_STEP_FIRST: {
|
||||
MMSmsList *list;
|
||||
|
||||
list = mm_sms_list_new (MM_BASE_MODEM (self), G_OBJECT (self));
|
||||
list = mm_sms_list_new (G_OBJECT (self));
|
||||
g_object_set (self,
|
||||
MM_IFACE_MODEM_MESSAGING_SMS_LIST, list,
|
||||
NULL);
|
||||
|
||||
@@ -78,6 +78,21 @@ struct _MMIfaceModemMessagingInterface {
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
/* Lock storages (async) */
|
||||
void (*lock_storages) (MMIfaceModemMessaging *self,
|
||||
MMSmsStorage mem1, /* reading/listing/deleting */
|
||||
MMSmsStorage mem2, /* storing/sending */
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean (*lock_storages_finish) (MMIfaceModemMessaging *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
/* Unlock storages */
|
||||
void (*unlock_storages) (MMIfaceModemMessaging *self,
|
||||
gboolean mem1,
|
||||
gboolean mem2);
|
||||
|
||||
/* Setup SMS format (async) */
|
||||
void (* setup_sms_format) (MMIfaceModemMessaging *self,
|
||||
GAsyncReadyCallback callback,
|
||||
@@ -127,9 +142,6 @@ struct _MMIfaceModemMessagingInterface {
|
||||
gboolean (*load_initial_sms_parts_finish) (MMIfaceModemMessaging *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
/* Create SMS objects */
|
||||
MMBaseSms * (* create_sms) (MMIfaceModemMessaging *self);
|
||||
};
|
||||
|
||||
/* Initialize Messaging interface (async) */
|
||||
@@ -166,10 +178,12 @@ void mm_iface_modem_messaging_bind_simple_status (MMIfaceModemMessaging *self,
|
||||
MMSimpleStatus *status);
|
||||
|
||||
/* Report new SMS part */
|
||||
gboolean mm_iface_modem_messaging_take_part (MMIfaceModemMessaging *self,
|
||||
MMSmsPart *sms_part,
|
||||
MMSmsState state,
|
||||
MMSmsStorage storage);
|
||||
gboolean mm_iface_modem_messaging_take_part (MMIfaceModemMessaging *self,
|
||||
MMBaseSms *uninitialized_sms,
|
||||
MMSmsPart *sms_part,
|
||||
MMSmsState state,
|
||||
MMSmsStorage storage,
|
||||
GError **error);
|
||||
|
||||
/* Check storage support */
|
||||
gboolean mm_iface_modem_messaging_is_storage_supported_for_storing (MMIfaceModemMessaging *self,
|
||||
@@ -179,12 +193,22 @@ gboolean mm_iface_modem_messaging_is_storage_supported_for_receiving (MMIfaceMod
|
||||
MMSmsStorage storage,
|
||||
GError **error);
|
||||
|
||||
MMSmsStorage mm_iface_modem_messaging_get_default_storage (MMIfaceModemMessaging *self);
|
||||
|
||||
/* SMS creation */
|
||||
MMBaseSms *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);
|
||||
/* Locking/unlocking SMS storages */
|
||||
void mm_iface_modem_messaging_lock_storages (MMIfaceModemMessaging *self,
|
||||
MMSmsStorage mem1,
|
||||
MMSmsStorage mem2,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_iface_modem_messaging_lock_storages_finish (MMIfaceModemMessaging *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
void mm_iface_modem_messaging_unlock_storages (MMIfaceModemMessaging *self,
|
||||
gboolean mem1,
|
||||
gboolean mem2);
|
||||
|
||||
#endif /* MM_IFACE_MODEM_MESSAGING_H */
|
||||
|
||||
@@ -6616,25 +6616,25 @@ mm_iface_modem_get_current_capabilities (MMIfaceModem *self)
|
||||
gboolean
|
||||
mm_iface_modem_is_3gpp (MMIfaceModem *self)
|
||||
{
|
||||
return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_3GPP);
|
||||
return !!(mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_3GPP);
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_iface_modem_is_3gpp_lte (MMIfaceModem *self)
|
||||
{
|
||||
return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_LTE);
|
||||
return !!(mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_LTE);
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_iface_modem_is_3gpp_5gnr (MMIfaceModem *self)
|
||||
{
|
||||
return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_5GNR);
|
||||
return !!(mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_5GNR);
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_iface_modem_is_cdma (MMIfaceModem *self)
|
||||
{
|
||||
return (mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_CDMA_EVDO);
|
||||
return !!(mm_iface_modem_get_current_capabilities (self) & MM_MODEM_CAPABILITY_CDMA_EVDO);
|
||||
}
|
||||
|
||||
gboolean
|
||||
@@ -6643,13 +6643,13 @@ mm_iface_modem_is_3gpp_only (MMIfaceModem *self)
|
||||
MMModemCapability capabilities;
|
||||
|
||||
capabilities = mm_iface_modem_get_current_capabilities (self);
|
||||
return (capabilities & MM_MODEM_CAPABILITY_3GPP) && !((MM_MODEM_CAPABILITY_3GPP ^ capabilities) & capabilities);
|
||||
return !!((capabilities & MM_MODEM_CAPABILITY_3GPP) && !((MM_MODEM_CAPABILITY_3GPP ^ capabilities) & capabilities));
|
||||
}
|
||||
|
||||
gboolean
|
||||
mm_iface_modem_is_cdma_only (MMIfaceModem *self)
|
||||
{
|
||||
return (mm_iface_modem_get_current_capabilities (self) == MM_MODEM_CAPABILITY_CDMA_EVDO);
|
||||
return !!(mm_iface_modem_get_current_capabilities (self) == MM_MODEM_CAPABILITY_CDMA_EVDO);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
+839
@@ -0,0 +1,839 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2008 - 2009 Novell, Inc.
|
||||
* Copyright (C) 2009 - 2012 Red Hat, Inc.
|
||||
* Copyright (C) 2012 Google, Inc.
|
||||
* Copyright (C) 2025 Dan Williams <dan@ioncontrol.co>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <ModemManager.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-sms-at.h"
|
||||
#include "mm-iface-modem-messaging.h"
|
||||
#include "mm-sms-part-3gpp.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-bind.h"
|
||||
|
||||
G_DEFINE_TYPE (MMSmsAt, mm_sms_at, MM_TYPE_BASE_SMS)
|
||||
|
||||
struct _MMSmsAtPrivate {
|
||||
MMBaseModem *modem;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
sms_get_store_or_send_command (MMSmsAt *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)
|
||||
{
|
||||
MMSmsAt *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)
|
||||
{
|
||||
MMSmsAt *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 = mm_base_sms_get_parts (MM_BASE_SMS (self));
|
||||
sms_store_next_part (task);
|
||||
}
|
||||
|
||||
static void
|
||||
sms_store (MMBaseSms *sms,
|
||||
MMSmsStorage storage,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMSmsAt *self = MM_SMS_AT (sms);
|
||||
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)
|
||||
{
|
||||
MMSmsAt *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)
|
||||
{
|
||||
MMSmsAt *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)
|
||||
{
|
||||
MMSmsAt *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 = mm_base_sms_get_parts (MM_BASE_SMS (self));
|
||||
sms_send_next_part (task);
|
||||
}
|
||||
|
||||
static void
|
||||
sms_send (MMBaseSms *sms,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMSmsAt *self = MM_SMS_AT (sms);
|
||||
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 (MM_BASE_SMS (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 (MM_BASE_SMS (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 = mm_base_sms_get_parts (MM_BASE_SMS (self));
|
||||
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)
|
||||
{
|
||||
MMSmsAt *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)
|
||||
{
|
||||
MMSmsAt *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 = mm_base_sms_get_parts (MM_BASE_SMS (self));
|
||||
delete_next_part (task);
|
||||
}
|
||||
|
||||
static void
|
||||
sms_delete (MMBaseSms *sms,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMSmsAt *self = MM_SMS_AT (sms);
|
||||
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 (MM_BASE_SMS (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 (MM_BASE_SMS (self)),
|
||||
MM_SMS_STORAGE_UNKNOWN, /* none required for mem2 */
|
||||
(GAsyncReadyCallback)delete_lock_sms_storages_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseSms *
|
||||
mm_sms_at_new (MMBaseModem *modem,
|
||||
gboolean is_3gpp,
|
||||
MMSmsStorage default_storage)
|
||||
{
|
||||
MMBaseSms *sms;
|
||||
|
||||
sms = MM_BASE_SMS (g_object_new (MM_TYPE_SMS_AT,
|
||||
MM_BIND_TO, G_OBJECT (modem),
|
||||
MM_BASE_SMS_IS_3GPP, is_3gpp,
|
||||
MM_BASE_SMS_DEFAULT_STORAGE, default_storage,
|
||||
NULL));
|
||||
MM_SMS_AT (sms)->priv->modem = g_object_ref (modem);
|
||||
return sms;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_sms_at_init (MMSmsAt *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_SMS_AT, MMSmsAtPrivate);
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
MMSmsAt *self = MM_SMS_AT (object);
|
||||
|
||||
g_clear_object (&self->priv->modem);
|
||||
|
||||
G_OBJECT_CLASS (mm_sms_at_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_sms_at_class_init (MMSmsAtClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MMBaseSmsClass *base_sms_class = MM_BASE_SMS_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (MMSmsAtPrivate));
|
||||
|
||||
object_class->dispose = dispose;
|
||||
|
||||
base_sms_class->store = sms_store;
|
||||
base_sms_class->store_finish = sms_store_finish;
|
||||
base_sms_class->send = sms_send;
|
||||
base_sms_class->send_finish = sms_send_finish;
|
||||
base_sms_class->delete = sms_delete;
|
||||
base_sms_class->delete_finish = sms_delete_finish;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Author: Aleksander Morgado <aleksander@lanedo.com>
|
||||
*
|
||||
* Copyright (C) 2012 Google, Inc.
|
||||
* Copyright (C) 2025 Dan Williams <dan@ioncontrol.co>
|
||||
*/
|
||||
|
||||
#ifndef MM_SMS_AT_H
|
||||
#define MM_SMS_AT_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-base-sms.h"
|
||||
#include "mm-base-modem.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#define MM_TYPE_SMS_AT (mm_sms_at_get_type ())
|
||||
#define MM_SMS_AT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SMS_AT, MMSmsAt))
|
||||
#define MM_SMS_AT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_SMS_AT, MMSmsAtClass))
|
||||
#define MM_IS_SMS_AT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SMS_AT))
|
||||
#define MM_IS_SMS_AT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_SMS_AT))
|
||||
#define MM_SMS_AT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_SMS_AT, MMSmsAtClass))
|
||||
|
||||
typedef struct _MMSmsAt MMSmsAt;
|
||||
typedef struct _MMSmsAtClass MMSmsAtClass;
|
||||
typedef struct _MMSmsAtPrivate MMSmsAtPrivate;
|
||||
|
||||
struct _MMSmsAt {
|
||||
MMBaseSms parent;
|
||||
MMSmsAtPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMSmsAtClass {
|
||||
MMBaseSmsClass parent;
|
||||
};
|
||||
|
||||
GType mm_sms_at_get_type (void);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSmsAt, g_object_unref)
|
||||
|
||||
MMBaseSms *mm_sms_at_new (MMBaseModem *modem,
|
||||
gboolean is_3gpp,
|
||||
MMSmsStorage default_storage);
|
||||
|
||||
#endif /* MM_SMS_AT_H */
|
||||
+83
-52
@@ -24,7 +24,6 @@
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-iface-modem-messaging.h"
|
||||
#include "mm-sms-list.h"
|
||||
#include "mm-base-sms.h"
|
||||
#include "mm-log-object.h"
|
||||
@@ -40,10 +39,8 @@ G_DEFINE_TYPE_EXTENDED (MMSmsList, mm_sms_list, G_TYPE_OBJECT, 0,
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_BIND_TO,
|
||||
PROP_MODEM,
|
||||
PROP_LAST
|
||||
};
|
||||
static GParamSpec *properties[PROP_LAST];
|
||||
|
||||
enum {
|
||||
SIGNAL_ADDED,
|
||||
@@ -55,12 +52,12 @@ static guint signals[SIGNAL_LAST];
|
||||
struct _MMSmsListPrivate {
|
||||
/* The object this SMS list is bound to */
|
||||
GObject *bind_to;
|
||||
/* The owner modem */
|
||||
MMBaseModem *modem;
|
||||
/* List of sms objects */
|
||||
GList *list;
|
||||
};
|
||||
|
||||
static void _release_sms_internal (MMBaseSms *sms, MMSmsList *self);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean
|
||||
@@ -161,7 +158,7 @@ delete_ready (MMBaseSms *sms,
|
||||
path,
|
||||
(GCompareFunc)cmp_sms_by_path);
|
||||
if (l) {
|
||||
g_object_unref (MM_BASE_SMS (l->data));
|
||||
_release_sms_internal (MM_BASE_SMS (l->data), self);
|
||||
self->priv->list = g_list_delete_link (self->priv->list, l);
|
||||
}
|
||||
|
||||
@@ -213,14 +210,61 @@ mm_sms_list_delete_sms (MMSmsList *self,
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
set_local_multipart_reference (MMBaseSms *sms,
|
||||
const gchar *number,
|
||||
MMSmsList *self)
|
||||
{
|
||||
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 */
|
||||
first = reference;
|
||||
do {
|
||||
if (!mm_sms_list_has_local_multipart_reference (self, number, reference)) {
|
||||
mm_base_sms_set_multipart_reference (sms, reference);
|
||||
return;
|
||||
}
|
||||
|
||||
if (reference == 255)
|
||||
reference = 1;
|
||||
else
|
||||
reference++;
|
||||
} while (reference != first);
|
||||
}
|
||||
|
||||
static void
|
||||
_release_sms_internal (MMBaseSms *sms, MMSmsList *self)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (sms, set_local_multipart_reference, self);
|
||||
g_object_unref (sms);
|
||||
}
|
||||
|
||||
static void
|
||||
_add_sms_internal (MMSmsList *self,
|
||||
MMBaseSms *sms,
|
||||
gboolean received)
|
||||
{
|
||||
self->priv->list = g_list_prepend (self->priv->list, g_object_ref (sms));
|
||||
g_signal_connect (sms,
|
||||
MM_BASE_SMS_SET_LOCAL_MULTIPART_REFERENCE,
|
||||
(GCallback)set_local_multipart_reference,
|
||||
self);
|
||||
|
||||
g_signal_emit (self, signals[SIGNAL_ADDED], 0,
|
||||
mm_base_sms_get_path (sms),
|
||||
received);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
mm_sms_list_add_sms (MMSmsList *self,
|
||||
MMBaseSms *sms)
|
||||
{
|
||||
self->priv->list = g_list_prepend (self->priv->list, g_object_ref (sms));
|
||||
g_signal_emit (self, signals[SIGNAL_ADDED], 0,
|
||||
mm_base_sms_get_path (sms),
|
||||
FALSE);
|
||||
_add_sms_internal (self, sms, FALSE);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -259,39 +303,33 @@ cmp_sms_by_part_index_and_storage (MMBaseSms *sms,
|
||||
|
||||
static gboolean
|
||||
take_singlepart (MMSmsList *self,
|
||||
MMBaseSms *sms,
|
||||
MMSmsPart *part,
|
||||
MMSmsState state,
|
||||
MMSmsStorage storage,
|
||||
GError **error)
|
||||
{
|
||||
MMBaseSms *sms;
|
||||
|
||||
sms = mm_base_sms_singlepart_new (self->priv->modem,
|
||||
if (!mm_base_sms_singlepart_init (sms,
|
||||
state,
|
||||
storage,
|
||||
part,
|
||||
error);
|
||||
if (!sms)
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
mm_obj_dbg (sms, "creating new singlepart SMS object");
|
||||
|
||||
self->priv->list = g_list_prepend (self->priv->list, sms);
|
||||
g_signal_emit (self, signals[SIGNAL_ADDED], 0,
|
||||
mm_base_sms_get_path (sms),
|
||||
state == MM_SMS_STATE_RECEIVED);
|
||||
_add_sms_internal (self, sms, state == MM_SMS_STATE_RECEIVED);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
take_multipart (MMSmsList *self,
|
||||
MMBaseSms *sms,
|
||||
MMSmsPart *part,
|
||||
MMSmsState state,
|
||||
MMSmsStorage storage,
|
||||
GError **error)
|
||||
{
|
||||
GList *l;
|
||||
MMBaseSms *sms;
|
||||
guint concat_reference;
|
||||
|
||||
concat_reference = mm_sms_part_get_concat_reference (part);
|
||||
@@ -304,25 +342,19 @@ take_multipart (MMSmsList *self,
|
||||
}
|
||||
|
||||
/* Create new Multipart */
|
||||
sms = mm_base_sms_multipart_new (self->priv->modem,
|
||||
if (!mm_base_sms_multipart_init (sms,
|
||||
state,
|
||||
storage,
|
||||
concat_reference,
|
||||
mm_sms_part_get_concat_max (part),
|
||||
part,
|
||||
error);
|
||||
if (!sms)
|
||||
error))
|
||||
return FALSE;
|
||||
|
||||
mm_obj_dbg (sms, "creating new multipart SMS object: need to receive %u parts with reference '%u'",
|
||||
mm_sms_part_get_concat_max (part),
|
||||
concat_reference);
|
||||
self->priv->list = g_list_prepend (self->priv->list, sms);
|
||||
g_signal_emit (self, signals[SIGNAL_ADDED], 0,
|
||||
mm_base_sms_get_path (sms),
|
||||
(state == MM_SMS_STATE_RECEIVED ||
|
||||
state == MM_SMS_STATE_RECEIVING));
|
||||
|
||||
_add_sms_internal (self, sms, (state == MM_SMS_STATE_RECEIVED || state == MM_SMS_STATE_RECEIVING));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -347,6 +379,7 @@ mm_sms_list_has_part (MMSmsList *self,
|
||||
|
||||
gboolean
|
||||
mm_sms_list_take_part (MMSmsList *self,
|
||||
MMBaseSms *uninitialized_sms,
|
||||
MMSmsPart *part,
|
||||
MMSmsState state,
|
||||
MMSmsStorage storage,
|
||||
@@ -379,7 +412,7 @@ mm_sms_list_take_part (MMSmsList *self,
|
||||
mm_sms_part_get_concat_sequence (part),
|
||||
mm_sms_part_get_concat_max (part));
|
||||
|
||||
return take_multipart (self, part, state, storage, error);
|
||||
return take_multipart (self, uninitialized_sms, part, state, storage, error);
|
||||
}
|
||||
|
||||
/* Otherwise, we build a whole new single-part MMSms just from this part */
|
||||
@@ -389,7 +422,22 @@ mm_sms_list_take_part (MMSmsList *self,
|
||||
mm_sms_part_get_index (part));
|
||||
else
|
||||
mm_obj_dbg (self, "SMS part (not stored) is from a singlepart SMS");
|
||||
return take_singlepart (self, part, state, storage, error);
|
||||
return take_singlepart (self, uninitialized_sms, part, state, storage, error);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
void
|
||||
mm_sms_list_set_default_storage (MMSmsList *self,
|
||||
MMSmsStorage default_storage)
|
||||
{
|
||||
GList *l;
|
||||
|
||||
for (l = self->priv->list; l; l = g_list_next (l)) {
|
||||
g_object_set (MM_BASE_SMS (l->data),
|
||||
MM_BASE_SMS_DEFAULT_STORAGE, default_storage,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -403,11 +451,10 @@ log_object_build_id (MMLogObject *_self)
|
||||
/*****************************************************************************/
|
||||
|
||||
MMSmsList *
|
||||
mm_sms_list_new (MMBaseModem *modem, GObject *bind_to)
|
||||
mm_sms_list_new (GObject *bind_to)
|
||||
{
|
||||
/* Create the object */
|
||||
return g_object_new (MM_TYPE_SMS_LIST,
|
||||
MM_SMS_LIST_MODEM, modem,
|
||||
MM_BIND_TO, bind_to,
|
||||
NULL);
|
||||
}
|
||||
@@ -426,10 +473,6 @@ set_property (GObject *object,
|
||||
self->priv->bind_to = g_value_dup_object (value);
|
||||
mm_bind_to (MM_BIND (self), NULL, self->priv->bind_to);
|
||||
break;
|
||||
case PROP_MODEM:
|
||||
g_clear_object (&self->priv->modem);
|
||||
self->priv->modem = g_value_dup_object (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -448,9 +491,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;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -471,10 +511,9 @@ dispose (GObject *object)
|
||||
{
|
||||
MMSmsList *self = MM_SMS_LIST (object);
|
||||
|
||||
g_clear_object (&self->priv->modem);
|
||||
g_clear_object (&self->priv->bind_to);
|
||||
g_list_free_full (self->priv->list, g_object_unref);
|
||||
self->priv->list = NULL;
|
||||
g_list_foreach (self->priv->list, (GFunc)_release_sms_internal, self);
|
||||
g_clear_pointer (&self->priv->list, (GDestroyNotify)g_list_free);
|
||||
|
||||
G_OBJECT_CLASS (mm_sms_list_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -503,14 +542,6 @@ mm_sms_list_class_init (MMSmsListClass *klass)
|
||||
object_class->dispose = dispose;
|
||||
|
||||
/* Properties */
|
||||
properties[PROP_MODEM] =
|
||||
g_param_spec_object (MM_SMS_LIST_MODEM,
|
||||
"Modem",
|
||||
"The Modem which owns this SMS list",
|
||||
MM_TYPE_BASE_MODEM,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property (object_class, PROP_MODEM, properties[PROP_MODEM]);
|
||||
|
||||
g_object_class_override_property (object_class, PROP_BIND_TO, MM_BIND_TO);
|
||||
|
||||
/* Signals */
|
||||
|
||||
+6
-5
@@ -19,7 +19,7 @@
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "mm-base-modem.h"
|
||||
#include "mm-base-sms.h"
|
||||
#include "mm-sms-part.h"
|
||||
|
||||
#define MM_TYPE_SMS_LIST (mm_sms_list_get_type ())
|
||||
@@ -33,8 +33,6 @@ typedef struct _MMSmsList MMSmsList;
|
||||
typedef struct _MMSmsListClass MMSmsListClass;
|
||||
typedef struct _MMSmsListPrivate MMSmsListPrivate;
|
||||
|
||||
#define MM_SMS_LIST_MODEM "sms-list-modem"
|
||||
|
||||
#define MM_SMS_ADDED "sms-added"
|
||||
#define MM_SMS_DELETED "sms-deleted"
|
||||
|
||||
@@ -57,8 +55,7 @@ struct _MMSmsListClass {
|
||||
GType mm_sms_list_get_type (void);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSmsList, g_object_unref)
|
||||
|
||||
MMSmsList *mm_sms_list_new (MMBaseModem *modem,
|
||||
GObject *bind_to);
|
||||
MMSmsList *mm_sms_list_new (GObject *bind_to);
|
||||
|
||||
GStrv mm_sms_list_get_paths (MMSmsList *self);
|
||||
guint mm_sms_list_get_count (MMSmsList *self);
|
||||
@@ -68,6 +65,7 @@ gboolean mm_sms_list_has_part (MMSmsList *self,
|
||||
guint index);
|
||||
|
||||
gboolean mm_sms_list_take_part (MMSmsList *self,
|
||||
MMBaseSms *uninitialized_sms,
|
||||
MMSmsPart *part,
|
||||
MMSmsState state,
|
||||
MMSmsStorage storage,
|
||||
@@ -88,4 +86,7 @@ gboolean mm_sms_list_has_local_multipart_reference (MMSmsList *self,
|
||||
const gchar *number,
|
||||
guint8 reference);
|
||||
|
||||
void mm_sms_list_set_default_storage (MMSmsList *self,
|
||||
MMSmsStorage default_storage);
|
||||
|
||||
#endif /* MM_SMS_LIST_H */
|
||||
|
||||
+41
-31
@@ -35,25 +35,22 @@
|
||||
|
||||
G_DEFINE_TYPE (MMSmsMbim, mm_sms_mbim, MM_TYPE_BASE_SMS)
|
||||
|
||||
struct _MMSmsMbimPrivate {
|
||||
MMBaseModem *modem;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
peek_device (gpointer self,
|
||||
MbimDevice **o_device,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
peek_device (MMSmsMbim *self,
|
||||
MbimDevice **o_device,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBaseModem *modem = NULL;
|
||||
|
||||
g_object_get (G_OBJECT (self),
|
||||
MM_BASE_SMS_MODEM, &modem,
|
||||
NULL);
|
||||
g_assert (MM_IS_BASE_MODEM (modem));
|
||||
|
||||
if (o_device) {
|
||||
MMPortMbim *port;
|
||||
|
||||
port = mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (modem));
|
||||
port = mm_broadband_modem_mbim_peek_port_mbim (MM_BROADBAND_MODEM_MBIM (self->priv->modem));
|
||||
if (!port) {
|
||||
g_task_report_new_error (self,
|
||||
callback,
|
||||
@@ -62,14 +59,12 @@ peek_device (gpointer self,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"Couldn't peek MBIM port");
|
||||
g_object_unref (modem);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*o_device = mm_port_mbim_peek_device (port);
|
||||
}
|
||||
|
||||
g_object_unref (modem);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -77,7 +72,6 @@ peek_device (gpointer self,
|
||||
/* Send the SMS */
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
MbimDevice *device;
|
||||
GList *current;
|
||||
} SmsSendContext;
|
||||
@@ -86,7 +80,6 @@ static void
|
||||
sms_send_context_free (SmsSendContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->device);
|
||||
g_object_unref (ctx->modem);
|
||||
g_slice_free (SmsSendContext, ctx);
|
||||
}
|
||||
|
||||
@@ -193,15 +186,12 @@ sms_send (MMBaseSms *self,
|
||||
MbimDevice *device;
|
||||
GTask *task;
|
||||
|
||||
if (!peek_device (self, &device, callback, user_data))
|
||||
if (!peek_device (MM_SMS_MBIM (self), &device, callback, user_data))
|
||||
return;
|
||||
|
||||
/* Setup the context */
|
||||
ctx = g_slice_new0 (SmsSendContext);
|
||||
ctx->device = g_object_ref (device);
|
||||
g_object_get (self,
|
||||
MM_BASE_SMS_MODEM, &ctx->modem,
|
||||
NULL);
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)sms_send_context_free);
|
||||
@@ -213,7 +203,6 @@ sms_send (MMBaseSms *self,
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
MbimDevice *device;
|
||||
GList *current;
|
||||
guint n_failed;
|
||||
@@ -223,7 +212,6 @@ static void
|
||||
sms_delete_parts_context_free (SmsDeletePartsContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->device);
|
||||
g_object_unref (ctx->modem);
|
||||
g_slice_free (SmsDeletePartsContext, ctx);
|
||||
}
|
||||
|
||||
@@ -322,14 +310,11 @@ sms_delete (MMBaseSms *self,
|
||||
MbimDevice *device;
|
||||
GTask *task;
|
||||
|
||||
if (!peek_device (self, &device, callback, user_data))
|
||||
if (!peek_device (MM_SMS_MBIM (self), &device, callback, user_data))
|
||||
return;
|
||||
|
||||
ctx = g_slice_new0 (SmsDeletePartsContext);
|
||||
ctx->device = g_object_ref (device);
|
||||
g_object_get (self,
|
||||
MM_BASE_SMS_MODEM, &ctx->modem,
|
||||
NULL);
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)sms_delete_parts_context_free);
|
||||
@@ -342,24 +327,49 @@ sms_delete (MMBaseSms *self,
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseSms *
|
||||
mm_sms_mbim_new (MMBaseModem *modem)
|
||||
mm_sms_mbim_new (MMBaseModem *modem,
|
||||
gboolean is_3gpp,
|
||||
MMSmsStorage default_storage)
|
||||
{
|
||||
return MM_BASE_SMS (g_object_new (MM_TYPE_SMS_MBIM,
|
||||
MM_BASE_SMS_MODEM, modem,
|
||||
MM_BIND_TO, G_OBJECT (modem),
|
||||
NULL));
|
||||
MMBaseSms *sms;
|
||||
|
||||
g_return_val_if_fail (MM_IS_BROADBAND_MODEM_MBIM (modem), NULL);
|
||||
|
||||
sms = MM_BASE_SMS (g_object_new (MM_TYPE_SMS_MBIM,
|
||||
MM_BIND_TO, G_OBJECT (modem),
|
||||
MM_BASE_SMS_IS_3GPP, is_3gpp,
|
||||
MM_BASE_SMS_DEFAULT_STORAGE, default_storage,
|
||||
NULL));
|
||||
MM_SMS_MBIM (sms)->priv->modem = g_object_ref (modem);
|
||||
return sms;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_sms_mbim_init (MMSmsMbim *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_SMS_MBIM, MMSmsMbimPrivate);
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
MMSmsMbim *self = MM_SMS_MBIM (object);
|
||||
|
||||
g_clear_object (&self->priv->modem);
|
||||
|
||||
G_OBJECT_CLASS (mm_sms_mbim_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_sms_mbim_class_init (MMSmsMbimClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MMBaseSmsClass *base_sms_class = MM_BASE_SMS_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (MMSmsMbimPrivate));
|
||||
|
||||
object_class->dispose = dispose;
|
||||
|
||||
base_sms_class->store = NULL;
|
||||
base_sms_class->store_finish = NULL;
|
||||
base_sms_class->send = sms_send;
|
||||
|
||||
+5
-1
@@ -33,9 +33,11 @@
|
||||
|
||||
typedef struct _MMSmsMbim MMSmsMbim;
|
||||
typedef struct _MMSmsMbimClass MMSmsMbimClass;
|
||||
typedef struct _MMSmsMbimPrivate MMSmsMbimPrivate;
|
||||
|
||||
struct _MMSmsMbim {
|
||||
MMBaseSms parent;
|
||||
MMSmsMbimPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMSmsMbimClass {
|
||||
@@ -45,6 +47,8 @@ struct _MMSmsMbimClass {
|
||||
GType mm_sms_mbim_get_type (void);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSmsMbim, g_object_unref)
|
||||
|
||||
MMBaseSms *mm_sms_mbim_new (MMBaseModem *modem);
|
||||
MMBaseSms *mm_sms_mbim_new (MMBaseModem *modem,
|
||||
gboolean is_3gpp,
|
||||
MMSmsStorage default_storage);
|
||||
|
||||
#endif /* MM_SMS_MBIM_H */
|
||||
|
||||
+46
-40
@@ -37,6 +37,10 @@
|
||||
|
||||
G_DEFINE_TYPE (MMSmsQmi, mm_sms_qmi, MM_TYPE_BASE_SMS)
|
||||
|
||||
struct _MMSmsQmiPrivate {
|
||||
MMBaseModem *modem;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gboolean
|
||||
@@ -46,18 +50,10 @@ ensure_qmi_client (MMSmsQmi *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMBaseModem *modem = NULL;
|
||||
QmiClient *client;
|
||||
MMPortQmi *port;
|
||||
|
||||
g_object_get (self,
|
||||
MM_BASE_SMS_MODEM, &modem,
|
||||
NULL);
|
||||
g_assert (MM_IS_BASE_MODEM (modem));
|
||||
|
||||
port = mm_broadband_modem_qmi_peek_port_qmi (MM_BROADBAND_MODEM_QMI (modem));
|
||||
g_object_unref (modem);
|
||||
|
||||
port = mm_broadband_modem_qmi_peek_port_qmi (MM_BROADBAND_MODEM_QMI (self->priv->modem));
|
||||
if (!port) {
|
||||
g_task_report_new_error (self,
|
||||
callback,
|
||||
@@ -119,7 +115,6 @@ check_sms_type_support (MMSmsQmi *self,
|
||||
/* Store the SMS */
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
QmiClientWms *client;
|
||||
MMSmsStorage storage;
|
||||
GList *current;
|
||||
@@ -129,7 +124,6 @@ static void
|
||||
sms_store_context_free (SmsStoreContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->client);
|
||||
g_object_unref (ctx->modem);
|
||||
g_slice_free (SmsStoreContext, ctx);
|
||||
}
|
||||
|
||||
@@ -260,11 +254,12 @@ sms_store_next_part (GTask *task)
|
||||
}
|
||||
|
||||
static void
|
||||
sms_store (MMBaseSms *self,
|
||||
sms_store (MMBaseSms *_self,
|
||||
MMSmsStorage storage,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMSmsQmi *self = MM_SMS_QMI (_self);
|
||||
SmsStoreContext *ctx;
|
||||
QmiClient *client = NULL;
|
||||
GError *error = NULL;
|
||||
@@ -280,17 +275,13 @@ sms_store (MMBaseSms *self,
|
||||
ctx = g_slice_new0 (SmsStoreContext);
|
||||
ctx->client = QMI_CLIENT_WMS (g_object_ref (client));
|
||||
ctx->storage = storage;
|
||||
g_object_get (self,
|
||||
MM_BASE_SMS_MODEM, &ctx->modem,
|
||||
NULL);
|
||||
|
||||
ctx->current = mm_base_sms_get_parts (self);
|
||||
ctx->current = mm_base_sms_get_parts (_self);
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)sms_store_context_free);
|
||||
|
||||
/* Check whether we support the given SMS type */
|
||||
if (!check_sms_type_support (MM_SMS_QMI (self), ctx->modem, (MMSmsPart *)ctx->current->data, &error)) {
|
||||
if (!check_sms_type_support (MM_SMS_QMI (self), self->priv->modem, (MMSmsPart *)ctx->current->data, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
@@ -304,7 +295,6 @@ sms_store (MMBaseSms *self,
|
||||
/* Send the SMS */
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
QmiClientWms *client;
|
||||
gboolean from_storage;
|
||||
GList *current;
|
||||
@@ -314,7 +304,6 @@ static void
|
||||
sms_send_context_free (SmsSendContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->client);
|
||||
g_object_unref (ctx->modem);
|
||||
g_slice_free (SmsSendContext, ctx);
|
||||
}
|
||||
|
||||
@@ -595,10 +584,11 @@ sms_send_next_part (GTask *task)
|
||||
}
|
||||
|
||||
static void
|
||||
sms_send (MMBaseSms *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
sms_send (MMBaseSms *_self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMSmsQmi *self = MM_SMS_QMI (_self);
|
||||
SmsSendContext *ctx;
|
||||
QmiClient *client = NULL;
|
||||
GError *error = NULL;
|
||||
@@ -613,20 +603,16 @@ sms_send (MMBaseSms *self,
|
||||
/* Setup the context */
|
||||
ctx = g_slice_new0 (SmsSendContext);
|
||||
ctx->client = QMI_CLIENT_WMS (g_object_ref (client));
|
||||
g_object_get (self,
|
||||
MM_BASE_SMS_MODEM, &ctx->modem,
|
||||
NULL);
|
||||
|
||||
/* If the SMS is STORED, try to send from storage */
|
||||
ctx->from_storage = (mm_base_sms_get_storage (self) != MM_SMS_STORAGE_UNKNOWN);
|
||||
ctx->from_storage = (mm_base_sms_get_storage (_self) != MM_SMS_STORAGE_UNKNOWN);
|
||||
|
||||
ctx->current = mm_base_sms_get_parts (self);
|
||||
ctx->current = mm_base_sms_get_parts (_self);
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)sms_send_context_free);
|
||||
|
||||
/* Check whether we support the given SMS type */
|
||||
if (!check_sms_type_support (MM_SMS_QMI (self), ctx->modem, (MMSmsPart *)ctx->current->data, &error)) {
|
||||
if (!check_sms_type_support (MM_SMS_QMI (self), self->priv->modem, (MMSmsPart *)ctx->current->data, &error)) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
@@ -638,7 +624,6 @@ sms_send (MMBaseSms *self,
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
MMBaseModem *modem;
|
||||
QmiClientWms *client;
|
||||
GList *current;
|
||||
guint n_failed;
|
||||
@@ -648,7 +633,6 @@ static void
|
||||
sms_delete_parts_context_free (SmsDeletePartsContext *ctx)
|
||||
{
|
||||
g_object_unref (ctx->client);
|
||||
g_object_unref (ctx->modem);
|
||||
g_slice_free (SmsDeletePartsContext, ctx);
|
||||
}
|
||||
|
||||
@@ -771,9 +755,6 @@ sms_delete (MMBaseSms *self,
|
||||
|
||||
ctx = g_slice_new0 (SmsDeletePartsContext);
|
||||
ctx->client = QMI_CLIENT_WMS (g_object_ref (client));
|
||||
g_object_get (self,
|
||||
MM_BASE_SMS_MODEM, &ctx->modem,
|
||||
NULL);
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
g_task_set_task_data (task, ctx, (GDestroyNotify)sms_delete_parts_context_free);
|
||||
@@ -786,24 +767,49 @@ sms_delete (MMBaseSms *self,
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseSms *
|
||||
mm_sms_qmi_new (MMBaseModem *modem)
|
||||
mm_sms_qmi_new (MMBaseModem *modem,
|
||||
gboolean is_3gpp,
|
||||
MMSmsStorage default_storage)
|
||||
{
|
||||
return MM_BASE_SMS (g_object_new (MM_TYPE_SMS_QMI,
|
||||
MM_BASE_SMS_MODEM, modem,
|
||||
MM_BIND_TO, G_OBJECT (modem),
|
||||
NULL));
|
||||
MMBaseSms *sms;
|
||||
|
||||
g_return_val_if_fail (MM_IS_BROADBAND_MODEM_QMI (modem), NULL);
|
||||
|
||||
sms = MM_BASE_SMS (g_object_new (MM_TYPE_SMS_QMI,
|
||||
MM_BIND_TO, G_OBJECT (modem),
|
||||
MM_BASE_SMS_IS_3GPP, is_3gpp,
|
||||
MM_BASE_SMS_DEFAULT_STORAGE, default_storage,
|
||||
NULL));
|
||||
MM_SMS_QMI (sms)->priv->modem = g_object_ref (modem);
|
||||
return sms;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_sms_qmi_init (MMSmsQmi *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_SMS_QMI, MMSmsQmiPrivate);
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
MMSmsQmi *self = MM_SMS_QMI (object);
|
||||
|
||||
g_clear_object (&self->priv->modem);
|
||||
|
||||
G_OBJECT_CLASS (mm_sms_qmi_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_sms_qmi_class_init (MMSmsQmiClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MMBaseSmsClass *base_sms_class = MM_BASE_SMS_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (MMSmsQmiPrivate));
|
||||
|
||||
object_class->dispose = dispose;
|
||||
|
||||
base_sms_class->store = sms_store;
|
||||
base_sms_class->store_finish = sms_store_finish;
|
||||
base_sms_class->send = sms_send;
|
||||
|
||||
+5
-1
@@ -35,9 +35,11 @@
|
||||
|
||||
typedef struct _MMSmsQmi MMSmsQmi;
|
||||
typedef struct _MMSmsQmiClass MMSmsQmiClass;
|
||||
typedef struct _MMSmsQmiPrivate MMSmsQmiPrivate;
|
||||
|
||||
struct _MMSmsQmi {
|
||||
MMBaseSms parent;
|
||||
MMSmsQmiPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMSmsQmiClass {
|
||||
@@ -47,6 +49,8 @@ struct _MMSmsQmiClass {
|
||||
GType mm_sms_qmi_get_type (void);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMSmsQmi, g_object_unref)
|
||||
|
||||
MMBaseSms *mm_sms_qmi_new (MMBaseModem *modem);
|
||||
MMBaseSms *mm_sms_qmi_new (MMBaseModem *modem,
|
||||
gboolean is_3gpp,
|
||||
MMSmsStorage default_storage);
|
||||
|
||||
#endif /* MM_SMS_QMI_H */
|
||||
|
||||
@@ -10,6 +10,7 @@ test_units = {
|
||||
'modem-helpers': libhelpers_dep,
|
||||
'sms-part-3gpp': libhelpers_dep,
|
||||
'sms-part-cdma': libhelpers_dep,
|
||||
'sms-list': libsms_dep,
|
||||
'udev-rules': libkerneldevice_dep,
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2025 Dan Williams <dan@ioncontrol.co>
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <locale.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-sms-part-3gpp.h"
|
||||
#include "mm-sms-list.h"
|
||||
#include "mm-log-test.h"
|
||||
#include "mm-base-modem.h"
|
||||
|
||||
#include "mm-iface-modem-messaging.h"
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
static void
|
||||
test_mbim_multipart_unstored (void)
|
||||
{
|
||||
static const gchar *part1_pdu =
|
||||
"07912160130300f4440b915155685703f900005240713104738a3e050003c40202da6f37881e96"
|
||||
"9fcbf4b4fb0ccabfeb20f4fb0ea287e5e7323ded3e83dae17519747fcbd96490b95c6683d27310"
|
||||
"1d5d0601";
|
||||
static const gchar *part2_pdu =
|
||||
"07912160130300f4440b915155685703f900005240713104738aa0050003c40201ac69373d7c2e"
|
||||
"83e87538bc2cbf87e565d039dc2e83c220769a4e6797416132394d4fbfdda0fb5b4e4783c2ee3c"
|
||||
"888e2e83e86fd0db0c1a86e769f71b647eb3d9ef7bda7d06a5e7a0b09b0c9ab3df74109c1dce83"
|
||||
"e8e8301d44479741f9771d949e83e861f9b94c4fbbcf20f13b4c9f83e8e832485c068ddfedf6db"
|
||||
"0da2a3cba0fcbb0e1abfdb";
|
||||
MMSmsPart *part1, *part2;
|
||||
MMSmsList *list;
|
||||
MMBaseSms *sms1, *sms2;
|
||||
GError *error = NULL;
|
||||
|
||||
/* Some MBIM devices (Dell 5821e) report SMSes via the MBIM_CID_SMS_READ
|
||||
* unsolicited notification usually used for Class-0 (flash/alert) messages.
|
||||
* These always have a message index of 0; thus when a multipart SMS
|
||||
* arrives it comes as two individual notifications both with 0 indexes.
|
||||
* The MBIM modem code used SMS_PART_INVALID_INDEX for unstored SMSes.
|
||||
* Ensure the MMSmsList can handle combining the two parts with the same
|
||||
* index.
|
||||
*/
|
||||
part1 = mm_sms_part_3gpp_new_from_pdu (SMS_PART_INVALID_INDEX, part1_pdu, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
part2 = mm_sms_part_3gpp_new_from_pdu (SMS_PART_INVALID_INDEX, part2_pdu, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
list = mm_sms_list_new (NULL);
|
||||
|
||||
sms1 = MM_BASE_SMS (g_object_new (MM_TYPE_BASE_SMS,
|
||||
MM_BASE_SMS_IS_3GPP, TRUE,
|
||||
MM_BASE_SMS_DEFAULT_STORAGE, MM_SMS_STORAGE_MT,
|
||||
NULL));
|
||||
mm_sms_list_take_part (list,
|
||||
sms1,
|
||||
part1,
|
||||
MM_SMS_STATE_RECEIVED,
|
||||
MM_SMS_STORAGE_MT,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
sms2 = MM_BASE_SMS (g_object_new (MM_TYPE_BASE_SMS,
|
||||
MM_BASE_SMS_IS_3GPP, TRUE,
|
||||
MM_BASE_SMS_DEFAULT_STORAGE, MM_SMS_STORAGE_MT,
|
||||
NULL));
|
||||
mm_sms_list_take_part (list,
|
||||
sms2,
|
||||
part2,
|
||||
MM_SMS_STATE_RECEIVED,
|
||||
MM_SMS_STORAGE_MT,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_assert_cmpint (mm_sms_list_get_count (list), ==, 1);
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
static void
|
||||
test_mbim_multipart_zero_index (void)
|
||||
{
|
||||
static const gchar *pdu =
|
||||
"07912160130300f4440b915155685703f900005240713104738a3e050003c40202da6f37881e96"
|
||||
"9fcbf4b4fb0ccabfeb20f4fb0ea287e5e7323ded3e83dae17519747fcbd96490b95c6683d27310"
|
||||
"1d5d0601";
|
||||
MMSmsPart *part;
|
||||
MMSmsList *list;
|
||||
MMBaseSms *sms;
|
||||
GError *error = NULL;
|
||||
|
||||
part = mm_sms_part_3gpp_new_from_pdu (0, pdu, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
list = mm_sms_list_new (NULL);
|
||||
|
||||
sms = MM_BASE_SMS (g_object_new (MM_TYPE_BASE_SMS,
|
||||
MM_BASE_SMS_IS_3GPP, TRUE,
|
||||
MM_BASE_SMS_DEFAULT_STORAGE, MM_SMS_STORAGE_MT,
|
||||
NULL));
|
||||
mm_sms_list_take_part (list,
|
||||
sms,
|
||||
part,
|
||||
MM_SMS_STATE_RECEIVED,
|
||||
MM_SMS_STORAGE_MT,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_assert_cmpint (mm_sms_list_get_count (list), ==, 1);
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/MM/SMS/3GPP/sms-list/zero-index", test_mbim_multipart_zero_index);
|
||||
g_test_add_func ("/MM/SMS/3GPP/sms-list/mbim-multipart-unstored", test_mbim_multipart_unstored);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
Reference in New Issue
Block a user