mirror of
https://github.com/znc/znc.git
synced 2026-08-07 01:13:25 +02:00
Merge pull request #1000 from jpnurmi/message
Say hello to a Message type
This commit is contained in:
+2
-2
@@ -44,12 +44,12 @@ LIB_SRCS := ZNCString.cpp Csocket.cpp znc.cpp IRCNetwork.cpp User.cpp IRCSock.c
|
||||
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 Query.cpp \
|
||||
SSLVerifyHost.cpp
|
||||
SSLVerifyHost.cpp Message.cpp
|
||||
LIB_SRCS := $(addprefix src/,$(LIB_SRCS))
|
||||
BIN_SRCS := src/main.cpp
|
||||
LIB_OBJS := $(patsubst %cpp,%o,$(LIB_SRCS))
|
||||
BIN_OBJS := $(patsubst %cpp,%o,$(BIN_SRCS))
|
||||
TESTS := StringTest ConfigTest UtilsTest ThreadTest NickTest ClientTest NetworkTest
|
||||
TESTS := StringTest ConfigTest UtilsTest ThreadTest NickTest ClientTest NetworkTest MessageTest
|
||||
TESTS := $(addprefix test/,$(addsuffix .o,$(TESTS)))
|
||||
CLEAN := znc src/*.o test/*.o core core.* .version_extra .depend modules/.depend \
|
||||
unittest $(LIBZNC)
|
||||
|
||||
+1
-1
@@ -292,7 +292,7 @@ if test "$POLL" = "yes"; then
|
||||
fi
|
||||
|
||||
AC_CHECK_LIB( gnugetopt, getopt_long,)
|
||||
AC_CHECK_FUNCS([lstat getopt_long getpassphrase])
|
||||
AC_CHECK_FUNCS([lstat getopt_long getpassphrase clock_gettime])
|
||||
|
||||
# ----- Check for dlopen
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class CClient;
|
||||
class CBufLine {
|
||||
public:
|
||||
CBufLine() : CBufLine("") { throw 0; } // shouldn't be called, but is needed for compilation
|
||||
CBufLine(const CString& sFormat, const CString& sText = "", const timeval* ts = nullptr);
|
||||
CBufLine(const CString& sFormat, const CString& sText = "", const timeval* ts = nullptr, const MCString& mssTags = MCString::EmptyMap);
|
||||
~CBufLine();
|
||||
CString GetLine(const CClient& Client, const MCString& msParams) const;
|
||||
void UpdateTime();
|
||||
@@ -38,12 +38,14 @@ public:
|
||||
void SetFormat(const CString& sFormat) { m_sFormat = sFormat; }
|
||||
void SetText(const CString& sText) { m_sText = sText; }
|
||||
void SetTime(const timeval& ts) { m_time = ts; }
|
||||
void SetTags(const MCString& mssTags) { m_mssTags = mssTags; }
|
||||
// !Setters
|
||||
|
||||
// Getters
|
||||
const CString& GetFormat() const { return m_sFormat; }
|
||||
const CString& GetText() const { return m_sText; }
|
||||
timeval GetTime() const { return m_time; }
|
||||
const MCString& GetTags() const { return m_mssTags; }
|
||||
// !Getters
|
||||
|
||||
private:
|
||||
@@ -51,6 +53,7 @@ protected:
|
||||
CString m_sFormat;
|
||||
CString m_sText;
|
||||
timeval m_time;
|
||||
MCString m_mssTags;
|
||||
};
|
||||
|
||||
class CBuffer : private std::deque<CBufLine> {
|
||||
@@ -58,7 +61,7 @@ public:
|
||||
CBuffer(unsigned int uLineCount = 100);
|
||||
~CBuffer();
|
||||
|
||||
size_type AddLine(const CString& sFormat, const CString& sText = "", const timeval* ts = nullptr);
|
||||
size_type AddLine(const CString& sFormat, const CString& sText = "", const timeval* ts = nullptr, const MCString& mssTags = MCString::EmptyMap);
|
||||
/// Same as AddLine, but replaces a line whose format string starts with sMatch if there is one.
|
||||
size_type UpdateLine(const CString& sMatch, const CString& sFormat, const CString& sText = "");
|
||||
/// Same as UpdateLine, but does nothing if this exact line already exists.
|
||||
|
||||
+1
-1
@@ -98,7 +98,7 @@ public:
|
||||
bool SetBufferCount(unsigned int u, bool bForce = false) { m_bHasBufferCountSet = true; return m_Buffer.SetLineCount(u, bForce); }
|
||||
void InheritBufferCount(unsigned int u, bool bForce = false) { if (!m_bHasBufferCountSet) m_Buffer.SetLineCount(u, bForce); }
|
||||
void ResetBufferCount();
|
||||
size_t AddBuffer(const CString& sFormat, const CString& sText = "", const timeval* ts = nullptr) { return m_Buffer.AddLine(sFormat, sText, ts); }
|
||||
size_t AddBuffer(const CString& sFormat, const CString& sText = "", const timeval* ts = nullptr, const MCString& mssTags = MCString::EmptyMap) { return m_Buffer.AddLine(sFormat, sText, ts, mssTags); }
|
||||
void ClearBuffer() { m_Buffer.Clear(); }
|
||||
void SendBuffer(CClient* pClient);
|
||||
void SendBuffer(CClient* pClient, const CBuffer& Buffer);
|
||||
|
||||
@@ -29,6 +29,7 @@ class CUser;
|
||||
class CIRCNetwork;
|
||||
class CIRCSock;
|
||||
class CClient;
|
||||
class CMessage;
|
||||
// !Forward Declarations
|
||||
|
||||
class CAuthBase {
|
||||
@@ -174,7 +175,46 @@ public:
|
||||
void SetPlaybackActive(bool bActive) { m_bPlaybackActive = bActive; }
|
||||
|
||||
void PutIRC(const CString& sLine);
|
||||
/** Sends a raw data line to the client.
|
||||
* @param sLine The line to be sent.
|
||||
*
|
||||
* The line is first passed \e unmodified to the \ref CModule::OnSendToClient()
|
||||
* module hook. If no module halts the process, the line is then sent to the client.
|
||||
*
|
||||
* These lines appear in the debug output in the following syntax:
|
||||
* \code [time] (user/network) ZNC -> CLI [line] \endcode
|
||||
*/
|
||||
void PutClient(const CString& sLine);
|
||||
/** Sends a message to the client.
|
||||
* @param Message The message to be sent.
|
||||
* @note Only known and compatible message tags are sent.
|
||||
*
|
||||
* Not all IRC clients are capable of handling arbitrary sets of message
|
||||
* tags. For example, some older versions of some popular clients were
|
||||
* prepared to parse just one interesting tag, \c time, and would break
|
||||
* if multiple tags were included. Thus, in order to stay compatible with
|
||||
* a variety of IRC clients, ZNC has to filter out message tags that the
|
||||
* client has not explicitly requested.
|
||||
*
|
||||
* The following table documents currently supported message tags, and
|
||||
* which capabilities the client is required to have requested to receive
|
||||
* the respective message tags.
|
||||
*
|
||||
* Message tag | Capability
|
||||
* ----------- | ----------
|
||||
* \c time | \l CClient::HasServerTime() (<a href="http://ircv3.net/specs/extensions/server-time-3.2.html">server-time</a>)
|
||||
* \c batch | \l CClient::HasBatch() (<a href="http://ircv3.net/specs/extensions/batch-3.2.html">batch</a>)
|
||||
*
|
||||
* @warning Bypassing the filter may cause troubles to some older IRC clients.
|
||||
*
|
||||
* It is possible to bypass the filter by converting a message to a string
|
||||
* using \l CMessage::ToString(), and passing the resulting raw line to the
|
||||
* \l CClient::PutClient(const CString& sLine) overload:
|
||||
* \code
|
||||
* pClient->PutClient(Message.ToString());
|
||||
* \endcode
|
||||
*/
|
||||
void PutClient(const CMessage& Message);
|
||||
unsigned int PutStatus(const CTable& table);
|
||||
void PutStatus(const CString& sLine);
|
||||
void PutStatusNotice(const CString& sLine);
|
||||
|
||||
@@ -35,6 +35,7 @@ class CServer;
|
||||
class CIRCSock;
|
||||
class CIRCNetworkPingTimer;
|
||||
class CIRCNetworkJoinTimer;
|
||||
class CMessage;
|
||||
|
||||
class CIRCNetwork {
|
||||
public:
|
||||
@@ -90,6 +91,7 @@ public:
|
||||
// !Modules
|
||||
|
||||
bool PutUser(const CString& sLine, CClient* pClient = nullptr, CClient* pSkipClient = nullptr);
|
||||
bool PutUser(const CMessage& Message, CClient* pClient = nullptr, CClient* pSkipClient = nullptr);
|
||||
bool PutStatus(const CString& sLine, CClient* pClient = nullptr, CClient* pSkipClient = nullptr);
|
||||
bool PutModule(const CString& sModule, const CString& sLine, CClient* pClient = nullptr, CClient* pSkipClient = nullptr);
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ class CChan;
|
||||
class CUser;
|
||||
class CIRCNetwork;
|
||||
class CClient;
|
||||
class CMessage;
|
||||
// !Forward Declarations
|
||||
|
||||
// TODO: This class needs new name
|
||||
@@ -49,13 +50,13 @@ public:
|
||||
|
||||
// Message Handlers
|
||||
bool OnCTCPReply(CNick& Nick, CString& sMessage);
|
||||
bool OnPrivCTCP(CNick& Nick, CString& sMessage);
|
||||
bool OnChanCTCP(CNick& Nick, const CString& sChan, CString& sMessage);
|
||||
bool OnGeneralCTCP(CNick& Nick, CString& sMessage);
|
||||
bool OnPrivMsg(CNick& Nick, CString& sMessage);
|
||||
bool OnChanMsg(CNick& Nick, const CString& sChan, CString& sMessage);
|
||||
bool OnPrivNotice(CNick& Nick, CString& sMessage);
|
||||
bool OnChanNotice(CNick& Nick, const CString& sChan, CString& sMessage);
|
||||
bool OnPrivCTCP(CMessage& Message);
|
||||
bool OnChanCTCP(CMessage& Message);
|
||||
bool OnGeneralCTCP(CMessage& Message);
|
||||
bool OnPrivMsg(CMessage& Message);
|
||||
bool OnChanMsg(CMessage& Message);
|
||||
bool OnPrivNotice(CMessage& Message);
|
||||
bool OnChanNotice(CMessage& Message);
|
||||
bool OnServerCapAvailable(const CString& sCap);
|
||||
// !Message Handlers
|
||||
|
||||
@@ -113,6 +114,7 @@ public:
|
||||
CString GetISupport(const CString& sKey, const CString& sDefault = "") const;
|
||||
// !Getters
|
||||
|
||||
// TODO: CMessage
|
||||
// This handles NAMESX and UHNAMES in a raw 353 reply
|
||||
void ForwardRaw353(const CString& sLine) const;
|
||||
void ForwardRaw353(const CString& sLine, CClient* pClient) const;
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2015 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 _MESSAGE_H
|
||||
#define _MESSAGE_H
|
||||
|
||||
#include <znc/zncconfig.h>
|
||||
#include <znc/ZNCString.h>
|
||||
#include <znc/Nick.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
class CChan;
|
||||
class CClient;
|
||||
class CIRCNetwork;
|
||||
|
||||
class CMessage {
|
||||
public:
|
||||
explicit CMessage(const CString& sMessage = "");
|
||||
CMessage(const CNick& Nick, const CString& sCommand, const VCString& vsParams, const MCString& mssTags = MCString::EmptyMap);
|
||||
|
||||
// ZNC <-> IRC
|
||||
CIRCNetwork* GetNetwork() const { return m_pNetwork; }
|
||||
void SetNetwork(CIRCNetwork* pNetwork) { m_pNetwork = pNetwork; }
|
||||
|
||||
// ZNC <-> CLI
|
||||
CClient* GetClient() const { return m_pClient; }
|
||||
void SetClient(CClient* pClient) { m_pClient = pClient; }
|
||||
|
||||
CChan* GetChan() const { return m_pChan; }
|
||||
void SetChan(CChan* pChan) { m_pChan = pChan; }
|
||||
|
||||
CNick& GetNick() { return m_Nick; }
|
||||
const CNick& GetNick() const { return m_Nick; }
|
||||
void SetNick(const CNick& Nick) { m_Nick = Nick; }
|
||||
|
||||
const CString& GetCommand() const { return m_sCommand; }
|
||||
void SetCommand(const CString& sCommand) { m_sCommand = sCommand; }
|
||||
|
||||
const VCString& GetParams() const { return m_vsParams; }
|
||||
CString GetParams(unsigned int uIdx, unsigned int uLen = -1) const;
|
||||
void SetParams(const VCString& vsParams) { m_vsParams = vsParams; }
|
||||
|
||||
CString GetParam(unsigned int uIdx) const;
|
||||
void SetParam(unsigned int uIdx, const CString& sParam);
|
||||
|
||||
const timeval& GetTime() const { return m_time; }
|
||||
void SetTime(const timeval& ts) { m_time = ts; }
|
||||
|
||||
const MCString& GetTags() const { return m_mssTags; }
|
||||
void SetTags(const MCString& mssTags) { m_mssTags = mssTags; }
|
||||
|
||||
CString GetTag(const CString& sKey) const;
|
||||
void SetTag(const CString& sKey, const CString& sValue);
|
||||
|
||||
enum FormatFlags {
|
||||
IncludeAll = 0x0,
|
||||
ExcludePrefix = 0x1,
|
||||
ExcludeTags = 0x2
|
||||
};
|
||||
|
||||
CString ToString(unsigned int uFlags = IncludeAll) const;
|
||||
void Parse(CString sMessage);
|
||||
|
||||
private:
|
||||
void InitTime();
|
||||
|
||||
CNick m_Nick;
|
||||
CString m_sCommand;
|
||||
VCString m_vsParams;
|
||||
MCString m_mssTags;
|
||||
timeval m_time;
|
||||
CIRCNetwork* m_pNetwork = nullptr;
|
||||
CClient* m_pClient = nullptr;
|
||||
CChan* m_pChan = nullptr;
|
||||
};
|
||||
|
||||
class CChanAction : public CMessage {
|
||||
public:
|
||||
CString GetText() const { return GetParam(1).TrimLeft_n("\001ACTION ").TrimRight_n("\001"); }
|
||||
void SetText(const CString& sText) { SetParam(1, "\001ACTION " + sText + "\001"); }
|
||||
};
|
||||
|
||||
class CChanCTCP : public CMessage {
|
||||
public:
|
||||
CString GetText() const { return GetParam(1).TrimLeft_n("\001").TrimRight_n("\001"); }
|
||||
void SetText(const CString& sText) { SetParam(1, "\001" + sText + "\001"); }
|
||||
};
|
||||
|
||||
class CChanMessage : public CMessage {
|
||||
public:
|
||||
CString GetText() const { return GetParam(1); }
|
||||
void SetText(const CString& sText) { SetParam(1, sText); }
|
||||
};
|
||||
|
||||
class CChanNotice : public CMessage {
|
||||
public:
|
||||
CString GetText() const { return GetParam(1); }
|
||||
void SetText(const CString& sText) { SetParam(1, sText); }
|
||||
};
|
||||
|
||||
class CJoinMessage : public CMessage {
|
||||
public:
|
||||
};
|
||||
|
||||
class CNickMessage : public CMessage {
|
||||
public:
|
||||
CString GetOldNick() const { return GetNick().GetNick(); }
|
||||
CString GetNewNick() const { return GetParam(0); }
|
||||
void SetNewNick(const CString& sNick) { SetParam(0, sNick); }
|
||||
};
|
||||
|
||||
class CKickMessage : public CMessage {
|
||||
public:
|
||||
CString GetKickedNick() const { return GetParam(1); }
|
||||
void SetKickedNick(const CString& sNick) { SetParam(1, sNick); }
|
||||
CString GetReason() const { return GetParam(2); }
|
||||
void SetReason(const CString& sReason) { SetParam(2, sReason); }
|
||||
};
|
||||
|
||||
class CPartMessage : public CMessage {
|
||||
public:
|
||||
CString GetReason() const { return GetParam(1); }
|
||||
void SetReason(const CString& sReason) { SetParam(1, sReason); }
|
||||
};
|
||||
|
||||
class CPrivAction : public CMessage {
|
||||
public:
|
||||
CString GetText() const { return GetParam(1).TrimLeft_n("\001ACTION ").TrimRight_n("\001"); }
|
||||
void SetText(const CString& sText) { SetParam(1, "\001ACTION " + sText + "\001"); }
|
||||
};
|
||||
|
||||
class CPrivCTCP : public CMessage {
|
||||
public:
|
||||
CString GetText() const { return GetParam(1).TrimLeft_n("\001").TrimRight_n("\001"); }
|
||||
void SetText(const CString& sText) { SetParam(1, "\001" + sText + "\001"); }
|
||||
};
|
||||
|
||||
class CPrivMessage : public CMessage {
|
||||
public:
|
||||
CString GetText() const { return GetParam(1); }
|
||||
void SetText(const CString& sText) { SetParam(1, sText); }
|
||||
};
|
||||
|
||||
class CPrivNotice : public CMessage {
|
||||
public:
|
||||
CString GetText() const { return GetParam(1); }
|
||||
void SetText(const CString& sText) { SetParam(1, sText); }
|
||||
};
|
||||
|
||||
class CQuitMessage : public CMessage {
|
||||
public:
|
||||
CString GetReason() const { return GetParam(0); }
|
||||
void SetReason(const CString& sReason) { SetParam(0, sReason); }
|
||||
};
|
||||
|
||||
class CTopicMessage : public CMessage {
|
||||
public:
|
||||
CString GetTopic() const { return GetParam(1); }
|
||||
void SetTopic(const CString& sTopic) { SetParam(1, sTopic); }
|
||||
};
|
||||
|
||||
// The various CMessage subclasses are "mutable views" to the data held by CMessage.
|
||||
// They provide convenient access to message type speficic attributes, but are not
|
||||
// allowed to hold extra data of their own.
|
||||
static_assert(sizeof(CChanAction) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CChanCTCP) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CChanMessage) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CChanNotice) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CJoinMessage) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CPartMessage) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CPrivAction) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CPrivCTCP) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CPrivMessage) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CPrivNotice) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CNickMessage) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CKickMessage) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CQuitMessage) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
static_assert(sizeof(CTopicMessage) == sizeof(CMessage), "No data members allowed in CMessage subclasses.");
|
||||
|
||||
#endif // !_MESSAGE_H
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <znc/WebModules.h>
|
||||
#include <znc/Utils.h>
|
||||
#include <znc/Threads.h>
|
||||
#include <znc/Message.h>
|
||||
#include <znc/main.h>
|
||||
#include <functional>
|
||||
#include <set>
|
||||
@@ -593,6 +594,7 @@ public:
|
||||
* @param vChans List of channels which you and nick share.
|
||||
*/
|
||||
virtual void OnQuit(const CNick& Nick, const CString& sMessage, const std::vector<CChan*>& vChans);
|
||||
virtual void OnQuitMessage(CQuitMessage& Message, const std::vector<CChan*>& vChans);
|
||||
/** Called when a nickname change occurs. If we are changing our nick,
|
||||
* sNewNick will equal m_pIRCSock->GetNick().
|
||||
* @param Nick The nick which changed its nickname
|
||||
@@ -600,6 +602,7 @@ public:
|
||||
* @param vChans Channels which we and nick share.
|
||||
*/
|
||||
virtual void OnNick(const CNick& Nick, const CString& sNewNick, const std::vector<CChan*>& vChans);
|
||||
virtual void OnNickMessage(CNickMessage& Message, const std::vector<CChan*>& vChans);
|
||||
/** Called when a nick is kicked from a channel.
|
||||
* @param OpNick The nick which generated the kick.
|
||||
* @param sKickedNick The nick which was kicked.
|
||||
@@ -607,6 +610,7 @@ public:
|
||||
* @param sMessage The kick message.
|
||||
*/
|
||||
virtual void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage);
|
||||
virtual void OnKickMessage(CKickMessage& Message);
|
||||
/** This module hook is called just before ZNC tries to join an IRC channel.
|
||||
* @param Chan The channel which is about to get joined.
|
||||
* @return See CModule::EModRet.
|
||||
@@ -617,12 +621,14 @@ public:
|
||||
* @param Channel The channel which was joined.
|
||||
*/
|
||||
virtual void OnJoin(const CNick& Nick, CChan& Channel);
|
||||
virtual void OnJoinMessage(CJoinMessage& Message);
|
||||
/** Called when a nick parts a channel.
|
||||
* @param Nick The nick who parted.
|
||||
* @param Channel The channel which was parted.
|
||||
* @param sMessage The part message.
|
||||
*/
|
||||
virtual void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage);
|
||||
virtual void OnPartMessage(CPartMessage& Message);
|
||||
/** Called when user is invited into a channel
|
||||
* @param Nick The nick who invited you.
|
||||
* @param sChan The channel the user got invited into
|
||||
@@ -652,6 +658,7 @@ public:
|
||||
*/
|
||||
virtual EModRet OnChanBufferPlayLine2(CChan& Chan, CClient& Client, CString& sLine, const timeval& tv);
|
||||
virtual EModRet OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine);
|
||||
virtual EModRet OnChanBufferPlayMessage(CMessage& Message);
|
||||
/** Called when a line from the query buffer is played back.
|
||||
* @param Client The client this line will go to.
|
||||
* @param sLine The raw IRC traffic line from the buffer.
|
||||
@@ -660,6 +667,7 @@ public:
|
||||
*/
|
||||
virtual EModRet OnPrivBufferPlayLine2(CClient& Client, CString& sLine, const timeval& tv);
|
||||
virtual EModRet OnPrivBufferPlayLine(CClient& Client, CString& sLine);
|
||||
virtual EModRet OnPrivBufferPlayMessage(CMessage& Message);
|
||||
|
||||
/** Called when a client successfully logged in to ZNC. */
|
||||
virtual void OnClientLogin();
|
||||
@@ -749,6 +757,7 @@ public:
|
||||
* @return See CModule::EModRet.
|
||||
*/
|
||||
virtual EModRet OnPrivCTCP(CNick& Nick, CString& sMessage);
|
||||
virtual EModRet OnPrivCTCPMessage(CPrivCTCP& Message);
|
||||
/** Called when we receive a channel CTCP request <em>from IRC</em>.
|
||||
* @param Nick The nick the CTCP request is from.
|
||||
* @param Channel The channel to which the request was sent.
|
||||
@@ -756,6 +765,7 @@ public:
|
||||
* @return See CModule::EModRet.
|
||||
*/
|
||||
virtual EModRet OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage);
|
||||
virtual EModRet OnChanCTCPMessage(CChanCTCP& Message);
|
||||
/** Called when we receive a private CTCP ACTION ("/me" in query) <em>from IRC</em>.
|
||||
* This is called after CModule::OnPrivCTCP().
|
||||
* @param Nick The nick the action came from.
|
||||
@@ -763,6 +773,7 @@ public:
|
||||
* @return See CModule::EModRet.
|
||||
*/
|
||||
virtual EModRet OnPrivAction(CNick& Nick, CString& sMessage);
|
||||
virtual EModRet OnPrivActionMessage(CPrivAction& Message);
|
||||
/** Called when we receive a channel CTCP ACTION ("/me" in a channel) <em>from IRC</em>.
|
||||
* This is called after CModule::OnChanCTCP().
|
||||
* @param Nick The nick the action came from.
|
||||
@@ -771,12 +782,14 @@ public:
|
||||
* @return See CModule::EModRet.
|
||||
*/
|
||||
virtual EModRet OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage);
|
||||
virtual EModRet OnChanActionMessage(CChanAction& Message);
|
||||
/** Called when we receive a private message <em>from IRC</em>.
|
||||
* @param Nick The nick which sent the message.
|
||||
* @param sMessage The message.
|
||||
* @return See CModule::EModRet.
|
||||
*/
|
||||
virtual EModRet OnPrivMsg(CNick& Nick, CString& sMessage);
|
||||
virtual EModRet OnPrivMessage(CPrivMessage& Message);
|
||||
/** Called when we receive a channel message <em>from IRC</em>.
|
||||
* @param Nick The nick which sent the message.
|
||||
* @param Channel The channel to which the message was sent.
|
||||
@@ -784,12 +797,14 @@ public:
|
||||
* @return See CModule::EModRet.
|
||||
*/
|
||||
virtual EModRet OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage);
|
||||
virtual EModRet OnChanMessage(CChanMessage& Message);
|
||||
/** Called when we receive a private notice.
|
||||
* @param Nick The nick which sent the notice.
|
||||
* @param sMessage The notice message.
|
||||
* @return See CModule::EModRet.
|
||||
*/
|
||||
virtual EModRet OnPrivNotice(CNick& Nick, CString& sMessage);
|
||||
virtual EModRet OnPrivNoticeMessage(CPrivNotice& Message);
|
||||
/** Called when we receive a channel notice.
|
||||
* @param Nick The nick which sent the notice.
|
||||
* @param Channel The channel to which the notice was sent.
|
||||
@@ -797,6 +812,7 @@ public:
|
||||
* @return See CModule::EModRet.
|
||||
*/
|
||||
virtual EModRet OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage);
|
||||
virtual EModRet OnChanNoticeMessage(CChanNotice& Message);
|
||||
/** Called when we receive a channel topic change <em>from IRC</em>.
|
||||
* @param Nick The nick which changed the topic.
|
||||
* @param Channel The channel whose topic was changed.
|
||||
@@ -804,6 +820,7 @@ public:
|
||||
* @return See CModule::EModRet.
|
||||
*/
|
||||
virtual EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic);
|
||||
virtual EModRet OnTopicMessage(CTopicMessage& Message);
|
||||
|
||||
/** Called for every CAP received via CAP LS from server.
|
||||
* @param sCap capability supported by server.
|
||||
@@ -1186,11 +1203,16 @@ public:
|
||||
bool OnModCTCP(const CString& sMessage);
|
||||
|
||||
bool OnQuit(const CNick& Nick, const CString& sMessage, const std::vector<CChan*>& vChans);
|
||||
bool OnQuitMessage(CQuitMessage& Message, const std::vector<CChan*>& vChans);
|
||||
bool OnNick(const CNick& Nick, const CString& sNewNick, const std::vector<CChan*>& vChans);
|
||||
bool OnNickMessage(CNickMessage& Message, const std::vector<CChan*>& vChans);
|
||||
bool OnKick(const CNick& Nick, const CString& sOpNick, CChan& Channel, const CString& sMessage);
|
||||
bool OnKickMessage(CKickMessage& Message);
|
||||
bool OnJoining(CChan& Channel);
|
||||
bool OnJoin(const CNick& Nick, CChan& Channel);
|
||||
bool OnJoinMessage(CJoinMessage& Message);
|
||||
bool OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage);
|
||||
bool OnPartMessage(CPartMessage& Message);
|
||||
bool OnInvite(const CNick& Nick, const CString& sChan);
|
||||
|
||||
bool OnChanBufferStarting(CChan& Chan, CClient& Client);
|
||||
@@ -1199,6 +1221,8 @@ public:
|
||||
bool OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine);
|
||||
bool OnPrivBufferPlayLine2(CClient& Client, CString& sLine, const timeval& tv);
|
||||
bool OnPrivBufferPlayLine(CClient& Client, CString& sLine);
|
||||
bool OnChanBufferPlayMessage(CMessage& Message);
|
||||
bool OnPrivBufferPlayMessage(CMessage& Message);
|
||||
|
||||
bool OnClientLogin();
|
||||
bool OnClientDisconnect();
|
||||
@@ -1216,14 +1240,23 @@ public:
|
||||
|
||||
bool OnCTCPReply(CNick& Nick, CString& sMessage);
|
||||
bool OnPrivCTCP(CNick& Nick, CString& sMessage);
|
||||
bool OnPrivCTCPMessage(CPrivCTCP& Message);
|
||||
bool OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage);
|
||||
bool OnChanCTCPMessage(CChanCTCP& Message);
|
||||
bool OnPrivAction(CNick& Nick, CString& sMessage);
|
||||
bool OnPrivActionMessage(CPrivAction& Message);
|
||||
bool OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage);
|
||||
bool OnChanActionMessage(CChanAction& Message);
|
||||
bool OnPrivMsg(CNick& Nick, CString& sMessage);
|
||||
bool OnPrivMessage(CPrivMessage& Message);
|
||||
bool OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage);
|
||||
bool OnChanMessage(CChanMessage& Message);
|
||||
bool OnPrivNotice(CNick& Nick, CString& sMessage);
|
||||
bool OnPrivNoticeMessage(CPrivNotice& Message);
|
||||
bool OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage);
|
||||
bool OnChanNoticeMessage(CChanNotice& Message);
|
||||
bool OnTopic(CNick& Nick, CChan& Channel, CString& sTopic);
|
||||
bool OnTopicMessage(CTopicMessage& Message);
|
||||
bool OnTimerAutoJoin(CChan& Channel);
|
||||
|
||||
bool OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet);
|
||||
|
||||
+1
-1
@@ -38,7 +38,7 @@ public:
|
||||
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 = nullptr) { return m_Buffer.AddLine(sFormat, sText, ts); }
|
||||
size_t AddBuffer(const CString& sFormat, const CString& sText = "", const timeval* ts = nullptr, const MCString& mssTags = MCString::EmptyMap) { return m_Buffer.AddLine(sFormat, sText, ts, mssTags); }
|
||||
void ClearBuffer() { m_Buffer.Clear(); }
|
||||
void SendBuffer(CClient* pClient);
|
||||
void SendBuffer(CClient* pClient, const CBuffer& Buffer);
|
||||
|
||||
@@ -83,6 +83,7 @@ public:
|
||||
static CString CTime(time_t t, const CString& sTZ);
|
||||
static CString FormatTime(time_t t, const CString& sFormat, const CString& sTZ);
|
||||
static CString FormatServerTime(const timeval& tv);
|
||||
static timeval ParseServerTime(const CString& sTime);
|
||||
static SCString GetTimezones();
|
||||
static SCString GetEncodings();
|
||||
|
||||
|
||||
+30
-14
@@ -25,12 +25,12 @@ public:
|
||||
|
||||
virtual ~CBuffExtras() {}
|
||||
|
||||
void AddBuffer(CChan& Channel, const CString& sMessage) {
|
||||
void AddBuffer(CChan& Channel, const CString& sMessage, const timeval* tv = nullptr, const MCString& mssTags = MCString::EmptyMap) {
|
||||
// If they have AutoClearChanBuffer enabled, only add messages if no client is connected
|
||||
if (Channel.AutoClearChanBuffer() && GetNetwork()->IsUserOnline())
|
||||
return;
|
||||
|
||||
Channel.AddBuffer(":" + GetModNick() + "!" + GetModName() + "@znc.in PRIVMSG " + _NAMEDFMT(Channel.GetName()) + " :{text}", sMessage);
|
||||
Channel.AddBuffer(":" + GetModNick() + "!" + GetModName() + "@znc.in PRIVMSG " + _NAMEDFMT(Channel.GetName()) + " :{text}", sMessage, tv, mssTags);
|
||||
}
|
||||
|
||||
void OnRawMode2(const CNick* pOpNick, CChan& Channel, const CString& sModes, const CString& sArgs) override {
|
||||
@@ -38,34 +38,50 @@ public:
|
||||
AddBuffer(Channel, sNickMask + " set mode: " + sModes + " " + sArgs);
|
||||
}
|
||||
|
||||
void OnKick(const CNick& OpNick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) override {
|
||||
AddBuffer(Channel, OpNick.GetNickMask() + " kicked " + sKickedNick + " Reason: [" + sMessage + "]");
|
||||
void OnKickMessage(CKickMessage& Message) override {
|
||||
const CNick& OpNick = Message.GetNick();
|
||||
const CString sKickedNick = Message.GetKickedNick();
|
||||
CChan& Channel = *Message.GetChan();
|
||||
const CString sMessage = Message.GetReason();
|
||||
AddBuffer(Channel, OpNick.GetNickMask() + " kicked " + sKickedNick + " Reason: [" + sMessage + "]", &Message.GetTime(), Message.GetTags());
|
||||
}
|
||||
|
||||
void OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans) override {
|
||||
void OnQuitMessage(CQuitMessage& Message, const vector<CChan*>& vChans) override {
|
||||
const CNick& Nick = Message.GetNick();
|
||||
const CString sMessage = Message.GetReason();
|
||||
CString sMsg = Nick.GetNickMask() + " quit with message: [" + sMessage + "]";
|
||||
for (CChan* pChan : vChans) {
|
||||
AddBuffer(*pChan, sMsg);
|
||||
AddBuffer(*pChan, sMsg, &Message.GetTime(), Message.GetTags());
|
||||
}
|
||||
}
|
||||
|
||||
void OnJoin(const CNick& Nick, CChan& Channel) override {
|
||||
AddBuffer(Channel, Nick.GetNickMask() + " joined");
|
||||
void OnJoinMessage(CJoinMessage& Message) override {
|
||||
const CNick& Nick = Message.GetNick();
|
||||
CChan& Channel = *Message.GetChan();
|
||||
AddBuffer(Channel, Nick.GetNickMask() + " joined", &Message.GetTime(), Message.GetTags());
|
||||
}
|
||||
|
||||
void OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) override {
|
||||
AddBuffer(Channel, Nick.GetNickMask() + " parted with message: [" + sMessage + "]");
|
||||
void OnPartMessage(CPartMessage& Message) override {
|
||||
const CNick& Nick = Message.GetNick();
|
||||
CChan& Channel = *Message.GetChan();
|
||||
const CString sMessage = Message.GetReason();
|
||||
AddBuffer(Channel, Nick.GetNickMask() + " parted with message: [" + sMessage + "]", &Message.GetTime(), Message.GetTags());
|
||||
}
|
||||
|
||||
void OnNick(const CNick& OldNick, const CString& sNewNick, const vector<CChan*>& vChans) override {
|
||||
void OnNickMessage(CNickMessage& Message, const vector<CChan*>& vChans) override {
|
||||
const CNick& OldNick = Message.GetNick();
|
||||
const CString sNewNick = Message.GetNewNick();
|
||||
CString sMsg = OldNick.GetNickMask() + " is now known as " + sNewNick;
|
||||
for (CChan* pChan : vChans) {
|
||||
AddBuffer(*pChan, sMsg);
|
||||
AddBuffer(*pChan, sMsg, &Message.GetTime(), Message.GetTags());
|
||||
}
|
||||
}
|
||||
|
||||
EModRet OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) override {
|
||||
AddBuffer(Channel, Nick.GetNickMask() + " changed the topic to: " + sTopic);
|
||||
EModRet OnTopicMessage(CTopicMessage& Message) override {
|
||||
const CNick& Nick = Message.GetNick();
|
||||
CChan& Channel = *Message.GetChan();
|
||||
const CString sTopic = Message.GetTopic();
|
||||
AddBuffer(Channel, Nick.GetNickMask() + " changed the topic to: " + sTopic, &Message.GetTime(), Message.GetTags());
|
||||
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
+3
-3
@@ -19,7 +19,7 @@
|
||||
#include <znc/User.h>
|
||||
#include <time.h>
|
||||
|
||||
CBufLine::CBufLine(const CString& sFormat, const CString& sText, const timeval* ts) : m_sFormat(sFormat), m_sText(sText), m_time() {
|
||||
CBufLine::CBufLine(const CString& sFormat, const CString& sText, const timeval* ts, const MCString& mssTags) : m_sFormat(sFormat), m_sText(sText), m_time(), m_mssTags(mssTags) {
|
||||
if (ts == nullptr)
|
||||
UpdateTime();
|
||||
else
|
||||
@@ -54,7 +54,7 @@ CBuffer::CBuffer(unsigned int uLineCount) : m_uLineCount(uLineCount) {
|
||||
|
||||
CBuffer::~CBuffer() {}
|
||||
|
||||
CBuffer::size_type CBuffer::AddLine(const CString& sFormat, const CString& sText, const timeval* ts) {
|
||||
CBuffer::size_type CBuffer::AddLine(const CString& sFormat, const CString& sText, const timeval* ts, const MCString& mssTags) {
|
||||
if (!m_uLineCount) {
|
||||
return 0;
|
||||
}
|
||||
@@ -63,7 +63,7 @@ CBuffer::size_type CBuffer::AddLine(const CString& sFormat, const CString& sText
|
||||
erase(begin());
|
||||
}
|
||||
|
||||
push_back(CBufLine(sFormat, sText, ts));
|
||||
push_back(CBufLine(sFormat, sText, ts, mssTags));
|
||||
return size();
|
||||
}
|
||||
|
||||
|
||||
+10
-6
@@ -20,6 +20,7 @@
|
||||
#include <znc/IRCNetwork.h>
|
||||
#include <znc/Config.h>
|
||||
#include <znc/znc.h>
|
||||
#include <znc/Message.h>
|
||||
|
||||
using std::set;
|
||||
using std::vector;
|
||||
@@ -610,16 +611,19 @@ void CChan::SendBuffer(CClient* pClient, const CBuffer& Buffer) {
|
||||
size_t uSize = Buffer.Size();
|
||||
for (size_t uIdx = 0; uIdx < uSize; uIdx++) {
|
||||
const CBufLine& BufLine = Buffer.GetBufLine(uIdx);
|
||||
CString sLine = BufLine.GetLine(*pUseClient, MCString::EmptyMap);
|
||||
CMessage Message(BufLine.GetLine(*pUseClient, MCString::EmptyMap));
|
||||
Message.SetChan(this);
|
||||
Message.SetNetwork(m_pNetwork);
|
||||
Message.SetClient(pClient);
|
||||
Message.SetTime(BufLine.GetTime());
|
||||
Message.SetTags(BufLine.GetTags());
|
||||
if (bBatch) {
|
||||
MCString msBatchTags = CUtils::GetMessageTags(sLine);
|
||||
msBatchTags["batch"] = sBatchName;
|
||||
CUtils::SetMessageTags(sLine, msBatchTags);
|
||||
Message.SetTag("batch", sBatchName);
|
||||
}
|
||||
bool bNotShowThisLine = false;
|
||||
NETWORKMODULECALL(OnChanBufferPlayLine2(*this, *pUseClient, sLine, BufLine.GetTime()), m_pNetwork->GetUser(), m_pNetwork, nullptr, &bNotShowThisLine);
|
||||
NETWORKMODULECALL(OnChanBufferPlayMessage(Message), m_pNetwork->GetUser(), m_pNetwork, nullptr, &bNotShowThisLine);
|
||||
if (bNotShowThisLine) continue;
|
||||
m_pNetwork->PutUser(sLine, pUseClient);
|
||||
m_pNetwork->PutUser(Message, pUseClient);
|
||||
}
|
||||
|
||||
bSkipStatusMsg = pUseClient->HasServerTime();
|
||||
|
||||
+37
-6
@@ -96,8 +96,9 @@ void CClient::ReadLine(const CString& sData) {
|
||||
|
||||
DEBUG("(" << GetFullName() << ") CLI -> ZNC [" << sLine << "]");
|
||||
|
||||
MCString mssTags;
|
||||
if (sLine.StartsWith("@")) {
|
||||
// TODO support message-tags properly
|
||||
mssTags = CUtils::GetMessageTags(sLine);
|
||||
sLine = sLine.Token(1, true);
|
||||
}
|
||||
|
||||
@@ -262,7 +263,7 @@ void CClient::ReadLine(const CString& sData) {
|
||||
CChan* pChan = m_pNetwork->FindChan(sTarget);
|
||||
|
||||
if ((pChan) && (!pChan->AutoClearChanBuffer())) {
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " NOTICE " + _NAMEDFMT(sTarget) + " :{text}", sMsg);
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " NOTICE " + _NAMEDFMT(sTarget) + " :{text}", sMsg, nullptr, mssTags);
|
||||
}
|
||||
|
||||
// Relay to the rest of the clients that may be connected to this user
|
||||
@@ -313,13 +314,13 @@ void CClient::ReadLine(const CString& sData) {
|
||||
CChan* pChan = m_pNetwork->FindChan(sTarget);
|
||||
|
||||
if (pChan && (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline())) {
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :\001ACTION {text}\001", sMessage);
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :\001ACTION {text}\001", sMessage, nullptr, mssTags);
|
||||
}
|
||||
} 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);
|
||||
pQuery->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :\001ACTION {text}\001", sMessage, nullptr, mssTags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -368,13 +369,13 @@ void CClient::ReadLine(const CString& sData) {
|
||||
CChan* pChan = m_pNetwork->FindChan(sTarget);
|
||||
|
||||
if ((pChan) && (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline())) {
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :{text}", sMsg);
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :{text}", sMsg, nullptr, mssTags);
|
||||
}
|
||||
} 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);
|
||||
pQuery->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :{text}", sMsg, nullptr, mssTags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -793,6 +794,36 @@ void CClient::PutClient(const CString& sLine) {
|
||||
Write(sCopy + "\r\n");
|
||||
}
|
||||
|
||||
void CClient::PutClient(const CMessage& Message)
|
||||
{
|
||||
CString sLine = Message.ToString(CMessage::ExcludeTags);
|
||||
|
||||
// TODO: introduce a module hook that gives control over the tags that are sent
|
||||
MCString mssTags;
|
||||
|
||||
if (HasServerTime()) {
|
||||
CString sServerTime = Message.GetTag("time");
|
||||
if (!sServerTime.empty()) {
|
||||
mssTags["time"] = sServerTime;
|
||||
} else {
|
||||
mssTags["time"] = CUtils::FormatServerTime(Message.GetTime());
|
||||
}
|
||||
}
|
||||
|
||||
if (HasBatch()) {
|
||||
CString sBatch = Message.GetTag("batch");
|
||||
if (!sBatch.empty()) {
|
||||
mssTags["batch"] = sBatch;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mssTags.empty()) {
|
||||
CUtils::SetMessageTags(sLine, mssTags);
|
||||
}
|
||||
|
||||
PutClient(sLine);
|
||||
}
|
||||
|
||||
void CClient::PutStatusNotice(const CString& sLine) {
|
||||
PutModNotice("status", sLine);
|
||||
}
|
||||
|
||||
+22
-3
@@ -22,6 +22,7 @@
|
||||
#include <znc/Server.h>
|
||||
#include <znc/Chan.h>
|
||||
#include <znc/Query.h>
|
||||
#include <znc/Message.h>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
@@ -642,11 +643,15 @@ void CIRCNetwork::ClientConnected(CClient *pClient) {
|
||||
uSize = m_NoticeBuffer.Size();
|
||||
for (uIdx = 0; uIdx < uSize; uIdx++) {
|
||||
const CBufLine& BufLine = m_NoticeBuffer.GetBufLine(uIdx);
|
||||
CString sLine = BufLine.GetLine(*pClient, msParams);
|
||||
CMessage Message(BufLine.GetLine(*pClient, msParams));
|
||||
Message.SetNetwork(this);
|
||||
Message.SetClient(pClient);
|
||||
Message.SetTime(BufLine.GetTime());
|
||||
Message.SetTags(BufLine.GetTags());
|
||||
bool bContinue = false;
|
||||
NETWORKMODULECALL(OnPrivBufferPlayLine2(*pClient, sLine, BufLine.GetTime()), m_pUser, this, nullptr, &bContinue);
|
||||
NETWORKMODULECALL(OnPrivBufferPlayMessage(Message), m_pUser, this, nullptr, &bContinue);
|
||||
if (bContinue) continue;
|
||||
pClient->PutClient(sLine);
|
||||
pClient->PutClient(Message);
|
||||
}
|
||||
m_NoticeBuffer.Clear();
|
||||
|
||||
@@ -726,6 +731,20 @@ bool CIRCNetwork::PutUser(const CString& sLine, CClient* pClient, CClient* pSkip
|
||||
return (pClient == nullptr);
|
||||
}
|
||||
|
||||
bool CIRCNetwork::PutUser(const CMessage& Message, CClient* pClient, CClient* pSkipClient) {
|
||||
for (CClient* pEachClient : m_vClients) {
|
||||
if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) {
|
||||
pEachClient->PutClient(Message);
|
||||
|
||||
if (pClient) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (pClient == nullptr);
|
||||
}
|
||||
|
||||
bool CIRCNetwork::PutStatus(const CString& sLine, CClient* pClient, CClient* pSkipClient) {
|
||||
for (CClient* pEachClient : m_vClients) {
|
||||
if ((!pClient || pClient == pEachClient) && pSkipClient != pEachClient) {
|
||||
|
||||
+119
-109
@@ -20,6 +20,7 @@
|
||||
#include <znc/IRCNetwork.h>
|
||||
#include <znc/Server.h>
|
||||
#include <znc/Query.h>
|
||||
#include <znc/Message.h>
|
||||
#include <time.h>
|
||||
|
||||
using std::set;
|
||||
@@ -156,29 +157,31 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
IRCSOCKMODULECALL(OnRaw(sLine), &bReturn);
|
||||
if (bReturn) return;
|
||||
|
||||
if (sLine.StartsWith("PING ")) {
|
||||
CMessage Message(sLine);
|
||||
Message.SetNetwork(m_pNetwork);
|
||||
|
||||
CString sCmd = Message.GetCommand();
|
||||
|
||||
if (sCmd.Equals("PING")) {
|
||||
// Generate a reply and don't forward this to any user,
|
||||
// we don't want any PING forwarded
|
||||
PutIRCQuick("PONG " + sLine.substr(5));
|
||||
PutIRCQuick("PONG " + Message.GetParam(0));
|
||||
return;
|
||||
} else if (sLine.Token(1).Equals("PONG")) {
|
||||
} else if (sCmd.Equals("PONG")) {
|
||||
// Block PONGs, we already responded to the pings
|
||||
return;
|
||||
} else if (sLine.StartsWith("ERROR ")) {
|
||||
} else if (sCmd.Equals("ERROR")) {
|
||||
//ERROR :Closing Link: nick[24.24.24.24] (Excess Flood)
|
||||
CString sError(sLine.substr(6));
|
||||
sError.TrimPrefix();
|
||||
CString sError = Message.GetParam(0);
|
||||
m_pNetwork->PutStatus("Error from Server [" + sError + "]");
|
||||
return;
|
||||
}
|
||||
|
||||
CString sCmd = sLine.Token(1);
|
||||
|
||||
if ((sCmd.length() == 3) && (isdigit(sCmd[0])) && (isdigit(sCmd[1])) && (isdigit(sCmd[2]))) {
|
||||
CString sServer = sLine.Token(0).LeftChomp_n();
|
||||
CString sServer = Message.GetNick().GetHostMask();
|
||||
unsigned int uRaw = sCmd.ToUInt();
|
||||
CString sNick = sLine.Token(2);
|
||||
CString sRest = sLine.Token(3, true);
|
||||
CString sNick = Message.GetParam(0);
|
||||
CString sRest = Message.GetParams(1);
|
||||
CString sTmp;
|
||||
|
||||
switch (uRaw) {
|
||||
@@ -224,9 +227,9 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
m_pNetwork->UpdateExactRawBuffer(":" + _NAMEDFMT(sServer) + " " + sCmd + " {target} " + _NAMEDFMT(sRest));
|
||||
break;
|
||||
case 10: { // :irc.server.com 010 nick <hostname> <port> :<info>
|
||||
CString sHost = sRest.Token(0);
|
||||
CString sPort = sRest.Token(1);
|
||||
CString sInfo = sRest.Token(2, true).TrimPrefix_n();
|
||||
CString sHost = Message.GetParam(1);
|
||||
CString sPort = Message.GetParam(2);
|
||||
CString sInfo = Message.GetParam(3);
|
||||
m_pNetwork->PutStatus("Server [" + m_pNetwork->GetCurrentServer()->GetString(false) +
|
||||
"] redirects us to [" + sHost + ":" + sPort + "] with reason [" + sInfo + "]");
|
||||
m_pNetwork->PutStatus("Perhaps you want to add it as a new server.");
|
||||
@@ -278,7 +281,7 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
CChan* pChan = m_pNetwork->FindChan(sRest.Token(0));
|
||||
|
||||
if (pChan) {
|
||||
unsigned long ulDate = sLine.Token(4).ToULong();
|
||||
unsigned long ulDate = Message.GetParam(2).ToULong();
|
||||
pChan->SetCreationDate(ulDate);
|
||||
|
||||
if (!pChan->IsModeKnown()) {
|
||||
@@ -296,7 +299,7 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
break;
|
||||
case 331: {
|
||||
// :irc.server.com 331 yournick #chan :No topic is set.
|
||||
CChan* pChan = m_pNetwork->FindChan(sLine.Token(3));
|
||||
CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1));
|
||||
|
||||
if (pChan) {
|
||||
pChan->SetTopic("");
|
||||
@@ -309,11 +312,10 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
}
|
||||
case 332: {
|
||||
// :irc.server.com 332 yournick #chan :This is a topic
|
||||
CChan* pChan = m_pNetwork->FindChan(sLine.Token(3));
|
||||
CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1));
|
||||
|
||||
if (pChan) {
|
||||
CString sTopic = sLine.Token(4, true);
|
||||
sTopic.LeftChomp();
|
||||
CString sTopic = Message.GetParam(2);
|
||||
pChan->SetTopic(sTopic);
|
||||
if (pChan->IsDetached()) {
|
||||
return;
|
||||
@@ -324,11 +326,11 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
}
|
||||
case 333: {
|
||||
// :irc.server.com 333 yournick #chan setternick 1112320796
|
||||
CChan* pChan = m_pNetwork->FindChan(sLine.Token(3));
|
||||
CChan* pChan = m_pNetwork->FindChan(Message.GetParam(1));
|
||||
|
||||
if (pChan) {
|
||||
sNick = sLine.Token(4);
|
||||
unsigned long ulDate = sLine.Token(5).ToULong();
|
||||
sNick = Message.GetParam(2);
|
||||
unsigned long ulDate = Message.GetParam(3).ToULong();
|
||||
|
||||
pChan->SetTopicOwner(sNick);
|
||||
pChan->SetTopicDate(ulDate);
|
||||
@@ -342,13 +344,10 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
}
|
||||
case 352: { // WHO
|
||||
// :irc.yourserver.com 352 yournick #chan ident theirhost.com irc.theirserver.com theirnick H :0 Real Name
|
||||
sServer = sLine.Token(0);
|
||||
sNick = sLine.Token(7);
|
||||
CString sChan = sLine.Token(3);
|
||||
CString sIdent = sLine.Token(4);
|
||||
CString sHost = sLine.Token(5);
|
||||
|
||||
sServer.LeftChomp();
|
||||
sNick = Message.GetParam(5);
|
||||
CString sChan = Message.GetParam(1);
|
||||
CString sIdent = Message.GetParam(2);
|
||||
CString sHost = Message.GetParam(3);
|
||||
|
||||
if (sNick.Equals(GetNick())) {
|
||||
m_Nick.SetIdent(sIdent);
|
||||
@@ -370,7 +369,7 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
const vector<CClient*>& vClients = m_pNetwork->GetClients();
|
||||
for (CClient* pClient : vClients) {
|
||||
if (pClient->HasNamesx()) {
|
||||
m_pNetwork->PutUser(sLine, pClient);
|
||||
m_pNetwork->PutUser(Message, pClient);
|
||||
} else {
|
||||
// The client doesn't support multi-prefix so we need to remove
|
||||
// the other prefixes.
|
||||
@@ -380,6 +379,7 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
if (pos >= 2 && pos != CString::npos) {
|
||||
sNewNick = sNick[0] + sNick.substr(pos);
|
||||
}
|
||||
// TODO: CMessage
|
||||
CString sNewLine = sServer + " 352 " + sLine.Token(2) + " " +
|
||||
sChan + " " + sIdent + " " + sHost + " " +
|
||||
sLine.Token(6) + " " + sNewNick + " " +
|
||||
@@ -505,12 +505,11 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
CNick Nick(sLine.Token(0).TrimPrefix_n());
|
||||
sCmd = sLine.Token(1);
|
||||
CString sRest = sLine.Token(2, true);
|
||||
CNick Nick = Message.GetNick();
|
||||
|
||||
if (sCmd.Equals("NICK")) {
|
||||
CString sNewNick = sRest.TrimPrefix_n();
|
||||
CNickMessage& NickMsg = static_cast<CNickMessage&>(Message);
|
||||
CString sNewNick = NickMsg.GetNewNick();
|
||||
bool bIsVisible = false;
|
||||
|
||||
vector<CChan*> vFoundChans;
|
||||
@@ -530,22 +529,22 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
// We are changing our own nick, the clients always must see this!
|
||||
bIsVisible = false;
|
||||
SetNick(sNewNick);
|
||||
m_pNetwork->PutUser(sLine);
|
||||
m_pNetwork->PutUser(Message);
|
||||
}
|
||||
|
||||
IRCSOCKMODULECALL(OnNick(Nick, sNewNick, vFoundChans), NOTHING);
|
||||
IRCSOCKMODULECALL(OnNickMessage(NickMsg, vFoundChans), NOTHING);
|
||||
|
||||
if (!bIsVisible) {
|
||||
return;
|
||||
}
|
||||
} else if (sCmd.Equals("QUIT")) {
|
||||
CString sMessage = sRest.TrimPrefix_n();
|
||||
CQuitMessage& QuitMsg = static_cast<CQuitMessage&>(Message);
|
||||
bool bIsVisible = false;
|
||||
|
||||
// :nick!ident@host.com QUIT :message
|
||||
|
||||
if (Nick.NickEquals(GetNick())) {
|
||||
m_pNetwork->PutStatus("You quit [" + sMessage + "]");
|
||||
m_pNetwork->PutStatus("You quit [" + QuitMsg.GetReason() + "]");
|
||||
// We don't call module hooks and we don't
|
||||
// forward this quit to clients (Some clients
|
||||
// disconnect if they receive such a QUIT)
|
||||
@@ -565,14 +564,15 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
}
|
||||
}
|
||||
|
||||
IRCSOCKMODULECALL(OnQuit(Nick, sMessage, vFoundChans), NOTHING);
|
||||
IRCSOCKMODULECALL(OnQuitMessage(QuitMsg, vFoundChans), NOTHING);
|
||||
|
||||
if (!bIsVisible) {
|
||||
return;
|
||||
}
|
||||
} else if (sCmd.Equals("JOIN")) {
|
||||
CString sChan = sRest.Token(0).TrimPrefix_n();
|
||||
CChan* pChan;
|
||||
CJoinMessage& JoinMsg = static_cast<CJoinMessage&>(Message);
|
||||
CString sChan = JoinMsg.GetParam(0);
|
||||
CChan* pChan = nullptr;
|
||||
|
||||
if (Nick.NickEquals(GetNick())) {
|
||||
m_pNetwork->AddChan(sChan, false);
|
||||
@@ -588,7 +588,8 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
|
||||
if (pChan) {
|
||||
pChan->AddNick(Nick.GetNickMask());
|
||||
IRCSOCKMODULECALL(OnJoin(Nick.GetNickMask(), *pChan), NOTHING);
|
||||
JoinMsg.SetChan(pChan);
|
||||
IRCSOCKMODULECALL(OnJoinMessage(JoinMsg), NOTHING);
|
||||
|
||||
if (pChan->IsDetached()) {
|
||||
return;
|
||||
@@ -610,14 +611,15 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
}
|
||||
}
|
||||
} else if (sCmd.Equals("PART")) {
|
||||
CString sChan = sRest.Token(0).TrimPrefix_n();
|
||||
CString sMsg = sRest.Token(1, true).TrimPrefix_n();
|
||||
CPartMessage& PartMsg = static_cast<CPartMessage&>(Message);
|
||||
CString sChan = PartMsg.GetParam(0);
|
||||
|
||||
CChan* pChan = m_pNetwork->FindChan(sChan);
|
||||
bool bDetached = false;
|
||||
if (pChan) {
|
||||
pChan->RemNick(Nick.GetNick());
|
||||
IRCSOCKMODULECALL(OnPart(Nick.GetNickMask(), *pChan, sMsg), NOTHING);
|
||||
PartMsg.SetChan(pChan);
|
||||
IRCSOCKMODULECALL(OnPartMessage(PartMsg), NOTHING);
|
||||
|
||||
if (pChan->IsDetached())
|
||||
bDetached = true;
|
||||
@@ -637,8 +639,8 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
return;
|
||||
}
|
||||
} else if (sCmd.Equals("MODE")) {
|
||||
CString sTarget = sRest.Token(0);
|
||||
CString sModes = sRest.Token(1, true).TrimPrefix_n(":");
|
||||
CString sTarget = Message.GetParam(0);
|
||||
CString sModes = Message.GetParams(1);
|
||||
|
||||
CChan* pChan = m_pNetwork->FindChan(sTarget);
|
||||
if (pChan) {
|
||||
@@ -670,16 +672,16 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
}
|
||||
}
|
||||
} else if (sCmd.Equals("KICK")) {
|
||||
CKickMessage& KickMsg = static_cast<CKickMessage&>(Message);
|
||||
// :opnick!ident@host.com KICK #chan nick :msg
|
||||
CString sChan = sRest.Token(0);
|
||||
CString sKickedNick = sRest.Token(1);
|
||||
CString sMsg = sRest.Token(2, true);
|
||||
sMsg.LeftChomp();
|
||||
CString sChan = KickMsg.GetParam(0);
|
||||
CString sKickedNick = KickMsg.GetKickedNick();
|
||||
|
||||
CChan* pChan = m_pNetwork->FindChan(sChan);
|
||||
|
||||
if (pChan) {
|
||||
IRCSOCKMODULECALL(OnKick(Nick, sKickedNick, *pChan, sMsg), NOTHING);
|
||||
KickMsg.SetChan(pChan);
|
||||
IRCSOCKMODULECALL(OnKickMessage(KickMsg), NOTHING);
|
||||
// do not remove the nick till after the OnKick call, so modules
|
||||
// can do Chan.FindNick or something to get more info.
|
||||
pChan->RemNick(sKickedNick);
|
||||
@@ -697,9 +699,8 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
}
|
||||
} else if (sCmd.Equals("NOTICE")) {
|
||||
// :nick!ident@host.com NOTICE #chan :Message
|
||||
CString sTarget = sRest.Token(0);
|
||||
CString sMsg = sRest.Token(1, true);
|
||||
sMsg.LeftChomp();
|
||||
CString sTarget = Message.GetParam(0);
|
||||
CString sMsg = Message.GetParam(1);
|
||||
|
||||
if (sMsg.WildCmp("\001*\001")) {
|
||||
sMsg.LeftChomp();
|
||||
@@ -715,11 +716,11 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
return;
|
||||
} else {
|
||||
if (sTarget.Equals(GetNick())) {
|
||||
if (OnPrivNotice(Nick, sMsg)) {
|
||||
if (OnPrivNotice(Message)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (OnChanNotice(Nick, sTarget, sMsg)) {
|
||||
if (OnChanNotice(Message)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -733,41 +734,38 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
|
||||
return;
|
||||
} else if (sCmd.Equals("TOPIC")) {
|
||||
CTopicMessage& TopicMsg = static_cast<CTopicMessage&>(Message);
|
||||
// :nick!ident@host.com TOPIC #chan :This is a topic
|
||||
CChan* pChan = m_pNetwork->FindChan(sLine.Token(2));
|
||||
CChan* pChan = m_pNetwork->FindChan(TopicMsg.GetParam(0));
|
||||
|
||||
if (pChan) {
|
||||
CString sTopic = sLine.Token(3, true);
|
||||
sTopic.LeftChomp();
|
||||
|
||||
IRCSOCKMODULECALL(OnTopic(Nick, *pChan, sTopic), &bReturn);
|
||||
TopicMsg.SetChan(pChan);
|
||||
IRCSOCKMODULECALL(OnTopicMessage(TopicMsg), &bReturn);
|
||||
if (bReturn) return;
|
||||
|
||||
pChan->SetTopicOwner(Nick.GetNick());
|
||||
pChan->SetTopicDate((unsigned long) time(nullptr));
|
||||
pChan->SetTopic(sTopic);
|
||||
pChan->SetTopic(TopicMsg.GetTopic());
|
||||
|
||||
if (pChan->IsDetached()) {
|
||||
return; // Don't forward this
|
||||
}
|
||||
|
||||
sLine = ":" + Nick.GetNickMask() + " TOPIC " + pChan->GetName() + " :" + sTopic;
|
||||
}
|
||||
} else if (sCmd.Equals("PRIVMSG")) {
|
||||
// :nick!ident@host.com PRIVMSG #chan :Message
|
||||
CString sTarget = sRest.Token(0);
|
||||
CString sMsg = sRest.Token(1, true).TrimPrefix_n();
|
||||
CString sTarget = Message.GetParam(0);
|
||||
CString sMsg = Message.GetParam(1);
|
||||
|
||||
if (sMsg.WildCmp("\001*\001")) {
|
||||
sMsg.LeftChomp();
|
||||
sMsg.RightChomp();
|
||||
|
||||
if (sTarget.Equals(GetNick())) {
|
||||
if (OnPrivCTCP(Nick, sMsg)) {
|
||||
if (OnPrivCTCP(Message)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (OnChanCTCP(Nick, sTarget, sMsg)) {
|
||||
if (OnChanCTCP(Message)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -776,11 +774,11 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
return;
|
||||
} else {
|
||||
if (sTarget.Equals(GetNick())) {
|
||||
if (OnPrivMsg(Nick, sMsg)) {
|
||||
if (OnPrivMsg(Message)) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (OnChanMsg(Nick, sTarget, sMsg)) {
|
||||
if (OnChanMsg(Message)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -790,7 +788,7 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
}
|
||||
} else if (sCmd.Equals("WALLOPS")) {
|
||||
// :blub!dummy@rox-8DBEFE92 WALLOPS :this is a test
|
||||
CString sMsg = sRest.Token(0, true).TrimPrefix_n();
|
||||
CString sMsg = Message.GetParam(0);
|
||||
|
||||
if (!m_pNetwork->IsUserOnline()) {
|
||||
m_pNetwork->AddNoticeBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " WALLOPS :{text}", sMsg);
|
||||
@@ -798,10 +796,10 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
} else if (sCmd.Equals("CAP")) {
|
||||
// CAPs are supported only before authorization.
|
||||
if (!m_bAuthed) {
|
||||
// sRest.Token(0) is most likely "*". No idea why, the
|
||||
// The first parameter is most likely "*". No idea why, the
|
||||
// CAP spec don't mention this, but all implementations
|
||||
// I've seen add this extra asterisk
|
||||
CString sSubCmd = sRest.Token(1);
|
||||
CString sSubCmd = Message.GetParam(1);
|
||||
|
||||
// If the caplist of a reply is too long, it's split
|
||||
// into multiple replies. A "*" is prepended to show
|
||||
@@ -815,10 +813,10 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
// to recognize past request of NAK by 100 chars
|
||||
// of this reply.
|
||||
CString sArgs;
|
||||
if (sRest.Token(2) == "*") {
|
||||
sArgs = sRest.Token(3, true).TrimPrefix_n();
|
||||
if (Message.GetParam(2) == "*") {
|
||||
sArgs = Message.GetParam(3);
|
||||
} else {
|
||||
sArgs = sRest.Token(2, true).TrimPrefix_n();
|
||||
sArgs = Message.GetParam(2);
|
||||
}
|
||||
|
||||
std::map<CString, std::function<void(bool bVal)>> mSupportedCaps = {
|
||||
@@ -879,7 +877,7 @@ void CIRCSock::ReadLine(const CString& sData) {
|
||||
}
|
||||
}
|
||||
|
||||
m_pNetwork->PutUser(sLine);
|
||||
m_pNetwork->PutUser(Message);
|
||||
}
|
||||
|
||||
void CIRCSock::SendNextCap() {
|
||||
@@ -917,31 +915,34 @@ bool CIRCSock::OnCTCPReply(CNick& Nick, CString& sMessage) {
|
||||
return bResult;
|
||||
}
|
||||
|
||||
bool CIRCSock::OnPrivCTCP(CNick& Nick, CString& sMessage) {
|
||||
bool CIRCSock::OnPrivCTCP(CMessage& Message) {
|
||||
CPrivCTCP& PrivCTCP = static_cast<CPrivCTCP&>(Message);
|
||||
bool bResult = false;
|
||||
IRCSOCKMODULECALL(OnPrivCTCP(Nick, sMessage), &bResult);
|
||||
IRCSOCKMODULECALL(OnPrivCTCPMessage(PrivCTCP), &bResult);
|
||||
if (bResult) return true;
|
||||
|
||||
if (sMessage.TrimPrefix("ACTION ")) {
|
||||
if (PrivCTCP.GetText().StartsWith("ACTION ")) {
|
||||
bResult = false;
|
||||
IRCSOCKMODULECALL(OnPrivAction(Nick, sMessage), &bResult);
|
||||
CPrivAction& PrivAction = static_cast<CPrivAction&>(Message);
|
||||
IRCSOCKMODULECALL(OnPrivActionMessage(PrivAction), &bResult);
|
||||
if (bResult) return true;
|
||||
|
||||
if (!m_pNetwork->IsUserOnline() || !m_pNetwork->GetUser()->AutoClearQueryBuffer()) {
|
||||
const CNick& Nick = PrivAction.GetNick();
|
||||
CQuery* pQuery = m_pNetwork->AddQuery(Nick.GetNick());
|
||||
if (pQuery) {
|
||||
pQuery->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG {target} :\001ACTION {text}\001", sMessage);
|
||||
pQuery->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG {target} :\001ACTION {text}\001", PrivAction.GetText(), &PrivAction.GetTime(), PrivAction.GetTags());
|
||||
}
|
||||
}
|
||||
|
||||
sMessage = "ACTION " + sMessage;
|
||||
}
|
||||
|
||||
// This handles everything which wasn't handled yet
|
||||
return OnGeneralCTCP(Nick, sMessage);
|
||||
return OnGeneralCTCP(Message);
|
||||
}
|
||||
|
||||
bool CIRCSock::OnGeneralCTCP(CNick& Nick, CString& sMessage) {
|
||||
bool CIRCSock::OnGeneralCTCP(CMessage& Message) {
|
||||
const CNick& Nick = Message.GetNick();
|
||||
const CString& sMessage = Message.GetParam(1);
|
||||
const MCString& mssCTCPReplies = m_pNetwork->GetUser()->GetCTCPReplies();
|
||||
CString sQuery = sMessage.Token(0).AsUpper();
|
||||
MCString::const_iterator it = mssCTCPReplies.find(sQuery);
|
||||
@@ -985,83 +986,92 @@ bool CIRCSock::OnGeneralCTCP(CNick& Nick, CString& sMessage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CIRCSock::OnPrivNotice(CNick& Nick, CString& sMessage) {
|
||||
bool CIRCSock::OnPrivNotice(CMessage& Message) {
|
||||
CPrivNotice& PrivNotice = static_cast<CPrivNotice&>(Message);
|
||||
bool bResult = false;
|
||||
IRCSOCKMODULECALL(OnPrivNotice(Nick, sMessage), &bResult);
|
||||
IRCSOCKMODULECALL(OnPrivNoticeMessage(PrivNotice), &bResult);
|
||||
if (bResult) return true;
|
||||
|
||||
if (!m_pNetwork->IsUserOnline()) {
|
||||
// If the user is detached, add to the buffer
|
||||
m_pNetwork->AddNoticeBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " NOTICE {target} :{text}", sMessage);
|
||||
m_pNetwork->AddNoticeBuffer(":" + _NAMEDFMT(PrivNotice.GetNick().GetNickMask()) + " NOTICE {target} :{text}", PrivNotice.GetText());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CIRCSock::OnPrivMsg(CNick& Nick, CString& sMessage) {
|
||||
bool CIRCSock::OnPrivMsg(CMessage& Message) {
|
||||
CPrivMessage& PrivMsg = static_cast<CPrivMessage&>(Message);
|
||||
bool bResult = false;
|
||||
IRCSOCKMODULECALL(OnPrivMsg(Nick, sMessage), &bResult);
|
||||
IRCSOCKMODULECALL(OnPrivMessage(PrivMsg), &bResult);
|
||||
if (bResult) return true;
|
||||
|
||||
if (!m_pNetwork->IsUserOnline() || !m_pNetwork->GetUser()->AutoClearQueryBuffer()) {
|
||||
const CNick& Nick = PrivMsg.GetNick();
|
||||
CQuery* pQuery = m_pNetwork->AddQuery(Nick.GetNick());
|
||||
if (pQuery) {
|
||||
pQuery->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG {target} :{text}", sMessage);
|
||||
pQuery->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG {target} :{text}", PrivMsg.GetText(), &PrivMsg.GetTime(), PrivMsg.GetTags());
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CIRCSock::OnChanCTCP(CNick& Nick, const CString& sChan, CString& sMessage) {
|
||||
CChan* pChan = m_pNetwork->FindChan(sChan);
|
||||
bool CIRCSock::OnChanCTCP(CMessage& Message) {
|
||||
CChanCTCP& ChanCTCP = static_cast<CChanCTCP&>(Message);
|
||||
CChan* pChan = m_pNetwork->FindChan(ChanCTCP.GetParam(0));
|
||||
if (pChan) {
|
||||
bool bResult = false;
|
||||
IRCSOCKMODULECALL(OnChanCTCP(Nick, *pChan, sMessage), &bResult);
|
||||
ChanCTCP.SetChan(pChan);
|
||||
IRCSOCKMODULECALL(OnChanCTCPMessage(ChanCTCP), &bResult);
|
||||
if (bResult) return true;
|
||||
|
||||
// Record a /me
|
||||
if (sMessage.TrimPrefix("ACTION ")) {
|
||||
if (ChanCTCP.GetText().StartsWith("ACTION ")) {
|
||||
bResult = false;
|
||||
IRCSOCKMODULECALL(OnChanAction(Nick, *pChan, sMessage), &bResult);
|
||||
CChanAction& ChanAction = static_cast<CChanAction&>(Message);
|
||||
IRCSOCKMODULECALL(OnChanActionMessage(ChanAction), &bResult);
|
||||
if (bResult) return true;
|
||||
if (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline() || pChan->IsDetached()) {
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sChan) + " :\001ACTION {text}\001", sMessage);
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(Message.GetNick().GetNickMask()) + " PRIVMSG " + _NAMEDFMT(pChan->GetName()) + " :\001ACTION {text}\001", ChanAction.GetText(), &ChanAction.GetTime(), ChanAction.GetTags());
|
||||
}
|
||||
sMessage = "ACTION " + sMessage;
|
||||
}
|
||||
}
|
||||
|
||||
if (OnGeneralCTCP(Nick, sMessage))
|
||||
if (OnGeneralCTCP(Message))
|
||||
return true;
|
||||
|
||||
return (pChan && pChan->IsDetached());
|
||||
}
|
||||
|
||||
bool CIRCSock::OnChanNotice(CNick& Nick, const CString& sChan, CString& sMessage) {
|
||||
CChan* pChan = m_pNetwork->FindChan(sChan);
|
||||
bool CIRCSock::OnChanNotice(CMessage& Message) {
|
||||
CChanNotice& ChanNotice = static_cast<CChanNotice&>(Message);
|
||||
CChan* pChan = m_pNetwork->FindChan(ChanNotice.GetParam(0));
|
||||
if (pChan) {
|
||||
bool bResult = false;
|
||||
IRCSOCKMODULECALL(OnChanNotice(Nick, *pChan, sMessage), &bResult);
|
||||
ChanNotice.SetChan(pChan);
|
||||
IRCSOCKMODULECALL(OnChanNoticeMessage(ChanNotice), &bResult);
|
||||
if (bResult) return true;
|
||||
|
||||
if (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline() || pChan->IsDetached()) {
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " NOTICE " + _NAMEDFMT(sChan) + " :{text}", sMessage);
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(ChanNotice.GetNick().GetNickMask()) + " NOTICE " + _NAMEDFMT(pChan->GetName()) + " :{text}", ChanNotice.GetText(), &ChanNotice.GetTime(), ChanNotice.GetTags());
|
||||
}
|
||||
}
|
||||
|
||||
return ((pChan) && (pChan->IsDetached()));
|
||||
}
|
||||
|
||||
bool CIRCSock::OnChanMsg(CNick& Nick, const CString& sChan, CString& sMessage) {
|
||||
CChan* pChan = m_pNetwork->FindChan(sChan);
|
||||
bool CIRCSock::OnChanMsg(CMessage& Message) {
|
||||
CChanMessage& ChanMsg = static_cast<CChanMessage&>(Message);
|
||||
CChan* pChan = m_pNetwork->FindChan(ChanMsg.GetParam(0));
|
||||
if (pChan) {
|
||||
bool bResult = false;
|
||||
IRCSOCKMODULECALL(OnChanMsg(Nick, *pChan, sMessage), &bResult);
|
||||
ChanMsg.SetChan(pChan);
|
||||
IRCSOCKMODULECALL(OnChanMessage(ChanMsg), &bResult);
|
||||
if (bResult) return true;
|
||||
|
||||
if (!pChan->AutoClearChanBuffer() || !m_pNetwork->IsUserOnline() || pChan->IsDetached()) {
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sChan) + " :{text}", sMessage);
|
||||
pChan->AddBuffer(":" + _NAMEDFMT(ChanMsg.GetNick().GetNickMask()) + " PRIVMSG " + _NAMEDFMT(pChan->GetName()) + " :{text}", ChanMsg.GetText(), &ChanMsg.GetTime(), ChanMsg.GetTags());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2015 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.
|
||||
*/
|
||||
|
||||
#include <znc/Message.h>
|
||||
#include <znc/Utils.h>
|
||||
|
||||
CMessage::CMessage(const CString& sMessage)
|
||||
{
|
||||
Parse(sMessage);
|
||||
InitTime();
|
||||
}
|
||||
|
||||
CMessage::CMessage(const CNick& Nick, const CString& sCommand, const VCString& vsParams, const MCString& mssTags)
|
||||
: m_Nick(Nick), m_sCommand(sCommand), m_vsParams(vsParams), m_mssTags(mssTags)
|
||||
{
|
||||
InitTime();
|
||||
}
|
||||
|
||||
CString CMessage::GetParams(unsigned int uIdx, unsigned int uLen) const
|
||||
{
|
||||
VCString vsParams;
|
||||
if (uLen > m_vsParams.size() - uIdx - 1) {
|
||||
uLen = m_vsParams.size() - uIdx - 1;
|
||||
}
|
||||
for (unsigned int i = uIdx; i <= uIdx + uLen; ++i) {
|
||||
CString sParam = m_vsParams[i];
|
||||
if (sParam.Contains(" ")) {
|
||||
sParam = ":" + sParam;
|
||||
}
|
||||
vsParams.push_back(sParam);
|
||||
}
|
||||
return CString(" ").Join(vsParams.begin(), vsParams.end());
|
||||
}
|
||||
|
||||
CString CMessage::GetParam(unsigned int uIdx) const
|
||||
{
|
||||
if (uIdx >= m_vsParams.size()) {
|
||||
return "";
|
||||
}
|
||||
return m_vsParams[uIdx];
|
||||
}
|
||||
|
||||
void CMessage::SetParam(unsigned int uIdx, const CString& sParam)
|
||||
{
|
||||
if (uIdx >= m_vsParams.size()) {
|
||||
m_vsParams.resize(uIdx + 1);
|
||||
}
|
||||
m_vsParams[uIdx] = sParam;
|
||||
}
|
||||
|
||||
CString CMessage::GetTag(const CString& sKey) const
|
||||
{
|
||||
MCString::const_iterator it = m_mssTags.find(sKey);
|
||||
if (it != m_mssTags.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void CMessage::SetTag(const CString& sKey, const CString& sValue)
|
||||
{
|
||||
m_mssTags[sKey] = sValue;
|
||||
}
|
||||
|
||||
CString CMessage::ToString(unsigned int uFlags) const
|
||||
{
|
||||
CString sMessage;
|
||||
|
||||
// <prefix>
|
||||
if (!(uFlags & ExcludePrefix)) {
|
||||
CString sPrefix = m_Nick.GetHostMask();
|
||||
if (!sPrefix.empty()) {
|
||||
sMessage += ":" + sPrefix;
|
||||
}
|
||||
}
|
||||
|
||||
// <command>
|
||||
if (!m_sCommand.empty()) {
|
||||
if (!sMessage.empty()) {
|
||||
sMessage += " ";
|
||||
}
|
||||
sMessage += m_sCommand;
|
||||
}
|
||||
|
||||
// <params>
|
||||
for (const CString& sParam : m_vsParams) {
|
||||
sMessage += " ";
|
||||
if (sParam.Contains(" ")) {
|
||||
sMessage += ":";
|
||||
}
|
||||
sMessage += sParam;
|
||||
}
|
||||
|
||||
// <tags>
|
||||
if (!(uFlags & ExcludeTags)) {
|
||||
CUtils::SetMessageTags(sMessage, m_mssTags);
|
||||
}
|
||||
|
||||
return sMessage;
|
||||
}
|
||||
|
||||
void CMessage::Parse(CString sMessage)
|
||||
{
|
||||
// <tags>
|
||||
if (sMessage.StartsWith("@")) {
|
||||
m_mssTags = CUtils::GetMessageTags(sMessage);
|
||||
sMessage = sMessage.Token(1, true);
|
||||
}
|
||||
|
||||
// <message> ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
|
||||
// <prefix> ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
|
||||
// <command> ::= <letter> { <letter> } | <number> <number> <number>
|
||||
// <SPACE> ::= ' ' { ' ' }
|
||||
// <params> ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
|
||||
// <middle> ::= <Any *non-empty* sequence of octets not including SPACE
|
||||
// or NUL or CR or LF, the first of which may not be ':'>
|
||||
// <trailing> ::= <Any, possibly *empty*, sequence of octets not including
|
||||
// NUL or CR or LF>
|
||||
|
||||
// <prefix>
|
||||
if (sMessage.TrimLeft(":")) {
|
||||
m_Nick.Parse(sMessage.Token(0));
|
||||
sMessage = sMessage.Token(1, true);
|
||||
}
|
||||
|
||||
// <command>
|
||||
m_sCommand = sMessage.Token(0);
|
||||
sMessage = sMessage.Token(1, true);
|
||||
|
||||
// <params>
|
||||
m_vsParams.clear();
|
||||
while (!sMessage.empty()) {
|
||||
if (sMessage.TrimLeft(":")) {
|
||||
m_vsParams.push_back(sMessage);
|
||||
sMessage.clear();
|
||||
} else {
|
||||
m_vsParams.push_back(sMessage.Token(0));
|
||||
sMessage = sMessage.Token(1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CMessage::InitTime()
|
||||
{
|
||||
auto it = m_mssTags.find("time");
|
||||
if (it != m_mssTags.end()) {
|
||||
m_time = CUtils::ParseServerTime(it->second);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_CLOCK_GETTIME
|
||||
timespec ts;
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
|
||||
m_time.tv_sec = ts.tv_sec;
|
||||
m_time.tv_usec = ts.tv_nsec / 1000;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!gettimeofday(&m_time, nullptr)) {
|
||||
m_time.tv_sec = time(nullptr);
|
||||
m_time.tv_usec = 0;
|
||||
}
|
||||
}
|
||||
@@ -636,11 +636,16 @@ void CModule::OnUnknownModCommand(const CString& sLine) {
|
||||
}
|
||||
|
||||
void CModule::OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans) {}
|
||||
void CModule::OnQuitMessage(CQuitMessage& Message, const vector<CChan*>& vChans) { OnQuit(Message.GetNick(), Message.GetReason(), vChans); }
|
||||
void CModule::OnNick(const CNick& Nick, const CString& sNewNick, const vector<CChan*>& vChans) {}
|
||||
void CModule::OnNickMessage(CNickMessage& Message, const vector<CChan*>& vChans) { OnNick(Message.GetNick(), Message.GetNewNick(), vChans); }
|
||||
void CModule::OnKick(const CNick& Nick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) {}
|
||||
void CModule::OnKickMessage(CKickMessage& Message) { OnKick(Message.GetNick(), Message.GetKickedNick(), *Message.GetChan(), Message.GetReason()); }
|
||||
CModule::EModRet CModule::OnJoining(CChan& Channel) { return CONTINUE; }
|
||||
void CModule::OnJoin(const CNick& Nick, CChan& Channel) {}
|
||||
void CModule::OnJoinMessage(CJoinMessage& Message) { OnJoin(Message.GetNick(), *Message.GetChan()); }
|
||||
void CModule::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) {}
|
||||
void CModule::OnPartMessage(CPartMessage& Message) { OnPart(Message.GetNick(), *Message.GetChan(), Message.GetReason()); }
|
||||
CModule::EModRet CModule::OnInvite(const CNick& Nick, const CString& sChan) { return CONTINUE; }
|
||||
|
||||
CModule::EModRet CModule::OnChanBufferStarting(CChan& Chan, CClient& Client) { return CONTINUE; }
|
||||
@@ -655,6 +660,25 @@ CModule::EModRet CModule::OnPrivBufferPlayLine2(CClient& Client, CString& sLine,
|
||||
return OnPrivBufferPlayLine(Client, sLine);
|
||||
}
|
||||
|
||||
CModule::EModRet CModule::OnChanBufferPlayMessage(CMessage& Message) {
|
||||
CString sOriginal, sModified;
|
||||
sOriginal = sModified = Message.ToString(CMessage::ExcludeTags);
|
||||
EModRet ret = OnChanBufferPlayLine2(*Message.GetChan(), *Message.GetClient(), sModified, Message.GetTime());
|
||||
if (ret == CONTINUE && sOriginal != sModified) {
|
||||
Message.Parse(sModified);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
CModule::EModRet CModule::OnPrivBufferPlayMessage(CMessage& Message) {
|
||||
CString sOriginal, sModified;
|
||||
sOriginal = sModified = Message.ToString(CMessage::ExcludeTags);
|
||||
EModRet ret = OnPrivBufferPlayLine2(*Message.GetClient(), sModified, Message.GetTime());
|
||||
if (ret == CONTINUE && sOriginal != sModified) {
|
||||
Message.Parse(sModified);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CModule::OnClientLogin() {}
|
||||
void CModule::OnClientDisconnect() {}
|
||||
CModule::EModRet CModule::OnUserRaw(CString& sLine) { return CONTINUE; }
|
||||
@@ -671,14 +695,68 @@ 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; }
|
||||
CModule::EModRet CModule::OnPrivCTCPMessage(CPrivCTCP& Message) {
|
||||
CString sText = Message.GetText();
|
||||
EModRet ret = OnPrivCTCP(Message.GetNick(), sText);
|
||||
Message.SetText(sText);
|
||||
return ret;
|
||||
}
|
||||
CModule::EModRet CModule::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
|
||||
CModule::EModRet CModule::OnChanCTCPMessage(CChanCTCP& Message) {
|
||||
CString sText = Message.GetText();
|
||||
EModRet ret = OnChanCTCP(Message.GetNick(), *Message.GetChan(), sText);
|
||||
Message.SetText(sText);
|
||||
return ret;
|
||||
}
|
||||
CModule::EModRet CModule::OnPrivAction(CNick& Nick, CString& sMessage) { return CONTINUE; }
|
||||
CModule::EModRet CModule::OnPrivActionMessage(CPrivAction& Message) {
|
||||
CString sText = Message.GetText();
|
||||
EModRet ret = OnPrivAction(Message.GetNick(), sText);
|
||||
Message.SetText(sText);
|
||||
return ret;
|
||||
}
|
||||
CModule::EModRet CModule::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
|
||||
CModule::EModRet CModule::OnChanActionMessage(CChanAction& Message) {
|
||||
CString sText = Message.GetText();
|
||||
EModRet ret = OnChanAction(Message.GetNick(), *Message.GetChan(), sText);
|
||||
Message.SetText(sText);
|
||||
return ret;
|
||||
}
|
||||
CModule::EModRet CModule::OnPrivMsg(CNick& Nick, CString& sMessage) { return CONTINUE; }
|
||||
CModule::EModRet CModule::OnPrivMessage(CPrivMessage& Message) {
|
||||
CString sText = Message.GetText();
|
||||
EModRet ret = OnPrivMsg(Message.GetNick(), sText);
|
||||
Message.SetText(sText);
|
||||
return ret;
|
||||
}
|
||||
CModule::EModRet CModule::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
|
||||
CModule::EModRet CModule::OnChanMessage(CChanMessage& Message) {
|
||||
CString sText = Message.GetText();
|
||||
EModRet ret = OnChanMsg(Message.GetNick(), *Message.GetChan(), sText);
|
||||
Message.SetText(sText);
|
||||
return ret;
|
||||
}
|
||||
CModule::EModRet CModule::OnPrivNotice(CNick& Nick, CString& sMessage) { return CONTINUE; }
|
||||
CModule::EModRet CModule::OnPrivNoticeMessage(CPrivNotice& Message) {
|
||||
CString sText = Message.GetText();
|
||||
EModRet ret = OnPrivNotice(Message.GetNick(), sText);
|
||||
Message.SetText(sText);
|
||||
return ret;
|
||||
}
|
||||
CModule::EModRet CModule::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
|
||||
CModule::EModRet CModule::OnChanNoticeMessage(CChanNotice& Message) {
|
||||
CString sText = Message.GetText();
|
||||
EModRet ret = OnChanNotice(Message.GetNick(), *Message.GetChan(), sText);
|
||||
Message.SetText(sText);
|
||||
return ret;
|
||||
}
|
||||
CModule::EModRet CModule::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { return CONTINUE; }
|
||||
CModule::EModRet CModule::OnTopicMessage(CTopicMessage& Message) {
|
||||
CString sTopic = Message.GetTopic();
|
||||
EModRet ret = OnTopic(Message.GetNick(), *Message.GetChan(), sTopic);
|
||||
Message.SetTopic(sTopic);
|
||||
return ret;
|
||||
}
|
||||
CModule::EModRet CModule::OnTimerAutoJoin(CChan& Channel) { return CONTINUE; }
|
||||
CModule::EModRet CModule::OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet) { return CONTINUE; }
|
||||
CModule::EModRet CModule::OnDeleteNetwork(CIRCNetwork& Network) { return CONTINUE; }
|
||||
@@ -829,11 +907,16 @@ bool CModules::OnUserTopicRequest(CString& sChannel) { MODHALTCHK(OnUserTopicReq
|
||||
bool CModules::OnUserQuit(CString& sMessage) { MODHALTCHK(OnUserQuit(sMessage)); }
|
||||
|
||||
bool CModules::OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans) { MODUNLOADCHK(OnQuit(Nick, sMessage, vChans)); return false; }
|
||||
bool CModules::OnQuitMessage(CQuitMessage& Message, const vector<CChan*>& vChans) { MODUNLOADCHK(OnQuitMessage(Message, vChans)); return false; }
|
||||
bool CModules::OnNick(const CNick& Nick, const CString& sNewNick, const vector<CChan*>& vChans) { MODUNLOADCHK(OnNick(Nick, sNewNick, vChans)); return false; }
|
||||
bool CModules::OnNickMessage(CNickMessage& Message, const vector<CChan*>& vChans) { MODUNLOADCHK(OnNickMessage(Message, vChans)); return false; }
|
||||
bool CModules::OnKick(const CNick& Nick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) { MODUNLOADCHK(OnKick(Nick, sKickedNick, Channel, sMessage)); return false; }
|
||||
bool CModules::OnKickMessage(CKickMessage& Message) { MODUNLOADCHK(OnKickMessage(Message)); return false; }
|
||||
bool CModules::OnJoining(CChan& Channel) { MODHALTCHK(OnJoining(Channel)); }
|
||||
bool CModules::OnJoin(const CNick& Nick, CChan& Channel) { MODUNLOADCHK(OnJoin(Nick, Channel)); return false; }
|
||||
bool CModules::OnJoinMessage(CJoinMessage& Message) { MODUNLOADCHK(OnJoinMessage(Message)); return false; }
|
||||
bool CModules::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) { MODUNLOADCHK(OnPart(Nick, Channel, sMessage)); return false; }
|
||||
bool CModules::OnPartMessage(CPartMessage& Message) { MODUNLOADCHK(OnPartMessage(Message)); return false; }
|
||||
bool CModules::OnInvite(const CNick& Nick, const CString& sChan) { MODHALTCHK(OnInvite(Nick, sChan)); }
|
||||
bool CModules::OnChanBufferStarting(CChan& Chan, CClient& Client) { MODHALTCHK(OnChanBufferStarting(Chan, Client)); }
|
||||
bool CModules::OnChanBufferEnding(CChan& Chan, CClient& Client) { MODHALTCHK(OnChanBufferEnding(Chan, Client)); }
|
||||
@@ -841,16 +924,27 @@ bool CModules::OnChanBufferPlayLine2(CChan& Chan, CClient& Client, CString& sLin
|
||||
bool CModules::OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) { MODHALTCHK(OnChanBufferPlayLine(Chan, Client, sLine)); }
|
||||
bool CModules::OnPrivBufferPlayLine2(CClient& Client, CString& sLine, const timeval& tv) { MODHALTCHK(OnPrivBufferPlayLine2(Client, sLine, tv)); }
|
||||
bool CModules::OnPrivBufferPlayLine(CClient& Client, CString& sLine) { MODHALTCHK(OnPrivBufferPlayLine(Client, sLine)); }
|
||||
bool CModules::OnChanBufferPlayMessage(CMessage& Message) { MODHALTCHK(OnChanBufferPlayMessage(Message)); }
|
||||
bool CModules::OnPrivBufferPlayMessage(CMessage& Message) { MODHALTCHK(OnPrivBufferPlayMessage(Message)); }
|
||||
bool CModules::OnCTCPReply(CNick& Nick, CString& sMessage) { MODHALTCHK(OnCTCPReply(Nick, sMessage)); }
|
||||
bool CModules::OnPrivCTCP(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivCTCP(Nick, sMessage)); }
|
||||
bool CModules::OnPrivCTCPMessage(CPrivCTCP& Message) { MODHALTCHK(OnPrivCTCPMessage(Message)); }
|
||||
bool CModules::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanCTCP(Nick, Channel, sMessage)); }
|
||||
bool CModules::OnChanCTCPMessage(CChanCTCP& Message) { MODHALTCHK(OnChanCTCPMessage(Message)); }
|
||||
bool CModules::OnPrivAction(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivAction(Nick, sMessage)); }
|
||||
bool CModules::OnPrivActionMessage(CPrivAction& Message) { MODHALTCHK(OnPrivActionMessage(Message)); }
|
||||
bool CModules::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanAction(Nick, Channel, sMessage)); }
|
||||
bool CModules::OnChanActionMessage(CChanAction& Message) { MODHALTCHK(OnChanActionMessage(Message)); }
|
||||
bool CModules::OnPrivMsg(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivMsg(Nick, sMessage)); }
|
||||
bool CModules::OnPrivMessage(CPrivMessage& Message) { MODHALTCHK(OnPrivMessage(Message)); }
|
||||
bool CModules::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanMsg(Nick, Channel, sMessage)); }
|
||||
bool CModules::OnChanMessage(CChanMessage& Message) { MODHALTCHK(OnChanMessage(Message)); }
|
||||
bool CModules::OnPrivNotice(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivNotice(Nick, sMessage)); }
|
||||
bool CModules::OnPrivNoticeMessage(CPrivNotice& Message) { MODHALTCHK(OnPrivNoticeMessage(Message)); }
|
||||
bool CModules::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanNotice(Nick, Channel, sMessage)); }
|
||||
bool CModules::OnChanNoticeMessage(CChanNotice& Message) { MODHALTCHK(OnChanNoticeMessage(Message)); }
|
||||
bool CModules::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { MODHALTCHK(OnTopic(Nick, Channel, sTopic)); }
|
||||
bool CModules::OnTopicMessage(CTopicMessage& Message) { MODHALTCHK(OnTopicMessage(Message)); }
|
||||
bool CModules::OnTimerAutoJoin(CChan& Channel) { MODHALTCHK(OnTimerAutoJoin(Channel)); }
|
||||
bool CModules::OnAddNetwork(CIRCNetwork& Network, CString& sErrorRet) { MODHALTCHK(OnAddNetwork(Network, sErrorRet)); }
|
||||
bool CModules::OnDeleteNetwork(CIRCNetwork& Network) { MODHALTCHK(OnDeleteNetwork(Network)); }
|
||||
|
||||
+10
-10
@@ -17,6 +17,7 @@
|
||||
#include <znc/Query.h>
|
||||
#include <znc/User.h>
|
||||
#include <znc/IRCNetwork.h>
|
||||
#include <znc/Message.h>
|
||||
|
||||
using std::vector;
|
||||
|
||||
@@ -55,24 +56,23 @@ void CQuery::SendBuffer(CClient* pClient, const CBuffer& Buffer) {
|
||||
size_t uSize = Buffer.Size();
|
||||
for (size_t uIdx = 0; uIdx < uSize; uIdx++) {
|
||||
const CBufLine& BufLine = Buffer.GetBufLine(uIdx);
|
||||
|
||||
CMessage Message(BufLine.GetLine(*pUseClient, MCString::EmptyMap));
|
||||
if (!pUseClient->HasEchoMessage() && !pUseClient->HasSelfMessage()) {
|
||||
CNick Sender(BufLine.GetFormat().Token(0));
|
||||
if (Sender.NickEquals(pUseClient->GetNick())) {
|
||||
if (Message.GetNick().NickEquals(pUseClient->GetNick())) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
CString sLine = BufLine.GetLine(*pUseClient, msParams);
|
||||
Message.SetNetwork(m_pNetwork);
|
||||
Message.SetClient(pUseClient);
|
||||
Message.SetTime(BufLine.GetTime());
|
||||
Message.SetTags(BufLine.GetTags());
|
||||
if (bBatch) {
|
||||
MCString msBatchTags = CUtils::GetMessageTags(sLine);
|
||||
msBatchTags["batch"] = sBatchName;
|
||||
CUtils::SetMessageTags(sLine, msBatchTags);
|
||||
Message.SetTag("batch", sBatchName);
|
||||
}
|
||||
bool bContinue = false;
|
||||
NETWORKMODULECALL(OnPrivBufferPlayLine2(*pUseClient, sLine, BufLine.GetTime()), m_pNetwork->GetUser(), m_pNetwork, nullptr, &bContinue);
|
||||
NETWORKMODULECALL(OnPrivBufferPlayMessage(Message), m_pNetwork->GetUser(), m_pNetwork, nullptr, &bContinue);
|
||||
if (bContinue) continue;
|
||||
m_pNetwork->PutUser(sLine, pUseClient);
|
||||
m_pNetwork->PutUser(Message, pUseClient);
|
||||
}
|
||||
|
||||
if (bBatch) {
|
||||
|
||||
@@ -458,6 +458,19 @@ CString CUtils::FormatServerTime(const timeval& tv) {
|
||||
return CString(sTime) + "." + s_msec + "Z";
|
||||
}
|
||||
|
||||
timeval CUtils::ParseServerTime(const CString& sTime) {
|
||||
struct tm stm;
|
||||
memset(&stm, 0, sizeof(stm));
|
||||
const char* cp = strptime(sTime.c_str(), "%Y-%m-%dT%H:%M:%S", &stm);
|
||||
struct timeval tv;
|
||||
tv.tv_sec = mktime(&stm);
|
||||
CString s_usec(cp);
|
||||
if (s_usec.TrimPrefix(".") && s_usec.TrimSuffix("Z")) {
|
||||
tv.tv_usec = s_usec.ToULong() * 1000;
|
||||
}
|
||||
return tv;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void FillTimezones(const CString& sPath, SCString& result, const CString& sPrefix) {
|
||||
CDir Dir;
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2015 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.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <znc/ZNCString.h>
|
||||
#include <znc/Message.h>
|
||||
|
||||
TEST(MessageTest, SetParam) {
|
||||
CMessage msg;
|
||||
|
||||
msg.SetParam(1, "bar");
|
||||
msg.SetParam(0, "foo");
|
||||
|
||||
VCString params = {"foo", "bar"};
|
||||
EXPECT_EQ(params, msg.GetParams());
|
||||
|
||||
msg.SetParam(3, "baz");
|
||||
|
||||
params = {"foo", "bar", "", "baz"};
|
||||
EXPECT_EQ(params, msg.GetParams());
|
||||
}
|
||||
|
||||
TEST(MessageTest, ToString) {
|
||||
EXPECT_EQ("CMD", CMessage("CMD").ToString());
|
||||
EXPECT_EQ("CMD p1", CMessage("CMD p1").ToString());
|
||||
EXPECT_EQ("CMD p1 p2", CMessage("CMD p1 p2").ToString());
|
||||
EXPECT_EQ("CMD :p p p", CMessage("CMD :p p p").ToString());
|
||||
EXPECT_EQ(":irc.znc.in", CMessage(":irc.znc.in").ToString());
|
||||
EXPECT_EQ(":irc.znc.in CMD", CMessage(":irc.znc.in CMD").ToString());
|
||||
EXPECT_EQ(":irc.znc.in CMD p1", CMessage(":irc.znc.in CMD p1").ToString());
|
||||
EXPECT_EQ(":irc.znc.in CMD p1 p2", CMessage(":irc.znc.in CMD p1 p2").ToString());
|
||||
EXPECT_EQ(":irc.znc.in CMD :p p p", CMessage(":irc.znc.in CMD :p p p").ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, FormatFlags) {
|
||||
const CString line = "@foo=bar :irc.example.com COMMAND param";
|
||||
|
||||
CMessage msg(line);
|
||||
EXPECT_EQ(line, msg.ToString());
|
||||
EXPECT_EQ(":irc.example.com COMMAND param", msg.ToString(CMessage::ExcludeTags));
|
||||
EXPECT_EQ("@foo=bar COMMAND param", msg.ToString(CMessage::ExcludePrefix));
|
||||
EXPECT_EQ("COMMAND param", msg.ToString(CMessage::ExcludePrefix|CMessage::ExcludeTags));
|
||||
}
|
||||
|
||||
TEST(MessageTest, ChanAction) {
|
||||
CMessage msg(":sender PRIVMSG #chan :\001ACTION text\001");
|
||||
CChanAction& chan = static_cast<CChanAction&>(msg);
|
||||
EXPECT_EQ("sender", chan.GetNick().GetNick());
|
||||
EXPECT_EQ("PRIVMSG", chan.GetCommand());
|
||||
EXPECT_EQ("text", chan.GetText());
|
||||
|
||||
chan.SetText("foo bar");
|
||||
EXPECT_EQ("foo bar", chan.GetText());
|
||||
EXPECT_EQ(":sender PRIVMSG #chan :\001ACTION foo bar\001", chan.ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, ChanCTCP) {
|
||||
CMessage msg(":sender PRIVMSG #chan :\001text\001");
|
||||
CChanCTCP& chan = static_cast<CChanCTCP&>(msg);
|
||||
EXPECT_EQ("sender", chan.GetNick().GetNick());
|
||||
EXPECT_EQ("PRIVMSG", chan.GetCommand());
|
||||
EXPECT_EQ("text", chan.GetText());
|
||||
|
||||
chan.SetText("foo bar");
|
||||
EXPECT_EQ("foo bar", chan.GetText());
|
||||
EXPECT_EQ(":sender PRIVMSG #chan :\001foo bar\001", chan.ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, ChanMsg) {
|
||||
CMessage msg(":sender PRIVMSG #chan :text");
|
||||
CChanMessage& priv = static_cast<CChanMessage&>(msg);
|
||||
EXPECT_EQ("sender", priv.GetNick().GetNick());
|
||||
EXPECT_EQ("PRIVMSG", priv.GetCommand());
|
||||
EXPECT_EQ("text", priv.GetText());
|
||||
|
||||
priv.SetText("foo bar");
|
||||
EXPECT_EQ("foo bar", priv.GetText());
|
||||
EXPECT_EQ(":sender PRIVMSG #chan :foo bar", priv.ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, Kick) {
|
||||
CMessage msg(":nick KICK #chan person :reason");
|
||||
CKickMessage& kick = static_cast<CKickMessage&>(msg);
|
||||
EXPECT_EQ("nick", kick.GetNick().GetNick());
|
||||
EXPECT_EQ("KICK", kick.GetCommand());
|
||||
EXPECT_EQ("person", kick.GetKickedNick());
|
||||
EXPECT_EQ("reason", kick.GetReason());
|
||||
|
||||
kick.SetKickedNick("noone");
|
||||
EXPECT_EQ("noone", kick.GetKickedNick());
|
||||
kick.SetReason("test");
|
||||
EXPECT_EQ("test", kick.GetReason());
|
||||
EXPECT_EQ(":nick KICK #chan noone test", kick.ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, Join) {
|
||||
CMessage msg(":nick JOIN #chan");
|
||||
EXPECT_EQ("nick", msg.GetNick().GetNick());
|
||||
EXPECT_EQ("JOIN", msg.GetCommand());
|
||||
EXPECT_EQ("#chan", msg.GetParam(0));
|
||||
}
|
||||
|
||||
TEST(MessageTest, Nick) {
|
||||
CMessage msg(":nick NICK person");
|
||||
CNickMessage& nick = static_cast<CNickMessage&>(msg);
|
||||
EXPECT_EQ("nick", nick.GetNick().GetNick());
|
||||
EXPECT_EQ("NICK", nick.GetCommand());
|
||||
EXPECT_EQ("nick", nick.GetOldNick());
|
||||
EXPECT_EQ("person", nick.GetNewNick());
|
||||
|
||||
nick.SetNewNick("test");
|
||||
EXPECT_EQ("test", nick.GetNewNick());
|
||||
EXPECT_EQ(":nick NICK test", nick.ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, Part) {
|
||||
CMessage msg(":nick PART #chan :reason");
|
||||
CPartMessage& part = static_cast<CPartMessage&>(msg);
|
||||
EXPECT_EQ("nick", part.GetNick().GetNick());
|
||||
EXPECT_EQ("PART", part.GetCommand());
|
||||
EXPECT_EQ("reason", part.GetReason());
|
||||
|
||||
part.SetReason("test");
|
||||
EXPECT_EQ("test", part.GetReason());
|
||||
EXPECT_EQ(":nick PART #chan test", part.ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, PrivAction) {
|
||||
CMessage msg(":sender PRIVMSG receiver :\001ACTION text\001");
|
||||
CPrivAction& priv = static_cast<CPrivAction&>(msg);
|
||||
EXPECT_EQ("sender", priv.GetNick().GetNick());
|
||||
EXPECT_EQ("PRIVMSG", priv.GetCommand());
|
||||
EXPECT_EQ("text", priv.GetText());
|
||||
|
||||
priv.SetText("foo bar");
|
||||
EXPECT_EQ("foo bar", priv.GetText());
|
||||
EXPECT_EQ(":sender PRIVMSG receiver :\001ACTION foo bar\001", priv.ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, PrivCTCP) {
|
||||
CMessage msg(":sender PRIVMSG receiver :\001text\001");
|
||||
CPrivCTCP& priv = static_cast<CPrivCTCP&>(msg);
|
||||
EXPECT_EQ("sender", priv.GetNick().GetNick());
|
||||
EXPECT_EQ("PRIVMSG", priv.GetCommand());
|
||||
EXPECT_EQ("text", priv.GetText());
|
||||
|
||||
priv.SetText("foo bar");
|
||||
EXPECT_EQ("foo bar", priv.GetText());
|
||||
EXPECT_EQ(":sender PRIVMSG receiver :\001foo bar\001", priv.ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, PrivMsg) {
|
||||
CMessage msg(":sender PRIVMSG receiver :text");
|
||||
CPrivMessage& priv = static_cast<CPrivMessage&>(msg);
|
||||
EXPECT_EQ("sender", priv.GetNick().GetNick());
|
||||
EXPECT_EQ("PRIVMSG", priv.GetCommand());
|
||||
EXPECT_EQ("text", priv.GetText());
|
||||
|
||||
priv.SetText("foo bar");
|
||||
EXPECT_EQ("foo bar", priv.GetText());
|
||||
EXPECT_EQ(":sender PRIVMSG receiver :foo bar", priv.ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, Quit) {
|
||||
CMessage msg(":nick QUIT :reason");
|
||||
CQuitMessage& quit = static_cast<CQuitMessage&>(msg);
|
||||
EXPECT_EQ("nick", quit.GetNick().GetNick());
|
||||
EXPECT_EQ("QUIT", quit.GetCommand());
|
||||
EXPECT_EQ("reason", quit.GetReason());
|
||||
|
||||
quit.SetReason("test");
|
||||
EXPECT_EQ("test", quit.GetReason());
|
||||
EXPECT_EQ(":nick QUIT test", quit.ToString());
|
||||
}
|
||||
|
||||
TEST(MessageTest, Topic) {
|
||||
CMessage msg(":nick TOPIC #chan :topic");
|
||||
CTopicMessage& topic = static_cast<CTopicMessage&>(msg);
|
||||
EXPECT_EQ("nick", topic.GetNick().GetNick());
|
||||
EXPECT_EQ("TOPIC", topic.GetCommand());
|
||||
EXPECT_EQ("topic", topic.GetTopic());
|
||||
|
||||
topic.SetTopic("test");
|
||||
EXPECT_EQ("test", topic.GetTopic());
|
||||
EXPECT_EQ(":nick TOPIC #chan test", topic.ToString());
|
||||
}
|
||||
|
||||
// The test data for MessageTest.Parse originates from https://github.com/SaberUK/ircparser
|
||||
//
|
||||
// IRCParser - Internet Relay Chat Message Parser
|
||||
//
|
||||
// Copyright (C) 2015 Peter "SaberUK" Powell <petpow@saberuk.com>
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any purpose with or without
|
||||
// fee is hereby granted, provided that the above copyright notice and this permission notice appear
|
||||
// in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
// SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
// OF THIS SOFTWARE.
|
||||
|
||||
// when checking a valid message with tags and a source
|
||||
TEST(MessageTest, ParseWithTags) {
|
||||
const CString line = "@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 :irc.example.com COMMAND param1 param2 :param3 param3";
|
||||
|
||||
MCString tags;
|
||||
tags["tag1"] = "value1";
|
||||
tags["tag2"] = "";
|
||||
tags["vendor1/tag3"] = "value2";
|
||||
tags["vendor2/tag4"] = "";
|
||||
|
||||
VCString params = {"param1", "param2", "param3 param3"};
|
||||
|
||||
CMessage msg(line);
|
||||
EXPECT_EQ(line, msg.ToString());
|
||||
EXPECT_EQ(tags, msg.GetTags());
|
||||
EXPECT_EQ("irc.example.com", msg.GetNick().GetNick());
|
||||
EXPECT_EQ("COMMAND", msg.GetCommand());
|
||||
EXPECT_EQ(params, msg.GetParams());
|
||||
}
|
||||
|
||||
// when checking a valid message with a source but no tags
|
||||
TEST(MessageTest, ParseWithoutTags) {
|
||||
const CString line = ":irc.example.com COMMAND param1 param2 :param3 param3";
|
||||
|
||||
VCString params = {"param1", "param2", "param3 param3"};
|
||||
|
||||
CMessage msg(line);
|
||||
EXPECT_EQ(line, msg.ToString());
|
||||
EXPECT_EQ(MCString(), msg.GetTags());
|
||||
EXPECT_EQ("irc.example.com", msg.GetNick().GetNick());
|
||||
EXPECT_EQ("COMMAND", msg.GetCommand());
|
||||
EXPECT_EQ(params, msg.GetParams());
|
||||
}
|
||||
|
||||
// when checking a valid message with tags but no source
|
||||
TEST(MessageTest, ParseWithoutSource) {
|
||||
const CString line = "@tag1=value1;tag2;vendor1/tag3=value2;vendor2/tag4 COMMAND param1 param2 :param3 param3";
|
||||
|
||||
MCString tags;
|
||||
tags["tag1"] = "value1";
|
||||
tags["tag2"] = "";
|
||||
tags["vendor1/tag3"] = "value2";
|
||||
tags["vendor2/tag4"] = "";
|
||||
|
||||
VCString params = {"param1", "param2", "param3 param3"};
|
||||
|
||||
CMessage msg(line);
|
||||
EXPECT_EQ(line, msg.ToString());
|
||||
EXPECT_EQ(tags, msg.GetTags());
|
||||
EXPECT_EQ("", msg.GetNick().GetNick());
|
||||
EXPECT_EQ("COMMAND", msg.GetCommand());
|
||||
EXPECT_EQ(params, msg.GetParams());
|
||||
}
|
||||
|
||||
// when checking a valid message with no tags, source or parameters
|
||||
TEST(MessageTest, ParseWithoutSourceAndTags) {
|
||||
const CString line = "COMMAND";
|
||||
|
||||
CMessage msg(line);
|
||||
EXPECT_EQ(line, msg.ToString());
|
||||
EXPECT_EQ(MCString(), msg.GetTags());
|
||||
EXPECT_EQ("", msg.GetNick().GetNick());
|
||||
EXPECT_EQ("COMMAND", msg.GetCommand());
|
||||
EXPECT_EQ(VCString(), msg.GetParams());
|
||||
}
|
||||
@@ -75,3 +75,32 @@ TEST(IRC32, SetMessageTags) {
|
||||
EXPECT_EQ(R"(@a=\:\s\\\r\n :rest)", sLine);
|
||||
}
|
||||
|
||||
TEST(UtilsTest, ServerTime) {
|
||||
char* oldTZ = getenv("TZ");
|
||||
if (oldTZ) oldTZ = strdup(oldTZ);
|
||||
setenv("TZ", "UTC", 1);
|
||||
tzset();
|
||||
|
||||
timeval tv1 = CUtils::ParseServerTime("2011-10-19T16:40:51.620Z");
|
||||
CString str1 = CUtils::FormatServerTime(tv1);
|
||||
EXPECT_EQ("2011-10-19T16:40:51.620Z", str1);
|
||||
|
||||
timeval now;
|
||||
if (!gettimeofday(&now, nullptr)) {
|
||||
now.tv_sec = time(nullptr);
|
||||
now.tv_usec = 0;
|
||||
}
|
||||
|
||||
CString str2 = CUtils::FormatServerTime(now);
|
||||
timeval tv2 = CUtils::ParseServerTime(str2);
|
||||
EXPECT_EQ(now.tv_sec, tv2.tv_sec);
|
||||
EXPECT_EQ(now.tv_usec, tv2.tv_usec);
|
||||
|
||||
if (oldTZ) {
|
||||
setenv("TZ", oldTZ, 1);
|
||||
free(oldTZ);
|
||||
} else {
|
||||
unsetenv("TZ");
|
||||
}
|
||||
tzset();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user