+ }
+
+ void HandleClear(LocalUser* user, std::vector<std::string>& result)
+ {
+ HandleList(result, user, false, false, true);
+ capext.unset(user);
+ }
+};
+
+namespace
+{
+ std::string SerializeCaps(const Extensible* container, void* item, bool human)
+ {
+ // XXX: Cast away the const because IS_LOCAL() doesn't handle it
+ LocalUser* user = IS_LOCAL(const_cast<User*>(static_cast<const User*>(container)));
+ if (!user)
+ return std::string();
+
+ // List requested caps
+ std::vector<std::string> result;
+ managerimpl->HandleList(result, user, false, false);
+
+ // Serialize cap protocol version. If building a human-readable string append a
+ // new token, otherwise append only a single character indicating the version.
+ std::string version;
+ if (human)
+ version.append("capversion=3.");
+ switch (managerimpl->GetProtocol(user))
+ {
+ case Cap::CAP_302:
+ version.push_back('2');
+ break;
+ default:
+ version.push_back('1');
+ break;
+ }
+ result.push_back(version);
+
+ return stdalgo::string::join(result, ' ');
+ }
+}
+
+Cap::ExtItem::ExtItem(Module* mod)
+ : LocalIntExt("caps", ExtensionItem::EXT_USER, mod)
+{
+}
+
+std::string Cap::ExtItem::ToHuman(const Extensible* container, void* item) const
+{
+ return SerializeCaps(container, item, true);
+}
+
+std::string Cap::ExtItem::ToInternal(const Extensible* container, void* item) const
+{
+ return SerializeCaps(container, item, false);
+}
+
+void Cap::ExtItem::FromInternal(Extensible* container, const std::string& value)
+{
+ LocalUser* user = IS_LOCAL(static_cast<User*>(container));
+ if (!user)
+ return; // Can't happen
+
+ // Process the cap protocol version which is a single character at the end of the serialized string
+ const char verchar = *value.rbegin();
+ if (verchar == '2')
+ managerimpl->Set302Protocol(user);
+
+ // Remove the version indicator from the string passed to HandleReq
+ std::string caplist(value, 0, value.size()-1);
+ managerimpl->HandleReq(user, caplist);
+}
+
+class CapMessage : public Cap::MessageBase
+{
+ public:
+ CapMessage(LocalUser* user, const std::string& subcmd, const std::string& result, bool asterisk)
+ : Cap::MessageBase(subcmd)
+ {
+ SetUser(user);
+ if (asterisk)
+ PushParam("*");
+ PushParamRef(result);
+ }
+};
+
+class CommandCap : public SplitCommand
+{
+ private:
+ Events::ModuleEventProvider evprov;
+ Cap::ManagerImpl manager;
+ ClientProtocol::EventProvider protoevprov;
+
+ void DisplayResult(LocalUser* user, const std::string& subcmd, std::vector<std::string> result, bool asterisk)
+ {
+ size_t maxline = ServerInstance->Config->Limits.MaxLine - ServerInstance->Config->ServerName.size() - user->nick.length() - subcmd.length() - 11;
+ std::string line;
+ for (std::vector<std::string>::const_iterator iter = result.begin(); iter != result.end(); ++iter)