Permalink
Browse files

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.
  • Loading branch information...
jpnurmi committed Jul 20, 2014
1 parent b1b3888 commit 14a534c9534b328169d5d52c2ef33f29cc421ef4
Showing with 357 additions and 78 deletions.
  1. +1 −1 Makefile.in
  2. +1 −0 NOTICE
  3. +12 −4 include/znc/IRCNetwork.h
  4. +54 −0 include/znc/Query.h
  5. +6 −0 include/znc/User.h
  6. +27 −10 src/Client.cpp
  7. +85 −49 src/ClientCommand.cpp
  8. +81 −5 src/IRCNetwork.cpp
  9. +13 −8 src/IRCSock.cpp
  10. +61 −0 src/Query.cpp
  11. +10 −0 src/User.cpp
  12. +6 −1 src/znc.cpp
View
@@ -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))
View
1 NOTICE
@@ -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.
View
@@ -30,6 +30,7 @@ class CConfig;
class CClient;
class CConfig;
class CChan;
+class CQuery;
class CServer;
class CIRCSock;
class CIRCNetworkPingTimer;
@@ -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;
@@ -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
@@ -192,6 +199,7 @@ class CIRCNetwork {
CIRCSock* m_pIRCSock;
std::vector<CChan*> m_vChans;
+ std::vector<CQuery*> m_vQueries;
CString m_sChanPrefixes;
@@ -208,7 +216,7 @@ class CIRCNetwork {
CBuffer m_RawBuffer;
CBuffer m_MotdBuffer;
- CBuffer m_QueryBuffer;
+ CBuffer m_NoticeBuffer;
CIRCNetworkPingTimer* m_pPingTimer;
CIRCNetworkJoinTimer* m_pJoinTimer;
View
@@ -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
View
@@ -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; }
@@ -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
@@ -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; }
@@ -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:
@@ -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;
@@ -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;
View
@@ -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;
@@ -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++) {
@@ -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);
@@ -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);
Oops, something went wrong.

0 comments on commit 14a534c

Please sign in to comment.