# rank A numeric rank for this prefix, defining what permissions it gives.
# The rank of voice, halfop and op is 10000, 20000, and 30000,
# respectively.
-# ranktoset The numeric rank required to set/unset this mode. Defaults to rank.
+# ranktoset The numeric rank required to set this mode. Defaults to rank.
+# ranktounset The numeric rank required to unset this mode. Defaults to ranktoset.
# depriv Can you remove the mode from yourself? Defaults to yes.
#<customprefix name="founder" letter="q" prefix="~" rank="50000" ranktoset="50000">
#<customprefix name="admin" letter="a" prefix="&" rank="40000" ranktoset="50000">
ModeChannelOp()
: PrefixMode(NULL, "op", 'o', OP_VALUE, '@')
{
- levelrequired = OP_VALUE;
+ ranktoset = ranktounset = OP_VALUE;
}
};
ModeChannelVoice()
: PrefixMode(NULL, "voice", 'v', VOICE_VALUE, '+')
{
- levelrequired = HALFOP_VALUE;
+ ranktoset = ranktounset = HALFOP_VALUE;
}
};
*/
const Class type_id;
- /** The prefix char needed on channel to use this mode,
- * only checked for channel modes
- */
- int levelrequired;
+ /** The prefix rank required to set this mode on channels. */
+ unsigned int ranktoset;
+
+ /** The prefix rank required to unset this mode on channels. */
+ unsigned int ranktounset;
public:
/**
*/
virtual void RemoveMode(Channel* channel, Modes::ChangeList& changelist);
- inline unsigned int GetLevelRequired() const { return levelrequired; }
+ /** Retrieves the level required to modify this mode.
+ * @param adding Whether the mode is being added or removed.
+ */
+ inline unsigned int GetLevelRequired(bool adding) const
+ {
+ return adding ? ranktoset : ranktounset;
+ }
friend class ModeParser;
};
/** If this flag is set then the mode change will be subject to access checks.
* For more information see the documentation of the PrefixMode class,
- * ModeHandler::levelrequired and ModeHandler::AccessCheck().
+ * ModeHandler::ranktoset and ModeHandler::AccessCheck().
* Modules may explicitly allow a mode change regardless of this flag by returning
* MOD_RES_ALLOW from the OnPreMode hook. Only affects channel mode changes.
*/
for (std::string::size_type i = 0; i < memb->modes.length(); i++)
{
ModeHandler* mh = ServerInstance->Modes->FindMode(memb->modes[i], MODETYPE_CHANNEL);
- if (mh && mh->GetLevelRequired() > req)
- req = mh->GetLevelRequired();
+ if (mh && mh->GetLevelRequired(true) > req)
+ req = mh->GetLevelRequired(true);
}
if (them < req)
#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)
{
}
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
public:
AuditoriumMode(Module* Creator) : SimpleChannelModeHandler(Creator, "auditorium", 'u')
{
- levelrequired = OP_VALUE;
+ ranktoset = ranktounset = OP_VALUE;
}
};
public:
AutoOpList(Module* Creator) : ListModeBase(Creator, "autoop", 'w', "End of Channel Access List", 910, 911, true)
{
- levelrequired = OP_VALUE;
+ ranktoset = ranktounset = OP_VALUE;
tidy = false;
}
std::string dummy;
if (mh->AccessCheck(source, channel, dummy, true) == MOD_RES_DENY)
return MOD_RES_DENY;
- if (mh->GetLevelRequired() > mylevel)
+ if (mh->GetLevelRequired(true) > mylevel)
{
source->WriteNumeric(ERR_CHANOPRIVSNEEDED, channel->name, InspIRCd::Format("You must be able to set mode '%s' to include it in an autoop", mid.c_str()));
return MOD_RES_DENY;
prefix = v.c_str()[0];
v = tag->getString("letter");
mode = v.c_str()[0];
- levelrequired = tag->getInt("ranktoset", prefixrank);
+ ranktoset = tag->getInt("ranktoset", prefixrank, prefixrank, UINT_MAX);
+ ranktounset = tag->getInt("ranktounset", ranktoset, ranktoset, UINT_MAX);
depriv = tag->getBool("depriv", true);
}
public:
DelayJoinMode(Module* Parent) : ModeHandler(Parent, "delayjoin", 'D', PARAM_NONE, MODETYPE_CHANNEL)
{
- levelrequired = OP_VALUE;
+ ranktoset = ranktounset = OP_VALUE;
}
ModeAction OnModeChange(User* source, User* dest, Channel* channel, std::string ¶meter, bool adding);
: ParamMode<DelayMsgMode, LocalIntExt>(Parent, "delaymsg", 'd')
, jointime("delaymsg", ExtensionItem::EXT_MEMBERSHIP, Parent)
{
- levelrequired = OP_VALUE;
+ ranktoset = ranktounset = OP_VALUE;
}
bool ResolveModeConflict(std::string &their_param, const std::string &our_param, Channel*)
NetworkPrefix(Module* parent, char NPrefix)
: PrefixMode(parent, "official-join", 'Y', NETWORK_VALUE, NPrefix)
{
- levelrequired = INT_MAX;
+ ranktoset = ranktounset = UINT_MAX;
}
ModResult AccessCheck(User* source, Channel* channel, std::string ¶meter, bool adding)
: PrefixMode(Creator, "operprefix", 'y', OPERPREFIX_VALUE)
{
prefix = ServerInstance->Config->ConfValue("operprefix")->getString("prefix", "!", 1, 1)[0];
- levelrequired = INT_MAX;
+ ranktoset = ranktounset = UINT_MAX;
}
};
for (Modes::ChangeList::List::const_iterator i = list.begin(); i != list.end(); ++i)
{
ModeHandler* mh = i->mh;
- if (mh->GetLevelRequired() > userlevel)
+ if (mh->GetLevelRequired(i->adding) > userlevel)
return true;
}
return false;
return CMD_FAILURE;
}
- if (chan->GetPrefixValue(user) < mh->GetLevelRequired())
+ if (chan->GetPrefixValue(user) < mh->GetLevelRequired(false))
{
user->WriteNotice("You do not have access to unset " + ConvToStr(modeletter) + " on " + chan->name + ".");
return CMD_FAILURE;