/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2022 iwalkalone * 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" #include "modules/exemption.h" #include "numerichelper.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); } bool 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; CheckExemption::EventProvider exemptionprov; ModResult HandleMessage(User* user, const MessageTarget& target); 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) , exemptionprov(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; }; bool 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 true; } 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); } ModResult ModuleDelayMsg::OnUserPreTagMessage(User* user, const MessageTarget& target, CTCTags::TagMessageDetails& details) { return HandleMessage(user, target); } ModResult ModuleDelayMsg::HandleMessage(User* user, const MessageTarget& target) { if (!IS_LOCAL(user) || target.type != MessageTarget::TYPE_CHANNEL) 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()) { ModResult res = exemptionprov.Check(user, channel, "delaymsg"); if (res == MOD_RES_ALLOW) return MOD_RES_PASSTHRU; if (user->HasPrivPermission("channels/ignore-delaymsg")) return MOD_RES_PASSTHRU; const std::string message = INSP_FORMAT("You cannot send messages to this channel until you have been a member for {} 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; } MODULE_INIT(ModuleDelayMsg)