X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmode.cpp;h=66ce313f4006a34f9f44cc397a47728f885d0fef;hb=8d066e557eeabaea40634dec8d6f5cd4d39cfe60;hp=90b8efeb8122752c90f07f55fcfd2a70fa077ddf;hpb=8f901b33a8d2ee0d318ae5feba3d84f1af939f22;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/mode.cpp b/src/mode.cpp index 90b8efeb8..66ce313f4 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -27,7 +27,7 @@ #include "builtinmodes.h" ModeHandler::ModeHandler(Module* Creator, const std::string& Name, char modeletter, ParamSpec Params, ModeType type, Class mclass) - : ServiceProvider(Creator, Name, SERVICE_MODE), m_paramtype(TR_TEXT), + : ServiceProvider(Creator, Name, SERVICE_MODE), modeid(ModeParser::MODEID_MAX), m_paramtype(TR_TEXT), parameters_taken(Params), mode(modeletter), oper(false), list(false), m_type(type), type_id(mclass), levelrequired(HALFOP_VALUE) { @@ -35,7 +35,7 @@ ModeHandler::ModeHandler(Module* Creator, const std::string& Name, char modelett CullResult ModeHandler::cull() { - if (ServerInstance->Modes) + if (ServerInstance) ServerInstance->Modes->DelMode(this); return classbase::cull(); } @@ -182,9 +182,9 @@ void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targ } } -PrefixMode::PrefixMode(Module* Creator, const std::string& Name, char ModeLetter) +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(0), prefixrank(0) + , prefix(PrefixChar), prefixrank(Rank) { list = true; m_paramtype = TR_NICK; @@ -251,7 +251,7 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool parameter = parameter.substr(0, 250); ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, modechar, parameter, adding, pcnt)); + FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mh, parameter, adding)); if (IS_LOCAL(user) && (MOD_RESULT == MOD_RES_DENY)) return MODEACTION_DENY; @@ -375,6 +375,7 @@ void ModeParser::Process(const std::vector& parameters, User* user, LastParse.clear(); LastParseParams.clear(); LastParseTranslate.clear(); + LastChangeList.clear(); if ((!targetchannel) && ((!targetuser) || (IS_SERVER(targetuser)))) { @@ -403,10 +404,10 @@ void ModeParser::Process(const std::vector& parameters, User* user, return; } - std::string mode_sequence = parameters[1]; + const std::string& mode_sequence = parameters[1]; std::string output_mode; - std::ostringstream output_parameters; + std::string output_parameters; LastParseParams.push_back(output_mode); LastParseTranslate.push_back(TR_TEXT); @@ -469,12 +470,14 @@ void ModeParser::Process(const std::vector& parameters, User* user, if (pcnt) { - output_parameters << " " << parameter; + output_parameters.push_back(' '); + output_parameters.append(parameter); LastParseParams.push_back(parameter); LastParseTranslate.push_back(mh->GetTranslateType()); } + LastChangeList.push(mh, adding, parameter); - if ( (output_mode.length() + output_parameters.str().length() > 450) + if ((output_mode.length() + output_parameters.length() > 450) || (output_mode.length() > 100) || (LastParseParams.size() > ServerInstance->Config->Limits.MaxModes)) { @@ -490,7 +493,7 @@ void ModeParser::Process(const std::vector& parameters, User* user, LastParse = targetchannel ? targetchannel->name : targetuser->nick; LastParse.append(" "); LastParse.append(output_mode); - LastParse.append(output_parameters.str()); + LastParse.append(output_parameters); if (!(flags & MODE_LOCALONLY)) ServerInstance->PI->SendMode(user, targetuser, targetchannel, LastParseParams, LastParseTranslate); @@ -500,7 +503,7 @@ void ModeParser::Process(const std::vector& parameters, User* user, else targetuser->WriteFrom(user, "MODE " + LastParse); - FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastParseParams, LastParseTranslate)); + FOREACH_MOD(OnMode, (user, targetuser, targetchannel, LastChangeList, flags, output_mode)); } else if (targetchannel && parameters.size() == 2) { @@ -511,7 +514,7 @@ void ModeParser::Process(const std::vector& parameters, User* user, } } -void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_sequence) +void ModeParser::DisplayListModes(User* user, Channel* chan, const std::string& mode_sequence) { seq++; @@ -535,7 +538,7 @@ void ModeParser::DisplayListModes(User* user, Channel* chan, std::string &mode_s return; ModResult MOD_RESULT; - FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mletter, "", true, 0)); + FIRST_MOD_RESULT(OnRawMode, MOD_RESULT, (user, chan, mh, "", true)); if (MOD_RESULT == MOD_RES_DENY) continue; @@ -608,17 +611,25 @@ void ModeParser::CleanMask(std::string &mask) } } -bool ModeParser::AddMode(ModeHandler* mh) +ModeHandler::Id ModeParser::AllocateModeId(ModeType mt) { - unsigned char mask = 0; - unsigned char pos = 0; + for (ModeHandler::Id i = 0; i != MODEID_MAX; ++i) + { + if (!modehandlersbyid[mt][i]) + return i; + } + + throw ModuleException("Out of ModeIds"); +} +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')) - return false; + throw ModuleException("Invalid letter for mode " + mh->name); /* 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. @@ -628,41 +639,55 @@ bool ModeParser::AddMode(ModeHandler* mh) if (pm) { if ((pm->GetPrefix() > 126) || (pm->GetPrefix() == ',') || (pm->GetPrefix() == ':') || (pm->GetPrefix() == '#')) - return false; + throw ModuleException("Invalid prefix for mode " + mh->name); if (FindPrefix(pm->GetPrefix())) - return false; + throw ModuleException("Prefix already exists for mode " + mh->name); } - mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL; - pos = (mh->GetModeChar()-65) | mask; + ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65]; + if (slot) + throw ModuleException("Letter is already in use for mode " + mh->name); - if (modehandlers[pos]) - return false; + // 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. + ModeHandler::Id modeid = MODEID_MAX; + 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); // Everything is fine, add the mode - modehandlers[pos] = mh; + + // If we allocated an id for this mode then save it and put the mode handler into the slot + if (modeid != MODEID_MAX) + { + mh->modeid = modeid; + modehandlersbyid[mh->GetModeType()][modeid] = mh; + } + + slot = mh; if (pm) mhlist.prefix.push_back(pm); else if (mh->IsListModeBase()) mhlist.list.push_back(mh->IsListModeBase()); RecreateModeListFor004Numeric(); - return true; } bool ModeParser::DelMode(ModeHandler* mh) { - unsigned char mask = 0; - unsigned char pos = 0; - if ((mh->GetModeChar() < 'A') || (mh->GetModeChar() > 'z')) return false; - mh->GetModeType() == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL; - pos = (mh->GetModeChar()-65) | mask; + ModeHandlerMap& mhmap = modehandlersbyname[mh->GetModeType()]; + ModeHandlerMap::iterator mhmapit = mhmap.find(mh->name); + if ((mhmapit == mhmap.end()) || (mhmapit->second != mh)) + return false; - if (modehandlers[pos] != mh) + ModeHandler*& slot = modehandlers[mh->GetModeType()][mh->GetModeChar()-65]; + if (slot != mh) return false; /* Note: We can't stack here, as we have modes potentially being removed across many different channels. @@ -671,15 +696,20 @@ bool ModeParser::DelMode(ModeHandler* mh) switch (mh->GetModeType()) { case MODETYPE_USER: - for (user_hash::iterator i = ServerInstance->Users->clientlist->begin(); i != ServerInstance->Users->clientlist->end(); ) + { + const user_hash& users = ServerInstance->Users->GetUsers(); + for (user_hash::const_iterator i = users.begin(); i != users.end(); ) { User* user = i->second; ++i; mh->RemoveMode(user); } + } break; case MODETYPE_CHANNEL: - for (chan_hash::iterator i = ServerInstance->chanlist->begin(); i != ServerInstance->chanlist->end(); ) + { + const chan_hash& chans = ServerInstance->GetChans(); + for (chan_hash::const_iterator i = chans.begin(); i != chans.end(); ) { // The channel may not be in the hash after RemoveMode(), see m_permchannels Channel* chan = i->second; @@ -696,10 +726,14 @@ bool ModeParser::DelMode(ModeHandler* mh) stackresult.erase(stackresult.begin() + 1, stackresult.end()); } } + } break; } - modehandlers[pos] = NULL; + mhmap.erase(mhmapit); + if (mh->GetId() != MODEID_MAX) + modehandlersbyid[mh->GetModeType()][mh->GetId()] = NULL; + slot = NULL; if (mh->IsPrefixMode()) mhlist.prefix.erase(std::find(mhlist.prefix.begin(), mhlist.prefix.end(), mh->IsPrefixMode())); else if (mh->IsListModeBase()) @@ -709,18 +743,22 @@ bool ModeParser::DelMode(ModeHandler* mh) return true; } -ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt) +ModeHandler* ModeParser::FindMode(const std::string& modename, ModeType mt) { - unsigned char mask = 0; - unsigned char pos = 0; + ModeHandlerMap& mhmap = modehandlersbyname[mt]; + ModeHandlerMap::const_iterator it = mhmap.find(modename); + if (it != mhmap.end()) + return it->second; + + return NULL; +} +ModeHandler* ModeParser::FindMode(unsigned const char modeletter, ModeType mt) +{ if ((modeletter < 'A') || (modeletter > 'z')) return NULL; - mt == MODETYPE_USER ? mask = MASK_USER : mask = MASK_CHANNEL; - pos = (modeletter-65) | mask; - - return modehandlers[pos]; + return modehandlers[mt][modeletter-65]; } PrefixMode* ModeParser::FindPrefixMode(unsigned char modeletter) @@ -734,13 +772,11 @@ PrefixMode* ModeParser::FindPrefixMode(unsigned char modeletter) std::string ModeParser::CreateModeList(ModeType mt, bool needparam) { std::string modestr; - unsigned char mask = ((mt == MODETYPE_CHANNEL) ? MASK_CHANNEL : MASK_USER); for (unsigned char mode = 'A'; mode <= 'z'; mode++) { - unsigned char pos = (mode-65) | mask; - - if ((modehandlers[pos]) && ((!needparam) || (modehandlers[pos]->GetNumParams(true)))) + ModeHandler* mh = modehandlers[mt][mode-65]; + if ((mh) && ((!needparam) || (mh->GetNumParams(true)))) modestr.push_back(mode); } @@ -773,38 +809,38 @@ std::string ModeParser::GiveModeList(ModeType mt) for (unsigned char mode = 'A'; mode <= 'z'; mode++) { - unsigned char pos = (mode-65) | ((mt == MODETYPE_CHANNEL) ? MASK_CHANNEL : MASK_USER); + ModeHandler* mh = modehandlers[mt][mode-65]; /* One parameter when adding */ - if (modehandlers[pos]) + if (mh) { - if (modehandlers[pos]->GetNumParams(true)) + if (mh->GetNumParams(true)) { - PrefixMode* pm = modehandlers[pos]->IsPrefixMode(); - if ((modehandlers[pos]->IsListMode()) && ((!pm) || (pm->GetPrefix() == 0))) + PrefixMode* pm = mh->IsPrefixMode(); + if ((mh->IsListMode()) && ((!pm) || (pm->GetPrefix() == 0))) { - type1 += modehandlers[pos]->GetModeChar(); + type1 += mh->GetModeChar(); } else { /* ... and one parameter when removing */ - if (modehandlers[pos]->GetNumParams(false)) + if (mh->GetNumParams(false)) { /* But not a list mode */ if (!pm) { - type2 += modehandlers[pos]->GetModeChar(); + type2 += mh->GetModeChar(); } } else { /* No parameters when removing */ - type3 += modehandlers[pos]->GetModeChar(); + type3 += mh->GetModeChar(); } } } else { - type4 += modehandlers[pos]->GetModeChar(); + type4 += mh->GetModeChar(); } } } @@ -882,8 +918,8 @@ void ModeHandler::RemoveMode(Channel* channel, irc::modestacker& stack) void PrefixMode::RemoveMode(Channel* chan, irc::modestacker& stack) { - const UserMembList* userlist = chan->GetUsers(); - for (UserMembCIter i = userlist->begin(); i != userlist->end(); ++i) + const Channel::MemberMap& userlist = chan->GetUsers(); + for (Channel::MemberMap::const_iterator i = userlist.begin(); i != userlist.end(); ++i) { if (i->second->hasMode(this->GetModeChar())) stack.Push(this->GetModeChar(), i->first->nick); @@ -892,13 +928,13 @@ void PrefixMode::RemoveMode(Channel* chan, irc::modestacker& stack) struct builtin_modes { - ModeChannelSecret s; - ModeChannelPrivate p; - ModeChannelModerated m; - ModeChannelTopicOps t; + SimpleChannelModeHandler s; + SimpleChannelModeHandler p; + SimpleChannelModeHandler m; + SimpleChannelModeHandler t; - ModeChannelNoExternal n; - ModeChannelInviteOnly i; + SimpleChannelModeHandler n; + SimpleChannelModeHandler i; ModeChannelKey k; ModeChannelLimit l; @@ -906,15 +942,25 @@ struct builtin_modes ModeChannelOp o; ModeChannelVoice v; - ModeUserWallops uw; - ModeUserInvisible ui; + 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, - &uw, &ui, &uo, &us }; + &ui, &uo, &us }; ServerInstance->Modules->AddServices(modes, sizeof(modes)/sizeof(ServiceProvider*)); } }; @@ -931,6 +977,7 @@ ModeParser::ModeParser() { /* Clear mode handler list */ memset(modehandlers, 0, sizeof(modehandlers)); + memset(modehandlersbyid, 0, sizeof(modehandlersbyid)); seq = 0; memset(&sent, 0, sizeof(sent));