aboutsummaryrefslogtreecommitdiff
path: root/src/tests/fake-modem.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/fake-modem.c')
-rw-r--r--src/tests/fake-modem.c463
1 files changed, 463 insertions, 0 deletions
diff --git a/src/tests/fake-modem.c b/src/tests/fake-modem.c
new file mode 100644
index 00000000..0d1100bc
--- /dev/null
+++ b/src/tests/fake-modem.c
@@ -0,0 +1,463 @@
+/* -*- 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 "fake-modem.h"
+#include "mm-iface-modem.h"
+#include "mm-iface-modem-voice.h"
+#include "mm-call-list.h"
+#include "fake-call.h"
+#include "mm-bind.h"
+
+#define MM_FAKE_MODEM_PATH "fake-modem-path"
+
+static void iface_modem_init (MMIfaceModemInterface *iface);
+static void iface_modem_voice_init (MMIfaceModemVoiceInterface *iface);
+
+G_DEFINE_TYPE_EXTENDED (MMFakeModem, mm_fake_modem, MM_TYPE_BASE_MODEM, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init))
+
+enum {
+ PROP_0,
+ PROP_CONNECTION,
+ PROP_PATH,
+ PROP_MODEM_DBUS_SKELETON,
+ PROP_MODEM_STATE,
+ PROP_MODEM_SIM,
+ PROP_MODEM_SIM_SLOTS,
+ PROP_MODEM_SIM_HOT_SWAP_SUPPORTED,
+ PROP_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED,
+ PROP_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED,
+ PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED,
+ PROP_MODEM_CARRIER_CONFIG_MAPPING,
+ PROP_MODEM_BEARER_LIST,
+ PROP_MODEM_INDICATION_CALL_LIST_RELOAD_ENABLED,
+ PROP_MODEM_VOICE_DBUS_SKELETON,
+ PROP_MODEM_VOICE_CALL_LIST,
+ PROP_LAST
+};
+
+static GParamSpec *properties[PROP_LAST];
+
+struct _MMFakeModemPrivate {
+ GDBusConnection *connection;
+ guint dbus_id;
+ gchar *path;
+
+ GObject *modem_dbus_skeleton;
+ MMModemState modem_state;
+ GObject *modem_sim;
+ GPtrArray *modem_sim_slots;
+ gboolean sim_hot_swap_supported;
+ gboolean periodic_signal_check_disabled;
+ gboolean periodic_access_tech_check_disabled;
+ gboolean periodic_call_list_check_disabled;
+ gchar *carrier_config_mapping;
+ MMBearerList *modem_bearer_list;
+ gboolean indication_call_list_reload_enabled;
+ GObject *modem_voice_dbus_skeleton;
+ MMCallList *modem_voice_call_list;
+};
+
+/*****************************************************************************/
+
+const gchar *
+mm_fake_modem_get_path (MMFakeModem *self)
+{
+ return self->priv->path;
+}
+
+MMCallList *
+mm_fake_modem_get_call_list (MMFakeModem *self)
+{
+ return self->priv->modem_voice_call_list;
+}
+
+gboolean
+mm_fake_modem_export_interfaces (MMFakeModem *self, GError **error)
+{
+ g_assert (self->priv->path);
+ g_assert (self->priv->connection);
+
+ if (self->priv->modem_dbus_skeleton) {
+ if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->priv->modem_dbus_skeleton),
+ self->priv->connection,
+ self->priv->path,
+ error))
+ return FALSE;
+ }
+
+ if (self->priv->modem_voice_dbus_skeleton) {
+ if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self->priv->modem_voice_dbus_skeleton),
+ self->priv->connection,
+ self->priv->path,
+ error))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+modem_voice_check_support_finish (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ gboolean foobar;
+
+ foobar = g_task_propagate_boolean (G_TASK (res), error);
+ return foobar;
+}
+
+static void
+modem_voice_check_support (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+/*****************************************************************************/
+
+static MMBaseCall *
+modem_voice_create_call (MMIfaceModemVoice *_self,
+ MMCallDirection direction,
+ const gchar *number,
+ const guint dtmf_tone_duration)
+{
+ MMFakeModem *self = MM_FAKE_MODEM (_self);
+
+ return MM_BASE_CALL (mm_fake_call_new (self->priv->connection,
+ _self,
+ direction,
+ number,
+ dtmf_tone_duration));
+}
+
+/*****************************************************************************/
+
+MMFakeModem *
+mm_fake_modem_new (GDBusConnection *connection)
+{
+ return MM_FAKE_MODEM (g_object_new (MM_TYPE_FAKE_MODEM,
+ MM_BINDABLE_CONNECTION, connection,
+ NULL));
+}
+
+static void
+set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ MMFakeModem *self = MM_FAKE_MODEM (object);
+
+ switch (prop_id) {
+ case PROP_PATH:
+ g_free (self->priv->path);
+ self->priv->path = g_value_dup_string (value);
+ break;
+ case PROP_CONNECTION:
+ g_clear_object (&self->priv->connection);
+ self->priv->connection = g_value_dup_object (value);
+ break;
+ case PROP_MODEM_DBUS_SKELETON:
+ g_clear_object (&self->priv->modem_dbus_skeleton);
+ self->priv->modem_dbus_skeleton = g_value_dup_object (value);
+ break;
+ case PROP_MODEM_STATE:
+ self->priv->modem_state = g_value_get_enum (value);
+ break;
+ case PROP_MODEM_SIM:
+ g_clear_object (&self->priv->modem_sim);
+ self->priv->modem_sim = g_value_dup_object (value);
+ break;
+ case PROP_MODEM_SIM_SLOTS:
+ g_clear_pointer (&self->priv->modem_sim_slots, g_ptr_array_unref);
+ self->priv->modem_sim_slots = g_value_dup_boxed (value);
+ break;
+ case PROP_MODEM_SIM_HOT_SWAP_SUPPORTED:
+ self->priv->sim_hot_swap_supported = g_value_get_boolean (value);
+ break;
+ case PROP_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED:
+ self->priv->periodic_signal_check_disabled = g_value_get_boolean (value);
+ break;
+ case PROP_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED:
+ self->priv->periodic_access_tech_check_disabled = g_value_get_boolean (value);
+ break;
+ case PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED:
+ self->priv->periodic_call_list_check_disabled = g_value_get_boolean (value);
+ break;
+ case PROP_MODEM_CARRIER_CONFIG_MAPPING:
+ self->priv->carrier_config_mapping = g_value_dup_string (value);
+ break;
+ case PROP_MODEM_BEARER_LIST:
+ g_clear_object (&self->priv->modem_bearer_list);
+ self->priv->modem_bearer_list = g_value_dup_object (value);
+ break;
+ case PROP_MODEM_INDICATION_CALL_LIST_RELOAD_ENABLED:
+ self->priv->indication_call_list_reload_enabled = g_value_get_boolean (value);
+ break;
+ case PROP_MODEM_VOICE_DBUS_SKELETON:
+ g_clear_object (&self->priv->modem_voice_dbus_skeleton);
+ self->priv->modem_voice_dbus_skeleton = g_value_dup_object (value);
+ break;
+ case PROP_MODEM_VOICE_CALL_LIST:
+ g_clear_object (&self->priv->modem_voice_call_list);
+ self->priv->modem_voice_call_list = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ MMFakeModem *self = MM_FAKE_MODEM (object);
+
+ switch (prop_id) {
+ case PROP_PATH:
+ g_value_set_string (value, self->priv->path);
+ break;
+ case PROP_CONNECTION:
+ g_value_set_object (value, self->priv->connection);
+ break;
+ case PROP_MODEM_DBUS_SKELETON:
+ g_value_set_object (value, self->priv->modem_dbus_skeleton);
+ break;
+ case PROP_MODEM_STATE:
+ g_value_set_enum (value, self->priv->modem_state);
+ break;
+ case PROP_MODEM_SIM:
+ g_value_set_object (value, self->priv->modem_sim);
+ break;
+ case PROP_MODEM_SIM_SLOTS:
+ g_value_set_boxed (value, self->priv->modem_sim_slots);
+ break;
+ case PROP_MODEM_SIM_HOT_SWAP_SUPPORTED:
+ g_value_set_boolean (value, self->priv->sim_hot_swap_supported);
+ break;
+ case PROP_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED:
+ g_value_set_boolean (value, self->priv->periodic_signal_check_disabled);
+ break;
+ case PROP_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED:
+ g_value_set_boolean (value, self->priv->periodic_access_tech_check_disabled);
+ break;
+ case PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED:
+ g_value_set_boolean (value, self->priv->periodic_call_list_check_disabled);
+ break;
+ case PROP_MODEM_CARRIER_CONFIG_MAPPING:
+ g_value_set_string (value, self->priv->carrier_config_mapping);
+ break;
+ case PROP_MODEM_BEARER_LIST:
+ g_value_set_object (value, self->priv->modem_bearer_list);
+ break;
+ case PROP_MODEM_INDICATION_CALL_LIST_RELOAD_ENABLED:
+ g_value_set_boolean (value, self->priv->indication_call_list_reload_enabled);
+ break;
+ case PROP_MODEM_VOICE_DBUS_SKELETON:
+ g_value_set_object (value, self->priv->modem_voice_dbus_skeleton);
+ break;
+ case PROP_MODEM_VOICE_CALL_LIST:
+ g_value_set_object (value, self->priv->modem_voice_call_list);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+mm_fake_modem_init (MMFakeModem *self)
+{
+ static guint id = 0;
+
+ /* Initialize private data */
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ MM_TYPE_FAKE_MODEM,
+ MMFakeModemPrivate);
+
+ /* Each modem is given a unique id to build its own DBus path */
+ self->priv->dbus_id = id++;
+ self->priv->path = g_strdup_printf (MM_DBUS_MODEM_PREFIX "/%d", self->priv->dbus_id);
+}
+
+static void
+finalize (GObject *object)
+{
+ MMFakeModem *self = MM_FAKE_MODEM (object);
+
+ g_free (self->priv->path);
+ g_free (self->priv->carrier_config_mapping);
+
+ G_OBJECT_CLASS (mm_fake_modem_parent_class)->finalize (object);
+}
+
+static void
+dispose (GObject *object)
+{
+ MMFakeModem *self = MM_FAKE_MODEM (object);
+
+ if (self->priv->modem_dbus_skeleton) {
+ mm_iface_modem_shutdown (MM_IFACE_MODEM (object));
+ g_clear_object (&self->priv->modem_dbus_skeleton);
+ }
+ if (self->priv->modem_voice_dbus_skeleton) {
+ mm_iface_modem_voice_shutdown (MM_IFACE_MODEM_VOICE (object));
+ g_clear_object (&self->priv->modem_voice_dbus_skeleton);
+ }
+ g_clear_object (&self->priv->modem_sim);
+ g_clear_pointer (&self->priv->modem_sim_slots, g_ptr_array_unref);
+ g_clear_object (&self->priv->modem_bearer_list);
+ g_clear_object (&self->priv->modem_voice_call_list);
+ g_clear_object (&self->priv->connection);
+
+ G_OBJECT_CLASS (mm_fake_modem_parent_class)->dispose (object);
+}
+
+static void
+iface_modem_init (MMIfaceModemInterface *iface)
+{
+}
+
+static void
+iface_modem_voice_init (MMIfaceModemVoiceInterface *iface)
+{
+ iface->check_support = modem_voice_check_support;
+ iface->check_support_finish = modem_voice_check_support_finish;
+ iface->create_call = modem_voice_create_call;
+
+#if 0
+ iface->load_call_list = modem_voice_load_call_list;
+ iface->load_call_list_finish = modem_voice_load_call_list_finish;
+ iface->hold_and_accept = modem_voice_hold_and_accept;
+ iface->hold_and_accept_finish = modem_voice_hold_and_accept_finish;
+ iface->hangup_and_accept = modem_voice_hangup_and_accept;
+ iface->hangup_and_accept_finish = modem_voice_hangup_and_accept_finish;
+ iface->hangup_all = modem_voice_hangup_all;
+ iface->hangup_all_finish = modem_voice_hangup_all_finish;
+ iface->join_multiparty = modem_voice_join_multiparty;
+ iface->join_multiparty_finish = modem_voice_join_multiparty_finish;
+ iface->leave_multiparty = modem_voice_leave_multiparty;
+ iface->leave_multiparty_finish = modem_voice_leave_multiparty_finish;
+ iface->transfer = modem_voice_transfer;
+ iface->transfer_finish = modem_voice_transfer_finish;
+ iface->call_waiting_setup = modem_voice_call_waiting_setup;
+ iface->call_waiting_setup_finish = modem_voice_call_waiting_setup_finish;
+ iface->call_waiting_query = modem_voice_call_waiting_query;
+ iface->call_waiting_query_finish = modem_voice_call_waiting_query_finish;
+#endif
+}
+
+static void
+mm_fake_modem_class_init (MMFakeModemClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMFakeModemPrivate));
+
+ object_class->set_property = set_property;
+ object_class->get_property = get_property;
+ object_class->finalize = finalize;
+ object_class->dispose = dispose;
+
+ properties[PROP_CONNECTION] =
+ g_param_spec_object (MM_BINDABLE_CONNECTION,
+ "Connection",
+ "GDBus connection to the system bus.",
+ G_TYPE_DBUS_CONNECTION,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_CONNECTION, properties[PROP_CONNECTION]);
+
+ properties[PROP_PATH] =
+ g_param_spec_string (MM_FAKE_MODEM_PATH,
+ "Path",
+ "DBus path of the call",
+ NULL,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class, PROP_PATH, properties[PROP_PATH]);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_DBUS_SKELETON,
+ MM_IFACE_MODEM_DBUS_SKELETON);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_STATE,
+ MM_IFACE_MODEM_STATE);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_SIM,
+ MM_IFACE_MODEM_SIM);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_SIM_SLOTS,
+ MM_IFACE_MODEM_SIM_SLOTS);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_SIM_HOT_SWAP_SUPPORTED,
+ MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED,
+ MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED,
+ MM_IFACE_MODEM_PERIODIC_ACCESS_TECH_CHECK_DISABLED);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED,
+ MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_CARRIER_CONFIG_MAPPING,
+ MM_IFACE_MODEM_CARRIER_CONFIG_MAPPING);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_BEARER_LIST,
+ MM_IFACE_MODEM_BEARER_LIST);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_INDICATION_CALL_LIST_RELOAD_ENABLED,
+ MM_IFACE_MODEM_VOICE_INDICATION_CALL_LIST_RELOAD_ENABLED);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_VOICE_DBUS_SKELETON,
+ MM_IFACE_MODEM_VOICE_DBUS_SKELETON);
+
+ g_object_class_override_property (object_class,
+ PROP_MODEM_VOICE_CALL_LIST,
+ MM_IFACE_MODEM_VOICE_CALL_LIST);
+}