File indexing completed on 2023-10-01 08:41:45

0001 /*
0002     Copyright (C) 2012  Lasath Fernando <kde@lasath.org>
0003 
0004     This library is free software; you can redistribute it and/or
0005     modify it under the terms of the GNU Lesser General Public
0006     License as published by the Free Software Foundation; either
0007     version 2.1 of the License, or (at your option) any later version.
0008 
0009     This library is distributed in the hope that it will be useful,
0010     but WITHOUT ANY WARRANTY; without even the implied warranty of
0011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012     Lesser General Public License for more details.
0013 
0014     You should have received a copy of the GNU Lesser General Public
0015     License along with this library; if not, write to the Free Software
0016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
0017 */
0018 
0019 
0020 #include "message-processor.h"
0021 #include "message-processor-private.h"
0022 #include "message-filters-private.h"
0023 #include "message-filter-config-manager.h"
0024 
0025 #include <QMutex>
0026 #include <QStringBuilder>
0027 
0028 #include "ktp-debug.h"
0029 #include <KService>
0030 #include <KPluginFactory>
0031 
0032 Q_LOGGING_CATEGORY(KTP_MESSAGEPROCESSOR, "ktp-message-processor")
0033 
0034 using namespace KTp;
0035 
0036 FilterPlugin::FilterPlugin(const KPluginInfo &pluginInfo, KTp::AbstractMessageFilter *instance_):
0037     name(pluginInfo.pluginName()),
0038     instance(instance_)
0039 {
0040     bool ok;
0041     weight = pluginInfo.service()->property(QLatin1String("X-KDE-PluginInfo-Weight"), QVariant::Int).toInt(&ok);
0042     if (!ok) {
0043         weight = 100;
0044     }
0045 }
0046 
0047 FilterPlugin::FilterPlugin(const QString &name_, int weight_, KTp::AbstractMessageFilter *instance_):
0048     name(name_),
0049     weight(weight_),
0050     instance(instance_)
0051 {
0052 }
0053 
0054 bool FilterPlugin::operator<(const FilterPlugin &other) const
0055 {
0056     return weight < other.weight;
0057 }
0058 
0059 bool FilterPlugin::operator==(const FilterPlugin &other) const
0060 {
0061     return instance == other.instance &&
0062            name == other.name &&
0063            weight == other.weight;
0064 }
0065 
0066 void MessageProcessor::Private::loadFilter(const KPluginInfo &pluginInfo)
0067 {
0068     KService::Ptr service = pluginInfo.service();
0069 
0070     KPluginFactory *factory = KPluginLoader(service->library()).factory();
0071     if (factory) {
0072         qCDebug(KTP_MESSAGEPROCESSOR) << "loaded factory :" << factory;
0073         AbstractMessageFilter *filter = factory->create<AbstractMessageFilter>(q);
0074 
0075         if (filter) {
0076             qCDebug(KTP_MESSAGEPROCESSOR) << "loaded message filter : " << filter;
0077             filters << FilterPlugin(pluginInfo, filter);
0078         }
0079     } else {
0080         qCWarning(KTP_MESSAGEPROCESSOR) << "error loading plugin :" << service->library();
0081     }
0082 
0083     // Re-sort filters by weight
0084     std::sort(filters.begin(), filters.end());
0085 }
0086 
0087 void MessageProcessor::Private::unloadFilter(const KPluginInfo &pluginInfo)
0088 {
0089     QList<FilterPlugin>::Iterator iter = filters.begin();
0090     for ( ; iter != filters.end(); ++iter) {
0091         const FilterPlugin &plugin = *iter;
0092 
0093         if (plugin.name == pluginInfo.pluginName()) {
0094             qCDebug(KTP_MESSAGEPROCESSOR) << "unloading message filter : " << plugin.instance;
0095             plugin.instance->deleteLater();
0096             filters.erase(iter);
0097             return;
0098         }
0099     }
0100 }
0101 
0102 void MessageProcessor::Private::loadFilters()
0103 {
0104     qCDebug(KTP_MESSAGEPROCESSOR) << "Starting loading filters...";
0105 
0106     KPluginInfo::List plugins = MessageFilterConfigManager::self()->enabledPlugins();
0107 
0108     Q_FOREACH (const KPluginInfo &plugin, plugins) {
0109         loadFilter(plugin);
0110     }
0111 }
0112 
0113 KTp::MessageProcessor* MessageProcessor::instance()
0114 {
0115     static KTp::MessageProcessor *mp_instance;
0116     static QMutex mutex;
0117     mutex.lock();
0118     if (!mp_instance) {
0119         mp_instance= new MessageProcessor;
0120     }
0121     mutex.unlock();
0122 
0123     return mp_instance;
0124 }
0125 
0126 
0127 MessageProcessor::MessageProcessor():
0128     d(new MessageProcessor::Private(this))
0129 {
0130     // Default weight is 100. Make sure these two plugins are always above those
0131     // which don't have weight specified and in this exact order.
0132     //
0133     // The escape filter also has the URL filter in it, see message-escape-filter.cpp for details
0134     d->filters << FilterPlugin(QLatin1String("__messageEscapeFilter"), 98, new MessageEscapeFilter(this));
0135 
0136     d->loadFilters();
0137 }
0138 
0139 
0140 MessageProcessor::~MessageProcessor()
0141 {
0142     delete d;
0143 }
0144 
0145 QString MessageProcessor::header()
0146 {
0147     QStringList scripts;
0148     QStringList stylesheets;
0149     Q_FOREACH (const FilterPlugin &plugin, d->filters) {
0150         Q_FOREACH (const QString &script, plugin.instance->requiredScripts()) {
0151             // Avoid duplicates
0152             if (!scripts.contains(script)) {
0153                 scripts << script;
0154             }
0155         }
0156         Q_FOREACH (const QString &stylesheet, plugin.instance->requiredStylesheets()) {
0157             // Avoid duplicates
0158             if (!stylesheets.contains(stylesheet)) {
0159                 stylesheets << stylesheet;
0160             }
0161         }
0162     }
0163 
0164     QString out(QLatin1String("\n    <!-- The following scripts and stylesheets are injected here by the plugins -->\n"));
0165     Q_FOREACH(const QString &script, scripts) {
0166         out = out % QLatin1String("    <script type=\"text/javascript\" src=\"")
0167                   % QStandardPaths::locate(QStandardPaths::GenericDataLocation, script)
0168                   % QLatin1String("\"></script>\n");
0169     }
0170     Q_FOREACH(const QString &stylesheet, stylesheets) {
0171         out = out % QLatin1String("    <link rel=\"stylesheet\" type=\"text/css\" href=\"")
0172                   % QStandardPaths::locate(QStandardPaths::GenericDataLocation, stylesheet)
0173                   % QLatin1String("\" />\n");
0174     }
0175 
0176     qCDebug(KTP_MESSAGEPROCESSOR) << out;
0177 
0178     return out;
0179 }
0180 
0181 KTp::Message MessageProcessor::processIncomingMessage(const Tp::Message &message, const Tp::AccountPtr &account, const Tp::TextChannelPtr &channel)
0182 {
0183     KTp::MessageContext context(account, channel);
0184     return processIncomingMessage(KTp::Message(message, context), context);
0185 }
0186 
0187 KTp::Message KTp::MessageProcessor::processIncomingMessage(const Tp::ReceivedMessage &message, const Tp::AccountPtr &account, const Tp::TextChannelPtr &channel)
0188 {
0189     KTp::MessageContext context(account, channel);
0190     return processIncomingMessage(KTp::Message(message, context), context);
0191 }
0192 
0193 KTp::Message MessageProcessor::processIncomingMessage(KTp::Message message, const KTp::MessageContext &context)
0194 {
0195     Q_FOREACH (const FilterPlugin &plugin, d->filters) {
0196         qCDebug(KTP_MESSAGEPROCESSOR) << "running filter:" << plugin.instance->metaObject()->className();
0197         plugin.instance->filterMessage(message, context);
0198     }
0199     return message;
0200 }
0201 
0202 KTp::OutgoingMessage MessageProcessor::processOutgoingMessage(const QString &messageText, const Tp::AccountPtr &account, const Tp::TextChannelPtr &channel)
0203 {
0204     KTp::MessageContext context(account, channel);
0205     KTp::OutgoingMessage message(messageText);
0206 
0207     Q_FOREACH (const FilterPlugin &plugin, d->filters) {
0208         qCDebug(KTP_MESSAGEPROCESSOR) << "running outgoing filter: " << plugin.instance->metaObject()->className();
0209         plugin.instance->filterOutgoingMessage(message, context);
0210     }
0211 
0212     return message;
0213 }