Make GPermission more forgiving
[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, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
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 "gsimpleasyncresult.h"
30 #include "glibintl.h"
31
32
33 /**
34  * SECTION:gpermission
35  * @title: GPermission
36  * @short_description: An object representing the permission to perform
37  *                     a certain action
38  *
39  * A #GPermission represents the status of the caller's permission to
40  * perform a certain action.
41  *
42  * You can query if the action is currently allowed and if it is
43  * possible to acquire the permission so that the action will be allowed
44  * in the future.
45  *
46  * There is also an API to actually acquire the permission and one to
47  * release it.
48  *
49  * As an example, a #GPermission might represent the ability for the
50  * user to write to a #GSettings object.  This #GPermission object could
51  * then be used to decide if it is appropriate to show a "Click here to
52  * unlock" button in a dialog and to provide the mechanism to invoke
53  * when that button is clicked.
54  **/
55
56 /**
57  * GPermission:
58  *
59  * #GPermission is an opaque data structure and can only be accessed
60  * using the following functions.
61  **/
62
63 G_DEFINE_ABSTRACT_TYPE (GPermission, g_permission, G_TYPE_OBJECT)
64
65 struct _GPermissionPrivate
66 {
67   gboolean allowed;
68   gboolean can_acquire;
69   gboolean can_release;
70 };
71
72 enum  {
73   PROP_NONE,
74   PROP_ALLOWED,
75   PROP_CAN_ACQUIRE,
76   PROP_CAN_RELEASE
77 };
78
79 /**
80  * g_permission_acquire:
81  * @permission: a #GPermission instance
82  * @cancellable: (allow-none): a #GCancellable, or %NULL
83  * @error: a pointer to a %NULL #GError, or %NULL
84  *
85  * Attempts to acquire the permission represented by @permission.
86  *
87  * The precise method by which this happens depends on the permission
88  * and the underlying authentication mechanism.  A simple example is
89  * that a dialog may appear asking the user to enter their password.
90  *
91  * You should check with g_permission_get_can_acquire() before calling
92  * this function.
93  *
94  * If the permission is acquired then %TRUE is returned.  Otherwise,
95  * %FALSE is returned and @error is set appropriately.
96  *
97  * This call is blocking, likely for a very long time (in the case that
98  * user interaction is required).  See g_permission_acquire_async() for
99  * the non-blocking version.
100  *
101  * Returns: %TRUE if the permission was successfully acquired
102  *
103  * Since: 2.26
104  */
105 gboolean
106 g_permission_acquire (GPermission   *permission,
107                       GCancellable  *cancellable,
108                       GError       **error)
109 {
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_PERMISSION_GET_CLASS (permission)
135     ->acquire_async (permission, cancellable, callback, user_data);
136 }
137
138 /**
139  * g_permission_acquire_finish:
140  * @permission: a #GPermission instance
141  * @result: the #GAsyncResult given to the #GAsyncReadyCallback
142  * @error: a pointer to a %NULL #GError, or %NULL
143  *
144  * Collects the result of attempting to acquire the permission
145  * represented by @permission.
146  *
147  * This is the second half of the asynchronous version of
148  * g_permission_acquire().
149  *
150  * Returns: %TRUE if the permission was successfully acquired
151  *
152  * Since: 2.26
153  **/
154 gboolean
155 g_permission_acquire_finish (GPermission   *permission,
156                              GAsyncResult  *result,
157                              GError       **error)
158 {
159   return G_PERMISSION_GET_CLASS (permission)
160     ->acquire_finish (permission, result, error);
161 }
162
163 /**
164  * g_permission_release:
165  * @permission: a #GPermission instance
166  * @cancellable: (allow-none): a #GCancellable, or %NULL
167  * @error: a pointer to a %NULL #GError, or %NULL
168  *
169  * Attempts to release the permission represented by @permission.
170  *
171  * The precise method by which this happens depends on the permission
172  * and the underlying authentication mechanism.  In most cases the
173  * permission will be dropped immediately without further action.
174  *
175  * You should check with g_permission_get_can_release() before calling
176  * this function.
177  *
178  * If the permission is released then %TRUE is returned.  Otherwise,
179  * %FALSE is returned and @error is set appropriately.
180  *
181  * This call is blocking, likely for a very long time (in the case that
182  * user interaction is required).  See g_permission_release_async() for
183  * the non-blocking version.
184  *
185  * Returns: %TRUE if the permission was successfully released
186  *
187  * Since: 2.26
188  **/
189 gboolean
190 g_permission_release (GPermission   *permission,
191                       GCancellable  *cancellable,
192                       GError       **error)
193 {
194   return G_PERMISSION_GET_CLASS (permission)
195     ->release (permission, cancellable, error);
196 }
197
198 /**
199  * g_permission_release_async:
200  * @permission: a #GPermission instance
201  * @cancellable: (allow-none): a #GCancellable, or %NULL
202  * @callback: the #GAsyncReadyCallback to call when done
203  * @user_data: the user data to pass to @callback
204  *
205  * Attempts to release the permission represented by @permission.
206  *
207  * This is the first half of the asynchronous version of
208  * g_permission_release().
209  *
210  * Since: 2.26
211  **/
212 void
213 g_permission_release_async (GPermission         *permission,
214                             GCancellable        *cancellable,
215                             GAsyncReadyCallback  callback,
216                             gpointer             user_data)
217 {
218   G_PERMISSION_GET_CLASS (permission)
219     ->release_async (permission, cancellable, callback, user_data);
220 }
221
222 /**
223  * g_permission_release_finish:
224  * @permission: a #GPermission instance
225  * @result: the #GAsyncResult given to the #GAsyncReadyCallback
226  * @error: a pointer to a %NULL #GError, or %NULL
227  *
228  * Collects the result of attempting to release the permission
229  * represented by @permission.
230  *
231  * This is the second half of the asynchronous version of
232  * g_permission_release().
233  *
234  * Returns: %TRUE if the permission was successfully released
235  *
236  * Since: 2.26
237  **/
238 gboolean
239 g_permission_release_finish (GPermission   *permission,
240                              GAsyncResult  *result,
241                              GError       **error)
242 {
243   return G_PERMISSION_GET_CLASS (permission)
244     ->release_finish (permission, result, error);
245 }
246
247 /**
248  * g_permission_get_allowed:
249  * @permission: a #GPermission instance
250  *
251  * Gets the value of the 'allowed' property.  This property is %TRUE if
252  * the caller currently has permission to perform the action that
253  * @permission represents the permission to perform.
254  *
255  * Returns: the value of the 'allowed' property
256  *
257  * Since: 2.26
258  **/
259 gboolean
260 g_permission_get_allowed (GPermission *permission)
261 {
262   return permission->priv->allowed;
263 }
264
265 /**
266  * g_permission_get_can_acquire:
267  * @permission: a #GPermission instance
268  *
269  * Gets the value of the 'can-acquire' property.  This property is %TRUE
270  * if it is generally possible to acquire the permission by calling
271  * g_permission_acquire().
272  *
273  * Returns: the value of the 'can-acquire' property
274  *
275  * Since: 2.26
276  **/
277 gboolean
278 g_permission_get_can_acquire (GPermission *permission)
279 {
280   return permission->priv->can_acquire;
281 }
282
283 /**
284  * g_permission_get_can_release:
285  * @permission: a #GPermission instance
286  *
287  * Gets the value of the 'can-release' property.  This property is %TRUE
288  * if it is generally possible to release the permission by calling
289  * g_permission_release().
290  *
291  * Returns: the value of the 'can-release' property
292  *
293  * Since: 2.26
294  **/
295 gboolean
296 g_permission_get_can_release (GPermission *permission)
297 {
298   return permission->priv->can_release;
299 }
300
301 /**
302  * g_permission_impl_update:
303  * @permission: a #GPermission instance
304  * @allowed: the new value for the 'allowed' property
305  * @can_acquire: the new value for the 'can-acquire' property
306  * @can_release: the new value for the 'can-release' property
307  *
308  * This function is called by the #GPermission implementation to update
309  * the properties of the permission.  You should never call this
310  * function except from a #GPermission implementation.
311  *
312  * GObject notify signals are generated, as appropriate.
313  *
314  * Since: 2.26
315  **/
316 void
317 g_permission_impl_update (GPermission *permission,
318                           gboolean     allowed,
319                           gboolean     can_acquire,
320                           gboolean     can_release)
321 {
322   GObject *object = G_OBJECT (permission);
323
324   g_object_freeze_notify (object);
325
326   allowed = allowed != FALSE;
327   if (allowed != permission->priv->allowed)
328     {
329       permission->priv->allowed = allowed;
330       g_object_notify (object, "allowed");
331     }
332
333   can_acquire = can_acquire != FALSE;
334   if (can_acquire != permission->priv->can_acquire)
335     {
336       permission->priv->can_acquire = can_acquire;
337       g_object_notify (object, "can-acquire");
338     }
339
340   can_release = can_release != FALSE;
341   if (can_release != permission->priv->can_release)
342     {
343       permission->priv->can_release = can_release;
344       g_object_notify (object, "can-release");
345     }
346
347   g_object_thaw_notify (object);
348 }
349
350 static void
351 g_permission_get_property (GObject *object, guint prop_id,
352                            GValue *value, GParamSpec *pspec)
353 {
354   GPermission *permission = G_PERMISSION (object);
355
356   switch (prop_id)
357     {
358     case PROP_ALLOWED:
359       g_value_set_boolean (value, permission->priv->allowed);
360       break;
361
362     case PROP_CAN_ACQUIRE:
363       g_value_set_boolean (value, permission->priv->can_acquire);
364       break;
365
366     case PROP_CAN_RELEASE:
367       g_value_set_boolean (value, permission->priv->can_release);
368       break;
369
370     default:
371       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
372   }
373 }
374
375 static void
376 g_permission_init (GPermission *permission)
377 {
378   permission->priv = G_TYPE_INSTANCE_GET_PRIVATE (permission,
379                                                   G_TYPE_PERMISSION,
380                                                   GPermissionPrivate);
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_simple_async_report_error_in_idle (G_OBJECT (permission),
401                                        callback, user_data,
402                                        G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
403                                        "Can't acquire or release permission");
404 }
405
406 static gboolean
407 acquire_or_release_finish (GPermission   *permission,
408                            GAsyncResult  *result,
409                            GError       **error)
410 {
411   g_async_result_legacy_propagate_error (result, error);
412   return FALSE;
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",
437                            P_("Is allowed"),
438                            P_("If the caller is allowed to perform the action"),
439                            FALSE,
440                            G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
441
442   /**
443    * GPermission:can-acquire:
444    *
445    * %TRUE if it is generally possible to acquire the permission by calling
446    * g_permission_acquire().
447    */
448    g_object_class_install_property (object_class, PROP_CAN_ACQUIRE,
449      g_param_spec_boolean ("can-acquire",
450                            P_("Can acquire"),
451                            P_("If calling g_permission_acquire() makes sense"),
452                            FALSE,
453                            G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
454
455   /**
456    * GPermission:can-release:
457    *
458    * %TRUE if it is generally possible to release the permission by calling
459    * g_permission_release().
460    */
461    g_object_class_install_property (object_class, PROP_CAN_RELEASE,
462      g_param_spec_boolean ("can-release",
463                            P_("Can release"),
464                            P_("If calling g_permission_release() makes sense"),
465                            FALSE,
466                            G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
467
468   g_type_class_add_private (class, sizeof (GPermissionPrivate));
469 }