Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : *
3 : : * Copyright 2024 GNOME Foundation, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General Public
18 : : * License along with this library; if not, write to the Free Software
19 : : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 : : *
21 : : * Authors:
22 : : * - Philip Withnall <pwithnall@gnome.org>
23 : : */
24 : :
25 : : #include "config.h"
26 : :
27 : : #include <glib.h>
28 : : #include <glib-object.h>
29 : : #include <glib-unix.h>
30 : : #include <glib/gi18n-lib.h>
31 : : #include <gio/gio.h>
32 : : #include <locale.h>
33 : : #include <libgsystemservice/service.h>
34 : : #include <libmalcontent-timer/extension-agent-object.h>
35 : : #include <libmalcontent-timer/extension-agent-object-polkit.h>
36 : : #include <libmalcontent-timer/extension-agent-service.h>
37 : :
38 : :
39 : : static void mct_extension_agent_service_dispose (GObject *object);
40 : :
41 : : static void mct_extension_agent_service_startup_async (GssService *service,
42 : : GCancellable *cancellable,
43 : : GAsyncReadyCallback callback,
44 : : gpointer user_data);
45 : : static void mct_extension_agent_service_startup_finish (GssService *service,
46 : : GAsyncResult *result,
47 : : GError **error);
48 : : static void mct_extension_agent_service_shutdown (GssService *service);
49 : :
50 : : static void notify_busy_cb (GObject *obj,
51 : : GParamSpec *pspec,
52 : : gpointer user_data);
53 : :
54 : : /**
55 : : * MctExtensionAgentService:
56 : : *
57 : : * The core implementation of the extension agent daemon, which exposes its
58 : : * D-Bus API on the bus.
59 : : *
60 : : * Since: 0.14.0
61 : : */
62 : : struct _MctExtensionAgentService
63 : : {
64 : : GssService parent;
65 : :
66 : : MctExtensionAgentObject *extension_agent_object; /* (owned) */
67 : : unsigned long extension_agent_object_notify_busy_id;
68 : :
69 : : gboolean busy;
70 : : };
71 : :
72 [ + + + - : 9 : G_DEFINE_TYPE (MctExtensionAgentService, mct_extension_agent_service, GSS_TYPE_SERVICE)
+ + ]
73 : :
74 : : static void
75 : 1 : mct_extension_agent_service_class_init (MctExtensionAgentServiceClass *klass)
76 : : {
77 : 1 : GObjectClass *object_class = (GObjectClass *) klass;
78 : 1 : GssServiceClass *service_class = (GssServiceClass *) klass;
79 : :
80 : 1 : object_class->dispose = mct_extension_agent_service_dispose;
81 : :
82 : 1 : service_class->startup_async = mct_extension_agent_service_startup_async;
83 : 1 : service_class->startup_finish = mct_extension_agent_service_startup_finish;
84 : 1 : service_class->shutdown = mct_extension_agent_service_shutdown;
85 : 1 : }
86 : :
87 : : static void
88 : 1 : mct_extension_agent_service_init (MctExtensionAgentService *self)
89 : : {
90 : 1 : }
91 : :
92 : : static void
93 : 1 : mct_extension_agent_service_dispose (GObject *object)
94 : : {
95 : 1 : MctExtensionAgentService *self = MCT_EXTENSION_AGENT_SERVICE (object);
96 : :
97 [ + - ]: 1 : g_clear_signal_handler (&self->extension_agent_object_notify_busy_id, self->extension_agent_object);
98 [ + - ]: 1 : g_clear_object (&self->extension_agent_object);
99 : :
100 : : /* Chain up to the parent class */
101 : 1 : G_OBJECT_CLASS (mct_extension_agent_service_parent_class)->dispose (object);
102 : 1 : }
103 : :
104 : : static void
105 : 1 : mct_extension_agent_service_startup_async (GssService *service,
106 : : GCancellable *cancellable,
107 : : GAsyncReadyCallback callback,
108 : : gpointer user_data)
109 : : {
110 : 1 : MctExtensionAgentService *self = MCT_EXTENSION_AGENT_SERVICE (service);
111 : 1 : GDBusConnection *connection = gss_service_get_dbus_connection (GSS_SERVICE (self));
112 : 1 : g_autoptr(GTask) task = NULL;
113 : 1 : g_autoptr(GError) local_error = NULL;
114 : :
115 : 1 : task = g_task_new (service, cancellable, callback, user_data);
116 [ + - ]: 1 : g_task_set_source_tag (task, mct_extension_agent_service_startup_async);
117 : :
118 : : /* For now we hardcode the polkit-based extension agent D-Bus object. If people
119 : : * are to provide other implementations of the agent in future, this could be
120 : : * refactored so the MctExtensionAgentService code is easier to reuse and only
121 : : * the MctExtensionAgentObject needs to be custom. */
122 : 1 : self->extension_agent_object =
123 : 1 : MCT_EXTENSION_AGENT_OBJECT (mct_extension_agent_object_polkit_new (connection,
124 : : "/org/freedesktop/MalcontentTimer1/ExtensionAgent"));
125 : 1 : self->extension_agent_object_notify_busy_id =
126 : 1 : g_signal_connect (self->extension_agent_object, "notify::busy",
127 : : (GCallback) notify_busy_cb, self);
128 : :
129 : 1 : notify_busy_cb (NULL, NULL, self);
130 : :
131 [ - + ]: 1 : if (!mct_extension_agent_object_register (self->extension_agent_object, &local_error))
132 : 0 : g_task_return_error (task, g_steal_pointer (&local_error));
133 : : else
134 : 1 : g_task_return_boolean (task, TRUE);
135 : 1 : }
136 : :
137 : : static void
138 : 1 : mct_extension_agent_service_startup_finish (GssService *service,
139 : : GAsyncResult *result,
140 : : GError **error)
141 : : {
142 : 1 : g_task_propagate_boolean (G_TASK (result), error);
143 : 1 : }
144 : :
145 : : static void
146 : 3 : notify_busy_cb (GObject *obj,
147 : : GParamSpec *pspec,
148 : : gpointer user_data)
149 : : {
150 : 3 : MctExtensionAgentService *self = MCT_EXTENSION_AGENT_SERVICE (user_data);
151 : :
152 : 3 : gboolean was_busy = self->busy;
153 : 3 : gboolean now_busy = mct_extension_agent_object_get_busy (self->extension_agent_object);
154 : :
155 [ - + - + ]: 3 : g_debug ("%s: was_busy: %s, now_busy: %s",
156 : : G_STRFUNC,
157 : : was_busy ? "yes" : "no",
158 : : now_busy ? "yes" : "no");
159 : :
160 [ - + - - ]: 3 : if (was_busy && !now_busy)
161 : 0 : gss_service_release (GSS_SERVICE (self));
162 [ + - - + ]: 3 : else if (!was_busy && now_busy)
163 : 0 : gss_service_hold (GSS_SERVICE (self));
164 : :
165 : 3 : self->busy = now_busy;
166 : 3 : }
167 : :
168 : : static void
169 : 1 : mct_extension_agent_service_shutdown (GssService *service)
170 : : {
171 : 1 : MctExtensionAgentService *self = MCT_EXTENSION_AGENT_SERVICE (service);
172 : :
173 : 1 : mct_extension_agent_object_unregister (self->extension_agent_object);
174 : 1 : }
175 : :
176 : : /**
177 : : * mct_extension_agent_service_new:
178 : : *
179 : : * Create a new [class@Malcontent.ExtensionAgentService].
180 : : *
181 : : * Returns: (transfer full): a new [class@Malcontent.ExtensionAgentService]
182 : : * Since: 0.14.0
183 : : */
184 : : MctExtensionAgentService *
185 : 1 : mct_extension_agent_service_new (void)
186 : : {
187 : 1 : return g_object_new (MCT_TYPE_EXTENSION_AGENT_SERVICE,
188 : : "bus-type", G_BUS_TYPE_SYSTEM,
189 : : "service-id", "org.freedesktop.MalcontentTimer1.ExtensionAgent",
190 : : "inactivity-timeout", 30000 /* ms */,
191 : : "translation-domain", GETTEXT_PACKAGE,
192 : 1 : "parameter-string", _("— decide on screen time limit extension requests for parental controls"),
193 : 1 : "summary", _("Decide whether to grant extension "
194 : : "requests from accounts which have screen "
195 : : "time limits set as part of parental "
196 : : "controls."),
197 : : NULL);
198 : : }
199 : :
|