0fcd17ec74032b4627ffff9b77d4a103784aa56a
[platform/upstream/glib.git] / gio / gpermission.c
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 of the licence, 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 "gsimpleasyncresult.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: (allow-none): 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: (allow-none): 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: (allow-none): 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: (allow-none): 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, "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, "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, "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, permission->priv->allowed);
371       break;
372
373     case PROP_CAN_ACQUIRE:
374       g_value_set_boolean (value, permission->priv->can_acquire);
375       break;
376
377     case PROP_CAN_RELEASE:
378       g_value_set_boolean (value, 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 (permission);
390 }
391
392 static gboolean
393 acquire_or_release (GPermission   *permission,
394                     GCancellable  *cancellable,
395                     GError       **error)
396 {
397   g_set_error_literal  (error,
398                         G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
399                         "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_simple_async_report_error_in_idle (G_OBJECT (permission),
410                                        callback, user_data,
411                                        G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
412                                        "Can't acquire or release permission");
413 }
414
415 static gboolean
416 acquire_or_release_finish (GPermission   *permission,
417                            GAsyncResult  *result,
418                            GError       **error)
419 {
420   g_async_result_legacy_propagate_error (result, error);
421   return FALSE;
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 (object_class, PROP_ALLOWED,
445      g_param_spec_boolean ("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 (object_class, PROP_CAN_ACQUIRE,
458      g_param_spec_boolean ("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 (object_class, PROP_CAN_RELEASE,
471      g_param_spec_boolean ("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 }