File indexing completed on 2024-11-24 04:53:25

0001 /* Copyright (C) 2013 Pali Rohár <pali.rohar@gmail.com>
0002 
0003    This file is part of the Trojita Qt IMAP e-mail client,
0004    http://trojita.flaska.net/
0005 
0006    This program is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU General Public License as
0008    published by the Free Software Foundation; either version 2 of
0009    the License or (at your option) version 3 or any later version
0010    accepted by the membership of KDE e.V. (or its successor approved
0011    by the membership of KDE e.V.), which shall act as a proxy
0012    defined in Section 14 of version 3 of the license.
0013 
0014    This program is distributed in the hope that it will be useful,
0015    but WITHOUT ANY WARRANTY; without even the implied warranty of
0016    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0017    GNU General Public License for more details.
0018 
0019    You should have received a copy of the GNU General Public License
0020    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0021 */
0022 
0023 #include <QCoreApplication>
0024 #include <QDebug>
0025 #include <QDir>
0026 #include <QFileInfo>
0027 #include <QLibraryInfo>
0028 #include <QMap>
0029 #include <QPluginLoader>
0030 #include <QSettings>
0031 #include <QString>
0032 #include <QStringList>
0033 
0034 #include "configure.cmake.h"
0035 #include "Common/InvokeMethod.h"
0036 #include "Plugins/AddressbookPlugin.h"
0037 #include "Plugins/PasswordPlugin.h"
0038 #include "Plugins/PluginInterface.h"
0039 #include "Plugins/PluginManager.h"
0040 
0041 
0042 namespace Plugins {
0043 
0044 PluginManager::PluginManager(QObject *parent, QSettings *settings,
0045                              const QString &addressbookKey, const QString &passwordKey, const QString &spellcheckerKey)
0046     : QObject(parent)
0047     , m_settings(settings)
0048     , m_addressbookKey(addressbookKey)
0049     , m_passwordKey(passwordKey)
0050     , m_spellcheckerKey(spellcheckerKey)
0051 {
0052     m_addressbookName = m_settings->value(m_addressbookKey, QLatin1String("abookaddressbook")).toString();
0053     m_passwordName = m_settings->value(m_passwordKey, QLatin1String("cleartextpassword")).toString();
0054     m_spellcheckerName = m_settings->value(m_spellcheckerKey, QString()).toString();
0055     CALL_LATER_NOARG(this, loadPlugins)
0056 }
0057 
0058 void PluginManager::loadPlugins()
0059 {
0060     QStringList pluginDirs;
0061     pluginDirs << qApp->applicationDirPath();
0062 
0063     auto pluginDir = QStringLiteral(PLUGIN_DIR);
0064     if (!pluginDirs.contains(pluginDir))
0065         pluginDirs << pluginDir;
0066 
0067 #ifdef PLUGIN_DEBUG
0068     qDebug() << "Number of static linked plugins:" << QPluginLoader::staticInstances().size();
0069 #endif
0070 
0071 #ifdef PLUGIN_DEBUG
0072     qDebug() << "Searching for plugins in:" << pluginDirs;
0073 #endif
0074 
0075     QStringList absoluteFilePaths;
0076 
0077     QSet<QString> loadedFiles;
0078 
0079     Q_FOREACH(const QString &dirName, pluginDirs) {
0080         QDir dir(dirName);
0081         auto filter(QStringLiteral("trojita_plugin_*"));
0082         Q_FOREACH(const QString &fileName, dir.entryList(QStringList() << filter, QDir::Files)) {
0083             const auto fi = QFileInfo(dir.absoluteFilePath(fileName));
0084             const auto &absoluteFilePath = fi.canonicalFilePath();
0085             const auto &shortFileName = fi.fileName();
0086             if (absoluteFilePaths.contains(absoluteFilePath)) {
0087                 continue;
0088             }
0089             absoluteFilePaths << absoluteFilePath;
0090             if (!QLibrary::isLibrary(absoluteFilePath)) {
0091                 continue;
0092             }
0093             if (loadedFiles.contains(shortFileName)) {
0094 #ifdef PLUGIN_DEBUG
0095             qDebug() << "Skiping file" << absoluteFilePath << "because the same-named plugin has been already seen";
0096 #endif
0097                 continue;
0098             }
0099 #ifdef PLUGIN_DEBUG
0100             qDebug() << "Opening file" << absoluteFilePath;
0101 #endif
0102             QPluginLoader *loader = new QPluginLoader(absoluteFilePath, this);
0103             if (loader->load()) {
0104                 loadPlugin(loader->instance());
0105                 loadedFiles.insert(shortFileName);
0106             } else {
0107                 emit pluginError(loader->errorString());
0108             }
0109         }
0110     }
0111 
0112     Q_FOREACH(QObject *pluginInstance, QPluginLoader::staticInstances()) {
0113         loadPlugin(pluginInstance);
0114     }
0115 
0116     emit pluginsChanged();
0117 }
0118 
0119 PluginManager::~PluginManager()
0120 {
0121 }
0122 
0123 void PluginManager::loadPlugin(QObject *pluginInstance)
0124 {
0125     Q_ASSERT(pluginInstance);
0126 
0127     if (auto abookPlugin = qobject_cast<AddressbookPluginInterface *>(pluginInstance)) {
0128         const QString &name = abookPlugin->name();
0129         Q_ASSERT(!name.isEmpty());
0130         Q_ASSERT(!m_availableAddressbookPlugins.contains(name));
0131         m_availableAddressbookPlugins[name] = abookPlugin;
0132 #ifdef PLUGIN_DEBUG
0133         qDebug() << "Found addressbook plugin" << name << ":" << abookPlugin->description();
0134 #endif
0135         if (name == m_addressbookName) {
0136 #ifdef PLUGIN_DEBUG
0137             qDebug() << "Will activate new default plugin" << name;
0138 #endif
0139             setAddressbookPlugin(name);
0140         }
0141     }
0142 
0143     if (auto passwordPlugin = qobject_cast<PasswordPluginInterface *>(pluginInstance)) {
0144         const QString &name = passwordPlugin->name();
0145         Q_ASSERT(!name.isEmpty());
0146         Q_ASSERT(!m_availablePasswordPlugins.contains(name));
0147         m_availablePasswordPlugins[name] = passwordPlugin;
0148 #ifdef PLUGIN_DEBUG
0149         qDebug() << "Found password plugin" << name << ":" << passwordPlugin->description();
0150 #endif
0151         if (name == m_passwordName) {
0152 #ifdef PLUGIN_DEBUG
0153             qDebug() << "Will activate new default plugin" << name;
0154 #endif
0155             setPasswordPlugin(name);
0156         }
0157     }
0158 
0159     if (auto spellcheckerPlugin = qobject_cast<SpellcheckerPluginInterface *>(pluginInstance)) {
0160         const QString &name = spellcheckerPlugin->name();
0161         Q_ASSERT(!name.isEmpty());
0162         Q_ASSERT(!m_availableSpellcheckPlugins.contains(name));
0163         m_availableSpellcheckPlugins[name] = spellcheckerPlugin;
0164 #ifdef PLUGIN_DEBUG
0165         qDebug() << "Found spellchecker plugin" << name << ":" << spellcheckerPlugin->description();
0166 #endif
0167         if (name == m_spellcheckerName) {
0168 #ifdef PLUGIN_DEBUG
0169             qDebug() << "Will activate new default plugin" << name;
0170 #endif
0171             setSpellcheckerPlugin(name);
0172         }
0173     }
0174 }
0175 
0176 QMap<QString, QString> PluginManager::availableAddressbookPlugins() const
0177 {
0178     QMap<QString, QString> res;
0179     for (auto plugin: m_availableAddressbookPlugins) {
0180         res[plugin->name()] = plugin->description();
0181     }
0182     return res;
0183 }
0184 
0185 QMap<QString, QString> PluginManager::availablePasswordPlugins() const
0186 {
0187     QMap<QString, QString> res;
0188     for (auto plugin: m_availablePasswordPlugins) {
0189         res[plugin->name()] = plugin->description();
0190     }
0191     return res;
0192 }
0193 
0194 QMap<QString, QString> PluginManager::availableSpellcheckerPlugins() const
0195 {
0196     QMap<QString, QString> res;
0197     for (auto plugin: m_availableSpellcheckPlugins) {
0198         res[plugin->name()] = plugin->description();
0199     }
0200     return res;
0201 }
0202 
0203 QString PluginManager::addressbookPlugin() const
0204 {
0205     return m_addressbookName;
0206 }
0207 
0208 QString PluginManager::passwordPlugin() const
0209 {
0210     return m_passwordName;
0211 }
0212 
0213 QString PluginManager::spellcheckerPlugin() const
0214 {
0215     return m_spellcheckerName;
0216 }
0217 
0218 void PluginManager::setAddressbookPlugin(const QString &name)
0219 {
0220     m_addressbookName = name;
0221     m_settings->setValue(m_addressbookKey, name);
0222 
0223     if (m_addressbook) {
0224         delete m_addressbook;
0225     }
0226 
0227     auto plugin = m_availableAddressbookPlugins.find(name);
0228     if (plugin != m_availableAddressbookPlugins.end()) {
0229 #ifdef PLUGIN_DEBUG
0230         qDebug() << "Setting new address book plugin:" << (*plugin)->name();
0231 #endif
0232         m_addressbook = (*plugin)->create(this, m_settings);
0233     }
0234 
0235     emit pluginsChanged();
0236 }
0237 
0238 void PluginManager::setPasswordPlugin(const QString &name)
0239 {
0240     m_passwordName = name;
0241     m_settings->setValue(m_passwordKey, name);
0242 
0243     if (m_password) {
0244         delete m_password;
0245     }
0246 
0247     auto plugin = m_availablePasswordPlugins.find(name);
0248     if (plugin != m_availablePasswordPlugins.end()) {
0249 #ifdef PLUGIN_DEBUG
0250         qDebug() << "Setting new password plugin:" << (*plugin)->name();
0251 #endif
0252         m_password = (*plugin)->create(this, m_settings);
0253     }
0254 
0255     emit pluginsChanged();
0256 }
0257 
0258 void PluginManager::setSpellcheckerPlugin(const QString &name)
0259 {
0260     m_spellcheckerName = name;
0261     m_settings->setValue(m_spellcheckerKey, name);
0262 
0263     if (m_spellchecker) {
0264         delete m_spellchecker;
0265     }
0266 
0267     auto plugin = m_availableSpellcheckPlugins.find(name);
0268     if (plugin != m_availableSpellcheckPlugins.end()) {
0269 #ifdef PLUGIN_DEBUG
0270         qDebug() << "Setting new spellchecker plugin:" << (*plugin)->name();
0271 #endif
0272         m_spellchecker = (*plugin)->create(this, m_settings);
0273     }
0274 
0275     emit pluginsChanged();
0276 }
0277 
0278 Plugins::AddressbookPlugin *PluginManager::addressbook() const
0279 {
0280     return m_addressbook;
0281 }
0282 
0283 Plugins::PasswordPlugin *PluginManager::password() const
0284 {
0285     return m_password;
0286 }
0287 
0288 Plugins::SpellcheckerPlugin *PluginManager::spellchecker() const
0289 {
0290     return m_spellchecker;
0291 }
0292 
0293 const PluginManager::MimePartReplacers &PluginManager::mimePartReplacers() const
0294 {
0295     return m_mimePartReplacers;
0296 }
0297 
0298 // FIXME: this API sucks, but there's a can of worms when it comes to libtrojita_plugins.so...
0299 void PluginManager::setMimePartReplacers(const MimePartReplacers &replacers)
0300 {
0301     m_mimePartReplacers = replacers;
0302 }
0303 
0304 } //namespace Common
0305 
0306 // vim: set et ts=4 sts=4 sw=4