inspircd/src/modules/m_knock.cpp

182 lines
4.9 KiB
C++
Raw Normal View History

/*
* InspIRCd -- Internet Relay Chat Daemon
*
2020-01-11 22:02:47 +00:00
* Copyright (C) 2017 B00mX0r <b00mx0r@aureus.pw>
2022-04-28 18:49:16 +01:00
* Copyright (C) 2013, 2018, 2020, 2022 Sadie Powell <sadie@witchery.services>
2020-01-11 22:02:47 +00:00
* Copyright (C) 2012-2013, 2016, 2018 Attila Molnar <attilamolnar@hush.com>
* Copyright (C) 2012, 2019 Robby <robby@chatbelgie.be>
* Copyright (C) 2009-2010 Daniel De Graaf <danieldg@inspircd.org>
* Copyright (C) 2009 Uli Schlachter <psychon@inspircd.org>
* Copyright (C) 2007 Robin Burchell <robin+git@viroteck.net>
2020-01-11 22:02:47 +00:00
* Copyright (C) 2007 Dennis Friis <peavey@inspircd.org>
2021-03-05 02:04:16 +00:00
* Copyright (C) 2004, 2006, 2008, 2010 Craig Edwards <brain@inspircd.org>
*
* 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/>.
*/
#include "inspircd.h"
#include "modules/invite.h"
2018-01-27 12:24:47 +00:00
enum
{
// From UnrealIRCd.
ERR_CANNOTKNOCK = 480,
// From ircd-ratbox.
RPL_KNOCK = 710,
RPL_KNOCKDLVR = 711,
ERR_CHANOPEN = 713,
ERR_KNOCKONCHAN = 714
2018-01-27 12:24:47 +00:00
};
// Actions which can be taken when a user knocks on a channel.
enum KnockNotify : uint8_t
{
// Send a notice when a user knocks on a channel.
KN_SEND_NOTICE = 1,
// Send a numeric when a user knocks on a channel.
KN_SEND_NUMERIC = 2,
// Send a notice and a numeric when a user knocks on a channel.
KN_SEND_BOTH = KN_SEND_NOTICE | KN_SEND_NUMERIC,
};
/** Handles the /KNOCK command
*/
2021-10-01 05:15:29 +01:00
class CommandKnock final
: public Command
{
2022-04-26 17:05:12 +01:00
private:
SimpleChannelMode& noknockmode;
ChanModeReference inviteonlymode;
Invite::API inviteapi;
public:
int notify;
CommandKnock(Module* Creator, SimpleChannelMode& Noknockmode)
: Command(Creator,"KNOCK", 2, 2)
, noknockmode(Noknockmode)
, inviteonlymode(Creator, "inviteonly")
, inviteapi(Creator)
{
syntax = { "<channel> :<reason>" };
Penalty = 5;
}
CmdResult Handle(User* user, const Params& parameters) override
{
Channel* c = ServerInstance->Channels.Find(parameters[0]);
if (!c)
{
user->WriteNumeric(Numerics::NoSuchChannel(parameters[0]));
return CmdResult::FAILURE;
}
if (c->HasUser(user))
{
user->WriteNumeric(ERR_KNOCKONCHAN, c->name, InspIRCd::Format("Can't KNOCK on %s, you are already on that channel.", c->name.c_str()));
return CmdResult::FAILURE;
}
if (c->IsModeSet(noknockmode))
{
2018-01-27 12:24:47 +00:00
user->WriteNumeric(ERR_CANNOTKNOCK, InspIRCd::Format("Can't KNOCK on %s, +K is set.", c->name.c_str()));
return CmdResult::FAILURE;
}
if (!c->IsModeSet(inviteonlymode))
{
user->WriteNumeric(ERR_CHANOPEN, c->name, InspIRCd::Format("Can't KNOCK on %s, channel is not invite only so knocking is pointless!", c->name.c_str()));
return CmdResult::FAILURE;
}
// Work out who we should send the knock to.
char status;
switch (inviteapi->GetAnnounceState())
{
case Invite::ANNOUNCE_ALL:
{
status = 0;
break;
}
case Invite::ANNOUNCE_DYNAMIC:
{
PrefixMode* mh = ServerInstance->Modes.FindNearestPrefixMode(HALFOP_VALUE);
status = mh->GetPrefix() ? mh->GetPrefix() : '@';
break;
}
default:
{
status = '@';
break;
}
}
if (notify & KN_SEND_NOTICE)
{
c->WriteNotice(InspIRCd::Format("User %s is KNOCKing on %s (%s)", user->nick.c_str(), c->name.c_str(), parameters[1].c_str()), status);
user->WriteNotice("KNOCKing on " + c->name);
}
if (notify & KN_SEND_NUMERIC)
{
Numeric::Numeric numeric(RPL_KNOCK);
numeric.push(c->name).push(user->GetFullHost()).push("is KNOCKing: " + parameters[1]);
ClientProtocol::Messages::Numeric numericmsg(numeric, c->name);
c->Write(ServerInstance->GetRFCEvents().numeric, numericmsg, status);
user->WriteNumeric(RPL_KNOCKDLVR, c->name, "KNOCKing on channel");
}
return CmdResult::SUCCESS;
}
RouteDescriptor GetRouting(User* user, const Params& parameters) override
{
return ROUTE_OPT_BCAST;
}
};
2021-10-01 04:37:03 +01:00
class ModuleKnock final
: public Module
{
SimpleChannelMode kn;
CommandKnock cmd;
public:
ModuleKnock()
2020-04-11 14:00:48 +01:00
: Module(VF_VENDOR | VF_OPTCOMMON, "Adds the /KNOCK command which allows users to request access to an invite-only channel and channel mode K (noknock) which allows channels to disable usage of this command.")
, kn(this, "noknock", 'K')
, cmd(this, kn)
{
}
void ReadConfig(ConfigStatus& status) override
{
auto tag = ServerInstance->Config->ConfValue("knock");
cmd.notify = tag->getEnum("notify", KN_SEND_NOTICE, {
{ "both", KN_SEND_BOTH },
{ "notice", KN_SEND_NOTICE },
{ "numeric", KN_SEND_NUMERIC },
});
}
};
MODULE_INIT(ModuleKnock)