/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013, 2017-2020 Sadie Powell * Copyright (C) 2012-2015 Attila Molnar * Copyright (C) 2012, 2019 Robby * Copyright (C) 2009-2010 Daniel De Graaf * * 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 . */ #include "inspircd.h" #include "modules/ctctags.h" class DelayMsgMode final : public ParamMode { public: IntExtItem jointime; DelayMsgMode(Module* Parent) : ParamMode(Parent, "delaymsg", 'd') , jointime(Parent, "delaymsg", ExtensionType::MEMBERSHIP) { ranktoset = ranktounset = OP_VALUE; syntax = ""; } bool ResolveModeConflict(const std::string& their_param, const std::string& our_param, Channel*) override { return ConvToNum(their_param) < ConvToNum(our_param); } ModeAction OnSet(User* source, Channel* chan, std::string& parameter) override; void OnUnset(User* source, Channel* chan) override; void SerializeParam(Channel* chan, intptr_t n, std::string& out) { out += ConvToStr(n); } }; class ModuleDelayMsg final : public Module , public CTCTags::EventListener { private: DelayMsgMode djm; bool allownotice; ModResult HandleMessage(User* user, const MessageTarget& target, bool notice); public: ModuleDelayMsg() : Module(VF_VENDOR, "Adds channel mode d (delaymsg) which prevents newly joined users from speaking until the specified number of seconds have passed.") , CTCTags::EventListener(this) , djm(this) { } void OnUserJoin(Membership* memb, bool sync, bool created, CUList&) override; ModResult OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) override; ModResult OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) override; void ReadConfig(ConfigStatus& status) override; }; ModeAction DelayMsgMode::OnSet(User* source, Channel* chan, std::string& parameter) { // Setting a new limit, sanity check intptr_t limit = ConvToNum(parameter); if (limit <= 0) limit = 1; ext.Set(chan, limit); return MODEACTION_ALLOW; } void DelayMsgMode::OnUnset(User* source, Channel* chan) { for (const auto& [_, memb] : chan->GetUsers()) jointime.Unset(memb); } void ModuleDelayMsg::OnUserJoin(Membership* memb, bool sync, bool created, CUList&) { if ((IS_LOCAL(memb->user)) && (memb->chan->IsModeSet(djm))) { djm.jointime.Set(memb, ServerInstance->Time()); } } ModResult ModuleDelayMsg::OnUserPreMessage(User* user, const MessageTarget& target, MessageDetails& details) { return HandleMessage(user, target, details.type == MSG_NOTICE); } ModResult ModuleDelayMsg::OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) { return HandleMessage(user, target, false); } ModResult ModuleDelayMsg::HandleMessage(User* user, const MessageTarget& target, bool notice) { if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; if ((target.type != MessageTarget::TYPE_CHANNEL) || ((!allownotice) && (notice))) return MOD_RES_PASSTHRU; Channel* channel = target.Get(); Membership* memb = channel->GetUser(user); if (!memb) return MOD_RES_PASSTHRU; time_t ts = djm.jointime.Get(memb); if (ts == 0) return MOD_RES_PASSTHRU; intptr_t len = djm.ext.Get(channel); if ((ts + len) > ServerInstance->Time()) { if (channel->GetPrefixValue(user) < VOICE_VALUE) { const std::string message = InspIRCd::Format("You cannot send messages to this channel until you have been a member for %ld seconds.", len); user->WriteNumeric(Numerics::CannotSendTo(channel, message)); return MOD_RES_DENY; } } else { /* Timer has expired, we can stop checking now */ djm.jointime.Unset(memb); } return MOD_RES_PASSTHRU; } void ModuleDelayMsg::ReadConfig(ConfigStatus& status) { auto tag = ServerInstance->Config->ConfValue("delaymsg"); allownotice = tag->getBool("allownotice", true); } MODULE_INIT(ModuleDelayMsg)