Skip to content

Commit

Permalink
Full-fledged query buffers
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jpnurmi committed Aug 4, 2014
1 parent b1b3888 commit 14a534c
Show file tree
Hide file tree
Showing 12 changed files with 357 additions and 78 deletions.
2 changes: 1 addition & 1 deletion Makefile.in
Expand Up @@ -42,7 +42,7 @@ endif
LIB_SRCS := ZNCString.cpp Csocket.cpp znc.cpp IRCNetwork.cpp User.cpp IRCSock.cpp \
Client.cpp Chan.cpp Nick.cpp Server.cpp Modules.cpp MD5.cpp Buffer.cpp Utils.cpp \
FileUtils.cpp HTTPSock.cpp Template.cpp ClientCommand.cpp Socket.cpp SHA256.cpp \
WebModules.cpp Listener.cpp Config.cpp ZNCDebug.cpp Threads.cpp version.cpp
WebModules.cpp Listener.cpp Config.cpp ZNCDebug.cpp Threads.cpp version.cpp Query.cpp
LIB_SRCS := $(addprefix src/,$(LIB_SRCS))
BIN_SRCS := src/main.cpp
LIB_OBJS := $(patsubst %cpp,%o,$(LIB_SRCS))
Expand Down
1 change: 1 addition & 0 deletions NOTICE
Expand Up @@ -46,5 +46,6 @@ Michael "adgar" Edgar <adgar@carboni.ca>
Jens-Andre "vain" Koch <jakoch@web.de>
Heiko Hund <heiko@ist.eigentlich.net> - cyrusauth module
Philippe (http://sourceforge.net/users/cycomate) - kickrejoin module
J-P Nurmi <jpnurmi@gmail.com>

If you did something useful and want to be listed here too, add yourself and submit the patch.
16 changes: 12 additions & 4 deletions include/znc/IRCNetwork.h
Expand Up @@ -30,6 +30,7 @@ class CConfig;
class CClient;
class CConfig;
class CChan;
class CQuery;
class CServer;
class CIRCSock;
class CIRCNetworkPingTimer;
Expand Down Expand Up @@ -96,6 +97,12 @@ class CIRCNetwork {
void JoinChans();
void JoinChans(std::set<CChan*>& sChans);

const std::vector<CQuery*>& GetQueries() const;
CQuery* FindQuery(const CString& sName) const;
std::vector<CQuery*> FindQueries(const CString& sWild) const;
CQuery* AddQuery(const CString& sName);
bool DelQuery(const CString& sName);

const CString& GetChanPrefixes() const { return m_sChanPrefixes; };
void SetChanPrefixes(const CString& s) { m_sChanPrefixes = s; };
bool IsChan(const CString& sChan) const;
Expand Down Expand Up @@ -144,9 +151,9 @@ class CIRCNetwork {
void UpdateMotdBuffer(const CString& sMatch, const CString& sFormat, const CString& sText = "") { m_MotdBuffer.UpdateLine(sMatch, sFormat, sText); }
void ClearMotdBuffer() { m_MotdBuffer.Clear(); }

void AddQueryBuffer(const CString& sFormat, const CString& sText = "") { m_QueryBuffer.AddLine(sFormat, sText); }
void UpdateQueryBuffer(const CString& sMatch, const CString& sFormat, const CString& sText = "") { m_QueryBuffer.UpdateLine(sMatch, sFormat, sText); }
void ClearQueryBuffer() { m_QueryBuffer.Clear(); }
void AddNoticeBuffer(const CString& sFormat, const CString& sText = "") { m_NoticeBuffer.AddLine(sFormat, sText); }
void UpdateNoticeBuffer(const CString& sMatch, const CString& sFormat, const CString& sText = "") { m_NoticeBuffer.UpdateLine(sMatch, sFormat, sText); }
void ClearNoticeBuffer() { m_NoticeBuffer.Clear(); }
// !Buffers

// la
Expand Down Expand Up @@ -192,6 +199,7 @@ class CIRCNetwork {
CIRCSock* m_pIRCSock;

std::vector<CChan*> m_vChans;
std::vector<CQuery*> m_vQueries;

CString m_sChanPrefixes;

Expand All @@ -208,7 +216,7 @@ class CIRCNetwork {

CBuffer m_RawBuffer;
CBuffer m_MotdBuffer;
CBuffer m_QueryBuffer;
CBuffer m_NoticeBuffer;

CIRCNetworkPingTimer* m_pPingTimer;
CIRCNetworkJoinTimer* m_pJoinTimer;
Expand Down
54 changes: 54 additions & 0 deletions include/znc/Query.h
@@ -0,0 +1,54 @@
/*
* Copyright (C) 2004-2014 ZNC, see the NOTICE file for details.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef _QUERY_H
#define _QUERY_H

#include <znc/zncconfig.h>
#include <znc/ZNCString.h>
#include <znc/Buffer.h>

// Forward Declarations
class CClient;
class CIRCNetwork;
// !Forward Declarations

class CQuery {
public:
CQuery(const CString& sName, CIRCNetwork* pNetwork);
~CQuery();

// Buffer
const CBuffer& GetBuffer() const { return m_Buffer; }
unsigned int GetBufferCount() const { return m_Buffer.GetLineCount(); }
bool SetBufferCount(unsigned int u, bool bForce = false) { return m_Buffer.SetLineCount(u, bForce); }
size_t AddBuffer(const CString& sFormat, const CString& sText = "", const timeval* ts = NULL) { return m_Buffer.AddLine(sFormat, sText, ts); }
void ClearBuffer() { m_Buffer.Clear(); }
void SendBuffer(CClient* pClient);
void SendBuffer(CClient* pClient, const CBuffer& Buffer);
// !Buffer

// Getters
const CString& GetName() const { return m_sName; }
// !Getters

private:
CString m_sName;
CIRCNetwork* m_pNetwork;
CBuffer m_Buffer;
};

#endif // !_QUERY_H
6 changes: 6 additions & 0 deletions include/znc/User.h
Expand Up @@ -126,6 +126,7 @@ class CUser {
bool DelCTCPReply(const CString& sCTCP);
bool SetBufferCount(unsigned int u, bool bForce = false);
void SetAutoClearChanBuffer(bool b);
void SetAutoClearQueryBuffer(bool b);

void SetBeingDeleted(bool b) { m_bBeingDeleted = b; }
void SetTimestampFormat(const CString& s) { m_sTimestampFormat = s; }
Expand All @@ -136,6 +137,7 @@ class CUser {
void SetMaxJoins(unsigned int i) { m_uMaxJoins = i; }
void SetSkinName(const CString& s) { m_sSkinName = s; }
void SetMaxNetworks(unsigned int i) { m_uMaxNetworks = i; }
void SetMaxQueryBuffers(unsigned int i) { m_uMaxQueryBuffers = i; }
// !Setters

// Getters
Expand Down Expand Up @@ -171,6 +173,7 @@ class CUser {
const MCString& GetCTCPReplies() const;
unsigned int GetBufferCount() const;
bool AutoClearChanBuffer() const;
bool AutoClearQueryBuffer() const;
bool IsBeingDeleted() const { return m_bBeingDeleted; }
CString GetTimezone() const { return m_sTimezone; }
unsigned long long BytesRead() const { return m_uBytesRead; }
Expand All @@ -179,6 +182,7 @@ class CUser {
unsigned int MaxJoins() const { return m_uMaxJoins; }
CString GetSkinName() const;
unsigned int MaxNetworks() const { return m_uMaxNetworks; }
unsigned int MaxQueryBuffers() const { return m_uMaxQueryBuffers; }
// !Getters

protected:
Expand Down Expand Up @@ -211,6 +215,7 @@ class CUser {
bool m_bAdmin;
bool m_bDenySetBindHost;
bool m_bAutoClearChanBuffer;
bool m_bAutoClearQueryBuffer;
bool m_bBeingDeleted;
bool m_bAppendTimestamp;
bool m_bPrependTimestamp;
Expand All @@ -225,6 +230,7 @@ class CUser {
unsigned long long m_uBytesWritten;
unsigned int m_uMaxJoinTries;
unsigned int m_uMaxNetworks;
unsigned int m_uMaxQueryBuffers;
unsigned int m_uMaxJoins;
CString m_sSkinName;

Expand Down
37 changes: 27 additions & 10 deletions src/Client.cpp
Expand Up @@ -18,6 +18,7 @@
#include <znc/IRCSock.h>
#include <znc/User.h>
#include <znc/IRCNetwork.h>
#include <znc/Query.h>

using std::map;
using std::vector;
Expand Down Expand Up @@ -298,20 +299,20 @@ void CClient::ReadLine(const CString& sData) {
}

if (m_pNetwork) {
CChan* pChan = m_pNetwork->FindChan(sTarget);

if (sCTCP.Token(0).Equals("ACTION")) {
CString sMessage = sCTCP.Token(1, true);
NETWORKMODULECALL(OnUserAction(sTarget, sMessage), m_pUser, m_pNetwork, this, &bReturn);
if (bReturn) return;
sCTCP = "ACTION " + sMessage;

if (pChan && (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline())) {
pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :\001ACTION {text}\001", sMessage);
}

// Relay to the rest of the clients that may be connected to this user
if (m_pNetwork->IsChan(sTarget)) {
CChan* pChan = m_pNetwork->FindChan(sTarget);

if (pChan && (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline())) {
pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :\001ACTION {text}\001", sMessage);
}

// Relay to the rest of the clients that may be connected to this user
vector<CClient*>& vClients = GetClients();

for (unsigned int a = 0; a < vClients.size(); a++) {
Expand All @@ -321,6 +322,13 @@ void CClient::ReadLine(const CString& sData) {
pClient->PutClient(":" + GetNickMask() + " PRIVMSG " + sTarget + " :\001" + sCTCP + "\001");
}
}
} else {
if (!m_pUser->AutoClearQueryBuffer() || !m_pNetwork->IsUserOnline()) {
CQuery* pQuery = m_pNetwork->AddQuery(sTarget);
if (pQuery) {
pQuery->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :\001ACTION {text}\001", sMessage);
}
}
}
} else {
NETWORKMODULECALL(OnUserCTCP(sTarget, sCTCP), m_pUser, m_pNetwork, this, &bReturn);
Expand Down Expand Up @@ -354,10 +362,19 @@ void CClient::ReadLine(const CString& sData) {
}

if (m_pNetwork) {
CChan* pChan = m_pNetwork->FindChan(sTarget);
if (m_pNetwork->IsChan(sTarget)) {
CChan* pChan = m_pNetwork->FindChan(sTarget);

if ((pChan) && (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline())) {
pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :{text}", sMsg);
if ((pChan) && (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline())) {
pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :{text}", sMsg);
}
} else {
if (!m_pUser->AutoClearQueryBuffer() || !m_pNetwork->IsUserOnline()) {
CQuery* pQuery = m_pNetwork->AddQuery(sTarget);
if (pQuery) {
pQuery->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :{text}", sMsg);
}
}
}

PutIRC("PRIVMSG " + sTarget + " :" + sMsg);
Expand Down

0 comments on commit 14a534c

Please sign in to comment.