diff --git a/Makefile.in b/Makefile.in index c26b3d96..ae6235af 100644 --- a/Makefile.in +++ b/Makefile.in @@ -47,7 +47,7 @@ LIB_SRCS := $(addprefix src/,$(LIB_SRCS)) BIN_SRCS := src/main.cpp LIB_OBJS := $(patsubst %cpp,%o,$(LIB_SRCS)) BIN_OBJS := $(patsubst %cpp,%o,$(BIN_SRCS)) -TESTS := StringTest ConfigTest UtilsTest ThreadTest +TESTS := StringTest ConfigTest UtilsTest ThreadTest NickTest TESTS := $(addprefix test/,$(addsuffix .o,$(TESTS))) CLEAN := znc src/*.o test/*.o core core.* .version_extra .depend modules/.depend unittest DISTCLEAN := Makefile config.log config.status znc-buildmod \ diff --git a/include/znc/Client.h b/include/znc/Client.h index f83ad356..938df057 100644 --- a/include/znc/Client.h +++ b/include/znc/Client.h @@ -95,6 +95,7 @@ public: m_bAway = false; m_bServerTime = false; m_bBatch = false; + m_bSelfMessage = false; EnableReadLine(); // RFC says a line can have 512 chars max, but we are // a little more gentle ;) @@ -116,6 +117,7 @@ public: bool IsAway() const { return m_bAway; } bool HasServerTime() const { return m_bServerTime; } bool HasBatch() const { return m_bBatch; } + bool HasSelfMessage() const { return m_bSelfMessage; } void UserCommand(CString& sLine); void UserPortCommand(CString& sLine); @@ -166,6 +168,7 @@ protected: bool m_bAway; bool m_bServerTime; bool m_bBatch; + bool m_bSelfMessage; CUser* m_pUser; CIRCNetwork* m_pNetwork; CString m_sNick; diff --git a/src/Client.cpp b/src/Client.cpp index bda6f7a1..05cc2e21 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -271,15 +271,11 @@ void CClient::ReadLine(const CString& sData) { } // Relay to the rest of the clients that may be connected to this user - if (m_pNetwork->IsChan(sTarget)) { - const vector& vClients = GetClients(); + const vector& vClients = GetClients(); - for (unsigned int a = 0; a < vClients.size(); a++) { - CClient* pClient = vClients[a]; - - if (pClient != this) { - pClient->PutClient(":" + GetNickMask() + " NOTICE " + sTarget + " :" + sMsg); - } + for (CClient* pClient : vClients) { + if (pClient != this && (m_pNetwork->IsChan(sTarget) || pClient->HasSelfMessage())) { + pClient->PutClient(":" + GetNickMask() + " NOTICE " + sTarget + " :" + sMsg); } } @@ -324,17 +320,6 @@ void CClient::ReadLine(const CString& sData) { if (pChan && (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline())) { pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :\001ACTION {text}\001", sMessage); } - - // Relay to the rest of the clients that may be connected to this user - const vector& vClients = GetClients(); - - for (unsigned int a = 0; a < vClients.size(); a++) { - CClient* pClient = vClients[a]; - - if (pClient != this) { - pClient->PutClient(":" + GetNickMask() + " PRIVMSG " + sTarget + " :\001" + sCTCP + "\001"); - } - } } else { if (!m_pUser->AutoClearQueryBuffer() || !m_pNetwork->IsUserOnline()) { CQuery* pQuery = m_pNetwork->AddQuery(sTarget); @@ -343,6 +328,15 @@ void CClient::ReadLine(const CString& sData) { } } } + + // Relay to the rest of the clients that may be connected to this user + const vector& vClients = GetClients(); + + for (CClient* pClient : vClients) { + if (pClient != this && (m_pNetwork->IsChan(sTarget) || pClient->HasSelfMessage())) { + pClient->PutClient(":" + GetNickMask() + " PRIVMSG " + sTarget + " :\001" + sCTCP + "\001"); + } + } } else { NETWORKMODULECALL(OnUserCTCP(sTarget, sCTCP), m_pUser, m_pNetwork, this, &bContinue); if (bContinue) continue; @@ -393,16 +387,11 @@ void CClient::ReadLine(const CString& sData) { PutIRC("PRIVMSG " + sTarget + " :" + sMsg); // Relay to the rest of the clients that may be connected to this user + const vector& vClients = GetClients(); - if (m_pNetwork->IsChan(sTarget)) { - const vector& vClients = GetClients(); - - for (unsigned int a = 0; a < vClients.size(); a++) { - CClient* pClient = vClients[a]; - - if (pClient != this) { - pClient->PutClient(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + sMsg); - } + for (CClient* pClient : vClients) { + if (pClient != this && (m_pNetwork->IsChan(sTarget) || pClient->HasSelfMessage())) { + pClient->PutClient(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + sMsg); } } } @@ -877,7 +866,7 @@ void CClient::HandleCap(const CString& sLine) for (SCString::iterator i = ssOfferCaps.begin(); i != ssOfferCaps.end(); ++i) { sRes += *i + " "; } - RespondCap("LS :" + sRes + "userhost-in-names multi-prefix znc.in/server-time-iso znc.in/batch"); + RespondCap("LS :" + sRes + "userhost-in-names multi-prefix znc.in/server-time-iso znc.in/batch znc.in/self-message"); m_bInCap = true; } else if (sSubCmd.Equals("END")) { m_bInCap = false; @@ -899,7 +888,7 @@ void CClient::HandleCap(const CString& sLine) if (sCap.TrimPrefix("-")) bVal = false; - bool bAccepted = ("multi-prefix" == sCap) || ("userhost-in-names" == sCap) || ("znc.in/server-time-iso" == sCap) || ("znc.in/batch" == sCap); + bool bAccepted = ("multi-prefix" == sCap) || ("userhost-in-names" == sCap) || ("znc.in/server-time-iso" == sCap) || ("znc.in/batch" == sCap) || ("znc.in/self-message" == sCap); GLOBALMODULECALL(IsClientCapSupported(this, sCap, bVal), &bAccepted); if (!bAccepted) { @@ -923,6 +912,8 @@ void CClient::HandleCap(const CString& sLine) m_bServerTime = bVal; } else if ("znc.in/batch" == *it) { m_bBatch = bVal; + } else if ("znc.in/self-message" == *it) { + m_bSelfMessage = bVal; } GLOBALMODULECALL(OnClientCapRequest(this, *it, bVal), NOTHING); @@ -966,6 +957,10 @@ void CClient::HandleCap(const CString& sLine) m_bBatch = false; ssRemoved.insert("znc.in/batch"); } + if (m_bSelfMessage) { + m_bSelfMessage = false; + ssRemoved.insert("znc.in/self-message"); + } CString sList = ""; for (SCString::iterator i = ssRemoved.begin(); i != ssRemoved.end(); ++i) { m_ssAcceptedCaps.erase(*i); diff --git a/src/Nick.cpp b/src/Nick.cpp index 5d225be5..4f735946 100644 --- a/src/Nick.cpp +++ b/src/Nick.cpp @@ -49,7 +49,7 @@ void CNick::Parse(const CString& sNickMask) { return; } - m_sNick = sNickMask.substr((sNickMask[0] == ':'), uPos); + m_sNick = sNickMask.substr((sNickMask[0] == ':'), uPos - (sNickMask[0] == ':')); m_sHost = sNickMask.substr(uPos +1); if ((uPos = m_sHost.find('@')) != CString::npos) { diff --git a/src/Query.cpp b/src/Query.cpp index c8ee025e..2432e71f 100644 --- a/src/Query.cpp +++ b/src/Query.cpp @@ -53,7 +53,16 @@ void CQuery::SendBuffer(CClient* pClient, const CBuffer& Buffer) { size_t uSize = Buffer.Size(); for (size_t uIdx = 0; uIdx < uSize; uIdx++) { - CString sLine = Buffer.GetLine(uIdx, *pUseClient, msParams); + const CBufLine& BufLine = Buffer.GetBufLine(uIdx); + + if (!pUseClient->HasSelfMessage()) { + CNick Sender(BufLine.GetFormat().Token(0)); + if (Sender.NickEquals(pUseClient->GetNick())) { + continue; + } + } + + CString sLine = BufLine.GetLine(*pUseClient, msParams); if (bBatch) { MCString msBatchTags = CUtils::GetMessageTags(sLine); msBatchTags["batch"] = sBatchName; diff --git a/test/NickTest.cpp b/test/NickTest.cpp new file mode 100644 index 00000000..56a352d0 --- /dev/null +++ b/test/NickTest.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2004-2014 ZNC, see the NOTICE file for details. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +TEST(NickTest, Parse) { + CNick Nick1("nick!~ident@host"); + EXPECT_EQ("nick", Nick1.GetNick()); + EXPECT_EQ("~ident", Nick1.GetIdent()); + EXPECT_EQ("host", Nick1.GetHost()); + EXPECT_EQ("nick!~ident@host", Nick1.GetNickMask()); + EXPECT_EQ("nick!~ident@host", Nick1.GetHostMask()); + EXPECT_TRUE(Nick1.NickEquals("nick")); + + CNick Nick2(":nick!~ident@host"); + EXPECT_EQ("nick", Nick2.GetNick()); + EXPECT_EQ("~ident", Nick2.GetIdent()); + EXPECT_EQ("host", Nick2.GetHost()); + EXPECT_EQ("nick!~ident@host", Nick2.GetNickMask()); + EXPECT_EQ("nick!~ident@host", Nick2.GetHostMask()); + EXPECT_TRUE(Nick2.NickEquals("nick")); +}