From 34fa5627de0a0431ca76f34445c680a76a9a7dc5 Mon Sep 17 00:00:00 2001 From: attilamolnar Date: Sun, 1 Sep 2013 14:25:15 +0200 Subject: [PATCH] Create a base class for prefix modes Move Channel::SetPrefix() into Membership --- include/builtinmodes.h | 10 ++---- include/channels.h | 11 ------- include/membership.h | 10 ++++++ include/mode.h | 56 +++++++++++++++++++++++++++++----- src/channels.cpp | 25 ++++++--------- src/mode.cpp | 56 ++++++++++++++++------------------ src/modes/cmode_o.cpp | 9 +----- src/modes/cmode_v.cpp | 9 +----- src/modules/m_customprefix.cpp | 12 ++------ src/modules/m_ojoin.cpp | 12 ++------ src/modules/m_operprefix.cpp | 22 ++----------- 11 files changed, 107 insertions(+), 125 deletions(-) diff --git a/include/builtinmodes.h b/include/builtinmodes.h index b1e5c3ccd..ce73a7817 100644 --- a/include/builtinmodes.h +++ b/include/builtinmodes.h @@ -86,13 +86,10 @@ class ModeChannelNoExternal : public SimpleChannelModeHandler /** Channel mode +o */ -class ModeChannelOp : public ModeHandler +class ModeChannelOp : public PrefixMode { - private: public: ModeChannelOp(); - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); - unsigned int GetPrefixRank(); }; /** Channel mode +p @@ -127,13 +124,10 @@ class ModeChannelTopicOps : public SimpleChannelModeHandler /** Channel mode +v */ -class ModeChannelVoice : public ModeHandler +class ModeChannelVoice : public PrefixMode { - private: public: ModeChannelVoice(); - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding); - unsigned int GetPrefixRank(); }; /** User mode +i diff --git a/include/channels.h b/include/channels.h index 0c7a3a20c..4f61e15e4 100644 --- a/include/channels.h +++ b/include/channels.h @@ -338,17 +338,6 @@ class CoreExport Channel : public Extensible, public InviteBase */ unsigned int GetPrefixValue(User* user); - /** Add a prefix character to a user. - * Only the core should call this method, usually from - * within the mode parser or when the first user joins - * the channel (to grant ops to them) - * @param user The user to associate the privilage with - * @param prefix The prefix character to associate - * @param adding True if adding the prefix, false when removing - * @return True if a change was made - */ - bool SetPrefix(User* user, char prefix, bool adding); - /** Check if a user is banned on this channel * @param user A user to check against the banlist * @returns True if the user given is banned diff --git a/include/membership.h b/include/membership.h index 5850e0ae0..7074566ae 100644 --- a/include/membership.h +++ b/include/membership.h @@ -32,6 +32,16 @@ class CoreExport Membership : public Extensible return modes.find(m) != std::string::npos; } unsigned int getRank(); + + /** Add a prefix character to a user. + * Only the core should call this method, usually from + * within the mode parser or when the first user joins + * the channel (to grant the default privs to them) + * @param mh The mode handler of the prefix mode to associate + * @param adding True if adding the prefix, false when removing + * @return True if a change was made + */ + bool SetPrefix(ModeHandler* mh, bool adding); }; class CoreExport InviteBase diff --git a/include/mode.h b/include/mode.h index 18fed8b0a..8c3e875f3 100644 --- a/include/mode.h +++ b/include/mode.h @@ -103,16 +103,10 @@ class CoreExport ModeHandler : public ServiceProvider public: enum Class { + MC_PREFIX, MC_OTHER }; - /** - * Removes this prefix mode from all users on the given channel - * @param channel The channel which the server wants to remove your mode from - * @param stack The mode stack to add the mode change to - */ - void RemovePrefixMode(Channel* chan, irc::modestacker& stack); - protected: /** * The mode parameter translation type @@ -312,6 +306,54 @@ class CoreExport ModeHandler : public ServiceProvider inline unsigned int GetLevelRequired() const { return levelrequired; } }; +/** + * Prefix modes are channel modes that grant a specific rank to members having prefix mode set. + * They require a parameter when setting and unsetting; the parameter is always a member of the channel. + * A prefix mode may be set on any number of members on a channel, but for a given member a given prefix + * mode is either set or not set, in other words members cannot have the same prefix mode set more than once. + * + * A rank of a member is defined as the rank given by the 'strongest' prefix mode that member has. + * Other parts of the IRCd use this rank to determine whether a channel action is allowable for a user or not. + * The rank of a prefix mode is constant, i.e. the same rank value is given to all users having that prefix mode set. + * + * Note that it is possible that the same action requires a different rank on a different channel; + * for example changing the topic on a channel having +t set requires a rank that is >= than the rank of a halfop, + * but there is no such restriction when +t isn't set. + */ +class PrefixMode : public ModeHandler +{ + public: + /** + * Constructor + * @param Creator The module creating this mode + * @param Name The user-friendly one word name of the prefix mode, e.g.: "op", "voice" + * @param ModeLetter The mode letter of this mode + */ + PrefixMode(Module* Creator, const std::string& Name, char ModeLetter); + + /** + * Handles setting and unsetting the prefix mode. + * Finds the given member of the given channel, if it's not found an error message is sent to 'source' + * and MODEACTION_DENY is returned. Otherwise the mode change is attempted. + * @param source Source of the mode change, an error message is sent to this user if the target is not found + * @param dest Unused + * @param channel The channel the mode change is happening on + * @param param The nickname or uuid of the target user + * @param adding True when the mode is being set, false when it is being unset + * @return MODEACTION_ALLOW if the change happened, MODEACTION_DENY if no change happened + * The latter occurs either when the member cannot be found or when the member already has this prefix set + * (when setting) or doesn't have this prefix set (when unsetting). + */ + ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string& param, bool adding); + + /** + * Removes this prefix mode from all users on the given channel + * @param chan The channel which the server wants to remove your mode from + * @param stack The mode stack to add the mode change to + */ + void RemoveMode(Channel* chan, irc::modestacker& stack); +}; + /** A prebuilt mode handler which handles a simple user mode, e.g. no parameters, usable by any user, with no extra * behaviour to the mode beyond the basic setting and unsetting of the mode, not allowing the mode to be set if it * is already set and not allowing it to be unset if it is already unset. diff --git a/src/channels.cpp b/src/channels.cpp index afc569909..91aec6fa5 100644 --- a/src/channels.cpp +++ b/src/channels.cpp @@ -343,9 +343,8 @@ void Channel::ForceJoin(User* user, const std::string* privs, bool bursting, boo if (mh && mh->GetPrefixRank()) { std::string nick = user->nick; - /* Set, and make sure that the mode handler knows this mode was now set */ - this->SetPrefix(user, mh->GetModeChar(), true); - mh->OnModeChange(ServerInstance->FakeClient, ServerInstance->FakeClient, this, nick, true); + // Set the mode on the user + mh->OnModeChange(ServerInstance->FakeClient, NULL, this, nick, true); } } } @@ -792,29 +791,23 @@ unsigned int Channel::GetPrefixValue(User* user) return m->second->getRank(); } -bool Channel::SetPrefix(User* user, char prefix, bool adding) +bool Membership::SetPrefix(ModeHandler* delta_mh, bool adding) { - ModeHandler* delta_mh = ServerInstance->Modes->FindMode(prefix, MODETYPE_CHANNEL); - if (!delta_mh) - return false; - UserMembIter m = userlist.find(user); - if (m == userlist.end()) - return false; - for(unsigned int i=0; i < m->second->modes.length(); i++) + char prefix = delta_mh->GetModeChar(); + for (unsigned int i = 0; i < modes.length(); i++) { - char mchar = m->second->modes[i]; + char mchar = modes[i]; ModeHandler* mh = ServerInstance->Modes->FindMode(mchar, MODETYPE_CHANNEL); if (mh && mh->GetPrefixRank() <= delta_mh->GetPrefixRank()) { - m->second->modes = - m->second->modes.substr(0,i) + + modes = modes.substr(0,i) + (adding ? std::string(1, prefix) : "") + - m->second->modes.substr(mchar == prefix ? i+1 : i); + modes.substr(mchar == prefix ? i+1 : i); return adding != (mchar == prefix); } } if (adding) - m->second->modes += std::string(1, prefix); + modes.push_back(prefix); return adding; } diff --git a/src/mode.cpp b/src/mode.cpp index b76e1558f..aedc8bb85 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -195,6 +195,30 @@ void ModeParser::DisplayCurrentModes(User *user, User* targetuser, Channel* targ } } +PrefixMode::PrefixMode(Module* Creator, const std::string& Name, char ModeLetter) + : ModeHandler(Creator, Name, ModeLetter, PARAM_ALWAYS, MODETYPE_CHANNEL, MC_PREFIX) +{ + list = true; + m_paramtype = TR_NICK; +} + +ModeAction PrefixMode::OnModeChange(User* source, User*, Channel* chan, std::string& parameter, bool adding) +{ + User* target = ServerInstance->FindNick(parameter); + if (!target) + { + source->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", source->nick.c_str(), parameter.c_str()); + return MODEACTION_DENY; + } + + Membership* memb = chan->GetUser(target); + if (!memb) + return MODEACTION_DENY; + + parameter = target->nick; + return (memb->SetPrefix(this, adding) ? MODEACTION_ALLOW : MODEACTION_DENY); +} + ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool adding, const unsigned char modechar, std::string ¶meter, bool SkipACL) { @@ -295,21 +319,6 @@ ModeAction ModeParser::TryMode(User* user, User* targetuser, Channel* chan, bool return MODEACTION_DENY; } - if (mh->GetTranslateType() == TR_NICK && !ServerInstance->FindNick(parameter)) - { - user->WriteNumeric(ERR_NOSUCHNICK, "%s %s :No such nick/channel", user->nick.c_str(), parameter.c_str()); - return MODEACTION_DENY; - } - - if (mh->GetPrefixRank() && chan) - { - User* user_to_prefix = ServerInstance->FindNick(parameter); - if (!user_to_prefix) - return MODEACTION_DENY; - if (!chan->SetPrefix(user_to_prefix, modechar, adding)) - return MODEACTION_DENY; - } - /* Call the handler for the mode */ ModeAction ma = mh->OnModeChange(user, targetuser, chan, parameter, adding); @@ -437,16 +446,9 @@ void ModeParser::Process(const std::vector& parameters, User* user, if (pcnt) { - TranslateType tt = mh->GetTranslateType(); - if (tt == TR_NICK) - { - User* u = ServerInstance->FindNick(parameter); - if (u) - parameter = u->nick; - } output_parameters << " " << parameter; LastParseParams.push_back(parameter); - LastParseTranslate.push_back(tt); + LastParseTranslate.push_back(mh->GetTranslateType()); } if ( (output_mode.length() + output_parameters.str().length() > 450) @@ -827,11 +829,7 @@ void ModeHandler::RemoveMode(User* user) void ModeHandler::RemoveMode(Channel* channel, irc::modestacker& stack) { - if (this->GetPrefixRank()) - { - RemovePrefixMode(channel, stack); - } - else if (channel->IsModeSet(this)) + if (channel->IsModeSet(this)) { if (this->GetNumParams(false)) // Removing this mode requires a parameter @@ -841,7 +839,7 @@ void ModeHandler::RemoveMode(Channel* channel, irc::modestacker& stack) } } -void ModeHandler::RemovePrefixMode(Channel* chan, 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) diff --git a/src/modes/cmode_o.cpp b/src/modes/cmode_o.cpp index d500f23b1..6e96afa67 100644 --- a/src/modes/cmode_o.cpp +++ b/src/modes/cmode_o.cpp @@ -28,16 +28,9 @@ #include "modules.h" #include "builtinmodes.h" -ModeChannelOp::ModeChannelOp() : ModeHandler(NULL, "op", 'o', PARAM_ALWAYS, MODETYPE_CHANNEL) +ModeChannelOp::ModeChannelOp() : PrefixMode(NULL, "op", 'o') { - list = true; prefix = '@'; levelrequired = OP_VALUE; - m_paramtype = TR_NICK; prefixrank = OP_VALUE; } - -ModeAction ModeChannelOp::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) -{ - return MODEACTION_ALLOW; -} diff --git a/src/modes/cmode_v.cpp b/src/modes/cmode_v.cpp index fe62c407f..c8ce30ab1 100644 --- a/src/modes/cmode_v.cpp +++ b/src/modes/cmode_v.cpp @@ -28,16 +28,9 @@ #include "modules.h" #include "builtinmodes.h" -ModeChannelVoice::ModeChannelVoice() : ModeHandler(NULL, "voice", 'v', PARAM_ALWAYS, MODETYPE_CHANNEL) +ModeChannelVoice::ModeChannelVoice() : PrefixMode(NULL, "voice", 'v') { - list = true; prefix = '+'; levelrequired = HALFOP_VALUE; - m_paramtype = TR_NICK; prefixrank = VOICE_VALUE; } - -ModeAction ModeChannelVoice::OnModeChange(User* source, User*, Channel* channel, std::string ¶meter, bool adding) -{ - return MODEACTION_ALLOW; -} diff --git a/src/modules/m_customprefix.cpp b/src/modules/m_customprefix.cpp index bda11e8b3..f0b6d88e3 100644 --- a/src/modules/m_customprefix.cpp +++ b/src/modules/m_customprefix.cpp @@ -19,17 +19,16 @@ #include "inspircd.h" -class CustomPrefixMode : public ModeHandler +class CustomPrefixMode : public PrefixMode { public: reference tag; bool depriv; CustomPrefixMode(Module* parent, ConfigTag* Tag) - : ModeHandler(parent, Tag->getString("name"), 0, PARAM_ALWAYS, MODETYPE_CHANNEL), tag(Tag) + : PrefixMode(parent, Tag->getString("name"), 0) + , tag(Tag) { - list = true; - m_paramtype = TR_NICK; std::string v = tag->getString("prefix"); prefix = v.c_str()[0]; v = tag->getString("letter"); @@ -45,11 +44,6 @@ class CustomPrefixMode : public ModeHandler return MOD_RES_ALLOW; return MOD_RES_PASSTHRU; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - return MODEACTION_ALLOW; - } }; class ModuleCustomPrefix : public Module diff --git a/src/modules/m_ojoin.cpp b/src/modules/m_ojoin.cpp index 54c7bfa73..0a5a57f40 100644 --- a/src/modules/m_ojoin.cpp +++ b/src/modules/m_ojoin.cpp @@ -84,16 +84,14 @@ class CommandOjoin : public SplitCommand /** channel mode +Y */ -class NetworkPrefix : public ModeHandler +class NetworkPrefix : public PrefixMode { public: NetworkPrefix(Module* parent, char NPrefix) - : ModeHandler(parent, "official-join", 'Y', PARAM_ALWAYS, MODETYPE_CHANNEL) + : PrefixMode(parent, "official-join", 'Y') { - list = true; prefix = NPrefix; levelrequired = INT_MAX; - m_paramtype = TR_NICK; prefixrank = NETWORK_VALUE; } @@ -106,12 +104,6 @@ class NetworkPrefix : public ModeHandler return MOD_RES_PASSTHRU; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - return MODEACTION_ALLOW; - } - }; class ModuleOjoin : public Module diff --git a/src/modules/m_operprefix.cpp b/src/modules/m_operprefix.cpp index 23390baea..3d2a34bdb 100644 --- a/src/modules/m_operprefix.cpp +++ b/src/modules/m_operprefix.cpp @@ -26,32 +26,16 @@ #define OPERPREFIX_VALUE 1000000 -class OperPrefixMode : public ModeHandler +class OperPrefixMode : public PrefixMode { public: - OperPrefixMode(Module* Creator) : ModeHandler(Creator, "operprefix", 'y', PARAM_ALWAYS, MODETYPE_CHANNEL) + OperPrefixMode(Module* Creator) : PrefixMode(Creator, "operprefix", 'y') { std::string pfx = ServerInstance->Config->ConfValue("operprefix")->getString("prefix", "!"); - list = true; prefix = pfx.empty() ? '!' : pfx[0]; - levelrequired = OPERPREFIX_VALUE; - m_paramtype = TR_NICK; + levelrequired = INT_MAX; prefixrank = OPERPREFIX_VALUE; } - - ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding) - { - if (IS_SERVER(source) || ServerInstance->ULine(source->server)) - return MODEACTION_ALLOW; - else - { - if (channel) - source->WriteNumeric(ERR_CHANOPRIVSNEEDED, "%s %s :Only servers are permitted to change channel mode '%c'", source->nick.c_str(), channel->name.c_str(), 'y'); - return MODEACTION_DENY; - } - } - - bool NeedsOper() { return true; } }; class ModuleOperPrefixMode; -- 2.39.5