Move the OnCheckExemption hook out of the core.
DEFINE_HANDLER2(GenRandomHandler, void, char*, size_t);
DEFINE_HANDLER1(IsIdentHandler, bool, const std::string&);
DEFINE_HANDLER1(IsChannelHandler, bool, const std::string&);
-DEFINE_HANDLER3(OnCheckExemptionHandler, ModResult, User*, Channel*, const std::string&);
/** The main class of the irc server.
* This class contains instances of all the other classes in this software.
IsNickHandler HandleIsNick;
IsIdentHandler HandleIsIdent;
- OnCheckExemptionHandler HandleOnCheckExemption;
IsChannelHandler HandleIsChannel;
GenRandomHandler HandleGenRandom;
*/
InspIRCd(int argc, char** argv);
- /** Called to check whether a channel restriction mode applies to a user
- * @param User that is attempting some action
- * @param Channel that the action is being performed on
- * @param Action name
- */
- caller3<ModResult, User*, Channel*, const std::string&> OnCheckExemption;
-
/** Prepare the ircd for restart or shutdown.
* This function unloads all modules which can be unloaded,
* closes all open sockets, and closes the logfile.
--- /dev/null
+/*
+ * InspIRCd -- Internet Relay Chat Daemon
+ *
+ * Copyright (C) 2016-2017 Peter Powell <petpow@saberuk.com>
+ *
+ * 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
+ * License as published by the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#pragma once
+
+#include "event.h"
+
+namespace CheckExemption
+{
+ class EventListener;
+ class EventProvider;
+}
+
+class CheckExemption::EventListener
+ : public Events::ModuleEventListener
+{
+ protected:
+ EventListener(Module* mod)
+ : ModuleEventListener(mod, "event/exemption")
+ {
+ }
+
+ public:
+ /** Called when checking if a user is exempt from something.
+ * @param user The user to check exemption for.
+ * @param chan The channel to check exemption on.
+ * @param restriction The restriction to check for.
+ * @return Either MOD_RES_ALLOW to confirm an exemption, MOD_RES_DENY to deny an exemption,
+ * or MOD_RES_PASSTHRU to let another module handle the event.
+ */
+ virtual ModResult OnCheckExemption(User* user, Channel* chan, const std::string& restriction) = 0;
+};
+
+class CheckExemption::EventProvider
+ : public Events::ModuleEventProvider
+{
+ public:
+ EventProvider(Module* mod)
+ : ModuleEventProvider(mod, "event/exemption")
+ {
+ }
+};
CommandTopic::CommandTopic(Module* parent)
: SplitCommand(parent, "TOPIC", 1, 2)
+ , exemptionprov(parent)
, secretmode(parent, "secret")
, topiclockmode(parent, "topiclock")
{
user->WriteNumeric(ERR_NOTONCHANNEL, c->name, "You're not on that channel!");
return CMD_FAILURE;
}
- if (c->IsModeSet(topiclockmode) && !ServerInstance->OnCheckExemption(user, c, "topiclock").check(c->GetPrefixValue(user) >= HALFOP_VALUE))
+ if (c->IsModeSet(topiclockmode))
{
- user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, "You do not have access to change the topic on this channel");
- return CMD_FAILURE;
+ ModResult MOD_RESULT;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, MOD_RESULT, (user, c, "topiclock"));
+ if (!MOD_RESULT.check(c->GetPrefixValue(user) >= HALFOP_VALUE))
+ {
+ user->WriteNumeric(ERR_CHANOPRIVSNEEDED, c->name, "You do not have access to change the topic on this channel");
+ return CMD_FAILURE;
+ }
}
}
#include "invite.h"
#include "listmode.h"
-class CoreModChannel : public Module
+class CoreModChannel : public Module, public CheckExemption::EventListener
{
Invite::APIImpl invapi;
CommandInvite cmdinvite;
CommandKick cmdkick;
CommandNames cmdnames;
CommandTopic cmdtopic;
+ insp::flat_map<std::string, char> exemptions;
ModResult IsInvited(User* user, Channel* chan)
{
public:
CoreModChannel()
- : invapi(this)
- , cmdinvite(this, invapi), cmdjoin(this), cmdkick(this), cmdnames(this), cmdtopic(this)
+ : CheckExemption::EventListener(this)
+ , invapi(this)
+ , cmdinvite(this, invapi)
+ , cmdjoin(this)
+ , cmdkick(this)
+ , cmdnames(this)
+ , cmdtopic(this)
{
}
for (unsigned int i = 0; i < sizeof(events)/sizeof(Implementation); i++)
ServerInstance->Modules.Detach(events[i], this);
}
+
+ std::string current;
+ irc::spacesepstream defaultstream(optionstag->getString("exemptchanops"));
+ insp::flat_map<std::string, char> exempts;
+ while (defaultstream.GetToken(current))
+ {
+ std::string::size_type pos = current.find(':');
+ if (pos == std::string::npos || (pos + 2) > current.size())
+ throw ModuleException("Invalid exemptchanops value '" + current + "' at " + optionstag->getTagLocation());
+
+ const std::string restriction = current.substr(0, pos);
+ const char prefix = current[pos + 1];
+
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Exempting prefix %c from %s", prefix, restriction.c_str());
+ exempts[restriction] = prefix;
+ }
+ exemptions.swap(exempts);
}
void On005Numeric(std::map<std::string, std::string>& tokens) CXX11_OVERRIDE
invapi.RemoveAll(chan);
}
+ ModResult OnCheckExemption(User* user, Channel* chan, const std::string& restriction) CXX11_OVERRIDE
+ {
+ if (!exemptions.count(restriction))
+ return MOD_RES_PASSTHRU;
+
+ unsigned int mypfx = chan->GetPrefixValue(user);
+ char minmode = exemptions[restriction];
+
+ PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(minmode);
+ if (mh && mypfx >= mh->GetPrefixRank())
+ return MOD_RES_ALLOW;
+ if (mh || minmode == '*')
+ return MOD_RES_DENY;
+ return MOD_RES_PASSTHRU;
+ }
+
void Prioritize() CXX11_OVERRIDE
{
ServerInstance->Modules.SetPriority(this, I_OnPostJoin, PRIORITY_FIRST);
#pragma once
#include "inspircd.h"
+#include "modules/exemption.h"
namespace Topic
{
*/
class CommandTopic : public SplitCommand
{
+ CheckExemption::EventProvider exemptionprov;
ChanModeReference secretmode;
ChanModeReference topiclockmode;
output[i] = random();
#endif
}
-
-ModResult OnCheckExemptionHandler::Call(User* user, Channel* chan, const std::string& restriction)
-{
- unsigned int mypfx = chan->GetPrefixValue(user);
- char minmode = 0;
- std::string current;
-
- irc::spacesepstream defaultstream(ServerInstance->Config->ConfValue("options")->getString("exemptchanops"));
-
- while (defaultstream.GetToken(current))
- {
- std::string::size_type pos = current.find(':');
- if (pos == std::string::npos)
- continue;
- if (!current.compare(0, pos, restriction))
- minmode = current[pos+1];
- }
-
- PrefixMode* mh = ServerInstance->Modes->FindPrefixMode(minmode);
- if (mh && mypfx >= mh->GetPrefixRank())
- return MOD_RES_ALLOW;
- if (mh || minmode == '*')
- return MOD_RES_DENY;
- return MOD_RES_PASSTHRU;
-}
GenRandom(&HandleGenRandom),
IsChannel(&HandleIsChannel),
IsNick(&HandleIsNick),
- IsIdent(&HandleIsIdent),
- OnCheckExemption(&HandleOnCheckExemption)
+ IsIdent(&HandleIsIdent)
{
ServerInstance = this;
#include "inspircd.h"
+#include "modules/exemption.h"
class AuditoriumMode : public SimpleChannelModeHandler
{
class ModuleAuditorium : public Module
{
+ CheckExemption::EventProvider exemptionprov;
AuditoriumMode aum;
bool OpsVisible;
bool OpsCanSee;
bool OperCanSee;
public:
- ModuleAuditorium() : aum(this)
+ ModuleAuditorium()
+ : exemptionprov(this)
+ , aum(this)
{
}
if (!memb->chan->IsModeSet(&aum))
return true;
- ModResult res = ServerInstance->OnCheckExemption(memb->user, memb->chan, "auditorium-vis");
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (memb->user, memb->chan, "auditorium-vis"));
return res.check(OpsVisible && memb->getRank() >= OP_VALUE);
}
return true;
// Can you see the list by permission?
- ModResult res = ServerInstance->OnCheckExemption(issuer,memb->chan,"auditorium-see");
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (issuer, memb->chan, "auditorium-see"));
if (res.check(OpsCanSee && memb->chan->GetPrefixValue(issuer) >= OP_VALUE))
return true;
#include "inspircd.h"
+#include "modules/exemption.h"
/** Handles the +B channel mode
class ModuleBlockCAPS : public Module
{
+ CheckExemption::EventProvider exemptionprov;
BlockCaps bc;
unsigned int percent;
unsigned int minlen;
char capsmap[256];
public:
- ModuleBlockCAPS() : bc(this)
+ ModuleBlockCAPS()
+ : exemptionprov(this)
+ , bc(this)
{
}
return MOD_RES_PASSTHRU;
Channel* c = (Channel*)dest;
- ModResult res = ServerInstance->OnCheckExemption(user,c,"blockcaps");
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, c, "blockcaps"));
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
#include "inspircd.h"
+#include "modules/exemption.h"
/** Handles the +c channel mode
*/
class ModuleBlockColor : public Module
{
+ CheckExemption::EventProvider exemptionprov;
BlockColor bc;
public:
- ModuleBlockColor() : bc(this)
+ ModuleBlockColor()
+ : exemptionprov(this)
+ , bc(this)
{
}
if ((target_type == TYPE_CHANNEL) && (IS_LOCAL(user)))
{
Channel* c = (Channel*)dest;
- ModResult res = ServerInstance->OnCheckExemption(user,c,"blockcolor");
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, c, "blockcolor"));
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
#include "inspircd.h"
+#include "modules/exemption.h"
typedef insp::flat_map<irc::string, irc::string> censor_t;
class ModuleCensor : public Module
{
+ CheckExemption::EventProvider exemptionprov;
censor_t censors;
CensorUser cu;
CensorChannel cc;
public:
- ModuleCensor() : cu(this), cc(this) { }
+ ModuleCensor()
+ : exemptionprov(this)
+ , cu(this)
+ , cc(this)
+ {
+ }
// format of a config entry is <badword text="shit" replace="poo">
ModResult OnUserPreMessage(User* user, void* dest, int target_type, std::string& text, char status, CUList& exempt_list, MessageType msgtype) CXX11_OVERRIDE
{
Channel* c = (Channel*)dest;
active = c->IsModeSet(cc);
- ModResult res = ServerInstance->OnCheckExemption(user,c,"censor");
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, c, "censor"));
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
#include "inspircd.h"
#include "listmode.h"
+#include "modules/exemption.h"
/** Handles channel mode +g
*/
class ModuleChanFilter : public Module
{
+ CheckExemption::EventProvider exemptionprov;
ChanFilter cf;
bool hidemask;
public:
ModuleChanFilter()
- : cf(this)
+ : exemptionprov(this)
+ , cf(this)
{
}
return MOD_RES_PASSTHRU;
Channel* chan = static_cast<Channel*>(dest);
- ModResult res = ServerInstance->OnCheckExemption(user,chan,"filter");
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, chan, "filter"));
if (!IS_LOCAL(user) || res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
#include "inspircd.h"
#include "listmode.h"
+#include "modules/exemption.h"
/** Handles channel mode +X
*/
}
};
-class ExemptHandler : public HandlerBase3<ModResult, User*, Channel*, const std::string&>
+class ExemptHandler : public CheckExemption::EventListener
{
public:
ExemptChanOps ec;
- ExemptHandler(Module* me) : ec(me) {}
+ ExemptHandler(Module* me)
+ : CheckExemption::EventListener(me)
+ , ec(me)
+ {
+ }
PrefixMode* FindMode(const std::string& mid)
{
return mh ? mh->IsPrefixMode() : NULL;
}
- ModResult Call(User* user, Channel* chan, const std::string& restriction)
+ ModResult OnCheckExemption(User* user, Channel* chan, const std::string& restriction) CXX11_OVERRIDE
{
unsigned int mypfx = chan->GetPrefixValue(user);
std::string minmode;
if (mh || minmode == "*")
return MOD_RES_DENY;
- return ServerInstance->HandleOnCheckExemption.Call(user, chan, restriction);
+ return MOD_RES_PASSTHRU;
}
};
{
}
- void init() CXX11_OVERRIDE
- {
- ServerInstance->OnCheckExemption = &eh;
- }
-
- ~ModuleExemptChanOps()
- {
- ServerInstance->OnCheckExemption = &ServerInstance->HandleOnCheckExemption;
- }
-
Version GetVersion() CXX11_OVERRIDE
{
return Version("Provides the ability to allow channel operators to be exempt from certain modes.",VF_VENDOR);
#include "inspircd.h"
+#include "modules/exemption.h"
/** Holds flood settings and state for mode +f
*/
class ModuleMsgFlood : public Module
{
+ CheckExemption::EventProvider exemptionprov;
MsgFlood mf;
public:
ModuleMsgFlood()
- : mf(this)
+ : exemptionprov(this)
+ , mf(this)
{
}
if ((!IS_LOCAL(user)) || !dest->IsModeSet(mf))
return MOD_RES_PASSTHRU;
- if (ServerInstance->OnCheckExemption(user,dest,"flood") == MOD_RES_ALLOW)
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, dest, "flood"));
+ if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
floodsettings *f = mf.ext.get(dest);
#include "inspircd.h"
+#include "modules/exemption.h"
// The number of seconds nickname changing will be blocked for.
static unsigned int duration;
class ModuleNickFlood : public Module
{
+ CheckExemption::EventProvider exemptionprov;
NickFlood nf;
public:
ModuleNickFlood()
- : nf(this)
+ : exemptionprov(this)
+ , nf(this)
{
}
nickfloodsettings *f = nf.ext.get(channel);
if (f)
{
- res = ServerInstance->OnCheckExemption(user,channel,"nickflood");
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, channel, "nickflood"));
if (res == MOD_RES_ALLOW)
continue;
nickfloodsettings *f = nf.ext.get(channel);
if (f)
{
- res = ServerInstance->OnCheckExemption(user,channel,"nickflood");
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, channel, "nickflood"));
if (res == MOD_RES_ALLOW)
return;
#include "inspircd.h"
+#include "modules/exemption.h"
class NoCTCP : public SimpleChannelModeHandler
{
class ModuleNoCTCP : public Module
{
+ CheckExemption::EventProvider exemptionprov;
NoCTCP nc;
public:
ModuleNoCTCP()
- : nc(this)
+ : exemptionprov(this)
+ , nc(this)
{
}
if ((text.empty()) || (text[0] != '\001') || (!strncmp(text.c_str(),"\1ACTION ",8)))
return MOD_RES_PASSTHRU;
- ModResult res = ServerInstance->OnCheckExemption(user,c,"noctcp");
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, c, "noctcp"));
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
#include "inspircd.h"
+#include "modules/exemption.h"
class NoNicks : public SimpleChannelModeHandler
{
class ModuleNoNickChange : public Module
{
+ CheckExemption::EventProvider exemptionprov;
NoNicks nn;
bool override;
public:
- ModuleNoNickChange() : nn(this)
+ ModuleNoNickChange()
+ : exemptionprov(this)
+ , nn(this)
{
}
{
Channel* curr = (*i)->chan;
- ModResult res = ServerInstance->OnCheckExemption(user,curr,"nonick");
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, curr, "nonick"));
if (res == MOD_RES_ALLOW)
continue;
#include "inspircd.h"
+#include "modules/exemption.h"
class NoNotice : public SimpleChannelModeHandler
{
class ModuleNoNotice : public Module
{
+ CheckExemption::EventProvider exemptionprov;
NoNotice nt;
public:
ModuleNoNotice()
- : nt(this)
+ : exemptionprov(this)
+ , nt(this)
{
}
Channel* c = (Channel*)dest;
if (!c->GetExtBanStatus(user, 'T').check(!c->IsModeSet(nt)))
{
- res = ServerInstance->OnCheckExemption(user,c,"nonotice");
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, c, "nonotice"));
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
else
#include "inspircd.h"
+#include "modules/exemption.h"
class ChannelSettings
{
class RepeatModule : public Module
{
+ CheckExemption::EventProvider exemptionprov;
RepeatMode rm;
public:
- RepeatModule() : rm(this) {}
+ RepeatModule()
+ : exemptionprov(this)
+ , rm(this)
+ {
+ }
void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE
{
if (!memb)
return MOD_RES_PASSTHRU;
- if (ServerInstance->OnCheckExemption(user, chan, "repeat") == MOD_RES_ALLOW)
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, chan, "repeat"));
+ if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
if (rm.MatchLine(memb, settings, text))
#include "inspircd.h"
#include "modules/account.h"
+#include "modules/exemption.h"
/** Channel mode +r - mark a channel as identified
*/
class ModuleServicesAccount : public Module, public Whois::EventListener
{
+ CheckExemption::EventProvider exemptionprov;
AChannel_R m1;
AChannel_M m2;
AUser_R m3;
public:
ModuleServicesAccount()
: Whois::EventListener(this)
+ , exemptionprov(this)
, m1(this), m2(this), m3(this), m4(this), m5(this)
, accountname(this)
, checking_ban(false)
if (target_type == TYPE_CHANNEL)
{
Channel* c = (Channel*)dest;
- ModResult res = ServerInstance->OnCheckExemption(user,c,"regmoderated");
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, c, "regmoderated"));
if (c->IsModeSet(m2) && !is_registered && res != MOD_RES_ALLOW)
{
#include "inspircd.h"
+#include "modules/exemption.h"
/** Handles channel mode +S
*/
class ModuleStripColor : public Module
{
+ CheckExemption::EventProvider exemptionprov;
ChannelStripColor csc;
UserStripColor usc;
public:
- ModuleStripColor() : csc(this), usc(this)
+ ModuleStripColor()
+ : exemptionprov(this)
+ , csc(this)
+ , usc(this)
{
}
else if (target_type == TYPE_CHANNEL)
{
Channel* t = (Channel*)dest;
- ModResult res = ServerInstance->OnCheckExemption(user,t,"stripcolor");
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, t, "stripcolor"));
if (res == MOD_RES_ALLOW)
return MOD_RES_PASSTHRU;
if (!IS_LOCAL(user))
return;
- bool active = channel->GetExtBanStatus(user, 'S').check(!user->IsModeSet(csc))
- && ServerInstance->OnCheckExemption(user, channel, "stripcolor") != MOD_RES_ALLOW;
-
- if (active)
+ if (channel->GetExtBanStatus(user, 'S').check(!user->IsModeSet(csc)))
{
- InspIRCd::StripColor(partmessage);
+ ModResult res;
+ FIRST_MOD_RESULT_CUSTOM(exemptionprov, CheckExemption::EventListener, OnCheckExemption, res, (user, channel, "stripcolor"));
+
+ if (res != MOD_RES_ALLOW)
+ InspIRCd::StripColor(partmessage);
}
}