pidgin/pidgin

Parents 9af9f229332a
Children db38cdfbc59e
Move the kwallet plugin to the plugins directory and make it autoload

Testing Done:
Ran from the devenv and verified that it autoloaded and was in the new location.

Reviewed at https://reviews.imfreedom.org/r/1125/
--- a/libpurple/plugins/keyrings/kwallet/meson.build Mon Nov 15 02:21:18 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,20 +0,0 @@
-if kwallet.found()
- kwallet_moc = qt5.preprocess(
- moc_headers: 'purplekwallet.h',
- dependencies: qt5_dep,
- )
-
- kwallet_sources = [
- 'purplekwallet.cpp',
- 'purplekwallet.h',
- kwallet_moc,
- ]
-
- kwallet_plugin = library('purplekwallet', kwallet_sources,
- c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Purple-KWalletKeyring"'],
- dependencies : [kwallet, qt5_dep, libpurple_dep],
- name_prefix : '',
- install : true, install_dir : PURPLE_PLUGINDIR)
-
- devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir())
-endif
--- a/libpurple/plugins/keyrings/kwallet/purplekwallet.cpp Mon Nov 15 02:21:18 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,617 +0,0 @@
-/*
- * purple
- *
- * 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
- * source distribution.
- *
- * 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 library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include <glib.h>
-#include <glib/gi18n-lib.h>
-
-#include <purple.h>
-
-#include <QCoreApplication>
-
-#include <kwallet.h>
-
-#include "purplekwallet.h"
-
-/******************************************************************************
- * Globals
- *****************************************************************************/
-static QCoreApplication *qCoreApp = NULL;
-static PurpleCredentialProvider *instance = NULL;
-
-#define PURPLE_KWALLET_DOMAIN (g_quark_from_static_string("purple-kwallet"))
-#define PURPLE_KWALLET_WALLET_NAME (KWallet::Wallet::NetworkWallet())
-
-struct _PurpleKWalletProvider {
- PurpleCredentialProvider parent;
-
- PurpleKWalletPlugin::Engine *engine;
-};
-
-G_DEFINE_DYNAMIC_TYPE(PurpleKWalletProvider, purple_kwallet_provider,
- PURPLE_TYPE_CREDENTIAL_PROVIDER)
-
-/******************************************************************************
- * Helpers
- *****************************************************************************/
-static QString
-purple_kwallet_get_ui_name(void) {
- PurpleUiInfo *ui_info = NULL;
- QString ui_name = NULL;
-
- ui_info = purple_core_get_ui_info();
- if(PURPLE_IS_UI_INFO(ui_info)) {
- ui_name = purple_ui_info_get_name(ui_info);
- g_object_unref(G_OBJECT(ui_info));
- }
-
- if(ui_name.isEmpty()) {
- ui_name = "libpurple";
- }
-
- return ui_name;
-}
-
-static QString
-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->key = key;
- 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) {
-}
-
-void
-PurpleKWalletPlugin::ReadRequest::execute(KWallet::Wallet *wallet) {
- QString password;
- int result = 0;
- bool missing;
-
- missing = KWallet::Wallet::keyDoesNotExist(PURPLE_KWALLET_WALLET_NAME,
- purple_kwallet_get_ui_name(),
- key);
-
- if(missing) {
- g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, 0,
- "no password stored");
-
- g_clear_object(&this->task);
-
- return;
- }
-
- result = wallet->readPassword(this->key, password);
-
- if(result != 0) {
- g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, result,
- _("failed to read password, kwallet responded "
- "with error code %d"), result);
- } else {
- gchar *c_password = g_strdup(password.toUtf8().constData());
- g_task_return_pointer(this->task, c_password, g_free);
- }
-
- g_clear_object(&this->task);
-}
-
-void
-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;
-}
-
-void
-PurpleKWalletPlugin::WriteRequest::execute(KWallet::Wallet *wallet) {
- int result;
-
- result = wallet->writePassword(this->key, this->password);
-
- if(result != 0) {
- g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, result,
- _("failed to write password, kwallet "
- "responded with error code %d"), result);
- } else {
- g_task_return_boolean(this->task, TRUE);
- }
-
- g_clear_object(&this->task);
-}
-
-void
-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) {
-}
-
-void
-PurpleKWalletPlugin::ClearRequest::execute(KWallet::Wallet *wallet) {
- int result;
-
- result = wallet->removeEntry(this->key);
-
- if(result != 0) {
- g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, result,
- _("failed to clear password, kwallet "
- "responded with error code %d"), result);
- } else {
- g_task_return_boolean(this->task, TRUE);
- }
-
- g_clear_object(&this->task);
-}
-
-void
-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->wallet = NULL;
-
- this->connected = false;
- this->failed = false;
- this->externallyClosed = false;
-}
-
-PurpleKWalletPlugin::Engine::~Engine(void) {
- this->close();
-}
-
-void
-PurpleKWalletPlugin::Engine::open(void) {
- purple_debug_misc("kwallet-provider", "attempting to open wallet");
-
- if(this->connected) {
- purple_debug_misc("kwallet-provider", "wallet already opened");
-
- return;
- }
-
- // Reset our externallyClosed and failed states.
- this->externallyClosed = false;
- this->failed = false;
-
- // No need to check this pointer as an async open always returns non-null.
- this->wallet = KWallet::Wallet::openWallet(PURPLE_KWALLET_WALLET_NAME,
- 0,
- KWallet::Wallet::Asynchronous);
-
- this->failed |= !QObject::connect(this->wallet, SIGNAL(walletOpened(bool)),
- SLOT(opened(bool)));
- this->failed |= !QObject::connect(this->wallet, SIGNAL(walletClosed(void)),
- SLOT(closed()));
-
- if(this->failed) {
- purple_debug_error("kwallet-provider",
- "Failed to connect KWallet signals");
- }
-}
-
-void
-PurpleKWalletPlugin::Engine::close(void) {
- while(!this->queue.isEmpty()) {
- PurpleKWalletPlugin::Request *request = this->queue.dequeue();
-
- request->cancel("wallet is closing");
-
- delete request;
- }
-
- if(this->wallet != NULL) {
- delete this->wallet;
- this->wallet = NULL;
- }
-
- this->connected = false;
- this->failed = false;
-}
-
-void
-PurpleKWalletPlugin::Engine::enqueue(PurpleKWalletPlugin::Request *request) {
- this->queue.enqueue(request);
-
- processQueue();
-}
-
-void
-PurpleKWalletPlugin::Engine::opened(bool opened) {
- QString folder_name;
-
- if(!opened) {
- purple_debug_error("kwallet-provider", "failed to open wallet");
-
- delete this->wallet;
- this->wallet = NULL;
-
- this->connected = false;
- this->failed = true;
-
- return;
- }
-
- // Handle the case where the wallet opened signal connected, but the wallet
- // closed signal failed to connect.
- if(this->failed) {
- purple_debug_error("kwallet-provider",
- "wallet opened, but failed to connect the wallet "
- "closed signal");
- return;
- }
-
- this->connected = true;
-
- // setup our folder
- 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());
- this->failed = true;
- }
- }
-
- if(!this->failed && !this->wallet->setFolder(folder_name)) {
- purple_debug_error("kwallet-provider", "failed to set folder to %s",
- folder_name.toUtf8().constData());
- this->failed = true;
- }
-
- purple_debug_misc("kwallet-provider", "successfully opened the wallet");
-
- processQueue();
-}
-
-void
-PurpleKWalletPlugin::Engine::closed(void) {
- purple_debug_misc("kwallet-provider", "the wallet was closed externally");
-
- this->externallyClosed = true;
- this->close();
-}
-
-void
-PurpleKWalletPlugin::Engine::processQueue() {
- if(this->externallyClosed && this->queue.isEmpty() == false) {
- this->open();
- } else if(this->connected || this->failed) {
- while(!this->queue.isEmpty()) {
- PurpleKWalletPlugin::Request *request = this->queue.dequeue();
-
- if(this->failed) {
- request->cancel(_("failed to open kwallet"));
- } else {
- request->execute(this->wallet);
- }
-
- delete request;
- }
- }
-}
-
-/******************************************************************************
- * PurpleCredentialProvider Implementation
- *****************************************************************************/
-static void
-purple_kwallet_provider_activate(PurpleCredentialProvider *provider) {
- PurpleKWalletProvider *kwallet_provider = NULL;
-
- kwallet_provider = PURPLE_KWALLET_PROVIDER(provider);
-
- kwallet_provider->engine->open();
-}
-
-static void
-purple_kwallet_provider_deactivate(PurpleCredentialProvider *provider) {
- PurpleKWalletProvider *kwallet_provider = NULL;
-
- kwallet_provider = PURPLE_KWALLET_PROVIDER(provider);
-
- kwallet_provider->engine->close();
-}
-
-static void
-purple_kwallet_read_password_async(PurpleCredentialProvider *provider,
- PurpleAccount *account,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer data)
-{
- PurpleKWalletProvider *kwallet_provider = NULL;
- PurpleKWalletPlugin::ReadRequest *request = NULL;
- GTask *task = NULL;
- QString key;
-
- 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);
-
- g_clear_object(&task);
-}
-
-static gchar *
-purple_kwallet_read_password_finish(PurpleCredentialProvider *provider,
- GAsyncResult *result, GError **error)
-{
- return (gchar *)g_task_propagate_pointer(G_TASK(result), error);
-}
-
-static void
-purple_kwallet_write_password_async(PurpleCredentialProvider *provider,
- PurpleAccount *account,
- const gchar *password,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer data)
-{
- PurpleKWalletProvider *kwallet_provider = NULL;
- PurpleKWalletPlugin::WriteRequest *request = NULL;
- GTask *task = NULL;
- QString key;
-
- 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);
-
- g_clear_object(&task);
-}
-
-static gboolean
-purple_kwallet_write_password_finish(PurpleCredentialProvider *provider,
- GAsyncResult *result, GError **error)
-{
- return g_task_propagate_boolean(G_TASK(result), error);
-}
-
-static void
-purple_kwallet_clear_password_async(PurpleCredentialProvider *provider,
- PurpleAccount *account,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer data)
-{
- PurpleKWalletProvider *kwallet_provider = NULL;
- PurpleKWalletPlugin::ClearRequest *request = NULL;
- GTask *task = NULL;
- QString key;
-
- 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);
-
- g_clear_object(&task);
-}
-
-static gboolean
-purple_kwallet_clear_password_finish(PurpleCredentialProvider *provider,
- GAsyncResult *result, GError **error)
-{
- return g_task_propagate_boolean(G_TASK(result), error);
-}
-
-/******************************************************************************
- * GObject Implementation
- *****************************************************************************/
-static void
-purple_kwallet_provider_dispose(GObject *obj) {
- PurpleKWalletProvider *provider = PURPLE_KWALLET_PROVIDER(obj);
-
- if(provider->engine != NULL) {
- provider->engine->close();
- }
-
- G_OBJECT_CLASS(purple_kwallet_provider_parent_class)->dispose(obj);
-}
-
-static void
-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);
-}
-
-static void
-purple_kwallet_provider_init(PurpleKWalletProvider *provider) {
- provider->engine = new PurpleKWalletPlugin::Engine();
-}
-
-static void
-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;
-}
-
-static void
-purple_kwallet_provider_class_finalize(PurpleKWalletProviderClass *klass) {
-}
-
-/******************************************************************************
- * API
- *****************************************************************************/
-static PurpleCredentialProvider *
-purple_kwallet_provider_new(void) {
- return PURPLE_CREDENTIAL_PROVIDER(g_object_new(
- PURPLE_KWALLET_TYPE_PROVIDER,
- "id", "kwallet",
- "name", _("KWallet"),
- "description", _("A credentials management application for the KDE "
- "Software Compilation desktop environment"),
- NULL
- ));
-}
-
-/******************************************************************************
- * Plugin Exports
- *****************************************************************************/
-static GPluginPluginInfo *
-kwallet_query(G_GNUC_UNUSED GError **error) {
- const gchar * const authors[] = {
- "Pidgin Developers <devel@pidgin.im>",
- NULL
- };
-
- return GPLUGIN_PLUGIN_INFO(purple_plugin_info_new(
- "id", "keyring-kwallet",
- "name", N_("KWallet"),
- "version", DISPLAY_VERSION,
- "category", N_("Keyring"),
- "summary", "KWallet Keyring Plugin",
- "description", N_("This plugin will store passwords in KWallet."),
- "authors", authors,
- "website", PURPLE_WEBSITE,
- "abi-version", PURPLE_ABI_VERSION,
- "flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL,
- NULL
- ));
-}
-
-static gboolean
-kwallet_load(GPluginPlugin *plugin, GError **error) {
- PurpleCredentialManager *manager = NULL;
-
- purple_kwallet_provider_register_type(G_TYPE_MODULE(plugin));
-
- if(qCoreApp == NULL) {
- int argc = 0;
- qCoreApp = new QCoreApplication(argc, NULL);
- qCoreApp->setApplicationName(purple_kwallet_get_ui_name());
- }
-
- if(!KWallet::Wallet::isEnabled()) {
- g_set_error(error, PURPLE_KWALLET_DOMAIN, 0,
- "KWallet service is disabled.");
-
- return FALSE;
- }
-
- manager = purple_credential_manager_get_default();
-
- instance = purple_kwallet_provider_new();
-
- return purple_credential_manager_register(manager, instance, error);
-}
-
-static gboolean
-kwallet_unload(G_GNUC_UNUSED GPluginPlugin *plugin,
- G_GNUC_UNUSED gboolean shutdown,
- GError **error)
-{
- PurpleCredentialManager *manager = NULL;
- gboolean ret = FALSE;
-
- manager = purple_credential_manager_get_default();
- ret = purple_credential_manager_unregister(manager, instance, error);
-
- if(!ret) {
- return ret;
- }
-
- if(qCoreApp != NULL) {
- delete qCoreApp;
- qCoreApp = NULL;
- }
-
- g_clear_object(&instance);
-
- return TRUE;
-}
-
-G_BEGIN_DECLS
-GPLUGIN_NATIVE_PLUGIN_DECLARE(kwallet)
-G_END_DECLS
--- a/libpurple/plugins/keyrings/kwallet/purplekwallet.h Mon Nov 15 02:21:18 2021 -0600
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-/*
- * purple
- *
- * 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
- * source distribution.
- *
- * 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 library; if not, see <https://www.gnu.org/licenses/>.
- */
-
-#include <glib.h>
-
-#include <purple.h>
-
-#include <kwallet.h>
-#include <QQueue>
-
-#define PURPLE_KWALLET_TYPE_PROVIDER (purple_kwallet_provider_get_type())
-G_DECLARE_FINAL_TYPE(PurpleKWalletProvider, purple_kwallet_provider,
- PURPLE_KWALLET, PROVIDER, PurpleCredentialProvider)
-
-namespace PurpleKWalletPlugin {
-
-class Request {
-public:
- Request(QString key, GTask *task);
- virtual ~Request(void);
- virtual void execute(KWallet::Wallet *wallet) = 0;
- virtual void cancel(QString reason) = 0;
-protected:
- QString key;
- GTask *task;
-};
-
-class ReadRequest : public Request {
-public:
- ReadRequest(QString key, GTask *task);
- void execute(KWallet::Wallet *wallet);
- void cancel(QString reason);
-};
-
-class WriteRequest : public Request {
-public:
- WriteRequest(QString key, GTask *task, QString password);
- void execute(KWallet::Wallet *wallet);
- void cancel(QString reason);
-private:
- QString password;
-};
-
-class ClearRequest : public Request {
-public:
- ClearRequest(QString key, GTask *task);
- void execute(KWallet::Wallet *wallet);
- void cancel(QString reason);
-};
-
-class Engine : public QObject {
- Q_OBJECT
-
-public:
- Engine(void);
- ~Engine(void);
-
- void open(void);
- void close(void);
- void enqueue(Request *request);
-private slots:
- void opened(bool opened);
- void closed(void);
-private:
- void processQueue(void);
-
- bool connected;
- bool externallyClosed;
- bool failed;
-
- KWallet::Wallet *wallet;
-
- QQueue<Request *> queue;
-};
-
-}
--- a/libpurple/plugins/keyrings/meson.build Mon Nov 15 02:21:18 2021 -0600
+++ b/libpurple/plugins/keyrings/meson.build Mon Nov 15 02:23:25 2021 -0600
@@ -1,5 +1,3 @@
-subdir('kwallet')
-
if nettle.found()
internalkeyring_plugin = library('internalkeyring', 'internalkeyring.c',
c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Purple-InternalKeyring"'],
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/kwallet/meson.build Mon Nov 15 02:23:25 2021 -0600
@@ -0,0 +1,20 @@
+if kwallet.found()
+ kwallet_moc = qt5.preprocess(
+ moc_headers: 'purplekwallet.h',
+ dependencies: qt5_dep,
+ )
+
+ kwallet_sources = [
+ 'purplekwallet.cpp',
+ 'purplekwallet.h',
+ kwallet_moc,
+ ]
+
+ kwallet_plugin = library('purplekwallet', kwallet_sources,
+ c_args : ['-DG_LOG_USE_STRUCTURED', '-DG_LOG_DOMAIN="Purple-KWalletKeyring"'],
+ dependencies : [kwallet, qt5_dep, libpurple_dep],
+ name_prefix : '',
+ install : true, install_dir : PURPLE_PLUGINDIR)
+
+ devenv.append('PURPLE_PLUGIN_PATH', meson.current_build_dir())
+endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/kwallet/purplekwallet.cpp Mon Nov 15 02:23:25 2021 -0600
@@ -0,0 +1,618 @@
+/*
+ * purple
+ *
+ * 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
+ * source distribution.
+ *
+ * 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 library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <purple.h>
+
+#include <QCoreApplication>
+
+#include <kwallet.h>
+
+#include "purplekwallet.h"
+
+/******************************************************************************
+ * Globals
+ *****************************************************************************/
+static QCoreApplication *qCoreApp = NULL;
+static PurpleCredentialProvider *instance = NULL;
+
+#define PURPLE_KWALLET_DOMAIN (g_quark_from_static_string("purple-kwallet"))
+#define PURPLE_KWALLET_WALLET_NAME (KWallet::Wallet::NetworkWallet())
+
+struct _PurpleKWalletProvider {
+ PurpleCredentialProvider parent;
+
+ PurpleKWalletPlugin::Engine *engine;
+};
+
+G_DEFINE_DYNAMIC_TYPE(PurpleKWalletProvider, purple_kwallet_provider,
+ PURPLE_TYPE_CREDENTIAL_PROVIDER)
+
+/******************************************************************************
+ * Helpers
+ *****************************************************************************/
+static QString
+purple_kwallet_get_ui_name(void) {
+ PurpleUiInfo *ui_info = NULL;
+ QString ui_name = NULL;
+
+ ui_info = purple_core_get_ui_info();
+ if(PURPLE_IS_UI_INFO(ui_info)) {
+ ui_name = purple_ui_info_get_name(ui_info);
+ g_object_unref(G_OBJECT(ui_info));
+ }
+
+ if(ui_name.isEmpty()) {
+ ui_name = "libpurple";
+ }
+
+ return ui_name;
+}
+
+static QString
+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->key = key;
+ 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) {
+}
+
+void
+PurpleKWalletPlugin::ReadRequest::execute(KWallet::Wallet *wallet) {
+ QString password;
+ int result = 0;
+ bool missing;
+
+ missing = KWallet::Wallet::keyDoesNotExist(PURPLE_KWALLET_WALLET_NAME,
+ purple_kwallet_get_ui_name(),
+ key);
+
+ if(missing) {
+ g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, 0,
+ "no password stored");
+
+ g_clear_object(&this->task);
+
+ return;
+ }
+
+ result = wallet->readPassword(this->key, password);
+
+ if(result != 0) {
+ g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, result,
+ _("failed to read password, kwallet responded "
+ "with error code %d"), result);
+ } else {
+ gchar *c_password = g_strdup(password.toUtf8().constData());
+ g_task_return_pointer(this->task, c_password, g_free);
+ }
+
+ g_clear_object(&this->task);
+}
+
+void
+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;
+}
+
+void
+PurpleKWalletPlugin::WriteRequest::execute(KWallet::Wallet *wallet) {
+ int result;
+
+ result = wallet->writePassword(this->key, this->password);
+
+ if(result != 0) {
+ g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, result,
+ _("failed to write password, kwallet "
+ "responded with error code %d"), result);
+ } else {
+ g_task_return_boolean(this->task, TRUE);
+ }
+
+ g_clear_object(&this->task);
+}
+
+void
+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) {
+}
+
+void
+PurpleKWalletPlugin::ClearRequest::execute(KWallet::Wallet *wallet) {
+ int result;
+
+ result = wallet->removeEntry(this->key);
+
+ if(result != 0) {
+ g_task_return_new_error(this->task, PURPLE_KWALLET_DOMAIN, result,
+ _("failed to clear password, kwallet "
+ "responded with error code %d"), result);
+ } else {
+ g_task_return_boolean(this->task, TRUE);
+ }
+
+ g_clear_object(&this->task);
+}
+
+void
+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->wallet = NULL;
+
+ this->connected = false;
+ this->failed = false;
+ this->externallyClosed = false;
+}
+
+PurpleKWalletPlugin::Engine::~Engine(void) {
+ this->close();
+}
+
+void
+PurpleKWalletPlugin::Engine::open(void) {
+ purple_debug_misc("kwallet-provider", "attempting to open wallet");
+
+ if(this->connected) {
+ purple_debug_misc("kwallet-provider", "wallet already opened");
+
+ return;
+ }
+
+ // Reset our externallyClosed and failed states.
+ this->externallyClosed = false;
+ this->failed = false;
+
+ // No need to check this pointer as an async open always returns non-null.
+ this->wallet = KWallet::Wallet::openWallet(PURPLE_KWALLET_WALLET_NAME,
+ 0,
+ KWallet::Wallet::Asynchronous);
+
+ this->failed |= !QObject::connect(this->wallet, SIGNAL(walletOpened(bool)),
+ SLOT(opened(bool)));
+ this->failed |= !QObject::connect(this->wallet, SIGNAL(walletClosed(void)),
+ SLOT(closed()));
+
+ if(this->failed) {
+ purple_debug_error("kwallet-provider",
+ "Failed to connect KWallet signals");
+ }
+}
+
+void
+PurpleKWalletPlugin::Engine::close(void) {
+ while(!this->queue.isEmpty()) {
+ PurpleKWalletPlugin::Request *request = this->queue.dequeue();
+
+ request->cancel("wallet is closing");
+
+ delete request;
+ }
+
+ if(this->wallet != NULL) {
+ delete this->wallet;
+ this->wallet = NULL;
+ }
+
+ this->connected = false;
+ this->failed = false;
+}
+
+void
+PurpleKWalletPlugin::Engine::enqueue(PurpleKWalletPlugin::Request *request) {
+ this->queue.enqueue(request);
+
+ processQueue();
+}
+
+void
+PurpleKWalletPlugin::Engine::opened(bool opened) {
+ QString folder_name;
+
+ if(!opened) {
+ purple_debug_error("kwallet-provider", "failed to open wallet");
+
+ delete this->wallet;
+ this->wallet = NULL;
+
+ this->connected = false;
+ this->failed = true;
+
+ return;
+ }
+
+ // Handle the case where the wallet opened signal connected, but the wallet
+ // closed signal failed to connect.
+ if(this->failed) {
+ purple_debug_error("kwallet-provider",
+ "wallet opened, but failed to connect the wallet "
+ "closed signal");
+ return;
+ }
+
+ this->connected = true;
+
+ // setup our folder
+ 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());
+ this->failed = true;
+ }
+ }
+
+ if(!this->failed && !this->wallet->setFolder(folder_name)) {
+ purple_debug_error("kwallet-provider", "failed to set folder to %s",
+ folder_name.toUtf8().constData());
+ this->failed = true;
+ }
+
+ purple_debug_misc("kwallet-provider", "successfully opened the wallet");
+
+ processQueue();
+}
+
+void
+PurpleKWalletPlugin::Engine::closed(void) {
+ purple_debug_misc("kwallet-provider", "the wallet was closed externally");
+
+ this->externallyClosed = true;
+ this->close();
+}
+
+void
+PurpleKWalletPlugin::Engine::processQueue() {
+ if(this->externallyClosed && this->queue.isEmpty() == false) {
+ this->open();
+ } else if(this->connected || this->failed) {
+ while(!this->queue.isEmpty()) {
+ PurpleKWalletPlugin::Request *request = this->queue.dequeue();
+
+ if(this->failed) {
+ request->cancel(_("failed to open kwallet"));
+ } else {
+ request->execute(this->wallet);
+ }
+
+ delete request;
+ }
+ }
+}
+
+/******************************************************************************
+ * PurpleCredentialProvider Implementation
+ *****************************************************************************/
+static void
+purple_kwallet_provider_activate(PurpleCredentialProvider *provider) {
+ PurpleKWalletProvider *kwallet_provider = NULL;
+
+ kwallet_provider = PURPLE_KWALLET_PROVIDER(provider);
+
+ kwallet_provider->engine->open();
+}
+
+static void
+purple_kwallet_provider_deactivate(PurpleCredentialProvider *provider) {
+ PurpleKWalletProvider *kwallet_provider = NULL;
+
+ kwallet_provider = PURPLE_KWALLET_PROVIDER(provider);
+
+ kwallet_provider->engine->close();
+}
+
+static void
+purple_kwallet_read_password_async(PurpleCredentialProvider *provider,
+ PurpleAccount *account,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer data)
+{
+ PurpleKWalletProvider *kwallet_provider = NULL;
+ PurpleKWalletPlugin::ReadRequest *request = NULL;
+ GTask *task = NULL;
+ QString key;
+
+ 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);
+
+ g_clear_object(&task);
+}
+
+static gchar *
+purple_kwallet_read_password_finish(PurpleCredentialProvider *provider,
+ GAsyncResult *result, GError **error)
+{
+ return (gchar *)g_task_propagate_pointer(G_TASK(result), error);
+}
+
+static void
+purple_kwallet_write_password_async(PurpleCredentialProvider *provider,
+ PurpleAccount *account,
+ const gchar *password,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer data)
+{
+ PurpleKWalletProvider *kwallet_provider = NULL;
+ PurpleKWalletPlugin::WriteRequest *request = NULL;
+ GTask *task = NULL;
+ QString key;
+
+ 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);
+
+ g_clear_object(&task);
+}
+
+static gboolean
+purple_kwallet_write_password_finish(PurpleCredentialProvider *provider,
+ GAsyncResult *result, GError **error)
+{
+ return g_task_propagate_boolean(G_TASK(result), error);
+}
+
+static void
+purple_kwallet_clear_password_async(PurpleCredentialProvider *provider,
+ PurpleAccount *account,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer data)
+{
+ PurpleKWalletProvider *kwallet_provider = NULL;
+ PurpleKWalletPlugin::ClearRequest *request = NULL;
+ GTask *task = NULL;
+ QString key;
+
+ 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);
+
+ g_clear_object(&task);
+}
+
+static gboolean
+purple_kwallet_clear_password_finish(PurpleCredentialProvider *provider,
+ GAsyncResult *result, GError **error)
+{
+ return g_task_propagate_boolean(G_TASK(result), error);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+static void
+purple_kwallet_provider_dispose(GObject *obj) {
+ PurpleKWalletProvider *provider = PURPLE_KWALLET_PROVIDER(obj);
+
+ if(provider->engine != NULL) {
+ provider->engine->close();
+ }
+
+ G_OBJECT_CLASS(purple_kwallet_provider_parent_class)->dispose(obj);
+}
+
+static void
+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);
+}
+
+static void
+purple_kwallet_provider_init(PurpleKWalletProvider *provider) {
+ provider->engine = new PurpleKWalletPlugin::Engine();
+}
+
+static void
+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;
+}
+
+static void
+purple_kwallet_provider_class_finalize(PurpleKWalletProviderClass *klass) {
+}
+
+/******************************************************************************
+ * API
+ *****************************************************************************/
+static PurpleCredentialProvider *
+purple_kwallet_provider_new(void) {
+ return PURPLE_CREDENTIAL_PROVIDER(g_object_new(
+ PURPLE_KWALLET_TYPE_PROVIDER,
+ "id", "kwallet",
+ "name", _("KWallet"),
+ "description", _("A credentials management application for the KDE "
+ "Software Compilation desktop environment"),
+ NULL
+ ));
+}
+
+/******************************************************************************
+ * Plugin Exports
+ *****************************************************************************/
+static GPluginPluginInfo *
+kwallet_query(G_GNUC_UNUSED GError **error) {
+ const gchar * const authors[] = {
+ "Pidgin Developers <devel@pidgin.im>",
+ NULL
+ };
+
+ return GPLUGIN_PLUGIN_INFO(purple_plugin_info_new(
+ "id", "keyring-kwallet",
+ "name", N_("KWallet"),
+ "version", DISPLAY_VERSION,
+ "category", N_("Keyring"),
+ "summary", "KWallet Keyring Plugin",
+ "description", N_("This plugin will store passwords in KWallet."),
+ "authors", authors,
+ "website", PURPLE_WEBSITE,
+ "abi-version", PURPLE_ABI_VERSION,
+ "flags", PURPLE_PLUGIN_INFO_FLAGS_INTERNAL |
+ PURPLE_PLUGIN_INFO_FLAGS_AUTO_LOAD,
+ NULL
+ ));
+}
+
+static gboolean
+kwallet_load(GPluginPlugin *plugin, GError **error) {
+ PurpleCredentialManager *manager = NULL;
+
+ purple_kwallet_provider_register_type(G_TYPE_MODULE(plugin));
+
+ if(qCoreApp == NULL) {
+ int argc = 0;
+ qCoreApp = new QCoreApplication(argc, NULL);
+ qCoreApp->setApplicationName(purple_kwallet_get_ui_name());
+ }
+
+ if(!KWallet::Wallet::isEnabled()) {
+ g_set_error(error, PURPLE_KWALLET_DOMAIN, 0,
+ "KWallet service is disabled.");
+
+ return FALSE;
+ }
+
+ manager = purple_credential_manager_get_default();
+
+ instance = purple_kwallet_provider_new();
+
+ return purple_credential_manager_register(manager, instance, error);
+}
+
+static gboolean
+kwallet_unload(G_GNUC_UNUSED GPluginPlugin *plugin,
+ G_GNUC_UNUSED gboolean shutdown,
+ GError **error)
+{
+ PurpleCredentialManager *manager = NULL;
+ gboolean ret = FALSE;
+
+ manager = purple_credential_manager_get_default();
+ ret = purple_credential_manager_unregister(manager, instance, error);
+
+ if(!ret) {
+ return ret;
+ }
+
+ if(qCoreApp != NULL) {
+ delete qCoreApp;
+ qCoreApp = NULL;
+ }
+
+ g_clear_object(&instance);
+
+ return TRUE;
+}
+
+G_BEGIN_DECLS
+GPLUGIN_NATIVE_PLUGIN_DECLARE(kwallet)
+G_END_DECLS
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/plugins/kwallet/purplekwallet.h Mon Nov 15 02:23:25 2021 -0600
@@ -0,0 +1,94 @@
+/*
+ * purple
+ *
+ * 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
+ * source distribution.
+ *
+ * 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 library; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+
+#include <purple.h>
+
+#include <kwallet.h>
+#include <QQueue>
+
+#define PURPLE_KWALLET_TYPE_PROVIDER (purple_kwallet_provider_get_type())
+G_DECLARE_FINAL_TYPE(PurpleKWalletProvider, purple_kwallet_provider,
+ PURPLE_KWALLET, PROVIDER, PurpleCredentialProvider)
+
+namespace PurpleKWalletPlugin {
+
+class Request {
+public:
+ Request(QString key, GTask *task);
+ virtual ~Request(void);
+ virtual void execute(KWallet::Wallet *wallet) = 0;
+ virtual void cancel(QString reason) = 0;
+protected:
+ QString key;
+ GTask *task;
+};
+
+class ReadRequest : public Request {
+public:
+ ReadRequest(QString key, GTask *task);
+ void execute(KWallet::Wallet *wallet);
+ void cancel(QString reason);
+};
+
+class WriteRequest : public Request {
+public:
+ WriteRequest(QString key, GTask *task, QString password);
+ void execute(KWallet::Wallet *wallet);
+ void cancel(QString reason);
+private:
+ QString password;
+};
+
+class ClearRequest : public Request {
+public:
+ ClearRequest(QString key, GTask *task);
+ void execute(KWallet::Wallet *wallet);
+ void cancel(QString reason);
+};
+
+class Engine : public QObject {
+ Q_OBJECT
+
+public:
+ Engine(void);
+ ~Engine(void);
+
+ void open(void);
+ void close(void);
+ void enqueue(Request *request);
+private slots:
+ void opened(bool opened);
+ void closed(void);
+private:
+ void processQueue(void);
+
+ bool connected;
+ bool externallyClosed;
+ bool failed;
+
+ KWallet::Wallet *wallet;
+
+ QQueue<Request *> queue;
+};
+
+}
--- a/libpurple/plugins/meson.build Mon Nov 15 02:21:18 2021 -0600
+++ b/libpurple/plugins/meson.build Mon Nov 15 02:23:25 2021 -0600
@@ -1,4 +1,5 @@
subdir('keyrings')
+subdir('kwallet')
subdir('notification-sound')
autoaccept = library('autoaccept', 'autoaccept.c',
--- a/po/POTFILES.in Mon Nov 15 02:21:18 2021 -0600
+++ b/po/POTFILES.in Mon Nov 15 02:23:25 2021 -0600
@@ -61,9 +61,9 @@
libpurple/plugins/idle.c
libpurple/plugins/joinpart.c
libpurple/plugins/keyrings/internalkeyring.c
-libpurple/plugins/keyrings/kwallet/purplekwallet.cpp
libpurple/plugins/keyrings/secretservice.c
libpurple/plugins/keyrings/wincred.c
+libpurple/plugins/kwallet/purplekwallet.cpp
libpurple/plugins/notification-sound/notification-sound.c
libpurple/plugins/psychic.c
libpurple/plugins/purple-toast.c