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 }