Branch data Line data Source code
1 : : /*
2 : : * Copyright © 2010 Codethink Limited
3 : : *
4 : : * SPDX-License-Identifier: LGPL-2.1-or-later
5 : : *
6 : : * This library is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU Lesser General Public
8 : : * License as published by the Free Software Foundation; either
9 : : * version 2.1 of the License, or (at your option) any later version.
10 : : *
11 : : * This library is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : : * Lesser General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU Lesser General Public
17 : : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 : : *
19 : : * Author: Ryan Lortie <desrt@desrt.ca>
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include "gpermission.h"
25 : :
26 : : #include "gioerror.h"
27 : : #include "gioenums.h"
28 : : #include "gasyncresult.h"
29 : : #include "gtask.h"
30 : : #include "glibintl.h"
31 : :
32 : :
33 : : /**
34 : : * GPermission:
35 : : *
36 : : * A `GPermission` represents the status of the caller’s permission to
37 : : * perform a certain action.
38 : : *
39 : : * You can query if the action is currently allowed and if it is
40 : : * possible to acquire the permission so that the action will be allowed
41 : : * in the future.
42 : : *
43 : : * There is also an API to actually acquire the permission and one to
44 : : * release it.
45 : : *
46 : : * As an example, a `GPermission` might represent the ability for the
47 : : * user to write to a [class@Gio.Settings] object. This `GPermission` object
48 : : * could then be used to decide if it is appropriate to show a “Click here to
49 : : * unlock” button in a dialog and to provide the mechanism to invoke
50 : : * when that button is clicked.
51 : : **/
52 : :
53 : : struct _GPermissionPrivate
54 : : {
55 : : gboolean allowed;
56 : : gboolean can_acquire;
57 : : gboolean can_release;
58 : : };
59 : :
60 : : enum {
61 : : PROP_NONE,
62 : : PROP_ALLOWED,
63 : : PROP_CAN_ACQUIRE,
64 : : PROP_CAN_RELEASE
65 : : };
66 : :
67 : 43 : G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GPermission, g_permission, G_TYPE_OBJECT)
68 : :
69 : : /**
70 : : * g_permission_acquire:
71 : : * @permission: a #GPermission instance
72 : : * @cancellable: (nullable): a #GCancellable, or %NULL
73 : : * @error: a pointer to a %NULL #GError, or %NULL
74 : : *
75 : : * Attempts to acquire the permission represented by @permission.
76 : : *
77 : : * The precise method by which this happens depends on the permission
78 : : * and the underlying authentication mechanism. A simple example is
79 : : * that a dialog may appear asking the user to enter their password.
80 : : *
81 : : * You should check with g_permission_get_can_acquire() before calling
82 : : * this function.
83 : : *
84 : : * If the permission is acquired then %TRUE is returned. Otherwise,
85 : : * %FALSE is returned and @error is set appropriately.
86 : : *
87 : : * This call is blocking, likely for a very long time (in the case that
88 : : * user interaction is required). See g_permission_acquire_async() for
89 : : * the non-blocking version.
90 : : *
91 : : * Returns: %TRUE if the permission was successfully acquired
92 : : *
93 : : * Since: 2.26
94 : : */
95 : : gboolean
96 : 1 : g_permission_acquire (GPermission *permission,
97 : : GCancellable *cancellable,
98 : : GError **error)
99 : : {
100 : 1 : g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
101 : 1 : return G_PERMISSION_GET_CLASS (permission)
102 : 1 : ->acquire (permission, cancellable, error);
103 : : }
104 : :
105 : : /**
106 : : * g_permission_acquire_async:
107 : : * @permission: a #GPermission instance
108 : : * @cancellable: (nullable): a #GCancellable, or %NULL
109 : : * @callback: the #GAsyncReadyCallback to call when done
110 : : * @user_data: the user data to pass to @callback
111 : : *
112 : : * Attempts to acquire the permission represented by @permission.
113 : : *
114 : : * This is the first half of the asynchronous version of
115 : : * g_permission_acquire().
116 : : *
117 : : * Since: 2.26
118 : : **/
119 : : void
120 : 1 : g_permission_acquire_async (GPermission *permission,
121 : : GCancellable *cancellable,
122 : : GAsyncReadyCallback callback,
123 : : gpointer user_data)
124 : : {
125 : 1 : g_return_if_fail (G_IS_PERMISSION (permission));
126 : 1 : G_PERMISSION_GET_CLASS (permission)
127 : 1 : ->acquire_async (permission, cancellable, callback, user_data);
128 : : }
129 : :
130 : : /**
131 : : * g_permission_acquire_finish:
132 : : * @permission: a #GPermission instance
133 : : * @result: the #GAsyncResult given to the #GAsyncReadyCallback
134 : : * @error: a pointer to a %NULL #GError, or %NULL
135 : : *
136 : : * Collects the result of attempting to acquire the permission
137 : : * represented by @permission.
138 : : *
139 : : * This is the second half of the asynchronous version of
140 : : * g_permission_acquire().
141 : : *
142 : : * Returns: %TRUE if the permission was successfully acquired
143 : : *
144 : : * Since: 2.26
145 : : **/
146 : : gboolean
147 : 1 : g_permission_acquire_finish (GPermission *permission,
148 : : GAsyncResult *result,
149 : : GError **error)
150 : : {
151 : 1 : g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
152 : 1 : return G_PERMISSION_GET_CLASS (permission)
153 : 1 : ->acquire_finish (permission, result, error);
154 : : }
155 : :
156 : : /**
157 : : * g_permission_release:
158 : : * @permission: a #GPermission instance
159 : : * @cancellable: (nullable): a #GCancellable, or %NULL
160 : : * @error: a pointer to a %NULL #GError, or %NULL
161 : : *
162 : : * Attempts to release the permission represented by @permission.
163 : : *
164 : : * The precise method by which this happens depends on the permission
165 : : * and the underlying authentication mechanism. In most cases the
166 : : * permission will be dropped immediately without further action.
167 : : *
168 : : * You should check with g_permission_get_can_release() before calling
169 : : * this function.
170 : : *
171 : : * If the permission is released then %TRUE is returned. Otherwise,
172 : : * %FALSE is returned and @error is set appropriately.
173 : : *
174 : : * This call is blocking, likely for a very long time (in the case that
175 : : * user interaction is required). See g_permission_release_async() for
176 : : * the non-blocking version.
177 : : *
178 : : * Returns: %TRUE if the permission was successfully released
179 : : *
180 : : * Since: 2.26
181 : : **/
182 : : gboolean
183 : 1 : g_permission_release (GPermission *permission,
184 : : GCancellable *cancellable,
185 : : GError **error)
186 : : {
187 : 1 : g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
188 : 1 : return G_PERMISSION_GET_CLASS (permission)
189 : 1 : ->release (permission, cancellable, error);
190 : : }
191 : :
192 : : /**
193 : : * g_permission_release_async:
194 : : * @permission: a #GPermission instance
195 : : * @cancellable: (nullable): a #GCancellable, or %NULL
196 : : * @callback: the #GAsyncReadyCallback to call when done
197 : : * @user_data: the user data to pass to @callback
198 : : *
199 : : * Attempts to release the permission represented by @permission.
200 : : *
201 : : * This is the first half of the asynchronous version of
202 : : * g_permission_release().
203 : : *
204 : : * Since: 2.26
205 : : **/
206 : : void
207 : 1 : g_permission_release_async (GPermission *permission,
208 : : GCancellable *cancellable,
209 : : GAsyncReadyCallback callback,
210 : : gpointer user_data)
211 : : {
212 : 1 : g_return_if_fail (G_IS_PERMISSION (permission));
213 : 1 : G_PERMISSION_GET_CLASS (permission)
214 : 1 : ->release_async (permission, cancellable, callback, user_data);
215 : : }
216 : :
217 : : /**
218 : : * g_permission_release_finish:
219 : : * @permission: a #GPermission instance
220 : : * @result: the #GAsyncResult given to the #GAsyncReadyCallback
221 : : * @error: a pointer to a %NULL #GError, or %NULL
222 : : *
223 : : * Collects the result of attempting to release the permission
224 : : * represented by @permission.
225 : : *
226 : : * This is the second half of the asynchronous version of
227 : : * g_permission_release().
228 : : *
229 : : * Returns: %TRUE if the permission was successfully released
230 : : *
231 : : * Since: 2.26
232 : : **/
233 : : gboolean
234 : 1 : g_permission_release_finish (GPermission *permission,
235 : : GAsyncResult *result,
236 : : GError **error)
237 : : {
238 : 1 : g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
239 : 1 : return G_PERMISSION_GET_CLASS (permission)
240 : 1 : ->release_finish (permission, result, error);
241 : : }
242 : :
243 : : /**
244 : : * g_permission_get_allowed:
245 : : * @permission: a #GPermission instance
246 : : *
247 : : * Gets the value of the 'allowed' property. This property is %TRUE if
248 : : * the caller currently has permission to perform the action that
249 : : * @permission represents the permission to perform.
250 : : *
251 : : * Returns: the value of the 'allowed' property
252 : : *
253 : : * Since: 2.26
254 : : **/
255 : : gboolean
256 : 1 : g_permission_get_allowed (GPermission *permission)
257 : : {
258 : 1 : g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
259 : 1 : return permission->priv->allowed;
260 : : }
261 : :
262 : : /**
263 : : * g_permission_get_can_acquire:
264 : : * @permission: a #GPermission instance
265 : : *
266 : : * Gets the value of the 'can-acquire' property. This property is %TRUE
267 : : * if it is generally possible to acquire the permission by calling
268 : : * g_permission_acquire().
269 : : *
270 : : * Returns: the value of the 'can-acquire' property
271 : : *
272 : : * Since: 2.26
273 : : **/
274 : : gboolean
275 : 1 : g_permission_get_can_acquire (GPermission *permission)
276 : : {
277 : 1 : g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
278 : 1 : return permission->priv->can_acquire;
279 : : }
280 : :
281 : : /**
282 : : * g_permission_get_can_release:
283 : : * @permission: a #GPermission instance
284 : : *
285 : : * Gets the value of the 'can-release' property. This property is %TRUE
286 : : * if it is generally possible to release the permission by calling
287 : : * g_permission_release().
288 : : *
289 : : * Returns: the value of the 'can-release' property
290 : : *
291 : : * Since: 2.26
292 : : **/
293 : : gboolean
294 : 1 : g_permission_get_can_release (GPermission *permission)
295 : : {
296 : 1 : g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
297 : 1 : return permission->priv->can_release;
298 : : }
299 : :
300 : : /**
301 : : * g_permission_impl_update:
302 : : * @permission: a #GPermission instance
303 : : * @allowed: the new value for the 'allowed' property
304 : : * @can_acquire: the new value for the 'can-acquire' property
305 : : * @can_release: the new value for the 'can-release' property
306 : : *
307 : : * This function is called by the #GPermission implementation to update
308 : : * the properties of the permission. You should never call this
309 : : * function except from a #GPermission implementation.
310 : : *
311 : : * GObject notify signals are generated, as appropriate.
312 : : *
313 : : * Since: 2.26
314 : : **/
315 : : void
316 : 7 : g_permission_impl_update (GPermission *permission,
317 : : gboolean allowed,
318 : : gboolean can_acquire,
319 : : gboolean can_release)
320 : : {
321 : : GObject *object;
322 : :
323 : 7 : g_return_if_fail (G_IS_PERMISSION (permission));
324 : :
325 : 7 : object = G_OBJECT (permission);
326 : 7 : g_object_freeze_notify (object);
327 : :
328 : 7 : allowed = allowed != FALSE;
329 : 7 : if (allowed != permission->priv->allowed)
330 : : {
331 : 7 : permission->priv->allowed = allowed;
332 : 7 : g_object_notify (object, "allowed");
333 : : }
334 : :
335 : 7 : can_acquire = can_acquire != FALSE;
336 : 7 : if (can_acquire != permission->priv->can_acquire)
337 : : {
338 : 0 : permission->priv->can_acquire = can_acquire;
339 : 0 : g_object_notify (object, "can-acquire");
340 : : }
341 : :
342 : 7 : can_release = can_release != FALSE;
343 : 7 : if (can_release != permission->priv->can_release)
344 : : {
345 : 0 : permission->priv->can_release = can_release;
346 : 0 : g_object_notify (object, "can-release");
347 : : }
348 : :
349 : 7 : g_object_thaw_notify (object);
350 : : }
351 : :
352 : : static void
353 : 3 : g_permission_get_property (GObject *object, guint prop_id,
354 : : GValue *value, GParamSpec *pspec)
355 : : {
356 : 3 : GPermission *permission = G_PERMISSION (object);
357 : :
358 : 3 : switch (prop_id)
359 : : {
360 : 1 : case PROP_ALLOWED:
361 : 1 : g_value_set_boolean (value, permission->priv->allowed);
362 : 1 : break;
363 : :
364 : 1 : case PROP_CAN_ACQUIRE:
365 : 1 : g_value_set_boolean (value, permission->priv->can_acquire);
366 : 1 : break;
367 : :
368 : 1 : case PROP_CAN_RELEASE:
369 : 1 : g_value_set_boolean (value, permission->priv->can_release);
370 : 1 : break;
371 : :
372 : 0 : default:
373 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
374 : : }
375 : 3 : }
376 : :
377 : : static void
378 : 8 : g_permission_init (GPermission *permission)
379 : : {
380 : 8 : permission->priv = g_permission_get_instance_private (permission);
381 : 8 : }
382 : :
383 : : static gboolean
384 : 2 : acquire_or_release (GPermission *permission,
385 : : GCancellable *cancellable,
386 : : GError **error)
387 : : {
388 : 2 : g_set_error_literal (error,
389 : : G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
390 : : "Can't acquire or release permission");
391 : 2 : return FALSE;
392 : : }
393 : :
394 : : static void
395 : 2 : acquire_or_release_async (GPermission *permission,
396 : : GCancellable *cancellable,
397 : : GAsyncReadyCallback callback,
398 : : gpointer user_data)
399 : : {
400 : 2 : g_task_report_new_error (permission,
401 : : callback, user_data,
402 : : NULL,
403 : : G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
404 : : "Can't acquire or release permission");
405 : 2 : }
406 : :
407 : : static gboolean
408 : 2 : acquire_or_release_finish (GPermission *permission,
409 : : GAsyncResult *result,
410 : : GError **error)
411 : : {
412 : 2 : return g_task_propagate_boolean (G_TASK (result), error);
413 : : }
414 : :
415 : : static void
416 : 4 : g_permission_class_init (GPermissionClass *class)
417 : : {
418 : 4 : GObjectClass *object_class = G_OBJECT_CLASS (class);
419 : :
420 : 4 : object_class->get_property = g_permission_get_property;
421 : :
422 : 4 : class->acquire = acquire_or_release;
423 : 4 : class->release = acquire_or_release;
424 : 4 : class->acquire_async = acquire_or_release_async;
425 : 4 : class->release_async = acquire_or_release_async;
426 : 4 : class->acquire_finish = acquire_or_release_finish;
427 : 4 : class->release_finish = acquire_or_release_finish;
428 : :
429 : : /**
430 : : * GPermission:allowed:
431 : : *
432 : : * %TRUE if the caller currently has permission to perform the action that
433 : : * @permission represents the permission to perform.
434 : : */
435 : 4 : g_object_class_install_property (object_class, PROP_ALLOWED,
436 : : g_param_spec_boolean ("allowed", NULL, NULL,
437 : : FALSE,
438 : : G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
439 : :
440 : : /**
441 : : * GPermission:can-acquire:
442 : : *
443 : : * %TRUE if it is generally possible to acquire the permission by calling
444 : : * g_permission_acquire().
445 : : */
446 : 4 : g_object_class_install_property (object_class, PROP_CAN_ACQUIRE,
447 : : g_param_spec_boolean ("can-acquire", NULL, NULL,
448 : : FALSE,
449 : : G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
450 : :
451 : : /**
452 : : * GPermission:can-release:
453 : : *
454 : : * %TRUE if it is generally possible to release the permission by calling
455 : : * g_permission_release().
456 : : */
457 : 4 : g_object_class_install_property (object_class, PROP_CAN_RELEASE,
458 : : g_param_spec_boolean ("can-release", NULL, NULL,
459 : : FALSE,
460 : : G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
461 : 4 : }
|