/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2013, 2018-2019 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 "modules/account.h" #include "modules/away.h" #include "modules/cap.h" #include "modules/ircv3.h" class AwayMessage : public ClientProtocol::Message { public: AwayMessage(User* user) : ClientProtocol::Message("AWAY", user) { SetParams(user, user->awaymsg); } AwayMessage() : ClientProtocol::Message("AWAY") { } void SetParams(User* user, const std::string& awaymsg) { // Going away: 1 parameter which is the away reason // Back from away: no parameter if (!awaymsg.empty()) PushParam(awaymsg); } }; class JoinHook : public ClientProtocol::EventHook { 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") , asterisk(1, '*') , awayprotoev(mod, "AWAY") , extendedjoincap(mod, "extended-join") , awaycap(mod, "away-notify") { } void OnEventInit(const ClientProtocol::Event& ev) CXX11_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; const AccountExtItem* const accountext = GetAccountExtItem(); if (accountext) { const std::string* accountname = accountext->get(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->awaymsg); } } ModResult OnPreEventSend(LocalUser* user, const ClientProtocol::Event& ev, ClientProtocol::MessageList& messagelist) CXX11_OVERRIDE { if (extendedjoincap.get(user)) messagelist.front() = &extendedjoinmsg; if ((!awaymsg.GetParams().empty()) && (awaycap.get(user))) messagelist.push_back(&awaymsg); return MOD_RES_PASSTHRU; } }; class ModuleIRCv3 : public Module , public AccountEventListener , public Away::EventListener { Cap::Capability cap_accountnotify; JoinHook joinhook; ClientProtocol::EventProvider accountprotoev; public: ModuleIRCv3() : AccountEventListener(this) , Away::EventListener(this) , cap_accountnotify(this, "account-notify") , joinhook(this) , accountprotoev(this, "ACCOUNT") { } void ReadConfig(ConfigStatus& status) CXX11_OVERRIDE { ConfigTag* 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)); } void OnAccountChange(User* user, const std::string& newaccount) CXX11_OVERRIDE { if (!(user->registered & REG_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(user, accountevent, cap_accountnotify); } void OnUserAway(User* user) CXX11_OVERRIDE { if (!joinhook.awaycap.IsActive()) return; // Going away: n!u@h AWAY :reason AwayMessage msg(user); ClientProtocol::Event awayevent(joinhook.awayprotoev, msg); IRCv3::WriteNeighborsWithCap(user, awayevent, joinhook.awaycap); } void OnUserBack(User* user) CXX11_OVERRIDE { if (!joinhook.awaycap.IsActive()) return; // Back from away: n!u@h AWAY AwayMessage msg(user); ClientProtocol::Event awayevent(joinhook.awayprotoev, msg); IRCv3::WriteNeighborsWithCap(user, awayevent, joinhook.awaycap); } Version GetVersion() CXX11_OVERRIDE { return Version("Provides the IRCv3 account-notify, away-notify, and extended-join client capabilities.", VF_VENDOR); } }; MODULE_INIT(ModuleIRCv3)