]> git.netwichtig.de Git - user/henk/code/inspircd.git/commitdiff
Add ParamModeBase and ParamMode, change all parameter modes to inherit from ParamMode
authorAttila Molnar <attilamolnar@hush.com>
Sat, 15 Feb 2014 13:38:24 +0000 (14:38 +0100)
committerAttila Molnar <attilamolnar@hush.com>
Sat, 15 Feb 2014 13:38:24 +0000 (14:38 +0100)
- 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

18 files changed:
include/builtinmodes.h
include/channels.h
include/extensible.h
include/mode.h
include/parammode.h [new file with mode: 0644]
include/typedefs.h
src/channels.cpp
src/mode.cpp
src/modes/cmode_k.cpp
src/modes/cmode_l.cpp
src/modules/m_chanhistory.cpp
src/modules/m_delaymsg.cpp
src/modules/m_joinflood.cpp
src/modules/m_kicknorejoin.cpp
src/modules/m_messageflood.cpp
src/modules/m_nickflood.cpp
src/modules/m_redirect.cpp
src/modules/m_repeat.cpp

index ce73a78171c374cbf3c4f44ee72f2ff7deb63200..6aab727cca448390852774ff7085a593bdf8a43d 100644 (file)
@@ -47,21 +47,24 @@ class ModeChannelInviteOnly : public SimpleChannelModeHandler
 
 /** Channel mode +k
  */
-class ModeChannelKey : public ModeHandler
+class ModeChannelKey : public ParamMode<ModeChannelKey, LocalStringExt>
 {
  public:
        ModeChannelKey();
        ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, 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<ModeChannelLimit, LocalIntExt>
 {
  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
index 9b018b23e9b58fb708aeea6245d3d5262d8648f3..ba2018e97a456065d6eb16203d0aaeeab3c8622e 100644 (file)
@@ -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<Channel>
         */
        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<Channel>
         */
        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<Channel>
          */
        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)
index a0544bba1a8fa3156be969e92546e128bb9860b5..0e1afdbdf5ff618f6983c414b5ecf6c3e07802bc 100644 (file)
@@ -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);
 };
 
index dd5334c66e640ce5e7d56f96088bb4b0a638457c..3193af65f1d8832c913aaf291b65debb03d2d758 100644 (file)
@@ -409,16 +409,6 @@ class CoreExport SimpleChannelModeHandler : public ModeHandler
        virtual ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, 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 &parameter, 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 (file)
index 0000000..b000526
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ *   Copyright (C) 2014 Attila Molnar <attilamolnar@hush.com>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#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 <typename T, typename ExtItemT>
+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<T*>(this);
+               mh->OnUnset(source, chan);
+               ext.unset(chan);
+       }
+
+       void GetParameter(Channel* chan, std::string& out) CXX11_OVERRIDE
+       {
+               T* mh = static_cast<T*>(this);
+               mh->SerializeParam(chan, ext.get(chan), out);
+       }
+};
index 77a45ce4e4f1c2b7ffd01099051af716b28bf8b4..336084c556657aaf4715fe9400325cf91953f432 100644 (file)
@@ -77,10 +77,6 @@ typedef UserChanList::iterator UCListIter;
  */
 typedef std::vector<Membership*> IncludeChanList;
 
-/** A list of custom modes parameters on a channel
- */
-typedef std::map<char,std::string> CustomModeList;
-
 /** A cached text file stored with its contents as lines
  */
 typedef std::vector<std::string> file_cache;
index a8f8db43ce042d5e5cf80d7960b5c1048227cee2..448764e1c46a3c272d6a908a0e321ecb261dc073 100644 (file)
@@ -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 += " <key>";
                        }
                        else
                        {
-                               const std::string param = this->GetModeParameter(mh);
-                               if (!param.empty())
-                               {
-                                       sparam += ' ';
-                                       sparam += param;
-                               }
+                               sparam += ' ';
+                               pm->GetParameter(this, sparam);
                        }
                }
        }
index ad46e602de1e39390dd3304b785be9266e289c8b..eeab0de3a1e3dd43d5af05ba37d0fe96d82d45cc 100644 (file)
@@ -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 &parameter, 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 &parameter, 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)
        {
index e56b26ff132b4975e8355eb38a46fef303f30e80..e14f93a770026cd4ab3f8617b8eb692e99886e4c 100644 (file)
 #include "users.h"
 #include "builtinmodes.h"
 
-ModeChannelKey::ModeChannelKey() : ModeHandler(NULL, "key", 'k', PARAM_ALWAYS, MODETYPE_CHANNEL)
+ModeChannelKey::ModeChannelKey()
+       : ParamMode<ModeChannelKey, LocalStringExt>(NULL, "key", 'k', PARAM_ALWAYS)
 {
 }
 
 ModeAction ModeChannelKey::OnModeChange(User* source, User*, Channel* channel, std::string &parameter, 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;
+}
index f057a75e6f000b12570569c50396a57e0f73f3b9..128854b50e94d19931736d9025ddfdfbbcb3d3dc 100644 (file)
@@ -25,7 +25,8 @@
 #include "users.h"
 #include "builtinmodes.h"
 
-ModeChannelLimit::ModeChannelLimit() : ParamChannelModeHandler(NULL, "limit", 'l')
+ModeChannelLimit::ModeChannelLimit()
+       : ParamMode<ModeChannelLimit, LocalIntExt>(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 &parameter)
+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);
 }
index 24c6237b3812b6d7e9a18426d2563381ef6c4944..f6e7ea40e6071a100203c576e880a744594e1f39 100644 (file)
@@ -30,10 +30,13 @@ struct HistoryList
 {
        std::deque<HistoryItem> 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<HistoryMode, SimpleExtItem<HistoryList> >
 {
        bool IsValidDuration(const std::string& duration)
        {
@@ -50,57 +53,53 @@ class HistoryMode : public ModeHandler
        }
 
  public:
-       SimpleExtItem<HistoryList> ext;
        unsigned int maxlines;
-       HistoryMode(Module* Creator) : ModeHandler(Creator, "history", 'H', PARAM_SETONLY, MODETYPE_CHANNEL),
-               ext("history", Creator) { }
+       HistoryMode(Module* Creator)
+               : ParamMode<HistoryMode, SimpleExtItem<HistoryList> >(Creator, "history", 'H')
+       {
+       }
 
-       ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, 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
index 031680e189cacb5d3ed6b673f99ba9b4bd0963ad..1730663c5b75fc478c2dc8cf0e9033f3f52601f4 100644 (file)
 
 #include "inspircd.h"
 
-class DelayMsgMode : public ModeHandler
+class DelayMsgMode : public ParamMode<DelayMsgMode, LocalIntExt>
 {
  public:
        LocalIntExt jointime;
-       DelayMsgMode(Module* Parent) : ModeHandler(Parent, "delaymsg", 'd', PARAM_SETONLY, MODETYPE_CHANNEL)
+       DelayMsgMode(Module* Parent)
+               : ParamMode<DelayMsgMode, LocalIntExt>(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 &parameter, 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 &parameter, 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 <int>, to deny messages to a channel until <int> 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;
                }
        }
index edce2b22cb6310236f5fcddb1911a0113f00c761..52802f168884fd2a1783b2b41b0cae08b984b001 100644 (file)
@@ -82,52 +82,40 @@ class joinfloodsettings
 
 /** Handles channel mode +j
  */
-class JoinFlood : public ModeHandler
+class JoinFlood : public ParamMode<JoinFlood, SimpleExtItem<joinfloodsettings> >
 {
  public:
-       SimpleExtItem<joinfloodsettings> ext;
-       JoinFlood(Module* Creator) : ModeHandler(Creator, "joinflood", 'j', PARAM_SETONLY, MODETYPE_CHANNEL),
-               ext("joinflood", Creator) { }
+       JoinFlood(Module* Creator)
+               : ParamMode<JoinFlood, SimpleExtItem<joinfloodsettings> >(Creator, "joinflood", 'j')
+       {
+       }
 
-       ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, 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));
        }
 };
 
index ce95085d85c234a55b19e2ed5750b4a047f16ef4..fdb7b8f2455fdcb8f8b5e913edaba0574f314705 100644 (file)
 
 typedef std::map<std::string, time_t> 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<KickRejoin, SimpleExtItem<KickRejoinData> >
 {
        static const unsigned int max = 60;
  public:
-       SimpleExtItem<delaylist> ext;
        KickRejoin(Module* Creator)
-               : ModeHandler(Creator, "kicknorejoin", 'J', PARAM_SETONLY, MODETYPE_CHANNEL)
-               , ext("norejoinusers", Creator)
+               : ParamMode<KickRejoin, SimpleExtItem<KickRejoinData> >(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;
                }
        }
 
index e2d752d183565f4a17bfe7e67d811549a1d3ee54..92d67b9abc98cc482f297a18daf8e78373607413 100644 (file)
@@ -64,52 +64,44 @@ class floodsettings
 
 /** Handles channel mode +f
  */
-class MsgFlood : public ModeHandler
+class MsgFlood : public ParamMode<MsgFlood, SimpleExtItem<floodsettings> >
 {
  public:
-       SimpleExtItem<floodsettings> ext;
-       MsgFlood(Module* Creator) : ModeHandler(Creator, "flood", 'f', PARAM_SETONLY, MODETYPE_CHANNEL),
-               ext("messageflood", Creator) { }
+       MsgFlood(Module* Creator)
+               : ParamMode<MsgFlood, SimpleExtItem<floodsettings> >(Creator, "flood", 'f')
+       {
+       }
 
-       ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, 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));
        }
 };
 
index 93fbbfaaa7c9838471823675f4b1a33756783225..f74a1842206f9772817292e7554aaf4ca26185f2 100644 (file)
@@ -78,51 +78,41 @@ class nickfloodsettings
 
 /** Handles channel mode +F
  */
-class NickFlood : public ModeHandler
+class NickFlood : public ParamMode<NickFlood, SimpleExtItem<nickfloodsettings> >
 {
  public:
-       SimpleExtItem<nickfloodsettings> ext;
-       NickFlood(Module* Creator) : ModeHandler(Creator, "nickflood", 'F', PARAM_SETONLY, MODETYPE_CHANNEL),
-               ext("nickflood", Creator) { }
+       NickFlood(Module* Creator)
+               : ParamMode<NickFlood, SimpleExtItem<nickfloodsettings> >(Creator, "nickflood", 'F')
+       {
+       }
 
-       ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, 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));
        }
 };
 
index 5fc97d3c5bd577a5b1dd439555f6e57afb542715..e822676bf7357c102233cbcd69f5768110a4daf7 100644 (file)
 
 /** Handle channel mode +L
  */
-class Redirect : public ModeHandler
+class Redirect : public ParamMode<Redirect, LocalStringExt>
 {
  public:
-       Redirect(Module* Creator) : ModeHandler(Creator, "redirect", 'L', PARAM_SETONLY, MODETYPE_CHANNEL) { }
+       Redirect(Module* Creator)
+               : ParamMode<Redirect, LocalStringExt>(Creator, "redirect", 'L') { }
 
-       ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string &parameter, 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);
index d91fe7e8a5f1a868b5f84614292071762124d11a..d8fccbffc05bbb8d82a912c1fa2440c80075ca0c 100644 (file)
 
 #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<RepeatMode, SimpleExtItem<ChannelSettings> >
 {
  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<MemberInfo> MemberInfoExt;
-       SimpleExtItem<ChannelSettings> ChanSet;
 
        RepeatMode(Module* Creator)
-               : ModeHandler(Creator, "repeat", 'E', PARAM_SETONLY, MODETYPE_CHANNEL)
+               : ParamMode<RepeatMode, SimpleExtItem<ChannelSettings> >(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<Channel*>(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<std::string> parameters;
                                parameters.push_back(memb->chan->name);