PluginManager.cpp

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006-2010 Jacek Sieka, arnetheduck on gmail point com
00003  *
00004  * This program is free software; you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License as published by
00006  * the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #include "adchpp.h"
00020 
00021 #include "PluginManager.h"
00022 
00023 #include "SimpleXML.h"
00024 #include "LogManager.h"
00025 #include "SocketManager.h"
00026 #include "version.h"
00027 #include "File.h"
00028 #include "Text.h"
00029 
00030 #ifdef _WIN32
00031 
00032 #define PLUGIN_EXT _T(".dll")
00033 
00034 #define PM_LOAD_LIBRARY(filename) ::LoadLibrary(filename)
00035 #define PM_UNLOAD_LIBRARY(lib) ::FreeLibrary(lib)
00036 #define PM_GET_ADDRESS(lib, name) ::GetProcAddress(lib, name)
00037 #define PM_GET_ERROR_STRING() Util::translateError(GetLastError())
00038 
00039 #else
00040 
00041 #include "dlfcn.h"
00042 
00043 #define PLUGIN_EXT ".so"
00044 
00045 #define PM_LOAD_LIBRARY(filename) ::dlopen(filename, RTLD_LAZY | RTLD_GLOBAL)
00046 #define PM_UNLOAD_LIBRARY(lib) ::dlclose(lib)
00047 #define PM_GET_ADDRESS(lib, name) ::dlsym(lib, name)
00048 #define PM_GET_ERROR_STRING() ::dlerror()
00049 
00050 #endif
00051 
00052 namespace adchpp {
00053 
00054 using namespace std;
00055 using std::placeholders::_1;
00056 
00057 PluginManager* PluginManager::instance = 0;
00058 const string PluginManager::className = "PluginManager";
00059 
00060 PluginManager::PluginManager() throw() {
00061 
00062 }
00063 
00064 PluginManager::~PluginManager() throw() {
00065 
00066 }
00067 
00068 void PluginManager::attention(const function<void()>& f) {
00069     SocketManager::getInstance()->addJob(f);
00070 }
00071 
00072 void PluginManager::load()  {
00073     for(StringIter i = plugins.begin(); i != plugins.end(); ++i) {
00074         loadPlugin(*i + PLUGIN_EXT);
00075     }
00076 }
00077 
00078 bool PluginManager::loadPlugin(const string& file) {
00079     if(file.length() < 3) {
00080         return false;
00081     }
00082     plugin_t h;
00083 
00084 #ifndef _WIN32
00085     if(!File::isAbsolutePath(file)) {
00086         h = PM_LOAD_LIBRARY((pluginPath + file).c_str());
00087     } else {
00088         h = PM_LOAD_LIBRARY(file.c_str());
00089     }
00090 #else
00091     if(!File::isAbsolutePath(file)) {
00092         h = LoadLibraryEx((pluginPath + file).c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES);
00093     } else {
00094         h = LoadLibraryEx(file.c_str(), NULL, DONT_RESOLVE_DLL_REFERENCES);
00095     }
00096 #endif
00097 
00098     if(h == NULL) {
00099         LOG(className, "Failed to load " + Text::utf8ToAcp(file) + ": " + PM_GET_ERROR_STRING());
00100         return false;
00101     }
00102 
00103     PLUGIN_GET_VERSION v = (PLUGIN_GET_VERSION)PM_GET_ADDRESS(h, "pluginGetVersion");
00104     if(v != NULL) {
00105         double ver = v();
00106         if(ver == PLUGINVERSION) {
00107 #ifdef _WIN32
00108             // Reload plugin with references resolved...
00109             FreeLibrary(h);
00110             if(!File::isAbsolutePath(file)) {
00111                 h = PM_LOAD_LIBRARY((pluginPath + file).c_str());
00112             } else {
00113                 h = PM_LOAD_LIBRARY(file.c_str());
00114             }
00115             if(h == NULL) {
00116                 LOG(className, "Failed to load " + Text::utf8ToAcp(file) + ": " + PM_GET_ERROR_STRING());
00117                 return false;
00118             }
00119 #endif
00120             PLUGIN_LOAD l = (PLUGIN_LOAD)PM_GET_ADDRESS(h, "pluginLoad");
00121             PLUGIN_UNLOAD u = (PLUGIN_UNLOAD)PM_GET_ADDRESS(h, "pluginUnload");
00122 
00123             if(l != NULL && u != NULL) {
00124                 int i = l();
00125                 if(i != 0) {
00126                     LOG(className, "Failed to load plugin " + Text::utf8ToAcp(file) + " (Error " + Util::toString(i) + ")");
00127                 } else {
00128                     // Wonderful, we have a plugin...
00129                     active.push_back(PluginInfo(h, v, l, u));
00130                     LOG(className, Text::utf8ToAcp(file) + " loaded");
00131                     return true;
00132                 }
00133             } else {
00134                 LOG(className, Text::utf8ToAcp(file) + " is not a valid ADCH++ plugin");
00135             }
00136         } else {
00137             LOG(className, Text::utf8ToAcp(file) + " is for another version of ADCH++ (" + Util::toString(ver) + "), please get the correct one from the author");
00138         }
00139     } else {
00140         LOG(className, Text::utf8ToAcp(file) + " is not a valid ADCH++ plugin");
00141     }
00142 
00143     PM_UNLOAD_LIBRARY(h);
00144     return false;
00145 }
00146 
00147 void PluginManager::shutdown() {
00148     for(PluginList::reverse_iterator i = active.rbegin(); i != active.rend(); ++i)
00149         i->pluginUnload();
00150 #ifndef HAVE_BROKEN_MTALLOC
00151     for(PluginList::reverse_iterator i = active.rbegin(); i != active.rend(); ++i)
00152         PM_UNLOAD_LIBRARY(i->handle);
00153 #endif
00154 
00155     registry.clear();
00156     active.clear();
00157 }
00158 
00159 PluginManager::CommandDispatch::CommandDispatch(const std::string& name_, const PluginManager::CommandSlot& f_) :
00160 name('+' + name_),
00161 f(f_)
00162 {
00163 }
00164 
00165 void PluginManager::CommandDispatch::operator()(Entity& e, AdcCommand& cmd, bool& ok) {
00166     if(e.getState() != Entity::STATE_NORMAL) {
00167         return;
00168     }
00169 
00170     if(cmd.getCommand() != AdcCommand::CMD_MSG) {
00171         return;
00172     }
00173 
00174     if(cmd.getParameters().size() < 1) {
00175         return;
00176     }
00177 
00178     StringList l;
00179     Util::tokenize(l, cmd.getParameters()[0], ' ');
00180     if(l[0] != name) {
00181         return;
00182     }
00183     l[0] = name.substr(1);
00184 
00185     if(!PluginManager::getInstance()->handleCommand(e, l)) {
00186         return;
00187     }
00188 
00189     cmd.setPriority(AdcCommand::PRIORITY_IGNORE);
00190     f(e, l, ok);
00191 }
00192 
00193 ClientManager::SignalReceive::Connection PluginManager::onCommand(const std::string& commandName, const CommandSlot& f) {
00194     return ClientManager::getInstance()->signalReceive().connect(CommandDispatch(commandName, f));
00195 }
00196 
00197 PluginManager::CommandSignal& PluginManager::getCommandSignal(const std::string& commandName) {
00198     CommandHandlers::iterator i = commandHandlers.find(commandName);
00199     if(i == commandHandlers.end())
00200         return commandHandlers.insert(make_pair(commandName, CommandSignal())).first->second;
00201 
00202     return i->second;
00203 }
00204 
00205 bool PluginManager::handleCommand(Entity& e, const StringList& l) {
00206     CommandHandlers::iterator i = commandHandlers.find(l[0]);
00207     if(i == commandHandlers.end())
00208         return true;
00209 
00210     bool ok = true;
00211     i->second(e, l, ok);
00212     return ok;
00213 }
00214 
00215 }
Generated on Sat Nov 27 23:37:53 2010 for adchpp by  doxygen 1.6.3