2 * InspIRCd -- Internet Relay Chat Daemon
4 * Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com>
6 * This file is part of InspIRCd. InspIRCd is free software: you can
7 * redistribute it and/or modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation, version 2.
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "modules/cap.h"
22 #include "modules/reload.h"
24 class CapNotify : public Cap::Capability
26 bool OnRequest(LocalUser* user, bool add) CXX11_OVERRIDE
28 // Users using the negotiation protocol v3.2 or newer may not turn off cap-notify
29 if ((!add) && (GetProtocol(user) != Cap::CAP_LEGACY))
34 bool OnList(LocalUser* user) CXX11_OVERRIDE
36 // If the client supports 3.2 enable cap-notify for them
37 if (GetProtocol(user) != Cap::CAP_LEGACY)
43 CapNotify(Module* mod)
44 : Cap::Capability(mod, "cap-notify")
49 class CapNotifyMessage : public Cap::MessageBase
52 CapNotifyMessage(bool add, const std::string& capname)
53 : Cap::MessageBase((add ? "NEW" : "DEL"))
55 PushParamRef(capname);
59 class CapNotifyValueMessage : public Cap::MessageBase
62 const std::string::size_type pos;
65 CapNotifyValueMessage(const std::string& capname)
66 : Cap::MessageBase("NEW")
74 void SetCapValue(const std::string& capvalue)
82 class ModuleIRCv3CapNotify : public Module, public Cap::EventListener, public ReloadModule::EventListener
85 std::string reloadedmod;
86 std::vector<std::string> reloadedcaps;
87 ClientProtocol::EventProvider protoev;
89 void Send(const std::string& capname, Cap::Capability* cap, bool add)
91 CapNotifyMessage msg(add, capname);
92 CapNotifyValueMessage msgwithval(capname);
94 ClientProtocol::Event event(protoev, msg);
95 ClientProtocol::Event eventwithval(protoev, msgwithval);
97 const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
98 for (UserManager::LocalList::const_iterator i = list.begin(); i != list.end(); ++i)
100 LocalUser* user = *i;
101 if (!capnotify.get(user))
104 // Check that this user can actually see the cap.
105 if (!cap->OnList(user))
108 // If the cap is being added and the client supports cap values then show the value, if any
109 if ((add) && (capnotify.GetProtocol(user) != Cap::CAP_LEGACY))
111 const std::string* capvalue = cap->GetValue(user);
112 if ((capvalue) && (!capvalue->empty()))
114 msgwithval.SetUser(user);
115 msgwithval.SetCapValue(*capvalue);
116 user->Send(eventwithval);
126 ModuleIRCv3CapNotify()
127 : Cap::EventListener(this)
128 , ReloadModule::EventListener(this)
130 , protoev(this, "CAP_NOTIFY")
134 void OnCapAddDel(Cap::Capability* cap, bool add) CXX11_OVERRIDE
136 if (cap->creator == this)
139 if (cap->creator->ModuleSourceFile == reloadedmod)
142 reloadedcaps.push_back(cap->GetName());
145 Send(cap->GetName(), cap, add);
148 void OnCapValueChange(Cap::Capability* cap) CXX11_OVERRIDE
150 // The value of a cap has changed, send CAP DEL and CAP NEW with the new value
151 Send(cap->GetName(), cap, false);
152 Send(cap->GetName(), cap, true);
155 void OnReloadModuleSave(Module* mod, ReloadModule::CustomData& cd) CXX11_OVERRIDE
159 reloadedmod = mod->ModuleSourceFile;
160 // Request callback when reload is complete
164 void OnReloadModuleRestore(Module* mod, void* data) CXX11_OVERRIDE
166 // Reloading can change the set of caps provided by a module so assuming that if the reload succeded all
167 // caps that the module previously provided are available or all were lost if the reload failed is wrong.
168 // Instead, we verify the availability of each cap individually.
169 dynamic_reference_nocheck<Cap::Manager> capmanager(this, "capmanager");
172 for (std::vector<std::string>::const_iterator i = reloadedcaps.begin(); i != reloadedcaps.end(); ++i)
174 const std::string& capname = *i;
175 if (!capmanager->Find(capname))
176 Send(capname, NULL, false);
180 reloadedcaps.clear();
183 Version GetVersion() CXX11_OVERRIDE
185 return Version("Provides the cap-notify IRCv3 extension", VF_VENDOR);
189 MODULE_INIT(ModuleIRCv3CapNotify)