2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2018-2020 Sadie Powell <sadie@witchery.services>
5 * Copyright (C) 2015, 2018 Attila Molnar <attilamolnar@hush.com>
7 * This file is part of InspIRCd. InspIRCd is free software: you can
8 * redistribute it and/or modify it under the terms of the GNU General Public
9 * License as published by the Free Software Foundation, version 2.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "modules/cap.h"
23 #include "modules/reload.h"
25 class CapNotify : public Cap::Capability
27 bool OnRequest(LocalUser* user, bool add) CXX11_OVERRIDE
29 // Users using the negotiation protocol v3.2 or newer may not turn off cap-notify
30 if ((!add) && (GetProtocol(user) != Cap::CAP_LEGACY))
35 bool OnList(LocalUser* user) CXX11_OVERRIDE
37 // If the client supports 3.2 enable cap-notify for them
38 if (GetProtocol(user) != Cap::CAP_LEGACY)
44 CapNotify(Module* mod)
45 : Cap::Capability(mod, "cap-notify")
50 class CapNotifyMessage : public Cap::MessageBase
53 CapNotifyMessage(bool add, const std::string& capname)
54 : Cap::MessageBase((add ? "NEW" : "DEL"))
56 PushParamRef(capname);
60 class CapNotifyValueMessage : public Cap::MessageBase
63 const std::string::size_type pos;
66 CapNotifyValueMessage(const std::string& capname)
67 : Cap::MessageBase("NEW")
75 void SetCapValue(const std::string& capvalue)
83 class ModuleIRCv3CapNotify : public Module, public Cap::EventListener, public ReloadModule::EventListener
86 std::string reloadedmod;
87 std::vector<std::string> reloadedcaps;
88 ClientProtocol::EventProvider protoev;
90 void Send(const std::string& capname, Cap::Capability* cap, bool add)
92 CapNotifyMessage msg(add, capname);
93 CapNotifyValueMessage msgwithval(capname);
95 ClientProtocol::Event event(protoev, msg);
96 ClientProtocol::Event eventwithval(protoev, msgwithval);
98 const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
99 for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
101 LocalUser* user = *i;
102 if (!capnotify.get(user))
105 // Check that this user can actually see the cap.
106 if (add && (!cap || !cap->OnList(user)))
109 // If the cap is being added and the client supports cap values then show the value, if any
110 if ((add) && (capnotify.GetProtocol(user) != Cap::CAP_LEGACY))
112 const std::string* capvalue = cap->GetValue(user);
113 if ((capvalue) && (!capvalue->empty()))
115 msgwithval.SetUser(user);
116 msgwithval.SetCapValue(*capvalue);
117 user->Send(eventwithval);
127 ModuleIRCv3CapNotify()
128 : Cap::EventListener(this)
129 , ReloadModule::EventListener(this)
131 , protoev(this, "CAP_NOTIFY")
135 void OnCapAddDel(Cap::Capability* cap, bool add) CXX11_OVERRIDE
137 if (cap->creator == this)
140 if (cap->creator->ModuleSourceFile == reloadedmod)
143 reloadedcaps.push_back(cap->GetName());
146 Send(cap->GetName(), cap, add);
149 void OnCapValueChange(Cap::Capability* cap) CXX11_OVERRIDE
151 // The value of a cap has changed, send CAP DEL and CAP NEW with the new value
152 Send(cap->GetName(), cap, false);
153 Send(cap->GetName(), cap, true);
156 void OnReloadModuleSave(Module* mod, ReloadModule::CustomData& cd) CXX11_OVERRIDE
160 reloadedmod = mod->ModuleSourceFile;
161 // Request callback when reload is complete
165 void OnReloadModuleRestore(Module* mod, void* data) CXX11_OVERRIDE
167 // Reloading can change the set of caps provided by a module so assuming that if the reload succeeded all
168 // caps that the module previously provided are available or all were lost if the reload failed is wrong.
169 // Instead, we verify the availability of each cap individually.
170 dynamic_reference_nocheck<Cap::Manager> capmanager(this, "capmanager");
173 for (std::vector<std::string>::const_iterator i = reloadedcaps.begin(); i != reloadedcaps.end(); ++i)
175 const std::string& capname = *i;
176 if (!capmanager->Find(capname))
177 Send(capname, NULL, false);
181 reloadedcaps.clear();
184 Version GetVersion() CXX11_OVERRIDE
186 return Version("Provides the IRCv3 cap-notify client capability.", VF_VENDOR);
190 MODULE_INIT(ModuleIRCv3CapNotify)