diff --git a/include/znc/Modules.h b/include/znc/Modules.h
index c7dde8ee..f963f4c7 100644
--- a/include/znc/Modules.h
+++ b/include/znc/Modules.h
@@ -720,6 +720,11 @@ public:
* @return See CModule::EModRet.
*/
virtual EModRet OnUserTopicRequest(CString& sChannel);
+ /** This module hook is called when a user requests to quit from network.
+ * @param sMessage The quit message the client sent.
+ * @return See CModule::EModRet.
+ */
+ virtual EModRet OnUserQuit(CString& sMessage);
/** Called when we receive a CTCP reply from IRC.
* @param Nick The nick the CTCP reply is from.
@@ -1190,6 +1195,7 @@ public:
bool OnUserPart(CString& sChannel, CString& sMessage);
bool OnUserTopic(CString& sChannel, CString& sTopic);
bool OnUserTopicRequest(CString& sChannel);
+ bool OnUserQuit(CString& sMessage);
bool OnCTCPReply(CNick& Nick, CString& sMessage);
bool OnPrivCTCP(CNick& Nick, CString& sMessage);
diff --git a/modules/clearbufferonmsg.cpp b/modules/clearbufferonmsg.cpp
index 37a5305b..557e7680 100644
--- a/modules/clearbufferonmsg.cpp
+++ b/modules/clearbufferonmsg.cpp
@@ -15,72 +15,154 @@
*/
#include
+#include
#include
#include
using std::vector;
+enum {
+ RULE_MSG,
+ RULE_CTCP,
+ RULE_ACTION,
+ RULE_NOTICE,
+ RULE_PART,
+ RULE_TOPIC,
+ RULE_QUIT,
+ RULE_MAX,
+};
+
class CClearBufferOnMsgMod : public CModule {
public:
- MODCONSTRUCTOR(CClearBufferOnMsgMod) {}
+ MODCONSTRUCTOR(CClearBufferOnMsgMod) {
+ SetAllRules(true);
+ // false for backward compatibility
+ m_bRules[RULE_QUIT] = false;
+ }
void ClearAllBuffers() {
CIRCNetwork* pNetwork = GetNetwork();
+
if (pNetwork) {
const vector& vChans = pNetwork->GetChans();
- for (vector::const_iterator it = vChans.begin(); it != vChans.end(); ++it) {
+ for (CChan* pChan : vChans) {
// Skip detached channels, they weren't read yet
- if ((*it)->IsDetached())
+ if (pChan->IsDetached())
continue;
- (*it)->ClearBuffer();
+ pChan->ClearBuffer();
// We deny AutoClearChanBuffer on all channels since this module
// doesn't make any sense with it
- (*it)->SetAutoClearChanBuffer(false);
+ pChan->SetAutoClearChanBuffer(false);
}
vector VQueries = pNetwork->GetQueries();
- for (vector::const_iterator it = VQueries.begin(); it != VQueries.end(); ++it) {
- pNetwork->DelQuery((*it)->GetName());
+ for (CQuery* pQuery : VQueries) {
+ pNetwork->DelQuery(pQuery->GetName());
}
+
+ // We deny AutoClearQueryBuffer since this module
+ // doesn't make any sense with it
+ GetUser()->SetAutoClearQueryBuffer(false);
}
}
virtual EModRet OnUserMsg(CString& sTarget, CString& sMessage) override {
- ClearAllBuffers();
+ if (m_bRules[RULE_MSG])
+ ClearAllBuffers();
return CONTINUE;
}
virtual EModRet OnUserCTCP(CString& sTarget, CString& sMessage) override {
- ClearAllBuffers();
+ if (m_bRules[RULE_CTCP])
+ ClearAllBuffers();
return CONTINUE;
}
virtual EModRet OnUserAction(CString& sTarget, CString& sMessage) override {
- ClearAllBuffers();
+ if (m_bRules[RULE_ACTION])
+ ClearAllBuffers();
return CONTINUE;
}
virtual EModRet OnUserNotice(CString& sTarget, CString& sMessage) override {
- ClearAllBuffers();
+ if (m_bRules[RULE_NOTICE])
+ ClearAllBuffers();
return CONTINUE;
}
virtual EModRet OnUserPart(CString& sChannel, CString& sMessage) override {
- ClearAllBuffers();
+ if (m_bRules[RULE_PART])
+ ClearAllBuffers();
return CONTINUE;
}
virtual EModRet OnUserTopic(CString& sChannel, CString& sTopic) override {
- ClearAllBuffers();
+ if (m_bRules[RULE_TOPIC])
+ ClearAllBuffers();
return CONTINUE;
}
+
+ virtual EModRet OnUserQuit(CString& sMessage) override {
+ if (m_bRules[RULE_QUIT])
+ ClearAllBuffers();
+ return CONTINUE;
+ }
+
+ void SetAllRules(bool bVal) {
+ for (int i = 0; i < RULE_MAX; i++)
+ m_bRules[i] = bVal;
+ }
+
+ void SetRule(const CString& sOpt, bool bVal) {
+ static const struct {
+ CString sName;
+ int Index;
+ } Names[RULE_MAX] = {
+ { "msg", RULE_MSG },
+ { "ctcp", RULE_CTCP },
+ { "action", RULE_ACTION },
+ { "notice", RULE_NOTICE },
+ { "part", RULE_PART },
+ { "topic", RULE_TOPIC },
+ { "quit", RULE_QUIT },
+ };
+
+ if (sOpt.Equals("all")) {
+ SetAllRules(bVal);
+ } else {
+ for (int i = 0; i < RULE_MAX; i++) {
+ if (sOpt.Equals(Names[i].sName))
+ m_bRules[Names[i].Index] = bVal;
+ }
+ }
+ }
+
+ virtual bool OnLoad(const CString& sArgs, CString& sMessage) override {
+ VCString vsOpts;
+
+ sArgs.Split(" ", vsOpts, false);
+
+ for (CString& sOpt : vsOpts) {
+ if (sOpt.StartsWith("!"))
+ SetRule(sOpt.substr(1), false);
+ else if (!sOpt.empty())
+ SetRule(sOpt, true);
+ }
+
+ return true;
+ }
+
+private:
+ bool m_bRules[RULE_MAX];
};
template<> void TModInfo(CModInfo& Info) {
Info.SetWikiPage("clearbufferonmsg");
+ Info.SetHasArgs(true);
+ Info.SetArgsHelpText("[ [!] ]");
}
USERMODULEDEFS(CClearBufferOnMsgMod, "Clear all channel and query buffers whenever the user does something")
diff --git a/modules/modperl/functions.in b/modules/modperl/functions.in
index 64ed0b41..e3f58298 100644
--- a/modules/modperl/functions.in
+++ b/modules/modperl/functions.in
@@ -47,6 +47,7 @@ EModRet OnUserJoin(CString& sChannel, CString& sKey)
EModRet OnUserPart(CString& sChannel, CString& sMessage)
EModRet OnUserTopic(CString& sChannel, CString& sTopic)
EModRet OnUserTopicRequest(CString& sChannel)
+EModRet OnUserQuit(CString& sMessage)
EModRet OnCTCPReply(CNick& Nick, CString& sMessage)
EModRet OnPrivCTCP(CNick& Nick, CString& sMessage)
EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage)
diff --git a/modules/modperl/module.h b/modules/modperl/module.h
index 28574708..acab1885 100644
--- a/modules/modperl/module.h
+++ b/modules/modperl/module.h
@@ -86,6 +86,7 @@ public:
virtual EModRet OnUserJoin(CString& sChannel, CString& sKey) override;
virtual EModRet OnUserPart(CString& sChannel, CString& sMessage) override;
virtual EModRet OnUserTopic(CString& sChannel, CString& sTopic) override;
+ virtual EModRet OnUserQuit(CString& sMessage) override;
virtual EModRet OnUserTopicRequest(CString& sChannel) override;
virtual EModRet OnCTCPReply(CNick& Nick, CString& sMessage) override;
virtual EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override;
diff --git a/modules/modperl/startup.pl b/modules/modperl/startup.pl
index f47a465d..55d095ea 100644
--- a/modules/modperl/startup.pl
+++ b/modules/modperl/startup.pl
@@ -356,6 +356,7 @@ sub OnUserJoin {}
sub OnUserPart {}
sub OnUserTopic {}
sub OnUserTopicRequest {}
+sub OnUserQuit {}
sub OnCTCPReply {}
sub OnPrivCTCP {}
sub OnChanCTCP {}
diff --git a/modules/modpython/functions.in b/modules/modpython/functions.in
index 5bf893d2..5e324687 100644
--- a/modules/modpython/functions.in
+++ b/modules/modpython/functions.in
@@ -47,6 +47,7 @@ EModRet OnUserJoin(CString& sChannel, CString& sKey)
EModRet OnUserPart(CString& sChannel, CString& sMessage)
EModRet OnUserTopic(CString& sChannel, CString& sTopic)
EModRet OnUserTopicRequest(CString& sChannel)
+EModRet OnUserQuit(CString& sMessage)
EModRet OnCTCPReply(CNick& Nick, CString& sMessage)
EModRet OnPrivCTCP(CNick& Nick, CString& sMessage)
EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage)
diff --git a/modules/modpython/module.h b/modules/modpython/module.h
index 97ed8230..56be98f4 100644
--- a/modules/modpython/module.h
+++ b/modules/modpython/module.h
@@ -103,6 +103,7 @@ public:
virtual EModRet OnUserPart(CString& sChannel, CString& sMessage) override;
virtual EModRet OnUserTopic(CString& sChannel, CString& sTopic) override;
virtual EModRet OnUserTopicRequest(CString& sChannel) override;
+ virtual EModRet OnUserQuit(CString& sMessage) override;
virtual EModRet OnCTCPReply(CNick& Nick, CString& sMessage) override;
virtual EModRet OnPrivCTCP(CNick& Nick, CString& sMessage) override;
virtual EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) override;
diff --git a/modules/modpython/znc.py b/modules/modpython/znc.py
index 81650f10..cd4de4b3 100644
--- a/modules/modpython/znc.py
+++ b/modules/modpython/znc.py
@@ -339,6 +339,9 @@ class Module:
def OnUserTopicRequest(self, sChannel):
pass
+ def OnUserQuit(self, sMessage):
+ pass
+
def OnCTCPReply(self, Nick, sMessage):
pass
diff --git a/src/Client.cpp b/src/Client.cpp
index fce77421..b9377daa 100644
--- a/src/Client.cpp
+++ b/src/Client.cpp
@@ -198,6 +198,9 @@ void CClient::ReadLine(const CString& sData) {
// Block PONGs, we already responded to the pings
return;
} else if (sCommand.Equals("QUIT")) {
+ CString sMsg = sLine.Token(1, true).TrimPrefix_n();
+ NETWORKMODULECALL(OnUserQuit(sMsg), m_pUser, m_pNetwork, this, &bReturn);
+ if (bReturn) return;
Close(Csock::CLT_AFTERWRITE); // Treat a client quit as a detach
return; // Don't forward this msg. We don't want the client getting us disconnected.
} else if (sCommand.Equals("PROTOCTL")) {
diff --git a/src/Modules.cpp b/src/Modules.cpp
index f7e9992b..55a1a311 100644
--- a/src/Modules.cpp
+++ b/src/Modules.cpp
@@ -693,6 +693,7 @@ CModule::EModRet CModule::OnUserJoin(CString& sChannel, CString& sKey) { return
CModule::EModRet CModule::OnUserPart(CString& sChannel, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnUserTopic(CString& sChannel, CString& sTopic) { return CONTINUE; }
CModule::EModRet CModule::OnUserTopicRequest(CString& sChannel) { return CONTINUE; }
+CModule::EModRet CModule::OnUserQuit(CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnCTCPReply(CNick& Nick, CString& sMessage) { return CONTINUE; }
CModule::EModRet CModule::OnPrivCTCP(CNick& Nick, CString& sMessage) { return CONTINUE; }
@@ -854,6 +855,7 @@ bool CModules::OnUserJoin(CString& sChannel, CString& sKey) { MODHALTCHK(OnUserJ
bool CModules::OnUserPart(CString& sChannel, CString& sMessage) { MODHALTCHK(OnUserPart(sChannel, sMessage)); }
bool CModules::OnUserTopic(CString& sChannel, CString& sTopic) { MODHALTCHK(OnUserTopic(sChannel, sTopic)); }
bool CModules::OnUserTopicRequest(CString& sChannel) { MODHALTCHK(OnUserTopicRequest(sChannel)); }
+bool CModules::OnUserQuit(CString& sMessage) { MODHALTCHK(OnUserQuit(sMessage)); }
bool CModules::OnQuit(const CNick& Nick, const CString& sMessage, const vector& vChans) { MODUNLOADCHK(OnQuit(Nick, sMessage, vChans)); return false; }
bool CModules::OnNick(const CNick& Nick, const CString& sNewNick, const vector& vChans) { MODUNLOADCHK(OnNick(Nick, sNewNick, vChans)); return false; }