+enum
+{
+ // From IRCv3 sasl-3.1
+ RPL_SASLSUCCESS = 903,
+ ERR_SASLFAIL = 904,
+ ERR_SASLTOOLONG = 905,
+ ERR_SASLABORTED = 906,
+ RPL_SASLMECHS = 908
+};
+
+static std::string sasl_target;
+
+class ServerTracker : public ServerEventListener
+{
+ bool online;
+
+ void Update(const Server* server, bool linked)
+ {
+ if (sasl_target == "*")
+ return;
+
+ if (InspIRCd::Match(server->GetName(), sasl_target))
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_VERBOSE, "SASL target server \"%s\" %s", sasl_target.c_str(), (linked ? "came online" : "went offline"));
+ online = linked;
+ }
+ }
+
+ void OnServerLink(const Server* server) CXX11_OVERRIDE
+ {
+ Update(server, true);
+ }
+
+ void OnServerSplit(const Server* server) CXX11_OVERRIDE
+ {
+ Update(server, false);
+ }
+
+ public:
+ ServerTracker(Module* mod)
+ : ServerEventListener(mod)
+ {
+ Reset();
+ }
+
+ void Reset()
+ {
+ if (sasl_target == "*")
+ {
+ online = true;
+ return;
+ }
+
+ online = false;
+
+ ProtocolInterface::ServerList servers;
+ ServerInstance->PI->GetServerList(servers);
+ for (ProtocolInterface::ServerList::const_iterator i = servers.begin(); i != servers.end(); ++i)
+ {
+ const ProtocolInterface::ServerInfo& server = *i;
+ if (InspIRCd::Match(server.servername, sasl_target))
+ {
+ online = true;
+ break;
+ }
+ }
+ }
+
+ bool IsOnline() const { return online; }
+};
+
+class SASLCap : public Cap::Capability
+{
+ std::string mechlist;
+ const ServerTracker& servertracker;
+
+ bool OnRequest(LocalUser* user, bool adding) CXX11_OVERRIDE
+ {
+ // Requesting this cap is allowed anytime
+ if (adding)
+ return true;
+
+ // But removing it can only be done when unregistered
+ return (user->registered != REG_ALL);
+ }
+
+ bool OnList(LocalUser* user) CXX11_OVERRIDE
+ {
+ return servertracker.IsOnline();
+ }
+
+ const std::string* GetValue(LocalUser* user) const CXX11_OVERRIDE
+ {
+ return &mechlist;
+ }
+
+ public:
+ SASLCap(Module* mod, const ServerTracker& tracker)
+ : Cap::Capability(mod, "sasl")
+ , servertracker(tracker)
+ {
+ }
+
+ void SetMechlist(const std::string& newmechlist)
+ {
+ if (mechlist == newmechlist)
+ return;
+
+ mechlist = newmechlist;
+ NotifyValueChange();
+ }
+};