diff --git a/include/znc/IRCSock.h b/include/znc/IRCSock.h index 12edffbb..b791d45c 100644 --- a/include/znc/IRCSock.h +++ b/include/znc/IRCSock.h @@ -136,7 +136,7 @@ private: // !Message Handlers void SetNick(const CString& sNick); - void ParseISupport(const CString& sLine); + void ParseISupport(const CMessage& Message); // This is called when we connect and the nick we want is already taken void SendAltNick(const CString& sBadNick); void SendNextCap(); diff --git a/src/IRCSock.cpp b/src/IRCSock.cpp index d92a0a7d..6af961de 100644 --- a/src/IRCSock.cpp +++ b/src/IRCSock.cpp @@ -695,7 +695,7 @@ bool CIRCSock::OnNumericMessage(CNumericMessage& Message) { break; } case 5: - ParseISupport(sRest); + ParseISupport(Message); m_pNetwork->UpdateExactRawBuffer(":" + _NAMEDFMT(sServer) + " " + sCmd + " {target} " + _NAMEDFMT(sRest)); break; case 10: { // :irc.server.com 010 nick : @@ -1281,14 +1281,13 @@ void CIRCSock::ReachedMaxBuffer() { Quit(); } -void CIRCSock::ParseISupport(const CString& sLine) { - VCString vsTokens; +void CIRCSock::ParseISupport(const CMessage& Message) { + const VCString vsParams = Message.GetParams(); - sLine.Split(" ", vsTokens, false); - - for (const CString& sToken : vsTokens) { - CString sName = sToken.Token(0, false, "="); - CString sValue = sToken.Token(1, true, "="); + for (size_t i = 1; i < vsParams.size() - 1; ++i) { + const CString& sParam = vsParams[i]; + CString sName = sParam.Token(0, false, "="); + CString sValue = sParam.Token(1, true, "="); if (0 < sName.length() && ':' == sName[0]) { break; diff --git a/test/IRCSockTest.cpp b/test/IRCSockTest.cpp index f2b024f6..3e958377 100644 --- a/test/IRCSockTest.cpp +++ b/test/IRCSockTest.cpp @@ -24,9 +24,11 @@ #include #include #include +#include using ::testing::IsEmpty; using ::testing::ElementsAre; +using ::testing::ContainerEq; class TestClient : public CClient { public: @@ -443,3 +445,71 @@ TEST_F(IRCSockTest, OnWallopsMessage) { EXPECT_THAT(m_pTestModule->vsHooks, IsEmpty()); // no OnWallopsMessage() hook (yet?) EXPECT_THAT(m_pTestClient->vsLines, ElementsAre(msg.ToString())); } + +TEST_F(IRCSockTest, ISupport) { + MCString m1 = { + {"CHANTYPES", "#"}, + {"EXCEPTS", ""}, + {"INVEX", ""}, + {"CHANMODES", "eIbq,k,flj,CFLMPQScgimnprstz"}, + {"CHANLIMIT", "#:120"}, + {"PREFIX", "(ov)@+"}, + {"MAXLIST", "bqeI:100"}, + {"MODES", "4"}, + {"NETWORK", "znc"}, + {"KNOCK", ""}, + {"STATUSMSG", "@+"}, + {"CALLERID", "g"}, + }; + + m_pTestSock->ReadLine(":irc.znc.in 005 user CHANTYPES=# EXCEPTS INVEX CHANMODES=eIbq,k,flj,CFLMPQScgimnprstz CHANLIMIT=#:120 PREFIX=(ov)@+ MAXLIST=bqeI:100 MODES=4 NETWORK=znc KNOCK STATUSMSG=@+ CALLERID=g :are supported by this server"); + EXPECT_THAT(m_pTestSock->GetISupport(), ContainerEq(m1)); + for (const auto& it : m1) { + EXPECT_EQ(it.second, m_pTestSock->GetISupport(it.first)); + } + + MCString m2 = { + {"CASEMAPPING", "rfc1459"}, + {"CHARSET", "ascii"}, + {"NICKLEN", "16"}, + {"CHANNELLEN", "50"}, + {"TOPICLEN", "390"}, + {"ETRACE", ""}, + {"CPRIVMSG", ""}, + {"CNOTICE", ""}, + {"DEAF", "D"}, + {"MONITOR", "100"}, + {"FNC", ""}, + {"TARGMAX", "NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR:"}, + }; + + MCString m12; + std::merge(m1.begin(), m1.end(), m2.begin(), m2.end(), std::inserter(m12, m12.begin())); + + m_pTestSock->ReadLine(":server 005 user CASEMAPPING=rfc1459 CHARSET=ascii NICKLEN=16 CHANNELLEN=50 TOPICLEN=390 ETRACE CPRIVMSG CNOTICE DEAF=D MONITOR=100 FNC TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,PRIVMSG:4,NOTICE:4,ACCEPT:,MONITOR: :are supported by this server"); + EXPECT_THAT(m_pTestSock->GetISupport(), ContainerEq(m12)); + for (const auto& it : m2) { + EXPECT_EQ(it.second, m_pTestSock->GetISupport(it.first)); + } + + MCString m3 = { + {"EXTBAN", "$,ajrxz"}, + {"WHOX", ""}, + {"CLIENTVER", "3.0"}, + {"SAFELIST", ""}, + {"ELIST", "CTU"}, + }; + + MCString m123; + std::merge(m12.begin(), m12.end(), m3.begin(), m3.end(), std::inserter(m123, m123.begin())); + + m_pTestSock->ReadLine(":server 005 zzzzzz EXTBAN=$,ajrxz WHOX CLIENTVER=3.0 SAFELIST ELIST=CTU :are supported by this server"); + EXPECT_THAT(m_pTestSock->GetISupport(), ContainerEq(m123)); + for (const auto& it : m3) { + EXPECT_EQ(it.second, m_pTestSock->GetISupport(it.first)); + } + + EXPECT_EQ("default", m_pTestSock->GetISupport("FOOBAR", "default")); + EXPECT_EQ("3.0", m_pTestSock->GetISupport("CLIENTVER", "default")); + EXPECT_EQ("", m_pTestSock->GetISupport("SAFELIST", "default")); +}