/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2009 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 . */ #include "inspircd.h" struct vtbase { virtual void isok(const char* name, int impl, Module* basemod, std::vector& allmods) = 0; virtual ~vtbase() {} }; template struct vtable : public vtbase { union u { T function; struct v { size_t delta; size_t vtoff; } v; } u; vtable(T t) { u.function = t; } /** member function pointer dereference from vtable; depends on the GCC 4.4 ABI (x86_64) */ template void* read(E* obj) { if (u.v.delta & 1) { uint8_t* optr = reinterpret_cast(obj); optr += u.v.vtoff; uint8_t* vptr = *reinterpret_cast(optr); vptr += u.v.delta - 1; return *reinterpret_cast(vptr); } else return reinterpret_cast(u.v.delta); } void isok(const char* name, int impl, Module* basemod, std::vector& allmods) { void* base = read(basemod); for(unsigned int i=0; i < allmods.size(); ++i) { Module* mod = ServerInstance->Modules->Find(allmods[i]); void* fptr = read(mod); for(EventHandlerIter j = ServerInstance->Modules->EventHandlers[impl].begin(); j != ServerInstance->Modules->EventHandlers[impl].end(); j++) { if (mod == *j) { if (fptr == base) { ServerInstance->SNO->WriteToSnoMask('a', "Module %s implements %s but uses default function", mod->ModuleSourceFile.c_str(), name); } goto done; } } if (fptr != base) { ServerInstance->SNO->WriteToSnoMask('a', "Module %s does not implement %s but overrides function", mod->ModuleSourceFile.c_str(), name); } done:; } } }; template vtbase* vtinit(T t) { return new vtable(t); } static void checkall(Module* noimpl) { std::vector allmods = ServerInstance->Modules->GetAllModuleNames(0); #define CHK(name) do { \ vtbase* vt = vtinit(&Module::name); \ vt->isok(#name, I_ ## name, noimpl, allmods); \ delete vt; \ } while (0) CHK(OnUserConnect); CHK(OnUserQuit); CHK(OnUserDisconnect); CHK(OnUserJoin); CHK(OnUserPart); CHK(OnRehash); CHK(OnSendSnotice); CHK(OnUserPreJoin); CHK(OnUserPreKick); CHK(OnUserKick); CHK(OnOper); CHK(OnInfo); CHK(OnWhois); CHK(OnUserPreInvite); CHK(OnUserInvite); CHK(OnUserPreMessage); CHK(OnUserPreNick); CHK(OnUserMessage); CHK(OnMode); CHK(OnGetServerDescription); CHK(OnSyncUser); CHK(OnSyncChannel); CHK(OnDecodeMetaData); CHK(OnAcceptConnection); CHK(OnChangeHost); CHK(OnChangeName); CHK(OnAddLine); CHK(OnDelLine); CHK(OnExpireLine); CHK(OnUserPostNick); CHK(OnPreMode); CHK(On005Numeric); CHK(OnKill); CHK(OnLoadModule); CHK(OnUnloadModule); CHK(OnBackgroundTimer); CHK(OnPreCommand); CHK(OnCheckReady); CHK(OnCheckInvite); CHK(OnRawMode); CHK(OnCheckKey); CHK(OnCheckLimit); CHK(OnCheckBan); CHK(OnCheckChannelBan); CHK(OnExtBanCheck); CHK(OnStats); CHK(OnChangeLocalUserHost); CHK(OnPreTopicChange); CHK(OnPostTopicChange); CHK(OnEvent); CHK(OnGlobalOper); CHK(OnPostConnect); CHK(OnChangeLocalUserGECOS); CHK(OnUserRegister); CHK(OnChannelPreDelete); CHK(OnChannelDelete); CHK(OnPostOper); CHK(OnSyncNetwork); CHK(OnSetAway); CHK(OnPostCommand); CHK(OnPostJoin); CHK(OnWhoisLine); CHK(OnBuildNeighborList); CHK(OnGarbageCollect); CHK(OnText); CHK(OnPassCompare); CHK(OnRunTestSuite); CHK(OnNamesListItem); CHK(OnNumeric); CHK(OnHookIO); CHK(OnPreRehash); CHK(OnModuleRehash); CHK(OnSendWhoLine); CHK(OnChangeIdent); } class CommandTest : public Command { public: CommandTest(Module* parent) : Command(parent, "TEST", 1) { syntax = " "; } CmdResult Handle(const std::vector ¶meters, User *user) { if (parameters[0] == "flood") { unsigned int count = parameters.size() > 1 ? atoi(parameters[1].c_str()) : 100; std::string line = parameters.size() > 2 ? parameters[2] : ":z.z NOTICE !flood :Flood text"; for(unsigned int i=0; i < count; i++) user->Write(line); } else if (parameters[0] == "freeze" && IS_LOCAL(user) && parameters.size() > 1) { IS_LOCAL(user)->CommandFloodPenalty += atoi(parameters[1].c_str()); } else if (parameters[0] == "check") { checkall(creator); ServerInstance->SNO->WriteToSnoMask('a', "Module check complete"); } return CMD_SUCCESS; } }; class ModuleTest : public Module { CommandTest cmd; public: ModuleTest() : cmd(this) { } void init() CXX11_OVERRIDE { if (!strstr(ServerInstance->Config->ServerName.c_str(), ".test")) throw ModuleException("Don't load modules without reading their descriptions!"); ServerInstance->Modules->AddService(cmd); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides a module for testing the server while linked in a network", VF_VENDOR|VF_OPTCOMMON); } }; MODULE_INIT(ModuleTest)