]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - include/modules/cap.h
m_cap Provide the OnCapValueChange event and add Cap::Manager::NotifyValueChange()
[user/henk/code/inspircd.git] / include / modules / cap.h
1 /*
2  * InspIRCd -- Internet Relay Chat Daemon
3  *
4  *   Copyright (C) 2015 Attila Molnar <attilamolnar@hush.com>
5  *
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.
9  *
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
13  * details.
14  *
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/>.
17  */
18
19
20 #pragma once
21
22 #include "event.h"
23
24 namespace Cap
25 {
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;
29
30         typedef intptr_t Ext;
31         typedef LocalIntExt ExtItem;
32         class Capability;
33
34         enum Protocol
35         {
36                 /** Supports capability negotiation protocol v3.1, or none
37                  */
38                 CAP_LEGACY,
39
40                 /** Supports capability negotiation v3.2
41                  */
42                 CAP_302
43         };
44
45         class EventListener : public Events::ModuleEventListener
46         {
47          public:
48                 EventListener(Module* mod)
49                         : ModuleEventListener(mod, "event/cap")
50                 {
51                 }
52
53                 /** Called whenever a new client capability becomes available or unavailable
54                  * @param cap Capability being added or removed
55                  * @param add If true, the capability is being added, otherwise its being removed
56                  */
57                 virtual void OnCapAddDel(Capability* cap, bool add) = 0;
58
59                 /** Called whenever the value of a cap changes.
60                  * @param cap Capability whose value changed
61                  */
62                 virtual void OnCapValueChange(Capability* cap) { }
63         };
64
65         class Manager : public DataProvider
66         {
67          public:
68                 Manager(Module* mod)
69                         : DataProvider(mod, "capmanager")
70                 {
71                 }
72
73                 /** Register a client capability.
74                  * Modules should call Capability::SetActive(true) instead of this method.
75                  * @param cap Capability to register
76                  */
77                 virtual void AddCap(Capability* cap) = 0;
78
79                 /** Unregister a client capability.
80                  * Modules should call Capability::SetActive(false) instead of this method.
81                  * @param cap Capability to unregister
82                  */
83                 virtual void DelCap(Capability* cap) = 0;
84
85                 /** Find a capability by name
86                  * @param name Capability to find
87                  * @return Capability object pointer if found, NULL otherwise
88                  */
89                 virtual Capability* Find(const std::string& name) const = 0;
90
91                 /** Notify manager when a value of a cap changed
92                  * @param cap Cap whose value changed
93                  */
94                 virtual void NotifyValueChange(Capability* cap) = 0;
95         };
96
97         /** Represents a client capability.
98          *
99          * Capabilities offer extensions to the client to server protocol. They must be negotiated with clients before they have any effect on the protocol.
100          * Each cap must have a unique name that is used during capability negotiation.
101          *
102          * After construction the cap is ready to be used by clients without any further setup, like other InspIRCd services.
103          * 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.
104          *
105          * 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.
106          * The capability can be deactivated and reactivated with the SetActive() method. Deactivated caps behave as if they don't exist.
107          *
108          * It is possible to implement special behavior by inheriting from this class and overriding some of its methods.
109          */
110         class Capability : public ServiceProvider, private dynamic_reference_base::CaptureHook
111         {
112                 typedef size_t Bit;
113
114                 /** Bit allocated to this cap, undefined if the cap is unregistered
115                  */
116                 Bit bit;
117
118                 /** Extension containing all caps set by a user. NULL if the cap is unregistered.
119                  */
120                 ExtItem* extitem;
121
122                 /** True if the cap is active. Only active caps are registered in the manager.
123                  */
124                 bool active;
125
126                 /** Reference to the cap manager object
127                  */
128                 dynamic_reference<Manager> manager;
129
130                 void OnCapture() CXX11_OVERRIDE
131                 {
132                         if (active)
133                                 SetActive(true);
134                 }
135
136                 void Unregister()
137                 {
138                         bit = 0;
139                         extitem = NULL;
140                 }
141
142                 Ext AddToMask(Ext mask) const { return (mask | GetMask()); }
143                 Ext DelFromMask(Ext mask) const { return (mask & (~GetMask())); }
144                 Bit GetMask() const { return bit; }
145
146                 friend class ManagerImpl;
147
148          protected:
149                 /** Notify the manager that the value of the capability changed.
150                  * Must be called if the value of the cap changes for any reason.
151                  */
152                 void NotifyValueChange()
153                 {
154                         if (IsRegistered())
155                                 manager->NotifyValueChange(this);
156                 }
157
158          public:
159                 /** Constructor, initializes the capability.
160                  * Caps are active by default.
161                  * @param mod Module providing the cap
162                  * @param Name Raw name of the cap as used in the protocol (CAP LS, etc.)
163                  */
164                 Capability(Module* mod, const std::string& Name)
165                         : ServiceProvider(mod, Name, SERVICE_CUSTOM)
166                         , active(true)
167                         , manager(mod, "capmanager")
168                 {
169                         Unregister();
170                 }
171
172                 ~Capability()
173                 {
174                         SetActive(false);
175                 }
176
177                 void RegisterService() CXX11_OVERRIDE
178                 {
179                         manager.SetCaptureHook(this);
180                         SetActive(true);
181                 }
182
183                 /** Check whether a user has the capability turned on.
184                  * This method is safe to call if the cap is unregistered and will return false.
185                  * @param user User to check
186                  * @return True if the user is using this capability, false otherwise
187                  */
188                 bool get(User* user) const
189                 {
190                         if (!IsRegistered())
191                                 return false;
192                         Ext caps = extitem->get(user);
193                         return (caps & GetMask());
194                 }
195
196                 /** Turn the capability on/off for a user. If the cap is not registered this method has no effect.
197                  * @param user User to turn the cap on/off for
198                  * @param val True to turn the cap on, false to turn it off
199                  */
200                 void set(User* user, bool val)
201                 {
202                         if (!IsRegistered())
203                                 return;
204                         Ext curr = extitem->get(user);
205                         extitem->set(user, (val ? AddToMask(curr) : DelFromMask(curr)));
206                 }
207
208                 /** Activate or deactivate the capability.
209                  * If activating, the cap is marked as active and if the manager is available the cap is registered in the manager.
210                  * If deactivating, the cap is marked as inactive and if it is registered, it will be unregistered.
211                  * Users who had the cap turned on will have it turned off automatically.
212                  * @param activate True to activate the cap, false to deactivate it
213                  */
214                 void SetActive(bool activate)
215                 {
216                         active = activate;
217                         if (manager)
218                         {
219                                 if (activate)
220                                         manager->AddCap(this);
221                                 else
222                                         manager->DelCap(this);
223                         }
224                 }
225
226                 /** Get the name of the capability that's used in the protocol
227                  * @return Name of the capability as used in the protocol
228                  */
229                 const std::string& GetName() const { return name; }
230
231                 /** Check whether the capability is active. The cap must be active and registered to be used by users.
232                  * @return True if the cap is active, false if it has been deactivated
233                  */
234                 bool IsActive() const { return active; }
235
236                 /** Check whether the capability is registered
237                  * The cap must be active and the manager must be available for a cap to be registered.
238                  * @return True if the cap is registered in the manager, false otherwise
239                  */
240                 bool IsRegistered() const { return (extitem != NULL); }
241
242                 /** Get the CAP negotiation protocol version of a user.
243                  * The cap must be registered for this to return anything other than CAP_LEGACY.
244                  * @param user User whose negotiation protocol version to query
245                  * @return One of the Capability::Protocol enum indicating the highest supported capability negotiation protocol version
246                  */
247                 Protocol GetProtocol(LocalUser* user) const
248                 {
249                         return ((IsRegistered() && (extitem->get(user) & CAP_302_BIT)) ? CAP_302 : CAP_LEGACY);
250                 }
251
252                 /** Called when a user requests to turn this capability on or off.
253                  * @param user User requesting to change the state of the cap
254                  * @param add True if requesting to turn the cap on, false if requesting to turn it off
255                  * @return True to allow the request, false to reject it
256                  */
257                 virtual bool OnRequest(LocalUser* user, bool add)
258                 {
259                         return true;
260                 }
261
262                 /** Called when a user requests a list of all capabilities and this capability is about to be included in the list.
263                  * The default behavior always includes the cap in the list.
264                  * @param user User querying a list capabilities
265                  * @return True to add this cap to the list sent to the user, false to not list it
266                  */
267                 virtual bool OnList(LocalUser* user)
268                 {
269                         return true;
270                 }
271
272                 /** Query the value of this capability for a user
273                  * @param user User who will get the value of the capability
274                  * @return Value to show to the user. If NULL, the capability has no value (default).
275                  */
276                 virtual const std::string* GetValue(LocalUser* user) const
277                 {
278                         return NULL;
279                 }
280         };
281 }