--- a/libpurple/account.c Fri Mar 19 02:47:40 2021 -0500
+++ b/libpurple/account.c Mon Mar 22 04:08:31 2021 -0500
@@ -154,10 +154,17 @@
PurpleCredentialManager *manager = PURPLE_CREDENTIAL_MANAGER(obj);
PurpleAccount *account = PURPLE_ACCOUNT(data);
password = purple_credential_manager_read_password_finish(manager, res,
+ purple_debug_warning("account", "failed to read password: %s", _purple_connection_new(account, TRUE, password);
@@ -187,12 +194,20 @@
PurpleCredentialManager *manager = PURPLE_CREDENTIAL_MANAGER(obj);
PurpleCallbackBundle *cbb = data;
PurpleAccountUnregistrationCb cb;
cb = (PurpleAccountUnregistrationCb)cbb->cb;
password = purple_credential_manager_read_password_finish(manager, res,
+ purple_debug_warning("account", "failed to read password: %s", _purple_connection_new_unregister(cbb->account, password, cb, cbb->data);
@@ -308,10 +323,18 @@
PurpleCredentialManager *manager = PURPLE_CREDENTIAL_MANAGER(obj);
PurpleAccount *account = PURPLE_ACCOUNT(data);
PurpleProtocol *protocol = NULL;
password = purple_credential_manager_read_password_finish(manager, res,
+ purple_debug_warning("account", "failed to read password %s", protocol = purple_account_get_protocol(account);
--- a/libpurple/accounts.c Fri Mar 19 02:47:40 2021 -0500
+++ b/libpurple/accounts.c Mon Mar 22 04:08:31 2021 -0500
@@ -583,13 +583,17 @@
purple_accounts_delete_set(GObject *obj, GAsyncResult *res, gpointer d) {
PurpleCredentialManager *manager = PURPLE_CREDENTIAL_MANAGER(obj);
PurpleAccount *account = PURPLE_ACCOUNT(d);
- r = purple_credential_manager_clear_password_finish(manager, res, NULL);
+ r = purple_credential_manager_clear_password_finish(manager, res, &error); purple_debug_warning("accounts",
- "Failed to remove password for account %s",
- purple_account_get_name_for_display(account));
+ "Failed to remove password for account %s: %s", + purple_account_get_name_for_display(account), g_object_unref(G_OBJECT(account));
--- a/libpurple/plugins/keyrings/kwallet/meson.build Fri Mar 19 02:47:40 2021 -0500
+++ b/libpurple/plugins/keyrings/kwallet/meson.build Mon Mar 22 04:08:31 2021 -0500
@@ -5,7 +5,13 @@
- kwallet_plugin = library('purplekwallet', 'purplekwallet.cpp', 'purplekwallet.h', kwallet_moc,
+ kwallet_plugin = library('purplekwallet', kwallet_sources, dependencies : [kwallet, qt5_dep, libpurple_dep],
install : true, install_dir : PURPLE_PLUGINDIR)
--- a/libpurple/plugins/keyrings/kwallet/purplekwallet.cpp Fri Mar 19 02:47:40 2021 -0500
+++ b/libpurple/plugins/keyrings/kwallet/purplekwallet.cpp Mon Mar 22 04:08:31 2021 -0500
@@ -1,9 +1,5 @@
- * @file kwallet.cpp KWallet password storage
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
@@ -19,390 +15,46 @@
* 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 02111-1301 USA
+ * You should have received a copy of the GNU General Public License along with + * this library; if not, see <https://www.gnu.org/licenses/>. #include <glib/gi18n-lib.h>
#include <QCoreApplication>
#include "purplekwallet.h"
-#define KWALLET_NAME N_("KWallet")
-#define KWALLET_DESCRIPTION N_("This plugin will store passwords in KWallet.")
-#define KWALLET_AUTHORS { "QuLogic (qulogic[at]pidgin.im)", NULL }
-#define KWALLET_ID "keyring-kwallet"
-#define KWALLET_DOMAIN (g_quark_from_static_string(KWALLET_ID))
-#define KWALLET_WALLET_NAME KWallet::Wallet::NetworkWallet()
-#define KWALLET_APP_NAME "Libpurple"
-#define KWALLET_FOLDER_NAME "libpurple"
-PurpleKeyring *keyring_handler = NULL;
-QCoreApplication *qCoreApp = NULL;
-kwallet_is_enabled(void)
- return KWallet::Wallet::isEnabled() ? TRUE : FALSE;
-KWalletPlugin::engine *KWalletPlugin::engine::pinstance = NULL;
-KWalletPlugin::request::~request()
-KWalletPlugin::request::abort()
- detailedAbort(PURPLE_KEYRING_ERROR_CANCELLED);
-KWalletPlugin::engine::engine()
- externallyClosed = false;
- closeAfterBusy = false;
-KWalletPlugin::engine::reopenWallet()
- purple_debug_error("keyring-kwallet",
- "wallet is closing right now\n");
- externallyClosed = false;
- wallet = KWallet::Wallet::openWallet(KWALLET_WALLET_NAME, 0,
- KWallet::Wallet::Asynchronous);
- purple_debug_error("keyring-kwallet",
- "failed opening a wallet\n");
- failed |= !connect(wallet, SIGNAL(walletClosed()),
- failed |= !connect(wallet, SIGNAL(walletOpened(bool)),
- SLOT(walletOpened(bool)));
- purple_debug_error("keyring-kwallet",
- "failed connecting to wallet signal\n");
-KWalletPlugin::engine::~engine()
+/****************************************************************************** + *****************************************************************************/ +static QCoreApplication *qCoreApp = NULL; +static PurpleCredentialProvider *instance = NULL;
-KWalletPlugin::engine::abortAll()
- request *req = dequeue();
- if (abortedCount > 0) {
- purple_debug_info("keyring-kwallet", "aborted requests: %d\n",
-KWalletPlugin::engine::instance(bool create)
- if (pinstance == NULL && create)
- pinstance = new engine;
+#define PURPLE_KWALLET_DOMAIN (g_quark_from_static_string("purple-kwallet")) +#define PURPLE_KWALLET_WALLET_NAME (KWallet::Wallet::NetworkWallet())
-KWalletPlugin::engine::closeInstance(void)
- if (pinstance->closing)
- purple_debug_misc("keyring-kwallet",
- "current instance is busy, will be freed later\n");
- pinstance->closeAfterBusy = true;
-KWalletPlugin::engine::walletOpened(bool opened)
- purple_debug_warning("keyring-kwallet",
- "failed to open a wallet\n");
- if (!wallet->hasFolder(KWALLET_FOLDER_NAME)) {
- if (!wallet->createFolder(KWALLET_FOLDER_NAME)) {
- purple_debug_error("keyring-kwallet",
- "couldn't create \"" KWALLET_FOLDER_NAME
- "\" folder in wallet\n");
- wallet->setFolder(KWALLET_FOLDER_NAME);
-KWalletPlugin::engine::walletClosed()
- purple_debug_info("keyring-kwallet",
- "wallet was externally closed\n");
- externallyClosed = true;
-KWalletPlugin::engine::queue(request *req)
+struct _PurpleKWalletProvider { + PurpleCredentialProvider parent;
-KWalletPlugin::engine::executeRequests()
- if (externallyClosed) {
- } else if (connected || failed) {
- request *req = dequeue();
- } else if (purple_debug_is_verbose()) {
- purple_debug_misc("keyring-kwallet", "not yet connected\n");
- purple_debug_misc("keyring-kwallet",
- "instance freed after being busy\n");
-KWalletPlugin::save_request::save_request(PurpleAccount *acc, const char *pw,
- PurpleKeyringSaveCallback cb, void *userdata)
- password = QString(pw);
- noPassword = (pw == NULL);
-KWalletPlugin::read_request::read_request(PurpleAccount *acc,
- PurpleKeyringReadCallback cb, void *userdata)
+ PurpleKWalletPlugin::Engine *engine;
-KWalletPlugin::save_request::detailedAbort(enum PurpleKeyringError error)
- gerror = g_error_new(PURPLE_KEYRING_ERROR, error,
- _("Failed to save password."));
- callback(account, gerror, data);
-KWalletPlugin::read_request::detailedAbort(enum PurpleKeyringError error)
- gerror = g_error_new(PURPLE_KEYRING_ERROR, error,
- _("Failed to read password."));
- callback(account, NULL, gerror, data);
-kwallet_account_key(PurpleAccount *account)
- return QString(purple_account_get_protocol_id(account)) + ":" +
- purple_account_get_username(account);
-KWalletPlugin::read_request::execute(KWallet::Wallet *wallet)
- g_return_if_fail(wallet != NULL);
- result = wallet->readPassword(kwallet_account_key(account), password);
- purple_debug_warning("keyring-kwallet",
- "failed to read password, result was %d\n", result);
+G_DEFINE_DYNAMIC_TYPE(PurpleKWalletProvider, purple_kwallet_provider, + PURPLE_TYPE_CREDENTIAL_PROVIDER) - purple_debug_misc("keyring-kwallet",
- "Got password for account %s (%s).\n",
- purple_account_get_username(account),
- purple_account_get_protocol_id(account));
- callback(account, password.toUtf8().constData(), NULL, data);
-KWalletPlugin::save_request::execute(KWallet::Wallet *wallet)
- g_return_if_fail(wallet != NULL);
- result = wallet->removeEntry(kwallet_account_key(account));
- result = wallet->writePassword(kwallet_account_key(account),
- purple_debug_warning("keyring-kwallet",
- "failed to write password, result was %d\n", result);
- purple_debug_misc("keyring-kwallet",
- "Password %s for account %s (%s).\n",
- (noPassword ? "removed" : "saved"),
- purple_account_get_username(account),
- purple_account_get_protocol_id(account));
- callback(account, NULL, data);
-kwallet_read(PurpleAccount *account, PurpleKeyringReadCallback cb,
- KWalletPlugin::read_request *req =
- new KWalletPlugin::read_request(account, cb, data);
- if (KWallet::Wallet::keyDoesNotExist(KWALLET_WALLET_NAME,
- KWALLET_FOLDER_NAME, kwallet_account_key(account)))
- req->detailedAbort(PURPLE_KEYRING_ERROR_NOPASSWORD);
- KWalletPlugin::engine::instance(true)->queue(req);
-kwallet_save(PurpleAccount *account, const char *password,
- PurpleKeyringSaveCallback cb, gpointer data)
- if (password == NULL && KWallet::Wallet::keyDoesNotExist(
- KWALLET_WALLET_NAME, KWALLET_FOLDER_NAME,
- kwallet_account_key(account)))
- cb(account, NULL, data);
- KWalletPlugin::engine::instance(true)->queue(
- new KWalletPlugin::save_request(account, password, cb,
- KWalletPlugin::engine *instance =
- KWalletPlugin::engine::instance(false);
-kwallet_get_handle(void)
-static const char *kwallet_get_ui_name(void)
+/****************************************************************************** + *****************************************************************************/ +purple_kwallet_get_ui_name(void) { PurpleUiInfo *ui_info = NULL;
- const char *ui_name = NULL;
+ QString ui_name = NULL; ui_info = purple_core_get_ui_info();
if(PURPLE_IS_UI_INFO(ui_info)) {
@@ -410,92 +62,551 @@
g_object_unref(G_OBJECT(ui_info));
- ui_name = KWALLET_APP_NAME;
+ if(ui_name.isEmpty()) { -static PurplePluginInfo *
-plugin_query(GError **error)
+purple_kwallet_provider_account_key(PurpleAccount *account) { + return QString(purple_account_get_protocol_id(account)) + ":" + + purple_account_get_username(account); +/****************************************************************************** + * Request Implementation + *****************************************************************************/ +PurpleKWalletPlugin::Request::Request(QString key, GTask *task) { + this->task = G_TASK(g_object_ref(G_OBJECT(task))); +PurpleKWalletPlugin::Request::~Request(void) { + g_clear_object(&this->task); +/****************************************************************************** + * ReadRequest Implementation + *****************************************************************************/ +PurpleKWalletPlugin::ReadRequest::ReadRequest(QString key, GTask *task) : PurpleKWalletPlugin::Request(key, task) { +PurpleKWalletPlugin::ReadRequest::execute(KWallet::Wallet *wallet) { + missing = KWallet::Wallet::keyDoesNotExist(PURPLE_KWALLET_WALLET_NAME, + purple_kwallet_get_ui_name(), + g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, 0, + g_clear_object(&this->task); + result = wallet->readPassword(this->key, password); + g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, result, + _("failed to read password, kwallet responded " + "with error code %d"), result); + gchar *c_password = g_strdup(password.toUtf8().constData()); + g_task_return_pointer(this->task, c_password, g_free); + g_clear_object(&this->task); +PurpleKWalletPlugin::ReadRequest::cancel(QString reason) { + g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, 0, + _("failed to read password: %s"), + reason.toUtf8().constData()); + g_clear_object(&this->task); +/****************************************************************************** + * WriteRequest Implementation + *****************************************************************************/ +PurpleKWalletPlugin::WriteRequest::WriteRequest(QString key, GTask *task, QString password) : PurpleKWalletPlugin::Request(key, task) { + this->password = password; +PurpleKWalletPlugin::WriteRequest::execute(KWallet::Wallet *wallet) { + result = wallet->writePassword(this->key, this->password); + g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, result, + _("failed to write password, kwallet " + "responded with error code %d"), result); + g_task_return_boolean(this->task, TRUE); + g_clear_object(&this->task); +PurpleKWalletPlugin::WriteRequest::cancel(QString reason) { + g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, 0, + _("failed to write password: %s"), + reason.toUtf8().constData()); + g_clear_object(&this->task); +/****************************************************************************** + * ClearRequest Implementation + *****************************************************************************/ +PurpleKWalletPlugin::ClearRequest::ClearRequest(QString key, GTask *task) : PurpleKWalletPlugin::Request(key, task) { +PurpleKWalletPlugin::ClearRequest::execute(KWallet::Wallet *wallet) { + result = wallet->removeEntry(this->key); + g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, result, + _("failed to clear password, kwallet " + "responded with error code %d"), result); + g_task_return_boolean(this->task, TRUE); + g_clear_object(&this->task); +PurpleKWalletPlugin::ClearRequest::cancel(QString reason) { + g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, 0, + _("failed to clear password: %s"), + reason.toUtf8().constData()); + g_clear_object(&this->task); +/****************************************************************************** + * Engine Implementation + *****************************************************************************/ +PurpleKWalletPlugin::Engine::Engine(void) { + this->queue = QQueue<PurpleKWalletPlugin::Request *>(); + this->connected = false; +PurpleKWalletPlugin::Engine::~Engine(void) { +PurpleKWalletPlugin::Engine::open(void) { + purple_debug_misc("kwallet-provider", "attempting to open wallet"); + purple_debug_misc("kwallet-provider", "wallet already opened"); + // Reset our externallyClosed and failed states. + this->externallyClosed = false; + // No need to check this pointer as an async open always returns non-null. + this->wallet = KWallet::Wallet::openWallet(PURPLE_KWALLET_WALLET_NAME, + KWallet::Wallet::Asynchronous); + this->failed |= !QObject::connect(this->wallet, SIGNAL(walletOpened(bool)), + this->failed |= !QObject::connect(this->wallet, SIGNAL(walletClosed(void)), + purple_debug_error("kwallet-provider", + "Failed to connect KWallet signals"); +PurpleKWalletPlugin::Engine::close(void) { + while(!this->queue.isEmpty()) { + PurpleKWalletPlugin::Request *request = this->queue.dequeue(); + request->cancel("wallet is closing"); + if(this->wallet != NULL) { + this->connected = false; +PurpleKWalletPlugin::Engine::enqueue(PurpleKWalletPlugin::Request *request) { + this->queue.enqueue(request); +PurpleKWalletPlugin::Engine::opened(bool opened) { + purple_debug_error("kwallet-provider", "failed to open wallet"); + this->connected = false; + // Handle the case where the wallet opened signal connected, but the wallet + // closed signal failed to connect. + purple_debug_error("kwallet-provider", + "wallet opened, but failed to connect the wallet " + this->connected = true; + folder_name = purple_kwallet_get_ui_name(); + if(!this->wallet->hasFolder(folder_name)) { + if(!this->wallet->createFolder(folder_name)) { + purple_debug_error("kwallet-provider", + "failed to create folder %s in wallet.", + folder_name.toUtf8().constData()); + if(!this->failed && !this->wallet->setFolder(folder_name)) { + purple_debug_error("kwallet-provider", "failed to set folder to %s", + folder_name.toUtf8().constData()); + purple_debug_misc("kwallet-provider", "successfully opened the wallet"); +PurpleKWalletPlugin::Engine::closed(void) { + purple_debug_misc("kwallet-provider", "the wallet was closed externally"); + this->externallyClosed = true; +PurpleKWalletPlugin::Engine::processQueue() { + if(this->externallyClosed && this->queue.isEmpty() == false) { + } else if(this->connected || this->failed) { + while(!this->queue.isEmpty()) { + PurpleKWalletPlugin::Request *request = this->queue.dequeue(); + request->cancel(_("failed to open kwallet")); + request->execute(this->wallet); +/****************************************************************************** + * PurpleCredentialProvider Implementation + *****************************************************************************/ +purple_kwallet_provider_activate(PurpleCredentialProvider *provider) { + PurpleKWalletProvider *kwallet_provider = NULL; + kwallet_provider = PURPLE_KWALLET_PROVIDER(provider); + kwallet_provider->engine->open(); +purple_kwallet_provider_deactivate(PurpleCredentialProvider *provider) { + PurpleKWalletProvider *kwallet_provider = NULL; + kwallet_provider = PURPLE_KWALLET_PROVIDER(provider); + kwallet_provider->engine->close(); +purple_kwallet_read_password_async(PurpleCredentialProvider *provider, + PurpleAccount *account, + GCancellable *cancellable, + GAsyncReadyCallback callback, - const gchar * const authors[] = KWALLET_AUTHORS;
+ PurpleKWalletProvider *kwallet_provider = NULL; + PurpleKWalletPlugin::ReadRequest *request = NULL; + key = purple_kwallet_provider_account_key(account); + task = g_task_new(G_OBJECT(provider), cancellable, callback, data); + request = new PurpleKWalletPlugin::ReadRequest(key, task); + kwallet_provider = PURPLE_KWALLET_PROVIDER(provider); + kwallet_provider->engine->enqueue(request); +purple_kwallet_read_password_finish(PurpleCredentialProvider *provider, + GAsyncResult *result, GError **error) + return (gchar *)g_task_propagate_pointer(G_TASK(result), error); +purple_kwallet_write_password_async(PurpleCredentialProvider *provider, + PurpleAccount *account, + GCancellable *cancellable, + GAsyncReadyCallback callback, + PurpleKWalletProvider *kwallet_provider = NULL; + PurpleKWalletPlugin::WriteRequest *request = NULL; + task = g_task_new(G_OBJECT(provider), cancellable, callback, data); + key = purple_kwallet_provider_account_key(account); + request = new PurpleKWalletPlugin::WriteRequest(key, task, password); + kwallet_provider = PURPLE_KWALLET_PROVIDER(provider); + kwallet_provider->engine->enqueue(request); +purple_kwallet_write_password_finish(PurpleCredentialProvider *provider, + GAsyncResult *result, GError **error) + return g_task_propagate_boolean(G_TASK(result), error); +purple_kwallet_clear_password_async(PurpleCredentialProvider *provider, + PurpleAccount *account, + GCancellable *cancellable, + GAsyncReadyCallback callback, + PurpleKWalletProvider *kwallet_provider = NULL; + PurpleKWalletPlugin::ClearRequest *request = NULL; + task = g_task_new(G_OBJECT(provider), cancellable, callback, data); + key = purple_kwallet_provider_account_key(account); + request = new PurpleKWalletPlugin::ClearRequest(key, task); + kwallet_provider = PURPLE_KWALLET_PROVIDER(provider); + kwallet_provider->engine->enqueue(request); +purple_kwallet_clear_password_finish(PurpleCredentialProvider *provider, + GAsyncResult *result, GError **error) + return g_task_propagate_boolean(G_TASK(result), error); - return purple_plugin_info_new(
+/****************************************************************************** + * GObject Implementation + *****************************************************************************/ +purple_kwallet_provider_dispose(GObject *obj) { + PurpleKWalletProvider *provider = PURPLE_KWALLET_PROVIDER(obj); + delete provider->engine; + provider->engine = NULL; + G_OBJECT_CLASS(purple_kwallet_provider_parent_class)->dispose(obj); +purple_kwallet_provider_finalize(GObject *obj) { + PurpleKWalletProvider *provider = PURPLE_KWALLET_PROVIDER(obj); + if(provider->engine != NULL) { + delete provider->engine; + provider->engine = NULL; + G_OBJECT_CLASS(purple_kwallet_provider_parent_class)->finalize(obj); +purple_kwallet_provider_init(PurpleKWalletProvider *provider) { + provider->engine = new PurpleKWalletPlugin::Engine(); +purple_kwallet_provider_class_init(PurpleKWalletProviderClass *klass) { + GObjectClass *obj_class = G_OBJECT_CLASS(klass); + PurpleCredentialProviderClass *provider_class = NULL; + provider_class = PURPLE_CREDENTIAL_PROVIDER_CLASS(klass); + obj_class->dispose = purple_kwallet_provider_dispose; + obj_class->finalize = purple_kwallet_provider_finalize; + provider_class->activate = purple_kwallet_provider_activate; + provider_class->deactivate = purple_kwallet_provider_deactivate; + provider_class->read_password_async = purple_kwallet_read_password_async; + provider_class->read_password_finish = purple_kwallet_read_password_finish; + provider_class->write_password_async = purple_kwallet_write_password_async; + provider_class->write_password_finish = + purple_kwallet_write_password_finish; + provider_class->clear_password_async = purple_kwallet_clear_password_async; + provider_class->clear_password_finish = + purple_kwallet_clear_password_finish; +purple_kwallet_provider_class_finalize(PurpleKWalletProviderClass *klass) { +/****************************************************************************** + *****************************************************************************/ +static PurpleCredentialProvider * +purple_kwallet_provider_new(void) { + return PURPLE_CREDENTIAL_PROVIDER(g_object_new( + PURPLE_KWALLET_TYPE_PROVIDER, + "description", _("A credentials management application for the KDE " + "Software Compilation desktop environment"), +/****************************************************************************** + *****************************************************************************/ +G_MODULE_EXPORT GPluginPluginInfo * +gplugin_query(GError **error) { + const gchar * const authors[] = { + "Pidgin Developers <devel@pidgin.im>", + return GPLUGIN_PLUGIN_INFO(purple_plugin_info_new( + "id", "keyring-kwallet", "version", DISPLAY_VERSION,
"category", N_("Keyring"),
"summary", "KWallet Keyring Plugin",
- "description", KWALLET_DESCRIPTION,
+ "description", N_("This plugin will store passwords in KWallet."), "website", PURPLE_WEBSITE,
"abi-version", PURPLE_ABI_VERSION,
"flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL,
-plugin_load(PurplePlugin *plugin, GError **error)
+G_MODULE_EXPORT gboolean +gplugin_load(GPluginPlugin *plugin, GError **error) { + PurpleCredentialManager *manager = NULL; + purple_kwallet_provider_register_type(G_TYPE_MODULE(plugin)); qCoreApp = new QCoreApplication(argc, NULL);
- qCoreApp->setApplicationName(kwallet_get_ui_name());
+ qCoreApp->setApplicationName(purple_kwallet_get_ui_name()); - if (!kwallet_is_enabled()) {
- g_set_error(error, KWALLET_DOMAIN, 0, "KWallet service is disabled.");
- purple_debug_info("keyring-kwallet",
- "KWallet service is disabled\n");
+ if(!KWallet::Wallet::isEnabled()) { + g_set_error(error, PURPLE_KWALLET_DOMAIN, 0, + "KWallet service is disabled."); - keyring_handler = purple_keyring_new();
+ manager = purple_credential_manager_get_default(); + instance = purple_kwallet_provider_new(); + return purple_credential_manager_register_provider(manager, instance, +G_MODULE_EXPORT gboolean +gplugin_unload(GPluginPlugin *plugin, GError **error) { + PurpleCredentialManager *manager = NULL; - purple_keyring_set_name(keyring_handler, _(KWALLET_NAME));
- purple_keyring_set_id(keyring_handler, KWALLET_ID);
- purple_keyring_set_read_password(keyring_handler, kwallet_read);
- purple_keyring_set_save_password(keyring_handler, kwallet_save);
- purple_keyring_set_cancel_requests(keyring_handler, kwallet_cancel);
- purple_keyring_set_close_keyring(keyring_handler,
- KWalletPlugin::engine::closeInstance);
+ manager = purple_credential_manager_get_default(); + ret = purple_credential_manager_unregister_provider(manager, instance, - purple_keyring_register(keyring_handler);
+ g_clear_object(&instance);
-plugin_unload(PurplePlugin *plugin, GError **error)
- if (purple_keyring_get_inuse() == keyring_handler) {
- g_set_error(error, KWALLET_DOMAIN, 0, "The keyring is currently "
- purple_debug_warning("keyring-kwallet",
- "keyring in use, cannot unload\n");
- purple_signals_disconnect_by_handle(kwallet_get_handle());
- KWalletPlugin::engine::closeInstance();
- purple_keyring_unregister(keyring_handler);
- purple_keyring_free(keyring_handler);
- keyring_handler = NULL;
-PURPLE_PLUGIN_INIT(kwallet_keyring, plugin_query, plugin_load, plugin_unload);
--- a/libpurple/plugins/keyrings/kwallet/purplekwallet.h Fri Mar 19 02:47:40 2021 -0500
+++ b/libpurple/plugins/keyrings/kwallet/purplekwallet.h Mon Mar 22 04:08:31 2021 -0500
@@ -1,4 +1,5 @@
* Purple is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
@@ -14,86 +15,80 @@
* 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 02111-1301 USA
+ * You should have received a copy of the GNU General Public License along with + * this library; if not, see <https://www.gnu.org/licenses/>. -namespace KWalletPlugin {
+#define PURPLE_KWALLET_TYPE_PROVIDER (purple_kwallet_provider_get_type()) +G_DECLARE_FINAL_TYPE(PurpleKWalletProvider, purple_kwallet_provider, + PURPLE_KWALLET, PROVIDER, PurpleCredentialProvider) +namespace PurpleKWalletPlugin {
- virtual void detailedAbort(enum PurpleKeyringError error) = 0;
- virtual void execute(KWallet::Wallet *wallet) = 0;
- PurpleAccount *account;
+ Request(QString key, GTask *task); + virtual ~Request(void); + virtual void execute(KWallet::Wallet *wallet) = 0; + virtual void cancel(QString reason) = 0; -class engine : private QObject, private QQueue<request*>
+class ReadRequest : public Request { + ReadRequest(QString key, GTask *task); + void execute(KWallet::Wallet *wallet); + void cancel(QString reason); +class WriteRequest : public Request { + WriteRequest(QString key, GTask *task, QString password); + void execute(KWallet::Wallet *wallet); + void cancel(QString reason); +class ClearRequest : public Request { + ClearRequest(QString key, GTask *task); + void execute(KWallet::Wallet *wallet); + void cancel(QString reason); +class Engine : public QObject {
- void queue(request *req);
- static engine *instance(bool create);
- static void closeInstance(void);
- void walletOpened(bool opened);
- static engine *pinstance;
- KWallet::Wallet *wallet;
- void executeRequests();
-class save_request : public request
- save_request(PurpleAccount *account, const char *password,
- PurpleKeyringSaveCallback cb, void *data);
- void detailedAbort(enum PurpleKeyringError error);
- void execute(KWallet::Wallet *wallet);
+ void enqueue(Request *request); + void opened(bool opened); + void processQueue(void);
- PurpleKeyringSaveCallback callback;
-class read_request : public request
- read_request(PurpleAccount *account,
- PurpleKeyringReadCallback cb, void *data);
- void detailedAbort(enum PurpleKeyringError error);
- void execute(KWallet::Wallet *wallet);
+ KWallet::Wallet *wallet;
- PurpleKeyringReadCallback callback;
+ QQueue<Request *> queue; --- a/libpurple/purplecredentialmanager.c Fri Mar 19 02:47:40 2021 -0500
+++ b/libpurple/purplecredentialmanager.c Mon Mar 22 04:08:31 2021 -0500
@@ -394,6 +394,14 @@
if(g_set_object(&priv->active_provider, provider)) {
+ if(PURPLE_IS_CREDENTIAL_PROVIDER(old)) { + purple_credential_provider_deactivate(old); + if(PURPLE_IS_CREDENTIAL_PROVIDER(provider)) { + purple_credential_provider_activate(provider); g_signal_emit(G_OBJECT(manager), signals[SIG_ACTIVE_PROVIDER_CHANGED],
0, old, priv->active_provider);
--- a/libpurple/purplecredentialprovider.c Fri Mar 19 02:47:40 2021 -0500
+++ b/libpurple/purplecredentialprovider.c Mon Mar 22 04:08:31 2021 -0500
@@ -18,6 +18,8 @@
#include "purplecredentialprovider.h"
+#include "purpleprivate.h" @@ -204,6 +206,29 @@
/******************************************************************************
+ *****************************************************************************/ +purple_credential_provider_activate(PurpleCredentialProvider *provider) { + PurpleCredentialProviderClass *klass = NULL; + klass = PURPLE_CREDENTIAL_PROVIDER_GET_CLASS(provider); + if(klass && klass->activate) { + klass->activate(provider); +purple_credential_provider_deactivate(PurpleCredentialProvider *provider) { + PurpleCredentialProviderClass *klass = NULL; + klass = PURPLE_CREDENTIAL_PROVIDER_GET_CLASS(provider); + if(klass && klass->deactivate) { + klass->deactivate(provider); +/****************************************************************************** *****************************************************************************/
--- a/libpurple/purplecredentialprovider.h Fri Mar 19 02:47:40 2021 -0500
+++ b/libpurple/purplecredentialprovider.h Mon Mar 22 04:08:31 2021 -0500
@@ -62,6 +62,8 @@
* PurpleCredentialProviderClass:
+ * @activate: Called when the provider is made active. + * @deactivate: Called when another provider has been made active. * @read_password_async: Reads a password from the provider.
* @read_password_finish: Finishes reading a password.
* @write_password_async: Writes a password to the provider.
@@ -82,6 +84,9 @@
+ void (*activate)(PurpleCredentialProvider *provider); + void (*deactivate)(PurpleCredentialProvider *provider); void (*read_password_async)(PurpleCredentialProvider *provider, PurpleAccount *account, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data);
gchar *(*read_password_finish)(PurpleCredentialProvider *provider, GAsyncResult *result, GError **error);
--- a/libpurple/purpleprivate.h Fri Mar 19 02:47:40 2021 -0500
+++ b/libpurple/purpleprivate.h Mon Mar 22 04:08:31 2021 -0500
@@ -31,6 +31,7 @@
+#include "purplecredentialprovider.h" #define PURPLE_STATIC_ASSERT(condition, message) \
{ typedef char static_assertion_failed_ ## message \
@@ -199,6 +200,8 @@
* purple_credential_manager_startup:
* Starts up the credential manager by creating the default instance.
void purple_credential_manager_startup(void);
@@ -206,6 +209,8 @@
* purple_credential_manager_shutdown:
* Shuts down the credential manager by destroying the default instance.
void purple_credential_manager_shutdown(void);
@@ -213,6 +218,8 @@
* purple_protocol_manager_startup:
* Starts up the protocol manager by creating the default instance.
void purple_protocol_manager_startup(void);
@@ -220,9 +227,32 @@
* purple_protocol_manager_shutdown:
* Shuts down the protocol manager by destroying the default instance.
void purple_protocol_manager_shutdown(void);
+ * purple_credential_provider_activate: + * @provider: The #PurpleCredentialProvider instance. + * Tells a @provider that it has become the active provider. +void purple_credential_provider_activate(PurpleCredentialProvider *provider); + * purple_credential_provider_deactivate: + * @provider: The #PurpleCredentialProvider instance. + * Tells @provider that another #PurpleCredentialProvider has become the active +void purple_credential_provider_deactivate(PurpleCredentialProvider *provider); #endif /* PURPLE_PRIVATE_H */
--- a/pidgin/gtkaccount.c Fri Mar 19 02:47:40 2021 -0500
+++ b/pidgin/gtkaccount.c Mon Mar 22 04:08:31 2021 -0500
@@ -1709,10 +1709,18 @@
PurpleCredentialManager *manager = PURPLE_CREDENTIAL_MANAGER(obj);
PidginAccountDialogShowData *d = (PidginAccountDialogShowData *)data;
password = purple_credential_manager_read_password_finish(manager, res,
+ purple_debug_warning("gtkaccount", "failed to read password: %s", pidgin_account_dialog_show_continue(d->type, d->account, password);