Use AM_CPPFLAGS instead of INCLUDES
[platform/upstream/libsecret.git] / libsecret / secret-util.c
1 /* libsecret - GLib wrapper for Secret Service
2  *
3  * Copyright 2011 Collabora Ltd.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published
7  * by the Free Software Foundation; either version 2.1 of the licence or (at
8  * your option) any later version.
9  *
10  * See the included COPYING file for more information.
11  *
12  * Author: Stef Walter <stefw@gnome.org>
13  */
14
15 #include "config.h"
16
17 #include "secret-private.h"
18 #include "secret-types.h"
19
20 #include <string.h>
21
22 /**
23  * SECTION:secret-error
24  * @title: SecretError
25  * @short_description: libsecret errors
26  *
27  * Various errors reported by the libsecret library. No error returned from
28  * the libsecret API is suitable for direct display to the user. It is up
29  * to the application to handle them appropriately.
30  *
31  * Stability: Stable
32  */
33
34 /**
35  * SecretError:
36  * @SECRET_ERROR_PROTOCOL: received an invalid data or message from the Secret
37  *                         Service
38  * @SECRET_ERROR_IS_LOCKED: the item or collection is locked and the operation
39  *                          cannot be performed
40  * @SECRET_ERROR_NO_SUCH_OBJECT: no such item or collection found in the
41  *                               Secret Service
42  * @SECRET_ERROR_ALREADY_EXISTS: a relevant item or collection already exists
43  *
44  * Errors returned by the Secret Service. None of the errors are appropriate
45  * for display to the user.
46  */
47
48 static void
49 list_unref_free (GList *reflist)
50 {
51         GList *l;
52         for (l = reflist; l; l = g_list_next (l)) {
53                 g_return_if_fail (G_IS_OBJECT (l->data));
54                 g_object_unref (l->data);
55         }
56         g_list_free (reflist);
57 }
58
59 static GList *
60 list_ref_copy (GList *reflist)
61 {
62         GList *l, *copy = g_list_copy (reflist);
63         for (l = copy; l; l = g_list_next (l)) {
64                 g_return_val_if_fail (G_IS_OBJECT (l->data), NULL);
65                 g_object_ref (l->data);
66         }
67         return copy;
68 }
69
70 GType
71 _secret_list_get_type (void)
72 {
73         static GType type = 0;
74         if (!type)
75                 type = g_boxed_type_register_static ("SecretObjectList",
76                                                      (GBoxedCopyFunc)list_ref_copy,
77                                                      (GBoxedFreeFunc)list_unref_free);
78         return type;
79
80 }
81
82 GQuark
83 secret_error_get_quark (void)
84 {
85         static volatile gsize quark = 0;
86
87         static const GDBusErrorEntry entries[] = {
88                 { SECRET_ERROR_IS_LOCKED, "org.freedesktop.Secret.Error.IsLocked", },
89                 { SECRET_ERROR_NO_SUCH_OBJECT, "org.freedesktop.Secret.Error.NoSuchObject", },
90                 { SECRET_ERROR_ALREADY_EXISTS, "org.freedesktop.Secret.Error.AlreadyExists" },
91         };
92
93         g_dbus_error_register_error_domain ("secret-error", &quark,
94                                             entries, G_N_ELEMENTS (entries));
95
96         return quark;
97 }
98
99 gboolean
100 _secret_util_propagate_error (GSimpleAsyncResult *async,
101                               GError **error)
102 {
103         if (!g_simple_async_result_propagate_error (async, error))
104                 return FALSE;
105
106         _secret_util_strip_remote_error (error);
107         return TRUE;
108 }
109
110 void
111 _secret_util_strip_remote_error (GError **error)
112 {
113         gchar *remote;
114
115         if (error == NULL || *error == NULL)
116                 return;
117
118         remote = g_dbus_error_get_remote_error (*error);
119         if (remote) {
120                 if (g_dbus_error_strip_remote_error (*error)) {
121                         g_message ("Remote error from secret service: %s: %s",
122                                    remote, (*error)->message);
123                 }
124                 g_free (remote);
125         }
126 }
127
128 gchar *
129 _secret_util_parent_path (const gchar *path)
130 {
131         const gchar *pos;
132
133         g_return_val_if_fail (path != NULL, NULL);
134
135         pos = strrchr (path, '/');
136         g_return_val_if_fail (pos != NULL, NULL);
137         g_return_val_if_fail (pos != path, NULL);
138
139         return g_strndup (path, pos - path);
140 }
141
142 gboolean
143 _secret_util_empty_path (const gchar *path)
144 {
145         g_return_val_if_fail (path != NULL, TRUE);
146         return (g_str_equal (path, "") || g_str_equal (path, "/"));
147 }
148
149 gchar *
150 _secret_util_collection_to_path (const gchar *collection)
151 {
152         if (collection == NULL)
153                 collection = SECRET_COLLECTION_DEFAULT;
154         if (strchr (collection, '/') == NULL)
155                 return g_strdup_printf ("/org/freedesktop/secrets/aliases/%s", collection);
156         return g_strdup (collection);
157 }
158
159 GVariant *
160 _secret_util_variant_for_properties (GHashTable *properties)
161 {
162         GHashTableIter iter;
163         GVariantBuilder builder;
164         const gchar *name;
165         GVariant *value;
166
167         g_return_val_if_fail (properties != NULL, NULL);
168
169         g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
170
171         g_hash_table_iter_init (&iter, properties);
172         while (g_hash_table_iter_next (&iter, (gpointer *)&name, (gpointer *)&value))
173                 g_variant_builder_add (&builder, "{sv}", name, value);
174
175         return g_variant_builder_end (&builder);
176 }
177
178 static void
179 process_get_all_reply (GDBusProxy *proxy,
180                        GVariant *retval)
181 {
182         const gchar *invalidated_properties[1] = { NULL };
183         GVariant *changed_properties;
184         GVariantIter *iter;
185         GVariant *value;
186         gchar *key;
187
188         if (!g_variant_is_of_type (retval, G_VARIANT_TYPE ("(a{sv})"))) {
189                 g_warning ("Value for GetAll reply with type `%s' does not match `(a{sv})'",
190                            g_variant_get_type_string (retval));
191                 return;
192         }
193
194         g_variant_get (retval, "(a{sv})", &iter);
195         while (g_variant_iter_loop (iter, "{sv}", &key, &value))
196                 g_dbus_proxy_set_cached_property (proxy, key, value);
197         g_variant_iter_free (iter);
198
199         g_variant_get (retval, "(@a{sv})", &changed_properties);
200         g_signal_emit_by_name (proxy, "g-properties-changed",
201                                changed_properties, invalidated_properties);
202         g_variant_unref (changed_properties);
203 }
204
205 static void
206 on_get_properties (GObject *source,
207                    GAsyncResult *result,
208                    gpointer user_data)
209 {
210         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
211         GDBusProxy *proxy = G_DBUS_PROXY (g_async_result_get_source_object (user_data));
212         GError *error = NULL;
213         GVariant *retval;
214
215         retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
216
217         if (error == NULL) {
218                 process_get_all_reply (proxy, retval);
219         } else {
220                 g_simple_async_result_take_error (res, error);
221         }
222         if (retval != NULL)
223                 g_variant_unref (retval);
224
225         g_simple_async_result_complete (res);
226         g_object_unref (proxy);
227         g_object_unref (res);
228 }
229
230 void
231 _secret_util_get_properties (GDBusProxy *proxy,
232                              gpointer result_tag,
233                              GCancellable *cancellable,
234                              GAsyncReadyCallback callback,
235                              gpointer user_data)
236 {
237         GSimpleAsyncResult *res;
238
239         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
240
241         res = g_simple_async_result_new (G_OBJECT (proxy), callback, user_data, result_tag);
242
243         g_dbus_connection_call (g_dbus_proxy_get_connection (proxy),
244                                 g_dbus_proxy_get_name (proxy),
245                                 g_dbus_proxy_get_object_path (proxy),
246                                 "org.freedesktop.DBus.Properties", "GetAll",
247                                 g_variant_new ("(s)", g_dbus_proxy_get_interface_name (proxy)),
248                                 G_VARIANT_TYPE ("(a{sv})"),
249                                 G_DBUS_CALL_FLAGS_NONE, -1,
250                                 cancellable, on_get_properties,
251                                 g_object_ref (res));
252
253         g_object_unref (res);
254 }
255
256 gboolean
257 _secret_util_get_properties_finish (GDBusProxy *proxy,
258                                     gpointer result_tag,
259                                     GAsyncResult *result,
260                                     GError **error)
261 {
262         GSimpleAsyncResult *res;
263
264         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), result_tag), FALSE);
265         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
266
267         res = G_SIMPLE_ASYNC_RESULT (result);
268
269         if (_secret_util_propagate_error (res, error))
270                 return FALSE;
271
272         return TRUE;
273 }
274
275 typedef struct {
276         gchar *property;
277         GVariant *value;
278         gboolean result;
279 } SetClosure;
280
281 static void
282 set_closure_free (gpointer data)
283 {
284         SetClosure *closure = data;
285         g_free (closure->property);
286         g_variant_unref (closure->value);
287         g_slice_free (SetClosure, closure);
288 }
289
290 static void
291 on_set_property (GObject *source,
292                  GAsyncResult *result,
293                  gpointer user_data)
294 {
295         GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
296         SetClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
297         GDBusProxy *proxy = G_DBUS_PROXY (g_async_result_get_source_object (user_data));
298         GError *error = NULL;
299         GVariant *retval;
300
301         retval = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source),
302                                                 result, &error);
303         if (error != NULL) {
304                 g_simple_async_result_take_error (res, error);
305         }
306         if (retval != NULL)
307                 g_variant_unref (retval);
308
309         closure->result = retval != NULL;
310         if (closure->result)
311                 g_dbus_proxy_set_cached_property (proxy, closure->property, closure->value);
312
313         g_simple_async_result_complete (res);
314         g_object_unref (proxy);
315         g_object_unref (res);
316 }
317
318 void
319 _secret_util_set_property (GDBusProxy *proxy,
320                            const gchar *property,
321                            GVariant *value,
322                            gpointer result_tag,
323                            GCancellable *cancellable,
324                            GAsyncReadyCallback callback,
325                            gpointer user_data)
326 {
327         GSimpleAsyncResult *res;
328         SetClosure *closure;
329
330         g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
331
332         res = g_simple_async_result_new (G_OBJECT (proxy), callback, user_data, result_tag);
333         closure = g_slice_new0 (SetClosure);
334         closure->property = g_strdup (property);
335         closure->value = g_variant_ref_sink (value);
336         g_simple_async_result_set_op_res_gpointer (res, closure, set_closure_free);
337
338         g_dbus_connection_call (g_dbus_proxy_get_connection (proxy),
339                                 g_dbus_proxy_get_name (proxy),
340                                 g_dbus_proxy_get_object_path (proxy),
341                                 SECRET_PROPERTIES_INTERFACE,
342                                 "Set",
343                                 g_variant_new ("(ssv)",
344                                                g_dbus_proxy_get_interface_name (proxy),
345                                                property,
346                                                closure->value),
347                                 G_VARIANT_TYPE ("()"),
348                                 G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
349                                 cancellable, on_set_property,
350                                 g_object_ref (res));
351
352         g_object_unref (res);
353 }
354
355 gboolean
356 _secret_util_set_property_finish (GDBusProxy *proxy,
357                                   gpointer result_tag,
358                                   GAsyncResult *result,
359                                   GError **error)
360 {
361         GSimpleAsyncResult *res;
362         SetClosure *closure;
363
364         g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), result_tag), FALSE);
365         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
366
367         res = G_SIMPLE_ASYNC_RESULT (result);
368
369         if (_secret_util_propagate_error (res, error))
370                 return FALSE;
371
372         closure = g_simple_async_result_get_op_res_gpointer (res);
373         return closure->result;
374 }
375
376 gboolean
377 _secret_util_set_property_sync (GDBusProxy *proxy,
378                                 const gchar *property,
379                                 GVariant *value,
380                                 GCancellable *cancellable,
381                                 GError **error)
382 {
383         gboolean result = FALSE;
384         GVariant *retval;
385
386         g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
387         g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
388
389         g_variant_ref_sink (value);
390
391         retval = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (proxy),
392                                               g_dbus_proxy_get_name (proxy),
393                                               g_dbus_proxy_get_object_path (proxy),
394                                               SECRET_PROPERTIES_INTERFACE,
395                                               "Set",
396                                               g_variant_new ("(ssv)",
397                                                              g_dbus_proxy_get_interface_name (proxy),
398                                                              property,
399                                                              value),
400                                               G_VARIANT_TYPE ("()"),
401                                               G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
402                                               cancellable, error);
403
404         if (retval != NULL) {
405                 result = TRUE;
406                 g_variant_unref (retval);
407                 g_dbus_proxy_set_cached_property (proxy, property, value);
408         }
409
410         g_variant_unref (value);
411
412         return result;
413 }
414
415 gboolean
416 _secret_util_have_cached_properties (GDBusProxy *proxy)
417 {
418         gchar **names;
419
420         names = g_dbus_proxy_get_cached_property_names (proxy);
421         g_strfreev (names);
422
423         return names != NULL;
424 }
425
426 SecretSync *
427 _secret_sync_new (void)
428 {
429         SecretSync *sync;
430
431         sync = g_new0 (SecretSync, 1);
432
433         sync->context = g_main_context_new ();
434         sync->loop = g_main_loop_new (sync->context, FALSE);
435
436         return sync;
437 }
438
439 void
440 _secret_sync_free (gpointer data)
441 {
442         SecretSync *sync = data;
443
444         g_clear_object (&sync->result);
445         g_main_loop_unref (sync->loop);
446         g_main_context_unref (sync->context);
447 }
448
449 void
450 _secret_sync_on_result (GObject *source,
451                         GAsyncResult *result,
452                         gpointer user_data)
453 {
454         SecretSync *sync = user_data;
455         g_assert (sync->result == NULL);
456         sync->result = g_object_ref (result);
457         g_main_loop_quit (sync->loop);
458 }