Update the "Locked" property of items/collections on lock/unlock

* Make sure this property is kept in sync so it can be used
   immediately in the logic to retrieve secrets or other stuff.
 * We don't wait for a PropertiesChanged, which may come later
This commit is contained in:
Stef Walter 2012-07-05 19:03:37 +02:00
parent 012ed7d620
commit 9c44ab0fa2
3 changed files with 99 additions and 186 deletions

View File

@ -367,179 +367,96 @@ _secret_service_decode_get_secrets_all (SecretService *self,
} }
typedef struct { typedef struct {
GCancellable *cancellable;
SecretPrompt *prompt;
GHashTable *objects; GHashTable *objects;
GPtrArray *xlocked; gchar **xlocked;
guint count;
gboolean locking;
} XlockClosure; } XlockClosure;
static void static void
xlock_closure_free (gpointer data) xlock_closure_free (gpointer data)
{ {
XlockClosure *closure = data; XlockClosure *closure = data;
g_clear_object (&closure->cancellable); g_strfreev (closure->xlocked);
g_clear_object (&closure->prompt); g_hash_table_unref (closure->objects);
if (closure->xlocked)
g_ptr_array_unref (closure->xlocked);
if (closure->objects)
g_hash_table_unref (closure->objects);
g_slice_free (XlockClosure, closure); g_slice_free (XlockClosure, closure);
} }
static void static void
on_xlock_prompted (GObject *source, on_xlock_paths (GObject *source,
GAsyncResult *result, GAsyncResult *result,
gpointer user_data) gpointer user_data)
{ {
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data); GSimpleAsyncResult *async = G_SIMPLE_ASYNC_RESULT (user_data);
XlockClosure *closure = g_simple_async_result_get_op_res_gpointer (res); XlockClosure *xlock = g_simple_async_result_get_op_res_gpointer (async);
SecretService *self = SECRET_SERVICE (source); GVariant *lockval;
GDBusProxy *object;
GError *error = NULL; GError *error = NULL;
GVariantIter iter; gint i;
GVariant *retval;
gchar *path;
retval = secret_service_prompt_finish (self, result, G_VARIANT_TYPE ("ao"), &error); xlock->count = _secret_service_xlock_paths_finish (SECRET_SERVICE (source), result,
if (error != NULL) &xlock->xlocked, &error);
g_simple_async_result_take_error (res, error);
if (retval != NULL) { if (error == NULL) {
g_variant_iter_init (&iter, retval); /*
while (g_variant_iter_loop (&iter, "o", &path)) * After a lock or unlock we want the Locked property to immediately
g_ptr_array_add (closure->xlocked, g_strdup (path)); * reflect the new state, and not have to wait for a PropertiesChanged
g_variant_unref (retval); * signal to be processed later.
} */
g_simple_async_result_complete (res); lockval = g_variant_ref_sink (g_variant_new_boolean (xlock->locking));
g_object_unref (res); for (i = 0; xlock->xlocked[i] != NULL; i++) {
} object = g_hash_table_lookup (xlock->objects, xlock->xlocked[i]);
if (object != NULL)
static void g_dbus_proxy_set_cached_property (object, "Locked", lockval);
on_xlock_called (GObject *source, }
GAsyncResult *result, g_variant_unref (lockval);
gpointer user_data)
{
GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
XlockClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
SecretService *self = SECRET_SERVICE (g_async_result_get_source_object (user_data));
const gchar *prompt = NULL;
gchar **xlocked = NULL;
GError *error = NULL;
GVariant *retval;
guint i;
retval = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), result, &error);
if (error != NULL) {
g_simple_async_result_take_error (res, error);
g_simple_async_result_complete (res);
} else { } else {
g_variant_get (retval, "(^ao&o)", &xlocked, &prompt); g_simple_async_result_take_error (async, error);
if (_secret_util_empty_path (prompt)) {
for (i = 0; xlocked[i]; i++)
g_ptr_array_add (closure->xlocked, g_strdup (xlocked[i]));
g_simple_async_result_complete (res);
} else {
closure->prompt = _secret_prompt_instance (self, prompt);
secret_service_prompt (self, closure->prompt, closure->cancellable,
on_xlock_prompted, g_object_ref (res));
}
g_strfreev (xlocked);
g_variant_unref (retval);
} }
g_object_unref (self); g_simple_async_result_complete (async);
g_object_unref (res); g_object_unref (async);
}
static GSimpleAsyncResult *
service_xlock_paths_async (SecretService *self,
const gchar *method,
const gchar **paths,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *res;
XlockClosure *closure;
res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
service_xlock_paths_async);
closure = g_slice_new0 (XlockClosure);
closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable;
closure->xlocked = g_ptr_array_new_with_free_func (g_free);
g_simple_async_result_set_op_res_gpointer (res, closure, xlock_closure_free);
g_dbus_proxy_call (G_DBUS_PROXY (self), method,
g_variant_new ("(@ao)", g_variant_new_objv (paths, -1)),
G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
cancellable, on_xlock_called, g_object_ref (res));
return res;
}
static gint
service_xlock_paths_finish (SecretService *self,
GAsyncResult *result,
gchar ***xlocked,
GError **error)
{
GSimpleAsyncResult *res;
XlockClosure *closure;
gint count;
res = G_SIMPLE_ASYNC_RESULT (result);
if (g_simple_async_result_propagate_error (res, error))
return -1;
closure = g_simple_async_result_get_op_res_gpointer (res);
count = closure->xlocked->len;
if (xlocked != NULL) {
g_ptr_array_add (closure->xlocked, NULL);
*xlocked = (gchar **)g_ptr_array_free (closure->xlocked, FALSE);
closure->xlocked = NULL;
}
return count;
} }
static void static void
service_xlock_async (SecretService *self, service_xlock_async (SecretService *self,
const gchar *method, gboolean locking,
GList *objects, GList *objects,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
GSimpleAsyncResult *res; GSimpleAsyncResult *async;
XlockClosure *closure; XlockClosure *xlock;
GHashTable *table;
GPtrArray *paths; GPtrArray *paths;
const gchar *path; const gchar *path;
GList *l; GList *l;
table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref); async = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
paths = g_ptr_array_new (); service_xlock_async);
xlock = g_slice_new0 (XlockClosure);
xlock->objects = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
xlock->locking = locking;
paths = g_ptr_array_new ();
for (l = objects; l != NULL; l = g_list_next (l)) { for (l = objects; l != NULL; l = g_list_next (l)) {
path = g_dbus_proxy_get_object_path (l->data); path = g_dbus_proxy_get_object_path (l->data);
g_ptr_array_add (paths, (gpointer)path); g_ptr_array_add (paths, (gpointer)path);
g_hash_table_insert (table, g_strdup (path), g_object_ref (l->data)); g_hash_table_insert (xlock->objects, g_strdup (path), g_object_ref (l->data));
} }
g_ptr_array_add (paths, NULL); g_ptr_array_add (paths, NULL);
res = service_xlock_paths_async (self, method, (const gchar **)paths->pdata, g_simple_async_result_set_op_res_gpointer (async, xlock, xlock_closure_free);
cancellable, callback, user_data);
closure = g_simple_async_result_get_op_res_gpointer (res); _secret_service_xlock_paths_async (self, locking ? "Lock" : "Unlock",
closure->objects = table; (const gchar **)paths->pdata,
cancellable, on_xlock_paths,
g_object_ref (async));
g_ptr_array_free (paths, TRUE); g_ptr_array_free (paths, TRUE);
g_object_unref (res); g_object_unref (async);
} }
static gint static gint
@ -548,31 +465,28 @@ service_xlock_finish (SecretService *self,
GList **xlocked, GList **xlocked,
GError **error) GError **error)
{ {
XlockClosure *closure; GSimpleAsyncResult *async;
gchar **paths = NULL; XlockClosure *xlock;
GObject *object; GDBusProxy *object;
gint count; gint i;
guint i;
count = service_xlock_paths_finish (self, result, g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self), service_xlock_async), -1);
xlocked ? &paths : NULL,
error);
if (count > 0 && xlocked) { async = G_SIMPLE_ASYNC_RESULT (result);
closure = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); if (g_simple_async_result_propagate_error (async, error))
return -1;
xlock = g_simple_async_result_get_op_res_gpointer (async);
if (xlocked) {
*xlocked = NULL; *xlocked = NULL;
for (i = 0; xlock->xlocked[i] != NULL; i++) {
for (i = 0; paths[i] != NULL; i++) { object = g_hash_table_lookup (xlock->objects, xlock->xlocked[i]);
object = g_hash_table_lookup (closure->objects, paths[i]);
if (object != NULL) if (object != NULL)
*xlocked = g_list_prepend (*xlocked, g_object_ref (object)); *xlocked = g_list_prepend (*xlocked, g_object_ref (object));
} }
*xlocked = g_list_reverse (*xlocked);
} }
return count; return xlock->count;
} }
/** /**
@ -606,7 +520,7 @@ secret_service_lock (SecretService *self,
g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (SECRET_IS_SERVICE (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
service_xlock_async (self, "Lock", objects, cancellable, callback, user_data); service_xlock_async (self, TRUE, objects, cancellable, callback, user_data);
} }
/** /**
@ -631,8 +545,8 @@ secret_service_lock_finish (SecretService *self,
GList **locked, GList **locked,
GError **error) GError **error)
{ {
g_return_val_if_fail (SECRET_IS_SERVICE (self), FALSE); g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, -1);
return service_xlock_finish (self, result, locked, error); return service_xlock_finish (self, result, locked, error);
} }
@ -722,7 +636,7 @@ secret_service_unlock (SecretService *self,
g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (SECRET_IS_SERVICE (self));
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
service_xlock_async (self, "Unlock", objects, cancellable, callback, user_data); service_xlock_async (self, FALSE, objects, cancellable, callback, user_data);
} }
/** /**
@ -749,8 +663,6 @@ secret_service_unlock_finish (SecretService *self,
{ {
g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
g_return_val_if_fail (error == NULL || *error == NULL, -1); g_return_val_if_fail (error == NULL || *error == NULL, -1);
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
service_xlock_paths_async), -1);
return service_xlock_finish (self, result, unlocked, error); return service_xlock_finish (self, result, unlocked, error);
} }

View File

@ -569,7 +569,6 @@ secret_service_get_secrets_for_paths_sync (SecretService *self,
typedef struct { typedef struct {
GCancellable *cancellable; GCancellable *cancellable;
SecretPrompt *prompt; SecretPrompt *prompt;
GHashTable *objects;
GPtrArray *xlocked; GPtrArray *xlocked;
} XlockClosure; } XlockClosure;
@ -581,8 +580,6 @@ xlock_closure_free (gpointer data)
g_clear_object (&closure->prompt); g_clear_object (&closure->prompt);
if (closure->xlocked) if (closure->xlocked)
g_ptr_array_unref (closure->xlocked); g_ptr_array_unref (closure->xlocked);
if (closure->objects)
g_hash_table_unref (closure->objects);
g_slice_free (XlockClosure, closure); g_slice_free (XlockClosure, closure);
} }
@ -655,19 +652,19 @@ on_xlock_called (GObject *source,
g_object_unref (res); g_object_unref (res);
} }
static GSimpleAsyncResult * void
service_xlock_paths_async (SecretService *self, _secret_service_xlock_paths_async (SecretService *self,
const gchar *method, const gchar *method,
const gchar **paths, const gchar **paths,
GCancellable *cancellable, GCancellable *cancellable,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
GSimpleAsyncResult *res; GSimpleAsyncResult *res;
XlockClosure *closure; XlockClosure *closure;
res = g_simple_async_result_new (G_OBJECT (self), callback, user_data, res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
service_xlock_paths_async); _secret_service_xlock_paths_async);
closure = g_slice_new0 (XlockClosure); closure = g_slice_new0 (XlockClosure);
closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable; closure->cancellable = cancellable ? g_object_ref (cancellable) : cancellable;
closure->xlocked = g_ptr_array_new_with_free_func (g_free); closure->xlocked = g_ptr_array_new_with_free_func (g_free);
@ -678,14 +675,14 @@ service_xlock_paths_async (SecretService *self,
G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1,
cancellable, on_xlock_called, g_object_ref (res)); cancellable, on_xlock_called, g_object_ref (res));
return res; g_object_unref (res);
} }
static gint gint
service_xlock_paths_finish (SecretService *self, _secret_service_xlock_paths_finish (SecretService *self,
GAsyncResult *result, GAsyncResult *result,
gchar ***xlocked, gchar ***xlocked,
GError **error) GError **error)
{ {
GSimpleAsyncResult *res; GSimpleAsyncResult *res;
XlockClosure *closure; XlockClosure *closure;
@ -792,16 +789,12 @@ secret_service_lock_paths (SecretService *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
GSimpleAsyncResult *res;
g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (SECRET_IS_SERVICE (self));
g_return_if_fail (paths != NULL); g_return_if_fail (paths != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
res = service_xlock_paths_async (self, "Lock", paths, cancellable, _secret_service_xlock_paths_async (self, "Lock", paths, cancellable,
callback, user_data); callback, user_data);
g_object_unref (res);
} }
/** /**
@ -831,7 +824,7 @@ secret_service_lock_paths_finish (SecretService *self,
g_return_val_if_fail (locked != NULL, -1); g_return_val_if_fail (locked != NULL, -1);
g_return_val_if_fail (error == NULL || *error == NULL, -1); g_return_val_if_fail (error == NULL || *error == NULL, -1);
return service_xlock_paths_finish (self, result, locked, error); return _secret_service_xlock_paths_finish (self, result, locked, error);
} }
/** /**
@ -920,17 +913,13 @@ secret_service_unlock_paths (SecretService *self,
GAsyncReadyCallback callback, GAsyncReadyCallback callback,
gpointer user_data) gpointer user_data)
{ {
GSimpleAsyncResult *res;
g_return_if_fail (SECRET_IS_SERVICE (self)); g_return_if_fail (SECRET_IS_SERVICE (self));
g_return_if_fail (paths != NULL); g_return_if_fail (paths != NULL);
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
res = service_xlock_paths_async (self, "Unlock", _secret_service_xlock_paths_async (self, "Unlock",
paths, cancellable, paths, cancellable,
callback, user_data); callback, user_data);
g_object_unref (res);
} }
/** /**
@ -959,8 +948,8 @@ secret_service_unlock_paths_finish (SecretService *self,
g_return_val_if_fail (SECRET_IS_SERVICE (self), -1); g_return_val_if_fail (SECRET_IS_SERVICE (self), -1);
g_return_val_if_fail (error == NULL || *error == NULL, -1); g_return_val_if_fail (error == NULL || *error == NULL, -1);
return service_xlock_paths_finish (self, result, return _secret_service_xlock_paths_finish (self, result,
unlocked, error); unlocked, error);
} }
typedef struct { typedef struct {

View File

@ -145,6 +145,18 @@ SecretValue * _secret_service_decode_get_secrets_first (SecretService *se
GHashTable * _secret_service_decode_get_secrets_all (SecretService *self, GHashTable * _secret_service_decode_get_secrets_all (SecretService *self,
GVariant *out); GVariant *out);
void _secret_service_xlock_paths_async (SecretService *self,
const gchar *method,
const gchar **paths,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gint _secret_service_xlock_paths_finish (SecretService *self,
GAsyncResult *result,
gchar ***xlocked,
GError **error);
SecretItem * _secret_collection_find_item_instance (SecretCollection *self, SecretItem * _secret_collection_find_item_instance (SecretCollection *self,
const gchar *item_path); const gchar *item_path);