mirror of
https://github.com/znc/znc.git
synced 2026-05-01 19:12:31 +02:00
Full-fledged query buffers
Store query buffers per query the same way it's done for channels. This allows clients to implement persistent query buffers. Queries remain open across clients and sessions until a client explicitly sends a command to clear a (closed) query buffer. A new config option AutoClearQueryBuffer that default to false ensures behavioral backwards compatibility, and another config MaxQueries protects from OOM eg. due to PM attacks.
This commit is contained in:
@@ -21,6 +21,7 @@
|
||||
#include <znc/IRCSock.h>
|
||||
#include <znc/Server.h>
|
||||
#include <znc/Chan.h>
|
||||
#include <znc/Query.h>
|
||||
|
||||
using std::vector;
|
||||
using std::set;
|
||||
@@ -116,7 +117,7 @@ CIRCNetwork::CIRCNetwork(CUser *pUser, const CString& sName) {
|
||||
|
||||
m_RawBuffer.SetLineCount(100, true); // This should be more than enough raws, especially since we are buffering the MOTD separately
|
||||
m_MotdBuffer.SetLineCount(200, true); // This should be more than enough motd lines
|
||||
m_QueryBuffer.SetLineCount(250, true);
|
||||
m_NoticeBuffer.SetLineCount(250, true);
|
||||
|
||||
m_pPingTimer = new CIRCNetworkPingTimer(this);
|
||||
CZNC::Get().GetManager().AddCron(m_pPingTimer);
|
||||
@@ -142,7 +143,7 @@ CIRCNetwork::CIRCNetwork(CUser *pUser, const CIRCNetwork &Network) {
|
||||
|
||||
m_RawBuffer.SetLineCount(100, true); // This should be more than enough raws, especially since we are buffering the MOTD separately
|
||||
m_MotdBuffer.SetLineCount(200, true); // This should be more than enough motd lines
|
||||
m_QueryBuffer.SetLineCount(250, true);
|
||||
m_NoticeBuffer.SetLineCount(250, true);
|
||||
|
||||
Clone(Network);
|
||||
}
|
||||
@@ -281,6 +282,12 @@ CIRCNetwork::~CIRCNetwork() {
|
||||
}
|
||||
m_vChans.clear();
|
||||
|
||||
// Delete Queries
|
||||
for (vector<CQuery*>::const_iterator it = m_vQueries.begin(); it != m_vQueries.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
m_vQueries.clear();
|
||||
|
||||
SetUser(NULL);
|
||||
|
||||
// Make sure we are not in the connection queue
|
||||
@@ -589,15 +596,26 @@ void CIRCNetwork::ClientConnected(CClient *pClient) {
|
||||
}
|
||||
}
|
||||
|
||||
uSize = m_QueryBuffer.Size();
|
||||
bool bClearQuery = m_pUser->AutoClearQueryBuffer();
|
||||
for (vector<CQuery*>::const_iterator it = m_vQueries.begin(); it != m_vQueries.end(); ++it) {
|
||||
(*it)->SendBuffer(pClient);
|
||||
if (bClearQuery) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
if (bClearQuery) {
|
||||
m_vQueries.clear();
|
||||
}
|
||||
|
||||
uSize = m_NoticeBuffer.Size();
|
||||
for (uIdx = 0; uIdx < uSize; uIdx++) {
|
||||
CString sLine = m_QueryBuffer.GetLine(uIdx, *pClient, msParams);
|
||||
CString sLine = m_NoticeBuffer.GetLine(uIdx, *pClient, msParams);
|
||||
bool bContinue = false;
|
||||
NETWORKMODULECALL(OnPrivBufferPlayLine(*pClient, sLine), m_pUser, this, NULL, &bContinue);
|
||||
if (bContinue) continue;
|
||||
pClient->PutClient(sLine);
|
||||
}
|
||||
m_QueryBuffer.Clear();
|
||||
m_NoticeBuffer.Clear();
|
||||
|
||||
// Tell them why they won't connect
|
||||
if (!GetIRCConnectEnabled())
|
||||
@@ -855,6 +873,64 @@ bool CIRCNetwork::IsChan(const CString& sChan) const {
|
||||
return GetChanPrefixes().find(sChan[0]) != CString::npos;
|
||||
}
|
||||
|
||||
// Queries
|
||||
|
||||
const vector<CQuery*>& CIRCNetwork::GetQueries() const { return m_vQueries; }
|
||||
|
||||
CQuery* CIRCNetwork::FindQuery(const CString& sName) const {
|
||||
for (unsigned int a = 0; a < m_vQueries.size(); a++) {
|
||||
CQuery* pQuery = m_vQueries[a];
|
||||
if (sName.Equals(pQuery->GetName())) {
|
||||
return pQuery;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::vector<CQuery*> CIRCNetwork::FindQueries(const CString& sWild) const {
|
||||
std::vector<CQuery*> vQueries;
|
||||
vQueries.reserve(m_vQueries.size());
|
||||
for (std::vector<CQuery*>::const_iterator it = m_vQueries.begin(); it != m_vQueries.end(); ++it) {
|
||||
if ((*it)->GetName().WildCmp(sWild))
|
||||
vQueries.push_back(*it);
|
||||
}
|
||||
return vQueries;
|
||||
}
|
||||
|
||||
CQuery* CIRCNetwork::AddQuery(const CString& sName) {
|
||||
if (sName.empty()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CQuery* pQuery = FindQuery(sName);
|
||||
if (!pQuery) {
|
||||
pQuery = new CQuery(sName, this);
|
||||
m_vQueries.push_back(pQuery);
|
||||
|
||||
if (m_pUser->MaxQueryBuffers() > 0) {
|
||||
while (m_vQueries.size() > m_pUser->MaxQueryBuffers()) {
|
||||
delete *m_vQueries.begin();
|
||||
m_vQueries.erase(m_vQueries.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pQuery;
|
||||
}
|
||||
|
||||
bool CIRCNetwork::DelQuery(const CString& sName) {
|
||||
for (vector<CQuery*>::iterator a = m_vQueries.begin(); a != m_vQueries.end(); ++a) {
|
||||
if (sName.Equals((*a)->GetName())) {
|
||||
delete *a;
|
||||
m_vQueries.erase(a);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Server list
|
||||
|
||||
const vector<CServer*>& CIRCNetwork::GetServers() const { return m_vServers; }
|
||||
|
||||
Reference in New Issue
Block a user