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