From 524235b86c66802f22197800f578d5a0d9827c71 Mon Sep 17 00:00:00 2001 From: Bardia Moshiri Date: Sat, 5 Oct 2024 19:49:23 +0000 Subject: [PATCH] ofono: implement USSD interface all the information for ofono USSD iface comes from https://github.com/FuriLabs/ofono/blob/trixie/ofono/doc/supplementaryservices-api.txt the introspect for gdbo bindings comes from gdbus introspect -x Signed-off-by: Bardia Moshiri Part-of: --- plugins/provider/ofono/calls-ofono-origin.c | 279 ++++++++++++++++++ plugins/provider/ofono/calls-ofono-origin.h | 1 + .../provider/ofono/libgdbofono/meson.build | 2 +- plugins/provider/ofono/libgdbofono/ussd.xml | 19 ++ 4 files changed, 300 insertions(+), 1 deletion(-) create mode 100644 plugins/provider/ofono/libgdbofono/ussd.xml diff --git a/plugins/provider/ofono/calls-ofono-origin.c b/plugins/provider/ofono/calls-ofono-origin.c index c56fb83..915c883 100644 --- a/plugins/provider/ofono/calls-ofono-origin.c +++ b/plugins/provider/ofono/calls-ofono-origin.c @@ -26,8 +26,10 @@ #include "calls-ofono-origin.h" #include "calls-origin.h" +#include "calls-ussd.h" #include "calls-ofono-call.h" #include "calls-message-source.h" +#include "calls-util.h" #include @@ -38,20 +40,27 @@ struct _CallsOfonoOrigin { GDBOModem *modem; gchar *name; GDBOVoiceCallManager *voice; + GDBOSupplementaryServices *ussd; gboolean sending_tones; GString *tone_queue; GHashTable *calls; + + CallsUssdState ussd_state; }; static void calls_ofono_origin_message_source_interface_init (CallsOriginInterface *iface); static void calls_ofono_origin_origin_interface_init (CallsOriginInterface *iface); +static void calls_ofono_origin_ussd_interface_init (CallsUssdInterface *iface); G_DEFINE_TYPE_WITH_CODE (CallsOfonoOrigin, calls_ofono_origin, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (CALLS_TYPE_MESSAGE_SOURCE, calls_ofono_origin_message_source_interface_init) + G_IMPLEMENT_INTERFACE (CALLS_TYPE_USSD, + calls_ofono_origin_ussd_interface_init) G_IMPLEMENT_INTERFACE (CALLS_TYPE_ORIGIN, calls_ofono_origin_origin_interface_init)) + enum { PROP_0, PROP_ID, @@ -65,6 +74,238 @@ enum { static GParamSpec *props[PROP_LAST_PROP]; +static void +ussd_initiate_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr (GTask) task = user_data; + GDBOSupplementaryServices *ussd = GDBO_SUPPLEMENTARY_SERVICES (object); + CallsOfonoOrigin *self = CALLS_OFONO_ORIGIN (user_data); + g_autoptr (GVariant) variant = NULL; + char *response = NULL; + GError *error = NULL; + + g_assert (G_IS_TASK (task)); + self = g_task_get_source_object (task); + + g_assert (GDBO_IS_SUPPLEMENTARY_SERVICES (ussd)); + g_assert (CALLS_IS_OFONO_ORIGIN (self)); + + gdbo_supplementary_services_call_initiate_finish (ussd, NULL, + &variant, result, &error); + + if (error) { + g_task_return_error (task, error); + } else { + g_autoptr (GVariant) child = g_variant_get_child_value (variant, 0); + response = g_variant_dup_string (child, NULL); + self->ussd_state = CALLS_USSD_STATE_USER_RESPONSE; + g_task_return_pointer (task, response, g_free); + } +} + +static void +ussd_reinitiate_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr (GTask) task = user_data; + CallsUssd *ussd = CALLS_USSD (object); + CallsOfonoOrigin *self = CALLS_OFONO_ORIGIN (user_data); + GCancellable *cancellable; + GError *error = NULL; + const char *command; + + g_assert (G_IS_TASK (task)); + self = g_task_get_source_object (task); + + g_assert (CALLS_IS_USSD (ussd)); + g_assert (CALLS_IS_OFONO_ORIGIN (self)); + + calls_ussd_cancel_finish (ussd, result, &error); + cancellable = g_task_get_cancellable (task); + command = g_task_get_task_data (task); + + if (error) + g_task_return_error (task, error); + else { + self->ussd_state = CALLS_USSD_STATE_ACTIVE; + gdbo_supplementary_services_call_initiate (self->ussd, command, cancellable, + ussd_initiate_cb, g_steal_pointer (&task)); + } +} + +static void +ussd_respond_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr (GTask) task = user_data; + GDBOSupplementaryServices *ussd = GDBO_SUPPLEMENTARY_SERVICES (object); + CallsOfonoOrigin *self; + char *response = NULL; + GError *error = NULL; + + g_assert (G_IS_TASK (task)); + self = g_task_get_source_object (task); + + g_assert (CALLS_IS_OFONO_ORIGIN (self)); + g_assert (GDBO_IS_SUPPLEMENTARY_SERVICES (ussd)); + + gdbo_supplementary_services_call_respond_finish (ussd, &response, result, &error); + + if (error) + g_task_return_error (task, error); + else + g_task_return_pointer (task, response, g_free); +} + +static void +ussd_cancel_cb (GObject *object, + GAsyncResult *result, + gpointer user_data) +{ + g_autoptr (GTask) task = user_data; + GDBOSupplementaryServices *ussd = GDBO_SUPPLEMENTARY_SERVICES (object); + CallsOfonoOrigin *self; + GError *error = NULL; + gboolean response; + + g_assert (G_IS_TASK (task)); + self = g_task_get_source_object (task); + + g_assert (CALLS_IS_OFONO_ORIGIN (self)); + g_assert (GDBO_IS_SUPPLEMENTARY_SERVICES (ussd)); + + response = gdbo_supplementary_services_call_cancel_finish (ussd, result, &error); + self->ussd_state = CALLS_USSD_STATE_IDLE; + + if (error) + g_task_return_error (task, error); + else + g_task_return_boolean (task, response); +} + +static CallsUssdState +calls_ofono_ussd_get_state (CallsUssd *ussd) +{ + CallsOfonoOrigin *self = CALLS_OFONO_ORIGIN (ussd); + + if (!self->ussd) + self->ussd_state = CALLS_USSD_STATE_UNKNOWN; + + return self->ussd_state; +} + +static void +calls_ofono_ussd_initiate_async (CallsUssd *ussd, + const char *command, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_autoptr (GTask) task = NULL; + CallsOfonoOrigin *self = CALLS_OFONO_ORIGIN (ussd); + CallsUssdState state; + + g_return_if_fail (CALLS_IS_USSD (ussd)); + + task = g_task_new (self, cancellable, callback, user_data); + + if (!self->ussd) { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "No USSD interface found"); + return; + } + + if (STR_IS_NULL_OR_EMPTY (command)) { + g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, + "USSD command empty"); + return; + } + + state = calls_ussd_get_state (CALLS_USSD (self)); + g_task_set_task_data (task, g_strdup (command), g_free); + + if (state == CALLS_USSD_STATE_ACTIVE || + state == CALLS_USSD_STATE_USER_RESPONSE) + calls_ussd_cancel_async (CALLS_USSD (self), cancellable, + ussd_reinitiate_cb, g_steal_pointer (&task)); + else { + self->ussd_state = CALLS_USSD_STATE_ACTIVE; + gdbo_supplementary_services_call_initiate (self->ussd, command, cancellable, + ussd_initiate_cb, g_steal_pointer (&task)); + } +} + +static char * +calls_ofono_ussd_initiate_finish (CallsUssd *ussd, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (CALLS_IS_USSD (ussd), NULL); + g_return_val_if_fail (G_IS_TASK (result), NULL); + + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +calls_ofono_ussd_respond_async (CallsUssd *ussd, + const char *response, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CallsOfonoOrigin *self = CALLS_OFONO_ORIGIN (ussd); + GTask *task; + + g_return_if_fail (CALLS_IS_USSD (ussd)); + task = g_task_new (self, cancellable, callback, user_data); + gdbo_supplementary_services_call_respond (self->ussd, response, cancellable, + ussd_respond_cb, task); +} + +static char * +calls_ofono_ussd_respond_finish (CallsUssd *ussd, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (CALLS_IS_USSD (ussd), NULL); + g_return_val_if_fail (G_IS_TASK (result), NULL); + + + return g_task_propagate_pointer (G_TASK (result), error); +} + +static void +calls_ofono_ussd_cancel_async (CallsUssd *ussd, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + CallsOfonoOrigin *self = CALLS_OFONO_ORIGIN (ussd); + GTask *task; + + g_return_if_fail (CALLS_IS_USSD (ussd)); + + task = g_task_new (self, cancellable, callback, user_data); + gdbo_supplementary_services_call_cancel (self->ussd, cancellable, + ussd_cancel_cb, task); +} + +static gboolean +calls_ofono_ussd_cancel_finish (CallsUssd *ussd, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (CALLS_IS_USSD (ussd), FALSE); + g_return_val_if_fail (G_IS_TASK (result), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + + static void dial_cb (GDBOVoiceCallManager *voice, GAsyncResult *res, @@ -479,6 +720,23 @@ voice_new_cb (GDBusConnection *connection, } +static void +ussd_new_cb (GDBusConnection *connection, + GAsyncResult *res, + CallsOfonoOrigin *self) +{ + g_autoptr (GError) error = NULL; + + self->ussd = gdbo_supplementary_services_proxy_new_finish (res, &error); + if (!self->ussd) { + g_warning ("Error creating oFono" + " SupplementaryServices `%s' proxy: %s", + self->name, error->message); + CALLS_ERROR (self, error); + } +} + + static void constructed (GObject *object) { @@ -508,6 +766,14 @@ constructed (GObject *object) self); G_OBJECT_CLASS (calls_ofono_origin_parent_class)->constructed (object); + + gdbo_supplementary_services_proxy_new (self->connection, + G_DBUS_PROXY_FLAGS_NONE, + g_dbus_proxy_get_name (modem_proxy), + g_dbus_proxy_get_object_path (modem_proxy), + NULL, + (GAsyncReadyCallback) ussd_new_cb, + self); } @@ -578,6 +844,19 @@ calls_ofono_origin_message_source_interface_init (CallsOriginInterface *iface) } +static void +calls_ofono_origin_ussd_interface_init (CallsUssdInterface *iface) +{ + iface->get_state = calls_ofono_ussd_get_state; + iface->initiate_async = calls_ofono_ussd_initiate_async; + iface->initiate_finish = calls_ofono_ussd_initiate_finish; + iface->respond_async = calls_ofono_ussd_respond_async; + iface->respond_finish = calls_ofono_ussd_respond_finish; + iface->cancel_async = calls_ofono_ussd_cancel_async; + iface->cancel_finish = calls_ofono_ussd_cancel_finish; +} + + static void calls_ofono_origin_origin_interface_init (CallsOriginInterface *iface) { diff --git a/plugins/provider/ofono/calls-ofono-origin.h b/plugins/provider/ofono/calls-ofono-origin.h index c21007d..259ca6b 100644 --- a/plugins/provider/ofono/calls-ofono-origin.h +++ b/plugins/provider/ofono/calls-ofono-origin.h @@ -26,6 +26,7 @@ #define CALLS_OFONO_ORIGIN_H__ #include +#include #include diff --git a/plugins/provider/ofono/libgdbofono/meson.build b/plugins/provider/ofono/libgdbofono/meson.build index 04d632d..b6ad418 100644 --- a/plugins/provider/ofono/libgdbofono/meson.build +++ b/plugins/provider/ofono/libgdbofono/meson.build @@ -23,7 +23,7 @@ gnome = import('gnome') -dbus_interfaces = ['manager', 'modem', 'call'] +dbus_interfaces = ['manager', 'modem', 'call', 'ussd'] gdbofono_src = [] gdbofono_headers = [] diff --git a/plugins/provider/ofono/libgdbofono/ussd.xml b/plugins/provider/ofono/libgdbofono/ussd.xml new file mode 100644 index 0000000..11e7144 --- /dev/null +++ b/plugins/provider/ofono/libgdbofono/ussd.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + +