/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009-2010 Daniel De Graaf * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program 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 General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define MODNAME cmd_all #include "inspircd.h" #include "exitcodes.h" #include #ifdef PURE_STATIC typedef std::map modmap; static std::vector* cmdlist = NULL; static modmap* modlist = NULL; AllCommandList::AllCommandList(fn cmd) { if (!cmdlist) cmdlist = new std::vector(); cmdlist->push_back(cmd); } AllModuleList::AllModuleList(AllModuleList::fn mod, const std::string& Name) : init(mod), name(Name) { if (!modlist) modlist = new modmap(); modlist->insert(std::make_pair(Name, this)); } class AllModule : public Module { std::vector cmds; public: AllModule() { if (!cmdlist) return; try { cmds.reserve(cmdlist->size()); for(std::vector::iterator i = cmdlist->begin(); i != cmdlist->end(); ++i) { Command* c = (*i)(this); cmds.push_back(c); ServerInstance->AddCommand(c); } } catch (...) { this->AllModule::~AllModule(); throw; } } ~AllModule() { for(std::vector::iterator i = cmds.begin(); i != cmds.end(); ++i) delete *i; } Version GetVersion() { return Version("All commands", VF_VENDOR|VF_CORE); } }; MODULE_INIT(AllModule) bool ModuleManager::Load(const std::string& name, bool defer) { modmap::iterator it = modlist->find(name); if (it == modlist->end()) return false; Module* mod = NULL; try { mod = (*it->second->init)(); mod->ModuleSourceFile = name; mod->ModuleDLLManager = NULL; mod->dying = false; Modules[name] = mod; if (defer) { ServerInstance->Logs->Log("MODULE", LOG_DEFAULT,"New module introduced: %s", name.c_str()); return true; } else { mod->init(); } } catch (CoreException& modexcept) { if (mod) DoSafeUnload(mod); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Unable to load " + name + ": " + modexcept.GetReason()); return false; } FOREACH_MOD(I_OnLoadModule,OnLoadModule(mod)); /* We give every module a chance to re-prioritize when we introduce a new one, * not just the one thats loading, as the new module could affect the preference * of others */ for(int tries = 0; tries < 20; tries++) { prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST; for (std::map::iterator n = Modules.begin(); n != Modules.end(); ++n) n->second->Prioritize(); if (prioritizationState == PRIO_STATE_LAST) break; if (tries == 19) ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Hook priority dependency loop detected while loading " + name); } ServerInstance->ISupport.Build(); return true; } namespace { struct UnloadAction : public HandlerBase0 { Module* const mod; UnloadAction(Module* m) : mod(m) {} void Call() { ServerInstance->Modules->DoSafeUnload(mod); ServerInstance->GlobalCulls.Apply(); ServerInstance->GlobalCulls.AddItem(this); } }; struct ReloadAction : public HandlerBase0 { Module* const mod; HandlerBase1* const callback; ReloadAction(Module* m, HandlerBase1* c) : mod(m), callback(c) {} void Call() { std::string name = mod->ModuleSourceFile; ServerInstance->Modules->DoSafeUnload(mod); ServerInstance->GlobalCulls.Apply(); bool rv = ServerInstance->Modules->Load(name.c_str()); callback->Call(rv); ServerInstance->GlobalCulls.AddItem(this); } }; } bool ModuleManager::Unload(Module* mod) { if (!CanUnload(mod)) return false; ServerInstance->AtomicActions.AddAction(new UnloadAction(mod)); return true; } void ModuleManager::Reload(Module* mod, HandlerBase1* callback) { if (CanUnload(mod)) ServerInstance->AtomicActions.AddAction(new ReloadAction(mod, callback)); else callback->Call(false); } void ModuleManager::LoadAll() { Load("cmd_all", true); Load("cmd_whowas.so", true); Load("cmd_lusers.so", true); ConfigTagList tags = ServerInstance->Config->ConfTags("module"); for(ConfigIter i = tags.first; i != tags.second; ++i) { ConfigTag* tag = i->second; std::string name = tag->getString("name"); std::cout << "[" << con_green << "*" << con_reset << "] Loading module:\t" << con_green << name << con_reset << std::endl; if (!this->Load(name, true)) { ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, this->LastError()); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << this->LastError() << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } } for(std::map::iterator i = Modules.begin(); i != Modules.end(); i++) { Module* mod = i->second; try { mod->init(); } catch (CoreException& modexcept) { LastModuleError = "Unable to initialize " + mod->ModuleSourceFile + ": " + modexcept.GetReason(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); std::cout << std::endl << "[" << con_red << "*" << con_reset << "] " << LastModuleError << std::endl << std::endl; ServerInstance->Exit(EXIT_STATUS_MODULE); } } /* We give every module a chance to re-prioritize when we introduce a new one, * not just the one thats loading, as the new module could affect the preference * of others */ for(int tries = 0; tries < 20; tries++) { prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST; for (std::map::iterator n = Modules.begin(); n != Modules.end(); ++n) n->second->Prioritize(); if (prioritizationState == PRIO_STATE_LAST) break; if (tries == 19) { ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Hook priority dependency loop detected"); ServerInstance->Exit(EXIT_STATUS_MODULE); } } } #endif