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 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 g_permission_acquire (GPermission *permission,
97 GCancellable *cancellable,
98 GError **error)
99 {
100 g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
101 return G_PERMISSION_GET_CLASS (permission)
102 ->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 g_permission_acquire_async (GPermission *permission,
121 GCancellable *cancellable,
122 GAsyncReadyCallback callback,
123 gpointer user_data)
124 {
125 g_return_if_fail (G_IS_PERMISSION (permission));
126 G_PERMISSION_GET_CLASS (permission)
127 ->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 g_permission_acquire_finish (GPermission *permission,
148 GAsyncResult *result,
149 GError **error)
150 {
151 g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
152 return G_PERMISSION_GET_CLASS (permission)
153 ->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 g_permission_release (GPermission *permission,
184 GCancellable *cancellable,
185 GError **error)
186 {
187 g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
188 return G_PERMISSION_GET_CLASS (permission)
189 ->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 g_permission_release_async (GPermission *permission,
208 GCancellable *cancellable,
209 GAsyncReadyCallback callback,
210 gpointer user_data)
211 {
212 g_return_if_fail (G_IS_PERMISSION (permission));
213 G_PERMISSION_GET_CLASS (permission)
214 ->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 g_permission_release_finish (GPermission *permission,
235 GAsyncResult *result,
236 GError **error)
237 {
238 g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
239 return G_PERMISSION_GET_CLASS (permission)
240 ->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 g_permission_get_allowed (GPermission *permission)
257 {
258 g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
259 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 g_permission_get_can_acquire (GPermission *permission)
276 {
277 g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
278 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 g_permission_get_can_release (GPermission *permission)
295 {
296 g_return_val_if_fail (G_IS_PERMISSION (permission), FALSE);
297 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 g_permission_impl_update (GPermission *permission,
317 gboolean allowed,
318 gboolean can_acquire,
319 gboolean can_release)
320 {
321 GObject *object;
322
323 g_return_if_fail (G_IS_PERMISSION (permission));
324
325 object = G_OBJECT (permission);
326 g_object_freeze_notify (object);
327
328 allowed = allowed != FALSE;
329 if (allowed != permission->priv->allowed)
330 {
331 permission->priv->allowed = allowed;
332 g_object_notify (object, "allowed");
333 }
334
335 can_acquire = can_acquire != FALSE;
336 if (can_acquire != permission->priv->can_acquire)
337 {
338 permission->priv->can_acquire = can_acquire;
339 g_object_notify (object, "can-acquire");
340 }
341
342 can_release = can_release != FALSE;
343 if (can_release != permission->priv->can_release)
344 {
345 permission->priv->can_release = can_release;
346 g_object_notify (object, "can-release");
347 }
348
349 g_object_thaw_notify (object);
350 }
351
352 static void
353 g_permission_get_property (GObject *object, guint prop_id,
354 GValue *value, GParamSpec *pspec)
355 {
356 GPermission *permission = G_PERMISSION (object);
357
358 switch (prop_id)
359 {
360 case PROP_ALLOWED:
361 g_value_set_boolean (value, permission->priv->allowed);
362 break;
363
364 case PROP_CAN_ACQUIRE:
365 g_value_set_boolean (value, permission->priv->can_acquire);
366 break;
367
368 case PROP_CAN_RELEASE:
369 g_value_set_boolean (value, permission->priv->can_release);
370 break;
371
372 default:
373 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
374 }
375 }
376
377 static void
378 g_permission_init (GPermission *permission)
379 {
380 permission->priv = g_permission_get_instance_private (permission);
381 }
382
383 static gboolean
384 acquire_or_release (GPermission *permission,
385 GCancellable *cancellable,
386 GError **error)
387 {
388 g_set_error_literal (error,
389 G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
390 "Can't acquire or release permission");
391 return FALSE;
392 }
393
394 static void
395 acquire_or_release_async (GPermission *permission,
396 GCancellable *cancellable,
397 GAsyncReadyCallback callback,
398 gpointer user_data)
399 {
400 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 }
406
407 static gboolean
408 acquire_or_release_finish (GPermission *permission,
409 GAsyncResult *result,
410 GError **error)
411 {
412 return g_task_propagate_boolean (G_TASK (result), error);
413 }
414
415 static void
416 g_permission_class_init (GPermissionClass *class)
417 {
418 GObjectClass *object_class = G_OBJECT_CLASS (class);
419
420 object_class->get_property = g_permission_get_property;
421
422 class->acquire = acquire_or_release;
423 class->release = acquire_or_release;
424 class->acquire_async = acquire_or_release_async;
425 class->release_async = acquire_or_release_async;
426 class->acquire_finish = acquire_or_release_finish;
427 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 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 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 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 }