From ecb9b210556f86efe534353e0be01ccef8f0b1a2 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Fri, 18 Sep 2015 22:25:58 +0200 Subject: [PATCH] Move message tags related code from CUtils to CMessage --- include/znc/Utils.h | 2 ++ src/Message.cpp | 31 +++++++++++++++++++++++++------ src/Utils.cpp | 31 +++++-------------------------- test/MessageTest.cpp | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 32 deletions(-) diff --git a/include/znc/Utils.h b/include/znc/Utils.h index 41d809a4..9a3b4062 100644 --- a/include/znc/Utils.h +++ b/include/znc/Utils.h @@ -87,7 +87,9 @@ public: static SCString GetTimezones(); static SCString GetEncodings(); + /// @deprecated Use CMessage instead static MCString GetMessageTags(const CString& sLine); + /// @deprecated Use CMessage instead static void SetMessageTags(CString& sLine, const MCString& mssTags); private: diff --git a/src/Message.cpp b/src/Message.cpp index 45b14669..85c5973a 100644 --- a/src/Message.cpp +++ b/src/Message.cpp @@ -117,10 +117,27 @@ CString CMessage::ToString(unsigned int uFlags) const { CString sMessage; + // + if (!(uFlags & ExcludeTags) && !m_mssTags.empty()) { + CString sTags; + for (const auto& it : m_mssTags) { + if (!sTags.empty()) { + sTags += ";"; + } + sTags += it.first; + if (!it.second.empty()) + sTags += "=" + it.second.Escape_n(CString::EMSGTAG); + } + sMessage = "@" + sTags; + } + // if (!(uFlags & ExcludePrefix)) { CString sPrefix = m_Nick.GetHostMask(); if (!sPrefix.empty()) { + if (!sMessage.empty()) { + sMessage += " "; + } sMessage += ":" + sPrefix; } } @@ -144,19 +161,21 @@ CString CMessage::ToString(unsigned int uFlags) const sMessage += sParam; } - // - if (!(uFlags & ExcludeTags)) { - CUtils::SetMessageTags(sMessage, m_mssTags); - } - return sMessage; } void CMessage::Parse(CString sMessage) { // + m_mssTags.clear(); if (sMessage.StartsWith("@")) { - m_mssTags = CUtils::GetMessageTags(sMessage); + VCString vsTags; + sMessage.Token(0).TrimPrefix_n("@").Split(";", vsTags, false); + for (const CString& sTag : vsTags) { + CString sKey = sTag.Token(0, false, "=", true); + CString sValue = sTag.Token(1, true, "=", true); + m_mssTags[sKey] = sValue.Escape(CString::EMSGTAG, CString::CString::EASCII); + } sMessage = sMessage.Token(1, true); } diff --git a/src/Utils.cpp b/src/Utils.cpp index f2bc6ef4..ddfffa56 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #ifdef HAVE_LIBSSL #include #endif /* HAVE_LIBSSL */ @@ -527,37 +528,15 @@ SCString CUtils::GetEncodings() { MCString CUtils::GetMessageTags(const CString& sLine) { if (sLine.StartsWith("@")) { - VCString vsTags; - sLine.Token(0).TrimPrefix_n("@").Split(";", vsTags, false); - - MCString mssTags; - for (const CString& sTag : vsTags) { - CString sKey = sTag.Token(0, false, "=", true); - CString sValue = sTag.Token(1, true, "=", true); - mssTags[sKey] = sValue.Escape(CString::EMSGTAG, CString::CString::EASCII); - } - return mssTags; + return CMessage(sLine).GetTags(); } return MCString::EmptyMap; } void CUtils::SetMessageTags(CString& sLine, const MCString& mssTags) { - if (sLine.StartsWith("@")) { - sLine.LeftChomp(sLine.Token(0).length() + 1); - } - - if (!mssTags.empty()) { - CString sTags; - for (const auto& it : mssTags) { - if (!sTags.empty()) { - sTags += ";"; - } - sTags += it.first; - if (!it.second.empty()) - sTags += "=" + it.second.Escape_n(CString::EMSGTAG); - } - sLine = "@" + sTags + " " + sLine; - } + CMessage Message(sLine); + Message.SetTags(mssTags); + sLine = Message.ToString(); } bool CTable::AddColumn(const CString& sName) { diff --git a/test/MessageTest.cpp b/test/MessageTest.cpp index 6ccfe832..9ff7608a 100644 --- a/test/MessageTest.cpp +++ b/test/MessageTest.cpp @@ -19,6 +19,7 @@ #include #include +using ::testing::IsEmpty; using ::testing::ContainerEq; TEST(MessageTest, SetParam) { @@ -96,6 +97,41 @@ TEST(MessageTest, ToString) { EXPECT_EQ(":services. 328 user #chan :http://znc.in", CMessage(":services. 328 user #chan :http://znc.in").ToString()); } +TEST(MessageTest, Tags) { + EXPECT_THAT(CMessage("").GetTags(), IsEmpty()); + EXPECT_THAT(CMessage(":nick!ident@host PRIVMSG #chan :hello world").GetTags(), IsEmpty()); + + EXPECT_THAT(CMessage("@a=b").GetTags(), ContainerEq(MCString{{"a","b"}})); + EXPECT_THAT(CMessage("@a=b :nick!ident@host PRIVMSG #chan :hello world").GetTags(), ContainerEq(MCString{{"a","b"}})); + EXPECT_THAT(CMessage("@a=b :rest").GetTags(), ContainerEq(MCString{{"a","b"}})); + + EXPECT_THAT(CMessage("@ab=cdef;znc.in/gh-ij=klmn,op :rest").GetTags(), ContainerEq(MCString{{"ab","cdef"},{"znc.in/gh-ij","klmn,op"}})); + EXPECT_THAT(CMessage("@a===b== :rest").GetTags(), ContainerEq(MCString{{"a","==b=="}})); + + EXPECT_THAT(CMessage("@a;b=c;d :rest").GetTags(), ContainerEq(MCString{{"a",""},{"b","c"},{"d",""}})); + + EXPECT_THAT(CMessage(R"(@semi-colon=\:;space=\s;NUL=\0;backslash=\\;CR=\r;LF=\n :rest)").GetTags(), + ContainerEq(MCString{{"semi-colon",";"},{"space"," "},{"NUL",{'\0'}},{"backslash","\\"},{"CR",{'\r'}},{"LF",{'\n'}}})); + + EXPECT_THAT(CMessage(R"(@a=\:\s\\\r\n :rest)").GetTags(), ContainerEq(MCString{{"a","; \\\r\n"}})); + + CMessage msg(":rest"); + msg.SetTags({{"a","b"}}); + EXPECT_EQ("@a=b :rest", msg.ToString()); + + msg.SetTags({{"a","b"}, {"c","d"}}); + EXPECT_EQ("@a=b;c=d :rest", msg.ToString()); + + msg.SetTags({{"a","b"},{"c","d"},{"e",""}}); + EXPECT_EQ("@a=b;c=d;e :rest", msg.ToString()); + + msg.SetTags({{"semi-colon",";"},{"space"," "},{"NUL",{'\0'}},{"backslash","\\"},{"CR",{'\r'}},{"LF",{'\n'}}}); + EXPECT_EQ(R"(@CR=\r;LF=\n;NUL=\0;backslash=\\;semi-colon=\:;space=\s :rest)", msg.ToString()); + + msg.SetTags({{"a","; \\\r\n"}}); + EXPECT_EQ(R"(@a=\:\s\\\r\n :rest)", msg.ToString()); +} + TEST(MessageTest, FormatFlags) { const CString line = "@foo=bar :irc.example.com COMMAND param";