diff --git a/include/znc/IRCNetwork.h b/include/znc/IRCNetwork.h index 3862e7f3..4966fab4 100644 --- a/include/znc/IRCNetwork.h +++ b/include/znc/IRCNetwork.h @@ -33,7 +33,7 @@ public: CIRCNetwork(CUser *pUser, const CIRCNetwork& Network); ~CIRCNetwork(); - void Clone(const CIRCNetwork& Network); + void Clone(const CIRCNetwork& Network, bool bCloneName = true); CString GetNetworkPath(); diff --git a/src/ClientCommand.cpp b/src/ClientCommand.cpp index be94822b..634a8690 100644 --- a/src/ClientCommand.cpp +++ b/src/ClientCommand.cpp @@ -491,6 +491,84 @@ void CClient::UserCommand(CString& sLine) { if (PutStatus(Table) == 0) { PutStatus("No networks"); } + } else if (sCommand.Equals("MOVENETWORK")) { + if (!m_pUser->IsAdmin()) { + PutStatus("Access Denied."); + return; + } + + CString sOldUser = sLine.Token(1); + CString sOldNetwork = sLine.Token(2); + CString sNewUser = sLine.Token(3); + CString sNewNetwork = sLine.Token(4); + + if (sOldUser.empty() || sOldNetwork.empty() || sNewUser.empty()) { + PutStatus("Usage: MoveNetwork old-user old-network new-user [new-network]"); + return; + } + if (sNewNetwork.empty()) { + sNewNetwork = sOldNetwork; + } + + CUser* pOldUser = CZNC::Get().FindUser(sOldUser); + if (!pOldUser) { + PutStatus("Old user [" + sOldUser + "] not found."); + return; + } + + CIRCNetwork* pOldNetwork = pOldUser->FindNetwork(sOldNetwork); + if (!pOldNetwork) { + PutStatus("Old network [" + sOldNetwork + "] not found."); + return; + } + + CUser* pNewUser = CZNC::Get().FindUser(sNewUser); + if (!pNewUser) { + PutStatus("New user [" + sOldUser + "] not found."); + return; + } + + if (pNewUser->FindNetwork(sNewNetwork)) { + PutStatus("User [" + sNewUser + "] already has network [" + sNewNetwork + "]."); + return; + } + + if (!CIRCNetwork::IsValidNetwork(sNewNetwork)) { + PutStatus("Invalid network name [" + sNewNetwork + "]"); + return; + } + + const CModules& vMods = pOldNetwork->GetModules(); + for (CModules::const_iterator i = vMods.begin(); i != vMods.end(); ++i) { + CFile fOldNVFile = CFile(pOldNetwork->GetNetworkPath() + "/moddata/" + (*i)->GetModName() + "/.registry"); + if (!fOldNVFile.Exists()) { + continue; + } + CString sNewModPath = pNewUser->GetUserPath() + "/networks/" + sNewNetwork + "/moddata/" + (*i)->GetModName(); + if (!CFile::Exists(sNewModPath)) { + CDir::MakeDir(sNewModPath); + } + fOldNVFile.Copy(sNewModPath + "/.registry"); + } + + CIRCNetwork* pNewNetwork = pNewUser->AddNetwork(sNewNetwork); + + if (!pNewNetwork) { + PutStatus("Error adding network."); + return; + } + + pNewNetwork->Clone(*pOldNetwork, false); + + if (m_pNetwork && m_pNetwork->GetName().Equals(sOldNetwork) && m_pUser == pOldUser) { + SetNetwork(NULL); + } + + if (pOldUser->DeleteNetwork(sOldNetwork)) { + PutStatus("Success."); + } else { + PutStatus("Copied the network to new user, but failed to delete old network"); + } } else if (sCommand.Equals("JUMPNETWORK")) { CString sNetwork = sLine.Token(1); @@ -1402,6 +1480,13 @@ void CClient::HelpUser() { Table.SetCell("Command", "ListNetworks"); Table.SetCell("Description", "List all networks"); + if (m_pUser->IsAdmin()) { + Table.AddRow(); + Table.SetCell("Command", "MoveNetwork"); + Table.SetCell("Arguments", "old-user old-net new-user [new-net]"); + Table.SetCell("Description", "Move an IRC network from one user to another"); + } + Table.AddRow(); Table.SetCell("Command", "JumpNetwork"); Table.SetCell("Arguments", ""); diff --git a/src/IRCNetwork.cpp b/src/IRCNetwork.cpp index 1fb43e8f..d1e6b27a 100644 --- a/src/IRCNetwork.cpp +++ b/src/IRCNetwork.cpp @@ -81,8 +81,10 @@ CIRCNetwork::CIRCNetwork(CUser *pUser, const CIRCNetwork &Network) { Clone(Network); } -void CIRCNetwork::Clone(const CIRCNetwork& Network) { - m_sName = Network.GetName(); +void CIRCNetwork::Clone(const CIRCNetwork& Network, bool bCloneName) { + if (bCloneName) { + m_sName = Network.GetName(); + } m_fFloodRate = Network.GetFloodRate(); m_uFloodBurst = Network.GetFloodBurst();