Sun, 16 May 2021 12:20:09 -0500
Port the plugins that were manually specific GPlugin exports to the new GPlugin declare macro
Testing Done:
Loaded some of the plugins to make sure they were fine.
Reviewed at https://reviews.imfreedom.org/r/654/
/* * 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_provider(manager, instance, error); } static gboolean kwallet_unload(G_GNUC_UNUSED GPluginPlugin *plugin, GError **error) { PurpleCredentialManager *manager = NULL; gboolean ret = FALSE; manager = purple_credential_manager_get_default(); ret = purple_credential_manager_unregister_provider(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