]> git.netwichtig.de Git - user/henk/code/inspircd.git/blobdiff - src/mode.cpp
Add support for blocking tag messages with the deaf mode.
[user/henk/code/inspircd.git] / src / mode.cpp
index 9d17f5be8b8eda5cae8a329fd550ef2d3d6d6b08..306d39c5d00a7033dd621a3d84420f82405e1d38 100644 (file)
@@ -1,13 +1,18 @@
 /*
  * InspIRCd -- Internet Relay Chat Daemon
  *
- *   Copyright (C) 2012 Shawn Smith <shawn@inspircd.org>
+ *   Copyright (C) 2019 Matt Schatz <genius3000@g3k.solutions>
+ *   Copyright (C) 2017 B00mX0r <b00mx0r@aureus.pw>
+ *   Copyright (C) 2016-2019, 2021 Sadie Powell <sadie@witchery.services>
+ *   Copyright (C) 2012-2016, 2018 Attila Molnar <attilamolnar@hush.com>
+ *   Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
+ *   Copyright (C) 2012 Shawn Smith <ShawnSmith0828@gmail.com>
  *   Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
- *   Copyright (C) 2007, 2009 Dennis Friis <peavey@inspircd.org>
- *   Copyright (C) 2006-2008 Robin Burchell <robin+git@viroteck.net>
+ *   Copyright (C) 2009 Uli Schlachter <psychon@inspircd.org>
  *   Copyright (C) 2008 Thomas Stagner <aquanight@inspircd.org>
- *   Copyright (C) 2004-2008 Craig Edwards <craigedwards@brainbox.cc>
- *   Copyright (C) 2006 Oliver Lupton <oliverlupton@gmail.com>
+ *   Copyright (C) 2008 Robin Burchell <robin+git@viroteck.net>
+ *   Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
+ *   Copyright (C) 2006-2008, 2010 Craig Edwards <brain@inspircd.org>
  *
  * 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
@@ -89,13 +94,24 @@ void ModeHandler::DisplayEmptyList(User*, Channel*)
 
 void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel)
 {
-       const std::string message = InspIRCd::Format("You must specify a parameter for the %s mode", name.c_str());
+       std::string message = InspIRCd::Format("You must specify a parameter for the %s mode.", name.c_str());
+       if (!syntax.empty())
+               message.append(InspIRCd::Format(" Syntax: %s.", syntax.c_str()));
+
        if (channel)
                user->WriteNumeric(Numerics::InvalidModeParameter(channel, this, "*", message));
        else
                user->WriteNumeric(Numerics::InvalidModeParameter(dest, this, "*", message));
 }
 
+void ModeHandler::OnParameterInvalid(User* user, Channel* targetchannel, User* targetuser, const std::string& parameter)
+{
+       if (targetchannel)
+               user->WriteNumeric(Numerics::InvalidModeParameter(targetchannel, this, "*"));
+       else
+               user->WriteNumeric(Numerics::InvalidModeParameter(targetuser, this, "*"));
+}
+
 bool ModeHandler::ResolveModeConflict(std::string& theirs, const std::string& ours, Channel*)
 {
        return (theirs < ours);
@@ -171,6 +187,7 @@ PrefixMode::PrefixMode(Module* Creator, const std::string& Name, char ModeLetter
        , selfremove(true)
 {
        list = true;
+       syntax = "<nick>";
 }
 
 ModResult PrefixMode::AccessCheck(User* src, Channel*, std::string& value, bool adding)
@@ -245,9 +262,9 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode
        const bool needs_param = mh->NeedsParam(adding);
 
        std::string& parameter = mcitem.param;
-       // crop mode parameter size to 250 characters
-       if (parameter.length() > 250 && adding)
-               parameter.erase(250);
+       // crop mode parameter size to MODE_PARAM_MAX characters
+       if (parameter.length() > MODE_PARAM_MAX && adding)
+               parameter.erase(MODE_PARAM_MAX);
 
        ModResult MOD_RESULT;
        FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mh, parameter, adding));
@@ -312,29 +329,18 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode
                }
        }
 
-       if (IS_LOCAL(user) && !user->IsOper())
-       {
-               const std::bitset<64>& disabled = (type == MODETYPE_CHANNEL) ? ServerInstance->Config->DisabledCModes : ServerInstance->Config->DisabledUModes;
-               if (disabled.test(modechar - 'A'))
-               {
-                       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(mh)))
+       if ((chan || (!chan && 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, 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));
+                       user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("Permission Denied - Oper type %s does not have access to %sset %s mode %c",
+                                       user->oper->name.c_str(), adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
                }
                else
                {
-                       user->WriteNumeric(ERR_NOPRIVILEGES, InspIRCd::Format("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 %sset %s mode %c",
+                                       adding ? "" : "un", type == MODETYPE_CHANNEL ? "channel" : "user", modechar));
                }
                return MODEACTION_DENY;
        }
@@ -382,7 +388,7 @@ 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, modechar, "is unknown mode char to me");
+                       user->WriteNumeric(type == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK, modechar, "is an unknown mode character");
                        continue;
                }
 
@@ -405,7 +411,10 @@ static bool IsModeParamValid(User* user, Channel* targetchannel, User* targetuse
 
        // The parameter cannot begin with a ':' character or contain a space
        if ((item.param[0] == ':') || (item.param.find(' ') != std::string::npos))
+       {
+               item.mh->OnParameterInvalid(user, targetchannel, targetuser, item.param);
                return false;
+       }
 
        return true;
 }
@@ -438,14 +447,9 @@ void ModeParser::Process(User* user, Channel* targetchannel, User* targetuser, M
 
 unsigned int ModeParser::ProcessSingle(User* user, Channel* targetchannel, User* targetuser, Modes::ChangeList& changelist, ModeProcessFlag flags, unsigned int beginindex)
 {
-       LastParse.clear();
        LastChangeList.clear();
 
        unsigned int modes_processed = 0;
-       std::string output_mode;
-       std::string output_parameters;
-
-       char output_pm = '\0'; // current output state, '+' or '-'
        Modes::ChangeList::List& list = changelist.getlist();
        for (Modes::ChangeList::List::iterator i = list.begin()+beginindex; i != list.end(); ++i)
        {
@@ -478,43 +482,30 @@ unsigned int ModeParser::ProcessSingle(User* user, Channel* targetchannel, User*
                if (ma != MODEACTION_ALLOW)
                        continue;
 
-               char needed_pm = item.adding ? '+' : '-';
-               if (needed_pm != output_pm)
-               {
-                       output_pm = needed_pm;
-                       output_mode.append(1, output_pm);
-               }
-               output_mode.push_back(mh->GetModeChar());
-
-               if (!item.param.empty())
-               {
-                       output_parameters.push_back(' ');
-                       output_parameters.append(item.param);
-               }
                LastChangeList.push(mh, item.adding, item.param);
 
-               if ((output_mode.length() + output_parameters.length() > 450)
-                               || (output_mode.length() > 100)
-                               || (LastChangeList.size() >= ServerInstance->Config->Limits.MaxModes))
+               if (LastChangeList.size() >= ServerInstance->Config->Limits.MaxModes)
                {
                        /* mode sequence is getting too long */
                        break;
                }
        }
 
-       if (!output_mode.empty())
+       if (!LastChangeList.empty())
        {
-               LastParse = targetchannel ? targetchannel->name : targetuser->nick;
-               LastParse.append(" ");
-               LastParse.append(output_mode);
-               LastParse.append(output_parameters);
-
+               ClientProtocol::Events::Mode modeevent(user, targetchannel, targetuser, LastChangeList);
                if (targetchannel)
-                       targetchannel->WriteChannel(user, "MODE " + LastParse);
+               {
+                       targetchannel->Write(modeevent);
+               }
                else
-                       targetuser->WriteFrom(user, "MODE " + LastParse);
+               {
+                       LocalUser* localtarget = IS_LOCAL(targetuser);
+                       if (localtarget)
+                               localtarget->Send(modeevent);
+               }
 
-               FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastChangeList, flags, output_mode));
+               FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastChangeList, flags));
        }
 
        return modes_processed;
@@ -605,7 +596,8 @@ ModeHandler::Id ModeParser::AllocateModeId(ModeType mt)
 void ModeParser::AddMode(ModeHandler* mh)
 {
        if (!ModeParser::IsModeChar(mh->GetModeChar()))
-               throw ModuleException("Invalid letter for mode " + mh->name);
+               throw ModuleException(InspIRCd::Format("Mode letter for %s is invalid: %c",
+                       mh->name.c_str(), mh->GetModeChar()));
 
        /* A mode prefix of ',' is not acceptable, it would fuck up server to server.
         * A mode prefix of ':' will fuck up both server to server, and client to server.
@@ -615,15 +607,19 @@ void ModeParser::AddMode(ModeHandler* mh)
        if (pm)
        {
                if ((pm->GetPrefix() > 126) || (pm->GetPrefix() == ',') || (pm->GetPrefix() == ':') || (pm->GetPrefix() == '#'))
-                       throw ModuleException("Invalid prefix for mode " + mh->name);
+                       throw ModuleException(InspIRCd::Format("Mode prefix for %s is invalid: %c",
+                               mh->name.c_str(), pm->GetPrefix()));
 
-               if (FindPrefix(pm->GetPrefix()))
-                       throw ModuleException("Prefix already exists for mode " + mh->name);
+               PrefixMode* otherpm = FindPrefix(pm->GetPrefix());
+               if (otherpm)
+                       throw ModuleException(InspIRCd::Format("Mode prefix for %s already used by %s from %s: %c",
+                               mh->name.c_str(), otherpm->name.c_str(), otherpm->creator->ModuleSourceFile.c_str(), pm->GetPrefix()));
        }
 
        ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65];
        if (slot)
-               throw ModuleException("Letter is already in use for mode " + mh->name);
+               throw ModuleException(InspIRCd::Format("Mode letter for %s already used by %s from %s: %c",
+                       mh->name.c_str(), slot->name.c_str(), slot->creator->ModuleSourceFile.c_str(), mh->GetModeChar()));
 
        // The mode needs an id if it is either a user mode, a simple mode (flag) or a parameter mode.
        // Otherwise (for listmodes and prefix modes) the id remains MODEID_MAX, which is invalid.
@@ -631,8 +627,13 @@ void ModeParser::AddMode(ModeHandler* mh)
        if ((mh->GetModeType() == MODETYPE_USER) || (mh->IsParameterMode()) || (!mh->IsListMode()))
                modeid = AllocateModeId(mh->GetModeType());
 
-       if (!modehandlersbyname[mh->GetModeType()].insert(std::make_pair(mh->name, mh)).second)
-               throw ModuleException("Mode name already in use: " + mh->name);
+       std::pair<ModeHandlerMap::iterator, bool> res = modehandlersbyname[mh->GetModeType()].insert(std::make_pair(mh->name, mh));
+       if (!res.second)
+       {
+               ModeHandler* othermh = res.first->second;
+               throw ModuleException(InspIRCd::Format("Mode name %s already used by %c from %s",
+                       mh->name.c_str(), othermh->GetModeChar(), othermh->creator->ModuleSourceFile.c_str()));
+       }
 
        // Everything is fine, add the mode
 
@@ -648,8 +649,6 @@ void ModeParser::AddMode(ModeHandler* mh)
                mhlist.prefix.push_back(pm);
        else if (mh->IsListModeBase())
                mhlist.list.push_back(mh->IsListModeBase());
-
-       RecreateModeListFor004Numeric();
 }
 
 bool ModeParser::DelMode(ModeHandler* mh)
@@ -707,8 +706,6 @@ bool ModeParser::DelMode(ModeHandler* mh)
                mhlist.prefix.erase(std::find(mhlist.prefix.begin(), mhlist.prefix.end(), mh->IsPrefixMode()));
        else if (mh->IsListModeBase())
                mhlist.list.erase(std::find(mhlist.list.begin(), mhlist.list.end(), mh->IsListModeBase()));
-
-       RecreateModeListFor004Numeric();
        return true;
 }
 
@@ -738,27 +735,6 @@ PrefixMode* ModeParser::FindPrefixMode(unsigned char modeletter)
        return mh->IsPrefixMode();
 }
 
-std::string ModeParser::CreateModeList(ModeType mt, bool needparam)
-{
-       std::string modestr;
-
-       for (unsigned char mode = 'A'; mode <= 'z'; mode++)
-       {
-               ModeHandler* mh = modehandlers[mt][mode-65];
-               if ((mh) && ((!needparam) || (mh->NeedsParam(true))))
-                       modestr.push_back(mode);
-       }
-
-       return modestr;
-}
-
-void ModeParser::RecreateModeListFor004Numeric()
-{
-       Cached004ModeList[0] = CreateModeList(MODETYPE_USER);
-       Cached004ModeList[1] = CreateModeList(MODETYPE_CHANNEL);
-       Cached004ModeList[2] = CreateModeList(MODETYPE_CHANNEL, true);
-}
-
 PrefixMode* ModeParser::FindPrefix(unsigned const char pfxletter)
 {
        const PrefixModeList& list = GetPrefixModes();