]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/mode.cpp
Extract RFC modes from the core to core_channel and core_user.
[user/henk/code/inspircd.git] / src / mode.cpp
index 6038f6f5b0a04771516ae3f90f922fd7c37d5fdd..e2129b55a46ce03a9466d169b2bed3886c5d082b 100644 (file)
 
 
 #include "inspircd.h"
-#include "builtinmodes.h"
 
 ModeHandler::ModeHandler(Module* Creator, const std::string& Name, char modeletter, ParamSpec Params, ModeType type, Class mclass)
-       : ServiceProvider(Creator, Name, SERVICE_MODE), modeid(ModeParser::MODEID_MAX),
-       parameters_taken(Params), mode(modeletter), oper(false),
-       list(false), m_type(type), type_id(mclass), levelrequired(HALFOP_VALUE)
+       : ServiceProvider(Creator, Name, SERVICE_MODE)
+       , modeid(ModeParser::MODEID_MAX)
+       , parameters_taken(Params)
+       , mode(modeletter)
+       , oper(false)
+       , list(false)
+       , m_type(type)
+       , type_id(mclass)
+       , ranktoset(HALFOP_VALUE)
+       , ranktounset(HALFOP_VALUE)
 {
 }
 
@@ -44,21 +50,21 @@ ModeHandler::~ModeHandler()
 {
 }
 
-int ModeHandler::GetNumParams(bool adding)
+bool ModeHandler::NeedsParam(bool adding) const
 {
        switch (parameters_taken)
        {
                case PARAM_ALWAYS:
-                       return 1;
+                       return true;
                case PARAM_SETONLY:
-                       return adding ? 1 : 0;
+                       return adding;
                case PARAM_NONE:
                        break;
        }
-       return 0;
+       return false;
 }
 
-std::string ModeHandler::GetUserParameter(User* user)
+std::string ModeHandler::GetUserParameter(const User* user) const
 {
        return "";
 }
@@ -144,11 +150,6 @@ ModeWatcher::~ModeWatcher()
        ServerInstance->Modes->DelModeWatcher(this);
 }
 
-ModeType ModeWatcher::GetModeType()
-{
-       return m_type;
-}
-
 bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool)
 {
        return true;
@@ -160,11 +161,20 @@ void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool)
 
 PrefixMode::PrefixMode(Module* Creator, const std::string& Name, char ModeLetter, unsigned int Rank, char PrefixChar)
        : ModeHandler(Creator, Name, ModeLetter, PARAM_ALWAYS, MODETYPE_CHANNEL, MC_PREFIX)
-       , prefix(PrefixChar), prefixrank(Rank)
+       , prefix(PrefixChar)
+       , prefixrank(Rank)
+       , selfremove(true)
 {
        list = true;
 }
 
+ModResult PrefixMode::AccessCheck(User* src, Channel*, std::string& value, bool adding)
+{
+       if (!adding && src->nick == value && selfremove)
+               return MOD_RES_ALLOW;
+       return MOD_RES_PASSTHRU;
+}
+
 ModeAction PrefixMode::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding)
 {
        User* target;
@@ -175,7 +185,7 @@ ModeAction PrefixMode::OnModeChange(User* source, User*, Channel* chan, std::str
 
        if (!target)
        {
-               source->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", parameter.c_str());
+               source->WriteNumeric(Numerics::NoSuchNick(parameter));
                return MODEACTION_DENY;
        }
 
@@ -187,6 +197,14 @@ ModeAction PrefixMode::OnModeChange(User* source, User*, Channel* chan, std::str
        return (memb->SetPrefix(this, adding) ? MODEACTION_ALLOW : MODEACTION_DENY);
 }
 
+void PrefixMode::Update(unsigned int rank, unsigned int setrank, unsigned int unsetrank, bool selfrm)
+{
+       prefixrank = rank;
+       ranktoset = setrank;
+       ranktounset = unsetrank;
+       selfremove = selfrm;
+}
+
 ModeAction ParamModeBase::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding)
 {
        if (adding)
@@ -219,7 +237,7 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode
 
        ModeHandler* mh = mcitem.mh;
        bool adding = mcitem.adding;
-       int pcnt = mh->GetNumParams(adding);
+       const bool needs_param = mh->NeedsParam(adding);
 
        std::string& parameter = mcitem.param;
        // crop mode parameter size to 250 characters
@@ -242,7 +260,7 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode
                        return MODEACTION_DENY;
                if (MOD_RESULT == MOD_RES_PASSTHRU)
                {
-                       unsigned int neededrank = mh->GetLevelRequired();
+                       unsigned int neededrank = mh->GetLevelRequired(adding);
                        /* Compare our rank on the channel against the rank of the required prefix,
                         * allow if >= ours. Because mIRC and xchat throw a tizz if the modes shown
                         * in NAMES(X) are not in rank order, we know the most powerful mode is listed
@@ -251,11 +269,12 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode
                        unsigned int ourrank = chan->GetPrefixValue(user);
                        if (ourrank < neededrank)
                        {
-                               PrefixMode* neededmh = NULL;
-                               for(char c='A'; c <= 'z'; c++)
+                               const PrefixMode* neededmh = NULL;
+                               const PrefixModeList& prefixmodes = GetPrefixModes();
+                               for (PrefixModeList::const_iterator i = prefixmodes.begin(); i != prefixmodes.end(); ++i)
                                {
-                                       PrefixMode* privmh = FindPrefixMode(c);
-                                       if (privmh && privmh->GetPrefixRank() >= neededrank)
+                                       const PrefixMode* const privmh = *i;
+                                       if (privmh->GetPrefixRank() >= neededrank)
                                        {
                                                // this mode is sufficient to allow this action
                                                if (!neededmh || privmh->GetPrefixRank() < neededmh->GetPrefixRank())
@@ -263,11 +282,10 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode
                                        }
                                }
                                if (neededmh)
-                                       user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You must have channel %s access or above to %sset channel mode %c",
-                                               chan->name.c_str(), neededmh->name.c_str(), adding ? "" : "un", modechar);
+                                       user->WriteNumeric(ERR_CHANOPRIVSNEEDED, chan->name, InspIRCd::Format("You must have channel %s access or above to %sset channel mode %c",
+                                               neededmh->name.c_str(), adding ? "" : "un", modechar));
                                else
-                                       user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You cannot %sset channel mode %c",
-                                               chan->name.c_str(), adding ? "" : "un", modechar);
+                                       user->WriteNumeric(ERR_CHANOPRIVSNEEDED, chan->name, InspIRCd::Format("You cannot %sset channel mode %c", (adding ? "" : "un"), modechar));
                                return MODEACTION_DENY;
                        }
                }
@@ -284,34 +302,34 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode
                                return MODEACTION_DENY;
 
                        // A module whacked the parameter completely, and there was one. Abort.
-                       if (pcnt && parameter.empty())
+                       if ((needs_param) && (parameter.empty()))
                                return MODEACTION_DENY;
                }
        }
 
        if (IS_LOCAL(user) && !user->IsOper())
        {
-               char* disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
-               if (disabled[modechar - 'A'])
+               const std::bitset<64>& disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
+               if (disabled.test(modechar - 'A'))
                {
-                       user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - %s mode %c has been locked by the administrator",
-                               type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
+                       user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - %s mode %c has been locked by the administrator",
+                               type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
                        return MODEACTION_DENY;
                }
        }
 
-       if (adding && IS_LOCAL(user) && mh->NeedsOper() && !user->HasModePermission(modechar, type))
+       if ((adding) && (IS_LOCAL(user)) && (mh->NeedsOper()) && (!user->HasModePermission(mh)))
        {
                /* It's an oper only mode, and they don't have access to it. */
                if (user->IsOper())
                {
-                       user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - Oper type %s does not have access to set %s mode %c",
-                                       user->oper->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
+                       user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to set %s mode %c",
+                                       user->oper->name.c_str(), type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
                }
                else
                {
-                       user->WriteNumeric(ERR_NOPRIVILEGES, ":Permission Denied - Only operators may set %s mode %c",
-                                       type == MODETYPE_CHANNEL ? "channel" : "user", modechar);
+                       user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Only operators may set %s mode %c",
+                                       type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
                }
                return MODEACTION_DENY;
        }
@@ -319,7 +337,7 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode
        /* Call the handler for the mode */
        ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding);
 
-       if (pcnt && parameter.empty())
+       if ((needs_param) && (parameter.empty()))
                return MODEACTION_DENY;
 
        if (ma != MODEACTION_ALLOW)
@@ -359,12 +377,12 @@ void ModeParser::ModeParamsToChangeList(User* user, ModeType type, const std::ve
                if (!mh)
                {
                        /* No mode handler? Unknown mode character then. */
-                       user->WriteNumeric(type == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK, "%c :is unknown mode char to me", modechar);
+                       user->WriteNumeric(type == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK, modechar, "is unknown mode char to me");
                        continue;
                }
 
                std::string parameter;
-               if (mh->GetNumParams(adding) && param_at < endindex)
+               if ((mh->NeedsParam(adding)) && (param_at < endindex))
                        parameter = parameters[param_at++];
 
                changelist.push(mh, adding, parameter);
@@ -433,7 +451,7 @@ unsigned int ModeParser::ProcessSingle(User* user, Channel* targetchannel, User*
 
                // If the mode is supposed to have a parameter then we first take a look at item.param
                // and, if we were asked to, also handle mode merges now
-               if (mh->GetNumParams(item.adding))
+               if (mh->NeedsParam(item.adding))
                {
                        // Skip the mode if the parameter does not pass basic validation
                        if (!IsModeParamValid(user, targetchannel, targetuser, item))
@@ -575,11 +593,7 @@ ModeHandler::Id ModeParser::AllocateModeId(ModeType mt)
 
 void ModeParser::AddMode(ModeHandler* mh)
 {
-       /* Yes, i know, this might let people declare modes like '_' or '^'.
-        * If they do that, thats their problem, and if i ever EVER see an
-        * official InspIRCd developer do that, i'll beat them with a paddle!
-        */
-       if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
+       if (!ModeParser::IsModeChar(mh->GetModeChar()))
                throw ModuleException("Invalid letter for mode " + mh->name);
 
        /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
@@ -629,7 +643,7 @@ void ModeParser::AddMode(ModeHandler* mh)
 
 bool ModeParser::DelMode(ModeHandler* mh)
 {
-       if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z'))
+       if (!ModeParser::IsModeChar(mh->GetModeChar()))
                return false;
 
        ModeHandlerMap& mhmap = modehandlersbyname[mh->GetModeType()];
@@ -699,7 +713,7 @@ ModeHandler* ModeParser::FindMode(const std::string& modename, ModeType mt)
 
 ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt)
 {
-       if ((modeletter < 'A') || (modeletter > 'z'))
+       if (!ModeParser::IsModeChar(modeletter))
                return NULL;
 
        return modehandlers[mt][modeletter-65];
@@ -720,7 +734,7 @@ std::string ModeParser::CreateModeList(ModeType mt, bool needparam)
        for (unsigned char mode = 'A'; mode <= 'z'; mode++)
        {
                ModeHandler* mh = modehandlers[mt][mode-65];
-               if ((mh) && ((!needparam) || (mh->GetNumParams(true))))
+               if ((mh) && ((!needparam) || (mh->NeedsParam(true))))
                        modestr.push_back(mode);
        }
 
@@ -729,7 +743,9 @@ std::string ModeParser::CreateModeList(ModeType mt, bool needparam)
 
 void ModeParser::RecreateModeListFor004Numeric()
 {
-       Cached004ModeList = CreateModeList(MODETYPE_USER) + " " + CreateModeList(MODETYPE_CHANNEL) + " " + CreateModeList(MODETYPE_CHANNEL, true);
+       Cached004ModeList[0] = CreateModeList(MODETYPE_USER);
+       Cached004ModeList[1] = CreateModeList(MODETYPE_CHANNEL);
+       Cached004ModeList[2] = CreateModeList(MODETYPE_CHANNEL, true);
 }
 
 PrefixMode* ModeParser::FindPrefix(unsigned const char pfxletter)
@@ -757,7 +773,7 @@ std::string ModeParser::GiveModeList(ModeType mt)
                 /* One parameter when adding */
                if (mh)
                {
-                       if (mh->GetNumParams(true))
+                       if (mh->NeedsParam(true))
                        {
                                PrefixMode* pm = mh->IsPrefixMode();
                                if ((mh->IsListMode()) && ((!pm) || (pm->GetPrefix() == 0)))
@@ -767,7 +783,7 @@ std::string ModeParser::GiveModeList(ModeType mt)
                                else
                                {
                                        /* ... and one parameter when removing */
-                                       if (mh->GetNumParams(false))
+                                       if (mh->NeedsParam(false))
                                        {
                                                /* But not a list mode */
                                                if (!pm)
@@ -792,24 +808,33 @@ std::string ModeParser::GiveModeList(ModeType mt)
        return type1 + "," + type2 + "," + type3 + "," + type4;
 }
 
+struct PrefixModeSorter
+{
+       bool operator()(PrefixMode* lhs, PrefixMode* rhs)
+       {
+               return lhs->GetPrefixRank() < rhs->GetPrefixRank();
+       }
+};
+
 std::string ModeParser::BuildPrefixes(bool lettersAndModes)
 {
        std::string mletters;
        std::string mprefixes;
-       insp::flat_map<int, std::pair<char, char> > prefixes;
+       std::vector<PrefixMode*> prefixes;
 
        const PrefixModeList& list = GetPrefixModes();
        for (PrefixModeList::const_iterator i = list.begin(); i != list.end(); ++i)
        {
                PrefixMode* pm = *i;
                if (pm->GetPrefix())
-                       prefixes[pm->GetPrefixRank()] = std::make_pair(pm->GetPrefix(), pm->GetModeChar());
+                       prefixes.push_back(pm);
        }
 
-       for (insp::flat_map<int, std::pair<char, char> >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); ++n)
+       std::sort(prefixes.begin(), prefixes.end(), PrefixModeSorter());
+       for (std::vector<PrefixMode*>::const_reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); ++n)
        {
-               mletters = mletters + n->second.first;
-               mprefixes = mprefixes + n->second.second;
+               mletters += (*n)->GetPrefix();
+               mprefixes += (*n)->GetModeChar();
        }
 
        return lettersAndModes ? "(" + mprefixes + ")" + mletters : mletters;
@@ -850,7 +875,7 @@ void ModeHandler::RemoveMode(Channel* channel, Modes::ChangeList& changelist)
 {
        if (channel->IsModeSet(this))
        {
-               if (this->GetNumParams(false))
+               if (this->NeedsParam(false))
                        // Removing this mode requires a parameter
                        changelist.push_remove(this, channel->GetModeParameter(this));
                else
@@ -863,56 +888,14 @@ void PrefixMode::RemoveMode(Channel* chan, Modes::ChangeList& changelist)
        const Channel::MemberMap& userlist = chan->GetUsers();
        for (Channel::MemberMap::const_iterator i = userlist.begin(); i != userlist.end(); ++i)
        {
-               if (i->second->hasMode(this->GetModeChar()))
+               if (i->second->HasMode(this))
                        changelist.push_remove(this, i->first->nick);
        }
 }
 
-struct builtin_modes
-{
-       SimpleChannelModeHandler s;
-       SimpleChannelModeHandler p;
-       SimpleChannelModeHandler m;
-       SimpleChannelModeHandler t;
-
-       SimpleChannelModeHandler n;
-       SimpleChannelModeHandler i;
-       ModeChannelKey k;
-       ModeChannelLimit l;
-
-       ModeChannelBan b;
-       ModeChannelOp o;
-       ModeChannelVoice v;
-
-       SimpleUserModeHandler ui;
-       ModeUserOperator uo;
-       ModeUserServerNoticeMask us;
-
-       builtin_modes()
-               : s(NULL, "secret", 's')
-               , p(NULL, "private", 'p')
-               , m(NULL, "moderated", 'm')
-               , t(NULL, "topiclock", 't')
-               , n(NULL, "noextmsg", 'n')
-               , i(NULL, "inviteonly", 'i')
-               , ui(NULL, "invisible", 'i')
-       {
-       }
-
-       void init()
-       {
-               ServiceProvider* modes[] = { &s, &p, &m, &t, &n, &i, &k, &l, &b, &o, &v,
-                                                                        &ui, &uo, &us };
-               ServerInstance->Modules->AddServices(modes, sizeof(modes)/sizeof(ServiceProvider*));
-       }
-};
-
-static builtin_modes static_modes;
-
-void ModeParser::InitBuiltinModes()
+bool ModeParser::IsModeChar(char chr)
 {
-       static_modes.init();
-       static_modes.b.DoRehash();
+       return ((chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z'));
 }
 
 ModeParser::ModeParser()