Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
2 : : *
3 : : * Copyright © 2019 Endless Mobile, 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 <withnall@endlessm.com>
23 : : */
24 : :
25 : : #include "config.h"
26 : :
27 : : #include <glib.h>
28 : : #include <glib-object.h>
29 : : #include <glib/gi18n-lib.h>
30 : : #include <gio/gio.h>
31 : : #include <libmalcontent/app-filter.h>
32 : : #include <libmalcontent/manager.h>
33 : : #include <libmalcontent/session-limits.h>
34 : : #include <libmalcontent/web-filter.h>
35 : :
36 : : #include "libmalcontent/app-filter-private.h"
37 : : #include "libmalcontent/session-limits-private.h"
38 : : #include "libmalcontent/web-filter-private.h"
39 : :
40 : :
41 : : /**
42 : : * mct_manager_error_quark:
43 : : *
44 : : * Error quark for [error@Malcontent.ManagerError].
45 : : *
46 : : * Returns: identifier for error domain
47 : : * Since: 0.5.0
48 : : */
49 [ + + ]: 72 : G_DEFINE_QUARK (MctManagerError, mct_manager_error)
50 : :
51 : : /**
52 : : * MctManager:
53 : : *
54 : : * #MctManager is a top-level management object which is used to query and
55 : : * monitor #MctAppFilters for different users.
56 : : *
57 : : * Since: 0.3.0
58 : : */
59 : : struct _MctManager
60 : : {
61 : : GObject parent_instance;
62 : :
63 : : GDBusConnection *connection; /* (owned) */
64 : : unsigned int user_properties_changed_old_id;
65 : : unsigned int user_properties_changed_id;
66 : : };
67 : :
68 [ + + + - : 283 : G_DEFINE_TYPE (MctManager, mct_manager, G_TYPE_OBJECT)
+ + ]
69 : :
70 : : typedef enum
71 : : {
72 : : PROP_CONNECTION = 1,
73 : : } MctManagerProperty;
74 : :
75 : : static GParamSpec *props[PROP_CONNECTION + 1] = { NULL, };
76 : :
77 : : typedef enum
78 : : {
79 : : SIGNAL_APP_FILTER_CHANGED,
80 : : SIGNAL_SESSION_LIMITS_CHANGED,
81 : : SIGNAL_WEB_FILTER_CHANGED,
82 : : } MctManagerSignal;
83 : :
84 : : static unsigned int signals[SIGNAL_WEB_FILTER_CHANGED + 1] = { 0, };
85 : :
86 : : static void
87 : 37 : mct_manager_init (MctManager *self)
88 : : {
89 : : /* Nothing to do here. */
90 : 37 : }
91 : :
92 : : static void
93 : 0 : mct_manager_get_property (GObject *object,
94 : : guint property_id,
95 : : GValue *value,
96 : : GParamSpec *spec)
97 : : {
98 : 0 : MctManager *self = MCT_MANAGER (object);
99 : :
100 [ # # ]: 0 : switch ((MctManagerProperty) property_id)
101 : : {
102 : 0 : case PROP_CONNECTION:
103 : 0 : g_value_set_object (value, self->connection);
104 : 0 : break;
105 : :
106 : 0 : default:
107 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
108 : 0 : break;
109 : : }
110 : 0 : }
111 : :
112 : : static void
113 : 37 : mct_manager_set_property (GObject *object,
114 : : guint property_id,
115 : : const GValue *value,
116 : : GParamSpec *spec)
117 : : {
118 : 37 : MctManager *self = MCT_MANAGER (object);
119 : :
120 [ + - ]: 37 : switch ((MctManagerProperty) property_id)
121 : : {
122 : 37 : case PROP_CONNECTION:
123 : : /* Construct-only. May not be %NULL. */
124 : 37 : g_assert (self->connection == NULL);
125 : 37 : self->connection = g_value_dup_object (value);
126 : 37 : g_assert (self->connection != NULL);
127 : 37 : break;
128 : :
129 : 0 : default:
130 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
131 : 0 : break;
132 : : }
133 : 37 : }
134 : :
135 : : static void _mct_manager_user_properties_changed_cb (GDBusConnection *connection,
136 : : const char *sender_name,
137 : : const char *object_path,
138 : : const char *interface_name,
139 : : const char *signal_name,
140 : : GVariant *parameters,
141 : : void *user_data);
142 : :
143 : : static void
144 : 37 : mct_manager_constructed (GObject *object)
145 : : {
146 : 37 : MctManager *self = MCT_MANAGER (object);
147 : :
148 : : /* Chain up. */
149 : 37 : G_OBJECT_CLASS (mct_manager_parent_class)->constructed (object);
150 : :
151 : : /* Connect to notifications from AccountsService. */
152 : 37 : g_assert (self->connection != NULL);
153 : 37 : self->user_properties_changed_old_id =
154 : 37 : g_dbus_connection_signal_subscribe (self->connection,
155 : : "org.freedesktop.Accounts", /* sender */
156 : : "org.freedesktop.DBus.Properties", /* interface name */
157 : : "PropertiesChanged", /* signal name */
158 : : NULL, /* object path */
159 : : "com.endlessm.ParentalControls", /* arg0 namespace prefix */
160 : : G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE,
161 : : _mct_manager_user_properties_changed_cb,
162 : : self, NULL);
163 : 37 : self->user_properties_changed_id =
164 : 37 : g_dbus_connection_signal_subscribe (self->connection,
165 : : "org.freedesktop.Accounts", /* sender */
166 : : "org.freedesktop.DBus.Properties", /* interface name */
167 : : "PropertiesChanged", /* signal name */
168 : : NULL, /* object path */
169 : : "org.freedesktop.Malcontent", /* arg0 namespace prefix */
170 : : G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE,
171 : : _mct_manager_user_properties_changed_cb,
172 : : self, NULL);
173 : 37 : }
174 : :
175 : : static void
176 : 35 : mct_manager_dispose (GObject *object)
177 : : {
178 : 35 : MctManager *self = MCT_MANAGER (object);
179 : :
180 [ + - + - ]: 35 : if (self->user_properties_changed_id != 0 && self->connection != NULL)
181 : 35 : g_dbus_connection_signal_unsubscribe (self->connection,
182 : : g_steal_handle_id (&self->user_properties_changed_id));
183 [ + - + - ]: 35 : if (self->user_properties_changed_old_id != 0 && self->connection != NULL)
184 : 35 : g_dbus_connection_signal_unsubscribe (self->connection,
185 : : g_steal_handle_id (&self->user_properties_changed_old_id));
186 [ + - ]: 35 : g_clear_object (&self->connection);
187 : :
188 : 35 : G_OBJECT_CLASS (mct_manager_parent_class)->dispose (object);
189 : 35 : }
190 : :
191 : : static void
192 : 5 : mct_manager_class_init (MctManagerClass *klass)
193 : : {
194 : 5 : GObjectClass *object_class = G_OBJECT_CLASS (klass);
195 : :
196 : 5 : object_class->constructed = mct_manager_constructed;
197 : 5 : object_class->dispose = mct_manager_dispose;
198 : 5 : object_class->get_property = mct_manager_get_property;
199 : 5 : object_class->set_property = mct_manager_set_property;
200 : :
201 : : /**
202 : : * MctManager:connection: (not nullable)
203 : : *
204 : : * A connection to the system bus, where accounts-service runs. It’s provided
205 : : * mostly for testing purposes, or to allow an existing connection to be
206 : : * re-used.
207 : : *
208 : : * Since: 0.3.0
209 : : */
210 : 5 : props[PROP_CONNECTION] = g_param_spec_object ("connection", NULL, NULL,
211 : : G_TYPE_DBUS_CONNECTION,
212 : : G_PARAM_READWRITE |
213 : : G_PARAM_CONSTRUCT_ONLY |
214 : : G_PARAM_STATIC_STRINGS);
215 : :
216 : 5 : g_object_class_install_properties (object_class,
217 : : G_N_ELEMENTS (props),
218 : : props);
219 : :
220 : : /**
221 : : * MctManager::app-filter-changed:
222 : : * @self: a #MctManager
223 : : * @user_id: UID of the user whose app filter has changed
224 : : *
225 : : * Emitted when the app filter stored for a user changes.
226 : : * The new app filter for the user should be requested again from
227 : : * the #MctManager instance.
228 : : *
229 : : * Since: 0.3.0
230 : : */
231 : 5 : signals[SIGNAL_APP_FILTER_CHANGED] =
232 : 5 : g_signal_new ("app-filter-changed", G_TYPE_FROM_CLASS (klass),
233 : : G_SIGNAL_RUN_LAST,
234 : : 0, NULL, NULL, NULL,
235 : : G_TYPE_NONE, 1,
236 : : G_TYPE_UINT64);
237 : :
238 : : /**
239 : : * MctManager::session-limits-changed:
240 : : * @self: a policy manager
241 : : * @user_id: UID of the user whose session limits have changed
242 : : *
243 : : * Emitted when the session limits stored for a user change.
244 : : *
245 : : * The new session limits for the user should be requested again from
246 : : * the [class@Malcontent.Manager] instance.
247 : : *
248 : : * Since: 0.14.0
249 : : */
250 : 5 : signals[SIGNAL_SESSION_LIMITS_CHANGED] =
251 : 5 : g_signal_new ("session-limits-changed", G_TYPE_FROM_CLASS (klass),
252 : : G_SIGNAL_RUN_LAST,
253 : : 0, NULL, NULL, NULL,
254 : : G_TYPE_NONE, 1,
255 : : G_TYPE_UINT64);
256 : :
257 : : /**
258 : : * MctManager::web-filter-changed:
259 : : * @self: a policy manager
260 : : * @user_id: UID of the user whose web filter has changed
261 : : *
262 : : * Emitted when the web filter stored for a user changes.
263 : : *
264 : : * The new web filter for the user should be requested again from
265 : : * the [class@Malcontent.Manager] instance.
266 : : *
267 : : * Since: 0.14.0
268 : : */
269 : 5 : signals[SIGNAL_WEB_FILTER_CHANGED] =
270 : 5 : g_signal_new ("web-filter-changed", G_TYPE_FROM_CLASS (klass),
271 : : G_SIGNAL_RUN_LAST,
272 : : 0, NULL, NULL, NULL,
273 : : G_TYPE_NONE, 1,
274 : : G_TYPE_UINT64);
275 : 5 : }
276 : :
277 : : /**
278 : : * mct_manager_new:
279 : : * @connection: (transfer none): a #GDBusConnection to use
280 : : *
281 : : * Create a new #MctManager.
282 : : *
283 : : * Returns: (transfer full): a new #MctManager
284 : : * Since: 0.3.0
285 : : */
286 : : MctManager *
287 : 37 : mct_manager_new (GDBusConnection *connection)
288 : : {
289 : 37 : g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
290 : :
291 : 37 : return g_object_new (MCT_TYPE_MANAGER,
292 : : "connection", connection,
293 : : NULL);
294 : : }
295 : :
296 : : static void
297 : 0 : _mct_manager_user_properties_changed_cb (GDBusConnection *connection,
298 : : const char *sender_name,
299 : : const char *object_path,
300 : : const char *interface_name,
301 : : const char *signal_name,
302 : : GVariant *parameters,
303 : : void *user_data)
304 : : {
305 : 0 : MctManager *manager = MCT_MANAGER (user_data);
306 [ # # ]: 0 : g_autoptr(GError) local_error = NULL;
307 : : const gchar *uid_str;
308 : : guint64 uid;
309 : : const char *properties_interface_name;
310 : :
311 : 0 : g_assert (g_str_equal (interface_name, "org.freedesktop.DBus.Properties"));
312 : 0 : g_assert (g_str_equal (signal_name, "PropertiesChanged"));
313 : :
314 : : /* Extract the UID from the object path. This is a bit hacky, but probably
315 : : * better than depending on libaccountsservice just for this. */
316 [ # # # # : 0 : if (!g_str_has_prefix (object_path, "/org/freedesktop/Accounts/User"))
# # # # ]
317 : 0 : return;
318 : :
319 : 0 : uid_str = object_path + strlen ("/org/freedesktop/Accounts/User");
320 [ # # ]: 0 : if (!g_ascii_string_to_unsigned (uid_str, 10, 0, G_MAXUINT64, &uid, &local_error))
321 : : {
322 : 0 : g_warning ("Error converting object path ‘%s’ to user ID: %s",
323 : : object_path, local_error->message);
324 : 0 : g_clear_error (&local_error);
325 : 0 : return;
326 : : }
327 : :
328 [ # # ]: 0 : if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sa{sv}as)")))
329 : : {
330 : 0 : g_warning ("Unexpected PropertiesChanged parameter type ‘%s’",
331 : : g_variant_get_type_string (parameters));
332 : 0 : return;
333 : : }
334 : :
335 : 0 : g_variant_get (parameters, "(&sa{sv}as)", &properties_interface_name, NULL, NULL);
336 : :
337 [ # # ]: 0 : if (g_str_equal (properties_interface_name, "com.endlessm.ParentalControls.AppFilter"))
338 : 0 : g_signal_emit (manager, signals[SIGNAL_APP_FILTER_CHANGED], 0, uid);
339 [ # # ]: 0 : else if (g_str_equal (properties_interface_name, "com.endlessm.ParentalControls.SessionLimits"))
340 : 0 : g_signal_emit (manager, signals[SIGNAL_SESSION_LIMITS_CHANGED], 0, uid);
341 [ # # ]: 0 : else if (g_str_equal (properties_interface_name, "org.freedesktop.Malcontent.WebFilter"))
342 : 0 : g_signal_emit (manager, signals[SIGNAL_WEB_FILTER_CHANGED], 0, uid);
343 : : else
344 : 0 : g_debug ("PropertiesChanged on unknown interface ‘%s’, ignoring", properties_interface_name);
345 : : }
346 : :
347 : : /* Check if @error is a D-Bus remote error matching @expected_error_name. */
348 : : static gboolean
349 : 32 : bus_remote_error_matches (const GError *error,
350 : : const gchar *expected_error_name)
351 : : {
352 : 32 : g_autofree gchar *error_name = NULL;
353 : :
354 [ - + ]: 32 : if (!g_dbus_error_is_remote_error (error))
355 : 0 : return FALSE;
356 : :
357 : 32 : error_name = g_dbus_error_get_remote_error (error);
358 : :
359 : 32 : return g_str_equal (error_name, expected_error_name);
360 : : }
361 : :
362 : : /* Convert a #GDBusError into a #MctManagerError. */
363 : : static GError *
364 : 18 : bus_error_to_manager_error (const GError *bus_error,
365 : : uid_t user_id)
366 : : {
367 [ + - + + ]: 36 : if (g_error_matches (bus_error, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED) ||
368 : 18 : bus_remote_error_matches (bus_error, "org.freedesktop.Accounts.Error.PermissionDenied"))
369 : 4 : return g_error_new (MCT_MANAGER_ERROR, MCT_MANAGER_ERROR_PERMISSION_DENIED,
370 : : _("Not allowed to query parental controls data for user %u"),
371 : : (guint) user_id);
372 [ + - + + ]: 28 : else if (g_error_matches (bus_error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD) ||
373 : 14 : bus_remote_error_matches (bus_error, "org.freedesktop.Accounts.Error.Failed"))
374 : 4 : return g_error_new (MCT_MANAGER_ERROR, MCT_MANAGER_ERROR_INVALID_USER,
375 : : _("User %u does not exist"), (guint) user_id);
376 [ + - - + ]: 20 : else if (g_error_matches (bus_error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN) ||
377 : 10 : g_error_matches (bus_error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER))
378 : : /* If accountsservice is not available on the system bus, then the
379 : : * com.endlessm.ParentalControls.AppFilter extension interface
380 : : * certainly can't be available. */
381 : 0 : return g_error_new_literal (MCT_MANAGER_ERROR,
382 : : MCT_MANAGER_ERROR_DISABLED,
383 : : _("System accounts service not available"));
384 : : else
385 : 10 : return g_error_copy (bus_error);
386 : : }
387 : :
388 : : /* Find the object path for the given @user_id on the accountsservice D-Bus
389 : : * interface, by calling its FindUserById() method. This is a synchronous,
390 : : * blocking function. */
391 : : static gchar *
392 : 35 : accounts_find_user_by_id (GDBusConnection *connection,
393 : : uid_t user_id,
394 : : gboolean allow_interactive_authorization,
395 : : GCancellable *cancellable,
396 : : GError **error)
397 : : {
398 : 35 : g_autofree gchar *object_path = NULL;
399 : 35 : g_autoptr(GVariant) result_variant = NULL;
400 : 35 : g_autoptr(GError) local_error = NULL;
401 : :
402 : 35 : result_variant =
403 [ - + ]: 35 : g_dbus_connection_call_sync (connection,
404 : : "org.freedesktop.Accounts",
405 : : "/org/freedesktop/Accounts",
406 : : "org.freedesktop.Accounts",
407 : : "FindUserById",
408 : : g_variant_new ("(x)", (gint64) user_id),
409 : : G_VARIANT_TYPE ("(o)"),
410 : : allow_interactive_authorization
411 : : ? G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION
412 : : : G_DBUS_CALL_FLAGS_NONE,
413 : : -1, /* timeout, ms */
414 : : cancellable,
415 : : &local_error);
416 [ + + ]: 35 : if (local_error != NULL)
417 : : {
418 : 6 : g_autoptr(GError) app_filter_error = bus_error_to_manager_error (local_error,
419 : : user_id);
420 : 6 : g_propagate_error (error, g_steal_pointer (&app_filter_error));
421 : 6 : return NULL;
422 : : }
423 : :
424 : 29 : g_variant_get (result_variant, "(o)", &object_path);
425 : :
426 : 29 : return g_steal_pointer (&object_path);
427 : : }
428 : :
429 : : static GVariant *
430 : 19 : account_get_interface_properties (MctManager *self,
431 : : uid_t user_id,
432 : : const char *interface_name,
433 : : const char *canary_key,
434 : : const GVariantType *canary_type,
435 : : const char *disabled_error_message,
436 : : MctManagerGetValueFlags flags,
437 : : GCancellable *cancellable,
438 : : GError **error)
439 : : {
440 : 19 : g_autofree gchar *object_path = NULL;
441 : 19 : g_autoptr(GVariant) result_variant = NULL;
442 : 19 : g_autoptr(GVariant) properties = NULL;
443 : 19 : g_autoptr(GVariant) canary_value = NULL;
444 : 19 : g_autoptr(GError) local_error = NULL;
445 : :
446 : 19 : g_return_val_if_fail (MCT_IS_MANAGER (self), NULL);
447 : 19 : g_return_val_if_fail (interface_name != NULL, NULL);
448 : 19 : g_return_val_if_fail (canary_key != NULL, NULL);
449 : 19 : g_return_val_if_fail (canary_type != NULL, NULL);
450 : 19 : g_return_val_if_fail (disabled_error_message != NULL, NULL);
451 : 19 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
452 : 19 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
453 : :
454 : 38 : object_path = accounts_find_user_by_id (self->connection, user_id,
455 : 19 : (flags & MCT_MANAGER_GET_VALUE_FLAGS_INTERACTIVE),
456 : : cancellable, error);
457 [ + + ]: 19 : if (object_path == NULL)
458 : 4 : return NULL;
459 : :
460 : 15 : result_variant =
461 : 15 : g_dbus_connection_call_sync (self->connection,
462 : : "org.freedesktop.Accounts",
463 : : object_path,
464 : : "org.freedesktop.DBus.Properties",
465 : : "GetAll",
466 : : g_variant_new ("(s)", interface_name),
467 : : G_VARIANT_TYPE ("(a{sv})"),
468 : : (flags & MCT_MANAGER_GET_VALUE_FLAGS_INTERACTIVE)
469 : : ? G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION
470 : 15 : : G_DBUS_CALL_FLAGS_NONE,
471 : : -1, /* timeout, ms */
472 : : cancellable,
473 : : &local_error);
474 [ + + ]: 15 : if (local_error != NULL)
475 : : {
476 : 5 : g_autoptr(GError) manager_error = NULL;
477 : 5 : g_autofree char *remote_dbus_error = g_dbus_error_get_remote_error (local_error);
478 : :
479 [ + + + + ]: 8 : if (g_error_matches (local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS) ||
480 : 3 : g_strcmp0 (remote_dbus_error, "org.freedesktop.Accounts.User.UnknownInterface") == 0)
481 : : {
482 : : /* o.fd.D.GetAll() will return InvalidArgs errors if
483 : : * accountsservice doesn’t have the `interface_name`
484 : : * extension interface installed. */
485 : 3 : manager_error = g_error_new_literal (MCT_MANAGER_ERROR,
486 : : MCT_MANAGER_ERROR_DISABLED,
487 : : disabled_error_message);
488 : : }
489 : : else
490 : : {
491 : 2 : manager_error = bus_error_to_manager_error (local_error, user_id);
492 : : }
493 : :
494 : 5 : g_propagate_error (error, g_steal_pointer (&manager_error));
495 : 5 : return NULL;
496 : : }
497 : :
498 : : /* Extract the properties we care about. They may be silently omitted from the
499 : : * results if we don’t have permission to access them. */
500 : 10 : properties = g_variant_get_child_value (result_variant, 0);
501 : 10 : canary_value = g_variant_lookup_value (properties, canary_key, canary_type);
502 [ + + ]: 10 : if (canary_value == NULL)
503 : : {
504 : 2 : g_set_error (error, MCT_MANAGER_ERROR,
505 : : MCT_MANAGER_ERROR_PERMISSION_DENIED,
506 : : _("Not allowed to query parental controls data for user %u"),
507 : : (guint) user_id);
508 : 2 : return NULL;
509 : : }
510 : :
511 : 8 : return g_steal_pointer (&properties);
512 : : }
513 : :
514 : : static gboolean
515 : 16 : account_set_interface_properties (MctManager *self,
516 : : uid_t user_id,
517 : : const char *interface_name,
518 : : GVariant *properties_variant,
519 : : const char *final_key,
520 : : MctManagerSetValueFlags flags,
521 : : GCancellable *cancellable,
522 : : GError **error)
523 : : {
524 : 16 : g_autofree gchar *object_path = NULL;
525 : 16 : g_autoptr(GVariant) properties_value = NULL;
526 : 16 : const gchar *properties_key = NULL;
527 : : GVariantIter iter;
528 : 16 : g_autoptr(GVariant) final_key_variant = NULL;
529 : 16 : g_autoptr(GVariant) final_key_result_variant = NULL;
530 : 16 : g_autoptr(GError) local_error = NULL;
531 : :
532 : 16 : g_return_val_if_fail (MCT_IS_MANAGER (self), FALSE);
533 : 16 : g_return_val_if_fail (interface_name != NULL, FALSE);
534 : 16 : g_return_val_if_fail (properties_variant != NULL, FALSE);
535 : 16 : g_return_val_if_fail (final_key != NULL, FALSE);
536 : 16 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
537 : 16 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
538 : :
539 : 32 : object_path = accounts_find_user_by_id (self->connection, user_id,
540 : 16 : (flags & MCT_MANAGER_SET_VALUE_FLAGS_INTERACTIVE),
541 : : cancellable, error);
542 [ + + ]: 16 : if (object_path == NULL)
543 : 2 : return FALSE;
544 : :
545 : 14 : g_variant_iter_init (&iter, properties_variant);
546 [ + + ]: 42 : while (g_variant_iter_loop (&iter, "{&sv}", &properties_key, &properties_value))
547 : : {
548 [ + + + ]: 34 : g_autoptr(GVariant) result_variant = NULL;
549 : :
550 : : /* Change the ‘final key’ last. This is the key which will trigger an
551 : : * atomic update in clients. */
552 [ + + ]: 34 : if (g_str_equal (properties_key, final_key))
553 : : {
554 : 13 : final_key_variant = g_steal_pointer (&properties_value);
555 : 13 : continue;
556 : : }
557 : :
558 : 21 : result_variant =
559 : 21 : g_dbus_connection_call_sync (self->connection,
560 : : "org.freedesktop.Accounts",
561 : : object_path,
562 : : "org.freedesktop.DBus.Properties",
563 : : "Set",
564 : : g_variant_new ("(ssv)",
565 : : interface_name,
566 : : properties_key,
567 : : properties_value),
568 : : G_VARIANT_TYPE ("()"),
569 : : (flags & MCT_MANAGER_SET_VALUE_FLAGS_INTERACTIVE)
570 : : ? G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION
571 : 21 : : G_DBUS_CALL_FLAGS_NONE,
572 : : -1, /* timeout, ms */
573 : : cancellable,
574 : : &local_error);
575 [ + + ]: 21 : if (local_error != NULL)
576 : : {
577 : 6 : g_propagate_error (error, bus_error_to_manager_error (local_error, user_id));
578 : 6 : return FALSE;
579 : : }
580 : : }
581 : :
582 : 8 : final_key_result_variant =
583 : 8 : g_dbus_connection_call_sync (self->connection,
584 : : "org.freedesktop.Accounts",
585 : : object_path,
586 : : "org.freedesktop.DBus.Properties",
587 : : "Set",
588 : : g_variant_new ("(ssv)",
589 : : interface_name,
590 : : final_key,
591 : : final_key_variant),
592 : : G_VARIANT_TYPE ("()"),
593 : : (flags & MCT_MANAGER_SET_VALUE_FLAGS_INTERACTIVE)
594 : : ? G_DBUS_CALL_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION
595 : 8 : : G_DBUS_CALL_FLAGS_NONE,
596 : : -1, /* timeout, ms */
597 : : cancellable,
598 : : &local_error);
599 [ + + ]: 8 : if (local_error != NULL)
600 : : {
601 : 4 : g_propagate_error (error, bus_error_to_manager_error (local_error, user_id));
602 : 4 : return FALSE;
603 : : }
604 : :
605 : 4 : return TRUE;
606 : : }
607 : :
608 : : /**
609 : : * mct_manager_get_app_filter:
610 : : * @self: a #MctManager
611 : : * @user_id: ID of the user to query, typically coming from getuid()
612 : : * @flags: flags to affect the behaviour of the call
613 : : * @cancellable: (nullable): a #GCancellable, or %NULL
614 : : * @error: return location for a #GError, or %NULL
615 : : *
616 : : * Synchronous version of mct_manager_get_app_filter_async().
617 : : *
618 : : * Returns: (transfer full): app filter for the queried user
619 : : * Since: 0.3.0
620 : : */
621 : : MctAppFilter *
622 : 10 : mct_manager_get_app_filter (MctManager *self,
623 : : uid_t user_id,
624 : : MctManagerGetValueFlags flags,
625 : : GCancellable *cancellable,
626 : : GError **error)
627 : : {
628 : 10 : g_autoptr(GVariant) properties = NULL;
629 : :
630 : 10 : g_return_val_if_fail (MCT_IS_MANAGER (self), NULL);
631 : 10 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
632 : 10 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
633 : :
634 : 10 : properties = account_get_interface_properties (self,
635 : : user_id,
636 : : "com.endlessm.ParentalControls.AppFilter",
637 : : "AppFilter",
638 : : G_VARIANT_TYPE ("(bas)"),
639 : 10 : _("App filtering is globally disabled"),
640 : : flags,
641 : : cancellable,
642 : : error);
643 [ + + ]: 10 : if (properties == NULL)
644 : 5 : return NULL;
645 : :
646 : 5 : return mct_app_filter_deserialize (properties, user_id, error);
647 : : }
648 : :
649 : : static void get_app_filter_thread_cb (GTask *task,
650 : : gpointer source_object,
651 : : gpointer task_data,
652 : : GCancellable *cancellable);
653 : :
654 : : typedef struct
655 : : {
656 : : uid_t user_id;
657 : : MctManagerGetValueFlags flags;
658 : : } GetAppFilterData;
659 : :
660 : : static void
661 : 6 : get_app_filter_data_free (GetAppFilterData *data)
662 : : {
663 : 6 : g_free (data);
664 : 6 : }
665 : :
666 [ - + ]: 12 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (GetAppFilterData, get_app_filter_data_free)
667 : :
668 : : /**
669 : : * mct_manager_get_app_filter_async:
670 : : * @self: a #MctManager
671 : : * @user_id: ID of the user to query, typically coming from getuid()
672 : : * @flags: flags to affect the behaviour of the call
673 : : * @cancellable: (nullable): a #GCancellable, or %NULL
674 : : * @callback: a #GAsyncReadyCallback
675 : : * @user_data: user data to pass to @callback
676 : : *
677 : : * Asynchronously get a snapshot of the app filter settings for the given
678 : : * @user_id.
679 : : *
680 : : * On failure, an #MctManagerError, a #GDBusError or a #GIOError will be
681 : : * returned.
682 : : *
683 : : * Since: 0.3.0
684 : : */
685 : : void
686 : 6 : mct_manager_get_app_filter_async (MctManager *self,
687 : : uid_t user_id,
688 : : MctManagerGetValueFlags flags,
689 : : GCancellable *cancellable,
690 : : GAsyncReadyCallback callback,
691 : : gpointer user_data)
692 : : {
693 [ + - ]: 6 : g_autoptr(GTask) task = NULL;
694 [ + - ]: 6 : g_autoptr(GetAppFilterData) data = NULL;
695 : :
696 : 6 : g_return_if_fail (MCT_IS_MANAGER (self));
697 : 6 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
698 : :
699 : 6 : task = g_task_new (self, cancellable, callback, user_data);
700 [ + - ]: 6 : g_task_set_source_tag (task, mct_manager_get_app_filter_async);
701 : :
702 : 6 : data = g_new0 (GetAppFilterData, 1);
703 : 6 : data->user_id = user_id;
704 : 6 : data->flags = flags;
705 : 6 : g_task_set_task_data (task, g_steal_pointer (&data),
706 : : (GDestroyNotify) get_app_filter_data_free);
707 : :
708 : 6 : g_task_run_in_thread (task, get_app_filter_thread_cb);
709 : : }
710 : :
711 : : static void
712 : 6 : get_app_filter_thread_cb (GTask *task,
713 : : gpointer source_object,
714 : : gpointer task_data,
715 : : GCancellable *cancellable)
716 : : {
717 : 6 : g_autoptr(MctAppFilter) filter = NULL;
718 : 6 : MctManager *manager = MCT_MANAGER (source_object);
719 : 6 : GetAppFilterData *data = task_data;
720 : 6 : g_autoptr(GError) local_error = NULL;
721 : :
722 : 6 : filter = mct_manager_get_app_filter (manager, data->user_id,
723 : : data->flags,
724 : : cancellable, &local_error);
725 : :
726 [ + + ]: 6 : if (local_error != NULL)
727 : 5 : g_task_return_error (task, g_steal_pointer (&local_error));
728 : : else
729 : 1 : g_task_return_pointer (task, g_steal_pointer (&filter),
730 : : (GDestroyNotify) mct_app_filter_unref);
731 : 6 : }
732 : :
733 : : /**
734 : : * mct_manager_get_app_filter_finish:
735 : : * @self: a #MctManager
736 : : * @result: a #GAsyncResult
737 : : * @error: return location for a #GError, or %NULL
738 : : *
739 : : * Finish an asynchronous operation to get the app filter for a user, started
740 : : * with mct_manager_get_app_filter_async().
741 : : *
742 : : * Returns: (transfer full): app filter for the queried user
743 : : * Since: 0.3.0
744 : : */
745 : : MctAppFilter *
746 : 6 : mct_manager_get_app_filter_finish (MctManager *self,
747 : : GAsyncResult *result,
748 : : GError **error)
749 : : {
750 : 6 : g_return_val_if_fail (MCT_IS_MANAGER (self), NULL);
751 : 6 : g_return_val_if_fail (g_task_is_valid (result, self), NULL);
752 : 6 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
753 : :
754 : 6 : return g_task_propagate_pointer (G_TASK (result), error);
755 : : }
756 : :
757 : : /**
758 : : * mct_manager_set_app_filter:
759 : : * @self: a #MctManager
760 : : * @user_id: ID of the user to set the filter for, typically coming from getuid()
761 : : * @app_filter: (transfer none): the app filter to set for the user
762 : : * @flags: flags to affect the behaviour of the call
763 : : * @cancellable: (nullable): a #GCancellable, or %NULL
764 : : * @error: return location for a #GError, or %NULL
765 : : *
766 : : * Synchronous version of mct_manager_set_app_filter_async().
767 : : *
768 : : * Returns: %TRUE on success, %FALSE otherwise
769 : : * Since: 0.3.0
770 : : */
771 : : gboolean
772 : 9 : mct_manager_set_app_filter (MctManager *self,
773 : : uid_t user_id,
774 : : MctAppFilter *app_filter,
775 : : MctManagerSetValueFlags flags,
776 : : GCancellable *cancellable,
777 : : GError **error)
778 : : {
779 : 9 : g_autoptr(GVariant) properties_variant = NULL;
780 : :
781 : 9 : g_return_val_if_fail (MCT_IS_MANAGER (self), FALSE);
782 : 9 : g_return_val_if_fail (app_filter != NULL, FALSE);
783 : 9 : g_return_val_if_fail (app_filter->ref_count >= 1, FALSE);
784 : 9 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
785 : 9 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
786 : :
787 : 9 : properties_variant = mct_app_filter_serialize (app_filter);
788 : :
789 : 9 : return account_set_interface_properties (self,
790 : : user_id,
791 : : "com.endlessm.ParentalControls.AppFilter",
792 : : properties_variant,
793 : : "AppFilter",
794 : : flags,
795 : : cancellable,
796 : : error);
797 : : }
798 : :
799 : : static void set_app_filter_thread_cb (GTask *task,
800 : : gpointer source_object,
801 : : gpointer task_data,
802 : : GCancellable *cancellable);
803 : :
804 : : typedef struct
805 : : {
806 : : uid_t user_id;
807 : : MctAppFilter *app_filter; /* (owned) */
808 : : MctManagerSetValueFlags flags;
809 : : } SetAppFilterData;
810 : :
811 : : static void
812 : 2 : set_app_filter_data_free (SetAppFilterData *data)
813 : : {
814 : 2 : mct_app_filter_unref (data->app_filter);
815 : 2 : g_free (data);
816 : 2 : }
817 : :
818 [ - + ]: 4 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (SetAppFilterData, set_app_filter_data_free)
819 : :
820 : : /**
821 : : * mct_manager_set_app_filter_async:
822 : : * @self: a #MctManager
823 : : * @user_id: ID of the user to set the filter for, typically coming from getuid()
824 : : * @app_filter: (transfer none): the app filter to set for the user
825 : : * @flags: flags to affect the behaviour of the call
826 : : * @cancellable: (nullable): a #GCancellable, or %NULL
827 : : * @callback: a #GAsyncReadyCallback
828 : : * @user_data: user data to pass to @callback
829 : : *
830 : : * Asynchronously set the app filter settings for the given @user_id to the
831 : : * given @app_filter instance. This will set all fields of the app filter.
832 : : *
833 : : * On failure, an #MctManagerError, a #GDBusError or a #GIOError will be
834 : : * returned. The user’s app filter settings will be left in an undefined state.
835 : : *
836 : : * Since: 0.3.0
837 : : */
838 : : void
839 : 2 : mct_manager_set_app_filter_async (MctManager *self,
840 : : uid_t user_id,
841 : : MctAppFilter *app_filter,
842 : : MctManagerSetValueFlags flags,
843 : : GCancellable *cancellable,
844 : : GAsyncReadyCallback callback,
845 : : gpointer user_data)
846 : : {
847 [ + - ]: 2 : g_autoptr(GTask) task = NULL;
848 [ + - ]: 2 : g_autoptr(SetAppFilterData) data = NULL;
849 : :
850 : 2 : g_return_if_fail (MCT_IS_MANAGER (self));
851 : 2 : g_return_if_fail (app_filter != NULL);
852 : 2 : g_return_if_fail (app_filter->ref_count >= 1);
853 : 2 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
854 : :
855 : 2 : task = g_task_new (self, cancellable, callback, user_data);
856 [ + - ]: 2 : g_task_set_source_tag (task, mct_manager_set_app_filter_async);
857 : :
858 : 2 : data = g_new0 (SetAppFilterData, 1);
859 : 2 : data->user_id = user_id;
860 : 2 : data->app_filter = mct_app_filter_ref (app_filter);
861 : 2 : data->flags = flags;
862 : 2 : g_task_set_task_data (task, g_steal_pointer (&data),
863 : : (GDestroyNotify) set_app_filter_data_free);
864 : :
865 : 2 : g_task_run_in_thread (task, set_app_filter_thread_cb);
866 : : }
867 : :
868 : : static void
869 : 2 : set_app_filter_thread_cb (GTask *task,
870 : : gpointer source_object,
871 : : gpointer task_data,
872 : : GCancellable *cancellable)
873 : : {
874 : : gboolean success;
875 : 2 : MctManager *manager = MCT_MANAGER (source_object);
876 : 2 : SetAppFilterData *data = task_data;
877 : 2 : g_autoptr(GError) local_error = NULL;
878 : :
879 : 2 : success = mct_manager_set_app_filter (manager, data->user_id,
880 : : data->app_filter, data->flags,
881 : : cancellable, &local_error);
882 : :
883 [ + + ]: 2 : if (local_error != NULL)
884 : 1 : g_task_return_error (task, g_steal_pointer (&local_error));
885 : : else
886 : 1 : g_task_return_boolean (task, success);
887 : 2 : }
888 : :
889 : : /**
890 : : * mct_manager_set_app_filter_finish:
891 : : * @self: a #MctManager
892 : : * @result: a #GAsyncResult
893 : : * @error: return location for a #GError, or %NULL
894 : : *
895 : : * Finish an asynchronous operation to set the app filter for a user, started
896 : : * with mct_manager_set_app_filter_async().
897 : : *
898 : : * Returns: %TRUE on success, %FALSE otherwise
899 : : * Since: 0.3.0
900 : : */
901 : : gboolean
902 : 2 : mct_manager_set_app_filter_finish (MctManager *self,
903 : : GAsyncResult *result,
904 : : GError **error)
905 : : {
906 : 2 : g_return_val_if_fail (MCT_IS_MANAGER (self), FALSE);
907 : 2 : g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
908 : 2 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
909 : :
910 : 2 : return g_task_propagate_boolean (G_TASK (result), error);
911 : : }
912 : :
913 : : /**
914 : : * mct_manager_get_session_limits:
915 : : * @self: a #MctManager
916 : : * @user_id: ID of the user to query, typically coming from getuid()
917 : : * @flags: flags to affect the behaviour of the call
918 : : * @cancellable: (nullable): a #GCancellable, or %NULL
919 : : * @error: return location for a #GError, or %NULL
920 : : *
921 : : * Synchronous version of mct_manager_get_session_limits_async().
922 : : *
923 : : * Returns: (transfer full): session limits for the queried user
924 : : * Since: 0.5.0
925 : : */
926 : : MctSessionLimits *
927 : 9 : mct_manager_get_session_limits (MctManager *self,
928 : : uid_t user_id,
929 : : MctManagerGetValueFlags flags,
930 : : GCancellable *cancellable,
931 : : GError **error)
932 : : {
933 : 9 : g_autoptr(GVariant) properties = NULL;
934 : :
935 : 9 : g_return_val_if_fail (MCT_IS_MANAGER (self), NULL);
936 : 9 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
937 : 9 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
938 : :
939 : 9 : properties = account_get_interface_properties (self,
940 : : user_id,
941 : : "com.endlessm.ParentalControls.SessionLimits",
942 : : "LimitType",
943 : : G_VARIANT_TYPE ("u"),
944 : 9 : _("Session limits are globally disabled"),
945 : : flags,
946 : : cancellable,
947 : : error);
948 [ + + ]: 9 : if (properties == NULL)
949 : 6 : return NULL;
950 : :
951 : 3 : return mct_session_limits_deserialize (properties, user_id, error);
952 : : }
953 : :
954 : : static void get_session_limits_thread_cb (GTask *task,
955 : : gpointer source_object,
956 : : gpointer task_data,
957 : : GCancellable *cancellable);
958 : :
959 : : typedef struct
960 : : {
961 : : uid_t user_id;
962 : : MctManagerGetValueFlags flags;
963 : : } GetSessionLimitsData;
964 : :
965 : : static void
966 : 7 : get_session_limits_data_free (GetSessionLimitsData *data)
967 : : {
968 : 7 : g_free (data);
969 : 7 : }
970 : :
971 [ - + ]: 14 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (GetSessionLimitsData, get_session_limits_data_free)
972 : :
973 : : /**
974 : : * mct_manager_get_session_limits_async:
975 : : * @self: a #MctManager
976 : : * @user_id: ID of the user to query, typically coming from getuid()
977 : : * @flags: flags to affect the behaviour of the call
978 : : * @cancellable: (nullable): a #GCancellable, or %NULL
979 : : * @callback: a #GAsyncReadyCallback
980 : : * @user_data: user data to pass to @callback
981 : : *
982 : : * Asynchronously get a snapshot of the session limit settings for the given
983 : : * @user_id.
984 : : *
985 : : * On failure, an #MctManagerError, a #GDBusError or a #GIOError will be
986 : : * returned via mct_manager_get_session_limits_finish().
987 : : *
988 : : * Since: 0.5.0
989 : : */
990 : : void
991 : 7 : mct_manager_get_session_limits_async (MctManager *self,
992 : : uid_t user_id,
993 : : MctManagerGetValueFlags flags,
994 : : GCancellable *cancellable,
995 : : GAsyncReadyCallback callback,
996 : : gpointer user_data)
997 : : {
998 [ + - ]: 7 : g_autoptr(GTask) task = NULL;
999 [ + - ]: 7 : g_autoptr(GetSessionLimitsData) data = NULL;
1000 : :
1001 : 7 : g_return_if_fail (MCT_IS_MANAGER (self));
1002 : 7 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1003 : :
1004 : 7 : task = g_task_new (self, cancellable, callback, user_data);
1005 [ + - ]: 7 : g_task_set_source_tag (task, mct_manager_get_session_limits_async);
1006 : :
1007 : 7 : data = g_new0 (GetSessionLimitsData, 1);
1008 : 7 : data->user_id = user_id;
1009 : 7 : data->flags = flags;
1010 : 7 : g_task_set_task_data (task, g_steal_pointer (&data),
1011 : : (GDestroyNotify) get_session_limits_data_free);
1012 : :
1013 : 7 : g_task_run_in_thread (task, get_session_limits_thread_cb);
1014 : : }
1015 : :
1016 : : static void
1017 : 7 : get_session_limits_thread_cb (GTask *task,
1018 : : gpointer source_object,
1019 : : gpointer task_data,
1020 : : GCancellable *cancellable)
1021 : : {
1022 : 7 : g_autoptr(MctSessionLimits) limits = NULL;
1023 : 7 : MctManager *manager = MCT_MANAGER (source_object);
1024 : 7 : GetSessionLimitsData *data = task_data;
1025 : 7 : g_autoptr(GError) local_error = NULL;
1026 : :
1027 : 7 : limits = mct_manager_get_session_limits (manager, data->user_id,
1028 : : data->flags,
1029 : : cancellable, &local_error);
1030 : :
1031 [ + + ]: 7 : if (local_error != NULL)
1032 : 6 : g_task_return_error (task, g_steal_pointer (&local_error));
1033 : : else
1034 : 1 : g_task_return_pointer (task, g_steal_pointer (&limits),
1035 : : (GDestroyNotify) mct_session_limits_unref);
1036 : 7 : }
1037 : :
1038 : : /**
1039 : : * mct_manager_get_session_limits_finish:
1040 : : * @self: a #MctManager
1041 : : * @result: a #GAsyncResult
1042 : : * @error: return location for a #GError, or %NULL
1043 : : *
1044 : : * Finish an asynchronous operation to get the session limits for a user,
1045 : : * started with mct_manager_get_session_limits_async().
1046 : : *
1047 : : * Returns: (transfer full): session limits for the queried user
1048 : : * Since: 0.5.0
1049 : : */
1050 : : MctSessionLimits *
1051 : 7 : mct_manager_get_session_limits_finish (MctManager *self,
1052 : : GAsyncResult *result,
1053 : : GError **error)
1054 : : {
1055 : 7 : g_return_val_if_fail (MCT_IS_MANAGER (self), NULL);
1056 : 7 : g_return_val_if_fail (g_task_is_valid (result, self), NULL);
1057 : 7 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1058 : :
1059 : 7 : return g_task_propagate_pointer (G_TASK (result), error);
1060 : : }
1061 : :
1062 : : /**
1063 : : * mct_manager_set_session_limits:
1064 : : * @self: a #MctManager
1065 : : * @user_id: ID of the user to set the limits for, typically coming from getuid()
1066 : : * @session_limits: (transfer none): the session limits to set for the user
1067 : : * @flags: flags to affect the behaviour of the call
1068 : : * @cancellable: (nullable): a #GCancellable, or %NULL
1069 : : * @error: return location for a #GError, or %NULL
1070 : : *
1071 : : * Synchronous version of mct_manager_set_session_limits_async().
1072 : : *
1073 : : * Returns: %TRUE on success, %FALSE otherwise
1074 : : * Since: 0.5.0
1075 : : */
1076 : : gboolean
1077 : 7 : mct_manager_set_session_limits (MctManager *self,
1078 : : uid_t user_id,
1079 : : MctSessionLimits *session_limits,
1080 : : MctManagerSetValueFlags flags,
1081 : : GCancellable *cancellable,
1082 : : GError **error)
1083 : : {
1084 : 7 : g_autoptr(GVariant) properties_variant = NULL;
1085 : :
1086 : 7 : g_return_val_if_fail (MCT_IS_MANAGER (self), FALSE);
1087 : 7 : g_return_val_if_fail (session_limits != NULL, FALSE);
1088 : 7 : g_return_val_if_fail (session_limits->ref_count >= 1, FALSE);
1089 : 7 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1090 : 7 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1091 : :
1092 : 7 : properties_variant = mct_session_limits_serialize (session_limits);
1093 : :
1094 : 7 : return account_set_interface_properties (self,
1095 : : user_id,
1096 : : "com.endlessm.ParentalControls.SessionLimits",
1097 : : properties_variant,
1098 : : "LimitType",
1099 : : flags,
1100 : : cancellable,
1101 : : error);
1102 : : }
1103 : :
1104 : : static void set_session_limits_thread_cb (GTask *task,
1105 : : gpointer source_object,
1106 : : gpointer task_data,
1107 : : GCancellable *cancellable);
1108 : :
1109 : : typedef struct
1110 : : {
1111 : : uid_t user_id;
1112 : : MctSessionLimits *session_limits; /* (owned) */
1113 : : MctManagerSetValueFlags flags;
1114 : : } SetSessionLimitsData;
1115 : :
1116 : : static void
1117 : 2 : set_session_limits_data_free (SetSessionLimitsData *data)
1118 : : {
1119 : 2 : mct_session_limits_unref (data->session_limits);
1120 : 2 : g_free (data);
1121 : 2 : }
1122 : :
1123 [ - + ]: 4 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (SetSessionLimitsData, set_session_limits_data_free)
1124 : :
1125 : : /**
1126 : : * mct_manager_set_session_limits_async:
1127 : : * @self: a #MctManager
1128 : : * @user_id: ID of the user to set the limits for, typically coming from getuid()
1129 : : * @session_limits: (transfer none): the session limits to set for the user
1130 : : * @flags: flags to affect the behaviour of the call
1131 : : * @cancellable: (nullable): a #GCancellable, or %NULL
1132 : : * @callback: a #GAsyncReadyCallback
1133 : : * @user_data: user data to pass to @callback
1134 : : *
1135 : : * Asynchronously set the session limits settings for the given @user_id to the
1136 : : * given @session_limits instance.
1137 : : *
1138 : : * On failure, an #MctManagerError, a #GDBusError or a #GIOError will be
1139 : : * returned via mct_manager_set_session_limits_finish(). The user’s session
1140 : : * limits settings will be left in an undefined state.
1141 : : *
1142 : : * Since: 0.5.0
1143 : : */
1144 : : void
1145 : 2 : mct_manager_set_session_limits_async (MctManager *self,
1146 : : uid_t user_id,
1147 : : MctSessionLimits *session_limits,
1148 : : MctManagerSetValueFlags flags,
1149 : : GCancellable *cancellable,
1150 : : GAsyncReadyCallback callback,
1151 : : gpointer user_data)
1152 : : {
1153 [ + - ]: 2 : g_autoptr(GTask) task = NULL;
1154 [ + - ]: 2 : g_autoptr(SetSessionLimitsData) data = NULL;
1155 : :
1156 : 2 : g_return_if_fail (MCT_IS_MANAGER (self));
1157 : 2 : g_return_if_fail (session_limits != NULL);
1158 : 2 : g_return_if_fail (session_limits->ref_count >= 1);
1159 : 2 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1160 : :
1161 : 2 : task = g_task_new (self, cancellable, callback, user_data);
1162 [ + - ]: 2 : g_task_set_source_tag (task, mct_manager_set_session_limits_async);
1163 : :
1164 : 2 : data = g_new0 (SetSessionLimitsData, 1);
1165 : 2 : data->user_id = user_id;
1166 : 2 : data->session_limits = mct_session_limits_ref (session_limits);
1167 : 2 : data->flags = flags;
1168 : 2 : g_task_set_task_data (task, g_steal_pointer (&data),
1169 : : (GDestroyNotify) set_session_limits_data_free);
1170 : :
1171 : 2 : g_task_run_in_thread (task, set_session_limits_thread_cb);
1172 : : }
1173 : :
1174 : : static void
1175 : 2 : set_session_limits_thread_cb (GTask *task,
1176 : : gpointer source_object,
1177 : : gpointer task_data,
1178 : : GCancellable *cancellable)
1179 : : {
1180 : : gboolean success;
1181 : 2 : MctManager *manager = MCT_MANAGER (source_object);
1182 : 2 : SetSessionLimitsData *data = task_data;
1183 : 2 : g_autoptr(GError) local_error = NULL;
1184 : :
1185 : 2 : success = mct_manager_set_session_limits (manager, data->user_id,
1186 : : data->session_limits, data->flags,
1187 : : cancellable, &local_error);
1188 : :
1189 [ + + ]: 2 : if (local_error != NULL)
1190 : 1 : g_task_return_error (task, g_steal_pointer (&local_error));
1191 : : else
1192 : 1 : g_task_return_boolean (task, success);
1193 : 2 : }
1194 : :
1195 : : /**
1196 : : * mct_manager_set_session_limits_finish:
1197 : : * @self: a #MctManager
1198 : : * @result: a #GAsyncResult
1199 : : * @error: return location for a #GError, or %NULL
1200 : : *
1201 : : * Finish an asynchronous operation to set the session limits for a user,
1202 : : * started with mct_manager_set_session_limits_async().
1203 : : *
1204 : : * Returns: %TRUE on success, %FALSE otherwise
1205 : : * Since: 0.5.0
1206 : : */
1207 : : gboolean
1208 : 2 : mct_manager_set_session_limits_finish (MctManager *self,
1209 : : GAsyncResult *result,
1210 : : GError **error)
1211 : : {
1212 : 2 : g_return_val_if_fail (MCT_IS_MANAGER (self), FALSE);
1213 : 2 : g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
1214 : 2 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1215 : :
1216 : 2 : return g_task_propagate_boolean (G_TASK (result), error);
1217 : : }
1218 : :
1219 : : /**
1220 : : * mct_manager_get_web_filter:
1221 : : * @self: a #MctManager
1222 : : * @user_id: ID of the user to query, typically coming from getuid()
1223 : : * @flags: flags to affect the behaviour of the call
1224 : : * @cancellable: (nullable): a #GCancellable, or %NULL
1225 : : * @error: return location for a #GError, or %NULL
1226 : : *
1227 : : * Synchronous version of mct_manager_get_web_filter_async().
1228 : : *
1229 : : * Returns: (transfer full): web filter for the queried user
1230 : : * Since: 0.14.0
1231 : : */
1232 : : MctWebFilter *
1233 : 0 : mct_manager_get_web_filter (MctManager *self,
1234 : : uid_t user_id,
1235 : : MctManagerGetValueFlags flags,
1236 : : GCancellable *cancellable,
1237 : : GError **error)
1238 : : {
1239 : 0 : g_autoptr(GVariant) properties = NULL;
1240 : :
1241 : 0 : g_return_val_if_fail (MCT_IS_MANAGER (self), NULL);
1242 : 0 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
1243 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1244 : :
1245 : 0 : properties = account_get_interface_properties (self,
1246 : : user_id,
1247 : : "org.freedesktop.Malcontent.WebFilter",
1248 : : "FilterType",
1249 : : G_VARIANT_TYPE ("u"),
1250 : 0 : _("Web filtering is globally disabled"),
1251 : : flags,
1252 : : cancellable,
1253 : : error);
1254 [ # # ]: 0 : if (properties == NULL)
1255 : 0 : return NULL;
1256 : :
1257 : 0 : return mct_web_filter_deserialize (properties, user_id, error);
1258 : : }
1259 : :
1260 : : static void get_web_filter_thread_cb (GTask *task,
1261 : : gpointer source_object,
1262 : : gpointer task_data,
1263 : : GCancellable *cancellable);
1264 : :
1265 : : typedef struct
1266 : : {
1267 : : uid_t user_id;
1268 : : MctManagerGetValueFlags flags;
1269 : : } GetWebFilterData;
1270 : :
1271 : : static void
1272 : 0 : get_web_filter_data_free (GetWebFilterData *data)
1273 : : {
1274 : 0 : g_free (data);
1275 : 0 : }
1276 : :
1277 [ # # ]: 0 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (GetWebFilterData, get_web_filter_data_free)
1278 : :
1279 : : /**
1280 : : * mct_manager_get_web_filter_async:
1281 : : * @self: a #MctManager
1282 : : * @user_id: ID of the user to query, typically coming from getuid()
1283 : : * @flags: flags to affect the behaviour of the call
1284 : : * @cancellable: (nullable): a #GCancellable, or %NULL
1285 : : * @callback: a #GAsyncReadyCallback
1286 : : * @user_data: user data to pass to @callback
1287 : : *
1288 : : * Asynchronously get a snapshot of the web filter settings for the given
1289 : : * @user_id.
1290 : : *
1291 : : * On failure, an #MctManagerError, a #GDBusError or a #GIOError will be
1292 : : * returned via mct_manager_get_web_filter_finish().
1293 : : *
1294 : : * Since: 0.14.0
1295 : : */
1296 : : void
1297 : 0 : mct_manager_get_web_filter_async (MctManager *self,
1298 : : uid_t user_id,
1299 : : MctManagerGetValueFlags flags,
1300 : : GCancellable *cancellable,
1301 : : GAsyncReadyCallback callback,
1302 : : void *user_data)
1303 : : {
1304 [ # # ]: 0 : g_autoptr(GTask) task = NULL;
1305 [ # # ]: 0 : g_autoptr(GetWebFilterData) data = NULL;
1306 : :
1307 : 0 : g_return_if_fail (MCT_IS_MANAGER (self));
1308 : 0 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1309 : :
1310 : 0 : task = g_task_new (self, cancellable, callback, user_data);
1311 [ # # ]: 0 : g_task_set_source_tag (task, mct_manager_get_web_filter_async);
1312 : :
1313 : 0 : data = g_new0 (GetWebFilterData, 1);
1314 : 0 : data->user_id = user_id;
1315 : 0 : data->flags = flags;
1316 : 0 : g_task_set_task_data (task, g_steal_pointer (&data),
1317 : : (GDestroyNotify) get_web_filter_data_free);
1318 : :
1319 : 0 : g_task_run_in_thread (task, get_web_filter_thread_cb);
1320 : : }
1321 : :
1322 : : static void
1323 : 0 : get_web_filter_thread_cb (GTask *task,
1324 : : gpointer source_object,
1325 : : gpointer task_data,
1326 : : GCancellable *cancellable)
1327 : : {
1328 : 0 : g_autoptr(MctWebFilter) web_filter = NULL;
1329 : 0 : MctManager *manager = MCT_MANAGER (source_object);
1330 : 0 : GetWebFilterData *data = task_data;
1331 : 0 : g_autoptr(GError) local_error = NULL;
1332 : :
1333 : 0 : web_filter = mct_manager_get_web_filter (manager, data->user_id,
1334 : : data->flags,
1335 : : cancellable, &local_error);
1336 : :
1337 [ # # ]: 0 : if (local_error != NULL)
1338 : 0 : g_task_return_error (task, g_steal_pointer (&local_error));
1339 : : else
1340 : 0 : g_task_return_pointer (task, g_steal_pointer (&web_filter),
1341 : : (GDestroyNotify) mct_web_filter_unref);
1342 : 0 : }
1343 : :
1344 : : /**
1345 : : * mct_manager_get_web_filter_finish:
1346 : : * @self: a #MctManager
1347 : : * @result: a #GAsyncResult
1348 : : * @error: return location for a #GError, or %NULL
1349 : : *
1350 : : * Finish an asynchronous operation to get the web filter for a user,
1351 : : * started with mct_manager_get_web_filter_async().
1352 : : *
1353 : : * Returns: (transfer full): web filter for the queried user
1354 : : * Since: 0.14.0
1355 : : */
1356 : : MctWebFilter *
1357 : 0 : mct_manager_get_web_filter_finish (MctManager *self,
1358 : : GAsyncResult *result,
1359 : : GError **error)
1360 : : {
1361 : 0 : g_return_val_if_fail (MCT_IS_MANAGER (self), NULL);
1362 : 0 : g_return_val_if_fail (g_task_is_valid (result, self), NULL);
1363 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, NULL);
1364 : :
1365 : 0 : return g_task_propagate_pointer (G_TASK (result), error);
1366 : : }
1367 : :
1368 : : /**
1369 : : * mct_manager_set_web_filter:
1370 : : * @self: a #MctManager
1371 : : * @user_id: ID of the user to set the web_filter for, typically coming from getuid()
1372 : : * @web_filter: (transfer none): the web filter to set for the user
1373 : : * @flags: flags to affect the behaviour of the call
1374 : : * @cancellable: (nullable): a #GCancellable, or %NULL
1375 : : * @error: return location for a #GError, or %NULL
1376 : : *
1377 : : * Synchronous version of mct_manager_set_web_filter_async().
1378 : : *
1379 : : * Returns: true on success, false otherwise
1380 : : * Since: 0.14.0
1381 : : */
1382 : : gboolean
1383 : 0 : mct_manager_set_web_filter (MctManager *self,
1384 : : uid_t user_id,
1385 : : MctWebFilter *web_filter,
1386 : : MctManagerSetValueFlags flags,
1387 : : GCancellable *cancellable,
1388 : : GError **error)
1389 : : {
1390 : 0 : g_autoptr(GVariant) properties_variant = NULL;
1391 : :
1392 : 0 : g_return_val_if_fail (MCT_IS_MANAGER (self), FALSE);
1393 : 0 : g_return_val_if_fail (web_filter != NULL, FALSE);
1394 : 0 : g_return_val_if_fail (web_filter->ref_count >= 1, FALSE);
1395 : 0 : g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
1396 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1397 : :
1398 : 0 : properties_variant = mct_web_filter_serialize (web_filter);
1399 : :
1400 : 0 : return account_set_interface_properties (self,
1401 : : user_id,
1402 : : "org.freedesktop.Malcontent.WebFilter",
1403 : : properties_variant,
1404 : : "FilterType",
1405 : : flags,
1406 : : cancellable,
1407 : : error);
1408 : :
1409 : : /* FIXME: Also call org.freedesktop.MalcontentWeb1.Filtering.UpdateFilters(uid)? */
1410 : : }
1411 : :
1412 : : static void set_web_filter_thread_cb (GTask *task,
1413 : : gpointer source_object,
1414 : : gpointer task_data,
1415 : : GCancellable *cancellable);
1416 : :
1417 : : typedef struct
1418 : : {
1419 : : uid_t user_id;
1420 : : MctWebFilter *web_filter; /* (owned) */
1421 : : MctManagerSetValueFlags flags;
1422 : : } SetWebFilterData;
1423 : :
1424 : : static void
1425 : 0 : set_web_filter_data_free (SetWebFilterData *data)
1426 : : {
1427 : 0 : mct_web_filter_unref (data->web_filter);
1428 : 0 : g_free (data);
1429 : 0 : }
1430 : :
1431 [ # # ]: 0 : G_DEFINE_AUTOPTR_CLEANUP_FUNC (SetWebFilterData, set_web_filter_data_free)
1432 : :
1433 : : /**
1434 : : * mct_manager_set_web_filter_async:
1435 : : * @self: a #MctManager
1436 : : * @user_id: ID of the user to set the web filter for, typically coming from getuid()
1437 : : * @web_filter: (transfer none): the web filter to set for the user
1438 : : * @flags: flags to affect the behaviour of the call
1439 : : * @cancellable: (nullable): a #GCancellable, or %NULL
1440 : : * @callback: a #GAsyncReadyCallback
1441 : : * @user_data: user data to pass to @callback
1442 : : *
1443 : : * Asynchronously set the web filter settings for the given @user_id to the
1444 : : * given @web_filter instance.
1445 : : *
1446 : : * On failure, an #MctManagerError, a #GDBusError or a #GIOError will be
1447 : : * returned via mct_manager_set_web_filter_finish(). The user’s web filter
1448 : : * settings will be left in an undefined state.
1449 : : *
1450 : : * Since: 0.14.0
1451 : : */
1452 : : void
1453 : 0 : mct_manager_set_web_filter_async (MctManager *self,
1454 : : uid_t user_id,
1455 : : MctWebFilter *web_filter,
1456 : : MctManagerSetValueFlags flags,
1457 : : GCancellable *cancellable,
1458 : : GAsyncReadyCallback callback,
1459 : : gpointer user_data)
1460 : : {
1461 [ # # ]: 0 : g_autoptr(GTask) task = NULL;
1462 [ # # ]: 0 : g_autoptr(SetWebFilterData) data = NULL;
1463 : :
1464 : 0 : g_return_if_fail (MCT_IS_MANAGER (self));
1465 : 0 : g_return_if_fail (web_filter != NULL);
1466 : 0 : g_return_if_fail (web_filter->ref_count >= 1);
1467 : 0 : g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
1468 : :
1469 : 0 : task = g_task_new (self, cancellable, callback, user_data);
1470 [ # # ]: 0 : g_task_set_source_tag (task, mct_manager_set_web_filter_async);
1471 : :
1472 : 0 : data = g_new0 (SetWebFilterData, 1);
1473 : 0 : data->user_id = user_id;
1474 : 0 : data->web_filter = mct_web_filter_ref (web_filter);
1475 : 0 : data->flags = flags;
1476 : 0 : g_task_set_task_data (task, g_steal_pointer (&data),
1477 : : (GDestroyNotify) set_web_filter_data_free);
1478 : :
1479 : 0 : g_task_run_in_thread (task, set_web_filter_thread_cb);
1480 : : }
1481 : :
1482 : : static void
1483 : 0 : set_web_filter_thread_cb (GTask *task,
1484 : : gpointer source_object,
1485 : : gpointer task_data,
1486 : : GCancellable *cancellable)
1487 : : {
1488 : : gboolean success;
1489 : 0 : MctManager *manager = MCT_MANAGER (source_object);
1490 : 0 : SetWebFilterData *data = task_data;
1491 : 0 : g_autoptr(GError) local_error = NULL;
1492 : :
1493 : 0 : success = mct_manager_set_web_filter (manager, data->user_id,
1494 : : data->web_filter, data->flags,
1495 : : cancellable, &local_error);
1496 : :
1497 [ # # ]: 0 : if (local_error != NULL)
1498 : 0 : g_task_return_error (task, g_steal_pointer (&local_error));
1499 : : else
1500 : 0 : g_task_return_boolean (task, success);
1501 : 0 : }
1502 : :
1503 : : /**
1504 : : * mct_manager_set_web_filter_finish:
1505 : : * @self: a #MctManager
1506 : : * @result: a #GAsyncResult
1507 : : * @error: return location for a #GError, or %NULL
1508 : : *
1509 : : * Finish an asynchronous operation to set the web filter for a user,
1510 : : * started with mct_manager_set_web_filter_async().
1511 : : *
1512 : : * Returns: true on success, false otherwise
1513 : : * Since: 0.14.0
1514 : : */
1515 : : gboolean
1516 : 0 : mct_manager_set_web_filter_finish (MctManager *self,
1517 : : GAsyncResult *result,
1518 : : GError **error)
1519 : : {
1520 : 0 : g_return_val_if_fail (MCT_IS_MANAGER (self), FALSE);
1521 : 0 : g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
1522 : 0 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
1523 : :
1524 : 0 : return g_task_propagate_boolean (G_TASK (result), error);
1525 : : }
|