From feec20b013d67ad716f03d0d852910f3589b5e73 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Sun, 22 Feb 2015 04:02:39 +0900 Subject: [PATCH 1/3] Add OnUserQuit() for extending clearbufferonmsg Add OnUserQuit() callback. On smartphone, user doesn't want to see same lines repeatedly. But, meanwhile, user doesn't want to miss lines when connection was lost. To do it, this uses OnUserQuit() callback. With this callback, clearbufferonmsg can clear buffer if user quited client explicitly. And when connection was lost, buffer is still not cleared. --- include/znc/Modules.h | 5 +++++ modules/modperl/functions.in | 1 + modules/modperl/module.h | 1 + modules/modperl/startup.pl | 1 + modules/modpython/functions.in | 1 + modules/modpython/module.h | 1 + modules/modpython/znc.py | 3 +++ src/Client.cpp | 2 ++ src/Modules.cpp | 2 ++ 9 files changed, 17 insertions(+) diff --git a/include/znc/Modules.h b/include/znc/Modules.h index c7dde8ee..f9ea0983 100644 --- a/include/znc/Modules.h +++ b/include/znc/Modules.h @@ -720,6 +720,10 @@ 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. + */ + virtual void OnUserQuit(CString& sMessage); /** Called when we receive a CTCP reply from IRC. * @param Nick The nick the CTCP reply is from. @@ -1190,6 +1194,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/modperl/functions.in b/modules/modperl/functions.in index 64ed0b41..babfae5a 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) +void 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..a2c36cee 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 void 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..264dd327 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) +void 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..0e3c9ce2 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 void 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..4c0c2a58 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -198,6 +198,8 @@ 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, NOTHING); 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..30d94f50 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; } +void CModule::OnUserQuit(CString& sMessage) {} 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) { MODUNLOADCHK(OnUserQuit(sMessage)); return false; } 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; } From 85941f87c0a0acc7d5c79f52686771402d18a7ff Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Wed, 4 Feb 2015 08:25:11 +0900 Subject: [PATCH 2/3] Extend clearbufferonmsg module and some znc commands for flexible buffer clear Current clearbufferonmsg clears buffer on some user actions (OnMsg, OnCTCP, OnAction, OnNotice, OnPart, OnTopic). And user can't change this fixed built-in rule. This built-in rule to clear buffer is too inflexible. So, this extends clearbufferonmsg to satisfy more users on different situations. Add args to clearbufferonmsg to allow that user choose callbacks to clear. msg - clear on OnUserMsg callback ctcp - clear on OnUserCTCP callback action - clear on OnUserAction callback notice - clear on OnUserNotice callback part - clear on OnUserPart callback topic - clear on OnUserTopic callback quit - clear on OnUserQuit callback all - set all options above By default, clear on msg, ctcp, action, notice, part, topic. (except quit for backward compatibility). Example usage in znc.conf: [set all options] LoadModule = clearbufferonmsg all [on quit and part] LoadModule = clearbufferonmsg !all quit part --- modules/clearbufferonmsg.cpp | 107 ++++++++++++++++++++++++++++++----- 1 file changed, 94 insertions(+), 13 deletions(-) diff --git a/modules/clearbufferonmsg.cpp b/modules/clearbufferonmsg.cpp index 37a5305b..313bac9a 100644 --- a/modules/clearbufferonmsg.cpp +++ b/modules/clearbufferonmsg.cpp @@ -15,72 +15,153 @@ */ #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 void OnUserQuit(CString& sMessage) override { + if (m_bRules[RULE_QUIT]) + ClearAllBuffers(); + } + + 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") From c6d093a53ad960f1618f610f27d664838b5aa819 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Sun, 22 Feb 2015 04:32:35 +0900 Subject: [PATCH 3/3] Change to return the value from OnUserQuit() as request --- include/znc/Modules.h | 3 ++- modules/clearbufferonmsg.cpp | 3 ++- modules/modperl/functions.in | 2 +- modules/modperl/module.h | 2 +- modules/modpython/functions.in | 2 +- modules/modpython/module.h | 2 +- src/Client.cpp | 3 ++- src/Modules.cpp | 4 ++-- 8 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/znc/Modules.h b/include/znc/Modules.h index f9ea0983..f963f4c7 100644 --- a/include/znc/Modules.h +++ b/include/znc/Modules.h @@ -722,8 +722,9 @@ public: 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 void OnUserQuit(CString& sMessage); + virtual EModRet OnUserQuit(CString& sMessage); /** Called when we receive a CTCP reply from IRC. * @param Nick The nick the CTCP reply is from. diff --git a/modules/clearbufferonmsg.cpp b/modules/clearbufferonmsg.cpp index 313bac9a..557e7680 100644 --- a/modules/clearbufferonmsg.cpp +++ b/modules/clearbufferonmsg.cpp @@ -105,9 +105,10 @@ public: return CONTINUE; } - virtual void OnUserQuit(CString& sMessage) override { + virtual EModRet OnUserQuit(CString& sMessage) override { if (m_bRules[RULE_QUIT]) ClearAllBuffers(); + return CONTINUE; } void SetAllRules(bool bVal) { diff --git a/modules/modperl/functions.in b/modules/modperl/functions.in index babfae5a..e3f58298 100644 --- a/modules/modperl/functions.in +++ b/modules/modperl/functions.in @@ -47,7 +47,7 @@ EModRet OnUserJoin(CString& sChannel, CString& sKey) EModRet OnUserPart(CString& sChannel, CString& sMessage) EModRet OnUserTopic(CString& sChannel, CString& sTopic) EModRet OnUserTopicRequest(CString& sChannel) -void OnUserQuit(CString& sMessage) +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 a2c36cee..acab1885 100644 --- a/modules/modperl/module.h +++ b/modules/modperl/module.h @@ -86,7 +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 void OnUserQuit(CString& sMessage) 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/modpython/functions.in b/modules/modpython/functions.in index 264dd327..5e324687 100644 --- a/modules/modpython/functions.in +++ b/modules/modpython/functions.in @@ -47,7 +47,7 @@ EModRet OnUserJoin(CString& sChannel, CString& sKey) EModRet OnUserPart(CString& sChannel, CString& sMessage) EModRet OnUserTopic(CString& sChannel, CString& sTopic) EModRet OnUserTopicRequest(CString& sChannel) -void OnUserQuit(CString& sMessage) +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 0e3c9ce2..56be98f4 100644 --- a/modules/modpython/module.h +++ b/modules/modpython/module.h @@ -103,7 +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 void OnUserQuit(CString& sMessage) 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/src/Client.cpp b/src/Client.cpp index 4c0c2a58..b9377daa 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -199,7 +199,8 @@ void CClient::ReadLine(const CString& sData) { return; } else if (sCommand.Equals("QUIT")) { CString sMsg = sLine.Token(1, true).TrimPrefix_n(); - NETWORKMODULECALL(OnUserQuit(sMsg), m_pUser, m_pNetwork, this, NOTHING); + 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 30d94f50..55a1a311 100644 --- a/src/Modules.cpp +++ b/src/Modules.cpp @@ -693,7 +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; } -void CModule::OnUserQuit(CString& sMessage) {} +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; } @@ -855,7 +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) { MODUNLOADCHK(OnUserQuit(sMessage)); return false; } +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; }