From 0b57b7d4371a9bc312f732f7be4cb3c821aeeb94 Mon Sep 17 00:00:00 2001 From: Kyle Fuller Date: Tue, 8 Nov 2011 19:09:28 +0000 Subject: [PATCH] Properly handle CIRCNetwork's when we rehash This commit does the following: - Do not segfault on rehash - Delete CIRCNetwork's when they are removed from config - Update to the configs nick/altnick/realname/ident --- include/znc/IRCNetwork.h | 4 +++- include/znc/User.h | 2 +- src/IRCNetwork.cpp | 52 ++++++++++++++++++++++++++++++++++++---- src/User.cpp | 39 ++++++++++++++++++++++++++---- 4 files changed, 85 insertions(+), 12 deletions(-) diff --git a/include/znc/IRCNetwork.h b/include/znc/IRCNetwork.h index 8e1f8a57..9e5c2e55 100644 --- a/include/znc/IRCNetwork.h +++ b/include/znc/IRCNetwork.h @@ -30,9 +30,11 @@ public: static bool IsValidNetwork(const CString& sNetwork); CIRCNetwork(CUser *pUser, const CString& sName); - CIRCNetwork(CUser *pUser, const CIRCNetwork *pNetwork, bool bCloneChans = true); + CIRCNetwork(CUser *pUser, const CIRCNetwork& Network, bool bCloneChans = true); ~CIRCNetwork(); + void Clone(const CIRCNetwork& Network, bool bCloneChans = true); + CString GetNetworkPath(); void DelServers(); diff --git a/include/znc/User.h b/include/znc/User.h index 6a8ff6e7..3646c5a6 100644 --- a/include/znc/User.h +++ b/include/znc/User.h @@ -68,7 +68,7 @@ public: bool DeleteNetwork(const CString& sNetwork); bool AddNetwork(CIRCNetwork *pNetwork); void RemoveNetwork(CIRCNetwork *pNetwork); - CIRCNetwork* FindNetwork(const CString& sNetwork); + CIRCNetwork* FindNetwork(const CString& sNetwork) const; const vector& GetNetworks() const; // !Networks diff --git a/src/IRCNetwork.cpp b/src/IRCNetwork.cpp index 3eb446f1..f2a0b4e9 100644 --- a/src/IRCNetwork.cpp +++ b/src/IRCNetwork.cpp @@ -54,10 +54,9 @@ CIRCNetwork::CIRCNetwork(CUser *pUser, const CString& sName) { m_QueryBuffer.SetLineCount(250, true); } -CIRCNetwork::CIRCNetwork(CUser *pUser, const CIRCNetwork *pNetwork, bool bCloneChans) { +CIRCNetwork::CIRCNetwork(CUser *pUser, const CIRCNetwork &Network, bool bCloneChans) { m_pUser = NULL; SetUser(pUser); - m_sName = pNetwork->GetName(); m_pModules = new CModules; @@ -71,8 +70,19 @@ CIRCNetwork::CIRCNetwork(CUser *pUser, const CIRCNetwork *pNetwork, bool bCloneC m_MotdBuffer.SetLineCount(200, true); // This should be more than enough motd lines m_QueryBuffer.SetLineCount(250, true); + Clone(Network, bCloneChans); +} + +void CIRCNetwork::Clone(const CIRCNetwork& Network, bool bCloneChans) { + m_sName = Network.GetName(); + + SetNick(Network.GetNick()); + SetAltNick(Network.GetAltNick()); + SetIdent(Network.GetIdent()); + SetRealName(Network.GetRealName()); + // Servers - const vector& vServers = pNetwork->GetServers(); + const vector& vServers = Network.GetServers(); CString sServer; CServer* pCurServ = GetCurrentServer(); @@ -107,7 +117,7 @@ CIRCNetwork::CIRCNetwork(CUser *pUser, const CIRCNetwork *pNetwork, bool bCloneC // !Servers // Chans - const vector& vChans = pNetwork->GetChans(); + const vector& vChans = Network.GetChans(); for (a = 0; a < vChans.size(); a++) { CChan* pNewChan = vChans[a]; CChan* pChan = FindChan(pNewChan->GetName()); @@ -121,7 +131,7 @@ CIRCNetwork::CIRCNetwork(CUser *pUser, const CIRCNetwork *pNetwork, bool bCloneC for (a = 0; a < m_vChans.size(); a++) { CChan* pChan = m_vChans[a]; - CChan* pNewChan = pNetwork->FindChan(pChan->GetName()); + CChan* pNewChan = Network.FindChan(pChan->GetName()); if (!pNewChan) { pChan->SetInConfig(false); @@ -131,6 +141,38 @@ CIRCNetwork::CIRCNetwork(CUser *pUser, const CIRCNetwork *pNetwork, bool bCloneC } } // !Chans + + // Modules + set ssUnloadMods; + CModules& vCurMods = GetModules(); + const CModules& vNewMods = Network.GetModules(); + + for (a = 0; a < vNewMods.size(); a++) { + CString sModRet; + CModule* pNewMod = vNewMods[a]; + CModule* pCurMod = vCurMods.FindModule(pNewMod->GetModName()); + + if (!pCurMod) { + vCurMods.LoadModule(pNewMod->GetModName(), pNewMod->GetArgs(), CModInfo::NetworkModule, m_pUser, this, sModRet); + } else if (pNewMod->GetArgs() != pCurMod->GetArgs()) { + vCurMods.ReloadModule(pNewMod->GetModName(), pNewMod->GetArgs(), m_pUser, this, sModRet); + } + } + + for (a = 0; a < vCurMods.size(); a++) { + CModule* pCurMod = vCurMods[a]; + CModule* pNewMod = vNewMods.FindModule(pCurMod->GetModName()); + + if (!pNewMod) { + ssUnloadMods.insert(pCurMod->GetModName()); + } + } + + for (set::iterator it = ssUnloadMods.begin(); it != ssUnloadMods.end(); ++it) { + vCurMods.UnloadModule(*it); + } + // !Modules + } CIRCNetwork::~CIRCNetwork() { diff --git a/src/User.cpp b/src/User.cpp index c196aaf0..48c83b37 100644 --- a/src/User.cpp +++ b/src/User.cpp @@ -449,8 +449,8 @@ bool CUser::DeleteNetwork(const CString& sNetwork) { return false; } -CIRCNetwork* CUser::FindNetwork(const CString& sNetwork) { - for (vector::iterator it = m_vIRCNetworks.begin(); it != m_vIRCNetworks.end(); ++it) { +CIRCNetwork* CUser::FindNetwork(const CString& sNetwork) const { + for (vector::const_iterator it = m_vIRCNetworks.begin(); it != m_vIRCNetworks.end(); ++it) { CIRCNetwork *pNetwork = *it; if (pNetwork->GetName().Equals(sNetwork)) { return pNetwork; @@ -528,7 +528,7 @@ CString CUser::AddTimestamp(time_t tm, const CString& sStr) const { // The Control+O key combination in mIRC inserts ascii character 15, // which turns off all previous attributes, including color, bold, underline, and italics. sRet += "\x0F "; - + sRet += szTimestamp; } } @@ -616,8 +616,37 @@ bool CUser::Clone(const CUser& User, CString& sErrorRet, bool bCloneChans) { // Networks const vector& vNetworks = User.GetNetworks(); - for (a = 0; a < vNetworks.size(); a++) { - new CIRCNetwork(this, vNetworks[a], bCloneChans); + for (vector::const_iterator it = vNetworks.begin(); it != vNetworks.end(); ++it) { + CIRCNetwork *pNetwork = FindNetwork((*it)->GetName()); + + if (pNetwork) { + pNetwork->Clone(*(*it), bCloneChans); + } else { + new CIRCNetwork(this, *(*it), bCloneChans); + } + } + + set ssDeleteNetworks; + for (vector::const_iterator it = m_vIRCNetworks.begin(); it != m_vIRCNetworks.end(); ++it) { + if (!(User.FindNetwork((*it)->GetName()))) { + ssDeleteNetworks.insert((*it)->GetName()); + } + } + + for (set::const_iterator it = ssDeleteNetworks.begin(); it != ssDeleteNetworks.end(); ++it) { + // The following will move all the clients to the user. + // So the clients are not disconnected. The client could + // have requested the rehash. Then when we do + // client->PutStatus("Rehashing succeeded!") we would + // crash if there was no client anymore. + vector& vClients = FindNetwork(*it)->GetClients(); + + while (vClients.begin() != vClients.end()) { + CClient *pClient = vClients.front(); + pClient->SetNetwork(NULL); + } + + DeleteNetwork(*it); } // !Networks