/* * InspIRCd -- Internet Relay Chat Daemon * * Copyright (C) 2026 Sadie Powell * * This file is part of InspIRCd. InspIRCd is free software: you can * redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, version 2. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "inspircd.h" static insp::intrusive_list* dynrefs = nullptr; dynamic_reference_base::dynamic_reference_base(const WeakModulePtr& mod, const std::string& stype, const std::string& sname, bool strict) : service_name(sname) , service_type(stype) , strict_ref(strict) , creator(mod) { if (!dynrefs) dynrefs = new insp::intrusive_list; dynrefs->push_front(this); // Resolve unless there is no ModuleManager (part of class InspIRCd) if (ServerInstance) resolve(); } dynamic_reference_base::dynamic_reference_base(const dynamic_reference_base& other) : dynamic_reference_base(other.creator, other.service_type, other.service_name, other.strict_ref) { // Intentionally left blank. } dynamic_reference_base::~dynamic_reference_base() { dynrefs->erase(this); if (dynrefs->empty()) insp::delete_zero(dynrefs); } void dynamic_reference_base::reset_all(const std::string& stype) { if (!dynrefs) return; for (auto* dynref : *dynrefs) { if (stype.empty() || dynref->service_type == stype) dynref->resolve(); } } void dynamic_reference_base::resolve() { auto* oldvalue = this->value; this->value = nullptr; // Because find() may return any element with a matching key in case count(key) > 1 use lower_bound() // to ensure a dynref with the same name as another one resolves to the same object auto i = ServerInstance->Modules.Services.lower_bound(std::make_pair(this->service_type, this->service_name)); if (i == ServerInstance->Modules.Services.end()) return; // No service found. const auto& [stype, sname] = i->first; if (!insp::casemapped_equals(this->service_type, stype) || !insp::casemapped_equals(this->service_name, sname)) return; // No service found. if (this->strict_ref && sname.empty()) return; // Can't use generic services for strict references. this->value = i->second; if (oldvalue != value && hook) hook->OnCapture(); } void dynamic_reference_base::ClearProviderName() { this->service_name.clear(); value = nullptr; } void dynamic_reference_base::SetProvider(const std::string& stype, const std::string& sname) { this->service_type = stype; this->service_name = sname; resolve(); } void dynamic_reference_base::SetProviderName(const std::string& sname) { SetProvider(GetProviderType(), sname); } Service::Provider::Provider(const WeakModulePtr& mod, const std::string& stype, const std::string& sname) : service_creator(mod) , service_name(sname) , service_type(stype) { if ((ServerInstance) && (ServerInstance->Modules.NewServices)) ServerInstance->Modules.NewServices->push_back(this); } void Service::Provider::DisableAutoRegister() { if ((ServerInstance) && (ServerInstance->Modules.NewServices)) std::erase(*ServerInstance->Modules.NewServices, this); } std::string Service::Provider::GetSource() const { if (insp::empty_ptr(this->service_creator)) return "the core"; const auto mod = this->service_creator.lock(); if (!mod) return "an unknown module"; return FMT::format("the {} module", ModuleManager::ShrinkModName(mod->ModuleFile)); } void Service::Provider::RegisterService() { // Intentionally left blank. } void Service::Provider::UnregisterService() { // Intentionally left blank. } Service::SimpleProvider::SimpleProvider(const WeakModulePtr& mod, const std::string& stype, const std::string& sname) : Service::Provider(mod, stype, sname) { } void Service::SimpleProvider::RegisterService() { if (!this->service_name.empty()) ServerInstance->Modules.AddReferent(this->service_type, this->service_name, this); ServerInstance->Modules.AddReferent(this->service_type, "", this); } void Service::SimpleProvider::UnregisterService() { ServerInstance->Modules.DelReferent(this); }