X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmode.cpp;h=3538052b7a3e4d4310527366853aa659bdcf7530;hb=b4a174ee9c32d62ea6bf010e837e8c5b1c3d36a3;hp=5642e35b67e829bc7cc2edaee6c775ff21be7a94;hpb=e3fc46af3ea3999ea5eea7274f038f4f03357e0e;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/mode.cpp b/src/mode.cpp index 5642e35b6..3538052b7 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -1,13 +1,18 @@ /* * InspIRCd -- Internet Relay Chat Daemon * - * Copyright (C) 2012 Shawn Smith + * Copyright (C) 2019 Matt Schatz + * Copyright (C) 2017 B00mX0r + * Copyright (C) 2016-2019, 2021 Sadie Powell + * Copyright (C) 2012-2016, 2018 Attila Molnar + * Copyright (C) 2012, 2019 Robby + * Copyright (C) 2012 Shawn Smith * Copyright (C) 2009-2010 Daniel De Graaf - * Copyright (C) 2007, 2009 Dennis Friis - * Copyright (C) 2006-2008 Robin Burchell + * Copyright (C) 2009 Uli Schlachter * Copyright (C) 2008 Thomas Stagner - * Copyright (C) 2004-2008 Craig Edwards - * Copyright (C) 2006 Oliver Lupton + * Copyright (C) 2008 Robin Burchell + * Copyright (C) 2007 Dennis Friis + * Copyright (C) 2006-2008, 2010 Craig Edwards * * 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 @@ -24,12 +29,18 @@ #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 +55,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 ""; } @@ -83,6 +94,22 @@ void ModeHandler::DisplayEmptyList(User*, Channel*) void ModeHandler::OnParameterMissing(User* user, User* dest, Channel* channel) { + 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*) @@ -90,6 +117,12 @@ bool ModeHandler::ResolveModeConflict(std::string& theirs, const std::string& ou return (theirs < ours); } +void ModeHandler::RegisterService() +{ + ServerInstance->Modes.AddMode(this); + ServerInstance->Modules.AddReferent((GetModeType() == MODETYPE_CHANNEL ? "mode/" : "umode/") + name, this); +} + ModeAction SimpleUserModeHandler::OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) { /* We're either trying to add a mode we already have or @@ -138,11 +171,6 @@ ModeWatcher::~ModeWatcher() ServerInstance->Modes->DelModeWatcher(this); } -ModeType ModeWatcher::GetModeType() -{ - return m_type; -} - bool ModeWatcher::BeforeMode(User*, User*, Channel*, std::string&, bool) { return true; @@ -152,41 +180,21 @@ void ModeWatcher::AfterMode(User*, User*, Channel*, const std::string&, bool) { } -void ModeParser::DisplayCurrentModes(User* user, User* targetuser, Channel* targetchannel) -{ - if (targetchannel) - { - /* Display channel's current mode string */ - user->WriteNumeric(RPL_CHANNELMODEIS, "%s +%s", targetchannel->name.c_str(), targetchannel->ChanModes(targetchannel->HasUser(user))); - user->WriteNumeric(RPL_CHANNELCREATED, "%s %lu", targetchannel->name.c_str(), (unsigned long)targetchannel->age); - return; - } - else - { - if (targetuser == user || user->HasPrivPermission("users/auspex")) - { - /* Display user's current mode string */ - user->WriteNumeric(RPL_UMODEIS, ":+%s", targetuser->FormatModes()); - if ((targetuser->IsOper())) - { - ModeHandler* snomask = FindMode('s', MODETYPE_USER); - user->WriteNumeric(RPL_SNOMASKIS, "%s :Server notice mask", snomask->GetUserParameter(user).c_str()); - } - return; - } - else - { - user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't view modes for other users"); - return; - } - } -} - 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; + syntax = ""; +} + +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) @@ -199,7 +207,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; } @@ -211,6 +219,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) @@ -243,12 +259,12 @@ 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 - if (parameter.length() > 250 && adding) - parameter = parameter.substr(0, 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)); @@ -266,7 +282,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 @@ -275,11 +291,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()) @@ -287,19 +304,18 @@ 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; } } } // Ask mode watchers whether this mode change is OK - std::pair itpair = modewatchermap.equal_range(mh->name); - for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) + std::pair itpair = modewatchermap.equal_range(mh->name); + for (ModeWatcherMap::iterator i = itpair.first; i != itpair.second; ++i) { ModeWatcher* mw = i->second; if (mw->GetModeType() == type) @@ -308,34 +324,23 @@ 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']) - { - user->WriteNumeric(ERR_NOPRIVILEGES, ":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 ((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, ":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, ":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; } @@ -343,14 +348,14 @@ 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) return ma; itpair = modewatchermap.equal_range(mh->name); - for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) + for (ModeWatcherMap::iterator i = itpair.first; i != itpair.second; ++i) { ModeWatcher* mw = i->second; if (mw->GetModeType() == type) @@ -360,71 +365,6 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, Mode return MODEACTION_ALLOW; } -void ModeParser::Process(const std::vector& parameters, User* user, ModeProcessFlag flags) -{ - const std::string& target = parameters[0]; - Channel* targetchannel = ServerInstance->FindChan(target); - User* targetuser = NULL; - if (!targetchannel) - { - if (IS_LOCAL(user)) - targetuser = ServerInstance->FindNickOnly(target); - else - targetuser = ServerInstance->FindNick(target); - } - ModeType type = targetchannel ? MODETYPE_CHANNEL : MODETYPE_USER; - - LastParse.clear(); - LastChangeList.clear(); - - if ((!targetchannel) && ((!targetuser) || (IS_SERVER(targetuser)))) - { - user->WriteNumeric(ERR_NOSUCHNICK, "%s :No such nick/channel", target.c_str()); - return; - } - if (parameters.size() == 1) - { - this->DisplayCurrentModes(user, targetuser, targetchannel); - return; - } - - // Populate a temporary Modes::ChangeList with the parameters - Modes::ChangeList changelist; - ModeParamsToChangeList(user, type, parameters, changelist); - - ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnPreMode, MOD_RESULT, (user, targetuser, targetchannel, changelist)); - - if (IS_LOCAL(user)) - { - if (MOD_RESULT == MOD_RES_PASSTHRU) - { - if ((targetuser) && (user != targetuser)) - { - // Local users may only change the modes of other users if a module explicitly allows it - user->WriteNumeric(ERR_USERSDONTMATCH, ":Can't change mode for other users"); - return; - } - - // This is a mode change by a local user and modules didn't explicitly allow/deny. - // Ensure access checks will happen for each mode being changed. - flags |= MODE_CHECKACCESS; - } - else if (MOD_RESULT == MOD_RES_DENY) - return; // Entire mode change denied by a module - } - - ProcessSingle(user, targetchannel, targetuser, changelist, flags); - - if ((LastParse.empty()) && (targetchannel) && (parameters.size() == 2)) - { - /* Special case for displaying the list for listmodes, - * e.g. MODE #chan b, or MODE #chan +b without a parameter - */ - this->DisplayListModes(user, targetchannel, parameters[1]); - } -} - void ModeParser::ModeParamsToChangeList(User* user, ModeType type, const std::vector& parameters, Modes::ChangeList& changelist, unsigned int beginindex, unsigned int endindex) { if (endindex > parameters.size()) @@ -448,12 +388,14 @@ 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); + int numeric = (type == MODETYPE_CHANNEL ? ERR_UNKNOWNMODE : ERR_UNKNOWNSNOMASK); + const char* typestr = (type == MODETYPE_CHANNEL ? "channel" : "user"); + user->WriteNumeric(numeric, modechar, InspIRCd::Format("is not a recognised %s mode.", typestr)); 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); @@ -471,7 +413,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; } @@ -504,14 +449,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) { @@ -520,9 +460,15 @@ unsigned int ModeParser::ProcessSingle(User* user, Channel* targetchannel, User* Modes::Change& item = *i; ModeHandler* mh = item.mh; + // If a mode change has been given for a mode that does not exist then reject + // it. This can happen when core_reloadmodule attempts to restore a mode that + // no longer exists. + if (!mh) + continue; + // 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)) @@ -538,75 +484,35 @@ 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; } -void ModeParser::DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence) -{ - seq++; - - for (std::string::const_iterator letter = mode_sequence.begin(); letter != mode_sequence.end(); letter++) - { - unsigned char mletter = *letter; - if (mletter == '+') - continue; - - /* Ensure the user doesnt request the same mode twice, - * so they cant flood themselves off out of idiocy. - */ - if (sent[mletter] == seq) - continue; - - sent[mletter] = seq; - - ModeHandler *mh = this->FindMode(mletter, MODETYPE_CHANNEL); - - if (!mh || !mh->IsListMode()) - return; - - ShowListModeList(user, chan, mh); - } -} - void ModeParser::ShowListModeList(User* user, Channel* chan, ModeHandler* mh) { { @@ -615,18 +521,11 @@ void ModeParser::ShowListModeList(User* user, Channel* chan, ModeHandler* mh) if (MOD_RESULT == MOD_RES_DENY) return; - unsigned char mletter = mh->GetModeChar(); bool display = true; - if (!user->HasPrivPermission("channels/auspex") && ServerInstance->Config->HideModeLists[mletter] && (chan->GetPrefixValue(user) < HALFOP_VALUE)) - { - user->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s :You do not have access to view the +%c list", - chan->name.c_str(), mletter); - display = false; - } // Ask mode watchers whether it's OK to show the list - std::pair itpair = modewatchermap.equal_range(mh->name); - for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) + std::pair itpair = modewatchermap.equal_range(mh->name); + for (ModeWatcherMap::iterator i = itpair.first; i != itpair.second; ++i) { ModeWatcher* mw = i->second; if (mw->GetModeType() == MODETYPE_CHANNEL) @@ -676,7 +575,7 @@ void ModeParser::CleanMask(std::string &mask) else if ((pos_of_pling == std::string::npos) && (pos_of_at != std::string::npos)) { /* Has an @ but no !, its a user@host */ - mask = "*!" + mask; + mask = "*!" + mask; } else if ((pos_of_pling != std::string::npos) && (pos_of_at == std::string::npos)) { @@ -698,12 +597,9 @@ 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')) - throw ModuleException("Invalid letter for mode " + mh->name); + if (!ModeParser::IsModeChar(mh->GetModeChar())) + 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. @@ -713,15 +609,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. @@ -729,8 +629,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 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 @@ -746,13 +651,11 @@ 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) { - if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z')) + if (!ModeParser::IsModeChar(mh->GetModeChar())) return false; ModeHandlerMap& mhmap = modehandlersbyname[mh->GetModeType()]; @@ -805,8 +708,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; } @@ -822,7 +723,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]; @@ -836,25 +737,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->GetNumParams(true)))) - modestr.push_back(mode); - } - - return modestr; -} - -void ModeParser::RecreateModeListFor004Numeric() -{ - Cached004ModeList = CreateModeList(MODETYPE_USER) + " " + CreateModeList(MODETYPE_CHANNEL) + " " + CreateModeList(MODETYPE_CHANNEL, true); -} - PrefixMode* ModeParser::FindPrefix(unsigned const char pfxletter) { const PrefixModeList& list = GetPrefixModes(); @@ -877,10 +759,10 @@ std::string ModeParser::GiveModeList(ModeType mt) for (unsigned char mode = 'A'; mode <= 'z'; mode++) { ModeHandler* mh = modehandlers[mt][mode-65]; - /* One parameter when adding */ if (mh) { - if (mh->GetNumParams(true)) + /* One parameter when adding */ + if (mh->NeedsParam(true)) { PrefixMode* pm = mh->IsPrefixMode(); if ((mh->IsListMode()) && ((!pm) || (pm->GetPrefix() == 0))) @@ -890,7 +772,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) @@ -915,24 +797,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; - std::map > prefixes; + std::vector 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(std::map >::reverse_iterator n = prefixes.rbegin(); n != prefixes.rend(); n++) + std::sort(prefixes.begin(), prefixes.end(), PrefixModeSorter()); + for (std::vector::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; @@ -945,8 +836,8 @@ void ModeParser::AddModeWatcher(ModeWatcher* mw) bool ModeParser::DelModeWatcher(ModeWatcher* mw) { - std::pair itpair = modewatchermap.equal_range(mw->GetModeName()); - for (ModeWatchIter i = itpair.first; i != itpair.second; ++i) + std::pair itpair = modewatchermap.equal_range(mw->GetModeName()); + for (ModeWatcherMap::iterator i = itpair.first; i != itpair.second; ++i) { if (i->second == mw) { @@ -973,7 +864,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 @@ -986,56 +877,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 +bool ModeParser::IsModeChar(char chr) { - 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() -{ - static_modes.init(); - static_modes.b.DoRehash(); + return ((chr >= 'A' && chr <= 'Z') || (chr >= 'a' && chr <= 'z')); } ModeParser::ModeParser() @@ -1043,9 +892,6 @@ ModeParser::ModeParser() /* Clear mode handler list */ memset(modehandlers, 0, sizeof(modehandlers)); memset(modehandlersbyid, 0, sizeof(modehandlersbyid)); - - seq = 0; - memset(&sent, 0, sizeof(sent)); } ModeParser::~ModeParser()