diff --git a/include/znc/User.h b/include/znc/User.h index d4eb4b83..df12adec 100644 --- a/include/znc/User.h +++ b/include/znc/User.h @@ -58,9 +58,6 @@ public: static bool IsValidUserName(const CString& sUserName); static CString MakeCleanUserName(const CString& sUserName); - // Unloads a module on all users who have it loaded and loads it again. - static bool UpdateModule(const CString &sModule); - // Modules CModules& GetModules() { return *m_pModules; } const CModules& GetModules() const { return *m_pModules; } diff --git a/include/znc/znc.h b/include/znc/znc.h index cba22f94..46ead889 100644 --- a/include/znc/znc.h +++ b/include/znc/znc.h @@ -125,6 +125,16 @@ public: CUser* FindUser(const CString& sUsername); CModule* FindModule(const CString& sModName, const CString& sUsername); CModule* FindModule(const CString& sModName, CUser* pUser); + + /** Reload a module everywhere + * + * This method will unload a module globally, for a user and for each + * network. It will then reload them all again. + * + * @param sModule The name of the module to reload + */ + bool UpdateModule(const CString &sModule); + bool DeleteUser(const CString& sUsername); bool AddUser(CUser* pUser, CString& sErrorRet); const map & GetUserMap() const { return(m_msUsers); } diff --git a/src/ClientCommand.cpp b/src/ClientCommand.cpp index 3d7f8cb7..f26046fa 100644 --- a/src/ClientCommand.cpp +++ b/src/ClientCommand.cpp @@ -963,17 +963,11 @@ void CClient::UserCommand(CString& sLine) { return; } - if (m_pUser->DenyLoadMod() || !m_pUser->IsAdmin()) { - PutStatus("Unable to reload [" + sMod + "] Access Denied."); - return; - } - - PutStatus("Reloading [" + sMod + "] on all users..."); - if (CUser::UpdateModule(sMod)) { + PutStatus("Reloading [" + sMod + "] everywhere"); + if (CZNC::Get().UpdateModule(sMod)) { PutStatus("Done"); } else { - PutStatus("Done, but there were errors, some users no longer have [" - + sMod + "] loaded"); + PutStatus("Done, but there were errors, [" + sMod + "] could not be loaded everywhere."); } } else if ((sCommand.Equals("ADDBINDHOST") || sCommand.Equals("ADDVHOST")) && m_pUser->IsAdmin()) { CString sHost = sLine.Token(1); @@ -1476,7 +1470,7 @@ void CClient::HelpUser() { Table.AddRow(); Table.SetCell("Command", "UpdateMod"); Table.SetCell("Arguments", ""); - Table.SetCell("Description", "Reload a module on all users"); + Table.SetCell("Description", "Reload a module everywhere"); } } diff --git a/src/User.cpp b/src/User.cpp index 635db777..978c566a 100644 --- a/src/User.cpp +++ b/src/User.cpp @@ -411,33 +411,6 @@ bool CUser::ParseConfig(CConfig* pConfig, CString& sError) { return true; } -bool CUser::UpdateModule(const CString &sModule) { - const map& Users = CZNC::Get().GetUserMap(); - map::const_iterator it; - map Affected; - map::iterator it2; - bool error = false; - - for (it = Users.begin(); it != Users.end(); ++it) { - CModule *pMod = it->second->GetModules().FindModule(sModule); - if (pMod) { - Affected[it->second] = pMod->GetArgs(); - it->second->GetModules().UnloadModule(pMod->GetModName()); - } - } - - CString sErr; - for (it2 = Affected.begin(); it2 != Affected.end(); ++it2) { - if (!it2->first->GetModules().LoadModule(sModule, it2->second, CModInfo::UserModule, it2->first, NULL, sErr)) { - error = true; - DEBUG("Failed to reload [" << sModule << "] for [" << it2->first->GetUserName() - << "]: " << sErr); - } - } - - return !error; -} - CIRCNetwork* CUser::AddNetwork(const CString &sNetwork) { if (!CIRCNetwork::IsValidNetwork(sNetwork) || FindNetwork(sNetwork)) { return NULL; diff --git a/src/znc.cpp b/src/znc.cpp index ae026f3e..20a188a3 100644 --- a/src/znc.cpp +++ b/src/znc.cpp @@ -1393,6 +1393,90 @@ CModule* CZNC::FindModule(const CString& sModName, CUser* pUser) { return CZNC::Get().GetModules().FindModule(sModName); } +bool CZNC::UpdateModule(const CString &sModule) { + CModule *pModule; + + map::const_iterator it; + map musLoaded; + map::iterator musIt; + map mnsLoaded; + map::iterator mnsIt; + + // Unload the module for every user and network + for (it = m_msUsers.begin(); it != m_msUsers.end(); ++it) { + CUser *pUser = it->second; + + pModule = pUser->GetModules().FindModule(sModule); + if (pModule) { + musLoaded[pUser] = pModule->GetArgs(); + pUser->GetModules().UnloadModule(sModule); + } + + // See if the user has this module loaded to a network + vector vNetworks = pUser->GetNetworks(); + vector::iterator it2; + for (it2 = vNetworks.begin(); it2 != vNetworks.end(); ++it2) { + CIRCNetwork *pNetwork = *it2; + + pModule = pNetwork->GetModules().FindModule(sModule); + if (pModule) { + mnsLoaded[pNetwork] = pModule->GetArgs(); + pNetwork->GetModules().UnloadModule(sModule); + } + } + } + + // Unload the global module + bool bGlobal = false; + CString sGlobalArgs; + + pModule = GetModules().FindModule(sModule); + if (pModule) { + bGlobal = true; + sGlobalArgs = pModule->GetArgs(); + GetModules().UnloadModule(sModule); + } + + // Lets reload everything + bool bError = false; + CString sErr; + + // Reload the global module + if (bGlobal) { + if (!GetModules().LoadModule(sModule, sGlobalArgs, CModInfo::GlobalModule, NULL, NULL, sErr)) { + DEBUG("Failed to reload [" << sModule << "] globally [" << sErr << "]"); + bError = true; + } + } + + // Reload the module for all users + for (musIt = musLoaded.begin(); musIt != musLoaded.end(); ++musIt) { + CUser *pUser = musIt->first; + CString& sArgs = musIt->second; + + if (!pUser->GetModules().LoadModule(sModule, sArgs, CModInfo::UserModule, pUser, NULL, sErr)) { + DEBUG("Failed to reload [" << sModule << "] for [" + << pUser->GetUserName() << "] [" << sErr << "]"); + bError = true; + } + } + + // Reload the module for all networks + for (mnsIt = mnsLoaded.begin(); mnsIt != mnsLoaded.end(); ++mnsIt) { + CIRCNetwork *pNetwork = mnsIt->first; + CString& sArgs = mnsIt->second; + + if (!pNetwork->GetModules().LoadModule(sModule, sArgs, CModInfo::NetworkModule, pNetwork->GetUser(), pNetwork, sErr)) { + DEBUG("Failed to reload [" << sModule << "] for [" + << pNetwork->GetUser()->GetUserName() << "/" + << pNetwork->GetName() << "] [" << sErr << "]"); + bError = true; + } + } + + return !bError; +} + CUser* CZNC::FindUser(const CString& sUsername) { map::iterator it = m_msUsers.find(sUsername);