--- a/configure.ac Sun Oct 09 18:32:16 2016 -0500
+++ b/configure.ac Mon Oct 24 17:11:11 2016 -0500
@@ -1522,19 +1522,29 @@
dnl # Check for Secret Service headers
dnl #######################################################################
-# disabled - see secretservice.c
-#AC_ARG_ENABLE(libsecret, [AC_HELP_STRING([--disable-libsecret], [enable Secret Service support])], enable_secret_service=no, enable_secret_service=yes)
+AC_ARG_ENABLE(libsecret, + [AC_HELP_STRING([--disable-libsecret], [enable Secret Service support])], + enable_secret_service="$enableval", enable_secret_service="$is_not_win32") -#if test "x$enable_secret_service" = "xyes" ; then
-# PKG_CHECK_MODULES(SECRETSERVICE, [libsecret-1], [
-# AC_SUBST(SECRETSERVICE_CFLAGS)
-# AC_SUBST(SECRETSERVICE_LIBS)
-# AC_DEFINE(HAVE_SECRETSERVICE, 1, [Define if we have Secret Service.])
+if test "x$enable_secret_service" = "xyes" ; then + PKG_CHECK_MODULES(SECRETSERVICE, [libsecret-1], [ + AC_SUBST(SECRETSERVICE_CFLAGS) + AC_SUBST(SECRETSERVICE_LIBS) + AC_DEFINE(HAVE_SECRETSERVICE, 1, [Define if we have Secret Service.]) + enable_secret_service="no" + if test "x$force_deps" = "xyes" ; then +Libsecret development headers not found +Use --disable-libsecret if you do not need it. -#AM_CONDITIONAL(ENABLE_SECRETSERVICE, test "x$enable_secret_service" = "xyes")
-AM_CONDITIONAL(ENABLE_SECRETSERVICE, test "x1" = "x2")
+AM_CONDITIONAL(ENABLE_SECRETSERVICE, test "x$enable_secret_service" = "xyes") dnl #######################################################################
dnl # Check for GNOME Keyring headers
@@ -2254,7 +2264,7 @@
echo Build with GNOME Keyring...... : $enable_gnome_keyring
echo Build with KWallet............ : $enable_kwallet
-#echo Build with Secret Service..... : $enable_secret_service
+echo Build with Secret Service..... : $enable_secret_service echo Build with plugin support..... : $enable_plugins
echo Enable Introspection...........: $enable_introspection
--- a/libpurple/plugins/keyrings/secretservice.c Sun Oct 09 18:32:16 2016 -0500
+++ b/libpurple/plugins/keyrings/secretservice.c Mon Oct 24 17:11:11 2016 -0500
@@ -21,17 +21,15 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
-#error "This keyring needs some more work (see TODO)"
- * This keyring needs some more work, so it will be disabled until its quality
- * was raised. Some of the pain points:
- * - throws a lot of g_warnings
- * - it doesn't notify about some backend faults (like access denied), some of
- * them are not handled at all
- * - it could use libsecret's Complete API
- * - code formatting could be better
+ * This keyring now works (at the time of this writing), but there are + * some inconvenient edge cases. When looking up passwords, libsecret + * doesn't error if the keyring is locked. Therefore, it appears to + * this plugin that there's no stored password. libpurple seems to + * handle this as gracefully as possible, but it's still inconvenient. + * This plugin could possibly be ported to use libsecret's "Complete API" + * to resolve this if desired. @@ -53,6 +51,7 @@
#define SECRETSERVICE_DOMAIN (g_quark_from_static_string(SECRETSERVICE_ID))
static PurpleKeyring *keyring_handler = NULL;
+static GCancellable *keyring_cancellable = NULL; static const SecretSchema purple_schema = {
"im.pidgin.Purple", SECRET_SCHEMA_NONE,
@@ -78,6 +77,62 @@
/***********************************************/
+ss_g_error_to_keyring_error(GError **error, PurpleAccount *account) + GError *new_error = NULL; + g_return_if_fail(error != NULL); + if (g_error_matches(old_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { + new_error = g_error_new(PURPLE_KEYRING_ERROR, + PURPLE_KEYRING_ERROR_CANCELLED, + _("Operation cancelled.")); + } else if (g_error_matches(old_error, G_DBUS_ERROR, + G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND) || + g_error_matches(old_error, G_DBUS_ERROR, + G_DBUS_ERROR_IO_ERROR)) { + purple_debug_info("keyring-libsecret", + "Failed to communicate with Secret " + "Service (account: %s (%s)).\n", + purple_account_get_username(account), + purple_account_get_protocol_id(account)); + new_error = g_error_new(PURPLE_KEYRING_ERROR, + PURPLE_KEYRING_ERROR_BACKENDFAIL, + "Failed to communicate with Secret " + "Service (account: %s).", + purple_account_get_username(account)); + } else if (g_error_matches(old_error, SECRET_ERROR, + SECRET_ERROR_IS_LOCKED)) { + purple_debug_info("keyring-libsecret", + "Secret Service is locked (account: %s (%s)).\n", + purple_account_get_username(account), + purple_account_get_protocol_id(account)); + new_error = g_error_new(PURPLE_KEYRING_ERROR, + PURPLE_KEYRING_ERROR_ACCESSDENIED, + "Secret Service is locked (account: %s).", + purple_account_get_username(account)); + purple_debug_error("keyring-libsecret", + "Unknown error (account: %s (%s), " + "domain: %s, code: %d): %s.\n", + purple_account_get_username(account), + purple_account_get_protocol_id(account), + g_quark_to_string(old_error->domain), + old_error->code, old_error->message); + new_error = g_error_new(PURPLE_KEYRING_ERROR, + PURPLE_KEYRING_ERROR_BACKENDFAIL, + "Unknown error (account: %s).", + purple_account_get_username(account)); + g_propagate_error(error, new_error); ss_read_continue(GObject *object, GAsyncResult *result, gpointer data)
InfoStorage *storage = data;
@@ -89,53 +144,19 @@
password = secret_password_lookup_finish(result, &error);
- int code = error->code;
- case G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND:
- case G_DBUS_ERROR_IO_ERROR:
- error = g_error_new(PURPLE_KEYRING_ERROR,
- PURPLE_KEYRING_ERROR_BACKENDFAIL,
- "Failed to communicate with Secret "
- "Service (account : %s).",
- purple_account_get_username(account));
- cb(account, NULL, error, storage->user_data);
- purple_debug_error("keyring-libsecret",
- "Unknown error (account: %s (%s), "
- "domain: %s, code: %d): %s.\n",
- purple_account_get_username(account),
- purple_account_get_protocol_id(account),
- g_quark_to_string(error->domain), code,
- error = g_error_new(PURPLE_KEYRING_ERROR,
- PURPLE_KEYRING_ERROR_BACKENDFAIL,
- "Unknown error (account : %s).",
- purple_account_get_username(account));
- cb(account, NULL, error, storage->user_data);
+ ss_g_error_to_keyring_error(&error, account); } else if (password == NULL) {
error = g_error_new(PURPLE_KEYRING_ERROR,
PURPLE_KEYRING_ERROR_NOPASSWORD,
"No password found for account: %s",
purple_account_get_username(account));
- cb(account, NULL, error, storage->user_data);
- cb(account, password, NULL, storage->user_data);
+ cb(account, password, error, storage->user_data); @@ -148,74 +169,57 @@
storage->user_data = data;
- secret_password_lookup(&purple_schema, NULL, ss_read_continue, storage,
+ secret_password_lookup(&purple_schema, keyring_cancellable, + ss_read_continue, storage, "user", purple_account_get_username(account),
"protocol", purple_account_get_protocol_id(account), NULL);
-ss_save_continue(GObject *object, GAsyncResult *result, gpointer data)
+ss_save_continue(GError *error, gpointer data) InfoStorage *storage = data;
PurpleKeyringSaveCallback cb;
account = storage->account;
- secret_password_store_finish(result, &error);
- int code = error->code;
- case G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND:
- case G_DBUS_ERROR_IO_ERROR:
- purple_debug_info("keyring-libsecret",
- "Failed to communicate with Secret "
- "Service (account : %s (%s)).\n",
- purple_account_get_username(account),
- purple_account_get_protocol_id(account));
- error = g_error_new(PURPLE_KEYRING_ERROR,
- PURPLE_KEYRING_ERROR_BACKENDFAIL,
- "Failed to communicate with Secret Service (account : %s).",
- purple_account_get_username(account));
- cb(account, error, storage->user_data);
- purple_debug_error("keyring-libsecret",
- "Unknown error (account: %s (%s), "
- "domain: %s, code: %d): %s.\n",
- purple_account_get_username(account),
- purple_account_get_protocol_id(account),
- g_quark_to_string(error->domain), code,
- error = g_error_new(PURPLE_KEYRING_ERROR,
- PURPLE_KEYRING_ERROR_BACKENDFAIL,
- "Unknown error (account : %s).",
- purple_account_get_username(account));
- cb(account, error, storage->user_data);
+ ss_g_error_to_keyring_error(&error, account); purple_debug_info("keyring-libsecret", "Password for %s updated.\n",
purple_account_get_username(account));
- cb(account, NULL, storage->user_data);
+ cb(account, error, storage->user_data); +ss_store_continue(GObject *object, GAsyncResult *result, gpointer data) + secret_password_store_finish(result, &error); + ss_save_continue(error, data); +ss_clear_continue(GObject *object, GAsyncResult *result, gpointer data) + secret_password_clear_finish(result, &error); + ss_save_continue(error, data); ss_save(PurpleAccount *account,
PurpleKeyringSaveCallback cb,
@@ -237,7 +241,8 @@
label = g_strdup_printf(_("Pidgin IM password for account %s"), username);
secret_password_store(&purple_schema, SECRET_COLLECTION_DEFAULT,
- label, password, NULL, ss_save_continue, storage,
+ label, password, keyring_cancellable, + ss_store_continue, storage, "protocol", purple_account_get_protocol_id(account),
@@ -249,27 +254,42 @@
purple_account_get_username(account),
purple_account_get_protocol_id(account));
- secret_password_clear(&purple_schema, NULL, ss_save_continue,
- storage, "user", purple_account_get_username(account),
+ secret_password_clear(&purple_schema, keyring_cancellable, + ss_clear_continue, storage, + "user", purple_account_get_username(account), "protocol", purple_account_get_protocol_id(account),
+ g_cancellable_cancel(keyring_cancellable); + /* Swap out cancelled cancellable for new one for further operations */ + g_clear_object(&keyring_cancellable); + keyring_cancellable = g_cancellable_new(); + keyring_cancellable = g_cancellable_new(); keyring_handler = purple_keyring_new();
purple_keyring_set_name(keyring_handler, _(SECRETSERVICE_NAME));
purple_keyring_set_id(keyring_handler, SECRETSERVICE_ID);
purple_keyring_set_read_password(keyring_handler, ss_read);
purple_keyring_set_save_password(keyring_handler, ss_save);
+ purple_keyring_set_cancel_requests(keyring_handler, ss_cancel); purple_keyring_set_close_keyring(keyring_handler, ss_close);
purple_keyring_register(keyring_handler);
@@ -284,6 +304,8 @@
purple_keyring_unregister(keyring_handler);
purple_keyring_free(keyring_handler);
+ g_clear_object(&keyring_cancellable); /***********************************************/