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 + "" + it->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();