diff --git a/Chan.cpp b/Chan.cpp index cdfd694a..95b66b90 100644 --- a/Chan.cpp +++ b/Chan.cpp @@ -64,26 +64,21 @@ void CChan::Reset() { ResetJoinTries(); } -bool CChan::WriteConfig(CFile& File) { - if (!InConfig()) { - return false; - } - - File.Write("\t\n"); +CConfig CChan::ToConfig() { + CConfig config; if (m_pUser->GetBufferCount() != GetBufferCount()) - m_pUser->PrintLine(File, "\tBuffer", CString(GetBufferCount())); + config.AddKeyValuePair("Buffer", CString(GetBufferCount())); if (m_pUser->KeepBuffer() != KeepBuffer()) - m_pUser->PrintLine(File, "\tKeepBuffer", CString(KeepBuffer())); + config.AddKeyValuePair("KeepBuffer", CString(KeepBuffer())); if (IsDetached()) - m_pUser->PrintLine(File, "\tDetached", "true"); + config.AddKeyValuePair("Detached", "true"); if (!GetKey().empty()) - m_pUser->PrintLine(File, "\tKey", GetKey()); + config.AddKeyValuePair("Key", GetKey()); if (!GetDefaultModes().empty()) - m_pUser->PrintLine(File, "\tModes", GetDefaultModes()); + config.AddKeyValuePair("Modes", GetDefaultModes()); - File.Write("\t\n"); - return true; + return config; } void CChan::Clone(CChan& chan) { diff --git a/Chan.h b/Chan.h index 5d3ad5b0..50b9ed28 100644 --- a/Chan.h +++ b/Chan.h @@ -56,7 +56,7 @@ public: ~CChan(); void Reset(); - bool WriteConfig(CFile& File); + CConfig ToConfig(); void Clone(CChan& chan); void Cycle() const; void JoinUser(bool bForce = false, const CString& sKey = "", CClient* pClient = NULL); diff --git a/Config.cpp b/Config.cpp index 4e89d4eb..833a1fa4 100644 --- a/Config.cpp +++ b/Config.cpp @@ -169,3 +169,23 @@ bool CConfig::Parse(CFile& file, CString& sErrorMsg) return true; } + +void CConfig::Write(CFile *pFile, unsigned int iIndentation) { + CString sIndentation = CString(" ", iIndentation); + + for (EntryMapIterator it = m_ConfigEntries.begin(); it != m_ConfigEntries.end(); ++it) { + for (VCString::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) { + pFile->Write(sIndentation + it->first + " = " + *it2 + "\n"); + } + } + + for (SubConfigMapIterator it = m_SubConfigs.begin(); it != m_SubConfigs.end(); ++it) { + for (SubConfig::const_iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) { + pFile->Write("\n"); + + pFile->Write(sIndentation + "<" + it->first + " " + it2->first + ">\n"); + it2->second.m_pSubConfig->Write(pFile, iIndentation + 1); + pFile->Write(sIndentation + "first + ">\n"); + } + } +} diff --git a/Config.h b/Config.h index e9e846b6..24493c8e 100644 --- a/Config.h +++ b/Config.h @@ -47,6 +47,26 @@ public: return m_SubConfigs.end(); } + void AddKeyValuePair(const CString& sName, const CString& sValue) { + if (sName.empty() || sValue.empty()) { + return; + } + + m_ConfigEntries[sName].push_back(sValue); + } + + bool AddSubConfig(const CString& sTag, const CString& sName, CConfig Config) { + SubConfig &conf = m_SubConfigs[sTag]; + SubConfig::const_iterator it = conf.find(sName); + + if (it != conf.end()) { + return false; + } + + conf[sName] = Config; + return true; + } + bool FindStringVector(const CString& sName, VCString& vsList) { EntryMap::iterator it = m_ConfigEntries.find(sName); vsList.clear(); @@ -85,6 +105,7 @@ public: } bool Parse(CFile& file, CString& sErrorMsg); + void Write(CFile *pFile, unsigned int iIndentation = 0); private: EntryMap m_ConfigEntries; diff --git a/User.cpp b/User.cpp index e86f6296..949bc418 100644 --- a/User.cpp +++ b/User.cpp @@ -829,79 +829,58 @@ bool CUser::DelChan(const CString& sName) { return false; } -bool CUser::PrintLine(CFile& File, CString sName, CString sValue) const { - sName.Trim(); - sValue.Trim(); - - if (sName.empty() || sValue.empty()) { - DEBUG("Refused writing an invalid line to a user config. [" - << sName << "] [" << sValue << "]"); - return false; - } - - // FirstLine() so that no one can inject new lines to the config if he - // manages to add "\n" to e.g. sValue. - CString sLine = "\t" + sName.FirstLine() + " = " + sValue.FirstLine() + "\n"; - return (File.Write(sLine) > 0); -} - -bool CUser::WriteConfig(CFile& File) { - File.Write("\n"); +CConfig CUser::ToConfig() { + CConfig config; if (m_eHashType != HASH_NONE) { CString sHash = "md5"; if (m_eHashType == HASH_SHA256) sHash = "sha256"; if (m_sPassSalt.empty()) { - PrintLine(File, "Pass", sHash + "#" + GetPass()); + config.AddKeyValuePair("Pass", sHash + "#" + GetPass()); } else { - PrintLine(File, "Pass", sHash + "#" + GetPass() + "#" + m_sPassSalt + "#"); + config.AddKeyValuePair("Pass", sHash + "#" + GetPass() + "#" + m_sPassSalt + "#"); } } else { - PrintLine(File, "Pass", "plain#" + GetPass()); + config.AddKeyValuePair("Pass", "plain#" + GetPass()); } - PrintLine(File, "Nick", GetNick()); - PrintLine(File, "AltNick", GetAltNick()); - PrintLine(File, "Ident", GetIdent()); - PrintLine(File, "RealName", GetRealName()); - PrintLine(File, "BindHost", GetBindHost()); - PrintLine(File, "DCCBindHost", GetDCCBindHost()); - PrintLine(File, "QuitMsg", GetQuitMsg()); + config.AddKeyValuePair("Nick", GetNick()); + config.AddKeyValuePair("AltNick", GetAltNick()); + config.AddKeyValuePair("Ident", GetIdent()); + config.AddKeyValuePair("RealName", GetRealName()); + config.AddKeyValuePair("BindHost", GetBindHost()); + config.AddKeyValuePair("DCCBindHost", GetDCCBindHost()); + config.AddKeyValuePair("QuitMsg", GetQuitMsg()); if (CZNC::Get().GetStatusPrefix() != GetStatusPrefix()) - PrintLine(File, "StatusPrefix", GetStatusPrefix()); - PrintLine(File, "Skin", GetSkinName()); - PrintLine(File, "ChanModes", GetDefaultChanModes()); - PrintLine(File, "Buffer", CString(GetBufferCount())); - PrintLine(File, "KeepBuffer", CString(KeepBuffer())); - PrintLine(File, "MultiClients", CString(MultiClients())); - PrintLine(File, "DenyLoadMod", CString(DenyLoadMod())); - PrintLine(File, "Admin", CString(IsAdmin())); - PrintLine(File, "DenySetBindHost", CString(DenySetBindHost())); - PrintLine(File, "TimestampFormat", GetTimestampFormat()); - PrintLine(File, "AppendTimestamp", CString(GetTimestampAppend())); - PrintLine(File, "PrependTimestamp", CString(GetTimestampPrepend())); - PrintLine(File, "TimezoneOffset", CString(m_fTimezoneOffset)); - PrintLine(File, "JoinTries", CString(m_uMaxJoinTries)); - PrintLine(File, "MaxJoins", CString(m_uMaxJoins)); - PrintLine(File, "IRCConnectEnabled", CString(GetIRCConnectEnabled())); - File.Write("\n"); + config.AddKeyValuePair("StatusPrefix", GetStatusPrefix()); + config.AddKeyValuePair("Skin", GetSkinName()); + config.AddKeyValuePair("ChanModes", GetDefaultChanModes()); + config.AddKeyValuePair("Buffer", CString(GetBufferCount())); + config.AddKeyValuePair("KeepBuffer", CString(KeepBuffer())); + config.AddKeyValuePair("MultiClients", CString(MultiClients())); + config.AddKeyValuePair("DenyLoadMod", CString(DenyLoadMod())); + config.AddKeyValuePair("Admin", CString(IsAdmin())); + config.AddKeyValuePair("DenySetBindHost", CString(DenySetBindHost())); + config.AddKeyValuePair("TimestampFormat", GetTimestampFormat()); + config.AddKeyValuePair("AppendTimestamp", CString(GetTimestampAppend())); + config.AddKeyValuePair("PrependTimestamp", CString(GetTimestampPrepend())); + config.AddKeyValuePair("TimezoneOffset", CString(m_fTimezoneOffset)); + config.AddKeyValuePair("JoinTries", CString(m_uMaxJoinTries)); + config.AddKeyValuePair("MaxJoins", CString(m_uMaxJoins)); + config.AddKeyValuePair("IRCConnectEnabled", CString(GetIRCConnectEnabled())); // Allow Hosts if (!m_ssAllowedHosts.empty()) { for (set::iterator it = m_ssAllowedHosts.begin(); it != m_ssAllowedHosts.end(); ++it) { - PrintLine(File, "Allow", *it); + config.AddKeyValuePair("Allow", *it); } - - File.Write("\n"); } // CTCP Replies if (!m_mssCTCPReplies.empty()) { for (MCString::const_iterator itb = m_mssCTCPReplies.begin(); itb != m_mssCTCPReplies.end(); ++itb) { - PrintLine(File, "CTCPReply", itb->first.AsUpper() + " " + itb->second); + config.AddKeyValuePair("CTCPReply", itb->first.AsUpper() + " " + itb->second); } - - File.Write("\n"); } // Modules @@ -915,31 +894,24 @@ bool CUser::WriteConfig(CFile& File) { sArgs = " " + sArgs; } - PrintLine(File, "LoadModule", Mods[a]->GetModName() + sArgs); + config.AddKeyValuePair("LoadModule", Mods[a]->GetModName() + sArgs); } - - File.Write("\n"); } // Servers for (unsigned int b = 0; b < m_vServers.size(); b++) { - PrintLine(File, "Server", m_vServers[b]->GetString()); + config.AddKeyValuePair("Server", m_vServers[b]->GetString()); } // Chans for (unsigned int c = 0; c < m_vChans.size(); c++) { CChan* pChan = m_vChans[c]; if (pChan->InConfig()) { - File.Write("\n"); - if (!pChan->WriteConfig(File)) { - return false; - } + config.AddSubConfig("Chan", pChan->GetName(), pChan->ToConfig()); } } - File.Write("\n"); - - return true; + return config; } CChan* CUser::FindChan(const CString& sName) const { diff --git a/User.h b/User.h index 3cbd142d..f0267814 100644 --- a/User.h +++ b/User.h @@ -48,8 +48,7 @@ public: return CUtils::SaltedSHA256Hash(sPass, sSalt); } - bool PrintLine(CFile& File, CString sName, CString sValue) const; - bool WriteConfig(CFile& File); + CConfig ToConfig(); CChan* FindChan(const CString& sName) const; bool AddChan(CChan* pChan); bool AddChan(const CString& sName, bool bInConfig); diff --git a/modules/modperl/modperl.i b/modules/modperl/modperl.i index a499be63..a6604a10 100644 --- a/modules/modperl/modperl.i +++ b/modules/modperl/modperl.i @@ -15,6 +15,7 @@ #endif #include #include "../Utils.h" +#include "../Config.h" #include "../Socket.h" #include "../Modules.h" #include "../Nick.h" @@ -74,6 +75,7 @@ namespace std { #include "../ZNCString.h" %include "../defines.h" %include "../Utils.h" +%include "../Config.h" %include "../Csocket.h" %template(ZNCSocketManager) TSocketManager; %include "../Socket.h" diff --git a/modules/modpython/modpython.i b/modules/modpython/modpython.i index 9a2ca318..db43812f 100644 --- a/modules/modpython/modpython.i +++ b/modules/modpython/modpython.i @@ -9,6 +9,7 @@ %module znc_core %{ #include #include "../Utils.h" +#include "../Config.h" #include "../Socket.h" #include "../Modules.h" #include "../Nick.h" @@ -87,6 +88,7 @@ namespace std { #include "../ZNCString.h" %include "../defines.h" %include "../Utils.h" +%include "../Config.h" %include "../Csocket.h" %template(ZNCSocketManager) TSocketManager; %include "../Socket.h" diff --git a/znc.cpp b/znc.cpp index bb776d68..8b99a61f 100644 --- a/znc.cpp +++ b/znc.cpp @@ -437,10 +437,11 @@ bool CZNC::WriteConfig() { pFile->Write(MakeConfigHeader() + "\n"); - pFile->Write("AnonIPLimit = " + CString(m_uiAnonIPLimit) + "\n"); - pFile->Write("MaxBufferSize= " + CString(m_uiMaxBufferSize) + "\n"); - pFile->Write("SSLCertFile = " + CString(m_sSSLCertFile) + "\n"); - pFile->Write("ProtectWebSessions = " + CString(m_bProtectWebSessions) + "\n"); + CConfig config; + config.AddKeyValuePair("AnonIPLimit", CString(m_uiAnonIPLimit)); + config.AddKeyValuePair("MaxBufferSize", CString(m_uiMaxBufferSize)); + config.AddKeyValuePair("SSLCertFile", CString(m_sSSLCertFile)); + config.AddKeyValuePair("ProtectWebSessions", CString(m_bProtectWebSessions)); for (size_t l = 0; l < m_vpListeners.size(); l++) { CListener* pListener = m_vpListeners[l]; @@ -469,31 +470,31 @@ bool CZNC::WriteConfig() { break; } - pFile->Write("Listener" + s6 + " = " + sAcceptProtocol + sHostPortion + - CString((pListener->IsSSL()) ? "+" : "") + CString(pListener->GetPort()) + "\n"); + config.AddKeyValuePair("Listener" + s6, sAcceptProtocol + sHostPortion + + CString((pListener->IsSSL()) ? "+" : "") + CString(pListener->GetPort())); } - pFile->Write("ConnectDelay = " + CString(m_uiConnectDelay) + "\n"); - pFile->Write("ServerThrottle = " + CString(m_sConnectThrottle.GetTTL()/1000) + "\n"); + config.AddKeyValuePair("ConnectDelay", CString(m_uiConnectDelay)); + config.AddKeyValuePair("ServerThrottle", CString(m_sConnectThrottle.GetTTL()/1000)); if (!m_sPidFile.empty()) { - pFile->Write("PidFile = " + m_sPidFile.FirstLine() + "\n"); + config.AddKeyValuePair("PidFile", m_sPidFile.FirstLine()); } if (!m_sSkinName.empty()) { - pFile->Write("Skin = " + m_sSkinName.FirstLine() + "\n"); + config.AddKeyValuePair("Skin", m_sSkinName.FirstLine()); } if (!m_sStatusPrefix.empty()) { - pFile->Write("StatusPrefix = " + m_sStatusPrefix.FirstLine() + "\n"); + config.AddKeyValuePair("StatusPrefix", m_sStatusPrefix.FirstLine()); } for (unsigned int m = 0; m < m_vsMotd.size(); m++) { - pFile->Write("Motd = " + m_vsMotd[m].FirstLine() + "\n"); + config.AddKeyValuePair("Motd", m_vsMotd[m].FirstLine()); } for (unsigned int v = 0; v < m_vsBindHosts.size(); v++) { - pFile->Write("BindHost = " + m_vsBindHosts[v].FirstLine() + "\n"); + config.AddKeyValuePair("BindHost", m_vsBindHosts[v].FirstLine()); } CModules& Mods = GetModules(); @@ -506,7 +507,7 @@ bool CZNC::WriteConfig() { sArgs = " " + sArgs.FirstLine(); } - pFile->Write("LoadModule = " + sName.FirstLine() + sArgs + "\n"); + config.AddKeyValuePair("LoadModule", sName.FirstLine() + sArgs); } for (map::iterator it = m_msUsers.begin(); it != m_msUsers.end(); ++it) { @@ -517,13 +518,11 @@ bool CZNC::WriteConfig() { continue; } - pFile->Write("\n"); - - if (!it->second->WriteConfig(*pFile)) { - DEBUG("** Error writing config for user [" << it->first << "]"); - } + config.AddSubConfig("User", it->second->GetUserName(), it->second->ToConfig()); } + config.Write(pFile); + // If Sync() fails... well, let's hope nothing important breaks.. pFile->Sync();