+ 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, bool error) CXX11_OVERRIDE
+ {
+ Update(server, false);
+ }
+
+ public:
+ ServerTracker(Module* mod)
+ : ServerProtocol::LinkEventListener(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
+{
+ private:
+ std::string mechlist;
+ const ServerTracker& servertracker;
+ UserCertificateAPI sslapi;
+
+ bool OnRequest(LocalUser* user, bool adding) CXX11_OVERRIDE
+ {
+ if (requiressl && sslapi && !sslapi->GetCertificate(user))
+ return false;
+
+ // Servers MUST NAK any sasl capability request if the authentication layer
+ // is unavailable.
+ return servertracker.IsOnline();
+ }
+
+ bool OnList(LocalUser* user) CXX11_OVERRIDE
+ {
+ if (requiressl && sslapi && !sslapi->GetCertificate(user))
+ return false;
+
+ // Servers MUST NOT advertise the sasl capability if the authentication layer
+ // is unavailable.
+ return servertracker.IsOnline();
+ }
+
+ const std::string* GetValue(LocalUser* user) const CXX11_OVERRIDE
+ {
+ return &mechlist;
+ }
+
+ public:
+ bool requiressl;
+ SASLCap(Module* mod, const ServerTracker& tracker)
+ : Cap::Capability(mod, "sasl")
+ , servertracker(tracker)
+ , sslapi(mod)
+ {
+ }
+
+ void SetMechlist(const std::string& newmechlist)
+ {
+ if (mechlist == newmechlist)
+ return;
+
+ mechlist = newmechlist;
+ NotifyValueChange();
+ }
+};