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