X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Fm_kicknorejoin.cpp;h=b8a7766675e8e191ea0cb45331ba495058f695d9;hb=63aa8d0d42f619c52d382bde3e6ba2e5e23b12ac;hp=97d88786ff13640247a44e99b5d7abcf8df8450d;hpb=bab14f0dd2345c9d7dcbc47c918563709e1ac094;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modules/m_kicknorejoin.cpp b/src/modules/m_kicknorejoin.cpp index 97d88786f..b8a776667 100644 --- a/src/modules/m_kicknorejoin.cpp +++ b/src/modules/m_kicknorejoin.cpp @@ -1 +1,160 @@ -/* +------------------------------------+ * | Inspire Internet Relay Chat Daemon | * +------------------------------------+ * * InspIRCd: (C) 2002-2007 InspIRCd Development Team * See: http://www.inspircd.org/wiki/index.php/Credits * * This program is free but copyrighted software; see * the file COPYING for details. * * --------------------------------------------------- */ #include "inspircd.h" #include #include "users.h" #include "channels.h" #include "modules.h" /* $ModDesc: Provides channel mode +J (delay rejoin after kick) */ inline int strtoint(const std::string &str) { std::istringstream ss(str); int result; ss >> result; return result; } typedef std::map delaylist; /** Handles channel mode +J */ class KickRejoin : public ModeHandler { public: KickRejoin(InspIRCd* Instance) : ModeHandler(Instance, 'J', 1, 0, false, MODETYPE_CHANNEL, false) { } ModePair ModeSet(userrec* source, userrec* dest, chanrec* channel, const std::string ¶meter) { if (channel->IsModeSet('J')) return std::make_pair(true, channel->GetModeParameter('J')); else return std::make_pair(false, parameter); } bool CheckTimeStamp(time_t theirs, time_t ours, const std::string &their_param, const std::string &our_param, chanrec* channel) { /* When TS is equal, the alphabetically later one wins */ return (their_param < our_param); } ModeAction OnModeChange(userrec* source, userrec* dest, chanrec* channel, std::string ¶meter, bool adding) { if (!adding) { // Taking the mode off, we need to clean up. delaylist* dl; if (channel->GetExt("norejoinusers", dl)) { DELETE(dl); channel->Shrink("norejoinusers"); } if (!channel->IsModeSet('J')) { return MODEACTION_DENY; } else { channel->SetMode('J', false); return MODEACTION_ALLOW; } } else if (atoi(parameter.c_str()) > 0) { if (!channel->IsModeSet('J')) { parameter = ConvToStr(atoi(parameter.c_str())); channel->SetModeParam('J', parameter.c_str(), adding); channel->SetMode('J', adding); return MODEACTION_ALLOW; } else { std::string cur_param = channel->GetModeParameter('J'); if (cur_param == parameter) { // mode params match, don't change mode return MODEACTION_DENY; } else { // new mode param, replace old with new parameter = ConvToStr(atoi(parameter.c_str())); cur_param = ConvToStr(atoi(cur_param.c_str())); if (parameter != "0") { channel->SetModeParam('J', cur_param.c_str(), false); channel->SetModeParam('J', parameter.c_str(), adding); return MODEACTION_ALLOW; } else { /* Fix to jamie's fix, dont allow +J 0 on the new value! */ return MODEACTION_DENY; } } } } else { return MODEACTION_DENY; } } }; class ModuleKickNoRejoin : public Module { KickRejoin* kr; public: ModuleKickNoRejoin(InspIRCd* Me) : Module(Me) { kr = new KickRejoin(ServerInstance); if (!ServerInstance->AddMode(kr, 'J')) throw ModuleException("Could not add new modes!"); } virtual int OnUserPreJoin(userrec* user, chanrec* chan, const char* cname, std::string &privs) { if (chan) { delaylist* dl; if (chan->GetExt("norejoinusers", dl)) { std::vector itemstoremove; for (delaylist::iterator iter = dl->begin(); iter != dl->end(); iter++) { if (iter->second > time(NULL)) { if (iter->first == user) { user->WriteServ( "495 %s %s :You cannot rejoin this channel yet after being kicked (+J)", user->nick, chan->name); return 1; } } else { // Expired record, remove. itemstoremove.push_back(iter->first); } } for (unsigned int i = 0; i < itemstoremove.size(); i++) dl->erase(itemstoremove[i]); if (!dl->size()) { // Now it's empty.. DELETE(dl); chan->Shrink("norejoinusers"); } } } return 0; } virtual void OnUserKick(userrec* source, userrec* user, chanrec* chan, const std::string &reason, bool &silent) { if (chan->IsModeSet('J') && (source != user)) { delaylist* dl; if (!chan->GetExt("norejoinusers", dl)) { dl = new delaylist; chan->Extend("norejoinusers", dl); } (*dl)[user] = time(NULL) + strtoint(chan->GetModeParameter('J')); } } virtual void OnChannelDelete(chanrec* chan) { delaylist* dl; if (chan->GetExt("norejoinusers", dl)) { DELETE(dl); chan->Shrink("norejoinusers"); } } virtual void OnCleanup(int target_type, void* item) { if(target_type == TYPE_CHANNEL) OnChannelDelete((chanrec*)item); } virtual void Implements(char* List) { List[I_OnCleanup] = List[I_OnChannelDelete] = List[I_OnUserPreJoin] = List[I_OnUserKick] = 1; } virtual ~ModuleKickNoRejoin() { ServerInstance->Modes->DelMode(kr); DELETE(kr); } virtual Version GetVersion() { return Version(1, 1, 0, 0, VF_COMMON | VF_VENDOR, API_VERSION); } }; MODULE_INIT(ModuleKickNoRejoin) \ No newline at end of file +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2009 Daniel De Graaf + * Copyright (C) 2008 Pippijn van Steenhoven + * Copyright (C) 2007 Dennis Friis + * Copyright (C) 2006-2007 Robin Burchell + * Copyright (C) 2006 John Brooks + * Copyright (C) 2006 Craig Edwards + * Copyright (C) 2006 Oliver Lupton + * + * 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" + +class KickRejoinData +{ + struct KickedUser + { + std::string uuid; + time_t expire; + + KickedUser(User* user, unsigned int Delay) + : uuid(user->uuid) + , expire(ServerInstance->Time() + Delay) + { + } + }; + + typedef std::vector KickedList; + + mutable KickedList kicked; + + public: + const unsigned int delay; + + KickRejoinData(unsigned int Delay) : delay(Delay) { } + + bool canjoin(LocalUser* user) const + { + for (KickedList::iterator i = kicked.begin(); i != kicked.end(); ) + { + KickedUser& rec = *i; + if (rec.expire > ServerInstance->Time()) + { + if (rec.uuid == user->uuid) + return false; + ++i; + } + else + { + // Expired record, remove. + stdalgo::vector::swaperase(kicked, i); + if (kicked.empty()) + break; + } + } + return true; + } + + void add(User* user) + { + // One user can be in the list multiple times if the user gets kicked, force joins + // (skipping OnUserPreJoin) and gets kicked again, but that's okay because canjoin() + // works correctly in this case as well + kicked.push_back(KickedUser(user, delay)); + } +}; + +/** Handles channel mode +J + */ +class KickRejoin : public ParamMode > +{ + const unsigned int max; + public: + KickRejoin(Module* Creator) + : ParamMode >(Creator, "kicknorejoin", 'J') + , max(60) + { + } + + ModeAction OnSet(User* source, Channel* channel, std::string& parameter) + { + int v = ConvToInt(parameter); + if (v <= 0) + return MODEACTION_DENY; + + if ((IS_LOCAL(source) && ((unsigned int)v > max))) + v = max; + + ext.set(channel, new KickRejoinData(v)); + return MODEACTION_ALLOW; + } + + void SerializeParam(Channel* chan, const KickRejoinData* krd, std::string& out) + { + out.append(ConvToStr(krd->delay)); + } + + std::string GetModuleSettings() const + { + return ConvToStr(max); + } +}; + +class ModuleKickNoRejoin : public Module +{ + KickRejoin kr; + +public: + ModuleKickNoRejoin() + : kr(this) + { + } + + ModResult OnUserPreJoin(LocalUser* user, Channel* chan, const std::string& cname, std::string& privs, const std::string& keygiven) CXX11_OVERRIDE + { + if (chan) + { + const KickRejoinData* data = kr.ext.get(chan); + if ((data) && (!data->canjoin(user))) + { + user->WriteNumeric(ERR_DELAYREJOIN, "%s :You must wait %u seconds after being kicked to rejoin (+J)", chan->name.c_str(), data->delay); + return MOD_RES_DENY; + } + } + return MOD_RES_PASSTHRU; + } + + void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE + { + if ((!IS_LOCAL(memb->user)) || (source == memb->user)) + return; + + KickRejoinData* data = kr.ext.get(memb->chan); + if (data) + { + data->add(memb->user); + } + } + + Version GetVersion() CXX11_OVERRIDE + { + return Version("Channel mode to delay rejoin after kick", VF_VENDOR | VF_COMMON, kr.GetModuleSettings()); + } +}; + +MODULE_INIT(ModuleKickNoRejoin)