2021-12-17 18:07:26 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2021 Purism SPC
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
*
|
|
|
|
* Author: Guido Günther <agx@sigxcpu.org>
|
|
|
|
*/
|
|
|
|
|
2024-02-09 11:27:03 +00:00
|
|
|
#define G_LOG_DOMAIN "CallsEmergencyCallsManager"
|
2021-12-17 18:07:26 +00:00
|
|
|
|
|
|
|
#include "calls-emergency-calls-manager.h"
|
2022-12-21 18:13:25 +00:00
|
|
|
#include "calls-emergency-call-types.h"
|
2021-12-17 18:42:47 +00:00
|
|
|
#include "calls-origin.h"
|
|
|
|
#include "calls-manager.h"
|
2021-12-17 18:07:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* SECTION:calls-emergency-calls-manager
|
|
|
|
* @short_description: Provide a DBus interface for emergency calls
|
|
|
|
* @Title: CallsEmergencyCallsManager
|
|
|
|
*
|
|
|
|
* This tracks emergency call information from the various origins
|
|
|
|
* and makes them available for initiating emergency calls.
|
|
|
|
*/
|
|
|
|
|
2023-04-09 09:37:50 +00:00
|
|
|
typedef struct _CallsEmergencyCallsManager {
|
2021-12-17 18:07:26 +00:00
|
|
|
CallsDBusEmergencyCallsSkeleton parent;
|
|
|
|
|
2023-04-09 09:37:50 +00:00
|
|
|
GListModel *origins;
|
2024-02-09 11:27:03 +00:00
|
|
|
} CallsEmergencyCallsManager;
|
2021-12-17 18:07:26 +00:00
|
|
|
|
|
|
|
static void calls_emergency_calls_iface_init (CallsDBusEmergencyCallsIface *iface);
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (CallsEmergencyCallsManager,
|
|
|
|
calls_emergency_calls_manager,
|
|
|
|
CALLS_DBUS_TYPE_EMERGENCY_CALLS_SKELETON,
|
|
|
|
G_IMPLEMENT_INTERFACE (
|
|
|
|
CALLS_DBUS_TYPE_EMERGENCY_CALLS,
|
|
|
|
calls_emergency_calls_iface_init));
|
|
|
|
|
2021-12-17 18:42:47 +00:00
|
|
|
static void
|
2024-02-09 11:27:03 +00:00
|
|
|
on_emergency_numbers_changed (CallsEmergencyCallsManager *self)
|
2022-12-21 18:13:23 +00:00
|
|
|
{
|
|
|
|
g_signal_emit_by_name (self, "emergency-numbers-changed", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2024-02-09 11:27:03 +00:00
|
|
|
on_origins_changed (CallsEmergencyCallsManager *self,
|
|
|
|
guint position,
|
|
|
|
guint removed,
|
|
|
|
guint added)
|
2021-12-17 18:42:47 +00:00
|
|
|
{
|
|
|
|
g_assert (CALLS_IS_EMERGENCY_CALLS_MANAGER (self));
|
|
|
|
|
2022-12-21 18:13:23 +00:00
|
|
|
for (int i = 0; i < added; i++) {
|
2023-04-09 09:32:10 +00:00
|
|
|
g_autoptr (CallsOrigin) origin = g_list_model_get_item (self->origins, position - i);
|
2022-12-21 18:13:23 +00:00
|
|
|
|
|
|
|
g_signal_connect_object (origin, "notify::emergency-numbers",
|
|
|
|
G_CALLBACK (on_emergency_numbers_changed),
|
|
|
|
self,
|
|
|
|
G_CONNECT_SWAPPED);
|
|
|
|
}
|
|
|
|
|
2021-12-17 18:42:47 +00:00
|
|
|
g_signal_emit_by_name (self, "emergency-numbers-changed", 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-17 18:07:26 +00:00
|
|
|
static gboolean
|
|
|
|
handle_call_emergency_contact (CallsDBusEmergencyCalls *object,
|
2023-04-07 13:00:55 +00:00
|
|
|
GDBusMethodInvocation *invocation,
|
|
|
|
const gchar *arg_id)
|
2021-12-17 18:07:26 +00:00
|
|
|
{
|
2024-02-09 11:27:03 +00:00
|
|
|
CallsEmergencyCallsManager *self = CALLS_EMERGENCY_CALLS_MANAGER (object);
|
2023-04-07 13:00:55 +00:00
|
|
|
g_debug ("Looking for emergency number %s", arg_id);
|
|
|
|
|
|
|
|
g_return_val_if_fail (CALLS_IS_EMERGENCY_CALLS_MANAGER (self), FALSE);
|
|
|
|
|
|
|
|
/* Pick the first origin that supports the given emergency number */
|
|
|
|
for (int i = 0; i < g_list_model_get_n_items (self->origins); i++) {
|
|
|
|
g_autoptr (CallsOrigin) origin = g_list_model_get_item (self->origins, i);
|
|
|
|
g_auto (GStrv) emergency_numbers = NULL;
|
|
|
|
|
|
|
|
emergency_numbers = calls_origin_get_emergency_numbers (origin);
|
|
|
|
if (!emergency_numbers)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for (int j = 0; j < g_strv_length (emergency_numbers); j++) {
|
|
|
|
if (g_strcmp0 (arg_id, emergency_numbers[j]) == 0) {
|
|
|
|
g_debug ("Dialing %s via %s", arg_id, calls_origin_get_name (origin));
|
|
|
|
calls_origin_dial (origin, arg_id);
|
|
|
|
calls_dbus_emergency_calls_complete_call_emergency_contact (object, invocation);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-12-17 18:42:47 +00:00
|
|
|
|
2023-04-07 13:00:55 +00:00
|
|
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
|
|
|
G_DBUS_ERROR_NOT_SUPPORTED,
|
|
|
|
"%s not a known emergency number", arg_id);
|
|
|
|
done:
|
2021-12-17 18:42:47 +00:00
|
|
|
return TRUE;
|
2021-12-17 18:07:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-17 18:42:47 +00:00
|
|
|
#define CONTACT_FORMAT "(ssia{sv})"
|
|
|
|
#define CONTACTS_FORMAT "a" CONTACT_FORMAT
|
|
|
|
|
2023-07-19 10:41:53 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
add_emergency_contact (GVariantBuilder *contacts_builder,
|
|
|
|
const char *number,
|
|
|
|
const char *contact,
|
|
|
|
CallsEmergencyContactSource type)
|
|
|
|
|
|
|
|
{
|
|
|
|
g_variant_builder_open (contacts_builder, G_VARIANT_TYPE (CONTACT_FORMAT));
|
|
|
|
g_variant_builder_add (contacts_builder, "s", number);
|
|
|
|
g_variant_builder_add (contacts_builder, "s", contact);
|
|
|
|
g_variant_builder_add (contacts_builder, "i", type);
|
|
|
|
/* Currently no hints */
|
|
|
|
g_variant_builder_add (contacts_builder, "a{sv}", NULL);
|
|
|
|
g_variant_builder_close (contacts_builder);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-12-17 18:07:26 +00:00
|
|
|
static gboolean
|
|
|
|
handle_get_emergency_contacts (CallsDBusEmergencyCalls *object,
|
2021-12-17 18:42:47 +00:00
|
|
|
GDBusMethodInvocation *invocation)
|
2021-12-17 18:07:26 +00:00
|
|
|
{
|
2021-12-17 18:42:47 +00:00
|
|
|
GVariant *contacts;
|
|
|
|
GVariantBuilder contacts_builder;
|
2024-02-09 11:27:03 +00:00
|
|
|
CallsEmergencyCallsManager *self = CALLS_EMERGENCY_CALLS_MANAGER (object);
|
2021-12-17 18:42:47 +00:00
|
|
|
|
|
|
|
g_variant_builder_init (&contacts_builder, G_VARIANT_TYPE (CONTACTS_FORMAT));
|
|
|
|
|
|
|
|
for (int i = 0; i < g_list_model_get_n_items (self->origins); i++) {
|
2023-04-07 13:00:32 +00:00
|
|
|
g_autoptr (CallsOrigin) origin = g_list_model_get_item (self->origins, i);
|
2021-12-17 18:42:47 +00:00
|
|
|
g_auto (GStrv) emergency_numbers = NULL;
|
2022-12-21 18:13:25 +00:00
|
|
|
const char *country_code;
|
2021-12-17 18:42:47 +00:00
|
|
|
|
|
|
|
emergency_numbers = calls_origin_get_emergency_numbers (origin);
|
|
|
|
if (!emergency_numbers)
|
|
|
|
continue;
|
|
|
|
|
2022-12-21 18:13:25 +00:00
|
|
|
country_code = calls_origin_get_country_code (origin);
|
2021-12-17 18:42:47 +00:00
|
|
|
for (int j = 0; j < g_strv_length (emergency_numbers); j++) {
|
2022-12-21 18:13:25 +00:00
|
|
|
g_autofree char *contact = NULL;
|
|
|
|
|
|
|
|
contact = calls_emergency_call_type_get_name (emergency_numbers[j], country_code);
|
|
|
|
if (contact == NULL)
|
|
|
|
contact = g_strdup (emergency_numbers[j]);
|
2023-07-19 10:41:53 +00:00
|
|
|
|
|
|
|
add_emergency_contact (&contacts_builder,
|
|
|
|
emergency_numbers[j],
|
|
|
|
contact,
|
|
|
|
/* TODO: allow to query type */
|
2022-12-21 18:13:25 +00:00
|
|
|
CALLS_EMERGENCY_CONTACT_SOURCE_UNKNOWN);
|
2021-12-17 18:42:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
contacts = g_variant_builder_end (&contacts_builder);
|
|
|
|
|
|
|
|
calls_dbus_emergency_calls_complete_get_emergency_contacts (object, invocation, contacts);
|
|
|
|
|
|
|
|
return TRUE;
|
2021-12-17 18:07:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
calls_emergency_calls_iface_init (CallsDBusEmergencyCallsIface *iface)
|
|
|
|
{
|
|
|
|
iface->handle_call_emergency_contact = handle_call_emergency_contact;
|
|
|
|
iface->handle_get_emergency_contacts = handle_get_emergency_contacts;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2021-12-17 18:42:47 +00:00
|
|
|
calls_emergency_calls_manager_dispose (GObject *object)
|
2021-12-17 18:07:26 +00:00
|
|
|
{
|
2021-12-17 18:42:47 +00:00
|
|
|
CallsEmergencyCallsManager *self = CALLS_EMERGENCY_CALLS_MANAGER (object);
|
|
|
|
|
|
|
|
g_clear_object (&self->origins);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (calls_emergency_calls_manager_parent_class)->dispose (object);
|
2021-12-17 18:07:26 +00:00
|
|
|
}
|
|
|
|
|
2021-12-17 18:42:47 +00:00
|
|
|
static void
|
|
|
|
calls_emergency_calls_manager_class_init (CallsEmergencyCallsManagerClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->dispose = calls_emergency_calls_manager_dispose;
|
|
|
|
}
|
2021-12-17 18:07:26 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
calls_emergency_calls_manager_init (CallsEmergencyCallsManager *self)
|
|
|
|
{
|
2021-12-17 18:42:47 +00:00
|
|
|
CallsManager *manager = calls_manager_get_default ();
|
|
|
|
|
|
|
|
self->origins = g_object_ref (calls_manager_get_origins (manager));
|
|
|
|
g_signal_connect_object (self->origins,
|
|
|
|
"items-changed",
|
|
|
|
G_CALLBACK (on_origins_changed),
|
|
|
|
self, G_CONNECT_SWAPPED);
|
2021-12-17 18:07:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CallsEmergencyCallsManager *
|
|
|
|
calls_emergency_calls_manager_new (void)
|
|
|
|
{
|
|
|
|
return g_object_new (CALLS_TYPE_EMERGENCY_CALLS_MANAGER, NULL);
|
|
|
|
}
|