From: Attila Molnar Date: Sat, 15 Feb 2014 13:38:24 +0000 (+0100) Subject: Add ParamModeBase and ParamMode, change all parameter modes to inherit from ParamMode X-Git-Url: https://git.netwichtig.de/gitweb/?a=commitdiff_plain;h=0556720b559d7ec5d8badacf0ac9b11e9c864847;p=user%2Fhenk%2Fcode%2Finspircd.git Add ParamModeBase and ParamMode, change all parameter modes to inherit from ParamMode - Type of the extension used to store data is a template parameter - The extension is automatically unset when the mode is unset - Handlers inheriting from ParamMode have to provide OnSet() and SerializeParam(); may optionally provide OnUnset() - Transparently handle the case when OnSet() modifies the mode parameter - Remove Channel::custom_mode_params map; ask the mode handlers to serialize their parameters instead --- diff --git a/include/builtinmodes.h b/include/builtinmodes.h index ce73a7817..6aab727cc 100644 --- a/include/builtinmodes.h +++ b/include/builtinmodes.h @@ -47,21 +47,24 @@ class ModeChannelInviteOnly : public SimpleChannelModeHandler /** Channel mode +k */ -class ModeChannelKey : public ModeHandler +class ModeChannelKey : public ParamMode { public: ModeChannelKey(); ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); + void SerializeParam(Channel* chan, const std::string* key, std::string& out); + ModeAction OnSet(User* source, Channel* chan, std::string& param); }; /** Channel mode +l */ -class ModeChannelLimit : public ParamChannelModeHandler +class ModeChannelLimit : public ParamMode { public: ModeChannelLimit(); - bool ParamValidate(std::string& parameter); bool ResolveModeConflict(std::string &their_param, const std::string &our_param, Channel* channel); + void SerializeParam(Channel* chan, intptr_t n, std::string& out); + ModeAction OnSet(User* source, Channel* channel, std::string& parameter); }; /** Channel mode +m diff --git a/include/channels.h b/include/channels.h index 9b018b23e..ba2018e97 100644 --- a/include/channels.h +++ b/include/channels.h @@ -24,6 +24,7 @@ #include "membership.h" #include "mode.h" +#include "parammode.h" /** Holds an entry for a ban list, exemption list, or invite list. * This class contains a single element in a channel list, such as a banlist. @@ -47,11 +48,6 @@ class CoreExport Channel : public Extensible, public InviteBase */ std::bitset<64> modes; - /** Parameters for custom modes. - * One for each custom mode letter. - */ - CustomModeList custom_mode_params; - /** Remove the given membership from the channel's internal map of * memberships and destroy the Membership object. * This function does not remove the channel from User::chanlist. @@ -113,13 +109,6 @@ class CoreExport Channel : public Extensible, public InviteBase */ void SetMode(ModeHandler* mode, bool value); - /** Sets or unsets a custom mode in the channels info - * @param mode The mode character to set or unset - * @param parameter The parameter string to associate with this mode character. - * If it is empty, the mode is unset; if it is nonempty, the mode is set. - */ - void SetModeParam(ModeHandler* mode, const std::string& parameter); - /** Returns true if a mode is set on a channel * @param mode The mode character you wish to query * @return True if the custom mode is set, false if otherwise @@ -140,6 +129,7 @@ class CoreExport Channel : public Extensible, public InviteBase */ std::string GetModeParameter(ModeHandler* mode); std::string GetModeParameter(ChanModeReference& mode); + std::string GetModeParameter(ParamModeBase* pm); /** Sets the channel topic. * @param user The user setting the topic. @@ -344,6 +334,23 @@ inline std::string Channel::GetModeParameter(ChanModeReference& mode) return GetModeParameter(*mode); } +inline std::string Channel::GetModeParameter(ModeHandler* mh) +{ + std::string out; + ParamModeBase* pm = mh->IsParameterMode(); + if (pm && this->IsModeSet(pm)) + pm->GetParameter(this, out); + return out; +} + +inline std::string Channel::GetModeParameter(ParamModeBase* pm) +{ + std::string out; + if (this->IsModeSet(pm)) + pm->GetParameter(this, out); + return out; +} + inline bool Channel::IsModeSet(ChanModeReference& mode) { if (!mode) diff --git a/include/extensible.h b/include/extensible.h index a0544bba1..0e1afdbdf 100644 --- a/include/extensible.h +++ b/include/extensible.h @@ -184,6 +184,7 @@ class CoreExport LocalIntExt : public LocalExtItem std::string serialize(SerializeFormat format, const Extensible* container, void* item) const; intptr_t get(const Extensible* container) const; intptr_t set(Extensible* container, intptr_t value); + void unset(Extensible* container) { set(container, 0); } void free(void* item); }; diff --git a/include/mode.h b/include/mode.h index dd5334c66..3193af65f 100644 --- a/include/mode.h +++ b/include/mode.h @@ -409,16 +409,6 @@ class CoreExport SimpleChannelModeHandler : public ModeHandler virtual ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); }; -class CoreExport ParamChannelModeHandler : public ModeHandler -{ - public: - ParamChannelModeHandler(Module* Creator, const std::string& Name, char modeletter) - : ModeHandler(Creator, Name, modeletter, PARAM_SETONLY, MODETYPE_CHANNEL) {} - virtual ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); - /** Validate the parameter - you may change the value to normalize it. Return true if it is valid. */ - virtual bool ParamValidate(std::string& parameter); -}; - /** * The ModeWatcher class can be used to alter the behaviour of a mode implemented * by the core or by another module. To use ModeWatcher, derive a class from it, diff --git a/include/parammode.h b/include/parammode.h new file mode 100644 index 000000000..b0005262e --- /dev/null +++ b/include/parammode.h @@ -0,0 +1,75 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2014 Attila Molnar + * + * 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 . + */ + + +#pragma once + +class CoreExport ParamModeBase : public ModeHandler +{ + private: + virtual void OnUnsetInternal(User* source, Channel* chan) = 0; + + public: + ParamModeBase(Module* Creator, const std::string& Name, char modeletter, ParamSpec ps) + : ModeHandler(Creator, Name, modeletter, ps, MODETYPE_CHANNEL, MC_PARAM) { } + + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& param, bool adding) CXX11_OVERRIDE; + + // Does nothing by default + void OnUnset(User* source, Channel* chan) { } + virtual ModeAction OnSet(User* source, Channel* chan, std::string& param) = 0; + virtual void GetParameter(Channel* chan, std::string& out) = 0; +}; + +/** Defines a parameter mode + * T = Child class + * ExtItemT = Type of the extension item used to store the parameter + * + * When unsetting the mode, the extension is automatically unset. + */ +template +class ParamMode : public ParamModeBase +{ + public: + ExtItemT ext; + + /** + * @param Creator Module handling this mode + * @param Name The internal name of this mode + * @param modeletter The mode letter of this mode + * @param ps The parameter type of this mode, one of ParamSpec + */ + ParamMode(Module* Creator, const std::string& Name, char modeletter, ParamSpec ps = PARAM_SETONLY) + : ParamModeBase(Creator, Name, modeletter, ps) + , ext("parammode_" + Name, Creator) + { + } + + void OnUnsetInternal(User* source, Channel* chan) CXX11_OVERRIDE + { + T* mh = static_cast(this); + mh->OnUnset(source, chan); + ext.unset(chan); + } + + void GetParameter(Channel* chan, std::string& out) CXX11_OVERRIDE + { + T* mh = static_cast(this); + mh->SerializeParam(chan, ext.get(chan), out); + } +}; diff --git a/include/typedefs.h b/include/typedefs.h index 77a45ce4e..336084c55 100644 --- a/include/typedefs.h +++ b/include/typedefs.h @@ -77,10 +77,6 @@ typedef UserChanList::iterator UCListIter; */ typedef std::vector IncludeChanList; -/** A list of custom modes parameters on a channel - */ -typedef std::map CustomModeList; - /** A cached text file stored with its contents as lines */ typedef std::vector file_cache; diff --git a/src/channels.cpp b/src/channels.cpp index a8f8db43c..448764e1c 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -51,29 +51,6 @@ void Channel::SetMode(ModeHandler* mh, bool on) modes[mh->GetModeChar() - 65] = on; } -void Channel::SetModeParam(ModeHandler* mh, const std::string& parameter) -{ - char mode = mh->GetModeChar(); - if (parameter.empty()) - { - custom_mode_params.erase(mode); - modes[mode-65] = false; - } - else - { - custom_mode_params[mode] = parameter; - modes[mode-65] = true; - } -} - -std::string Channel::GetModeParameter(ModeHandler* mode) -{ - CustomModeList::iterator n = custom_mode_params.find(mode->GetModeChar()); - if (n != custom_mode_params.end()) - return n->second; - return ""; -} - void Channel::SetTopic(User* u, const std::string& ntopic) { this->topic.assign(ntopic, 0, ServerInstance->Config->Limits.MaxTopic); @@ -628,18 +605,18 @@ const char* Channel::ChanModes(bool showkey) if (!mh) continue; + ParamModeBase* pm = mh->IsParameterMode(); + if (!pm) + continue; + if (n == 'k' - 65 && !showkey) { sparam += " "; } else { - const std::string param = this->GetModeParameter(mh); - if (!param.empty()) - { - sparam += ' '; - sparam += param; - } + sparam += ' '; + pm->GetParameter(this, sparam); } } } diff --git a/src/mode.cpp b/src/mode.cpp index ad46e602d..eeab0de3a 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -127,21 +127,6 @@ ModeAction SimpleChannelModeHandler::OnModeChange(User* source, User* dest, Chan return MODEACTION_ALLOW; } -ModeAction ParamChannelModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) -{ - if (adding && !ParamValidate(parameter)) - return MODEACTION_DENY; - std::string now = channel->GetModeParameter(this); - if (parameter == now) - return MODEACTION_DENY; - return MODEACTION_ALLOW; -} - -bool ParamChannelModeHandler::ParamValidate(std::string& parameter) -{ - return true; -} - ModeWatcher::ModeWatcher(Module* Creator, const std::string& modename, ModeType type) : mode(modename), m_type(type), creator(Creator) { @@ -227,6 +212,32 @@ ModeAction PrefixMode::OnModeChange(User* source, User*, Channel* chan, std::str return (memb->SetPrefix(this, adding) ? MODEACTION_ALLOW : MODEACTION_DENY); } +ModeAction ParamModeBase::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding) +{ + if (adding) + { + if (chan->GetModeParameter(this) == parameter) + return MODEACTION_DENY; + + if (OnSet(source, chan, parameter) != MODEACTION_ALLOW) + return MODEACTION_DENY; + + chan->SetMode(this, true); + + // Handler might have changed the parameter internally + parameter.clear(); + this->GetParameter(chan, parameter); + } + else + { + if (!chan->IsModeSet(this)) + return MODEACTION_DENY; + this->OnUnsetInternal(source, chan); + chan->SetMode(this, false); + } + return MODEACTION_ALLOW; +} + ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar, std::string ¶meter, bool SkipACL) { @@ -336,9 +347,6 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool if (ma != MODEACTION_ALLOW) return ma; - if ((!mh->IsListMode()) && (mh->GetNumParams(true)) && (chan)) - chan->SetModeParam(mh, (adding ? parameter : "")); - itpair = modewatchermap.equal_range(mh->name); for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) { diff --git a/src/modes/cmode_k.cpp b/src/modes/cmode_k.cpp index e56b26ff1..e14f93a77 100644 --- a/src/modes/cmode_k.cpp +++ b/src/modes/cmode_k.cpp @@ -26,32 +26,51 @@ #include "users.h" #include "builtinmodes.h" -ModeChannelKey::ModeChannelKey() : ModeHandler(NULL, "key", 'k', PARAM_ALWAYS, MODETYPE_CHANNEL) +ModeChannelKey::ModeChannelKey() + : ParamMode(NULL, "key", 'k', PARAM_ALWAYS) { } ModeAction ModeChannelKey::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) { - bool exists = channel->IsModeSet(this); + const std::string* key = ext.get(channel); + bool exists = (key != NULL); if (IS_LOCAL(source)) { if (exists == adding) return MODEACTION_DENY; - if (exists && (parameter != channel->GetModeParameter(this))) + if (exists && (parameter != *key)) { /* Key is currently set and the correct key wasnt given */ return MODEACTION_DENY; } } else { - if (exists && adding && parameter == channel->GetModeParameter(this)) + if (exists && adding && parameter == *key) { /* no-op, don't show */ return MODEACTION_DENY; } } + channel->SetMode(this, adding); if (adding) + { parameter = parameter.substr(0, 32); + ext.set(channel, parameter); + } + else + ext.unset(channel); return MODEACTION_ALLOW; } + +void ModeChannelKey::SerializeParam(Channel* chan, const std::string* key, std::string& out) +{ + out += *key; +} + +ModeAction ModeChannelKey::OnSet(User* source, Channel* chan, std::string& param) +{ + // Dummy function, never called + return MODEACTION_DENY; +} diff --git a/src/modes/cmode_l.cpp b/src/modes/cmode_l.cpp index f057a75e6..128854b50 100644 --- a/src/modes/cmode_l.cpp +++ b/src/modes/cmode_l.cpp @@ -25,7 +25,8 @@ #include "users.h" #include "builtinmodes.h" -ModeChannelLimit::ModeChannelLimit() : ParamChannelModeHandler(NULL, "limit", 'l') +ModeChannelLimit::ModeChannelLimit() + : ParamMode(NULL, "limit", 'l') { } @@ -35,13 +36,13 @@ bool ModeChannelLimit::ResolveModeConflict(std::string &their_param, const std:: return (atoi(their_param.c_str()) < atoi(our_param.c_str())); } -bool ModeChannelLimit::ParamValidate(std::string ¶meter) +ModeAction ModeChannelLimit::OnSet(User* user, Channel* chan, std::string& parameter) { - int limit = atoi(parameter.c_str()); - - if (limit < 0) - return false; + ext.set(chan, ConvToInt(parameter)); + return MODEACTION_ALLOW; +} - parameter = ConvToStr(limit); - return true; +void ModeChannelLimit::SerializeParam(Channel* chan, intptr_t n, std::string& out) +{ + out += ConvToStr(n); } diff --git a/src/modules/m_chanhistory.cpp b/src/modules/m_chanhistory.cpp index 24c6237b3..f6e7ea40e 100644 --- a/src/modules/m_chanhistory.cpp +++ b/src/modules/m_chanhistory.cpp @@ -30,10 +30,13 @@ struct HistoryList { std::deque lines; unsigned int maxlen, maxtime; - HistoryList(unsigned int len, unsigned int time) : maxlen(len), maxtime(time) {} + std::string param; + + HistoryList(unsigned int len, unsigned int time, const std::string& oparam) + : maxlen(len), maxtime(time), param(oparam) { } }; -class HistoryMode : public ModeHandler +class HistoryMode : public ParamMode > { bool IsValidDuration(const std::string& duration) { @@ -50,57 +53,53 @@ class HistoryMode : public ModeHandler } public: - SimpleExtItem ext; unsigned int maxlines; - HistoryMode(Module* Creator) : ModeHandler(Creator, "history", 'H', PARAM_SETONLY, MODETYPE_CHANNEL), - ext("history", Creator) { } + HistoryMode(Module* Creator) + : ParamMode >(Creator, "history", 'H') + { + } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + ModeAction OnSet(User* source, Channel* channel, std::string& parameter) { - if (adding) + std::string::size_type colon = parameter.find(':'); + if (colon == std::string::npos) + return MODEACTION_DENY; + + std::string duration = parameter.substr(colon+1); + if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!IsValidDuration(duration)))) + return MODEACTION_DENY; + + unsigned int len = ConvToInt(parameter.substr(0, colon)); + int time = InspIRCd::Duration(duration); + if (len == 0 || time < 0) + return MODEACTION_DENY; + if (len > maxlines && IS_LOCAL(source)) + return MODEACTION_DENY; + if (len > maxlines) + len = maxlines; + + HistoryList* history = ext.get(channel); + if (history) { - std::string::size_type colon = parameter.find(':'); - if (colon == std::string::npos) - return MODEACTION_DENY; - - std::string duration = parameter.substr(colon+1); - if ((IS_LOCAL(source)) && ((duration.length() > 10) || (!IsValidDuration(duration)))) - return MODEACTION_DENY; - - unsigned int len = ConvToInt(parameter.substr(0, colon)); - int time = InspIRCd::Duration(duration); - if (len == 0 || time < 0) - return MODEACTION_DENY; - if (len > maxlines && IS_LOCAL(source)) - return MODEACTION_DENY; - if (len > maxlines) - len = maxlines; - if (parameter == channel->GetModeParameter(this)) - return MODEACTION_DENY; - - HistoryList* history = ext.get(channel); - if (history) - { - // Shrink the list if the new line number limit is lower than the old one - if (len < history->lines.size()) - history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - len)); + // Shrink the list if the new line number limit is lower than the old one + if (len < history->lines.size()) + history->lines.erase(history->lines.begin(), history->lines.begin() + (history->lines.size() - len)); - history->maxlen = len; - history->maxtime = time; - } - else - { - ext.set(channel, new HistoryList(len, time)); - } + history->maxlen = len; + history->maxtime = time; + history->param = parameter; } else { - if (!channel->IsModeSet(this)) - return MODEACTION_DENY; - ext.unset(channel); + ext.set(channel, new HistoryList(len, time, parameter)); } return MODEACTION_ALLOW; } + + void SerializeParam(Channel* chan, const HistoryList* history, std::string& out) + { + out.append(history->param); + } }; class ModuleChanHistory : public Module diff --git a/src/modules/m_delaymsg.cpp b/src/modules/m_delaymsg.cpp index 031680e18..1730663c5 100644 --- a/src/modules/m_delaymsg.cpp +++ b/src/modules/m_delaymsg.cpp @@ -19,11 +19,12 @@ #include "inspircd.h" -class DelayMsgMode : public ModeHandler +class DelayMsgMode : public ParamMode { public: LocalIntExt jointime; - DelayMsgMode(Module* Parent) : ModeHandler(Parent, "delaymsg", 'd', PARAM_SETONLY, MODETYPE_CHANNEL) + DelayMsgMode(Module* Parent) + : ParamMode(Parent, "delaymsg", 'd') , jointime("delaymsg", Parent) { levelrequired = OP_VALUE; @@ -34,7 +35,13 @@ class DelayMsgMode : public ModeHandler return (atoi(their_param.c_str()) < atoi(our_param.c_str())); } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); + ModeAction OnSet(User* source, Channel* chan, std::string& parameter); + void OnUnset(User* source, Channel* chan); + + void SerializeParam(Channel* chan, int n, std::string& out) + { + out += ConvToStr(n); + } }; class ModuleDelayMsg : public Module @@ -50,37 +57,27 @@ class ModuleDelayMsg : public Module ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE; }; -ModeAction DelayMsgMode::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) +ModeAction DelayMsgMode::OnSet(User* source, Channel* chan, std::string& parameter) { - if (adding) - { - if ((channel->IsModeSet(this)) && (channel->GetModeParameter(this) == parameter)) - return MODEACTION_DENY; + // Setting a new limit, sanity check + unsigned int limit = ConvToInt(parameter); + if (limit == 0) + limit = 1; - /* Setting a new limit, sanity check */ - long limit = atoi(parameter.c_str()); - - /* Wrap low values at 32768 */ - if (limit < 0) - limit = 0x7FFF; - - parameter = ConvToStr(limit); - } - else - { - if (!channel->IsModeSet(this)) - return MODEACTION_DENY; - - /* - * Clean up metadata - */ - const UserMembList* names = channel->GetUsers(); - for (UserMembCIter n = names->begin(); n != names->end(); ++n) - jointime.set(n->second, 0); - } + ext.set(chan, limit); return MODEACTION_ALLOW; } +void DelayMsgMode::OnUnset(User* source, Channel* chan) +{ + /* + * Clean up metadata + */ + const UserMembList* names = chan->GetUsers(); + for (UserMembCIter n = names->begin(); n != names->end(); ++n) + jointime.set(n->second, 0); +} + Version ModuleDelayMsg::GetVersion() { return Version("Provides channelmode +d , to deny messages to a channel until seconds.", VF_VENDOR); @@ -114,14 +111,14 @@ ModResult ModuleDelayMsg::OnUserPreMessage(User* user, void* dest, int target_ty if (ts == 0) return MOD_RES_PASSTHRU; - std::string len = channel->GetModeParameter(&djm); + int len = djm.ext.get(channel); - if (ts + atoi(len.c_str()) > ServerInstance->Time()) + if ((ts + len) > ServerInstance->Time()) { if (channel->GetPrefixValue(user) < VOICE_VALUE) { - user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :You must wait %s seconds after joining to send to channel (+d)", - channel->name.c_str(), len.c_str()); + user->WriteNumeric(ERR_CANNOTSENDTOCHAN, "%s :You must wait %d seconds after joining to send to channel (+d)", + channel->name.c_str(), len); return MOD_RES_DENY; } } diff --git a/src/modules/m_joinflood.cpp b/src/modules/m_joinflood.cpp index edce2b22c..52802f168 100644 --- a/src/modules/m_joinflood.cpp +++ b/src/modules/m_joinflood.cpp @@ -82,52 +82,40 @@ class joinfloodsettings /** Handles channel mode +j */ -class JoinFlood : public ModeHandler +class JoinFlood : public ParamMode > { public: - SimpleExtItem ext; - JoinFlood(Module* Creator) : ModeHandler(Creator, "joinflood", 'j', PARAM_SETONLY, MODETYPE_CHANNEL), - ext("joinflood", Creator) { } + JoinFlood(Module* Creator) + : ParamMode >(Creator, "joinflood", 'j') + { + } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + ModeAction OnSet(User* source, Channel* channel, std::string& parameter) { - if (adding) + std::string::size_type colon = parameter.find(':'); + if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { - std::string::size_type colon = parameter.find(':'); - if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) - { - source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str()); - return MODEACTION_DENY; - } - - /* Set up the flood parameters for this channel */ - unsigned int njoins = ConvToInt(parameter.substr(0, colon)); - unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); - if ((njoins<1) || (nsecs<1)) - { - source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str()); - return MODEACTION_DENY; - } - - joinfloodsettings jfs(nsecs, njoins); - joinfloodsettings* f = ext.get(channel); - if ((f) && (*f == jfs)) - // mode params match - return MODEACTION_DENY; - - ext.set(channel, jfs); - parameter = ConvToStr(njoins) + ":" + ConvToStr(nsecs); - return MODEACTION_ALLOW; + source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str()); + return MODEACTION_DENY; } - else - { - if (!channel->IsModeSet(this)) - return MODEACTION_DENY; - ext.unset(channel); - return MODEACTION_ALLOW; + /* Set up the flood parameters for this channel */ + unsigned int njoins = ConvToInt(parameter.substr(0, colon)); + unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); + if ((njoins<1) || (nsecs<1)) + { + source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str()); + return MODEACTION_DENY; } - return MODEACTION_DENY; + + ext.set(channel, new joinfloodsettings(nsecs, njoins)); + return MODEACTION_ALLOW; + } + + void SerializeParam(Channel* chan, const joinfloodsettings* jfs, std::string& out) + { + out.append(ConvToStr(jfs->joins)).push_back(':'); + out.append(ConvToStr(jfs->secs)); } }; diff --git a/src/modules/m_kicknorejoin.cpp b/src/modules/m_kicknorejoin.cpp index ce95085d8..fdb7b8f24 100644 --- a/src/modules/m_kicknorejoin.cpp +++ b/src/modules/m_kicknorejoin.cpp @@ -27,43 +27,42 @@ typedef std::map delaylist; +struct KickRejoinData +{ + delaylist kicked; + unsigned int delay; + + KickRejoinData(unsigned int Delay) : delay(Delay) { } +}; + /** Handles channel mode +J */ -class KickRejoin : public ModeHandler +class KickRejoin : public ParamMode > { static const unsigned int max = 60; public: - SimpleExtItem ext; KickRejoin(Module* Creator) - : ModeHandler(Creator, "kicknorejoin", 'J', PARAM_SETONLY, MODETYPE_CHANNEL) - , ext("norejoinusers", Creator) + : ParamMode >(Creator, "kicknorejoin", 'J') { } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) CXX11_OVERRIDE + ModeAction OnSet(User* source, Channel* channel, std::string& parameter) { - if (adding) - { - int v = ConvToInt(parameter); - if (v <= 0) - return MODEACTION_DENY; - if (parameter == channel->GetModeParameter(this)) - return MODEACTION_DENY; - - if ((IS_LOCAL(source) && ((unsigned int)v > max))) - v = max; + int v = ConvToInt(parameter); + if (v <= 0) + return MODEACTION_DENY; - parameter = ConvToStr(v); - } - else - { - if (!channel->IsModeSet(this)) - return MODEACTION_DENY; + if ((IS_LOCAL(source) && ((unsigned int)v > max))) + v = max; - ext.unset(channel); - } + ext.set(channel, new KickRejoinData(v)); return MODEACTION_ALLOW; } + + void SerializeParam(Channel* chan, const KickRejoinData* krd, std::string& out) + { + out.append(ConvToStr(krd->delay)); + } }; class ModuleKickNoRejoin : public Module @@ -80,18 +79,18 @@ public: { if (chan) { - delaylist* dl = kr.ext.get(chan); - if (dl) + KickRejoinData* data = kr.ext.get(chan); + if (data) { - for (delaylist::iterator iter = dl->begin(); iter != dl->end(); ) + delaylist& kicked = data->kicked; + for (delaylist::iterator iter = kicked.begin(); iter != kicked.end(); ) { if (iter->second > ServerInstance->Time()) { if (iter->first == user->uuid) { - std::string modeparam = chan->GetModeParameter(&kr); - user->WriteNumeric(ERR_DELAYREJOIN, "%s :You must wait %s seconds after being kicked to rejoin (+J)", - chan->name.c_str(), modeparam.c_str()); + 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; } ++iter; @@ -99,12 +98,9 @@ public: else { // Expired record, remove. - dl->erase(iter++); + kicked.erase(iter++); } } - - if (dl->empty()) - kr.ext.unset(chan); } } return MOD_RES_PASSTHRU; @@ -112,15 +108,13 @@ public: void OnUserKick(User* source, Membership* memb, const std::string &reason, CUList& excepts) CXX11_OVERRIDE { - if (memb->chan->IsModeSet(&kr) && (IS_LOCAL(memb->user)) && (source != memb->user)) + if ((!IS_LOCAL(memb->user)) || (source == memb->user)) + return; + + KickRejoinData* data = kr.ext.get(memb->chan); + if (data) { - delaylist* dl = kr.ext.get(memb->chan); - if (!dl) - { - dl = new delaylist; - kr.ext.set(memb->chan, dl); - } - (*dl)[memb->user->uuid] = ServerInstance->Time() + ConvToInt(memb->chan->GetModeParameter(&kr)); + data->kicked[memb->user->uuid] = ServerInstance->Time() + data->delay; } } diff --git a/src/modules/m_messageflood.cpp b/src/modules/m_messageflood.cpp index e2d752d18..92d67b9ab 100644 --- a/src/modules/m_messageflood.cpp +++ b/src/modules/m_messageflood.cpp @@ -64,52 +64,44 @@ class floodsettings /** Handles channel mode +f */ -class MsgFlood : public ModeHandler +class MsgFlood : public ParamMode > { public: - SimpleExtItem ext; - MsgFlood(Module* Creator) : ModeHandler(Creator, "flood", 'f', PARAM_SETONLY, MODETYPE_CHANNEL), - ext("messageflood", Creator) { } + MsgFlood(Module* Creator) + : ParamMode >(Creator, "flood", 'f') + { + } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + ModeAction OnSet(User* source, Channel* channel, std::string& parameter) { - if (adding) + std::string::size_type colon = parameter.find(':'); + if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { - std::string::size_type colon = parameter.find(':'); - if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) - { - source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str()); - return MODEACTION_DENY; - } - - /* Set up the flood parameters for this channel */ - bool ban = (parameter[0] == '*'); - unsigned int nlines = ConvToInt(parameter.substr(ban ? 1 : 0, ban ? colon-1 : colon)); - unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); - - if ((nlines<2) || (nsecs<1)) - { - source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str()); - return MODEACTION_DENY; - } + source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str()); + return MODEACTION_DENY; + } - floodsettings* f = ext.get(channel); - if ((f) && (nlines == f->lines) && (nsecs == f->secs) && (ban == f->ban)) - // mode params match - return MODEACTION_DENY; + /* Set up the flood parameters for this channel */ + bool ban = (parameter[0] == '*'); + unsigned int nlines = ConvToInt(parameter.substr(ban ? 1 : 0, ban ? colon-1 : colon)); + unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); - ext.set(channel, new floodsettings(ban, nsecs, nlines)); - parameter = std::string(ban ? "*" : "") + ConvToStr(nlines) + ":" + ConvToStr(nsecs); - return MODEACTION_ALLOW; - } - else + if ((nlines<2) || (nsecs<1)) { - if (!channel->IsModeSet(this)) - return MODEACTION_DENY; - - ext.unset(channel); - return MODEACTION_ALLOW; + source->WriteNumeric(608, "%s :Invalid flood parameter", channel->name.c_str()); + return MODEACTION_DENY; } + + ext.set(channel, new floodsettings(ban, nsecs, nlines)); + return MODEACTION_ALLOW; + } + + void SerializeParam(Channel* chan, const floodsettings* fs, std::string& out) + { + if (fs->ban) + out.push_back('*'); + out.append(ConvToStr(fs->lines)).push_back(':'); + out.append(ConvToStr(fs->secs)); } }; diff --git a/src/modules/m_nickflood.cpp b/src/modules/m_nickflood.cpp index 93fbbfaaa..f74a18422 100644 --- a/src/modules/m_nickflood.cpp +++ b/src/modules/m_nickflood.cpp @@ -78,51 +78,41 @@ class nickfloodsettings /** Handles channel mode +F */ -class NickFlood : public ModeHandler +class NickFlood : public ParamMode > { public: - SimpleExtItem ext; - NickFlood(Module* Creator) : ModeHandler(Creator, "nickflood", 'F', PARAM_SETONLY, MODETYPE_CHANNEL), - ext("nickflood", Creator) { } + NickFlood(Module* Creator) + : ParamMode >(Creator, "nickflood", 'F') + { + } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + ModeAction OnSet(User* source, Channel* channel, std::string& parameter) { - if (adding) + std::string::size_type colon = parameter.find(':'); + if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) { - std::string::size_type colon = parameter.find(':'); - if ((colon == std::string::npos) || (parameter.find('-') != std::string::npos)) - { - source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str()); - return MODEACTION_DENY; - } - - /* Set up the flood parameters for this channel */ - unsigned int nnicks = ConvToInt(parameter.substr(0, colon)); - unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); - - if ((nnicks<1) || (nsecs<1)) - { - source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str()); - return MODEACTION_DENY; - } + source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str()); + return MODEACTION_DENY; + } - nickfloodsettings* f = ext.get(channel); - if ((f) && (nnicks == f->nicks) && (nsecs == f->secs)) - // mode params match - return MODEACTION_DENY; + /* Set up the flood parameters for this channel */ + unsigned int nnicks = ConvToInt(parameter.substr(0, colon)); + unsigned int nsecs = ConvToInt(parameter.substr(colon+1)); - ext.set(channel, new nickfloodsettings(nsecs, nnicks)); - parameter = ConvToStr(nnicks) + ":" + ConvToStr(nsecs); - return MODEACTION_ALLOW; - } - else + if ((nnicks<1) || (nsecs<1)) { - if (!channel->IsModeSet(this)) - return MODEACTION_DENY; - - ext.unset(channel); - return MODEACTION_ALLOW; + source->WriteNumeric(608, "%s :Invalid flood parameter",channel->name.c_str()); + return MODEACTION_DENY; } + + ext.set(channel, new nickfloodsettings(nsecs, nnicks)); + return MODEACTION_ALLOW; + } + + void SerializeParam(Channel* chan, const nickfloodsettings* nfs, std::string& out) + { + out.append(ConvToStr(nfs->nicks)).push_back(':'); + out.append(ConvToStr(nfs->secs)); } }; diff --git a/src/modules/m_redirect.cpp b/src/modules/m_redirect.cpp index 5fc97d3c5..e822676bf 100644 --- a/src/modules/m_redirect.cpp +++ b/src/modules/m_redirect.cpp @@ -26,57 +26,49 @@ /** Handle channel mode +L */ -class Redirect : public ModeHandler +class Redirect : public ParamMode { public: - Redirect(Module* Creator) : ModeHandler(Creator, "redirect", 'L', PARAM_SETONLY, MODETYPE_CHANNEL) { } + Redirect(Module* Creator) + : ParamMode(Creator, "redirect", 'L') { } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) + ModeAction OnSet(User* source, Channel* channel, std::string& parameter) { - if (adding) + if (IS_LOCAL(source)) { - if (IS_LOCAL(source)) + if (!ServerInstance->IsChannel(parameter)) { - if (!ServerInstance->IsChannel(parameter)) - { - source->WriteNumeric(ERR_NOSUCHCHANNEL, "%s :Invalid channel name", parameter.c_str()); - return MODEACTION_DENY; - } + source->WriteNumeric(ERR_NOSUCHCHANNEL, "%s :Invalid channel name", parameter.c_str()); + return MODEACTION_DENY; } + } - if (IS_LOCAL(source) && !source->IsOper()) + if (IS_LOCAL(source) && !source->IsOper()) + { + Channel* c = ServerInstance->FindChan(parameter); + if (!c) { - Channel* c = ServerInstance->FindChan(parameter); - if (!c) - { - source->WriteNumeric(690, ":Target channel %s must exist to be set as a redirect.",parameter.c_str()); - return MODEACTION_DENY; - } - else if (c->GetPrefixValue(source) < OP_VALUE) - { - source->WriteNumeric(690, ":You must be opped on %s to set it as a redirect.",parameter.c_str()); - return MODEACTION_DENY; - } - } - - if (channel->GetModeParameter(this) == parameter) + source->WriteNumeric(690, ":Target channel %s must exist to be set as a redirect.",parameter.c_str()); return MODEACTION_DENY; - /* - * We used to do some checking for circular +L here, but there is no real need for this any more especially as we - * now catch +L looping in PreJoin. Remove it, since O(n) logic makes me sad, and we catch it anyway. :) -- w00t - */ - return MODEACTION_ALLOW; - } - else - { - if (channel->IsModeSet(this)) + } + else if (c->GetPrefixValue(source) < OP_VALUE) { - return MODEACTION_ALLOW; + source->WriteNumeric(690, ":You must be opped on %s to set it as a redirect.",parameter.c_str()); + return MODEACTION_DENY; } } - return MODEACTION_DENY; + /* + * We used to do some checking for circular +L here, but there is no real need for this any more especially as we + * now catch +L looping in PreJoin. Remove it, since O(n) logic makes me sad, and we catch it anyway. :) -- w00t + */ + ext.set(channel, parameter); + return MODEACTION_ALLOW; + } + void SerializeParam(Channel* chan, const std::string* str, std::string& out) + { + out += *str; } }; @@ -121,7 +113,7 @@ class ModuleRedirect : public Module { if (chan->GetUserCounter() >= ConvToInt(chan->GetModeParameter(limitmode))) { - std::string channel = chan->GetModeParameter(&re); + const std::string& channel = *re.ext.get(chan); /* sometimes broken ulines can make circular or chained +L, avoid this */ Channel* destchan = ServerInstance->FindChan(channel); diff --git a/src/modules/m_repeat.cpp b/src/modules/m_repeat.cpp index d91fe7e8a..d8fccbffc 100644 --- a/src/modules/m_repeat.cpp +++ b/src/modules/m_repeat.cpp @@ -19,7 +19,45 @@ #include "inspircd.h" -class RepeatMode : public ModeHandler +class ChannelSettings +{ + public: + enum RepeatAction + { + ACT_KICK, + ACT_BLOCK, + ACT_BAN + }; + + RepeatAction Action; + unsigned int Backlog; + unsigned int Lines; + unsigned int Diff; + unsigned int Seconds; + + void serialize(std::string& out) const + { + if (Action == ACT_BAN) + out.push_back('*'); + else if (Action == ACT_BLOCK) + out.push_back('~'); + + out.append(ConvToStr(Lines)).push_back(':'); + out.append(ConvToStr(Seconds)); + if (Diff) + { + out.push_back(':'); + out.append(ConvToStr(Diff)); + if (Backlog) + { + out.push_back(':'); + out.append(ConvToStr(Backlog)); + } + } + } +}; + +class RepeatMode : public ParamMode > { private: struct RepeatItem @@ -80,64 +118,24 @@ class RepeatMode : public ModeHandler } public: - enum RepeatAction - { - ACT_KICK, - ACT_BLOCK, - ACT_BAN - }; - - class ChannelSettings - { - public: - RepeatAction Action; - unsigned int Backlog; - unsigned int Lines; - unsigned int Diff; - unsigned int Seconds; - - std::string serialize() - { - std::string ret = ((Action == ACT_BAN) ? "*" : (Action == ACT_BLOCK ? "~" : "")) + ConvToStr(Lines) + ":" + ConvToStr(Seconds); - if (Diff) - { - ret += ":" + ConvToStr(Diff); - if (Backlog) - ret += ":" + ConvToStr(Backlog); - } - return ret; - } - }; - SimpleExtItem MemberInfoExt; - SimpleExtItem ChanSet; RepeatMode(Module* Creator) - : ModeHandler(Creator, "repeat", 'E', PARAM_SETONLY, MODETYPE_CHANNEL) + : ParamMode >(Creator, "repeat", 'E') , MemberInfoExt("repeat_memb", Creator) - , ChanSet("repeat", Creator) { } - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& parameter, bool adding) + void OnUnset(User* source, Channel* chan) { - if (!adding) - { - if (!channel->IsModeSet(this)) - return MODEACTION_DENY; - - // Unset the per-membership extension when the mode is removed - const UserMembList* users = channel->GetUsers(); - for (UserMembCIter i = users->begin(); i != users->end(); ++i) - MemberInfoExt.unset(i->second); - - ChanSet.unset(channel); - return MODEACTION_ALLOW; - } - - if (channel->GetModeParameter(this) == parameter) - return MODEACTION_DENY; + // Unset the per-membership extension when the mode is removed + const UserMembList* users = chan->GetUsers(); + for (UserMembCIter i = users->begin(); i != users->end(); ++i) + MemberInfoExt.unset(i->second); + } + ModeAction OnSet(User* source, Channel* channel, std::string& parameter) + { ChannelSettings settings; if (!ParseSettings(source, parameter, settings)) { @@ -155,7 +153,7 @@ class RepeatMode : public ModeHandler if ((localsource) && (!ValidateSettings(localsource, settings))) return MODEACTION_DENY; - ChanSet.set(channel, settings); + ext.set(channel, settings); return MODEACTION_ALLOW; } @@ -197,7 +195,7 @@ class RepeatMode : public ModeHandler { if (++matches >= rs->Lines) { - if (rs->Action != ACT_BLOCK) + if (rs->Action != ChannelSettings::ACT_BLOCK) rp->Counter = 0; return true; } @@ -251,6 +249,11 @@ class RepeatMode : public ModeHandler return ConvToStr(ms.MaxLines) + ":" + ConvToStr(ms.MaxSecs) + ":" + ConvToStr(ms.MaxDiff) + ":" + ConvToStr(ms.MaxBacklog); } + void SerializeParam(Channel* chan, const ChannelSettings* chset, std::string& out) + { + chset->serialize(out); + } + private: bool ParseSettings(User* source, std::string& parameter, ChannelSettings& settings) { @@ -262,11 +265,11 @@ class RepeatMode : public ModeHandler if ((item[0] == '*') || (item[0] == '~')) { - settings.Action = ((item[0] == '*') ? ACT_BAN : ACT_BLOCK); + settings.Action = ((item[0] == '*') ? ChannelSettings::ACT_BAN : ChannelSettings::ACT_BLOCK); item.erase(item.begin()); } else - settings.Action = ACT_KICK; + settings.Action = ChannelSettings::ACT_KICK; if ((settings.Lines = ConvToInt(item)) == 0) return false; @@ -295,7 +298,6 @@ class RepeatMode : public ModeHandler } } - parameter = settings.serialize(); return true; } @@ -352,26 +354,27 @@ class RepeatModule : public Module if (target_type != TYPE_CHANNEL || !IS_LOCAL(user)) return MOD_RES_PASSTHRU; - Membership* memb = ((Channel*)dest)->GetUser(user); - if (!memb || !memb->chan->IsModeSet(&rm)) + Channel* chan = reinterpret_cast(dest); + ChannelSettings* settings = rm.ext.get(chan); + if (!settings) return MOD_RES_PASSTHRU; - if (ServerInstance->OnCheckExemption(user, memb->chan, "repeat") == MOD_RES_ALLOW) + Membership* memb = chan->GetUser(user); + if (!memb) return MOD_RES_PASSTHRU; - RepeatMode::ChannelSettings* settings = rm.ChanSet.get(memb->chan); - if (!settings) + if (ServerInstance->OnCheckExemption(user, chan, "repeat") == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; if (rm.MatchLine(memb, settings, text)) { - if (settings->Action == RepeatMode::ACT_BLOCK) + if (settings->Action == ChannelSettings::ACT_BLOCK) { user->WriteNotice("*** This line is too similiar to one of your last lines."); return MOD_RES_DENY; } - if (settings->Action == RepeatMode::ACT_BAN) + if (settings->Action == ChannelSettings::ACT_BAN) { std::vector parameters; parameters.push_back(memb->chan->name);