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:
committed by
Marge Bot
parent
c6f816687d
commit
524235b86c
@@ -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 <glib/gi18n.h>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#define CALLS_OFONO_ORIGIN_H__
|
||||
|
||||
#include <libgdbofono/gdbo-modem.h>
|
||||
#include <libgdbofono/gdbo-ussd.h>
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
|
||||
gnome = import('gnome')
|
||||
dbus_interfaces = ['manager', 'modem', 'call']
|
||||
dbus_interfaces = ['manager', 'modem', 'call', 'ussd']
|
||||
|
||||
gdbofono_src = []
|
||||
gdbofono_headers = []
|
||||
|
||||
19
plugins/provider/ofono/libgdbofono/ussd.xml
Normal file
19
plugins/provider/ofono/libgdbofono/ussd.xml
Normal 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>
|
||||
Reference in New Issue
Block a user