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