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/>.
26 static const unsigned int MAX_CAPS = (sizeof(intptr_t) * 8) - 1;
27 static const intptr_t CAP_302_BIT = (intptr_t)1 << MAX_CAPS;
28 static const unsigned int MAX_VALUE_LENGTH = 100;
31 class ExtItem : public LocalIntExt
35 std::string serialize(SerializeFormat format, const Extensible* container, void* item) const CXX11_OVERRIDE;
36 void unserialize(SerializeFormat format, Extensible* container, const std::string& value) CXX11_OVERRIDE;
43 /** Supports capability negotiation protocol v3.1, or none
47 /** Supports capability negotiation v3.2
52 class EventListener : public Events::ModuleEventListener
55 EventListener(Module* mod)
56 : ModuleEventListener(mod, "event/cap")
60 /** Called whenever a new client capability becomes available or unavailable
61 * @param cap Capability being added or removed
62 * @param add If true, the capability is being added, otherwise its being removed
64 virtual void OnCapAddDel(Capability* cap, bool add) = 0;
66 /** Called whenever the value of a cap changes.
67 * @param cap Capability whose value changed
69 virtual void OnCapValueChange(Capability* cap) { }
72 class Manager : public DataProvider
76 : DataProvider(mod, "capmanager")
80 /** Register a client capability.
81 * Modules should call Capability::SetActive(true) instead of this method.
82 * @param cap Capability to register
84 virtual void AddCap(Capability* cap) = 0;
86 /** Unregister a client capability.
87 * Modules should call Capability::SetActive(false) instead of this method.
88 * @param cap Capability to unregister
90 virtual void DelCap(Capability* cap) = 0;
92 /** Find a capability by name
93 * @param name Capability to find
94 * @return Capability object pointer if found, NULL otherwise
96 virtual Capability* Find(const std::string& name) const = 0;
98 /** Notify manager when a value of a cap changed
99 * @param cap Cap whose value changed
101 virtual void NotifyValueChange(Capability* cap) = 0;
104 /** Represents a client capability.
106 * Capabilities offer extensions to the client to server protocol. They must be negotiated with clients before they have any effect on the protocol.
107 * Each cap must have a unique name that is used during capability negotiation.
109 * After construction the cap is ready to be used by clients without any further setup, like other InspIRCd services.
110 * The get() method accepts a user as parameter and can be used to check whether that user has negotiated usage of the cap. This is only known for local users.
112 * The cap module must be loaded for the capability to work. The IsRegistered() method can be used to query whether the cap is actually online or not.
113 * The capability can be deactivated and reactivated with the SetActive() method. Deactivated caps behave as if they don't exist.
115 * It is possible to implement special behavior by inheriting from this class and overriding some of its methods.
117 class Capability : public ServiceProvider, private dynamic_reference_base::CaptureHook
121 /** Bit allocated to this cap, undefined if the cap is unregistered
125 /** Extension containing all caps set by a user. NULL if the cap is unregistered.
129 /** True if the cap is active. Only active caps are registered in the manager.
133 /** Reference to the cap manager object
135 dynamic_reference<Manager> manager;
137 void OnCapture() CXX11_OVERRIDE
149 Ext AddToMask(Ext mask) const { return (mask | GetMask()); }
150 Ext DelFromMask(Ext mask) const { return (mask & (~GetMask())); }
151 Bit GetMask() const { return bit; }
153 friend class ManagerImpl;
156 /** Notify the manager that the value of the capability changed.
157 * Must be called if the value of the cap changes for any reason.
159 void NotifyValueChange()
162 manager->NotifyValueChange(this);
166 /** Constructor, initializes the capability.
167 * Caps are active by default.
168 * @param mod Module providing the cap
169 * @param Name Raw name of the cap as used in the protocol (CAP LS, etc.)
171 Capability(Module* mod, const std::string& Name)
172 : ServiceProvider(mod, Name, SERVICE_CUSTOM)
174 , manager(mod, "capmanager")
184 void RegisterService() CXX11_OVERRIDE
186 manager.SetCaptureHook(this);
190 /** Check whether a user has the capability turned on.
191 * This method is safe to call if the cap is unregistered and will return false.
192 * @param user User to check
193 * @return True if the user is using this capability, false otherwise
195 bool get(User* user) const
199 Ext caps = extitem->get(user);
200 return ((caps & GetMask()) != 0);
203 /** Turn the capability on/off for a user. If the cap is not registered this method has no effect.
204 * @param user User to turn the cap on/off for
205 * @param val True to turn the cap on, false to turn it off
207 void set(User* user, bool val)
211 Ext curr = extitem->get(user);
212 extitem->set(user, (val ? AddToMask(curr) : DelFromMask(curr)));
215 /** Activate or deactivate the capability.
216 * If activating, the cap is marked as active and if the manager is available the cap is registered in the manager.
217 * If deactivating, the cap is marked as inactive and if it is registered, it will be unregistered.
218 * Users who had the cap turned on will have it turned off automatically.
219 * @param activate True to activate the cap, false to deactivate it
221 void SetActive(bool activate)
227 manager->AddCap(this);
229 manager->DelCap(this);
233 /** Get the name of the capability that's used in the protocol
234 * @return Name of the capability as used in the protocol
236 const std::string& GetName() const { return name; }
238 /** Check whether the capability is active. The cap must be active and registered to be used by users.
239 * @return True if the cap is active, false if it has been deactivated
241 bool IsActive() const { return active; }
243 /** Check whether the capability is registered
244 * The cap must be active and the manager must be available for a cap to be registered.
245 * @return True if the cap is registered in the manager, false otherwise
247 bool IsRegistered() const { return (extitem != NULL); }
249 /** Get the CAP negotiation protocol version of a user.
250 * The cap must be registered for this to return anything other than CAP_LEGACY.
251 * @param user User whose negotiation protocol version to query
252 * @return One of the Capability::Protocol enum indicating the highest supported capability negotiation protocol version
254 Protocol GetProtocol(LocalUser* user) const
256 return ((IsRegistered() && (extitem->get(user) & CAP_302_BIT)) ? CAP_302 : CAP_LEGACY);
259 /** Called when a user requests to turn this capability on or off.
260 * @param user User requesting to change the state of the cap
261 * @param add True if requesting to turn the cap on, false if requesting to turn it off
262 * @return True to allow the request, false to reject it
264 virtual bool OnRequest(LocalUser* user, bool add)
269 /** Called when a user requests a list of all capabilities and this capability is about to be included in the list.
270 * The default behavior always includes the cap in the list.
271 * @param user User querying a list capabilities
272 * @return True to add this cap to the list sent to the user, false to not list it
274 virtual bool OnList(LocalUser* user)
279 /** Query the value of this capability for a user
280 * @param user User who will get the value of the capability
281 * @return Value to show to the user. If NULL, the capability has no value (default).
283 virtual const std::string* GetValue(LocalUser* user) const
289 /** Reference to a cap. The cap may be provided by another module.
293 dynamic_reference_nocheck<Capability> ref;
296 /** Constructor, initializes the capability reference
297 * @param mod Module creating this object
298 * @param Name Raw name of the cap as used in the protocol (CAP LS, etc.)
300 Reference(Module* mod, const std::string& Name)
301 : ref(mod, "cap/" + Name)
305 /** Check whether a user has the referenced capability turned on.
306 * @param user User to check
307 * @return True if the user is using the referenced capability, false otherwise
309 bool get(LocalUser* user)
312 return ref->get(user);