~ubuntu-branches/ubuntu/wily/psi/wily-proposed

« back to all changes in this revision

Viewing changes to src/pluginmanager.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jan Niehusmann
  • Date: 2009-09-25 17:49:51 UTC
  • mfrom: (6.1.3 sid)
  • Revision ID: james.westby@ubuntu.com-20090925174951-lvm7kdap82o8xhn3
Tags: 0.13-1
* Updated to upstream version 0.13
* Set Standards-Version to 3.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * (c) 2006 Kevin Smith
 
3
 * (c) 2008 Maciej Niedzielski
 
4
 */
 
5
 
 
6
#include "pluginmanager.h"
 
7
 
1
8
#include <QtCore>
 
9
#include <QtCrypto>
2
10
#include <QPluginLoader>
3
11
#include <QDebug>
4
12
 
5
 
#include "pluginmanager.h"
6
 
#include "psiplugin.h"
7
 
#include "userlist.h"
 
13
#include "xmpp_client.h"
 
14
#include "xmpp_task.h"
 
15
#include "xmpp_message.h"
 
16
 
8
17
#include "applicationinfo.h"
9
18
#include "psioptions.h"
10
 
#include <QtCrypto>
11
 
#include "xmpp_client.h"
 
19
 
 
20
#include "pluginhost.h"
 
21
#include "psiplugin.h"
 
22
#include "psiaccount.h"
 
23
#include "stanzafilter.h"
 
24
#include "stanzasender.h"
 
25
#include "iqfilter.h"
 
26
#include "iqnamespacefilter.h"
 
27
#include "eventfilter.h"
 
28
#include "optionaccessor.h"
 
29
 
 
30
 
 
31
//TODO(mck)
 
32
// - make sure PluginManager works correctly when changing profiles
 
33
// - use native separators when displaying file path
 
34
 
 
35
 
 
36
/**
 
37
 * Helper class used to process incoming XML in plugins.
 
38
 */
 
39
class PluginManager::StreamWatcher: public XMPP::Task
 
40
{
 
41
public:
 
42
        StreamWatcher(Task* t, PluginManager* m, int a) : Task(t), manager(m), account(a) {}
 
43
        bool take(const QDomElement& e) {
 
44
                return manager->incomingXml(account, e);
 
45
        }
 
46
        PluginManager* manager;
 
47
        int account;
 
48
};
 
49
 
12
50
 
13
51
/**
14
52
 * Function to obtain all the directories in which plugins can be stored
23
61
}
24
62
 
25
63
/**
 
64
 * Method for accessing the singleton instance of the class.
 
65
 * Instanciates if no instance yet exists.
 
66
 * \return Pointer to the plugin manager.
 
67
 */
 
68
PluginManager* PluginManager::instance()
 
69
{
 
70
        if (!instance_) {
 
71
                instance_ = new PluginManager();
 
72
        }
 
73
        return instance_;
 
74
}
 
75
 
 
76
/**
26
77
 * Default constructor. Locates all plugins, sets watchers on those directories to 
27
78
 * locate new ones and loads those enabled in the config.
28
79
 */ 
29
80
PluginManager::PluginManager() : QObject(NULL)
30
81
{
 
82
        updatePluginsList();
31
83
        loadEnabledPlugins();
32
84
        foreach (QString path, pluginDirs()) {
33
85
                QCA::DirWatch *dw = new QCA::DirWatch(path, this);
34
86
                connect(dw, SIGNAL(changed()), SLOT(dirsChanged()));
35
87
                dirWatchers_.append(dw);
36
88
        }
37
 
        connect( PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), this, SLOT(optionChanged(const QString&)));
 
89
        connect(PsiOptions::instance(), SIGNAL(optionChanged(const QString&)), this, SLOT(optionChanged(const QString&)));
 
90
}
 
91
 
 
92
/**
 
93
 * Updates list of known plugins by reading all plugin directories
 
94
 */
 
95
void PluginManager::updatePluginsList()
 
96
{
 
97
        foreach (QString d, pluginDirs()) {
 
98
                QDir dir(d);
 
99
                foreach (QString file, dir.entryList()) {
 
100
                        file = dir.absoluteFilePath(file);
 
101
                        qWarning(qPrintable(QString("Found plugin: %1").arg(file)));
 
102
                        if (!pluginByFile_.contains(file)) {
 
103
                                PluginHost* host = new PluginHost(this, file);
 
104
                                if (host->isValid()) {
 
105
                                        hosts_[host->name()] = host;
 
106
                                        pluginByFile_[file] = host;
 
107
                                }
 
108
                        } else {
 
109
                                qWarning("Which we already knew about");
 
110
                        }
 
111
                }
 
112
        }
38
113
}
39
114
 
40
115
/**
41
116
 * This slot is executed when the contents of a plugin directory changes
42
117
 * It causes the available plugin list to be refreshed.
 
118
 *
43
119
 * TODO: it should also load the plugins if they're on the autoload list
44
120
 */ 
45
121
void PluginManager::dirsChanged()
46
122
{
47
 
        availablePlugins();
 
123
        updatePluginsList();
48
124
}
49
125
 
50
126
/**
54
130
void PluginManager::loadEnabledPlugins()
55
131
{
56
132
        qDebug("Loading enabled plugins");
57
 
        QStringList plugins=availablePlugins();
58
 
        foreach(QString plugin, plugins) {
59
 
                QString option=QString("%1.%2").arg(loadOptionPrefix).arg(shortNames_[plugin]);
60
 
                if ( PsiOptions::instance()->getOption(option).toBool()  ) {
61
 
                        qWarning(qPrintable(QString("Plugin %1 is enabled in config: loading").arg(plugin)));
62
 
                        loadPlugin(files_[plugin]);
 
133
        foreach (PluginHost* plugin, hosts_.values()) {
 
134
                QString option = QString("%1.%2").arg(loadOptionPrefix).arg(plugin->shortName());
 
135
                if (PsiOptions::instance()->getOption(option).toBool()) {
 
136
                        qWarning(qPrintable(QString("Plugin %1 is enabled in config: loading").arg(plugin->shortName())));
 
137
                        plugin->load();
 
138
                        plugin->enable();
63
139
                }
64
140
        }
65
141
}
72
148
void PluginManager::optionChanged(const QString& option)
73
149
{
74
150
        //QString("%1.%2").arg(loadOptionPrefix).arg(shortNames_[plugin]);
 
151
 
 
152
        //TODO(mck): implement this... for now, enabling/disabling requires psi restart
75
153
}
76
154
 
77
155
/**
86
164
        }*/
87
165
 
88
166
        //Now look for external plugins
89
 
        QStringList plugins=availablePlugins();
90
 
        foreach(QString d, plugins)
91
 
                loadPlugin( d );
92
 
 
93
 
}
94
 
 
95
 
/**
96
 
 * Load a plugin file. Will fail if the plugin is already active.
97
 
 * If a plugin has previously had unloadPlugin() called on it but
98
 
 * Psi has been unable to unload it (such as on OSX) and it was 
99
 
 * instead disabled, this method will reactivate the plugin, instead
100
 
 * of attempting to reload it.
101
 
 * \param file File to load
102
 
 * \return Success in loading the plugin
103
 
 */ 
104
 
bool PluginManager::loadPlugin( const QString& file )
105
 
{
106
 
        qDebug() << "Loading Plugin " << file;
107
 
        //we can safely take the first key, as we won't have the same
108
 
        // file belonging to multiple plugins
109
 
        QList<QString> names = files_.keys(file);
110
 
        if (! names.isEmpty() ) {
111
 
                QString name = names.first();
112
 
                if ( plugins_.contains(name) ) {
113
 
                        qWarning() << QString("Plugin %1 is already active, but this should never be.").arg(file);
114
 
                        return false;
115
 
                }
116
 
        }
117
 
        QPluginLoader* loader=NULL;
118
 
        if ( loaders_.contains(file) ) {
119
 
                loader=loaders_[file];
120
 
        }
121
 
        else {
122
 
                loader=new QPluginLoader( file );
123
 
                loaders_.insert( file , loader);
124
 
        }
125
 
        QObject* plugin = loader->instance();
126
 
        if ( !loader->isLoaded() ) {
127
 
                delete loader;
128
 
                loaders_.remove( loaders_.keys(loader).first() );
129
 
                return false;
130
 
        }
131
 
        
132
 
        if ( !loadPlugin(plugin) ) {
133
 
                qWarning( qPrintable( QString("pluginmanager.cpp: Attempted to load %1, but it is not a valid plugin.").arg(file) ));
134
 
                if ( loader->isLoaded() ) {
135
 
                        qWarning("File is a plugin but not for Psi");
136
 
                        loader->unload();
137
 
                }
138
 
                delete loader;
139
 
                loaders_.remove( loaders_.keys(loader).first() );
140
 
                return false;
141
 
        }
142
 
        
143
 
        return true;
144
 
}
145
 
 
146
 
/**
147
 
 * Imports a Psi plugin loaded into a plugin object. Will fail if the plugin 
148
 
 * is not suitable (wrong Qt version, wrong debug setting, wrong Psi plugin 
149
 
 * interface version etc).
150
 
 * \param pluginObject Plugin Object
151
 
 * \return Success
152
 
 */
153
 
bool PluginManager::loadPlugin( QObject* pluginObject )
154
 
{
155
 
        if (!pluginObject)
156
 
                return false;
157
 
        qDebug( qPrintable( QString("Trying to load plugin") ) );
158
 
        //Check it's the right sort of plugin
159
 
        PsiPlugin* plugin = qobject_cast<PsiPlugin*> (pluginObject);
160
 
        if ( !plugin ) {
161
 
                return false;
162
 
        }
163
 
        qDebug() << "loading plugin " << plugin->name();
164
 
        plugins_.insert( plugin->name(), plugin );
165
 
        
166
 
        qDebug() << "connecting to plugin " << plugin->name();
167
 
        connect( plugin, SIGNAL(sendStanza(const PsiAccount*, const QDomElement&)), this, SLOT(sendStanza(const PsiAccount*, const QDomElement&)));
168
 
        connect( plugin, SIGNAL(sendStanza(const PsiAccount*, const QString&)), this, SLOT(sendStanza(const PsiAccount*, const QString&)));
169
 
        connect( plugin, SIGNAL(setPluginOption( const QString&, const QVariant& )), this, SLOT( setPluginOption( const QString&, const QVariant& )));
170
 
        connect( plugin, SIGNAL(getPluginOption( const QString&, QVariant&)), this, SLOT( getPluginOption( const QString&, QVariant&)));
171
 
        connect( plugin, SIGNAL(setGlobalOption( const QString&, const QVariant& )), this, SLOT( setGlobalOption( const QString&, const QVariant& )));
172
 
        connect( plugin, SIGNAL(getGlobalOption( const QString&, QVariant&)), this, SLOT( getGlobalOption( const QString&, QVariant&)));
173
 
        return true;
 
167
        foreach (PluginHost* plugin, hosts_.values()) {
 
168
                plugin->load();
 
169
                plugin->enable();
 
170
        }
174
171
}
175
172
 
176
173
/**
181
178
bool PluginManager::unloadAllPlugins()
182
179
{
183
180
        qDebug("Unloading all plugins");
184
 
        bool ok=true;
185
 
        foreach (QString plugin, plugins_.keys()) {
186
 
                if (!unloadPlugin(plugin))
187
 
                        ok=false;
 
181
        bool ok = true;
 
182
        foreach (PluginHost* plugin, hosts_.values()) {
 
183
                if (!plugin->disable()) {
 
184
                        ok = false;
 
185
                } else if (plugin->unload()) {
 
186
                        ok = false;
 
187
                }
188
188
        }
189
189
        return ok;
190
190
}
191
191
 
192
192
/**
193
 
 * Unloads the named plugin. If the plugin cannot be unloaded, the method
194
 
 * returns false but the plugin is still removed from the active list
195
 
 * and not used for further processing (This is most relevant on OSX
196
 
 * where it seems we can't ever unload a plugin).
197
 
 * \param plugin Name of the plugin to unload
198
 
 * \return Plugin unloaded result.
199
 
 */ 
200
 
bool PluginManager::unloadPlugin(const QString& plugin)
201
 
{
202
 
        if ( !plugins_.contains(plugin) ) {
203
 
                qWarning( qPrintable( QString("Plugin %1 wasn't found when trying to unload").arg(plugin) ) );
204
 
                return false;
205
 
        }
206
 
        qDebug() << "attempting to disconnect " << plugins_[plugin]->name();
207
 
        plugins_[plugin]->disconnect();
208
 
        QString file=files_[plugin];
209
 
        if ( !loaders_.contains(file) ) {
210
 
                qWarning( qPrintable( QString("Plugin %1's loader wasn't found when trying to unload").arg(plugin) ) );
211
 
                return false;
212
 
        }
213
 
        QPluginLoader* loader=loaders_[file];
214
 
        bool done=false;
215
 
        if ( loader->unload() ) {       
216
 
                //if we're done with the plugin completely and it's unloaded
217
 
                // we can delete the loader;
218
 
                done=true;
219
 
                delete loader;
220
 
                loaders_.remove(file);
221
 
        }
222
 
        //if the plugin was not unloaded, we remove it from the active
223
 
        // list, but keep the loader so we can obtain future instances
224
 
        plugins_.remove(plugin);
225
 
        return done;
226
 
}
227
 
 
228
 
/**
229
193
 * Find the file which provides the named plugin. If the named plugin is not
230
194
 * known, an empty string is provided.
231
195
 * \param plugin Name of the plugin.
233
197
 */ 
234
198
QString PluginManager::pathToPlugin(const QString& plugin)
235
199
{
236
 
        if (! files_.contains(plugin) )
237
 
                return QString("");
238
 
        return files_[plugin];
 
200
        QString path;
 
201
        if (hosts_.contains(plugin)) {
 
202
                path = hosts_[plugin]->path();
 
203
        }
 
204
        return path;
239
205
}
240
206
 
241
207
/**
242
 
 * Find the file which provides the named plugin. If the named plugin is not
 
208
 * Returns short name of the named plugin. If the named plugin is not
243
209
 * known, an empty string is provided.
244
210
 * \param plugin Name of the plugin.
245
211
 * \return Path to the plugin file.
246
212
 */ 
247
213
QString PluginManager::shortName(const QString& plugin)
248
214
{
249
 
        if (! shortNames_.contains(plugin) )
250
 
                return QString("");
251
 
        return shortNames_[plugin];
252
 
}
253
 
 
254
 
/**
255
 
 * Method for accessing the singleton instance of the class.
256
 
 * Instanciates if no instance yet exists.
257
 
 * \return Pointer to the plugin manager.
258
 
 */
259
 
PluginManager* PluginManager::instance()
260
 
{
261
 
        if (!instance_) {
262
 
                instance_ = new PluginManager();
 
215
        QString name;
 
216
        if (hosts_.contains(plugin)) {
 
217
                name = hosts_[plugin]->shortName();
263
218
        }
264
 
        return instance_;
 
219
        return name;
265
220
}
266
221
 
267
222
/**
268
 
 * Searches the relevant folders for plugins, queries them for their names
269
 
 * and returns a list of available plugin names.
 
223
 * Returns a list of available plugin names found in all plugin directories.
270
224
 */
271
225
QStringList PluginManager::availablePlugins()
272
226
{
273
 
        foreach(QString d, pluginDirs()) {
274
 
                QDir dir(d);
275
 
                foreach(QString file, dir.entryList()) {
276
 
                        file=dir.absoluteFilePath(file);
277
 
                        qWarning(qPrintable(QString("Found plugin: %1").arg(file)));
278
 
                        if ( !loaders_.contains(file) ) { 
279
 
                                loadPlugin(file);
280
 
                                if ( loaders_.contains(file) ) {
281
 
                                        qWarning("aye");
282
 
                                        PsiPlugin* plugin=qobject_cast<PsiPlugin*> ( loaders_[file]->instance() );
283
 
                                        files_.insert(plugin->name(), dir.absoluteFilePath(file) );
284
 
                                        shortNames_.insert(plugin->name(), plugin->shortName());
285
 
                                        unloadPlugin( plugin->name() );
286
 
                                }
287
 
                        }
288
 
                        else
289
 
                                qWarning("Which we already knew about");
290
 
                }
291
 
        }
292
 
 
293
 
        return files_.keys();
 
227
        return hosts_.keys();
294
228
}
295
229
 
296
230
/**
299
233
 * \param plugin Name of the plugin.
300
234
 * \return Pointer to the options widget for the named plugin.
301
235
 */
302
 
QWidget* PluginManager::getOptionsWidget( const QString& plugin )
 
236
QWidget* PluginManager::optionsWidget(const QString& plugin)
303
237
{
304
 
        if (plugins_.contains(plugin))
305
 
                return plugins_.value(plugin)->options();
306
 
        else
 
238
        QWidget* widget = 0;
 
239
        if (hosts_.contains(plugin)) {
 
240
                widget = hosts_[plugin]->optionsWidget();
 
241
        } else {
307
242
                qWarning(qPrintable(QString("Attempting to get options for %1 which doesn't exist").arg(plugin)));
308
 
        return NULL;
309
 
}
310
 
 
311
 
/**
312
 
 * \brief Sets an option (local to the plugin)
313
 
 * The options will be automatically prefixed by the plugin manager, so
314
 
 * there is no need to uniquely name the options. In the same way as the
315
 
 * main options system, a hierachy is available by dot-delimiting the 
316
 
 * levels ( e.g. "emoticons.show"). Use this and not setGlobalOption
317
 
 * in almost every case.
318
 
 * \param  option Option to set
319
 
 * \param value New option value
320
 
 */
321
 
void PluginManager::setPluginOption( const QString& option, const QVariant& value)
322
 
{
323
 
        PsiPlugin* plugin=NULL;
324
 
        
325
 
        if (!plugin)
326
 
                return;
327
 
        QString pluginName = plugin->name();
328
 
        QString optionKey=QString("%1.%2.%3").arg(pluginOptionPrefix).arg(shortNames_[pluginName]).arg(option);
329
 
        PsiOptions::instance()->setOption(optionKey,value);
330
 
}
331
 
 
332
 
/**
333
 
 * \brief Gets an option (local to the plugin)
334
 
 * The options will be automatically prefixed by the plugin manager, so
335
 
 * there is no need to uniquely name the options. In the same way as the
336
 
 * main options system, a hierachy is available by dot-delimiting the 
337
 
 * levels ( e.g. "emoticons.show"). Use this and not getGlobalOption
338
 
 * in almost every case.
339
 
 * \param  option Option to set
340
 
 * \param value Return value
341
 
 */
342
 
void PluginManager::getPluginOption( const QString& option, QVariant& value)
343
 
{
344
 
        
345
 
}
346
 
 
347
 
/**
348
 
 * \brief Sets a global option (not local to the plugin)
349
 
 * The options will be passed unaltered by the plugin manager, so
350
 
 * the options are presented as they are stored in the main option
351
 
 * system. Use setPluginOption instead of this in almost every case.
352
 
 * \param  option Option to set
353
 
 * \param value New option value
354
 
 */
355
 
void PluginManager::setGlobalOption( const QString& option, const QVariant& value)
356
 
{
357
 
        PsiOptions::instance()->setOption(option, value);
358
 
}
359
 
        
360
 
/**
361
 
 * \brief Gets a global option (not local to the plugin)
362
 
 * The options will be passed unaltered by the plugin manager, so
363
 
 * the options are presented as they are stored in the main option
364
 
 * system. Use getPluginOption instead of this in almost every case.
365
 
 * \param  option Option to set
366
 
 * \param value Return value
367
 
 */
368
 
void PluginManager::getGlobalOption( const QString& option, QVariant& value)
369
 
{
370
 
        value=PsiOptions::instance()->getOption(option);
371
 
        if (value.isValid())
372
 
                qDebug("valid option");
373
 
        else
374
 
                qDebug("not valid option");
375
 
}
376
 
        
377
 
void PluginManager::message(PsiAccount* account, const XMPP::Jid& from, const UserListItem* ul, const QString& message)
378
 
{
379
 
        QString fromString=QString("%1").arg(from.full());
380
 
        qDebug() << "message from" << fromString;
381
 
        foreach(PsiPlugin* plugin, plugins_.values() ) {
382
 
                plugin->message( account, message , fromString , from.full() );
383
 
        }
 
243
        }
 
244
        return widget;
 
245
}
 
246
 
 
247
/**
 
248
 * \brief Give each plugin the opportunity to process the incoming message event
 
249
 *
 
250
 * Each plugin is passed the event in turn. Any plugin may then modify the event
 
251
 * and may cause the event to be silently discarded.
 
252
 *
 
253
 * \param account Pointer to the PsiAccount responsible
 
254
 * \param event Incoming event
 
255
 * \return Continue processing the event; true if the event should be silently discarded.
 
256
 */
 
257
bool PluginManager::processMessage(const PsiAccount* account, const QString& jidFrom, const QString& body, const QString& subject)
 
258
{
 
259
        bool handled = false;
 
260
        foreach (PluginHost* host, hosts_.values()) {
 
261
                if (host->processMessage(accountIds_[account], jidFrom, body, subject)) {
 
262
                        handled = true;
 
263
                        break;
 
264
                }
 
265
        }
 
266
        return handled;
384
267
}
385
268
 
386
269
/**
391
274
 * 
392
275
 * \param account Pointer to the PsiAccount responsible
393
276
 * \param event Incoming event
394
 
 * \return Continue processing the event; false if the event should be silently discarded.
395
 
 */
396
 
bool PluginManager::processEvent( const PsiAccount* account, QDomElement &event )
397
 
{
398
 
        bool ok=true;
399
 
        QDomNode message = event.elementsByTagName("message").item(0);
400
 
        //QString account = event.elementsByTagName("account").item(0).toText().data();
401
 
        foreach(PsiPlugin* plugin, plugins_.values() ) {
402
 
                ok = ok && plugin->processEvent( account, message ) ;
403
 
        }
404
 
        return ok;
405
 
}
406
 
 
407
 
/**
408
 
 *      \brief Sends a stanza from the specified account.
409
 
 * 
410
 
 * \param account The account name, as used by the plugin interface.
411
 
 * \param stanza The stanza to be sent.
412
 
 */ 
413
 
void PluginManager::sendStanza( const PsiAccount* account, const QDomElement& stanza)
414
 
{
415
 
        sendStanza(account,PsiPlugin::toString(stanza));
416
 
}
417
 
 
418
 
/**
419
 
 *      \brief Sends a stanza from the specified account.
420
 
 * 
421
 
 * \param account The account name, as used by the plugin interface.
422
 
 * \param stanza The stanza to be sent.
423
 
 */ 
424
 
void PluginManager::sendStanza( const PsiAccount* account, const QString& stanza)
425
 
{
426
 
        qDebug() << "Want to send stanza to account " << (void*)account;
427
 
        if (!clients_.contains(account) || !verifyStanza(stanza))
428
 
                return;
429
 
        clients_[account]->send(stanza);
 
277
 * \return Continue processing the event; true if the event should be silently discarded.
 
278
 */
 
279
bool PluginManager::processEvent(const PsiAccount* account, QDomElement& event)
 
280
{
 
281
        bool handled = false;
 
282
        foreach (PluginHost* host, hosts_.values()) {
 
283
                if (host->processEvent(accountIds_[account], event)) {
 
284
                        handled = true;
 
285
                        break;
 
286
                }
 
287
        }
 
288
        return handled;
 
289
}
 
290
 
 
291
/**
 
292
 * \brief Give each plugin the opportunity to process the incoming xml
 
293
 *
 
294
 * Each plugin is passed the xml in turn using various filter interfaces
 
295
 * (for example, see StanzaFilter or IqFilter).
 
296
 * Any plugin may then modify the xml and may cause the stanza to be
 
297
 * silently discarded.
 
298
 * 
 
299
 * \param account Identifier of the PsiAccount responsible
 
300
 * \param xml Incoming XML
 
301
 * \return Continue processing the event; true if the event should be silently discarded.
 
302
 */
 
303
bool PluginManager::incomingXml(int account, const QDomElement &xml)
 
304
{
 
305
        bool handled = false;
 
306
        foreach (PluginHost* host, hosts_.values()) {
 
307
                if (host->incomingXml(account, xml)) {
 
308
                        handled = true;
 
309
                        break;
 
310
                }
 
311
        }
 
312
        return handled;
 
313
}
 
314
 
 
315
/**
 
316
 * Called by PluginHost when its hosted plugin wants to send xml stanza.
 
317
 *
 
318
 * \param account Identifier of the PsiAccount responsible
 
319
 * \param xml XML stanza to be sent
 
320
 */
 
321
void PluginManager::sendXml(int account, const QString& xml)
 
322
{
 
323
        //TODO(mck)
 
324
        // - think if it is better to ask plugin(host) for string or xml node
 
325
        // - validate things
 
326
        // - add id if missing
 
327
        // - maybe use appropriate Task to send
 
328
        // - make psi aware of things that are being send
 
329
        //   (for example, pipeline messages through history system)
 
330
 
 
331
        if (account < clients_.size()) {
 
332
                clients_[account]->send(xml);
 
333
        }
 
334
}
 
335
 
 
336
/**
 
337
 * Returns unique stanza identifier in account's stream
 
338
 *
 
339
 * \param account Identifier of the PsiAccount responsible
 
340
 * \return Unique ID to be used for when sending a stanza
 
341
 */
 
342
QString PluginManager::uniqueId(int account)
 
343
{
 
344
        QString id;
 
345
        if (account < clients_.size()) {
 
346
                id = clients_[account]->genUniqueId();
 
347
        }
 
348
        return id;
430
349
}
431
350
 
432
351
/**
433
352
 * Tells the plugin manager about an XMPP::Client and the owning PsiAccount
434
353
 */
435
 
void PluginManager::addAccount( const PsiAccount* account, XMPP::Client* client)
 
354
void PluginManager::addAccount(const PsiAccount* account, XMPP::Client* client)
436
355
{
437
 
        clients_[account]=client;
 
356
        clients_.append(client);
 
357
        const int id = clients_.size() - 1;
 
358
        accountIds_[account] = id;
 
359
        new StreamWatcher(client->rootTask(), this, id);
438
360
}
439
361
 
440
362
/**
441
363
 * Performs basic validity checking on a stanza
442
 
 * TODO : populate verifyStanza method
 
364
 * TODO : populate verifyStanza method and use it
443
365
 */
444
366
bool PluginManager::verifyStanza(const QString& stanza)
445
367
{