X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules.cpp;h=5f1081a1c529ad935466857116918dd4ef6215b2;hb=663f0620bea4dc1e64ec640992f4d511ae1ef97b;hp=22628ff0f1c5edc144527e3abcb203961d1e1e78;hpb=4b6bdeccb537b6f8030172c37afa7dc324e26765;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules.cpp b/src/modules.cpp index 22628ff0f..5f1081a1c 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -1,16 +1,29 @@ -/* +------------------------------------+ - * | Inspire Internet Relay Chat Daemon | - * +------------------------------------+ +/* + * InspIRCd -- Internet Relay Chat Daemon * - * InspIRCd: (C) 2002-2010 InspIRCd Development Team - * See: http://wiki.inspircd.org/Credits + * Copyright (C) 2009-2010 Daniel De Graaf + * Copyright (C) 2007, 2009 Dennis Friis + * Copyright (C) 2003-2008 Craig Edwards + * Copyright (C) 2008 Thomas Stagner + * Copyright (C) 2006-2007 Robin Burchell + * Copyright (C) 2006-2007 Oliver Lupton + * Copyright (C) 2007 Pippijn van Steenhoven + * Copyright (C) 2003 randomdan * - * This program is free but copyrighted software; see - * the file COPYING for details. + * 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 . */ + #include "inspircd.h" #include "xline.h" #include "socket.h" @@ -23,24 +36,24 @@ #include #endif +static std::vector* dynrefs = NULL; -// Version is a simple class for holding a modules version number -template<> -VersionBase::VersionBase(const std::string &desc, int flags) -: description(desc), Flags(flags) +void dynamic_reference_base::reset_all() { + if (!dynrefs) + return; + for(unsigned int i = 0; i < dynrefs->size(); i++) + (*dynrefs)[i]->ClearCache(); } -template<> -VersionBase::VersionBase(const std::string &desc, int flags, const std::string& linkdata) -: description(desc), Flags(flags), link_data(linkdata) +// Version is a simple class for holding a modules version number +Version::Version(const std::string &desc, int flags) : description(desc), Flags(flags) { } -template<> -bool VersionBase::CanLink(const std::string& other_data) +Version::Version(const std::string &desc, int flags, const std::string& linkdata) +: description(desc), Flags(flags), link_data(linkdata) { - return link_data == other_data; } Request::Request(Module* src, Module* dst, const char* idstr) @@ -99,8 +112,9 @@ ModResult Module::OnKill(User*, User*, const std::string&) { return MOD_RES_PASS void Module::OnLoadModule(Module*) { } void Module::OnUnloadModule(Module*) { } void Module::OnBackgroundTimer(time_t) { } -ModResult Module::OnPreCommand(std::string&, std::vector&, User *, bool, const std::string&) { return MOD_RES_PASSTHRU; } -void Module::OnPostCommand(const std::string&, const std::vector&, User *, CmdResult, const std::string&) { } +ModResult Module::OnPreCommand(std::string&, std::vector&, LocalUser*, bool, const std::string&) { return MOD_RES_PASSTHRU; } +void Module::OnPostCommand(const std::string&, const std::vector&, LocalUser*, CmdResult, const std::string&) { } +void Module::OnUserInit(LocalUser*) { } ModResult Module::OnCheckReady(LocalUser*) { return MOD_RES_PASSTHRU; } ModResult Module::OnUserRegister(LocalUser*) { return MOD_RES_PASSTHRU; } ModResult Module::OnUserPreKick(User*, Membership*, const std::string&) { return MOD_RES_PASSTHRU; } @@ -151,18 +165,17 @@ void Module::OnCleanup(int, void*) { } ModResult Module::OnChannelPreDelete(Channel*) { return MOD_RES_PASSTHRU; } void Module::OnChannelDelete(Channel*) { } ModResult Module::OnSetAway(User*, const std::string &) { return MOD_RES_PASSTHRU; } -ModResult Module::OnUserList(User*, Channel*) { return MOD_RES_PASSTHRU; } ModResult Module::OnWhoisLine(User*, User*, int&, std::string&) { return MOD_RES_PASSTHRU; } void Module::OnBuildNeighborList(User*, UserChanList&, std::map&) { } void Module::OnGarbageCollect() { } +ModResult Module::OnSetConnectClass(LocalUser* user, ConnectClass* myclass) { return MOD_RES_PASSTHRU; } void Module::OnText(User*, void*, int, const std::string&, char, CUList&) { } void Module::OnRunTestSuite() { } void Module::OnNamesListItem(User*, Membership*, std::string&, std::string&) { } ModResult Module::OnNumeric(User*, unsigned int, const std::string&) { return MOD_RES_PASSTHRU; } void Module::OnHookIO(StreamSocket*, ListenSocket*) { } ModResult Module::OnAcceptConnection(int, ListenSocket*, irc::sockets::sockaddrs*, irc::sockets::sockaddrs*) { return MOD_RES_PASSTHRU; } -void Module::OnSendWhoLine(User*, User*, Channel*, std::string&) { } -ModResult Module::OnChannelRestrictionApply(User*, Channel*, const char*) { return MOD_RES_PASSTHRU; } +void Module::OnSendWhoLine(User*, const std::vector&, User*, std::string&) { } ModuleManager::ModuleManager() : ModCount(0) { @@ -174,9 +187,6 @@ ModuleManager::~ModuleManager() bool ModuleManager::Attach(Implementation i, Module* mod) { - if (Modules.find(mod->ModuleSourceFile) == Modules.end()) - ServerInstance->Logs->Log("MODULE", ERROR, "Module %s is attaching to hook %d in constructor; this does not handle exceptions correctly!", mod->ModuleSourceFile.c_str(), i); - if (std::find(EventHandlers[i].begin(), EventHandlers[i].end(), mod) != EventHandlers[i].end()) return false; @@ -215,7 +225,7 @@ bool ModuleManager::SetPriority(Module* mod, Priority s) return true; } -bool ModuleManager::SetPriority(Module* mod, Implementation i, Priority s, Module** modules, size_t sz) +bool ModuleManager::SetPriority(Module* mod, Implementation i, Priority s, Module* which) { /** To change the priority of a module, we first find its position in the vector, * then we find the position of the other modules in the vector that this module @@ -223,10 +233,7 @@ bool ModuleManager::SetPriority(Module* mod, Implementation i, Priority s, Modul * on which they want, and we make sure our module is *at least* before or after * the first or last of this subset, depending again on the type of priority. */ - size_t swap_pos = 0; - size_t source = 0; - bool swap = true; - bool found = false; + size_t my_pos = 0; /* Locate our module. This is O(n) but it only occurs on module load so we're * not too bothered about it @@ -235,81 +242,65 @@ bool ModuleManager::SetPriority(Module* mod, Implementation i, Priority s, Modul { if (EventHandlers[i][x] == mod) { - source = x; - found = true; - break; + my_pos = x; + goto found_src; } } /* Eh? this module doesnt exist, probably trying to set priority on an event * theyre not attached to. */ - if (!found) - return false; + return false; +found_src: + size_t swap_pos = my_pos; switch (s) { - /* Dummy value */ - case PRIORITY_DONTCARE: - swap = false; - break; - /* Module wants to be first, sod everything else */ case PRIORITY_FIRST: if (prioritizationState != PRIO_STATE_FIRST) - swap = false; + return true; else swap_pos = 0; - break; - /* Module wants to be last. */ + break; case PRIORITY_LAST: if (prioritizationState != PRIO_STATE_FIRST) - swap = false; - else if (EventHandlers[i].empty()) - swap_pos = 0; + return true; else swap_pos = EventHandlers[i].size() - 1; - break; - /* Place this module after a set of other modules */ + break; case PRIORITY_AFTER: { - /* Find the latest possible position */ - swap_pos = 0; - swap = false; - for (size_t x = 0; x != EventHandlers[i].size(); ++x) + /* Find the latest possible position, only searching AFTER our position */ + for (size_t x = EventHandlers[i].size() - 1; x > my_pos; --x) { - for (size_t n = 0; n < sz; ++n) + if (EventHandlers[i][x] == which) { - if ((modules[n]) && (EventHandlers[i][x] == modules[n]) && (x >= swap_pos) && (source <= swap_pos)) - { - swap_pos = x; - swap = true; - } + swap_pos = x; + goto swap_now; } } + // didn't find it - either not loaded or we're already after + return true; } - break; /* Place this module before a set of other modules */ case PRIORITY_BEFORE: { - swap_pos = EventHandlers[i].size() - 1; - swap = false; - for (size_t x = 0; x != EventHandlers[i].size(); ++x) + for (size_t x = 0; x < my_pos; ++x) { - for (size_t n = 0; n < sz; ++n) + if (EventHandlers[i][x] == which) { - if ((modules[n]) && (EventHandlers[i][x] == modules[n]) && (x <= swap_pos) && (source >= swap_pos)) - { - swap = true; - swap_pos = x; - } + swap_pos = x; + goto swap_now; } } + // didn't find it - either not loaded or we're already before + return true; } - break; } +swap_now: /* Do we need to swap? */ - if (swap && (swap_pos != source)) + if (swap_pos != my_pos) { // We are going to change positions; we'll need to run again to verify all requirements if (prioritizationState == PRIO_STATE_LAST) @@ -317,10 +308,10 @@ bool ModuleManager::SetPriority(Module* mod, Implementation i, Priority s, Modul /* Suggestion from Phoenix, "shuffle" the modules to better retain call order */ int incrmnt = 1; - if (source > swap_pos) + if (my_pos > swap_pos) incrmnt = -1; - for (unsigned int j = source; j != swap_pos; j += incrmnt) + for (unsigned int j = my_pos; j != swap_pos; j += incrmnt) { if (( j + incrmnt > EventHandlers[i].size() - 1) || (j + incrmnt < 0)) continue; @@ -387,8 +378,8 @@ void ModuleManager::DoSafeUnload(Module* mod) if (curr->second->creator == mod) DataProviders.erase(curr); } - for(unsigned int i = 0; i < ServerInstance->Modules->ActiveDynrefs.size(); i++) - ServerInstance->Modules->ActiveDynrefs[i]->ClearCache(); + + dynamic_reference_base::reset_all(); /* Tidy up any dangling resolvers */ ServerInstance->Res->CleanResolvers(mod); @@ -405,6 +396,29 @@ void ModuleManager::DoSafeUnload(Module* mod) ServerInstance->BuildISupport(); } +void ModuleManager::UnloadAll() +{ + /* We do this more than once, so that any service providers get a + * chance to be unhooked by the modules using them, but then get + * a chance to be removed themsleves. + * + * Note: this deliberately does NOT delete the DLLManager objects + */ + for (int tries = 0; tries < 4; tries++) + { + std::map::iterator i = Modules.begin(); + while (i != Modules.end()) + { + std::map::iterator me = i++; + if (CanUnload(me->second)) + { + DoSafeUnload(me->second); + } + } + ServerInstance->GlobalCulls.Apply(); + } +} + std::string& ModuleManager::LastError() { return LastModuleError; @@ -422,18 +436,13 @@ bool InspIRCd::IsValidModuleCommand(const std::string &commandname, int pcnt, Us void ModuleManager::AddService(ServiceProvider& item) { - Module* owner = item.creator; - if (Modules.find(owner->ModuleSourceFile) == Modules.end()) - ServerInstance->Logs->Log("MODULE", ERROR, "Module %s is registering item %s in constructor; this does not handle exceptions correctly!", owner->ModuleSourceFile.c_str(), item.name.c_str()); - switch (item.service) { case SERVICE_COMMAND: if (!ServerInstance->Parser->AddCommand(static_cast(&item))) throw ModuleException("Command "+std::string(item.name)+" already exists."); return; - case SERVICE_CMODE: - case SERVICE_UMODE: + case SERVICE_MODE: if (!ServerInstance->Modes->AddMode(static_cast(&item))) throw ModuleException("Mode "+std::string(item.name)+" already exists."); return; @@ -457,6 +466,31 @@ void ModuleManager::AddService(ServiceProvider& item) } } +void ModuleManager::DelService(ServiceProvider& item) +{ + switch (item.service) + { + case SERVICE_MODE: + if (!ServerInstance->Modes->DelMode(static_cast(&item))) + throw ModuleException("Mode "+std::string(item.name)+" does not exist."); + return; + case SERVICE_DATA: + case SERVICE_IOHOOK: + { + for(std::multimap::iterator i = DataProviders.begin(); i != DataProviders.end(); ) + { + std::multimap::iterator curr = i++; + if (curr->second == &item) + DataProviders.erase(curr); + } + dynamic_reference_base::reset_all(); + return; + } + default: + throw ModuleException("Cannot delete unknown service type"); + } +} + ServiceProvider* ModuleManager::FindService(ServiceType type, const std::string& name) { switch (type) @@ -478,19 +512,26 @@ ServiceProvider* ModuleManager::FindService(ServiceType type, const std::string& dynamic_reference_base::dynamic_reference_base(Module* Creator, const std::string& Name) : name(Name), value(NULL), creator(Creator) { - ServerInstance->Modules->ActiveDynrefs.push_back(this); + if (!dynrefs) + dynrefs = new std::vector; + dynrefs->push_back(this); } dynamic_reference_base::~dynamic_reference_base() { - for(unsigned int i = 0; i < ServerInstance->Modules->ActiveDynrefs.size(); i++) + for(unsigned int i = 0; i < dynrefs->size(); i++) { - if (ServerInstance->Modules->ActiveDynrefs[i] == this) + if (dynrefs->at(i) == this) { - unsigned int last = ServerInstance->Modules->ActiveDynrefs.size() - 1; + unsigned int last = dynrefs->size() - 1; if (i != last) - ServerInstance->Modules->ActiveDynrefs[i] = ServerInstance->Modules->ActiveDynrefs[last]; - ServerInstance->Modules->ActiveDynrefs.erase(ServerInstance->Modules->ActiveDynrefs.begin() + last); + dynrefs->at(i) = dynrefs->at(last); + dynrefs->erase(dynrefs->begin() + last); + if (dynrefs->empty()) + { + delete dynrefs; + dynrefs = NULL; + } return; } } @@ -524,6 +565,14 @@ void InspIRCd::SendMode(const std::vector& parameters, User *user) this->Modes->Process(parameters, user); } + +void InspIRCd::SendGlobalMode(const std::vector& parameters, User *user) +{ + Modes->Process(parameters, user); + if (!Modes->GetLastParse().empty()) + this->PI->SendMode(parameters[0], Modes->GetLastParseParams(), Modes->GetLastParseTranslate()); +} + bool InspIRCd::AddResolver(Resolver* r, bool cached) { if (!cached) @@ -558,6 +607,8 @@ const std::vector ModuleManager::GetAllModuleNames(int filter) ConfigReader::ConfigReader() { this->error = 0; + ServerInstance->Logs->Log("MODULE", DEBUG, "ConfigReader is deprecated in 2.0; " + "use ServerInstance->Config->ConfValue(\"key\") or ->ConfTags(\"key\") instead"); } @@ -675,13 +726,27 @@ void FileReader::CalcSize() void FileReader::LoadFile(const std::string &filename) { - file_cache c; - c.clear(); - if (ServerInstance->Config->ReadFile(c,filename.c_str())) + std::map::iterator file = ServerInstance->Config->Files.find(filename); + if (file != ServerInstance->Config->Files.end()) { - this->fc = c; - this->CalcSize(); + this->fc = file->second; + } + else + { + fc.clear(); + FILE* f = fopen(filename.c_str(), "r"); + if (!f) + return; + char linebuf[MAXBUF*10]; + while (fgets(linebuf, sizeof(linebuf), f)) + { + int len = strlen(linebuf); + if (len) + fc.push_back(std::string(linebuf, len - 1)); + } + fclose(f); } + CalcSize(); }