summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAttila Molnar <attilamolnar@hush.com>2015-12-05 16:24:12 +0100
committerAttila Molnar <attilamolnar@hush.com>2015-12-05 16:24:12 +0100
commit4a02829e4ff8b89f48104d5a98eaad9d3739f594 (patch)
tree77e9940824b64826eaabcd9988bb902b324b2773
parent425d54073a0ae61c68de1b339177bb7c0db116f1 (diff)
m_cap Save and restore the cap state of a module when it is reloaded
-rw-r--r--src/modules/m_cap.cpp82
1 files changed, 81 insertions, 1 deletions
diff --git a/src/modules/m_cap.cpp b/src/modules/m_cap.cpp
index bfce2e68c..c01377f46 100644
--- a/src/modules/m_cap.cpp
+++ b/src/modules/m_cap.cpp
@@ -18,6 +18,7 @@
#include "inspircd.h"
+#include "modules/reload.h"
#include "modules/cap.h"
namespace Cap
@@ -27,8 +28,25 @@ namespace Cap
static Cap::ManagerImpl* managerimpl;
-class Cap::ManagerImpl : public Cap::Manager
+class Cap::ManagerImpl : public Cap::Manager, public ReloadModule::EventListener
{
+ /** Stores the cap state of a module being reloaded
+ */
+ struct CapModData
+ {
+ struct Data
+ {
+ std::string name;
+ std::vector<std::string> users;
+
+ Data(Capability* cap)
+ : name(cap->GetName())
+ {
+ }
+ };
+ std::vector<Data> caps;
+ };
+
typedef insp::flat_map<std::string, Capability*, irc::insensitive_swo> CapMap;
ExtItem capext;
@@ -61,9 +79,71 @@ class Cap::ManagerImpl : public Cap::Manager
throw ModuleException("Too many caps");
}
+ void OnReloadModuleSave(Module* mod, ReloadModule::CustomData& cd) CXX11_OVERRIDE
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "OnReloadModuleSave()");
+ if (mod == creator)
+ return;
+
+ CapModData* capmoddata = new CapModData;
+ cd.add(this, capmoddata);
+
+ for (CapMap::iterator i = caps.begin(); i != caps.end(); ++i)
+ {
+ Capability* cap = i->second;
+ // Only save users of caps that belong to the module being reloaded
+ if (cap->creator != mod)
+ continue;
+
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Module being reloaded implements cap %s, saving cap users", cap->GetName().c_str());
+ capmoddata->caps.push_back(CapModData::Data(cap));
+ CapModData::Data& capdata = capmoddata->caps.back();
+
+ // Populate list with uuids of users who are using the cap
+ const UserManager::LocalList& list = ServerInstance->Users.GetLocalUsers();
+ for (UserManager::LocalList::const_iterator j = list.begin(); j != list.end(); ++j)
+ {
+ LocalUser* user = *j;
+ if (cap->get(user))
+ capdata.users.push_back(user->uuid);
+ }
+ }
+ }
+
+ void OnReloadModuleRestore(Module* mod, void* data) CXX11_OVERRIDE
+ {
+ CapModData* capmoddata = static_cast<CapModData*>(data);
+ for (std::vector<CapModData::Data>::const_iterator i = capmoddata->caps.begin(); i != capmoddata->caps.end(); ++i)
+ {
+ const CapModData::Data& capdata = *i;
+ Capability* cap = ManagerImpl::Find(capdata.name);
+ if (!cap)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "Cap %s is no longer available after reload", capdata.name.c_str());
+ continue;
+ }
+
+ // Set back the cap for all users who were using it before the reload
+ for (std::vector<std::string>::const_iterator j = capdata.users.begin(); j != capdata.users.end(); ++j)
+ {
+ const std::string& uuid = *j;
+ User* user = ServerInstance->FindUUID(uuid);
+ if (!user)
+ {
+ ServerInstance->Logs->Log(MODNAME, LOG_DEBUG, "User %s is gone when trying to restore cap %s", uuid.c_str(), capdata.name.c_str());
+ continue;
+ }
+
+ cap->set(user, true);
+ }
+ }
+ delete capmoddata;
+ }
+
public:
ManagerImpl(Module* mod, Events::ModuleEventProvider& evprovref)
: Cap::Manager(mod)
+ , ReloadModule::EventListener(mod)
, capext(mod)
, evprov(evprovref)
{