Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
libreport.spec.in | 7 -
src/gtk-helpers/Makefile.am | 2 +-
src/gtk-helpers/abrt-keyring.c | 130 ----
src/gtk-helpers/event_config_dialog.c | 71 +--
src/gtk-helpers/internal_libreport_gtk.h | 15 +-
src/gtk-helpers/secrets.c | 1227 ++++++++++++++++++++++++++++++
src/gui-wizard-gtk/main.c | 2 +-
7 files changed, 1246 insertions(+), 208 deletions(-)
delete mode 100644 src/gtk-helpers/abrt-keyring.c
create mode 100644 src/gtk-helpers/secrets.c
diff --git a/libreport.spec.in b/libreport.spec.in
index f65c87d..ebe247a 100644
--- a/libreport.spec.in
+++ b/libreport.spec.in
@@ -35,13 +35,6 @@ Requires: libreport-filesystem
# FIXME: can be removed when F15 will EOLed, needs to stay in rhel6!
Requires: libreport-python
-# for rhel6
-%if 0%{?rhel} >= 6
-BuildRequires: gnome-keyring-devel
-%else
-BuildRequires: libgnome-keyring-devel
-%endif
-
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
%description
diff --git a/src/gtk-helpers/Makefile.am b/src/gtk-helpers/Makefile.am
index 188e48f..cb09a8a 100644
--- a/src/gtk-helpers/Makefile.am
+++ b/src/gtk-helpers/Makefile.am
@@ -10,7 +10,7 @@ lib_LTLIBRARIES = \
libreport_gtk_la_SOURCES = \
event_config_dialog.c \
- abrt-keyring.c \
+ secrets.c \
hyperlinks.c \
autowrapped_label.c
diff --git a/src/gtk-helpers/abrt-keyring.c b/src/gtk-helpers/abrt-keyring.c
deleted file mode 100644
index 4e830ca..0000000
--- a/src/gtk-helpers/abrt-keyring.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- Copyright (C) 2011 ABRT Team
- Copyright (C) 2011 RedHat inc.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with this program; if not, write to the Free Software Foundation, Inc.,
- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-*/
-#include <gnome-keyring.h>
-#include "internal_libreport.h"
-#include "internal_libreport_gtk.h"
-
-static char *keyring_name;
-static bool got_keyring = 0;
-bool g_keyring_available = 1; //by default we assume that keyring is available
-
-guint32 find_keyring_item_id_for_event(const char *event_name)
-{
- GnomeKeyringAttributeList *attrs = gnome_keyring_attribute_list_new();
- GList *found = NULL;
- gnome_keyring_attribute_list_append_string(attrs, "libreportEventConfig",
event_name);
- GnomeKeyringResult result = gnome_keyring_find_items_sync(
- GNOME_KEYRING_ITEM_GENERIC_SECRET,
- attrs,
- &found);
- gnome_keyring_attribute_list_free(attrs);
-
- //let's hope 0 is not valid item_id
- guint32 item_id = 0;
- if (result != GNOME_KEYRING_RESULT_OK)
- goto ret;
- if (found)
- item_id = ((GnomeKeyringFound *)found->data)->item_id;
- ret:
- if (found)
- gnome_keyring_found_list_free(found);
- VERB2 log("keyring has %sconfiguration for event '%s'", (item_id !=
0) ? "" : "no ", event_name);
- return item_id;
-}
-
-static void abrt_keyring_load_settings(const char *event_name, event_config_t *ec)
-{
- //don't bother when we already know that keyring is not available
- if (!g_keyring_available)
- return;
-
- guint item_id = find_keyring_item_id_for_event(event_name);
- if (!item_id)
- return;
- GnomeKeyringAttributeList *attrs = NULL;
- GnomeKeyringResult result = gnome_keyring_item_get_attributes_sync(
- keyring_name,
- item_id,
- &attrs);
- if (result == GNOME_KEYRING_RESULT_OK && attrs)
- {
- VERB3 log("num attrs %i", attrs->len);
- guint index;
- for (index = 0; index < attrs->len; index++)
- {
- char *name = g_array_index(attrs, GnomeKeyringAttribute, index).name;
- VERB2 log("keyring has name '%s'", name);
- event_option_t *option = get_event_option_from_list(name, ec->options);
- if (option)
- {
- free(option->eo_value);
- option->eo_value = xstrdup(g_array_index(attrs, GnomeKeyringAttribute,
index).value.string);
- VERB2 log("added or replaced in event config:'%s=%s'",
name, option->eo_value);
- }
- }
- }
- if (attrs)
- gnome_keyring_attribute_list_free(attrs);
-}
-
-static void init_keyring()
-{
- /* Called again? */
- if (got_keyring || !g_keyring_available)
- return;
-
- if (!gnome_keyring_is_available())
- {
- g_keyring_available = 0;
- VERB1 error_msg("Cannot connect to Gnome keyring daemon");
- return;
- }
-
- GnomeKeyringResult result =
gnome_keyring_get_default_keyring_sync(&keyring_name);
- if (result != GNOME_KEYRING_RESULT_OK)
- {
- error_msg("Can't get default keyring (result:%d)", result);
- return;
- }
-
- got_keyring = 1;
- /*
- * Note: The default keyring name can be NULL. It is a valid name.
- */
- VERB2 log("keyring:'%s'", keyring_name);
-}
-
-static void load_event_config(gpointer key, gpointer value, gpointer user_data)
-{
- char* event_name = (char*)key;
- event_config_t *ec = (event_config_t *)value;
- VERB2 log("loading event '%s' configuration from keyring",
event_name);
- abrt_keyring_load_settings(event_name, ec);
-}
-
-/*
- * Tries to load settings for all events in g_event_config_list
-*/
-void load_event_config_data_from_keyring(void)
-{
- init_keyring();
- if (!got_keyring)
- return;
- g_hash_table_foreach(g_event_config_list, &load_event_config, NULL);
-}
diff --git a/src/gtk-helpers/event_config_dialog.c
b/src/gtk-helpers/event_config_dialog.c
index 5a564fe..190dad1 100644
--- a/src/gtk-helpers/event_config_dialog.c
+++ b/src/gtk-helpers/event_config_dialog.c
@@ -17,7 +17,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <gtk/gtk.h>
-#include <gnome-keyring.h>
#include "internal_libreport_gtk.h"
static GtkWindow *g_event_list_window;
@@ -298,63 +297,6 @@ static void dehydrate_config_dialog()
g_list_foreach(option_widget_list, &save_value_from_widget, NULL);
}
-static void save_settings_to_keyring(const char *event_name)
-{
- //don't bother when we already know that keyring is not available
- if (!g_keyring_available)
- return;
- char *keyring_name = NULL;
- GnomeKeyringResult result =
gnome_keyring_get_default_keyring_sync(&keyring_name);
- if (result != GNOME_KEYRING_RESULT_OK)
- {
- error_msg("Can't get default keyring (result:%d)", result);
- return;
- }
-
- const char *store_passwords_s = get_user_setting("store_passwords");
- bool store_passwords = !(store_passwords_s && !strcmp(store_passwords_s,
"no"));
-
- GnomeKeyringAttributeList *attrs = gnome_keyring_attribute_list_new();
- event_config_t *ec = get_event_config(event_name);
- /* add string id which we use to search for items */
- gnome_keyring_attribute_list_append_string(attrs, "libreportEventConfig",
event_name);
- GList *l;
- for (l = g_list_first(ec->options); l != NULL; l = g_list_next(l))
- {
- event_option_t *op = (event_option_t *)l->data;
- gnome_keyring_attribute_list_append_string(attrs, op->eo_name,
- (!store_passwords && op->eo_type == OPTION_TYPE_PASSWORD) ?
"" : op->eo_value);
- }
-
- guint32 item_id = find_keyring_item_id_for_event(event_name);
- if (item_id)
- {
- /* found existing item, so just update the values */
- result = gnome_keyring_item_set_attributes_sync(keyring_name, item_id, attrs);
- VERB2 log("updated item with id: %i", item_id);
- }
- else
- {
- /* did't find existing item, so create a new one */
- result = gnome_keyring_item_create_sync(keyring_name,
- GNOME_KEYRING_ITEM_GENERIC_SECRET, /* type */
- event_name, /* display name */
- attrs, /* attributes */
- "", /* secret - no special handling for
password it's stored in attrs */
- 1, /* update if exist */
- &item_id);
- VERB2 log("created new item with id: %i", item_id);
- }
- gnome_keyring_attribute_list_free(attrs);
-
- if (result != GNOME_KEYRING_RESULT_OK)
- {
- error_msg("Error saving event '%s' configuration to keyring",
event_name);
- return;
- }
- VERB2 log("saved event '%s' configuration to keyring",
event_name);
-}
-
int show_event_config_dialog(const char *event_name, GtkWindow *parent)
{
if (option_widget_list != NULL)
@@ -425,14 +367,14 @@ int show_event_config_dialog(const char *event_name, GtkWindow
*parent)
if (g_list_length(gtk_container_get_children(GTK_CONTAINER(g_adv_option_table))) >
0)
gtk_box_pack_start(GTK_BOX(content), adv_expander, false, false, 0);
- /* add warning if keyring is not available showing the nagging dialog
+ /* add warning if secrets service is not available showing the nagging dialog
* is considered "too heavy UI" be designers
*/
- if (!g_keyring_available)
+ if (!is_event_config_user_storage_available())
{
GtkWidget *keyring_warn_lbl =
gtk_label_new(
- _("Gnome Keyring is not available, your settings won't be
saved!"));
+ _("Secret Service is not available, your settings won't be
saved!"));
static const GdkColor red = { .red = 0xffff };
gtk_widget_modify_fg(keyring_warn_lbl, GTK_STATE_NORMAL, &red);
gtk_box_pack_start(GTK_BOX(content), keyring_warn_lbl, false, false, 0);
@@ -444,7 +386,10 @@ int show_event_config_dialog(const char *event_name, GtkWindow
*parent)
if (result == GTK_RESPONSE_APPLY)
{
dehydrate_config_dialog();
- save_settings_to_keyring(event_name);
+ const char *const store_passwords_s =
get_user_setting("store_passwords");
+ save_event_config_data_to_user_storage(event_name,
+ get_event_config(event_name),
+ !(store_passwords_s &&
!strcmp(store_passwords_s, "no")));
}
//else if (result == GTK_RESPONSE_CANCEL)
// log("log");
@@ -460,7 +405,7 @@ void show_events_list_dialog(GtkWindow *parent)
if (g_event_config_list == NULL)
{
load_event_config_data();
- load_event_config_data_from_keyring();
+ load_event_config_data_from_user_storage(g_event_config_list);
}
GtkWidget *event_list_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
diff --git a/src/gtk-helpers/internal_libreport_gtk.h
b/src/gtk-helpers/internal_libreport_gtk.h
index 092bfad..dd9ff87 100644
--- a/src/gtk-helpers/internal_libreport_gtk.h
+++ b/src/gtk-helpers/internal_libreport_gtk.h
@@ -27,19 +27,22 @@
extern "C" {
#endif
-extern bool g_keyring_available;
-
#define make_label_autowrap_on_resize libreport_make_label_autowrap_on_resize
void make_label_autowrap_on_resize(GtkLabel *label);
#define show_events_list_dialog libreport_show_events_list_dialog
void show_events_list_dialog(GtkWindow *parent);
-#define load_event_config_data_from_keyring
libreport_load_event_config_data_from_keyring
-void load_event_config_data_from_keyring(void);
+#define is_event_config_user_storage_available
libreport_is_event_config_user_storage_available
+bool is_event_config_user_storage_available();
+
+#define load_event_config_data_from_user_storage
libreport_load_event_config_data_from_user_storage
+void load_event_config_data_from_user_storage(GHashTable *event_config_list);
-#define find_keyring_item_id_for_event libreport_find_keyring_item_id_for_event
-guint32 find_keyring_item_id_for_event(const char *event_name);
+#define save_event_config_data_to_user_storage
libreport_save_event_config_data_to_user_storage
+void save_event_config_data_to_user_storage(const char *event_name,
+ const event_config_t *event_config,
+ bool store_password);
#define show_event_config_dialog libreport_show_event_config_dialog
int show_event_config_dialog(const char *event_name, GtkWindow *parent);
diff --git a/src/gtk-helpers/secrets.c b/src/gtk-helpers/secrets.c
new file mode 100644
index 0000000..b03ab8d
--- /dev/null
+++ b/src/gtk-helpers/secrets.c
@@ -0,0 +1,1227 @@
+/*
+ Copyright (C) 2012 ABRT Team
+ Copyright (C) 2012 RedHat inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+#include "internal_libreport.h"
+#include "internal_libreport_gtk.h"
+
+#include <gio/gio.h>
+
+#define SECRETS_BUS "org.freedesktop.secrets"
+#define SECRETS_NAME_SPACE(interface) "org.freedesktop.Secret."interface
+
+/* label and alias have to be same because of ksecrets */
+#define SECRETS_COLLECTION_LABEL SECRETS_COLLECTION_ALIAS
+#define SECRETS_COLLECTION_ALIAS "default"
+
+#define SECRETS_SEARCH_ATTRIBUTE "libreportEventConfig"
+
+/* 5s timeout*/
+#define SECRETS_CALL_DEFAULT_TIMEOUT 5000
+
+/* Well known errors for which we have workarounds */
+#define NOT_IMPLEMENTED_READ_ALLIAS_ERROR_MESSAGE
"GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such method
'ReadAlias' in interface 'org.freedesktop.Secret.Service' at object path
'/org/freedesktop/secrets' (signature 's')"
+#define INVALID_PROPERTIES_ARGUMENTS
"GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Invalid properties
argument"
+
+
+enum secrets_bus_state
+{
+ SBS_CREATED, /* after instantiation */
+ SBS_INITIALIZED, /* after dbus initialization */
+ SBS_CONNECTED, /* after opening a session */
+ SBS_CLOSED, /* after closing session and detaching from bus */
+ SBS_UNAVAILABLE, /* dbus initialization failed at beginig */
+};
+
+struct secrets_bus;
+
+struct secrets_bus_object
+{
+ struct secrets_bus *bus;
+ GDBusProxy *proxy;
+ GDBusProxy *property_proxy;
+ const gchar *interface_name;
+};
+
+struct secrets_bus
+{
+ /* loop context */
+ GMainContext *context;
+
+ /* loop for receiving signals */
+ GMainLoop *loop;
+
+ /* Glib DBus object org.freedesktop.secrets */
+ GDBusConnection *connection;
+
+ /* State of the bus */
+ enum secrets_bus_state state;
+
+ /* xorg.freedesktop.Secret.Service interface object */
+ struct secrets_bus_object *service;
+
+ /* xorg.freedesktop.Secret.Session interface object */
+ GDBusProxy *session;
+};
+
+static void secrets_bus_error(struct secrets_bus* bus,
+ GError* error,
+ const char *comment);
+
+static GError *secrets_service_new(struct secrets_bus *bus,
+ struct secrets_bus_object **out_service);
+
+/*******************************************************************************/
+/* struct secrets_bus_object */
+/*******************************************************************************/
+
+static void secrets_bus_object_new_from_proxy(struct secrets_bus_object **out_obj,
+ struct secrets_bus *bus,
+ GDBusProxy *proxy)
+{
+ *out_obj = xmalloc(sizeof(**out_obj));
+ (*out_obj)->bus = bus;
+ (*out_obj)->proxy = proxy;
+ (*out_obj)->property_proxy = NULL;
+ (*out_obj)->interface_name = g_dbus_proxy_get_interface_name(proxy);
+}
+
+static GError *secrets_bus_object_new(struct secrets_bus_object **out_obj,
+ struct secrets_bus *bus,
+ const gchar *path,
+ const gchar *interface)
+{
+ GError *error = NULL;
+ GDBusProxy *const proxy = g_dbus_proxy_new_sync(bus->connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ SECRETS_BUS,
+ path,
+ interface,
+ NULL,
+ &error);
+
+ if (!error)
+ secrets_bus_object_new_from_proxy(out_obj, bus, proxy);
+
+ return error;
+}
+
+static GError *secrets_bus_object_change_path(struct secrets_bus_object *obj,
+ const gchar *path)
+{
+ GError *error = NULL;
+ GDBusProxy *const proxy = g_dbus_proxy_new_sync(obj->bus->connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ SECRETS_BUS,
+ path,
+ obj->interface_name,
+ NULL,
+ &error);
+
+ if (!error)
+ {
+ if (obj->proxy)
+ g_object_unref(obj->proxy);
+
+ obj->proxy = proxy;
+ }
+
+ return error;
+}
+
+static void secrets_bus_object_delete(struct secrets_bus_object *obj)
+{
+ if (obj->proxy)
+ g_object_unref(obj->proxy);
+
+ if (obj->property_proxy)
+ g_object_unref(obj->property_proxy);
+
+ free(obj);
+}
+
+static GError *secrets_bus_object_set_dbus_property(struct secrets_bus_object *obj,
+ const char *property,
+ GVariant *value)
+{
+ GError *error = NULL;
+ if (!obj->property_proxy)
+ {
+ obj->property_proxy = g_dbus_proxy_new_sync(obj->bus->connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ SECRETS_BUS,
+
g_dbus_proxy_get_object_path(obj->proxy),
+
"org.freedesktop.DBus.Properties",
+ NULL,
+ &error);
+
+ if (error)
+ return error;
+ }
+
+ GVariant *const ret = g_dbus_proxy_call_sync(obj->property_proxy,
+ "Set",
+ g_variant_new("(ssv)",
+ obj->interface_name,
+ property,
+ value),
+ G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL,
+ &error);
+
+ if (ret)
+ g_variant_unref(ret);
+
+ return error;
+}
+
+/*******************************************************************************/
+/* struct secrets_bus */
+/*******************************************************************************/
+
+/* DBus session bus */
+/* Believe that global data is set to 0 */
+static struct secrets_bus *g_secrets_bus;
+
+static struct secrets_bus *secrets_bus_instance()
+{
+ static struct secrets_bus secrets_bus = {
+ .context=NULL, /* GMainContext */
+ .loop=NULL, /* GMainLoop */
+ .connection=NULL, /* GDBusConnection */
+ .state=SBS_CREATED, /* enum secrets_bus_state */
+ .service=NULL, /* struct secrets_bus_object */
+ .session=NULL, /* struct secrets_bus_object */
+ };
+
+ if (!secrets_bus.context)
+ secrets_bus.context = g_main_context_get_thread_default();
+
+ if (!secrets_bus.loop)
+ secrets_bus.loop = g_main_loop_new(secrets_bus.context, FALSE);
+
+ return &secrets_bus;
+}
+
+static void secrets_bus_connect(struct secrets_bus *bus)
+{
+ GError *error = NULL;
+
+ bus->connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
+ if (bus->connection == NULL)
+ {
+ secrets_bus_error(bus, error, "failed to open connection to bus");
+ return;
+ }
+
+ error = secrets_service_new(bus, &bus->service);
+ if (error)
+ {
+ secrets_bus_error(bus, error, "failed to create service");
+ return;
+ }
+
+ GVariant *const alg_in = g_variant_new_string("");
+ GVariant *const args = g_variant_new("(sv)", "plain", alg_in);
+ GVariant *const ret = g_dbus_proxy_call_sync(bus->service->proxy,
+ "OpenSession",
+ args,
+ G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL,
+ &error);
+
+ g_variant_unref(alg_in);
+
+ if (error)
+ {
+ secrets_bus_error(bus, error, "cannot open session secrets session");
+ return;
+ }
+
+ GVariant *const var = g_variant_get_child_value(ret, 1);
+ g_variant_unref(ret);
+
+ const gchar *const session_path = g_variant_get_string(var, NULL);
+ bus->session = g_dbus_proxy_new_sync(bus->connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ SECRETS_BUS,
+ session_path,
+ SECRETS_NAME_SPACE("Session"),
+ NULL,
+ &error);
+
+ g_variant_unref(var);
+
+ if (error)
+ {
+ secrets_bus_error(bus, error, "cannot create Proxy for session");
+ return;
+ }
+
+ bus->state = SBS_CONNECTED;
+
+ return;
+}
+
+static void secrets_bus_close(struct secrets_bus *bus)
+{
+ switch (bus->state)
+ {
+ case SBS_CLOSED:
+ case SBS_UNAVAILABLE:
+ /* return because nothing to do */
+ return;
+ case SBS_CREATED:
+ /* no return because we want to set bus as closed */
+ break;
+ case SBS_CONNECTED:
+ {
+ GError *error = NULL;
+ GVariant *ret = g_dbus_proxy_call_sync(bus->session,
+ "Close",
+ g_variant_new("()"),
+ G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL,
+ &error);
+
+ if (error)
+ {
+ VERB1 log("error on closing session : %s\n",
error->message);
+ g_error_free(error);
+ }
+ else
+ g_variant_unref(ret);
+
+ g_object_unref(bus->session);
+ bus->session = NULL;
+
+ if (bus->service)
+ {
+ secrets_bus_object_delete(bus->service);
+ bus->service = NULL;
+ }
+
+ g_object_unref(bus->connection);
+ }
+ break;
+ default:
+ /* assert(!"Missing bus state handler");*/
+ log("Missing bus state handler");
+ break;
+ }
+
+ bus->state = SBS_CLOSED;
+}
+
+static void secrets_bus_set_unavailable(struct secrets_bus *bus)
+{
+ secrets_bus_close(bus);
+
+ bus->state = SBS_UNAVAILABLE;
+}
+
+static void secrets_bus_error(struct secrets_bus* bus,
+ GError* error,
+ const char *comment)
+{
+ if (comment)
+ {
+ log("%s : %s\n", comment, error->message);
+ }
+ else
+ {
+ log("%s\n", error->message);
+ }
+
+ g_error_free(error);
+ secrets_bus_set_unavailable(bus);
+}
+
+static struct secrets_bus *get_secrets_bus()
+{
+ if (g_secrets_bus == NULL)
+ {
+ g_secrets_bus = secrets_bus_instance();
+ secrets_bus_connect(g_secrets_bus);
+ }
+
+ return g_secrets_bus;
+}
+
+static int is_secrets_bus_available(const struct secrets_bus *bus)
+{
+ return bus->state != SBS_UNAVAILABLE;
+}
+
+/*******************************************************************************/
+/* org.freedesktop.Secret.Prompt */
+/*******************************************************************************/
+
+struct prompt_source
+{
+ GSource source;
+ GDBusProxy *prompt_proxy;
+ GError *error;
+ GMainLoop *loop;
+};
+
+struct prompt_result
+{
+ gboolean dismissed;
+ GVariant *value;
+};
+
+struct prompt_call_back_args
+{
+ struct prompt_result *result;
+ GMainLoop *loop;
+};
+
+static void prompt_quit_loop(GMainLoop* loop)
+{
+ if (g_main_loop_is_running(loop))
+ g_main_loop_quit(loop);
+}
+
+static gboolean prompt_g_idle_prepare(GSource *source_data, gint *timeout)
+{
+ return TRUE;
+}
+
+static gboolean prompt_g_idle_check(GSource *source)
+{
+ return TRUE;
+}
+
+static gboolean prompt_g_idle_dispatch(GSource *source, GSourceFunc callback, gpointer
user_data)
+{
+ struct prompt_source *const prompt_source = (struct prompt_source *)source;
+ GDBusProxy *const prompt_proxy = prompt_source->prompt_proxy;
+ GVariant *const args = g_variant_new("(s)","");
+
+ GVariant *const ret = g_dbus_proxy_call_sync(prompt_proxy,
+ "Prompt",
+ args,
+ G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL,
+ &prompt_source->error);
+
+ if (prompt_source->error)
+ prompt_quit_loop(prompt_source->loop);
+ else
+ g_variant_unref(ret);
+
+ /* always return FALSE, it means that this dispatch is to be removed from idle loop
*/
+ return FALSE;
+}
+
+static void prompt_call_back(GDBusConnection *connection, const gchar *sender_name,
+ const gchar *object_path, const gchar *interface_name,
+ const gchar *signal_name, GVariant *parameters,
+ gpointer user_data)
+{
+ struct prompt_call_back_args *const args = (struct prompt_call_back_args
*)user_data;
+ GVariant *const result = NULL;
+
+ g_variant_get(parameters, "(bv)", &args->result->dismissed,
&result);
+
+ if (!args->result->dismissed)
+ args->result->value = result;
+ else
+ g_variant_unref(result);
+
+ prompt_quit_loop(args->loop);
+}
+
+static GError *secrets_prompt_prompt(const struct secrets_bus *bus,
+ const char *prompt_path,
+ struct prompt_result *result)
+{
+ static GSourceFuncs idle_funcs = { .prepare=prompt_g_idle_prepare,
+ .check=prompt_g_idle_check,
+ .dispatch=prompt_g_idle_dispatch,
+ .finalize=NULL,
+ .closure_callback=NULL,
+ .closure_marshal=NULL };
+
+ GError *error = NULL;
+ GDBusProxy *const prompt_proxy = g_dbus_proxy_new_sync(bus->connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ SECRETS_BUS,
+ prompt_path,
+
SECRETS_NAME_SPACE("Prompt"),
+ NULL,
+ &error);
+
+ if (error)
+ return error;
+
+ struct prompt_call_back_args args = {.result=result, .loop=bus->loop};
+ const guint signal_ret = g_dbus_connection_signal_subscribe(bus->connection,
+ SECRETS_BUS,
+
SECRETS_NAME_SPACE("Prompt"),
+ "Completed",
+ prompt_path,
+ NULL,
+
G_DBUS_SIGNAL_FLAGS_NONE,
+ prompt_call_back,
+ &args,
+ NULL);
+
+ /* prepare prompt source */
+ struct prompt_source *const prompt_source =
+ (struct prompt_source*)g_source_new(&idle_funcs, sizeof(*prompt_source));
+ prompt_source->prompt_proxy = prompt_proxy;
+ prompt_source->error = NULL;
+
+ g_source_attach((GSource*)prompt_source, bus->context);
+
+ g_main_loop_run(bus->loop);
+
+ /* save error */
+ error = prompt_source->error;
+
+ /* destroy prompt source */
+ g_object_unref(prompt_proxy);
+ g_source_destroy((GSource*)prompt_source);
+
+ g_dbus_connection_signal_unsubscribe(bus->connection, signal_ret);
+
+ return NULL;
+}
+
+/*******************************************************************************/
+/* org.freedesktop.Secret.Service */
+/*******************************************************************************/
+
+static GError* secrets_service_new(struct secrets_bus *bus,
+ struct secrets_bus_object **out_service)
+{
+ return secrets_bus_object_new(out_service,
+ bus,
+ "/org/freedesktop/secrets",
+ SECRETS_NAME_SPACE("Service"));
+}
+
+static GError* secrets_service_unlock(const struct secrets_bus_object *service,
+ const gchar *const *objects,
+ GVariant **out_unlocked,
+ gboolean *out_dismissed)
+{
+ GError *error = NULL;
+ GVariant *const args = g_variant_new("(^ao)", objects);
+ GVariant *const ret = g_dbus_proxy_call_sync(service->proxy,
+ "Unlock",
+ args,
+ G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL,
+ &error);
+
+ if (error)
+ return error;
+
+ gchar *prompt;
+ GVariant *result;;
+
+ g_variant_get(ret, "(@aoo)", &result, &prompt);
+
+ if (out_unlocked)
+ *out_unlocked = result;
+ else
+ g_variant_unref(result);
+
+ if (prompt && strcmp(prompt, "/"))
+ {
+ struct prompt_result completed_result = {.dismissed=FALSE, .value=NULL};
+ error = secrets_prompt_prompt(service->bus, prompt, &completed_result);
+
+ if (!error)
+ {
+ if (out_dismissed)
+ *out_dismissed = completed_result.dismissed;
+
+ if (!completed_result.dismissed)
+ {
+ g_variant_unref(*out_unlocked);
+
+ if (out_unlocked)
+ *out_unlocked = completed_result.value;
+ }
+ }
+ }
+
+ g_variant_unref(ret);
+
+ return error;
+}
+
+static GError* secrets_service_unlock_object(const struct secrets_bus_object *service,
+ struct secrets_bus_object *obj,
+ gboolean *out_dismissed)
+{
+ const gchar *const locked[] = {g_dbus_proxy_get_object_path(obj->proxy), NULL};
+ GVariant *result = NULL;
+ GError *error = secrets_service_unlock(service, locked, &result, out_dismissed);
+
+ if (!error && !*out_dismissed && result)
+ {
+ gsize length;
+ const gchar *const *unlocked = g_variant_get_objv(result, &length);
+
+ /* ksecrets doesn't set dismissed correctly */
+ if (length)
+ {
+ error = secrets_bus_object_change_path(obj, *unlocked);
+ g_free((gpointer)unlocked);
+ }
+ else
+ *out_dismissed = TRUE;
+
+ g_variant_unref(result);
+ }
+
+ return error;
+}
+
+/*
+ * KSecretsService doesn't implement ReadAlias
+ */
+static GError *secrets_service_find_collection(const struct secrets_bus_object *service,
+ const char *alias,
+ struct secrets_bus_object
**out_collection)
+{
+ GError *error = NULL;
+ GDBusProxy *properties = g_dbus_proxy_new_sync(service->bus->connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ SECRETS_BUS,
+
g_dbus_proxy_get_object_path(service->proxy),
+
"org.freedesktop.DBus.Properties",
+ NULL,
+ &error);
+
+ if (error)
+ return error;
+
+ GVariant *prop = g_dbus_proxy_call_sync(properties,
+ "Get",
+ g_variant_new("(ss)",
+
SECRETS_NAME_SPACE("Service"),
+ "Collections"),
+ G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL,
+ &error);
+
+ g_object_unref(properties);
+
+ /* NULL means that collection wasn't found */
+ *out_collection = NULL;
+
+ if (error)
+ return error;
+
+ GVariant *const value = g_variant_get_child_value(prop,0);
+ GVariant *const list = g_variant_get_child_value(value,0);
+ GVariantIter *iter;
+ char *path;
+
+ g_variant_get(g_variant_get_child_value(value,0), "ao", &iter);
+
+ while (g_variant_iter_loop(iter, "o", &path))
+ {
+ GDBusProxy *collection_proxy = g_dbus_proxy_new_sync(
+ service->bus->connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ SECRETS_BUS,
+ path,
+ SECRETS_NAME_SPACE("Collection"),
+ NULL,
+ &error);
+
+ if (error)
+ break;
+
+ GVariant *const lbl_var = g_dbus_proxy_get_cached_property(collection_proxy,
+ "Label");
+
+ const gchar *const label = g_variant_get_string(lbl_var, NULL);
+ const int found = label && (strcmp(label, alias) == 0);
+
+ /* found is introduced because of break if collecion is found */
+ /* and I want to write the following statement just once */
+ /* the label variable is invalid after the following statement */
+ g_variant_unref(lbl_var);
+
+ if (found)
+ {
+ secrets_bus_object_new_from_proxy(out_collection,
+ service->bus,
+ collection_proxy);
+ break;
+ }
+
+ g_object_unref(collection_proxy);
+ }
+
+ g_variant_iter_free(iter);
+ g_variant_unref(list);
+ g_variant_unref(value);
+ g_variant_unref(prop);
+
+ return error;
+}
+
+static GError *secrets_service_read_allias(const struct secrets_bus_object *service,
+ const char *alias,
+ struct secrets_bus_object **out_collection)
+{
+ GError *error = NULL;
+ GVariant *const ret = g_dbus_proxy_call_sync(service->proxy,
+ "ReadAlias",
+ g_variant_new("(s)",
+ alias),
+ G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL,
+ &error);
+
+ if (!error)
+ {
+ GVariant *const obj_path = g_variant_get_child_value(ret, 0);
+ const gchar* const coll_path = g_variant_get_string(obj_path, NULL);
+
+ if (strcmp(coll_path,"/"))
+ {
+ error = secrets_bus_object_new(out_collection,
+ service->bus,
+ coll_path,
+ SECRETS_NAME_SPACE("Collection"));
+ }
+
+ g_variant_unref(obj_path);
+ g_variant_unref(ret);
+ }
+ else
+ {
+ /* ksecrets doesn't implement ReadAlias, thus search by label is performed
*/
+ if (!strcmp(error->message, NOT_IMPLEMENTED_READ_ALLIAS_ERROR_MESSAGE))
+ {
+ VERB1 log("ReadAlias failed, trying to search on the client side :
%s\n", error->message);
+ g_error_free(error);
+ error = secrets_service_find_collection(service, alias, out_collection);
+ }
+ }
+
+ return error;
+}
+
+static GError *secrets_service_create_collection(struct secrets_bus_object *service,
+ const gchar *label,
+ const gchar *alias,
+ struct secrets_bus_object
**out_collection,
+ gboolean *out_dismissed)
+{
+ GVariantBuilder *const prop_builder =
+ g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
+
+ g_variant_builder_add(prop_builder,
+ "{sv}",
+ "org.freedesktop.Secret.Collection.Label",
+ g_variant_new_string(label) );
+
+ GVariant *const call_args = g_variant_new("(@a{sv}s)",
+ g_variant_builder_end(prop_builder),
+ alias);
+
+ GError* error = NULL;
+ GVariant *const ret = g_dbus_proxy_call_sync(service->proxy,
+ "CreateCollection",
+ call_args,
+ G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL,
+ &error);
+
+ *out_dismissed = FALSE;
+
+ if (error)
+ return error;
+
+ gchar *prompt;
+ GVariant *collection_var;
+
+ g_variant_get(ret, "(@oo)", &collection_var, &prompt);
+
+ if (prompt && strcmp(prompt, "/"))
+ {
+ g_variant_unref(collection_var);
+ collection_var = NULL;
+
+ struct prompt_result completed_result = {.dismissed=FALSE, .value=NULL};
+ error = secrets_prompt_prompt(service->bus, prompt, &completed_result);
+
+ *out_dismissed = completed_result.dismissed;
+
+ if (!error && !completed_result.dismissed)
+ collection_var = completed_result.value;
+ }
+
+ if (collection_var)
+ {
+ gsize length;
+ const gchar *const coll_path = g_variant_get_string(collection_var,
&length);
+
+ /* ksecrets doens't properly set dismissed */
+ if (length)
+ {
+ error = secrets_bus_object_new(out_collection,
+ service->bus,
+ coll_path,
+ SECRETS_NAME_SPACE("Collection"));
+ }
+ else
+ *out_dismissed = TRUE;
+
+ g_variant_unref(collection_var);
+ }
+
+ g_variant_unref(ret);
+
+ return error;
+}
+
+/*******************************************************************************/
+/* org.freedesktop.Secret.Collection */
+/*******************************************************************************/
+
+static GVariant *create_item_call_args(const char *event_name,
+ GVariant *attributes,
+ GDBusProxy *session,
+ bool full_property_name)
+{
+ /* ksecrets accepts properties without namespace */
+ /* gnome-keyring accepts only with namespace */
+ const char *const lbl_name = full_property_name ?
SECRETS_NAME_SPACE("Item.Label")
+ : "Label";
+ const char *const att_name = full_property_name ?
SECRETS_NAME_SPACE("Item.Attributes")
+ : "Attributes";
+
+ GVariantBuilder *const prop_builder =
+ g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
+
+ g_variant_builder_add(prop_builder,
+ "{sv}",
+ lbl_name,
+ g_variant_new_string(event_name) );
+
+ g_variant_builder_add(prop_builder,
+ "{sv}",
+ att_name,
+ attributes);
+
+ GVariantBuilder *const param_builder =
g_variant_builder_new(G_VARIANT_TYPE("ay"));
+ GVariantBuilder *const value_builder =
g_variant_builder_new(G_VARIANT_TYPE("ay"));
+
+ GVariant *const secret = g_variant_new("(o@ay@ays)",
+ g_dbus_proxy_get_object_path(session),
+ g_variant_builder_end(param_builder),
+ g_variant_builder_end(value_builder),
+ "text/plain, charset=utf8");
+
+ return g_variant_new("(@a{sv}@(oayays)b)",
+ g_variant_builder_end(prop_builder),
+ secret,
+ FALSE);
+}
+
+static GError *secrets_collection_create_text_item(struct secrets_bus_object
*collection,
+ const char *event_name,
+ GVariant *attributes)
+{
+ GError* error = NULL;
+ GVariant *call_args, *ret;
+
+ /* ksecrets silently drops properties with full names */
+ /* gnome-keyring returns an error if a property key is not full property name */
+ /* the first iteration sends property names without namespace */
+ /* if NO error was returned service is ksecrets and everything is ok */
+ /* if error was returned service is gnome-keyring and and the second iteration */
+ /* must be performed */
+ /* the second iteration sends property names with namespace */
+ static bool const options[] = {FALSE, TRUE};
+ for (size_t choice = 0; choice < sizeof(options)/sizeof(*options); ++choice)
+ {
+ if (error)
+ { /* this code is here because I want to return an error */
+ /* it cannot be on the end of the loop because I need unfreed error after the
last iteration */
+ g_error_free(error);
+ error = NULL;
+ }
+
+ call_args = create_item_call_args(event_name,
+ g_variant_ref(attributes),
+ collection->bus->session,
+ options[choice]);
+
+ ret = g_dbus_proxy_call_sync(collection->proxy,
+ "CreateItem",
+ call_args,
+ G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL,
+ &error);
+
+ if (!error)
+ {
+ gchar *prompt, *item;
+
+ g_variant_get(ret, "(oo)", &item, &prompt);
+
+ if (prompt && strcmp(prompt, "/"))
+ {
+ struct prompt_result completed_result = {.dismissed=FALSE, .value=NULL};
+ error = secrets_prompt_prompt(collection->bus, prompt,
&completed_result);
+
+ /* don't care about result, just perform clean up */
+ if (completed_result.value)
+ g_variant_unref(completed_result.value);
+ }
+
+ g_variant_unref(ret);
+
+ break;
+ }
+ else if (strcmp(INVALID_PROPERTIES_ARGUMENTS, error->message))
+ break; /* if the error wasn't about invalid properties we have an another
problem */
+
+ VERB2 log("CreateItem failed, trying to use proporties with full names :
%s\n", error->message);
+ }
+
+ g_variant_unref(attributes);
+
+ return error;
+}
+
+/*
+ * Performs org.freedesktop.Secret.Collection.SearchItems and returns the first
+ * item from result. A found item can be possibly locked.
+ */
+static GError *secrets_collection_search_one_item(const struct secrets_bus_object
*collection,
+ GVariant *search_attrs,
+ struct secrets_bus_object **out_item)
+{
+ GError *error = NULL;
+ GVariant *const value = g_dbus_proxy_call_sync(collection->proxy,
+ "SearchItems",
+ g_variant_new("(@a{ss})",
+ search_attrs),
+ G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL,
+ &error);
+
+ if (error)
+ return error;
+
+ /* gnome-keyring returns (unlocked,locked) */
+ /* ksecretsservice returns (unlocked) */
+ /* all childs has to be taken into account */
+ const gsize n_results = g_variant_n_children(value);
+ for(gsize child = 0; child < n_results; ++child)
+ {
+ if (error)
+ {
+ VERB1 log("search items result error : %s", error->message);
+ free(error);
+ error = NULL;
+ }
+
+ GVariant *const paths = g_variant_get_child_value(value, 0);
+ const gchar *const *item_paths = g_variant_get_objv(paths, NULL);
+
+ /* the first found object path is to be returned */
+ if (*item_paths)
+ error = secrets_bus_object_new(out_item,
+ collection->bus,
+ *item_paths,
+ SECRETS_NAME_SPACE("Item"));
+
+ g_free((gpointer)item_paths);
+ g_variant_unref(paths);
+ }
+
+ g_variant_unref(value);
+
+ return error;
+}
+
+/*******************************************************************************/
+/* utility functions */
+/*******************************************************************************/
+
+static GError *get_unlocked_collection(const struct secrets_bus_object *service,
+ const char *alias,
+ struct secrets_bus_object **out_collection,
+ gboolean *out_dismissed)
+{
+ struct secrets_bus_object *collection = NULL;
+ GError *error = secrets_service_read_allias(service, alias, &collection);
+
+ if (!error && collection)
+ {
+ error = secrets_service_unlock_object(service, collection, out_dismissed);
+
+ if (error || *out_dismissed)
+ {
+ secrets_bus_object_delete(collection);
+ collection = NULL;
+ }
+ }
+
+ *out_collection = collection;
+ return error;
+}
+
+static GError *secrets_bus_get_default_collection(const struct secrets_bus *bus,
+ struct secrets_bus_object
**out_collection,
+ gboolean *out_dismissed)
+{
+ return get_unlocked_collection(bus->service,
+ SECRETS_COLLECTION_ALIAS,
+ out_collection,
+ out_dismissed);
+}
+
+static GError *secrets_bus_create_default_collection(const struct secrets_bus *bus,
+ struct secrets_bus_object
**out_collection,
+ gboolean *out_dismissed)
+{
+ return secrets_service_create_collection(bus->service,
+ SECRETS_COLLECTION_LABEL,
+ SECRETS_COLLECTION_ALIAS,
+ out_collection,
+ out_dismissed);
+}
+
+static void load_event_options_from_item(GList *options,
+ struct secrets_bus_object *item)
+{
+ GVariant *const attributes =
+ g_dbus_proxy_get_cached_property(item->proxy, "Attributes");
+
+ GVariantIter *iter;
+ g_variant_get(attributes, "a{ss}", &iter);
+
+ char *name, *value;
+ while (g_variant_iter_loop(iter, "{ss}", &name, &value))
+ {
+ event_option_t *const option = get_event_option_from_list(name, options);
+ if (option)
+ {
+ free(option->eo_value);
+ option->eo_value = xstrdup(value);
+ }
+ }
+
+ g_variant_unref(attributes);
+}
+
+static GVariant *create_attributes_from_options(GList *options,
+ const char *event_name,
+ bool store_passwords)
+{
+ GVariantBuilder *const attr_builder =
g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
+
+ for (GList *iter = g_list_first(options); iter; iter = g_list_next(iter))
+ { /* we store data in the search attributes */
+ event_option_t *const op = (event_option_t *)iter->data;
+ if (op->eo_type != OPTION_TYPE_PASSWORD || store_passwords)
+ g_variant_builder_add(attr_builder, "{ss}", op->eo_name,
op->eo_value);
+ }
+
+ /* and finaly, add extra attribute used for searching */
+ g_variant_builder_add(attr_builder, "{ss}", SECRETS_SEARCH_ATTRIBUTE,
event_name);
+
+ return g_variant_builder_end(attr_builder);
+}
+
+static GError *find_item_by_event_name(const struct secrets_bus_object *collection,
+ const char* event_name,
+ struct secrets_bus_object **out_item)
+{
+ GVariantBuilder *const attrs = g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
+
+ g_variant_builder_add(attrs, "{ss}", SECRETS_SEARCH_ATTRIBUTE,
event_name);
+
+ return secrets_collection_search_one_item(collection,
+ g_variant_builder_end(attrs),
+ out_item);
+}
+
+static void load_settings(struct secrets_bus *bus,
+ const char *event_name,
+ event_config_t *ec)
+{
+ gboolean dismissed = FALSE;
+ struct secrets_bus_object *default_collection = NULL;
+ GError *error = secrets_bus_get_default_collection(bus, &default_collection,
&dismissed);
+
+ if (dismissed)
+ secrets_bus_set_unavailable(bus);
+ else if (!error && default_collection)
+ {
+ struct secrets_bus_object *item = NULL;
+ error = find_item_by_event_name(default_collection, event_name, &item);
+ if (!error && item)
+ {
+ load_event_options_from_item(ec->options, item);
+ secrets_bus_object_delete(item);
+ }
+ }
+ else if (error)
+ secrets_bus_error(bus, error, NULL);
+}
+
+static void load_event_config(gpointer key, gpointer value, gpointer user_data)
+{
+ char *const event_name = (char*)key;
+ event_config_t *const ec = (event_config_t *)value;
+ struct secrets_bus *const bus = (struct secrets_bus*)user_data;
+
+ if (is_secrets_bus_available(bus))
+ load_settings(bus, event_name, ec);
+}
+
+static GError *save_options(struct secrets_bus_object *collection,
+ const char* event_name,
+ GList *options,
+ bool store_passwords)
+{
+ struct secrets_bus_object *item = NULL;
+ GError *error = find_item_by_event_name(collection, event_name, &item);
+
+ if (error)
+ return error;
+
+ GVariant *const attributes = create_attributes_from_options(options,
+ event_name,
+ store_passwords);
+
+ if (item)
+ { /* item exists */
+ error = secrets_bus_object_set_dbus_property(item,
+ "Attributes",
attributes);
+ secrets_bus_object_delete(item);
+ }
+ else /* create a new item */
+ error = secrets_collection_create_text_item(collection,
+ event_name,
+ attributes);
+
+ return error;
+}
+
+
+static void save_event_config(struct secrets_bus *bus,
+ const char *event_name,
+ GList *options,
+ bool store_passwords)
+{
+ struct secrets_bus_object *default_collection = NULL;
+ gboolean dismissed = FALSE;
+ GError *error = secrets_bus_get_default_collection(bus, &default_collection,
&dismissed);
+
+ if (!error && !dismissed)
+ {
+ if (!default_collection)
+ {
+ error = secrets_bus_create_default_collection(bus, &default_collection,
&dismissed);
+
+ if (error || dismissed)
+ goto SAVE_EVENT_CONFIG_END;
+ }
+
+ error = save_options(default_collection, event_name, options, store_passwords);
+ }
+
+SAVE_EVENT_CONFIG_END:
+
+ if (dismissed)
+ secrets_bus_set_unavailable(bus);
+
+ if (error)
+ secrets_bus_error(bus, error, NULL);
+}
+
+/******************************************************************************/
+/* Public interface */
+/******************************************************************************/
+
+bool is_event_config_user_storage_available()
+{
+ const struct secrets_bus *const bus = get_secrets_bus();
+
+ return is_secrets_bus_available(bus);
+}
+
+/*
+ * Loads event config options for passed events
+ *
+ * @param event_config_list Events configs
+ */
+void load_event_config_data_from_user_storage(GHashTable *event_config_list)
+{
+ struct secrets_bus *const bus = get_secrets_bus();
+
+ if (!is_secrets_bus_available(bus))
+ return;
+
+ g_hash_table_foreach(event_config_list, &load_event_config, bus);
+
+ return;
+}
+
+/*
+ * Saves an event_config options to some kind of session storage.
+ *
+ * @param event_name Lookup key
+ * @param event_config Event data
+ * @param store_passwords If TRUE stores options with passwords, otherwise skips them
+ */
+void save_event_config_data_to_user_storage(const char *event_name,
+ const event_config_t *event_config,
+ bool store_passwords)
+{
+ struct secrets_bus *const bus = get_secrets_bus();
+
+ if (!is_secrets_bus_available(bus))
+ return;
+
+ save_event_config(bus, event_name, event_config->options, store_passwords);
+}
diff --git a/src/gui-wizard-gtk/main.c b/src/gui-wizard-gtk/main.c
index 05d01e9..e9632c3 100644
--- a/src/gui-wizard-gtk/main.c
+++ b/src/gui-wizard-gtk/main.c
@@ -140,7 +140,7 @@ int main(int argc, char **argv)
/* load /etc/abrt/events/foo.{conf,xml} stuff
and $XDG_CACHE_HOME/abrt/events/foo.conf */
load_event_config_data();
- load_event_config_data_from_keyring();
+ load_event_config_data_from_user_storage(g_event_config_list);
load_user_settings("report-gtk");
reload_problem_data_from_dump_dir();
--
1.7.7.6