diff options
| author | 2023-07-01 13:43:14 +0100 | |
|---|---|---|
| committer | 2023-07-01 14:01:21 +0100 | |
| commit | 65a0c1430e86ac7a65c9cf51ca6217d48d286e10 (patch) | |
| tree | 5a5b7f4ce6017370db79ad24918ea95904eb638e /src/modules/m_services.cpp | |
| parent | Reorder the types in the services module. (diff) | |
Merge the svshold module into the services module.
Diffstat (limited to 'src/modules/m_services.cpp')
| -rw-r--r-- | src/modules/m_services.cpp | 158 |
1 files changed, 157 insertions, 1 deletions
diff --git a/src/modules/m_services.cpp b/src/modules/m_services.cpp index 9b429711c..19ba5b913 100644 --- a/src/modules/m_services.cpp +++ b/src/modules/m_services.cpp @@ -19,6 +19,9 @@ #include "inspircd.h" #include "modules/account.h" +#include "modules/stats.h" +#include "timeutils.h" +#include "xline.h" enum { @@ -90,23 +93,146 @@ public: } }; +class SVSHold final + : public XLine +{ +private: + std::string nickname; + +public: + SVSHold(time_t settime, unsigned long period, const std::string& setter, const std::string& message, const std::string& nick) + : XLine(settime, period, setter, message, "SVSHOLD") + , nickname(nick) + { + } + + const std::string& Displayable() const override + { + return nickname; + } + + void DisplayExpiry() override + { + // SVSHOLDs do not generate any messages. + } + + bool Matches(User* user) const override + { + return irc::equals(user->nick, nickname); + } + + bool Matches(const std::string& text) const override + { + return irc::equals(nickname, text): + } +}; + +class SVSHoldFactory final + : public XLineFactory +{ +public: + SVSHoldFactory() + : XLineFactory("SVSHOLD") + { + } + + XLine* Generate(time_t settime, unsigned long duration, const std::string& source, const std::string& reason, const std::string& nick) override + { + return new SVSHold(settime, duration, source, reason, nick); + } + + bool AutoApplyToUserList(XLine* x) override + { + return false; + } +}; + +class CommandSVSHold final + : public Command +{ +public: + CommandSVSHold(Module* Creator) + : Command(Creator, "SVSHOLD", 1) + { + // No need to set any privs because they're not checked for remote users. + } + + CmdResult Handle(User* user, const Params& parameters) + { + // The command can only be executed by remote services servers. + if (!IS_LOCAL(user) || !user->server->IsService()) + return CmdResult::FAILURE; + + if (parameters.size() == 1) + { + // :36DAAAAAA SVSHOLD ChanServ + std::string reason; + return ServerInstance->XLines->DelLine(parameters[0], "SVSHOLD", reason, user) ? CmdResult::SUCCESS : CmdResult::FAILURE; + } + + if (parameters.size() == 3) + { + /// :36DAAAAAA SVSHOLD NickServ 86400 :Reserved for services + /// :36DAAAAAA SVSHOLD NickServ 1d :Reserved for services + unsigned long duration; + if (!Duration::TryFrom(parameters[1], duration)) + return CmdResult::FAILURE; + + auto* svshold = new SVSHold(ServerInstance->Time(), duration, user->nick, parameters[2], parameters[0]); + return ServerInstance->XLines->AddLine(svshold, user) ? CmdResult::SUCCESS : CmdResult::FAILURE; + } + + return CmdResult::FAILURE; + } + + RouteDescriptor GetRouting(User* user, const Params& parameters) override + { + return ROUTE_BROADCAST; + } +}; + class ModuleServices final : public Module + , public Stats::EventListener { private: + Account::API accountapi; RegisteredChannel registeredcmode; RegisteredUser registeredumode; ServProtect servprotectmode; + SVSHoldFactory svsholdfactory; + CommandSVSHold svsholdcmd; + bool accountoverrideshold; public: ModuleServices() - : Module(VF_VENDOR, "Provides support for integrating with a services server.") + : Module(VF_COMMON | VF_VENDOR, "Provides support for integrating with a services server.") + , Stats::EventListener(this) + , accountapi(this) , registeredcmode(this) , registeredumode(this) , servprotectmode(this) + , svsholdcmd(this) { } + ~ModuleServices() override + { + ServerInstance->XLines->DelAll("SVSHOLD"); + ServerInstance->XLines->UnregisterFactory(&svsholdfactory); + } + + void init() override + { + ServerInstance->XLines->RegisterFactory(&svsholdfactory); + } + + void ReadConfig(ConfigStatus& status) override + { + const auto& tag = ServerInstance->Config->ConfValue("services"); + accountoverrideshold = tag->getBool("accountoverrideshold"); + } + ModResult OnKill(User* source, User* dest, const std::string& reason) override { if (!source) @@ -145,6 +271,15 @@ public: return MOD_RES_PASSTHRU; } + ModResult OnStats(Stats::Context& stats) override + { + if (stats.GetSymbol() != 'S') + return MOD_RES_PASSTHRU; + + ServerInstance->XLines->InvokeStats("SVSHOLD", stats); + return MOD_RES_DENY; + } + ModResult OnUserPreKick(User* source, Membership* memb, const std::string& reason) override { if (memb->user->IsModeSet(servprotectmode)) @@ -155,6 +290,27 @@ public: return MOD_RES_PASSTHRU; } + ModResult OnUserPreNick(LocalUser* user, const std::string& newnick) override + { + auto* svshold = ServerInstance->XLines->MatchesLine("SVSHOLD", newnick); + if (!svshold) + return MOD_RES_PASSTHRU; + + if (accountoverrideshold && accountapi) + { + Account::NickList* nicks = accountapi->GetAccountNicks(user); + if (nicks && nicks->find(svshold->Displayable()) != nicks->end()) + { + std::string reason; + ServerInstance->XLines->DelLine(svshold, reason, user); + return MOD_RES_PASSTHRU; + } + } + + user->WriteNumeric(ERR_ERRONEUSNICKNAME, newnick, INSP_FORMAT("Services reserved nickname: {}", svshold->reason)); + return MOD_RES_DENY; + } + void OnUserPostNick(User* user, const std::string& oldnick) override { if (user->IsModeSet(registeredumode) && irc::equals(oldnick, user->nick)) |
