File indexing completed on 2024-04-14 04:00:10

0001 //
0002 // C++ Implementation: cpluginmanager
0003 //
0004 // Description: plug-in manager
0005 //
0006 /*
0007 Copyright 2006-2011 Tomas Mecir <kmuddy@kmuddy.com>
0008 
0009 This program is free software; you can redistribute it and/or
0010 modify it under the terms of the GNU General Public License as
0011 published by the Free Software Foundation; either version 2 of 
0012 the License, or (at your option) any later version.
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 "cpluginmanager.h"
0024 
0025 #include "cactionmanager.h"
0026 #include "cplugin.h"
0027 
0028 #include <QDebug>
0029 #include <QDialog>
0030 #include <KLocalizedString>
0031 #include <KPluginWidget>
0032 #include <KPluginFactory>
0033 
0034 #include <list>
0035 #include <KConfigGroup>
0036 #include <QDialogButtonBox>
0037 #include <QPushButton>
0038 #include <QVBoxLayout>
0039 
0040 using namespace std;
0041 
0042 cPluginManager *cPluginManager::_self = nullptr;
0043 
0044 cPluginManager *cPluginManager::self ()
0045 {
0046   if (!_self)
0047     _self = new cPluginManager;
0048   return _self;
0049 }
0050 
0051 cPluginManager::cPluginManager () : cActionBase ("pluginmanager", 0)
0052 {
0053   findPlugins ();
0054   activeSess = 0;
0055   lastGagged = false;
0056   pluginDialog = nullptr;
0057 
0058   // global objects receive events from all sessions, hence this will work well
0059   addEventHandler ("send-command", 20, PT_STRING);
0060   addEventHandler ("raw-data", 20, PT_STRING);
0061   addEventHandler ("raw-data-comp", 20, PT_STRING);
0062   addEventHandler ("got-prompt", 20, PT_TEXTCHUNK);
0063   addEventHandler ("got-line", 20, PT_TEXTCHUNK);
0064   addEventHandler ("got-line-after-triggers", 20, PT_TEXTCHUNK);
0065   addEventHandler ("will-gag", 20, PT_NOTHING);
0066   addEventHandler ("connected", 20, PT_NOTHING);
0067   addEventHandler ("disconnected", 20, PT_NOTHING);
0068   addEventHandler ("save", 20, PT_NOTHING);
0069   addEventHandler ("session-activated", 20, PT_INT);
0070   addEventHandler ("session-created", 20, PT_INT);
0071   addEventHandler ("session-destroyed", 20, PT_INT);  
0072 }
0073 
0074 
0075 cPluginManager::~cPluginManager ()
0076 {
0077   //unload plug-ins
0078   unloadAll ();
0079   
0080   removeEventHandler ("raw-data");
0081   removeEventHandler ("raw-data-comp");
0082   removeEventHandler ("send-command");
0083   removeEventHandler ("raw-data");
0084   removeEventHandler ("raw-data-comp");
0085   removeEventHandler ("got-prompt");
0086   removeEventHandler ("got-line");
0087   removeEventHandler ("got-line-after-triggers");
0088   removeEventHandler ("will-gag");
0089   removeEventHandler ("connected");
0090   removeEventHandler ("disconnected");
0091   removeEventHandler ("save");
0092   removeEventHandler ("session-activated");
0093   removeEventHandler ("session-created");
0094   removeEventHandler ("session-destroyed");
0095   
0096   _self = nullptr;
0097 }
0098 
0099 void cPluginManager::eventIntHandler (QString event, int, int par1, int)
0100 {
0101   if (event == "session-activated") {
0102     passSessionSwitch (par1);
0103   }  
0104   if (event == "session-created") {
0105     passSessionAdd (par1);
0106   }  
0107   if (event == "session-destroyed") {
0108     passSessionRemove (par1);
0109   }  
0110 }
0111 
0112 void cPluginManager::eventStringHandler (QString event, int session, QString &par1, const QString &)
0113 {
0114   if (event == "send-command") {
0115     passCommand (session, par1);
0116   }
0117   else if (event == "raw-data-comp") {
0118     QByteArray par1Data = par1.toLatin1();
0119     char *data = par1Data.data();
0120     passRawData (session, data);
0121     par1 = data;  // make changes take effect
0122   }
0123   else if (event == "raw-data") {
0124     QByteArray par1Data = par1.toLatin1();
0125     char *data = par1Data.data();
0126     passRawData (session, data);
0127     par1 = data;  // make changes take effect
0128   }
0129 }
0130 
0131 void cPluginManager::eventNothingHandler (QString event, int session)
0132 {
0133   if (event == "will-gag") {
0134     lastGagged = true;
0135   }
0136   else if (event == "connected") {
0137     passConnected (session);
0138   }
0139   else if (event == "disconnected") {
0140     passDisconnected (session);
0141   }
0142   else if (event == "save") {
0143     passSave (session);
0144   }
0145 }
0146 
0147 void cPluginManager::eventChunkHandler (QString event, int session, cTextChunk *par)
0148 {
0149   if (event == "got-prompt") {
0150     passPrompt (session, par);
0151   }
0152   if (event == "got-line") {
0153     passInput (session, 1, par, false);
0154   }
0155   if (event == "got-line-after-triggers") {
0156     passInput (session, 2, par, lastGagged);
0157     lastGagged = false;
0158   }
0159 }
0160 
0161 void cPluginManager::findPlugins ()
0162 {
0163   pluginInfo.clear ();
0164   QVector< KPluginMetaData > pi = KPluginMetaData::findPlugins ("kmuddy");
0165   for (auto pinfo : pi) {
0166     QString name = pinfo.name();
0167     qDebug() << "Found plugin: " << name;
0168     pluginInfo[name] = pinfo;
0169   }
0170 }
0171 
0172 bool cPluginManager::loadPlugin (const QString &name)
0173 {
0174   if (isLoaded (name))    //plug-in is already loaded!
0175     return false;
0176   if (!(pluginInfo.count (name)))  //we know nothing of that plug-in
0177     return false;
0178 
0179   KPluginFactory::Result<cPlugin> res = KPluginFactory::instantiatePlugin<cPlugin>(pluginInfo[name]);
0180   if (!res) {
0181     qDebug() << "Failed to load plugin: " << name;
0182     return false;
0183   }
0184 
0185   cPlugin *plugin = res.plugin;
0186 
0187   loadedPlugins[name] = plugin;
0188   plugins.insert (pair<int, cPlugin *>(plugin->priority(), plugin));
0189   
0190   // call plugin's session loading for each active session - the plugin can load the data and
0191   // the like here
0192   cActionManager *am = cActionManager::self();
0193   map<int, bool>::iterator sit;
0194   for (sit = sessions.begin(); sit != sessions.end(); ++sit) {
0195     plugin->sessionAdd (sit->first, false);
0196     cActionBase *conn = am->object ("connection", sit->first);
0197     if (conn && conn->attrib ("connected"))
0198       plugin->connected (sit->first);  // if the session is connected, notify the plugin of that
0199   }
0200   plugin->setActiveSession (activeSess);
0201   plugin->sessionSwitch (activeSess);
0202   qDebug() << "Loaded plugin: " << name;
0203   return true;
0204 }
0205 
0206 bool cPluginManager::unloadPlugin (const QString &name)
0207 {
0208   if (!(isLoaded (name)))    //plug-in is not loaded!
0209     return false;
0210   cPlugin *p = loadedPlugins[name];
0211   loadedPlugins.erase (name);
0212   //remove plugin from the priority list
0213   for (it = plugins.begin(); it != plugins.end(); ++it)
0214     if (it->second == p)
0215     {
0216       plugins.erase (it);
0217       break;
0218     }
0219   
0220   // call plugin's session unloading for each active session - the plugin can save the data and
0221   // the like here
0222   map<int, bool>::iterator sit;
0223   for (sit = sessions.begin(); sit != sessions.end(); ++sit) {
0224     p->sessionRemove (sit->first, false);
0225   }
0226   
0227   qDebug() << "Unloaded plugin: " << name;
0228 
0229   delete p;
0230   return true;
0231 }
0232 
0233 bool cPluginManager::isLoaded (const QString &name)
0234 {
0235   return (loadedPlugins.count (name) != 0);
0236 }
0237 
0238 void cPluginManager::loadAll ()
0239 {
0240   for (auto e : pluginInfo)
0241     if (e.second.isEnabled(pluginConfig))
0242       loadPlugin (e.first);
0243 }
0244 
0245 void cPluginManager::unloadUnwanted ()
0246 {
0247   for (auto e : pluginInfo)
0248     if (isLoaded(e.first) && (!e.second.isEnabled(pluginConfig)))
0249       unloadPlugin (e.first);
0250 }
0251 
0252 void cPluginManager::unloadAll ()
0253 {
0254   //unloading a plug-in modifies the map, invalidating iterators...
0255   //I therefore have to create a list of loaded plug-in names and use that instead
0256   list<QString> loadedList;
0257   map<QString, cPlugin *>::iterator lpi;
0258   for (lpi = loadedPlugins.begin(); lpi != loadedPlugins.end(); ++lpi)
0259     loadedList.push_back (lpi->first);
0260   list<QString>::iterator it;
0261   for (it = loadedList.begin(); it != loadedList.end(); ++it)
0262     unloadPlugin (*it);
0263 }
0264 
0265 void cPluginManager::showPluginsDialog ()
0266 {
0267   pluginDialog = new QDialog (nullptr);
0268   pluginDialog->setWindowTitle (i18n ("Plugins"));
0269   QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
0270   QVBoxLayout *mainLayout = new QVBoxLayout;
0271   pluginDialog->setLayout(mainLayout);
0272   pluginSelector = new KPluginWidget (pluginDialog);
0273   pluginSelector->setConfig(pluginConfig);
0274   mainLayout->addWidget(pluginSelector);
0275   pluginDialog->connect(buttonBox, &QDialogButtonBox::accepted, this, &cPluginManager::closeDialog);
0276   pluginDialog->connect(buttonBox, &QDialogButtonBox::rejected, this, &cPluginManager::closeDialog);
0277   mainLayout->addWidget(buttonBox);
0278   pluginDialog->resize (QSize (400, 300));
0279 
0280 
0281   connect (pluginSelector, &KPluginWidget::changed, this, &cPluginManager::applyPluginDialog);
0282 
0283   QVector<KPluginMetaData> list;
0284   map<QString, KPluginMetaData>::iterator itp;
0285   for (itp = pluginInfo.begin(); itp != pluginInfo.end(); ++itp)
0286     list.append (itp->second);
0287   pluginSelector->addPlugins (list, QString("KMuddy"));
0288   pluginSelector->load();
0289 
0290   pluginDialog->exec ();
0291 
0292   delete pluginDialog;
0293   pluginDialog = nullptr;
0294 }
0295 
0296 void cPluginManager::applyPluginDialog ()
0297 {
0298   // unload unwanted plug-ins, load newly wanted ones
0299   pluginSelector->save();
0300   unloadUnwanted ();
0301   loadAll ();
0302 }
0303 
0304 void cPluginManager::closeDialog()
0305 {
0306   pluginDialog->close();
0307   delete pluginDialog;
0308   pluginDialog = nullptr;
0309 }
0310 
0311 void cPluginManager::passSessionAdd (int sess)
0312 {
0313   for (it = plugins.begin(); it != plugins.end(); ++it)
0314     it->second->sessionAdd (sess, true);
0315   sessions[sess] = true;
0316 }
0317 
0318 void cPluginManager::passSessionRemove (int sess)
0319 {
0320   for (it = plugins.begin(); it != plugins.end(); ++it)
0321     it->second->sessionRemove (sess, true);
0322   sessions.erase (sess);
0323 }
0324 
0325 void cPluginManager::passSessionSwitch (int sess)
0326 {
0327   for (it = plugins.begin(); it != plugins.end(); ++it)
0328   {
0329     it->second->sessionSwitch (sess);
0330     it->second->setActiveSession (sess);
0331   }
0332   activeSess = sess;
0333 }
0334 
0335 void cPluginManager::passConnected (int sess)
0336 {
0337   for (it = plugins.begin(); it != plugins.end(); ++it)
0338     it->second->connected (sess);
0339 }
0340 
0341 void cPluginManager::passDisconnected (int sess)
0342 {
0343   for (it = plugins.begin(); it != plugins.end(); ++it)
0344     it->second->disconnected (sess);
0345 }
0346 
0347 void cPluginManager::passSave (int sess)
0348 {
0349   for (it = plugins.begin(); it != plugins.end(); ++it)
0350     it->second->save (sess);
0351 }
0352 
0353 void cPluginManager::passRawData (int sess, char *data)
0354 {
0355   for (it = plugins.begin(); it != plugins.end(); ++it)
0356     it->second->rawData (sess, data);
0357 }
0358 
0359 void cPluginManager::passDecompressedData (int sess, char *data)
0360 {
0361   for (it = plugins.begin(); it != plugins.end(); ++it)
0362     it->second->decompressedData (sess, data);
0363 }
0364 
0365 void cPluginManager::passInput (int sess, int phase, cTextChunk *chunk, bool gagged)
0366 {
0367   for (it = plugins.begin(); it != plugins.end(); ++it)
0368     it->second->processInput (sess, phase, chunk, gagged);
0369 }
0370 
0371 void cPluginManager::passPrompt (int sess, cTextChunk *chunk)
0372 {
0373   for (it = plugins.begin(); it != plugins.end(); ++it)
0374     it->second->processPrompt (sess, chunk);
0375 }
0376 
0377 void cPluginManager::passCommand (int sess, QString &command)
0378 {
0379   bool dontSend = false;
0380   for (it = plugins.begin(); it != plugins.end(); ++it) {
0381     it->second->processCommand (sess, command, dontSend);
0382     if (dontSend) break;
0383   }
0384   if (dontSend) command = QString();
0385 }
0386 
0387 #include "moc_cpluginmanager.cpp"