mirror of
https://github.com/znc/znc.git
synced 2026-08-07 09:22:55 +02:00
Merge branch 'master' into notify
Conflicts:
test/Integration.cpp
This commit is contained in:
+9
-3
@@ -98,10 +98,16 @@ after_success:
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
# travis encrypt "irc.freenode.net#znc-dev" -r znc/znc
|
||||
# prevents forks from spamming #znc-dev by just enabling Travis
|
||||
- secure: "ACdKvJT+gvuzDTfQkhnHI8aQNtXHI1tJOgFPss9XpF8025KYxrvhuff15VRhYuDCuNSuqhZYG9Oz+ZCQzu85ravkXVa3X+ze8SRoIIwAN2tpkr7KTfbJc4gD2S/RZUi432ICiQznHWnhV209XSLXY4qBhnR0OkCg5/pY8zievYw="
|
||||
# irc.freenode.net #znc-dev (via ZNC-Linker)
|
||||
# encryption prevents forks from spamming #znc-dev by just enabling Travis
|
||||
# Format is poorly documented at https://github.com/travis-ci/travis-ci/issues/2813
|
||||
- secure: "L7UcaWs3Y0y0QlOzUFnCJQ3clFXcik1ygswDdzE3q4lyUa7/4WeAoocJWLxp9PPL6hXZygsiXj4gIBWq4wqDEbsZzO+xZvleq2i3KGf7YdDgPTYJJN9ppIHR3Q+pmnODtYu1dHpLTunS2g7vVzJHNjIKQvORl9CTx9lDNHKjG5A="
|
||||
on_success: always
|
||||
on_failure: always
|
||||
skip_join: true
|
||||
nick:
|
||||
secure: "UGh4tbpviOD438ZOi+I3W6eh+R68tbpNIJc0uf5FK6xhHLLo3FRIozkL7CRVA3TxYHuahwerZpBR4TbAyc+gVUn5YRHjdsMIPHPCW/kh8ZkEJKNYXkHerbH0Np6PRLI58l6lmjMQbiWn+lqlgsHdVsyknqxDwoj7JDieE+5X53c="
|
||||
password:
|
||||
secure: "B2F1coXddY1H0/v3OkiPnUlbnSN/wapRay1PUbN8tvm7IDYOjpivhsRk+31/4pauKOoF4AZhzP6F9mhGxkGYBQ23Td5Y6+uZeaDnTYnXjs8fbV0QY1Mx+2EkHDSkLQoYlYr06pK9q55X3uLK1zTz5Ye0Po3KzbeydxOyyG+xBGg="
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
+12
-2
@@ -117,21 +117,23 @@ public:
|
||||
#ifndef SWIG
|
||||
template <typename M>
|
||||
M& As() ZNC_LVREFQUAL {
|
||||
static_assert(std::is_base_of<CMessage, M>{}, "Must be subclass of CMessage");
|
||||
static_assert(sizeof(M) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
return static_cast<M&>(*this);
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
const M& As() const ZNC_LVREFQUAL {
|
||||
static_assert(std::is_base_of<CMessage, M>{}, "Must be subclass of CMessage");
|
||||
static_assert(sizeof(M) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
return static_cast<const M&>(*this);
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
template <typename M, typename = typename std::enable_if<std::is_base_of<CMessage, M>{}>::type>
|
||||
operator M&() ZNC_LVREFQUAL {
|
||||
return As<M>();
|
||||
}
|
||||
template <typename M>
|
||||
template <typename M, typename = typename std::enable_if<std::is_base_of<CMessage, M>{}>::type>
|
||||
operator const M&() const ZNC_LVREFQUAL {
|
||||
return As<M>();
|
||||
}
|
||||
@@ -158,6 +160,14 @@ private:
|
||||
bool m_bColon = false;
|
||||
};
|
||||
|
||||
// For gtest
|
||||
#ifdef GTEST_FAIL
|
||||
template <typename M, typename = typename std::enable_if<std::is_base_of<CMessage, M>{}>::type>
|
||||
inline ::std::ostream& operator<<(::std::ostream& os, const M& msg) {
|
||||
return os << msg.ToString().Escape_n(CString::EDEBUG);
|
||||
}
|
||||
#endif
|
||||
|
||||
// The various CMessage subclasses are "mutable views" to the data held by CMessage.
|
||||
// They provide convenient access to message type speficic attributes, but are not
|
||||
// allowed to hold extra data of their own.
|
||||
|
||||
@@ -128,6 +128,8 @@ public:
|
||||
CString GetUserPath() const;
|
||||
CString GetModPath() const;
|
||||
CString GetPemLocation() const;
|
||||
CString GetKeyLocation() const;
|
||||
CString GetDHParamLocation() const;
|
||||
const CString& GetConfigFile() const { return m_sConfigFile; }
|
||||
bool WritePemFile();
|
||||
/** @deprecated Since 1.7.0. List of allowed bind hosts was a flawed design. */
|
||||
@@ -233,6 +235,8 @@ protected:
|
||||
CString m_sStatusPrefix;
|
||||
CString m_sPidFile;
|
||||
CString m_sSSLCertFile;
|
||||
CString m_sSSLKeyFile;
|
||||
CString m_sSSLDHParamFile;
|
||||
CString m_sSSLCiphers;
|
||||
CString m_sSSLProtocols;
|
||||
VCString m_vsBindHosts; // TODO: remove (deprecated in 1.7.0)
|
||||
|
||||
@@ -501,10 +501,6 @@ public:
|
||||
return HandleMessage("NOTICE", sTarget, sMessage);
|
||||
}
|
||||
|
||||
EModRet OnUserAction(CString& sTarget, CString& sMessage) override {
|
||||
return HandleMessage("PRIVMSG", sTarget, "\001ACTION " + sMessage + "\001");
|
||||
}
|
||||
|
||||
EModRet OnUserCTCP(CString& sTarget, CString& sMessage) override {
|
||||
return HandleMessage("PRIVMSG", sTarget, "\001" + sMessage + "\001");
|
||||
}
|
||||
|
||||
@@ -290,6 +290,8 @@ bool CIRCSock::OnActionMessage(CActionMessage& Message) {
|
||||
CChan* pChan = nullptr;
|
||||
CString sTarget = Message.GetTarget();
|
||||
if (sTarget.Equals(GetNick())) {
|
||||
IRCSOCKMODULECALL(OnPrivCTCPMessage(Message), &bResult);
|
||||
if (bResult) return true;
|
||||
IRCSOCKMODULECALL(OnPrivActionMessage(Message), &bResult);
|
||||
if (bResult) return true;
|
||||
|
||||
@@ -310,6 +312,8 @@ bool CIRCSock::OnActionMessage(CActionMessage& Message) {
|
||||
if (pChan) {
|
||||
Message.SetChan(pChan);
|
||||
FixupChanNick(Message.GetNick(), pChan);
|
||||
IRCSOCKMODULECALL(OnChanCTCPMessage(Message), &bResult);
|
||||
if (bResult) return true;
|
||||
IRCSOCKMODULECALL(OnChanActionMessage(Message), &bResult);
|
||||
if (bResult) return true;
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ bool CListener::Listen() {
|
||||
if (IsSSL()) {
|
||||
bSSL = true;
|
||||
m_pListener->SetPemLocation(CZNC::Get().GetPemLocation());
|
||||
m_pListener->SetKeyLocation(CZNC::Get().GetKeyLocation());
|
||||
m_pListener->SetDHParamLocation(CZNC::Get().GetDHParamLocation());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
+17
-1
@@ -53,6 +53,8 @@ CZNC::CZNC()
|
||||
m_sStatusPrefix(""),
|
||||
m_sPidFile(""),
|
||||
m_sSSLCertFile(""),
|
||||
m_sSSLKeyFile(""),
|
||||
m_sSSLDHParamFile(""),
|
||||
m_sSSLCiphers(""),
|
||||
m_sSSLProtocols(""),
|
||||
m_vsBindHosts(),
|
||||
@@ -364,7 +366,7 @@ void CZNC::InitDirs(const CString& sArgvPath, const CString& sDataDir) {
|
||||
m_sZNCPath = sDataDir;
|
||||
}
|
||||
|
||||
m_sSSLCertFile = m_sZNCPath + "/znc.pem";
|
||||
m_sSSLCertFile = m_sSSLKeyFile = m_sSSLDHParamFile = m_sZNCPath + "/znc.pem";
|
||||
}
|
||||
|
||||
CString CZNC::GetConfPath(bool bAllowMkDir) const {
|
||||
@@ -413,6 +415,14 @@ CString CZNC::GetPemLocation() const {
|
||||
return CDir::ChangeDir("", m_sSSLCertFile);
|
||||
}
|
||||
|
||||
CString CZNC::GetKeyLocation() const {
|
||||
return CDir::ChangeDir("", m_sSSLKeyFile);
|
||||
}
|
||||
|
||||
CString CZNC::GetDHParamLocation() const {
|
||||
return CDir::ChangeDir("", m_sSSLDHParamFile);
|
||||
}
|
||||
|
||||
CString CZNC::ExpandConfigPath(const CString& sConfigFile, bool bAllowMkDir) {
|
||||
CString sRetPath;
|
||||
|
||||
@@ -462,6 +472,8 @@ bool CZNC::WriteConfig() {
|
||||
config.AddKeyValuePair("AnonIPLimit", CString(m_uiAnonIPLimit));
|
||||
config.AddKeyValuePair("MaxBufferSize", CString(m_uiMaxBufferSize));
|
||||
config.AddKeyValuePair("SSLCertFile", CString(m_sSSLCertFile));
|
||||
config.AddKeyValuePair("SSLKeyFile", CString(m_sSSLKeyFile));
|
||||
config.AddKeyValuePair("SSLDHParamFile", CString(m_sSSLDHParamFile));
|
||||
config.AddKeyValuePair("ProtectWebSessions", CString(m_bProtectWebSessions));
|
||||
config.AddKeyValuePair("HideVersion", CString(m_bHideVersion));
|
||||
config.AddKeyValuePair("Version", CString(VERSION_STR));
|
||||
@@ -1099,6 +1111,10 @@ bool CZNC::LoadGlobal(CConfig& config, CString& sError) {
|
||||
m_sStatusPrefix = sVal;
|
||||
if (config.FindStringEntry("sslcertfile", sVal))
|
||||
m_sSSLCertFile = sVal;
|
||||
if (config.FindStringEntry("sslkeyfile", sVal))
|
||||
m_sSSLKeyFile = sVal;
|
||||
if (config.FindStringEntry("ssldhparamfile", sVal))
|
||||
m_sSSLDHParamFile = sVal;
|
||||
if (config.FindStringEntry("sslciphers", sVal))
|
||||
m_sSSLCiphers = sVal;
|
||||
if (config.FindStringEntry("skin", sVal))
|
||||
|
||||
+86
-27
@@ -19,9 +19,14 @@
|
||||
#include "IRCTest.h"
|
||||
#include <algorithm>
|
||||
|
||||
using ::testing::IsEmpty;
|
||||
using ::testing::ElementsAre;
|
||||
using ::testing::ContainerEq;
|
||||
using testing::ElementsAre;
|
||||
using testing::ContainerEq;
|
||||
using testing::InSequence;
|
||||
using testing::Invoke;
|
||||
using testing::IsEmpty;
|
||||
using testing::Mock;
|
||||
using testing::ResultOf;
|
||||
using testing::_;
|
||||
|
||||
class IRCSockTest : public IRCTest {
|
||||
protected:
|
||||
@@ -36,38 +41,92 @@ TEST_F(IRCSockTest, OnAccountMessage) {
|
||||
}
|
||||
|
||||
TEST_F(IRCSockTest, OnActionMessage) {
|
||||
// 2 callbacks are called in row: OnCTCP, OnAction.
|
||||
// If OnCTCP returns HALT, OnAction isn't called.
|
||||
struct ActionModule : TestModule {
|
||||
ActionModule() {
|
||||
Reset();
|
||||
}
|
||||
void Reset() {
|
||||
Mock::VerifyAndClear(this);
|
||||
EXPECT_CALL(*this, OnPrivCTCPMessage(_)).Times(0);
|
||||
EXPECT_CALL(*this, OnChanCTCPMessage(_)).Times(0);
|
||||
EXPECT_CALL(*this, OnPrivActionMessage(_)).Times(0);
|
||||
EXPECT_CALL(*this, OnChanActionMessage(_)).Times(0);
|
||||
TestModule::Reset();
|
||||
}
|
||||
MOCK_METHOD1(OnPrivCTCPMessage, EModRet(CCTCPMessage&));
|
||||
MOCK_METHOD1(OnChanCTCPMessage, EModRet(CCTCPMessage&));
|
||||
MOCK_METHOD1(OnPrivActionMessage, EModRet(CActionMessage&));
|
||||
MOCK_METHOD1(OnChanActionMessage, EModRet(CActionMessage&));
|
||||
};
|
||||
ActionModule testModule;
|
||||
CZNC::Get().GetModules().push_back(&testModule);
|
||||
CChan* pExpectedChan = m_pTestChan;
|
||||
|
||||
CMessage msg(":nick PRIVMSG #chan :\001ACTION hello\001");
|
||||
m_pTestModule->eAction = CModule::HALT;
|
||||
auto CON = Invoke([&](CMessage& m) {
|
||||
EXPECT_EQ(msg.ToString(), m.ToString());
|
||||
EXPECT_EQ(m_pTestNetwork, m.GetNetwork());
|
||||
EXPECT_EQ(pExpectedChan, m.GetChan());
|
||||
return CModule::CONTINUE;
|
||||
});
|
||||
auto HAL = Invoke([&](CMessage& m) {
|
||||
EXPECT_EQ(msg.ToString(), m.ToString());
|
||||
EXPECT_EQ(m_pTestNetwork, m.GetNetwork());
|
||||
EXPECT_EQ(pExpectedChan, m.GetChan());
|
||||
return CModule::HALT;
|
||||
});
|
||||
auto Reset = [&]() { testModule.Reset(); m_pTestClient->Reset(); };
|
||||
|
||||
Reset();
|
||||
{
|
||||
InSequence seq;
|
||||
EXPECT_CALL(testModule, OnChanCTCPMessage(_)).WillOnce(CON);
|
||||
EXPECT_CALL(testModule, OnChanActionMessage(_)).WillOnce(CON);
|
||||
}
|
||||
m_pTestSock->ReadLine(msg.ToString());
|
||||
|
||||
EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnChanActionMessage"));
|
||||
EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
|
||||
EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(m_pTestNetwork));
|
||||
EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(m_pTestChan));
|
||||
EXPECT_THAT(m_pTestClient->vsLines, IsEmpty()); // halt
|
||||
|
||||
m_pTestModule->eAction = CModule::CONTINUE;
|
||||
m_pTestSock->ReadLine(msg.ToString());
|
||||
|
||||
EXPECT_THAT(m_pTestClient->vsLines, ElementsAre(msg.ToString()));
|
||||
|
||||
m_pTestClient->Reset();
|
||||
m_pTestModule->Reset();
|
||||
Reset();
|
||||
{
|
||||
InSequence seq;
|
||||
EXPECT_CALL(testModule, OnChanCTCPMessage(_)).WillOnce(CON);
|
||||
EXPECT_CALL(testModule, OnChanActionMessage(_)).WillOnce(HAL);
|
||||
}
|
||||
m_pTestSock->ReadLine(msg.ToString());
|
||||
EXPECT_THAT(m_pTestClient->vsLines, IsEmpty());
|
||||
|
||||
Reset();
|
||||
EXPECT_CALL(testModule, OnChanCTCPMessage(_)).WillOnce(HAL);
|
||||
m_pTestSock->ReadLine(msg.ToString());
|
||||
EXPECT_THAT(m_pTestClient->vsLines, IsEmpty());
|
||||
|
||||
msg.Parse(":nick PRIVMSG me :\001ACTION hello\001");
|
||||
m_pTestModule->eAction = CModule::HALT;
|
||||
pExpectedChan = nullptr;
|
||||
|
||||
Reset();
|
||||
{
|
||||
InSequence seq;
|
||||
EXPECT_CALL(testModule, OnPrivCTCPMessage(_)).WillOnce(CON);
|
||||
EXPECT_CALL(testModule, OnPrivActionMessage(_)).WillOnce(CON);
|
||||
}
|
||||
m_pTestSock->ReadLine(msg.ToString());
|
||||
|
||||
EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnPrivActionMessage"));
|
||||
EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
|
||||
EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(m_pTestNetwork));
|
||||
EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(nullptr));
|
||||
EXPECT_THAT(m_pTestClient->vsLines, IsEmpty()); // halt
|
||||
|
||||
m_pTestModule->eAction = CModule::CONTINUE;
|
||||
m_pTestSock->ReadLine(msg.ToString());
|
||||
|
||||
EXPECT_THAT(m_pTestClient->vsLines, ElementsAre(msg.ToString()));
|
||||
|
||||
Reset();
|
||||
{
|
||||
InSequence seq;
|
||||
EXPECT_CALL(testModule, OnPrivCTCPMessage(_)).WillOnce(CON);
|
||||
EXPECT_CALL(testModule, OnPrivActionMessage(_)).WillOnce(HAL);
|
||||
}
|
||||
m_pTestSock->ReadLine(msg.ToString());
|
||||
EXPECT_THAT(m_pTestClient->vsLines, IsEmpty());
|
||||
|
||||
Reset();
|
||||
EXPECT_CALL(testModule, OnPrivCTCPMessage(_)).WillOnce(HAL);
|
||||
m_pTestSock->ReadLine(msg.ToString());
|
||||
EXPECT_THAT(m_pTestClient->vsLines, IsEmpty());
|
||||
}
|
||||
|
||||
TEST_F(IRCSockTest, OnAwayMessage) {
|
||||
|
||||
@@ -1278,4 +1278,19 @@ TEST_F(ZNCTest, NotifyConnectModule) {
|
||||
client.ReadUntil("NOTICE nick :*** user@identifier detached (from 127.0.0.1)");Z;
|
||||
}
|
||||
|
||||
TEST_F(ZNCTest, WatchModule) {
|
||||
// TODO test other messages
|
||||
// TODO test options
|
||||
auto znc = Run();Z;
|
||||
auto ircd = ConnectIRCd();Z;
|
||||
auto client = LoginClient();Z;
|
||||
client.Write("znc loadmod watch");
|
||||
client.Write("PRIVMSG *watch :add *");
|
||||
client.ReadUntil("Adding entry:");
|
||||
ircd.Write(":server 001 nick :Hello");
|
||||
ircd.Write(":nick JOIN :#znc");
|
||||
ircd.Write(":n!i@h PRIVMSG #znc :\001ACTION foo\001");
|
||||
client.ReadUntil(":$*!watch@znc.in PRIVMSG nick :* CTCP: n [ACTION foo] to [#znc]");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Reference in New Issue
Block a user