namespace Cap
{
- static const unsigned int MAX_CAPS = sizeof(intptr_t) * 8;
+ static const unsigned int MAX_CAPS = (sizeof(intptr_t) * 8) - 1;
+ static const intptr_t CAP_302_BIT = (intptr_t)1 << MAX_CAPS;
+ static const unsigned int MAX_VALUE_LENGTH = 100;
+
typedef intptr_t Ext;
- typedef LocalIntExt ExtItem;
+ class ExtItem : public LocalIntExt
+ {
+ public:
+ ExtItem(Module* mod);
+ std::string serialize(SerializeFormat format, const Extensible* container, void* item) const CXX11_OVERRIDE;
+ void unserialize(SerializeFormat format, Extensible* container, const std::string& value) CXX11_OVERRIDE;
+ };
+
class Capability;
+ enum Protocol
+ {
+ /** Supports capability negotiation protocol v3.1, or none
+ */
+ CAP_LEGACY,
+
+ /** Supports capability negotiation v3.2
+ */
+ CAP_302
+ };
+
+ class EventListener : public Events::ModuleEventListener
+ {
+ public:
+ EventListener(Module* mod)
+ : ModuleEventListener(mod, "event/cap")
+ {
+ }
+
+ /** Called whenever a new client capability becomes available or unavailable
+ * @param cap Capability being added or removed
+ * @param add If true, the capability is being added, otherwise its being removed
+ */
+ virtual void OnCapAddDel(Capability* cap, bool add) = 0;
+
+ /** Called whenever the value of a cap changes.
+ * @param cap Capability whose value changed
+ */
+ virtual void OnCapValueChange(Capability* cap) { }
+ };
+
class Manager : public DataProvider
{
public:
* @return Capability object pointer if found, NULL otherwise
*/
virtual Capability* Find(const std::string& name) const = 0;
+
+ /** Notify manager when a value of a cap changed
+ * @param cap Cap whose value changed
+ */
+ virtual void NotifyValueChange(Capability* cap) = 0;
};
/** Represents a client capability.
*
* 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.
* The capability can be deactivated and reactivated with the SetActive() method. Deactivated caps behave as if they don't exist.
+ *
+ * It is possible to implement special behavior by inheriting from this class and overriding some of its methods.
*/
class Capability : public ServiceProvider, private dynamic_reference_base::CaptureHook
{
friend class ManagerImpl;
+ protected:
+ /** Notify the manager that the value of the capability changed.
+ * Must be called if the value of the cap changes for any reason.
+ */
+ void NotifyValueChange()
+ {
+ if (IsRegistered())
+ manager->NotifyValueChange(this);
+ }
+
public:
/** Constructor, initializes the capability.
* Caps are active by default.
if (!IsRegistered())
return false;
Ext caps = extitem->get(user);
- return (caps & GetMask());
+ return ((caps & GetMask()) != 0);
}
/** Turn the capability on/off for a user. If the cap is not registered this method has no effect.
* @return True if the cap is registered in the manager, false otherwise
*/
bool IsRegistered() const { return (extitem != NULL); }
+
+ /** Get the CAP negotiation protocol version of a user.
+ * The cap must be registered for this to return anything other than CAP_LEGACY.
+ * @param user User whose negotiation protocol version to query
+ * @return One of the Capability::Protocol enum indicating the highest supported capability negotiation protocol version
+ */
+ Protocol GetProtocol(LocalUser* user) const
+ {
+ return ((IsRegistered() && (extitem->get(user) & CAP_302_BIT)) ? CAP_302 : CAP_LEGACY);
+ }
+
+ /** Called when a user requests to turn this capability on or off.
+ * @param user User requesting to change the state of the cap
+ * @param add True if requesting to turn the cap on, false if requesting to turn it off
+ * @return True to allow the request, false to reject it
+ */
+ virtual bool OnRequest(LocalUser* user, bool add)
+ {
+ return true;
+ }
+
+ /** Called when a user requests a list of all capabilities and this capability is about to be included in the list.
+ * The default behavior always includes the cap in the list.
+ * @param user User querying a list capabilities
+ * @return True to add this cap to the list sent to the user, false to not list it
+ */
+ virtual bool OnList(LocalUser* user)
+ {
+ return true;
+ }
+
+ /** Query the value of this capability for a user
+ * @param user User who will get the value of the capability
+ * @return Value to show to the user. If NULL, the capability has no value (default).
+ */
+ virtual const std::string* GetValue(LocalUser* user) const
+ {
+ return NULL;
+ }
+ };
+
+ /** Reference to a cap. The cap may be provided by another module.
+ */
+ class Reference
+ {
+ dynamic_reference_nocheck<Capability> ref;
+
+ public:
+ /** Constructor, initializes the capability reference
+ * @param mod Module creating this object
+ * @param Name Raw name of the cap as used in the protocol (CAP LS, etc.)
+ */
+ Reference(Module* mod, const std::string& Name)
+ : ref(mod, "cap/" + Name)
+ {
+ }
+
+ /** Check whether a user has the referenced capability turned on.
+ * @param user User to check
+ * @return True if the user is using the referenced capability, false otherwise
+ */
+ bool get(LocalUser* user)
+ {
+ if (ref)
+ return ref->get(user);
+ return false;
+ }
+ };
+
+ class MessageBase : public ClientProtocol::Message
+ {
+ public:
+ MessageBase(const std::string& subcmd)
+ : ClientProtocol::Message("CAP", ServerInstance->Config->ServerName)
+ {
+ PushParamPlaceholder();
+ PushParam(subcmd);
+ }
+
+ void SetUser(LocalUser* user)
+ {
+ if (user->registered & REG_NICK)
+ ReplaceParamRef(0, user->nick);
+ else
+ ReplaceParam(0, "*");
+ }
};
}