diff --git a/include/znc/Modules.h b/include/znc/Modules.h index c63aa417..bad32c1f 100644 --- a/include/znc/Modules.h +++ b/include/znc/Modules.h @@ -1292,6 +1292,10 @@ class CModule { virtual EModRet OnUnknownUserRaw(CClient* pClient, CString& sLine); virtual EModRet OnUnknownUserRawMessage(CMessage& Message); + /** Called after login, upon disconnect, and also during JumpNetwork. */ + virtual void OnClientAttached(); + virtual void OnClientDetached(); + /** Called when a client told us CAP LS. Use ssCaps.insert("cap-name") * for announcing capabilities which your module supports. * @param pClient The client which requested the list. @@ -1550,6 +1554,8 @@ class CModules : public std::vector, private CCoreTranslationMixin { bool OnSendToClientMessage(CMessage& Message); bool OnSendToIRC(CString& sLine); bool OnSendToIRCMessage(CMessage& Message); + bool OnClientAttached(); + bool OnClientDetached(); bool OnServerCapAvailable(const CString& sCap, const CString& sValue); bool OnServerCapResult(const CString& sCap, bool bSuccess); diff --git a/src/Client.cpp b/src/Client.cpp index abe59200..05d0c92d 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -271,6 +271,7 @@ void CClient::SetNetwork(CIRCNetwork* pNetwork, bool bDisconnect, m_pNetwork->ClientDisconnected(this); if (bDisconnect) { + NETWORKMODULECALL(OnClientDetached(), m_pUser, m_pNetwork, this, NOTHING); ClearServerDependentCaps(); // Tell the client they are no longer in these channels. const vector& vChans = m_pNetwork->GetChans(); @@ -293,6 +294,7 @@ void CClient::SetNetwork(CIRCNetwork* pNetwork, bool bDisconnect, } else if (m_pUser) { m_pUser->UserConnected(this); } + NETWORKMODULECALL(OnClientAttached(), m_pUser, m_pNetwork, this, NOTHING); } } diff --git a/src/Modules.cpp b/src/Modules.cpp index a8c80f90..35a8d970 100644 --- a/src/Modules.cpp +++ b/src/Modules.cpp @@ -997,6 +997,8 @@ CModule::EModRet CModule::OnSendToIRC(CString& sLine) { return CONTINUE; } CModule::EModRet CModule::OnSendToIRCMessage(CMessage& Message) { return CONTINUE; } +void CModule::OnClientAttached() {} +void CModule::OnClientDetached() {} bool CModule::OnServerCapAvailable(const CString& sCap) { return false; } bool CModule::OnServerCap302Available(const CString& sCap, const CString& sValue) { @@ -1492,6 +1494,14 @@ bool CModules::OnModCTCP(const CString& sMessage) { MODUNLOADCHK(OnModCTCP(sMessage)); return false; } +bool CModules::OnClientAttached() { + MODUNLOADCHK(OnClientAttached()); + return false; +} +bool CModules::OnClientDetached() { + MODUNLOADCHK(OnClientDetached()); + return false; +} // Why MODHALTCHK works only with functions returning EModRet ? :( bool CModules::OnServerCapAvailable(const CString& sCap, const CString& sValue) { diff --git a/test/integration/tests/core.cpp b/test/integration/tests/core.cpp index cea66bc6..97259abf 100644 --- a/test/integration/tests/core.cpp +++ b/test/integration/tests/core.cpp @@ -585,13 +585,17 @@ TEST_F(ZNCTest, ServerDependentCapInModule) { } void OnServerCapResult(const CString& sCap, bool bSuccess) override { if (sCap == "testcap") { - GetNetwork()->NotifyClientsAboutServerDependentCap("testcap", bSuccess, [=](CClient* pClient, bool bState) { - PutModule("OnServerCapResult " + sCap + " " + CString(bSuccess) + " " + CString(bState)); - }); + PutModule("OnServerCapResult " + sCap + " " + CString(bSuccess)); + if (GetNetwork()->GetIRCSock()->IsAuthed()) { + GetNetwork()->NotifyClientsAboutServerDependentCap("testcap", bSuccess, [=](CClient* pClient, bool bState) { + PutModule("OnServerCapResult " + sCap + " " + CString(bSuccess) + " " + CString(bState)); + }); + } } } void OnIRCConnected() override { if (GetNetwork()->IsServerCapAccepted("testcap")) { + PutModule("OnIRCConnected"); GetNetwork()->NotifyClientsAboutServerDependentCap("testcap", true, [=](CClient* pClient, bool bState) { PutModule("OnIRCConnected " + CString(bState)); }); @@ -602,6 +606,14 @@ TEST_F(ZNCTest, ServerDependentCapInModule) { PutModule("OnIRCDisconnected " + CString(bState)); }); } + void OnClientAttached() override { + if (GetNetwork()->IsServerCapAccepted("testcap")) { + GetClient()->NotifyServerDependentCap("testcap", true, GetNetwork()->GetIRCSock()->GetCapLsValue("testcap"), nullptr); + } + } + void OnClientDetached() override { + GetClient()->NotifyServerDependentCap("testcap", false, "", [](CClient*, bool) {}); + } ~TestModule() override { // TODO user module GetNetwork()->NotifyClientsAboutServerDependentCap("testcap", false, [=](CClient* pClient, bool bState) { @@ -646,10 +658,11 @@ TEST_F(ZNCTest, ServerDependentCapInModule) { ircd.ReadUntil("CAP REQ :testcap"); ircd.Write("CAP nick ACK :testcap"); ircd.ReadUntil("CAP END"); - // TODO should NEW wait until 001? + // NEW waits until 001 + ASSERT_THAT(ircd.ReadRemainder().toStdString(), Not(HasSubstr("testcap"))); + ircd.Write("001 nick Welcome"); // TODO combine multiple NEWs to single line client.ReadUntil("CAP nick NEW :testcap=new"); - ircd.Write("001 nick Welcome"); client.ReadUntil("Welcome"); // NEW with new value without DEL @@ -657,7 +670,10 @@ TEST_F(ZNCTest, ServerDependentCapInModule) { client.ReadUntil("CAP nick NEW :testcap=another"); client.Write("znc jumpnetwork net2"); - client.ReadUntil("AAAAA"); + client.ReadUntil("CAP nick DEL :testcap"); + + client.Write("znc jumpnetwork test"); + client.ReadUntil("CAP nick NEW :testcap=another"); } TEST_F(ZNCTest, HashUpgrade) {