From 889d521e05f2e922683d48c74eb00290e7a2f548 Mon Sep 17 00:00:00 2001 From: Sadie Powell Date: Wed, 17 Jul 2024 00:06:50 +0100 Subject: Shuffle the modules about a bit. --- modules/ircv3.cpp | 187 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 modules/ircv3.cpp (limited to 'modules/ircv3.cpp') diff --git a/modules/ircv3.cpp b/modules/ircv3.cpp new file mode 100644 index 000000000..b77db39ef --- /dev/null +++ b/modules/ircv3.cpp @@ -0,0 +1,187 @@ +/* + * InspIRCd -- Internet Relay Chat Daemon + * + * Copyright (C) 2022 delthas + * Copyright (C) 2013, 2018-2023 Sadie Powell + * Copyright (C) 2012, 2015, 2018 Attila Molnar + * + * 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 "clientprotocolevent.h" +#include "modules/account.h" +#include "modules/away.h" +#include "modules/cap.h" +#include "modules/ircv3.h" +#include "modules/monitor.h" + +class AwayMessage final + : public ClientProtocol::Message +{ +public: + AwayMessage(User* user) + : ClientProtocol::Message("AWAY", user) + { + SetParams(user, user->away); + } + + AwayMessage() + : ClientProtocol::Message("AWAY") + { + } + + void SetParams(User* user, const std::optional& awaystate) + { + // Going away: 1 parameter which is the away reason + // Back from away: no parameter + if (awaystate) + PushParam(awaystate->message); + } +}; + +class JoinHook final + : public ClientProtocol::EventHook +{ +private: + Account::API accountapi; + ClientProtocol::Events::Join extendedjoinmsg; + +public: + const std::string asterisk = "*"; + ClientProtocol::EventProvider awayprotoev; + AwayMessage awaymsg; + Cap::Capability extendedjoincap; + Cap::Capability awaycap; + + JoinHook(Module* mod) + : ClientProtocol::EventHook(mod, "JOIN") + , accountapi(mod) + , awayprotoev(mod, "AWAY") + , extendedjoincap(mod, "extended-join") + , awaycap(mod, "away-notify") + { + } + + void OnEventInit(const ClientProtocol::Event& ev) override + { + const ClientProtocol::Events::Join& join = static_cast(ev); + + // An extended join has two extra parameters: + // First the account name of the joining user or an asterisk if the user is not logged in. + // The second parameter is the realname of the joining user. + + Membership* const memb = join.GetMember(); + const std::string* account = &asterisk; + if (accountapi) + { + const std::string* accountname = accountapi->GetAccountName(memb->user); + if (accountname) + account = accountname; + } + + extendedjoinmsg.ClearParams(); + extendedjoinmsg.SetSource(join); + extendedjoinmsg.PushParamRef(memb->chan->name); + extendedjoinmsg.PushParamRef(*account); + extendedjoinmsg.PushParamRef(memb->user->GetRealName()); + + awaymsg.ClearParams(); + if ((memb->user->IsAway()) && (awaycap.IsActive())) + { + awaymsg.SetSource(join); + awaymsg.SetParams(memb->user, memb->user->away); + } + } + + ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) override + { + if (extendedjoincap.IsEnabled(user)) + messagelist.front() = &extendedjoinmsg; + + if ((!awaymsg.GetParams().empty()) && (awaycap.IsEnabled(user))) + messagelist.push_back(&awaymsg); + + return MOD_RES_PASSTHRU; + } +}; + +class ModuleIRCv3 final + : public Module + , public Account::EventListener + , public Away::EventListener +{ +private: + Cap::Capability cap_accountnotify; + JoinHook joinhook; + ClientProtocol::EventProvider accountprotoev; + Monitor::API monitorapi; + Cap::Capability stdrplcap; + +public: + ModuleIRCv3() + : Module(VF_VENDOR, "Provides the IRCv3 account-notify, away-notify, extended-join, and standard-replies client capabilities.") + , Account::EventListener(this) + , Away::EventListener(this) + , cap_accountnotify(this, "account-notify") + , joinhook(this) + , accountprotoev(this, "ACCOUNT") + , monitorapi(this) + , stdrplcap(this, "standard-replies") + { + } + + void ReadConfig(ConfigStatus& status) override + { + const auto& conf = ServerInstance->Config->ConfValue("ircv3"); + cap_accountnotify.SetActive(conf->getBool("accountnotify", true)); + joinhook.awaycap.SetActive(conf->getBool("awaynotify", true)); + joinhook.extendedjoincap.SetActive(conf->getBool("extendedjoin", true)); + stdrplcap.SetActive(conf->getBool("standardreplies", true)); + } + + void OnAccountChange(User* user, const std::string& newaccount) override + { + if (!(user->connected & User::CONN_NICKUSER)) + return; + + // Logged in: 1 parameter which is the account name + // Logged out: 1 parameter which is a "*" + ClientProtocol::Message msg("ACCOUNT", user); + const std::string& param = (newaccount.empty() ? joinhook.asterisk : newaccount); + msg.PushParamRef(param); + ClientProtocol::Event accountevent(accountprotoev, msg); + IRCv3::WriteNeighborsWithCap res(user, accountevent, cap_accountnotify, true); + Monitor::WriteWatchersWithCap(monitorapi, user, accountevent, cap_accountnotify, res.GetAlreadySentId()); + } + + void OnUserAway(User* user, const std::optional& prevstate) override + { + if (!joinhook.awaycap.IsActive()) + return; + + // Going away: n!u@h AWAY :reason + AwayMessage msg(user); + ClientProtocol::Event awayevent(joinhook.awayprotoev, msg); + IRCv3::WriteNeighborsWithCap res(user, awayevent, joinhook.awaycap); + Monitor::WriteWatchersWithCap(monitorapi, user, awayevent, joinhook.awaycap, res.GetAlreadySentId()); + } + + void OnUserBack(User* user, const std::optional& prevstate) override + { + // Back from away: n!u@h AWAY + OnUserAway(user, prevstate); + } +}; + +MODULE_INIT(ModuleIRCv3) -- cgit v1.3.1-10-gc9f91