Add OnSendToIRCMessage and OnSendToClientMessage

This also alters PutClient such that the CMessage variant handles
sending messages, rather than the CString variant. As a side bonus, this
gives callers better information on whether the message was sent to the
client. Additionally, it eliminates the need for a hook to let modules
set the tags sent to a client, as that can now be done inside
OnSendToClientMessage.
This commit is contained in:
Eli Young
2017-04-11 13:03:38 -07:00
parent f37aa308e1
commit 823ac07240
13 changed files with 123 additions and 26 deletions
+13 -5
View File
@@ -1026,18 +1026,24 @@ class CModule {
*/
virtual EModRet OnDeleteNetwork(CIRCNetwork& Network);
/** Called when ZNC sends a raw traffic line to a client.
* @param sLine The raw traffic line sent.
* @param Client The client this line is sent to.
/** Called immediately before ZNC sends a raw traffic line to a client.
* @since 1.7.0
* @param Message The message being sent to the client.
* @warning Calling PutUser() from within this hook leads to infinite recursion.
* @return See CModule::EModRet.
*/
virtual EModRet OnSendToClientMessage(CMessage& Message);
/// @deprecated Use OnSendToClientMessage() instead.
virtual EModRet OnSendToClient(CString& sLine, CClient& Client);
/** Called when ZNC sends a raw traffic line to the IRC server.
* @param sLine The raw traffic line sent.
/** Called immediately before ZNC sends a raw traffic line to the IRC server.
* @since 1.7.0
* @param Message The message being sent to the IRC server.
* @warning Calling PutIRC() from within this hook leads to infinite recursion.
* @return See CModule::EModRet.
*/
virtual EModRet OnSendToIRCMessage(CMessage& Message);
/// @deprecated Use OnSendToIRCMessage() instead.
virtual EModRet OnSendToIRC(CString& sLine);
ModHandle GetDLL() { return m_pDLL; }
@@ -1515,7 +1521,9 @@ class CModules : public std::vector<CModule*> {
bool OnDeleteNetwork(CIRCNetwork& Network);
bool OnSendToClient(CString& sLine, CClient& Client);
bool OnSendToClientMessage(CMessage& Message);
bool OnSendToIRC(CString& sLine);
bool OnSendToIRCMessage(CMessage& Message);
bool OnServerCapAvailable(const CString& sCap);
bool OnServerCapResult(const CString& sCap, bool bSuccess);
+2
View File
@@ -97,3 +97,5 @@ EModRet OnChanTextMessage(CTextMessage& Message)
EModRet OnPrivNoticeMessage(CNoticeMessage& Message)
EModRet OnChanNoticeMessage(CNoticeMessage& Message)
EModRet OnTopicMessage(CTopicMessage& Message)
EModRet OnSendToClientMessage(CMessage& Message)
EModRet OnSendToIRCMessage(CMessage& Message)
+2
View File
@@ -153,6 +153,8 @@ class ZNC_EXPORT_LIB_EXPORT CPerlModule : public CModule {
EModRet OnPrivNoticeMessage(CNoticeMessage& Message) override;
EModRet OnChanNoticeMessage(CNoticeMessage& Message) override;
EModRet OnTopicMessage(CTopicMessage& Message) override;
EModRet OnSendToClientMessage(CMessage& Message) override;
EModRet OnSendToIRCMessage(CMessage& Message) override;
};
static inline CPerlModule* AsPerlModule(CModule* p) {
+2
View File
@@ -577,6 +577,8 @@ sub OnTopicMessage {
$msg->SetTopic($topic);
return $ret;
}
sub OnSendToClientMessage {}
sub OnSendToIRCMessage {}
# In Perl "undefined" is allowed value, so perl modules may continue using OnMode and not OnMode2
sub OnChanPermission2 { my $self = shift; $self->OnChanPermission(@_) }
+2
View File
@@ -97,6 +97,8 @@ EModRet OnChanTextMessage(CTextMessage& Message)
EModRet OnPrivNoticeMessage(CNoticeMessage& Message)
EModRet OnChanNoticeMessage(CNoticeMessage& Message)
EModRet OnTopicMessage(CTopicMessage& Message)
EModRet OnSendToClientMessage(CMessage& Message)
EModRet OnSendToIRCMessage(CMessage& Message)
EModRet OnAddUser(CUser& User, CString& sErrorRet)
EModRet OnDeleteUser(CUser& User)
+2
View File
@@ -173,6 +173,8 @@ class ZNC_EXPORT_LIB_EXPORT CPyModule : public CModule {
EModRet OnPrivNoticeMessage(CNoticeMessage& Message) override;
EModRet OnChanNoticeMessage(CNoticeMessage& Message) override;
EModRet OnTopicMessage(CTopicMessage& Message) override;
EModRet OnSendToClientMessage(CMessage& Message) override;
EModRet OnSendToIRCMessage(CMessage& Message) override;
// Global Modules
EModRet OnAddUser(CUser& User, CString& sErrorRet) override;
+6
View File
@@ -655,6 +655,12 @@ class Module:
def OnUnknownUserRawMessage(self, msg):
pass
def OnSendToClientMessage(self, msg):
pass
def OnSendToIRCMessage(self, msg):
pass
def make_inherit(cl, parent, attr):
def make_caller(parent, name, attr):
+18 -15
View File
@@ -483,13 +483,8 @@ CString CClient::GetFullName() const {
}
void CClient::PutClient(const CString& sLine) {
bool bReturn = false;
CString sCopy = sLine;
NETWORKMODULECALL(OnSendToClient(sCopy, *this), m_pUser, m_pNetwork, this,
&bReturn);
if (bReturn) return;
DEBUG("(" << GetFullName() << ") ZNC -> CLI [" << sCopy << "]");
Write(sCopy + "\r\n");
CMessage Message(sLine);
PutClient(Message);
}
bool CClient::PutClient(const CMessage& Message) {
@@ -563,10 +558,7 @@ bool CClient::PutClient(const CMessage& Message) {
}
}
CString sLine = Msg.ToString(CMessage::ExcludeTags);
// TODO: introduce a module hook that gives control over the tags that are
// sent
// TODO: add the ability to set a list of tags to send
MCString mssTags;
if (HasServerTime()) {
@@ -585,11 +577,22 @@ bool CClient::PutClient(const CMessage& Message) {
}
}
if (!mssTags.empty()) {
CUtils::SetMessageTags(sLine, mssTags);
}
Msg.SetTags(mssTags);
Msg.SetClient(this);
Msg.SetNetwork(m_pNetwork);
PutClient(sLine);
bool bReturn = false;
NETWORKMODULECALL(OnSendToClientMessage(Msg), m_pUser, m_pNetwork, this,
&bReturn);
if (bReturn) return false;
CString sCopy = Msg.ToString();
NETWORKMODULECALL(OnSendToClient(sCopy, *this), m_pUser, m_pNetwork, this,
&bReturn);
if (bReturn) return false;
DEBUG("(" << GetFullName() << ") ZNC -> CLI [" << sCopy << "]");
Write(sCopy + "\r\n");
return true;
}
+13 -6
View File
@@ -1154,13 +1154,20 @@ void CIRCSock::TrySend() {
m_iSendsAllowed--;
bool bSkip = false;
CString& sLine = m_vsSendQueue.front();
IRCSOCKMODULECALL(OnSendToIRC(sLine), &bSkip);
CMessage Message(sLine);
Message.SetNetwork(m_pNetwork);
IRCSOCKMODULECALL(OnSendToIRCMessage(Message), &bSkip);
if (!bSkip) {
;
DEBUG("(" << m_pNetwork->GetUser()->GetUserName() << "/"
<< m_pNetwork->GetName() << ") ZNC -> IRC [" << sLine
<< "]");
Write(sLine + "\r\n");
CString sCopy = Message.ToString();
IRCSOCKMODULECALL(OnSendToIRC(sCopy), &bSkip);
if (!bSkip) {
DEBUG("(" << m_pNetwork->GetUser()->GetUserName() << "/"
<< m_pNetwork->GetName() << ") ZNC -> IRC [" << sCopy
<< "]");
Write(sCopy + "\r\n");
}
}
m_vsSendQueue.pop_front();
}
+13
View File
@@ -983,7 +983,14 @@ CModule::EModRet CModule::OnDeleteNetwork(CIRCNetwork& Network) {
CModule::EModRet CModule::OnSendToClient(CString& sLine, CClient& Client) {
return CONTINUE;
}
CModule::EModRet CModule::OnSendToClientMessage(CMessage& Message) {
return CONTINUE;
}
CModule::EModRet CModule::OnSendToIRC(CString& sLine) { return CONTINUE; }
CModule::EModRet CModule::OnSendToIRCMessage(CMessage& Message) {
return CONTINUE;
}
bool CModule::OnServerCapAvailable(const CString& sCap) { return false; }
void CModule::OnServerCapResult(const CString& sCap, bool bSuccess) {}
@@ -1444,7 +1451,13 @@ bool CModules::OnDeleteNetwork(CIRCNetwork& Network) {
bool CModules::OnSendToClient(CString& sLine, CClient& Client) {
MODHALTCHK(OnSendToClient(sLine, Client));
}
bool CModules::OnSendToClientMessage(CMessage& Message) {
MODHALTCHK(OnSendToClientMessage(Message));
}
bool CModules::OnSendToIRC(CString& sLine) { MODHALTCHK(OnSendToIRC(sLine)); }
bool CModules::OnSendToIRCMessage(CMessage& Message) {
MODHALTCHK(OnSendToIRCMessage(Message));
}
bool CModules::OnStatusCommand(CString& sCommand) {
MODHALTCHK(OnStatusCommand(sCommand));
}
+20
View File
@@ -343,3 +343,23 @@ TEST_F(ClientTest, OnUserQuitMessage) {
m_pTestClient->ReadLine(msg.ToString());
EXPECT_THAT(m_pTestSock->vsLines, IsEmpty()); // quit is never forwarded
}
TEST_F(ClientTest, OnSendToClientMessage) {
CMessage msg("PRIVMSG #chan :text");
m_pTestModule->eAction = CModule::HALT;
m_pTestModule->bSendHooks = true;
m_pTestClient->PutClient(msg.ToString());
EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnSendToClientMessage"));
EXPECT_THAT(m_pTestModule->vsMessages, ElementsAre(msg.ToString()));
EXPECT_THAT(m_pTestModule->vNetworks, ElementsAre(m_pTestClient->GetNetwork()));
EXPECT_THAT(m_pTestModule->vClients, ElementsAre(m_pTestClient));
EXPECT_THAT(m_pTestModule->vChannels, ElementsAre(nullptr));
EXPECT_THAT(m_pTestSock->vsLines, IsEmpty()); // halt
m_pTestModule->eAction = CModule::CONTINUE;
m_pTestClient->ReadLine(msg.ToString());
EXPECT_THAT(m_pTestSock->vsLines, ElementsAre(msg.ToString()));
m_pTestModule->bSendHooks = false;
}
+19
View File
@@ -361,6 +361,25 @@ TEST_F(IRCSockTest, OnQuitMessage) {
EXPECT_THAT(m_pTestClient->vsLines, ElementsAre(msg.ToString()));
}
TEST_F(IRCSockTest, OnSendToIRCMessage) {
CMessage msg(":nick PRIVMSG #chan :hello");
m_pTestModule->eAction = CModule::HALT;
m_pTestModule->bSendHooks = true;
m_pTestSock->PutIRC(msg.ToString());
EXPECT_THAT(m_pTestModule->vsHooks, ElementsAre("OnSendToIRCMessage"));
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()));
m_pTestModule->bSendHooks = false;
}
TEST_F(IRCSockTest, OnTextMessage) {
CMessage msg(":nick PRIVMSG #chan :hello");
m_pTestModule->eAction = CModule::HALT;
+11
View File
@@ -129,6 +129,16 @@ class TestModule : public CModule {
OnMessage(msg);
}
EModRet OnSendToClientMessage(CMessage& msg) override {
if (!bSendHooks) return CONTINUE;
vsHooks.push_back("OnSendToClientMessage");
return OnMessage(msg);
}
EModRet OnSendToIRCMessage(CMessage& msg) override {
if (!bSendHooks) return CONTINUE;
vsHooks.push_back("OnSendToIRCMessage");
return OnMessage(msg);
}
EModRet OnUserCTCPReplyMessage(CCTCPMessage& msg) override {
vsHooks.push_back("OnUserCTCPReplyMessage");
return OnMessage(msg);
@@ -188,6 +198,7 @@ class TestModule : public CModule {
std::vector<CClient*> vClients;
std::vector<CChan*> vChannels;
EModRet eAction = CONTINUE;
bool bSendHooks = false;
};
class IRCTest : public ::testing::Test {