message-processor.cpp 6.96 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
    Copyright (C) 2012  Lasath Fernando <kde@lasath.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/


#include "message-processor.h"
21
#include "message-processor-private.h"
22
23
#include "message-filters-private.h"
#include "message-filter-config-manager.h"
24

25
#include <QMutex>
26
#include <QStringBuilder>
27

28
#include "ktp-debug.h"
Lasath Fernando's avatar
Lasath Fernando committed
29
30
31
32
#include <KService>
#include <KServiceTypeTrader>
#include <KPluginFactory>

33
34
Q_LOGGING_CATEGORY(KTP_MESSAGEPROCESSOR, "ktp-message-processor")

35
using namespace KTp;
36

37
38
39
FilterPlugin::FilterPlugin(const KPluginInfo &pluginInfo, KTp::AbstractMessageFilter *instance_):
    name(pluginInfo.pluginName()),
    instance(instance_)
40
{
41
42
43
44
45
46
    bool ok;
    weight = pluginInfo.service()->property(QLatin1String("X-KDE-PluginInfo-Weight"), QVariant::Int).toInt(&ok);
    if (!ok) {
        weight = 100;
    }
}
47

48
49
50
51
52
53
FilterPlugin::FilterPlugin(const QString &name_, int weight_, KTp::AbstractMessageFilter *instance_):
    name(name_),
    weight(weight_),
    instance(instance_)
{
}
54

55
56
57
58
bool FilterPlugin::operator<(const FilterPlugin &other) const
{
    return weight < other.weight;
}
59

60
61
62
63
64
65
bool FilterPlugin::operator==(const FilterPlugin &other) const
{
    return instance == other.instance &&
           name == other.name &&
           weight == other.weight;
}
66

67
void MessageProcessor::Private::loadFilter(const KPluginInfo &pluginInfo)
68
{
69
70
71
72
    KService::Ptr service = pluginInfo.service();

    KPluginFactory *factory = KPluginLoader(service->library()).factory();
    if (factory) {
73
        qCDebug(KTP_MESSAGEPROCESSOR) << "loaded factory :" << factory;
74
75
76
        AbstractMessageFilter *filter = factory->create<AbstractMessageFilter>(q);

        if (filter) {
77
            qCDebug(KTP_MESSAGEPROCESSOR) << "loaded message filter : " << filter;
78
79
80
            filters << FilterPlugin(pluginInfo, filter);
        }
    } else {
81
        qCWarning(KTP_MESSAGEPROCESSOR) << "error loading plugin :" << service->library();
82
83
    }

84
    // Re-sort filters by weight
Jonah Brüchert's avatar
Jonah Brüchert committed
85
    std::sort(filters.begin(), filters.end());
86
87
88
89
90
91
92
93
94
}

void MessageProcessor::Private::unloadFilter(const KPluginInfo &pluginInfo)
{
    QList<FilterPlugin>::Iterator iter = filters.begin();
    for ( ; iter != filters.end(); ++iter) {
        const FilterPlugin &plugin = *iter;

        if (plugin.name == pluginInfo.pluginName()) {
95
            qCDebug(KTP_MESSAGEPROCESSOR) << "unloading message filter : " << plugin.instance;
96
97
98
99
100
            plugin.instance->deleteLater();
            filters.erase(iter);
            return;
        }
    }
101
102
}

103
104
void MessageProcessor::Private::loadFilters()
{
105
    qCDebug(KTP_MESSAGEPROCESSOR) << "Starting loading filters...";
106

107
108
109
    KPluginInfo::List plugins = MessageFilterConfigManager::self()->enabledPlugins();

    Q_FOREACH (const KPluginInfo &plugin, plugins) {
110
        loadFilter(plugin);
111
112
113
114
    }
}

KTp::MessageProcessor* MessageProcessor::instance()
115
{
116
    static KTp::MessageProcessor *mp_instance;
117
    static QMutex mutex;
118
    mutex.lock();
119
120
    if (!mp_instance) {
        mp_instance= new MessageProcessor;
121
    }
122
123
    mutex.unlock();

124
    return mp_instance;
125
126
127
}


128
129
MessageProcessor::MessageProcessor():
    d(new MessageProcessor::Private(this))
130
{
131
132
    // Default weight is 100. Make sure these two plugins are always above those
    // which don't have weight specified and in this exact order.
133
134
    //
    // The escape filter also has the URL filter in it, see message-escape-filter.cpp for details
135
    d->filters << FilterPlugin(QLatin1String("__messageEscapeFilter"), 98, new MessageEscapeFilter(this));
Lasath Fernando's avatar
Lasath Fernando committed
136

137
    d->loadFilters();
138
139
}

140
141
142

MessageProcessor::~MessageProcessor()
{
143
    delete d;
144
145
}

146
147
148
149
QString MessageProcessor::header()
{
    QStringList scripts;
    QStringList stylesheets;
150
151
    Q_FOREACH (const FilterPlugin &plugin, d->filters) {
        Q_FOREACH (const QString &script, plugin.instance->requiredScripts()) {
152
153
154
155
156
            // Avoid duplicates
            if (!scripts.contains(script)) {
                scripts << script;
            }
        }
157
        Q_FOREACH (const QString &stylesheet, plugin.instance->requiredStylesheets()) {
158
159
160
161
162
163
164
165
166
            // Avoid duplicates
            if (!stylesheets.contains(stylesheet)) {
                stylesheets << stylesheet;
            }
        }
    }

    QString out(QLatin1String("\n    <!-- The following scripts and stylesheets are injected here by the plugins -->\n"));
    Q_FOREACH(const QString &script, scripts) {
167
        out = out % QLatin1String("    <script type=\"text/javascript\" src=\"")
168
                  % QStandardPaths::locate(QStandardPaths::GenericDataLocation, script)
169
                  % QLatin1String("\"></script>\n");
170
171
    }
    Q_FOREACH(const QString &stylesheet, stylesheets) {
172
        out = out % QLatin1String("    <link rel=\"stylesheet\" type=\"text/css\" href=\"")
173
                  % QStandardPaths::locate(QStandardPaths::GenericDataLocation, stylesheet)
174
                  % QLatin1String("\" />\n");
175
176
    }

177
    qCDebug(KTP_MESSAGEPROCESSOR) << out;
178
179
180
181

    return out;
}

182
KTp::Message MessageProcessor::processIncomingMessage(const Tp::Message &message, const Tp::AccountPtr &account, const Tp::TextChannelPtr &channel)
183
{
184
    KTp::MessageContext context(account, channel);
185
    return processIncomingMessage(KTp::Message(message, context), context);
186
187
}

188
KTp::Message KTp::MessageProcessor::processIncomingMessage(const Tp::ReceivedMessage &message, const Tp::AccountPtr &account, const Tp::TextChannelPtr &channel)
189
190
{
    KTp::MessageContext context(account, channel);
191
    return processIncomingMessage(KTp::Message(message, context), context);
192
193
}

194
KTp::Message MessageProcessor::processIncomingMessage(KTp::Message message, const KTp::MessageContext &context)
195
{
196
    Q_FOREACH (const FilterPlugin &plugin, d->filters) {
197
        qCDebug(KTP_MESSAGEPROCESSOR) << "running filter:" << plugin.instance->metaObject()->className();
198
        plugin.instance->filterMessage(message, context);
199
    }
200
    return message;
201
}
202

203
KTp::OutgoingMessage MessageProcessor::processOutgoingMessage(const QString &messageText, const Tp::AccountPtr &account, const Tp::TextChannelPtr &channel)
204
205
{
    KTp::MessageContext context(account, channel);
206
    KTp::OutgoingMessage message(messageText);
207

208
    Q_FOREACH (const FilterPlugin &plugin, d->filters) {
209
        qCDebug(KTP_MESSAGEPROCESSOR) << "running outgoing filter: " << plugin.instance->metaObject()->className();
210
        plugin.instance->filterOutgoingMessage(message, context);
211
212
213
214
    }

    return message;
}