mirror of
https://gitlab.gnome.org/GNOME/calls.git
synced 2024-05-18 11:09:28 +00:00
Merge branch 'wip/policy-engine' into 'main'
Draft: Revamp plugin infrastructure to accomodate "policy engine" plugins See merge request GNOME/calls!588
This commit is contained in:
commit
7a7a3b451f
|
@ -4,5 +4,7 @@ subdir('provider/dummy')
|
|||
subdir('provider/ofono')
|
||||
subdir('provider/sip')
|
||||
subdir('provider/tests')
|
||||
subdir('policy/keyfile')
|
||||
subdir('policy/tests')
|
||||
|
||||
calls_plugins = [calls_mm, calls_dummy, calls_ofono, calls_sip]
|
||||
|
|
221
plugins/policy/keyfile/calls-keyfile-engine.c
Normal file
221
plugins/policy/keyfile/calls-keyfile-engine.c
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Purism SPC
|
||||
*
|
||||
* This file is part of Calls.
|
||||
*
|
||||
* Calls 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Calls 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "CallsKeyfileEngine"
|
||||
|
||||
#include "calls-keyfile-engine.h"
|
||||
#include "calls-util.h"
|
||||
|
||||
/**
|
||||
* SECTION:calls-keyfile-engine
|
||||
* @short_description: #GKeyFile based #CallsPolicyEngine
|
||||
* @Title: CallsKeyfileEngine
|
||||
*
|
||||
* A simple #CallsPolicyEngine that looks up numbers in a #GKeyFile
|
||||
*/
|
||||
|
||||
struct _CallsKeyfileEngine {
|
||||
GObject parent_instance;
|
||||
|
||||
GKeyFile *keyfile;
|
||||
};
|
||||
|
||||
|
||||
static void calls_keyfile_policy_engine_interface_init (CallsPolicyEngineInterface *iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE
|
||||
(CallsKeyfileEngine, calls_keyfile_engine, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (CALLS_TYPE_POLICY_ENGINE,
|
||||
calls_keyfile_policy_engine_interface_init))
|
||||
|
||||
|
||||
static char *
|
||||
normalize_id (const char *id)
|
||||
{
|
||||
/* TODO */
|
||||
return g_strdup (id);
|
||||
}
|
||||
|
||||
|
||||
static CallsPolicyDecision
|
||||
decision_from_nick (const char *nick)
|
||||
{
|
||||
g_autoptr (GEnumClass) klass = NULL;
|
||||
GEnumValue *value;
|
||||
CallsPolicyDecision ret;
|
||||
|
||||
if (STR_IS_NULL_OR_EMPTY (nick))
|
||||
return CALLS_POLICY_DECISION_PASS;
|
||||
|
||||
klass = g_type_class_ref (CALLS_TYPE_POLICY_DECISION);
|
||||
value = g_enum_get_value_by_nick (klass, nick);
|
||||
|
||||
if (value)
|
||||
ret = (CallsPolicyDecision) value->value;
|
||||
else
|
||||
ret = CALLS_POLICY_DECISION_INTERNAL_ERROR;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_keyfile_engine_decide (CallsPolicyEngine *policy_engine,
|
||||
const char *id,
|
||||
const char *protocol,
|
||||
const char *origin_id,
|
||||
GTask *task)
|
||||
{
|
||||
CallsKeyfileEngine *self = (CallsKeyfileEngine *) policy_engine;
|
||||
g_autoptr (GError) error = NULL;
|
||||
g_auto (GStrv) keys = NULL;
|
||||
GVariantDict dict;
|
||||
g_autofree char *id_normalized = NULL;
|
||||
g_autofree char *action_lookup = NULL;
|
||||
CallsPolicyDecision action = CALLS_POLICY_DECISION_PASS;
|
||||
gsize n_keys;
|
||||
gboolean dict_has_keys = FALSE;
|
||||
|
||||
|
||||
g_assert (CALLS_IS_KEYFILE_ENGINE (self));
|
||||
g_assert (self->keyfile);
|
||||
g_assert (G_IS_TASK (task));
|
||||
|
||||
//id_normalized = calls_util_number_normalize (id); // TODO
|
||||
id_normalized = normalize_id (id);
|
||||
|
||||
keys = g_key_file_get_keys (self->keyfile, id_normalized, &n_keys, NULL);
|
||||
|
||||
if (!keys)
|
||||
goto out;
|
||||
|
||||
action_lookup =
|
||||
g_key_file_get_string (self->keyfile,
|
||||
id_normalized,
|
||||
"action",
|
||||
&error);
|
||||
if (STR_IS_NULL_OR_EMPTY (action_lookup))
|
||||
goto out;
|
||||
|
||||
action = decision_from_nick (action_lookup);
|
||||
|
||||
/* add any arguments found in the keyfile */
|
||||
g_variant_dict_init (&dict, NULL);
|
||||
|
||||
for (guint i = 0; i < n_keys; i++) {
|
||||
g_autofree char *val = NULL;
|
||||
|
||||
if (g_strcmp0 (keys[i], "action") == 0)
|
||||
continue;
|
||||
|
||||
val = g_key_file_get_string (self->keyfile, id_normalized, keys[i], NULL);
|
||||
if (STR_IS_NULL_OR_EMPTY (val)) {
|
||||
g_warning ("Empty value found for key '%s'", keys[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_variant_dict_insert (&dict, keys[i], "s", val);
|
||||
dict_has_keys = TRUE;
|
||||
}
|
||||
|
||||
if (!dict_has_keys)
|
||||
g_variant_dict_clear (&dict);
|
||||
|
||||
out:
|
||||
g_task_return_pointer (task,
|
||||
calls_policy_decision_new (action,
|
||||
dict_has_keys ? g_variant_dict_end (&dict) : NULL),
|
||||
(GDestroyNotify) g_variant_unref);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_keyfile_engine_dispose (GObject *object)
|
||||
{
|
||||
CallsKeyfileEngine *self = CALLS_KEYFILE_ENGINE (object);
|
||||
|
||||
g_clear_pointer (&self->keyfile, g_key_file_unref);
|
||||
|
||||
G_OBJECT_CLASS (calls_keyfile_engine_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_keyfile_policy_engine_interface_init (CallsPolicyEngineInterface *iface)
|
||||
{
|
||||
iface->decide = calls_keyfile_engine_decide;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_keyfile_engine_class_init (CallsKeyfileEngineClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->dispose = calls_keyfile_engine_dispose;
|
||||
}
|
||||
|
||||
static void
|
||||
calls_keyfile_engine_init (CallsKeyfileEngine *self)
|
||||
{
|
||||
self->keyfile = g_key_file_new ();
|
||||
}
|
||||
|
||||
|
||||
CallsKeyfileEngine *
|
||||
calls_keyfile_engine_new (void)
|
||||
{
|
||||
return g_object_new (CALLS_TYPE_KEYFILE_ENGINE, NULL);
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
calls_keyfile_engine_load_data (CallsKeyfileEngine *self,
|
||||
const char *data,
|
||||
gsize len,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (CALLS_IS_KEYFILE_ENGINE (self), FALSE);
|
||||
g_return_val_if_fail (self->keyfile, FALSE);
|
||||
|
||||
return g_key_file_load_from_data (self->keyfile,
|
||||
data,
|
||||
len,
|
||||
G_KEY_FILE_NONE,
|
||||
error);
|
||||
}
|
||||
|
||||
gboolean
|
||||
calls_keyfile_engine_load_file (CallsKeyfileEngine *self,
|
||||
const char *path,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (CALLS_IS_KEYFILE_ENGINE (self), FALSE);
|
||||
|
||||
return g_key_file_load_from_file (self->keyfile,
|
||||
path,
|
||||
G_KEY_FILE_KEEP_COMMENTS,
|
||||
error);
|
||||
}
|
45
plugins/policy/keyfile/calls-keyfile-engine.h
Normal file
45
plugins/policy/keyfile/calls-keyfile-engine.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Purism SPC
|
||||
*
|
||||
* This file is part of Calls.
|
||||
*
|
||||
* Calls 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Calls 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "calls-policy-engine.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CALLS_TYPE_KEYFILE_ENGINE calls_keyfile_engine_get_type ()
|
||||
|
||||
G_DECLARE_FINAL_TYPE (CallsKeyfileEngine, calls_keyfile_engine, CALLS, KEYFILE_ENGINE, GObject)
|
||||
|
||||
CallsKeyfileEngine *calls_keyfile_engine_new (void);
|
||||
gboolean calls_keyfile_engine_load_data (CallsKeyfileEngine *self,
|
||||
const char *data,
|
||||
gsize len,
|
||||
GError **error);
|
||||
gboolean calls_keyfile_engine_load_file (CallsKeyfileEngine *self,
|
||||
const char *path,
|
||||
GError **error);
|
||||
|
||||
|
||||
|
||||
G_END_DECLS
|
8
plugins/policy/keyfile/keyfile.plugin.in
Normal file
8
plugins/policy/keyfile/keyfile.plugin.in
Normal file
|
@ -0,0 +1,8 @@
|
|||
[Plugin]
|
||||
Module=keyfile
|
||||
Name=Keyfile
|
||||
Description=Keyfile based policy engine
|
||||
Authors=Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
Copyright=Copyright (C) 2021-2022 Purism SPC
|
||||
Website=@PACKAGE_URL_RAW@
|
||||
Version=@PACKAGE_VERSION@
|
54
plugins/policy/keyfile/meson.build
Normal file
54
plugins/policy/keyfile/meson.build
Normal file
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# Copyright (C) 2022 Purism SPC
|
||||
#
|
||||
# This file is part of Calls.
|
||||
#
|
||||
# Calls 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Calls 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
|
||||
|
||||
keyfile_include = include_directories('.')
|
||||
|
||||
keyfile_install_dir = join_paths(full_calls_plugin_libdir, 'keyfile')
|
||||
keyfile_plugin = configure_file(
|
||||
input: 'keyfile.plugin.in',
|
||||
output: 'keyfile.plugin',
|
||||
configuration: config_data,
|
||||
install: true,
|
||||
install_dir: keyfile_install_dir,
|
||||
)
|
||||
|
||||
keyfile_deps = [
|
||||
dependency('gobject-2.0'),
|
||||
dependency('gtk+-3.0'),
|
||||
dependency('libpeas-1.0'),
|
||||
]
|
||||
|
||||
keyfile_sources = files([
|
||||
'calls-keyfile-engine.c', 'calls-keyfile-engine.h',
|
||||
])
|
||||
|
||||
|
||||
calls_keyfile_policy = shared_module(
|
||||
'keyfile-policy',
|
||||
keyfile_sources,
|
||||
dependencies: keyfile_deps,
|
||||
include_directories: calls_includes,
|
||||
install: true,
|
||||
install_dir: keyfile_install_dir,
|
||||
)
|
72
plugins/policy/tests/meson.build
Normal file
72
plugins/policy/tests/meson.build
Normal file
|
@ -0,0 +1,72 @@
|
|||
#
|
||||
# Copyright (C) 2022 Purism SPC
|
||||
#
|
||||
# This file is part of Calls.
|
||||
#
|
||||
# Calls 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Calls 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
|
||||
|
||||
|
||||
if get_option('tests')
|
||||
|
||||
test_env = [
|
||||
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
|
||||
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
|
||||
'G_DEBUG=gc-friendly,fatal-warnings',
|
||||
'GSETTINGS_BACKEND=memory',
|
||||
'PYTHONDONTWRITEBYTECODE=yes',
|
||||
'MALLOC_CHECK_=2',
|
||||
'NO_AT_BRIDGE=1',
|
||||
'GSETTINGS_SCHEMA_DIR=@0@/data'.format(meson.project_build_root()),
|
||||
'CALLS_PLUGIN_DIR=@0@/plugins'.format(meson.project_build_root()),
|
||||
]
|
||||
|
||||
test_cflags = [
|
||||
'-DFOR_TESTING',
|
||||
'-Wno-error=deprecated-declarations',
|
||||
]
|
||||
|
||||
|
||||
tests = [
|
||||
['reject', ['test-keyfile-reject.c']],
|
||||
]
|
||||
|
||||
foreach test : tests
|
||||
name = test[0]
|
||||
|
||||
test_sources = []
|
||||
foreach src : test[1]
|
||||
test_sources += src
|
||||
endforeach
|
||||
t = executable(name, test_sources, keyfile_sources,
|
||||
c_args: test_cflags,
|
||||
link_args: test_link_args,
|
||||
pie: true,
|
||||
link_with: [calls_vala, libcalls],
|
||||
dependencies: keyfile_deps,
|
||||
include_directories: [
|
||||
calls_includes,
|
||||
keyfile_include,
|
||||
]
|
||||
)
|
||||
|
||||
test(name, t, env: test_env)
|
||||
endforeach
|
||||
|
||||
endif
|
68
plugins/policy/tests/test-keyfile-reject.c
Normal file
68
plugins/policy/tests/test-keyfile-reject.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Purism SPC
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0+
|
||||
*/
|
||||
|
||||
#include "calls-keyfile-engine.h"
|
||||
#include "calls-policy-engine.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
|
||||
static GMainLoop *loop;
|
||||
|
||||
static void
|
||||
on_decision_ready (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
CallsPolicyEngine *engine = CALLS_POLICY_ENGINE (source_object);
|
||||
GVariant *decision = calls_policy_engine_decide_finish (engine, res, &error);
|
||||
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_assert_cmpvariant (decision, user_data);
|
||||
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_reject (void)
|
||||
{
|
||||
CallsKeyfileEngine *kf_engine = calls_keyfile_engine_new ();
|
||||
g_autoptr (GVariant) expect_reject = calls_policy_decision_new (CALLS_POLICY_DECISION_REJECT, NULL);
|
||||
const char *data =
|
||||
"[0123456789]\n"
|
||||
"action=reject\n";
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
g_assert_true (calls_keyfile_engine_load_data (kf_engine, data, -1, NULL));
|
||||
|
||||
calls_policy_engine_decide (CALLS_POLICY_ENGINE (kf_engine),
|
||||
"0123456789",
|
||||
"tel",
|
||||
NULL,
|
||||
0,
|
||||
on_decision_ready,
|
||||
expect_reject);
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_assert_finalize_object (kf_engine);
|
||||
g_clear_pointer (&loop, g_main_loop_unref);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (gint argc,
|
||||
gchar *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/Calls/PolicyEngine/Keyfile/reject", test_reject);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
168
src/calls-extension.c
Normal file
168
src/calls-extension.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Purism SPC
|
||||
*
|
||||
* This file is part of Calls.
|
||||
*
|
||||
* Calls 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Calls 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "calls-extension.h"
|
||||
|
||||
#include "enum-types.h"
|
||||
|
||||
/**
|
||||
* SECTION:calls-extension
|
||||
* @short_description: An extension for calls
|
||||
* @Title: CallsExtension
|
||||
*
|
||||
* A base class for all plugin extensions.
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_TYPE,
|
||||
PROP_PROVIDER,
|
||||
PROP_LAST_PROP
|
||||
};
|
||||
static GParamSpec *props[PROP_LAST_PROP];
|
||||
|
||||
typedef struct {
|
||||
GObject parent_instance;
|
||||
|
||||
CallsExtensionType type;
|
||||
CallsProvider *provider;
|
||||
} CallsExtensionPrivate;
|
||||
|
||||
struct _CallsExtensionClass {
|
||||
GObjectClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (CallsExtension, calls_extension, G_TYPE_OBJECT)
|
||||
|
||||
|
||||
static void
|
||||
calls_extension_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
CallsExtension *self = CALLS_EXTENSION (object);
|
||||
CallsExtensionPrivate *priv = calls_extension_get_instance_private (self);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_TYPE:
|
||||
priv->type = g_value_get_enum (value);
|
||||
break;
|
||||
|
||||
case PROP_PROVIDER:
|
||||
priv->provider = g_value_dup_object (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_extension_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
CallsExtension *self = CALLS_EXTENSION (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_TYPE:
|
||||
g_value_set_enum (value, calls_extension_get_extension_type (self));
|
||||
break;
|
||||
|
||||
case PROP_PROVIDER:
|
||||
g_value_set_object (value, calls_extension_get_provider (self));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_extension_init (CallsExtension *self)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_extension_class_init (CallsExtensionClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = calls_extension_set_property;
|
||||
object_class->get_property = calls_extension_get_property;
|
||||
|
||||
/**
|
||||
* CallsExtension:type:
|
||||
*
|
||||
* The #CallsExtensionType implemented by this plugin
|
||||
*/
|
||||
props[PROP_TYPE] =
|
||||
g_param_spec_enum ("type",
|
||||
"",
|
||||
"",
|
||||
CALLS_TYPE_EXTENSION_TYPE,
|
||||
CALLS_EXTENSION_TYPE_UNKNOWN,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
|
||||
/**
|
||||
* CallsExtension:provider:
|
||||
*
|
||||
* The #CallsProvider implemented by this plugin
|
||||
*/
|
||||
props[PROP_PROVIDER] =
|
||||
g_param_spec_object ("provider",
|
||||
"",
|
||||
"",
|
||||
CALLS_TYPE_PROVIDER,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS);
|
||||
}
|
||||
|
||||
|
||||
CallsProvider *
|
||||
calls_extension_get_provider (CallsExtension *self)
|
||||
{
|
||||
CallsExtensionPrivate *priv = calls_extension_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (CALLS_IS_EXTENSION (self), NULL);
|
||||
g_return_val_if_fail (priv->type == CALLS_EXTENSION_TYPE_PROVIDER, NULL);
|
||||
|
||||
return priv->provider;
|
||||
}
|
||||
|
||||
|
||||
CallsExtensionType
|
||||
calls_extension_get_extension_type (CallsExtension *self)
|
||||
{
|
||||
CallsExtensionPrivate *priv = calls_extension_get_instance_private (self);
|
||||
|
||||
g_return_val_if_fail (CALLS_IS_EXTENSION (self), CALLS_EXTENSION_TYPE_UNKNOWN);
|
||||
|
||||
return priv->type;
|
||||
}
|
47
src/calls-extension.h
Normal file
47
src/calls-extension.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Purism SPC
|
||||
*
|
||||
* This file is part of Calls.
|
||||
*
|
||||
* Calls 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Calls 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#include "calls-provider.h"
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* CallsPluginType:
|
||||
* @CALLS_EXTENSION_TYPE_UNKNOWN: Unknown type of extension
|
||||
* @CALLS_EXTENSION_TYPE_PROVIDER: Provider extension
|
||||
*/
|
||||
typedef enum {
|
||||
CALLS_EXTENSION_TYPE_UNKNOWN,
|
||||
CALLS_EXTENSION_TYPE_PROVIDER,
|
||||
} CallsExtensionType;
|
||||
|
||||
#define CALLS_TYPE_EXTENSION (calls_extension_get_type ())
|
||||
|
||||
G_DECLARE_DERIVABLE_TYPE (CallsExtension, calls_extension, CALLS, EXTENSION, GObject)
|
||||
|
||||
CallsExtensionType calls_extension_get_extension_type (CallsExtension *self);
|
||||
CallsProvider *calls_extension_get_provider (CallsExtension *self);
|
||||
|
||||
G_END_DECLS
|
268
src/calls-policy-engine.c
Normal file
268
src/calls-policy-engine.c
Normal file
|
@ -0,0 +1,268 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Purism SPC
|
||||
*
|
||||
* This file is part of Calls.
|
||||
*
|
||||
* Calls 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Calls 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "CallsPolicyEngine"
|
||||
|
||||
#include "calls-policy-engine.h"
|
||||
#include "calls-util.h"
|
||||
#include "enum-types.h"
|
||||
|
||||
/**
|
||||
* SECTION:calls-policy-engine
|
||||
* @short_description: Policy engines allow taking predefined actions for incoming calls
|
||||
* @Title: CallsPolicyEngine
|
||||
*
|
||||
* The #CallsPolicyEngine interface provides an asynchronous decide() method
|
||||
* which returns a #CALLS_POLICY_DECISION
|
||||
*
|
||||
*/
|
||||
|
||||
G_DEFINE_INTERFACE (CallsPolicyEngine, calls_policy_engine, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
calls_policy_engine_default_init (CallsPolicyEngineInterface *iface)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
GCancellable *cancel;
|
||||
guint timeout_id;
|
||||
} PolicyTaskData;
|
||||
|
||||
|
||||
static void
|
||||
policy_task_data_free (PolicyTaskData *data)
|
||||
{
|
||||
g_object_unref (data->cancel);
|
||||
g_clear_handle_id (&data->timeout_id, g_source_remove);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
|
||||
#if !GLIB_CHECK_VERSION (2, 74,0)
|
||||
static gboolean
|
||||
on_cancel_task (PolicyTaskData *data)
|
||||
{
|
||||
g_cancellable_cancel (data->cancel);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* calls_policy_decision_is_valid:
|
||||
* @decision: A #GVariant of type @CALLS_POLICY_VARIANT_FORMAT
|
||||
* @error: (optional) (out): The return location of a #GError
|
||||
*
|
||||
* Checks if @decision is of the correct type and depending
|
||||
* on the type of decision if the dictionary inside @decision contains
|
||||
* required keys.
|
||||
*
|
||||
* Returns: Returns %TRUE if @decision is valid, %FALSE otherwise.
|
||||
*/
|
||||
gboolean
|
||||
calls_policy_decision_is_valid (GVariant *decision,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr (GVariant) var_dict = NULL;
|
||||
GVariantDict dict;
|
||||
CallsPolicyDecision decision_type;
|
||||
gboolean valid = FALSE;
|
||||
|
||||
if (!decision || g_strcmp0 (g_variant_get_type_string (decision), CALLS_POLICY_DECISION_FORMAT)) {
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, "Not a valid decision");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_variant_get (decision, CALLS_POLICY_DECISION_FORMAT_CONSUME_DICT, &decision_type, &var_dict);
|
||||
|
||||
g_variant_dict_init (&dict, var_dict);
|
||||
|
||||
switch (decision_type) {
|
||||
case CALLS_POLICY_DECISION_INTERNAL_ERROR:
|
||||
case CALLS_POLICY_DECISION_PASS:
|
||||
case CALLS_POLICY_DECISION_SILENCE:
|
||||
case CALLS_POLICY_DECISION_REJECT:
|
||||
case CALLS_POLICY_DECISION_FORCE_ALLOW:
|
||||
valid = TRUE;
|
||||
break;
|
||||
case CALLS_POLICY_DECISION_SMS:
|
||||
if (g_variant_dict_contains (&dict, "sms-text"))
|
||||
valid = TRUE;
|
||||
else
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
||||
"Dictionary must contain 'sms-text' key");
|
||||
break;
|
||||
case CALLS_POLICY_DECISION_REDIRECT:
|
||||
if (g_variant_dict_contains (&dict, "redirect-to"))
|
||||
valid = TRUE;
|
||||
else
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
||||
"Dictionary must contain 'redirect-to' key");
|
||||
break;
|
||||
|
||||
default:
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
|
||||
"Unknown decision type %d", decision_type);
|
||||
break;
|
||||
}
|
||||
|
||||
g_variant_dict_clear (&dict);
|
||||
|
||||
return valid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* calls_policy_engine_decide_finish:
|
||||
* @self: A #CallsPolicyEngine
|
||||
* @res: A #GAsyncResult
|
||||
* @error: (out) (optional): return location for a #GError
|
||||
*
|
||||
* Get the result of the policy decision.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): A #GVariant of type @CALLS_POLICY_VARIANT_FORMAT
|
||||
* where the first argument is the #CallsPolicyDecision and the second argument
|
||||
* a dictionary containing additional hints, or %NULL if there was an error.
|
||||
*
|
||||
* The returned value is never floating. You should free it with
|
||||
* g_variant_unref() when you're done with it.
|
||||
*/
|
||||
GVariant *
|
||||
calls_policy_engine_decide_finish (CallsPolicyEngine *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
GTask *task;
|
||||
GVariant *decision;
|
||||
|
||||
g_return_val_if_fail (g_task_is_valid (res, self),
|
||||
g_variant_new (CALLS_POLICY_DECISION_FORMAT,
|
||||
CALLS_POLICY_DECISION_INTERNAL_ERROR,
|
||||
NULL));
|
||||
|
||||
task = G_TASK (res);
|
||||
decision = g_task_propagate_pointer (task, error);
|
||||
g_object_unref (task);
|
||||
|
||||
if (!calls_policy_decision_is_valid (decision, error)) {
|
||||
g_variant_unref (decision);
|
||||
return g_variant_new (CALLS_POLICY_DECISION_FORMAT,
|
||||
CALLS_POLICY_DECISION_INTERNAL_ERROR,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return decision;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* calls_policy_engine_decide:
|
||||
* @self: A #CallsPolicyEngine
|
||||
* @id: The id of a call to check
|
||||
* @protocol: The protocol used for this call
|
||||
* @origin_id: The id of the origin which received the call
|
||||
* @timeout_msec: How long to wait for a decision before timing out. Set to 0 to avoid timing out.
|
||||
* @callback: The #GAsyncReadyCallback to call once a decision has been reached
|
||||
* @user_data: The user data for the @callback
|
||||
*
|
||||
* Ask the policy engine to come to a policy decision.
|
||||
*/
|
||||
void
|
||||
calls_policy_engine_decide (CallsPolicyEngine *self,
|
||||
const char *id,
|
||||
const char *protocol,
|
||||
const char *origin_id,
|
||||
guint timeout_msec,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
CallsPolicyEngineInterface *iface = CALLS_POLICY_ENGINE_GET_IFACE (self);
|
||||
GTask *task;
|
||||
PolicyTaskData *task_data;
|
||||
|
||||
g_return_if_fail (CALLS_IS_POLICY_ENGINE (self));
|
||||
g_return_if_fail (!STR_IS_NULL_OR_EMPTY (id));
|
||||
g_return_if_fail (iface->decide != NULL);
|
||||
|
||||
task_data = g_new0 (PolicyTaskData, 1);
|
||||
task_data->cancel = g_cancellable_new ();
|
||||
|
||||
if (timeout_msec > 0) {
|
||||
#if GLIB_CHECK_VERSION (2, 74,0)
|
||||
/** This raises a deprecation warning (on 2.74.6 ?!):
|
||||
* ‘g_timeout_add_once’ is deprecated: Not available before 2.74 [-Wdeprecated-declarations]
|
||||
*/
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
task_data->timeout_id =
|
||||
g_timeout_add_once (timeout_msec, (GSourceOnceFunc) g_cancellable_cancel, task_data->cancel);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
#else
|
||||
task_data->timeout_id = g_timeout_add (timeout_msec, G_SOURCE_FUNC (on_cancel_task), task_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
task = g_task_new (self, task_data->cancel, callback, user_data);
|
||||
g_task_set_task_data (task, task_data, (GDestroyNotify) policy_task_data_free);
|
||||
|
||||
iface->decide (self,
|
||||
id,
|
||||
protocol,
|
||||
origin_id,
|
||||
task);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* calls_policy_decision_new:
|
||||
* @decision: A #CallsPolicyDecision
|
||||
* @params: (optional): A #GVariant dictionary of parameters
|
||||
*
|
||||
* Returns: (nullable) (transfer full): A helper function to build the GVariant
|
||||
* as expected to be returned by implementations of #CallsPolicyEngine.
|
||||
* The GVariant is of type @CALLS_POLICY_VARIANT_FORMAT with the first
|
||||
* argument being @decision optionally followed by a parameter dictionary
|
||||
* as given by @params.
|
||||
*
|
||||
* Assumes ownership of @params, if given.
|
||||
*
|
||||
* Returns %NULL if @decision is not a member of the #CallsPolicyDecision enum.
|
||||
*/
|
||||
GVariant *
|
||||
calls_policy_decision_new (CallsPolicyDecision decision,
|
||||
GVariant *params)
|
||||
{
|
||||
g_autoptr (GEnumClass) enum_class = g_type_class_ref (CALLS_TYPE_POLICY_DECISION);
|
||||
|
||||
if (!g_enum_get_value (enum_class, decision))
|
||||
return NULL;
|
||||
|
||||
if (params)
|
||||
return g_variant_new (CALLS_POLICY_DECISION_FORMAT_CONSUME_DICT, decision, params);
|
||||
else
|
||||
return g_variant_new (CALLS_POLICY_DECISION_FORMAT, decision, NULL);
|
||||
}
|
91
src/calls-policy-engine.h
Normal file
91
src/calls-policy-engine.h
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Purism SPC
|
||||
*
|
||||
* This file is part of Calls.
|
||||
*
|
||||
* Calls 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Calls 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "enum-types.h"
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CALLS_POLICY_DECISION_FORMAT "(ia{sv})"
|
||||
#define CALLS_POLICY_DECISION_FORMAT_CONSUME_DICT "(i@a{sv})"
|
||||
|
||||
/**
|
||||
* CallsPolicyDecision:
|
||||
* all unknown values should be treated as @CALLS_POLICY_DECISION_PASS
|
||||
* @CALLS_POLICY_DECISION_INTERNAL_ERROR: An error occurred
|
||||
* @CALLS_POLICY_DECISION_PASS: Allow call
|
||||
* @CALLS_POLICY_DECISION_SMS: Send a predefined SMS (not implemented)
|
||||
* @CALLS_POLICY_DECISION_SILENCE: Set ringing to silent
|
||||
* @CALLS_POLICY_DECISION_REJECT: Reject (hang up) the call
|
||||
* @CALLS_POLICY_DECISION_IGNORE: Ignore the call (don't hang up)
|
||||
* @CALLS_POLICY_DECISION_REDIRECT: Redirect to a different number
|
||||
* @CALLS_POLICY_DECISION_REJECT: Reject the call
|
||||
* @CALLS_POLICY_DECISION_FORCE_ALLOW: Allow
|
||||
*/
|
||||
typedef enum {
|
||||
CALLS_POLICY_DECISION_INTERNAL_ERROR = -1,
|
||||
CALLS_POLICY_DECISION_PASS = 0,
|
||||
CALLS_POLICY_DECISION_SMS,
|
||||
CALLS_POLICY_DECISION_SILENCE,
|
||||
CALLS_POLICY_DECISION_REJECT = 16,
|
||||
CALLS_POLICY_DECISION_IGNORE = 32,
|
||||
CALLS_POLICY_DECISION_REDIRECT = 48,
|
||||
CALLS_POLICY_DECISION_FORCE_ALLOW = 128,
|
||||
} CallsPolicyDecision;
|
||||
|
||||
#define CALLS_TYPE_POLICY_ENGINE (calls_policy_engine_get_type ())
|
||||
|
||||
G_DECLARE_INTERFACE (CallsPolicyEngine, calls_policy_engine, CALLS, POLICY_ENGINE, GObject)
|
||||
|
||||
struct _CallsPolicyEngineInterface {
|
||||
GTypeInterface parent_iface;
|
||||
|
||||
void (*decide) (CallsPolicyEngine *self,
|
||||
const char *id,
|
||||
const char *protocol,
|
||||
const char *origin_id,
|
||||
GTask *task);
|
||||
};
|
||||
|
||||
|
||||
GVariant *calls_policy_engine_decide_finish (CallsPolicyEngine *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
void calls_policy_engine_decide (CallsPolicyEngine *self,
|
||||
const char *id,
|
||||
const char *protocol,
|
||||
const char *origin_id,
|
||||
guint timeout_msec,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
gboolean calls_policy_decision_is_valid (GVariant *decision,
|
||||
GError **error);
|
||||
GVariant *calls_policy_decision_new (CallsPolicyDecision decision,
|
||||
GVariant *params);
|
||||
|
||||
G_END_DECLS
|
225
src/calls-policy-manager.c
Normal file
225
src/calls-policy-manager.c
Normal file
|
@ -0,0 +1,225 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Purism SPC
|
||||
*
|
||||
* This file is part of Calls.
|
||||
*
|
||||
* Calls 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Calls 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "CallsPolicyManager"
|
||||
|
||||
#include "calls-policy-engine.h"
|
||||
#include "calls-policy-manager.h"
|
||||
|
||||
/**
|
||||
* SECTION:calls-policy-manager
|
||||
* @short_description: Manages call policy backends
|
||||
* @Title: CallsPolicyManager
|
||||
*
|
||||
* Queries managed policy engines for their individual #CallsPolicyDecision
|
||||
* and forms a final decision.
|
||||
*/
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_ENGINES,
|
||||
PROP_LAST_PROP
|
||||
};
|
||||
|
||||
static GParamSpec *props[PROP_LAST_PROP];
|
||||
|
||||
struct _CallsPolicyManager {
|
||||
GObject parent_instance;
|
||||
|
||||
GListModel *engines;
|
||||
GCancellable *cancel;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (CallsPolicyManager, calls_policy_manager, G_TYPE_OBJECT)
|
||||
|
||||
|
||||
typedef struct {
|
||||
char *id;
|
||||
GVariant *decision;
|
||||
guint n_decisions;
|
||||
GAsyncReadyCallback callback;
|
||||
gpointer user_data;
|
||||
} DecisionAggregationData;
|
||||
|
||||
|
||||
static void
|
||||
aggregate_decision (DecisionAggregationData *data,
|
||||
GVariant *new_decision)
|
||||
{
|
||||
g_autoptr (GError) error = NULL;
|
||||
|
||||
g_assert (data);
|
||||
|
||||
data->n_decisions++;
|
||||
|
||||
if (!calls_policy_decision_is_valid (new_decision, &error)) {
|
||||
g_warning ("Invalid policy decision: %s", error->message);
|
||||
|
||||
if (new_decision)
|
||||
g_variant_unref (new_decision);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!data->decision) {
|
||||
data->decision = new_decision;
|
||||
} else {
|
||||
CallsPolicyDecision new_decision_type;
|
||||
CallsPolicyDecision old_decision_type;
|
||||
|
||||
g_variant_get (new_decision, CALLS_POLICY_DECISION_FORMAT, &new_decision_type, NULL);
|
||||
g_variant_get (data->decision, CALLS_POLICY_DECISION_FORMAT, &old_decision_type, NULL);
|
||||
|
||||
if (new_decision_type > old_decision_type) {
|
||||
g_variant_unref (data->decision);
|
||||
data->decision = new_decision;
|
||||
} else {
|
||||
g_variant_unref (new_decision);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_decision_ready (GObject *object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_policy_manager_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
CallsPolicyManager *self = CALLS_POLICY_MANAGER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_ENGINES:
|
||||
self->engines = g_value_dup_object (value);
|
||||
g_assert (g_list_model_get_item_type (self->engines) == CALLS_TYPE_POLICY_ENGINE);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_policy_manager_dispose (GObject *object)
|
||||
{
|
||||
CallsPolicyManager *self = CALLS_POLICY_MANAGER (object);
|
||||
|
||||
g_clear_object (&self->engines);
|
||||
g_clear_object (&self->cancel);
|
||||
|
||||
G_OBJECT_CLASS (calls_policy_manager_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_policy_manager_class_init (CallsPolicyManagerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = calls_policy_manager_set_property;
|
||||
object_class->dispose = calls_policy_manager_dispose;
|
||||
|
||||
/**
|
||||
* CallsPolicyManager:engines:
|
||||
*
|
||||
* A #GListModel of [type@CALLS_POLICY_ENGINE]s which get queried
|
||||
* by @calls_policy_manager_decide
|
||||
*/
|
||||
props[PROP_ENGINES] =
|
||||
g_param_spec_object ("engines",
|
||||
"",
|
||||
"",
|
||||
G_TYPE_LIST_MODEL,
|
||||
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
calls_policy_manager_init (CallsPolicyManager *self)
|
||||
{
|
||||
self->cancel = g_cancellable_new ();
|
||||
}
|
||||
|
||||
|
||||
CallsPolicyManager *
|
||||
calls_policy_manager_new (void)
|
||||
{
|
||||
return g_object_new (CALLS_TYPE_POLICY_MANAGER, NULL);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
calls_policy_manager_decide (CallsPolicyManager *self,
|
||||
const char *id,
|
||||
const char *protocol,
|
||||
const char *origin_id,
|
||||
guint timeout_msec,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
DecisionAggregationData *data;
|
||||
guint n_engines;
|
||||
|
||||
g_return_if_fail (CALLS_IS_POLICY_MANAGER (self));
|
||||
|
||||
n_engines = g_list_model_get_n_items (self->engines);
|
||||
if (n_engines == 0) {
|
||||
GVariant *decision = calls_policy_decision_new (CALLS_POLICY_DECISION_PASS, NULL);
|
||||
task = g_task_new (self, self->cancel, callback, user_data);
|
||||
g_task_return_pointer (task, decision, (GDestroyNotify) g_variant_unref);
|
||||
return;
|
||||
}
|
||||
|
||||
data = g_new0 (DecisionAggregationData, 1);
|
||||
data->id = g_strdup (id);
|
||||
data->callback = callback;
|
||||
data->user_data = user_data;
|
||||
|
||||
for (guint i = 0; i < n_engines; i++) {
|
||||
g_autoptr (CallsPolicyEngine) engine = g_list_model_get_item (self->engines, i);
|
||||
|
||||
calls_policy_engine_decide (engine, id, protocol, origin_id, timeout_msec, on_decision_ready, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
GVariant *
|
||||
calls_policy_manager_decide_finish (CallsPolicyManager *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return NULL;
|
||||
}
|
47
src/calls-policy-manager.h
Normal file
47
src/calls-policy-manager.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (C) 2023 Purism SPC
|
||||
*
|
||||
* This file is part of Calls.
|
||||
*
|
||||
* Calls 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 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Calls 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Calls. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Evangelos Ribeiro Tzaras <devrtz@fortysixandtwo.eu>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define CALLS_TYPE_POLICY_MANAGER calls_policy_manager_get_type ()
|
||||
|
||||
G_DECLARE_FINAL_TYPE (CallsPolicyManager, calls_policy_manager, CALLS, POLICY_MANAGER, GObject);
|
||||
|
||||
CallsPolicyManager *calls_policy_manager_new (void);
|
||||
void calls_policy_manager_decide (CallsPolicyManager *self,
|
||||
const char *id,
|
||||
const char *protocol,
|
||||
const char *origin_id,
|
||||
guint timeout_msec,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GVariant *calls_policy_manager_decide_finish (CallsPolicyManager *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
|
@ -66,8 +66,10 @@ calls_enum_headers = files(
|
|||
'calls-account.h',
|
||||
'calls-call.h',
|
||||
'calls-manager.h',
|
||||
'calls-policy-engine.h',
|
||||
'calls-ringer.h',
|
||||
'calls-ussd.h',
|
||||
'calls-extension.h',
|
||||
]
|
||||
)
|
||||
calls_enum_sources = gnome.mkenums_simple('enum-types',
|
||||
|
@ -104,6 +106,7 @@ calls_sources = files([
|
|||
'calls-dbus-manager.c', 'calls-dbus-manager.h',
|
||||
'calls-emergency-calls-manager.c', 'calls-emergency-calls-manager.h',
|
||||
'calls-emergency-call-types.c', 'calls-emergency-call-types.h',
|
||||
'calls-extension.c', 'calls-extension.h',
|
||||
'calls-history-box.c', 'calls-history-box.h',
|
||||
'calls-in-app-notification.c', 'calls-in-app-notification.h',
|
||||
'calls-log.c', 'calls-log.h',
|
||||
|
@ -116,6 +119,8 @@ calls_sources = files([
|
|||
'calls-origin.c', 'calls-origin.h',
|
||||
'calls-plugin.c', 'calls-plugin.h',
|
||||
'calls-plugin-manager.c', 'calls-plugin-manager.h',
|
||||
'calls-policy-engine.c', 'calls-policy-engine.h',
|
||||
'calls-policy-manager.c', 'calls-policy-manager.h',
|
||||
'calls-provider.c', 'calls-provider.h',
|
||||
'calls-record-store.c', 'calls-record-store.h',
|
||||
'calls-ringer.c', 'calls-ringer.h',
|
||||
|
|
Loading…
Reference in a new issue