diff options
| author | 2024-07-17 00:06:50 +0100 | |
|---|---|---|
| committer | 2024-07-17 00:06:50 +0100 | |
| commit | 889d521e05f2e922683d48c74eb00290e7a2f548 (patch) | |
| tree | b4c56bd4cdf0881601c7e4d6ff571e491af10bf4 /src/modules/m_monitor.cpp | |
| parent | Use std::endian from C++20 in the sha1 module. (diff) | |
| download | inspircd++-889d521e05f2e922683d48c74eb00290e7a2f548.tar.gz inspircd++-889d521e05f2e922683d48c74eb00290e7a2f548.tar.bz2 inspircd++-889d521e05f2e922683d48c74eb00290e7a2f548.zip | |
Shuffle the modules about a bit.
Diffstat (limited to 'src/modules/m_monitor.cpp')
| -rw-r--r-- | src/modules/m_monitor.cpp | 444 |
1 files changed, 0 insertions, 444 deletions
diff --git a/src/modules/m_monitor.cpp b/src/modules/m_monitor.cpp deleted file mode 100644 index 62ffc332d..000000000 --- a/src/modules/m_monitor.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/* - * InspIRCd -- Internet Relay Chat Daemon - * - * Copyright (C) 2022 delthas - * Copyright (C) 2021 Dominic Hamon - * Copyright (C) 2018-2023 Sadie Powell <sadie@witchery.services> - * Copyright (C) 2016 Attila Molnar <attilamolnar@hush.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/>. - */ - - -#include "inspircd.h" -#include "modules/cap.h" -#include "modules/isupport.h" -#include "modules/monitor.h" -#include "numericbuilder.h" - -namespace IRCv3::Monitor -{ - class ExtItem; - struct Entry; - class Manager; - class ManagerInternal; - - typedef std::vector<Entry*> WatchedList; - typedef std::vector<LocalUser*> WatcherList; -} - -struct IRCv3::Monitor::Entry final -{ - WatcherList watchers; - std::string nick; - - void SetNick(const std::string& Nick) - { - nick.clear(); - // We may show this string to other users so do not leak the casing - std::transform(Nick.begin(), Nick.end(), std::back_inserter(nick), ::tolower); - } - - const std::string& GetNick() const { return nick; } -}; - -class IRCv3::Monitor::Manager final -{ - struct ExtData final - { - WatchedList list; - }; - - class ExtItem final - : public ExtensionItem - { - Manager& manager; - - public: - ExtItem(Module* mod, const std::string& extname, Manager& managerref) - : ExtensionItem(mod, extname, ExtensionType::USER) - , manager(managerref) - { - } - - ExtData* Get(User* user, bool create = false) - { - ExtData* extdata = static_cast<ExtData*>(GetRaw(user)); - if ((!extdata) && (create)) - { - extdata = new ExtData; - SetRaw(user, extdata); - } - return extdata; - } - - void Unset(User* user) - { - Delete(user, UnsetRaw(user)); - } - - std::string ToInternal(const Extensible* container, void* item) const noexcept override - { - std::string ret; - const ExtData* extdata = static_cast<ExtData*>(item); - for (const auto* entry : extdata->list) - ret.append(entry->GetNick()).push_back(' '); - if (!ret.empty()) - ret.pop_back(); - return ret; - } - - void FromInternal(Extensible* container, const std::string& value) noexcept override; - - void Delete(Extensible* container, void* item) override - { - delete static_cast<ExtData*>(item); - } - }; - -public: - Manager(Module* mod, const std::string& extname) - : ext(mod, extname, *this) - { - } - - enum WatchResult - { - WR_OK, - WR_TOOMANY, - WR_ALREADYWATCHING, - WR_INVALIDNICK - }; - - WatchResult Watch(LocalUser* user, const std::string& nick, unsigned long maxwatch) - { - if (!ServerInstance->IsNick(nick)) - return WR_INVALIDNICK; - - WatchedList* watched = GetWatchedPriv(user, true); - if (watched->size() >= maxwatch) - return WR_TOOMANY; - - Entry* entry = AddWatcher(nick, user); - if (stdalgo::isin(*watched, entry)) - return WR_ALREADYWATCHING; - - entry->watchers.push_back(user); - watched->push_back(entry); - return WR_OK; - } - - bool Unwatch(LocalUser* user, const std::string& nick) - { - WatchedList* list = GetWatchedPriv(user); - if (!list) - return false; - - bool ret = RemoveWatcher(nick, user, *list); - // If no longer watching any nick unset ext - if (list->empty()) - ext.Unset(user); - return ret; - } - - const WatchedList& GetWatched(LocalUser* user) - { - WatchedList* list = GetWatchedPriv(user); - if (list) - return *list; - return emptywatchedlist; - } - - void UnwatchAll(LocalUser* user) - { - WatchedList* list = GetWatchedPriv(user); - if (!list) - return; - - while (!list->empty()) - { - Entry* entry = list->front(); - RemoveWatcher(entry->GetNick(), user, *list); - } - ext.Unset(user); - } - - WatcherList* GetWatcherList(const std::string& nick) - { - Entry* entry = Find(nick); - if (entry) - return &entry->watchers; - return nullptr; - } - -private: - typedef std::unordered_map<std::string, Entry, irc::insensitive, irc::StrHashComp> NickHash; - - Entry* Find(const std::string& nick) - { - NickHash::iterator it = nicks.find(nick); - if (it != nicks.end()) - return &it->second; - return nullptr; - } - - Entry* AddWatcher(const std::string& nick, LocalUser* user) - { - std::pair<NickHash::iterator, bool> ret = nicks.emplace(nick, Entry()); - Entry& entry = ret.first->second; - if (ret.second) - entry.SetNick(nick); - return &entry; - } - - bool RemoveWatcher(const std::string& nick, LocalUser* user, WatchedList& watchedlist) - { - NickHash::iterator it = nicks.find(nick); - // If nobody is watching this nick the user trying to remove it isn't watching it for sure - if (it == nicks.end()) - return false; - - Entry& entry = it->second; - // Erase from the user's list of watched nicks - if (!stdalgo::vector::swaperase(watchedlist, &entry)) - return false; // User is not watching this nick - - // Erase from the nick's list of watching users - stdalgo::vector::swaperase(entry.watchers, user); - - // If nobody else is watching the nick remove map entry - if (entry.watchers.empty()) - nicks.erase(it); - - return true; - } - - WatchedList* GetWatchedPriv(LocalUser* user, bool create = false) - { - ExtData* extdata = ext.Get(user, create); - if (!extdata) - return nullptr; - return &extdata->list; - } - - NickHash nicks; - ExtItem ext; - WatchedList emptywatchedlist; -}; - -void IRCv3::Monitor::Manager::ExtItem::FromInternal(Extensible* container, const std::string& value) noexcept -{ - if (container->extype != this->extype) - return; - - irc::spacesepstream ss(value); - for (std::string nick; ss.GetToken(nick); ) - manager.Watch(static_cast<LocalUser*>(container), nick, ULONG_MAX); -} - -#ifndef INSPIRCD_MONITOR_MANAGER_ONLY - -enum -{ - RPL_MONONLINE = 730, - RPL_MONOFFLINE = 731, - RPL_MONLIST = 732, - RPL_ENDOFMONLIST = 733, - ERR_MONLISTFULL = 734 -}; - -class CommandMonitor final - : public SplitCommand -{ - typedef Numeric::Builder<> ReplyBuilder; - // Additional penalty for the /MONITOR L and /MONITOR S commands that request a list from the server - static constexpr unsigned int ListPenalty = 3000; - - IRCv3::Monitor::Manager& manager; - - void HandlePlus(LocalUser* user, const std::string& input) - { - ReplyBuilder online(user, RPL_MONONLINE); - ReplyBuilder offline(user, RPL_MONOFFLINE); - irc::commasepstream ss(input); - for (std::string nick; ss.GetToken(nick); ) - { - IRCv3::Monitor::Manager::WatchResult result = manager.Watch(user, nick, maxmonitor); - if (result == IRCv3::Monitor::Manager::WR_TOOMANY) - { - // List is full, send error which includes the remaining nicks that were not processed - user->WriteNumeric(ERR_MONLISTFULL, maxmonitor, fmt::format("{}{}{}", nick, (ss.StreamEnd() ? "" : ","), ss.GetRemaining()), "Monitor list is full"); - break; - } - else if (result != IRCv3::Monitor::Manager::WR_OK) - continue; // Already added or invalid nick - - ReplyBuilder& out = (ServerInstance->Users.FindNick(nick, true) ? online : offline); - out.Add(nick); - } - - online.Flush(); - offline.Flush(); - } - - void HandleMinus(LocalUser* user, const std::string& input) - { - irc::commasepstream ss(input); - for (std::string nick; ss.GetToken(nick); ) - manager.Unwatch(user, nick); - } - -public: - unsigned long maxmonitor; - - CommandMonitor(Module* mod, IRCv3::Monitor::Manager& managerref) - : SplitCommand(mod, "MONITOR", 1) - , manager(managerref) - { - penalty = 2000; - syntax = { "C", "L", "S", "(+|-) <nick>[,<nick>]+" }; - } - - CmdResult HandleLocal(LocalUser* user, const Params& parameters) override - { - char subcmd = toupper(parameters[0][0]); - if (subcmd == '+') - { - if (parameters.size() > 1) - HandlePlus(user, parameters[1]); - } - else if (subcmd == '-') - { - if (parameters.size() > 1) - HandleMinus(user, parameters[1]); - } - else if (subcmd == 'C') - { - manager.UnwatchAll(user); - } - else if (subcmd == 'L') - { - user->CommandFloodPenalty += ListPenalty; - const IRCv3::Monitor::WatchedList& list = manager.GetWatched(user); - ReplyBuilder out(user, RPL_MONLIST); - for (const auto* entry : list) - out.Add(entry->GetNick()); - out.Flush(); - user->WriteNumeric(RPL_ENDOFMONLIST, "End of MONITOR list"); - } - else if (subcmd == 'S') - { - user->CommandFloodPenalty += ListPenalty; - - ReplyBuilder online(user, RPL_MONONLINE); - ReplyBuilder offline(user, RPL_MONOFFLINE); - - for (const auto* entry : manager.GetWatched(user)) - { - ReplyBuilder& out = (ServerInstance->Users.FindNick(entry->GetNick(), true) ? online : offline); - out.Add(entry->GetNick()); - } - - online.Flush(); - offline.Flush(); - } - else - return CmdResult::FAILURE; - - return CmdResult::SUCCESS; - } -}; - -class ModuleMonitor final - : public Module - , public ISupport::EventListener - , public Monitor::APIBase -{ -private: - IRCv3::Monitor::Manager manager; - CommandMonitor cmd; - Cap::Capability extendedcap; - - void SendAlert(unsigned int numeric, const std::string& nick) - { - const IRCv3::Monitor::WatcherList* list = manager.GetWatcherList(nick); - if (!list) - return; - - for (const auto& curr : *list) - curr->WriteNumeric(numeric, nick); - } - -public: - ModuleMonitor() - : Module(VF_VENDOR, "Adds the /MONITOR command which allows users to find out when their friends are connected to the server.") - , ISupport::EventListener(this) - , Monitor::APIBase(this) - , manager(this, "monitor") - , cmd(this, manager) - , extendedcap(this, "extended-monitor") - { - } - - void ReadConfig(ConfigStatus& status) override - { - const auto& tag = ServerInstance->Config->ConfValue("monitor"); - cmd.maxmonitor = tag->getNum<unsigned long>("maxentries", 30, 1); - } - - void OnPostConnect(User* user) override - { - SendAlert(RPL_MONONLINE, user->nick); - } - - void OnUserPostNick(User* user, const std::string& oldnick) override - { - // Detect and ignore nickname case change - if (ServerInstance->Users.FindNick(oldnick) == user) - return; - - SendAlert(RPL_MONOFFLINE, oldnick); - SendAlert(RPL_MONONLINE, user->nick); - } - - void OnUserQuit(User* user, const std::string& message, const std::string& oper_message) override - { - LocalUser* localuser = IS_LOCAL(user); - if (localuser) - manager.UnwatchAll(localuser); - SendAlert(RPL_MONOFFLINE, user->nick); - } - - void OnBuildISupport(ISupport::TokenMap& tokens) override - { - tokens["MONITOR"] = ConvToStr(cmd.maxmonitor); - } - - void ForEachWatcher(User* user, Monitor::ForEachHandler& handler, bool extended_only) override - { - const IRCv3::Monitor::WatcherList* list = manager.GetWatcherList(user->nick); - if (!list) - return; - - for (IRCv3::Monitor::WatcherList::const_iterator i = list->begin(); i != list->end(); ++i) - { - LocalUser* curr = *i; - if (!extended_only || extendedcap.IsEnabled(curr)) - handler.Execute(curr); - } - } -}; - -MODULE_INIT(ModuleMonitor) - -#endif |
