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 <bardia@furilabs.com>
Part-of: <https://gitlab.gnome.org/GNOME/calls/-/merge_requests/742>
This commit is contained in:
Bardia Moshiri
2024-10-05 19:49:23 +00:00
committed by Marge Bot
parent c6f816687d
commit 524235b86c
4 changed files with 300 additions and 1 deletions

View File

@@ -26,8 +26,10 @@
#include "calls-ofono-origin.h" #include "calls-ofono-origin.h"
#include "calls-origin.h" #include "calls-origin.h"
#include "calls-ussd.h"
#include "calls-ofono-call.h" #include "calls-ofono-call.h"
#include "calls-message-source.h" #include "calls-message-source.h"
#include "calls-util.h"
#include <glib/gi18n.h> #include <glib/gi18n.h>
@@ -38,20 +40,27 @@ struct _CallsOfonoOrigin {
GDBOModem *modem; GDBOModem *modem;
gchar *name; gchar *name;
GDBOVoiceCallManager *voice; GDBOVoiceCallManager *voice;
GDBOSupplementaryServices *ussd;
gboolean sending_tones; gboolean sending_tones;
GString *tone_queue; GString *tone_queue;
GHashTable *calls; GHashTable *calls;
CallsUssdState ussd_state;
}; };
static void calls_ofono_origin_message_source_interface_init (CallsOriginInterface *iface); 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_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_DEFINE_TYPE_WITH_CODE (CallsOfonoOrigin, calls_ofono_origin, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (CALLS_TYPE_MESSAGE_SOURCE, G_IMPLEMENT_INTERFACE (CALLS_TYPE_MESSAGE_SOURCE,
calls_ofono_origin_message_source_interface_init) 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, G_IMPLEMENT_INTERFACE (CALLS_TYPE_ORIGIN,
calls_ofono_origin_origin_interface_init)) calls_ofono_origin_origin_interface_init))
enum { enum {
PROP_0, PROP_0,
PROP_ID, PROP_ID,
@@ -65,6 +74,238 @@ enum {
static GParamSpec *props[PROP_LAST_PROP]; 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 static void
dial_cb (GDBOVoiceCallManager *voice, dial_cb (GDBOVoiceCallManager *voice,
GAsyncResult *res, 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 static void
constructed (GObject *object) constructed (GObject *object)
{ {
@@ -508,6 +766,14 @@ constructed (GObject *object)
self); self);
G_OBJECT_CLASS (calls_ofono_origin_parent_class)->constructed (object); 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 static void
calls_ofono_origin_origin_interface_init (CallsOriginInterface *iface) calls_ofono_origin_origin_interface_init (CallsOriginInterface *iface)
{ {

View File

@@ -26,6 +26,7 @@
#define CALLS_OFONO_ORIGIN_H__ #define CALLS_OFONO_ORIGIN_H__
#include <libgdbofono/gdbo-modem.h> #include <libgdbofono/gdbo-modem.h>
#include <libgdbofono/gdbo-ussd.h>
#include <glib-object.h> #include <glib-object.h>

View File

@@ -23,7 +23,7 @@
gnome = import('gnome') gnome = import('gnome')
dbus_interfaces = ['manager', 'modem', 'call'] dbus_interfaces = ['manager', 'modem', 'call', 'ussd']
gdbofono_src = [] gdbofono_src = []
gdbofono_headers = [] gdbofono_headers = []

View File

@@ -0,0 +1,19 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.ofono.SupplementaryServices"><method name="Initiate"><arg name="command" type="s" direction="in"/>
<arg name="result_name" type="s" direction="out"/>
<arg name="value" type="v" direction="out"/>
</method><method name="Respond"><arg name="reply" type="s" direction="in"/>
<arg name="result" type="s" direction="out"/>
</method><method name="Cancel"></method><method name="GetProperties"><arg name="properties" type="a{sv}" direction="out"/>
</method><signal name="NotificationReceived"><arg name="message" type="s"/>
</signal>
<signal name="RequestReceived"><arg name="message" type="s"/>
</signal>
<signal name="PropertyChanged"><arg name="name" type="s"/>
<arg name="value" type="v"/>
</signal>
</interface>
</node>