diff --git a/include/znc/Buffer.h b/include/znc/Buffer.h index 3a2fa150..8a1503b5 100644 --- a/include/znc/Buffer.h +++ b/include/znc/Buffer.h @@ -15,17 +15,34 @@ using std::deque; +// Forward Declarations +class CClient; +// !Forward Declarations + class CBufLine { public: - CBufLine(const CString& sFormat); + CBufLine(const CString& sFormat, const CString& sText = "", time_t tm = 0); ~CBufLine(); - const CString& GetFormat() const { return m_sFormat; } + CString GetLine(const CClient& Client, const MCString& msParams) const; + void UpdateTime() { time(&m_tm); } + + // Setters void SetFormat(const CString& sFormat) { m_sFormat = sFormat; } - CString GetLine(const MCString& msParams) const; + void SetText(const CString& sText) { m_sText = sText; } + void SetTime(time_t tm) { m_tm = tm; } + // !Setters + + // Getters + const CString& GetFormat() const { return m_sFormat; } + const CString& GetText() const { return m_sText; } + time_t GetTime() const { return m_tm; } + // !Getters private: protected: CString m_sFormat; + CString m_sText; + time_t m_tm; }; class CBuffer : private deque { @@ -33,13 +50,13 @@ public: CBuffer(unsigned int uLineCount = 100); ~CBuffer(); - int AddLine(const CString& sFormat); - /// Same as AddLine, but replaces a line that starts with sMatch if there is one. - int UpdateLine(const CString& sMatch, const CString& sFormat); + int AddLine(const CString& sFormat, const CString& sText = "", time_t tm = 0); + /// Same as AddLine, but replaces a line whose format string starts with sMatch if there is one. + int UpdateLine(const CString& sMatch, const CString& sFormat, const CString& sText = ""); /// Same as UpdateLine, but does nothing if this exact line already exists. - int UpdateExactLine(const CString& sFormat); + int UpdateExactLine(const CString& sFormat, const CString& sText = ""); const CBufLine& GetBufLine(unsigned int uIdx) const; - CString GetLine(unsigned int uIdx, const MCString& msParams = MCString::EmptyMap) const; + CString GetLine(unsigned int uIdx, const CClient& Client, const MCString& msParams = MCString::EmptyMap) const; unsigned int Size() const { return size(); } bool IsEmpty() const { return empty(); } void Clear() { clear(); } diff --git a/include/znc/Chan.h b/include/znc/Chan.h index 9ba0f17b..d4127eeb 100644 --- a/include/znc/Chan.h +++ b/include/znc/Chan.h @@ -91,7 +91,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); }; - int AddBuffer(const CString& sFormat) { return m_Buffer.AddLine(sFormat); } + int AddBuffer(const CString& sFormat, const CString& sText = "") { return m_Buffer.AddLine(sFormat, sText); } void ClearBuffer() { m_Buffer.Clear(); } void SendBuffer(CClient* pClient); // !Buffer diff --git a/include/znc/Client.h b/include/znc/Client.h index ca164b21..424b5ab2 100644 --- a/include/znc/Client.h +++ b/include/znc/Client.h @@ -104,6 +104,7 @@ public: bool HasNamesx() const { return m_bNamesx; } bool HasUHNames() const { return m_bUHNames; } bool IsAway() const { return m_bAway; } + bool HasServerTime() const { return m_bServerTime; } void UserCommand(CString& sLine); void UserPortCommand(CString& sLine); diff --git a/include/znc/IRCNetwork.h b/include/znc/IRCNetwork.h index 7f35c439..8e1f8a57 100644 --- a/include/znc/IRCNetwork.h +++ b/include/znc/IRCNetwork.h @@ -107,17 +107,17 @@ public: bool PutIRC(const CString& sLine); // Buffers - void AddRawBuffer(const CString& sFormat) { m_RawBuffer.AddLine(sFormat); } - void UpdateRawBuffer(const CString& sMatch, const CString& sFormat) { m_RawBuffer.UpdateLine(sMatch, sFormat); } - void UpdateExactRawBuffer(const CString& sFormat) { m_RawBuffer.UpdateExactLine(sFormat); } + void AddRawBuffer(const CString& sFormat, const CString& sText = "") { m_RawBuffer.AddLine(sFormat, sText); } + void UpdateRawBuffer(const CString& sMatch, const CString& sFormat, const CString& sText = "") { m_RawBuffer.UpdateLine(sMatch, sFormat, sText); } + void UpdateExactRawBuffer(const CString& sFormat, const CString& sText = "") { m_RawBuffer.UpdateExactLine(sFormat, sText); } void ClearRawBuffer() { m_RawBuffer.Clear(); } - void AddMotdBuffer(const CString& sFormat) { m_MotdBuffer.AddLine(sFormat); } - void UpdateMotdBuffer(const CString& sMatch, const CString& sFormat) { m_MotdBuffer.UpdateLine(sMatch, sFormat); } + void AddMotdBuffer(const CString& sFormat, const CString& sText = "") { m_MotdBuffer.AddLine(sFormat, sText); } + void UpdateMotdBuffer(const CString& sMatch, const CString& sFormat, const CString& sText = "") { m_MotdBuffer.UpdateLine(sMatch, sFormat, sText); } void ClearMotdBuffer() { m_MotdBuffer.Clear(); } - void AddQueryBuffer(const CString& sFormat) { m_QueryBuffer.AddLine(sFormat); } - void UpdateQueryBuffer(const CString& sMatch, const CString& sFormat) { m_QueryBuffer.UpdateLine(sMatch, sFormat); } + void AddQueryBuffer(const CString& sFormat, const CString& sText = "") { m_QueryBuffer.AddLine(sFormat, sText); } + void UpdateQueryBuffer(const CString& sMatch, const CString& sFormat, const CString& sText = "") { m_QueryBuffer.UpdateLine(sMatch, sFormat, sText); } void ClearQueryBuffer() { m_QueryBuffer.Clear(); } // !Buffers diff --git a/include/znc/User.h b/include/znc/User.h index df12adec..6a8ff6e7 100644 --- a/include/znc/User.h +++ b/include/znc/User.h @@ -89,7 +89,7 @@ public: CString& ExpandString(const CString& sStr, CString& sRet) const; CString AddTimestamp(const CString& sStr) const; - CString& AddTimestamp(const CString& sStr, CString& sRet) const; + CString AddTimestamp(time_t tm, const CString& sStr) const; bool Clone(const CUser& User, CString& sErrorRet, bool bCloneChans = true); void BounceAllClients(); diff --git a/modules/buffextras.cpp b/modules/buffextras.cpp index 171dc4f5..d23d01ed 100644 --- a/modules/buffextras.cpp +++ b/modules/buffextras.cpp @@ -22,7 +22,7 @@ public: if (!Channel.KeepBuffer() && m_pNetwork->IsUserOnline()) return; - Channel.AddBuffer(":" + GetModNick() + "!" + GetModName() + "@znc.in PRIVMSG " + _NAMEDFMT(Channel.GetName()) + " :" + _NAMEDFMT(m_pUser->AddTimestamp(sMessage))); + Channel.AddBuffer(":" + GetModNick() + "!" + GetModName() + "@znc.in PRIVMSG " + _NAMEDFMT(Channel.GetName()) + " :{text}", sMessage); } virtual void OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) { diff --git a/modules/savebuff.cpp b/modules/savebuff.cpp index 0d35b824..106501b4 100644 --- a/modules/savebuff.cpp +++ b/modules/savebuff.cpp @@ -116,6 +116,7 @@ public: for (it = vsLines.begin(); it != vsLines.end(); ++it) { CString sLine(*it); sLine.Trim(); + // FIXME: Deserialize other CBufLine attributes. pChan->AddBuffer(sLine); } } else @@ -151,6 +152,7 @@ public: unsigned int uSize = Buffer.Size(); for (unsigned int uIdx = 0; uIdx < uSize; uIdx++) { const CBufLine& Line = Buffer.GetBufLine(uIdx); + // FIXME: Serialize other CBufLine attributes. sFile += Line.GetFormat() + "\n"; } diff --git a/modules/watch.cpp b/modules/watch.cpp index bf7d9be5..37069c14 100644 --- a/modules/watch.cpp +++ b/modules/watch.cpp @@ -172,7 +172,7 @@ public: unsigned int uSize = m_Buffer.Size(); for (unsigned int uIdx = 0; uIdx < uSize; uIdx++) { - PutUser(m_Buffer.GetLine(uIdx, msParams)); + PutUser(m_Buffer.GetLine(uIdx, *GetClient(), msParams)); } m_Buffer.Clear(); } @@ -293,7 +293,7 @@ private: if (m_pNetwork->IsUserAttached()) { m_pNetwork->PutUser(":" + WatchEntry.GetTarget() + "!watch@znc.in PRIVMSG " + m_pNetwork->GetCurNick() + " :" + sMessage); } else { - m_Buffer.AddLine(":" + _NAMEDFMT(WatchEntry.GetTarget()) + "!watch@znc.in PRIVMSG {target} :" + _NAMEDFMT(m_pUser->AddTimestamp(sMessage))); + m_Buffer.AddLine(":" + _NAMEDFMT(WatchEntry.GetTarget()) + "!watch@znc.in PRIVMSG {target} :{text}", sMessage); } } } diff --git a/src/Buffer.cpp b/src/Buffer.cpp index f205383b..972ee473 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -8,15 +8,31 @@ #include #include +#include +#include -CBufLine::CBufLine(const CString& sFormat) { +CBufLine::CBufLine(const CString& sFormat, const CString& sText, time_t tm) { m_sFormat = sFormat; + m_sText = sText; + if (tm == 0) + UpdateTime(); + else + m_tm = tm; } CBufLine::~CBufLine() {} -CString CBufLine::GetLine(const MCString& msParams) const { - return CString::NamedFormat(m_sFormat, msParams); +CString CBufLine::GetLine(const CClient& Client, const MCString& msParams) const { + MCString msThisParams = msParams; + + if (Client.HasServerTime()) { + msThisParams["text"] = m_sText; + CString sStr = CString::NamedFormat(m_sFormat, msThisParams); + return "@" + CString(m_tm) + " " + sStr; + } else { + msThisParams["text"] = Client.GetUser()->AddTimestamp(m_tm, m_sText); + return CString::NamedFormat(m_sFormat, msThisParams); + } } CBuffer::CBuffer(unsigned int uLineCount) { @@ -25,7 +41,7 @@ CBuffer::CBuffer(unsigned int uLineCount) { CBuffer::~CBuffer() {} -int CBuffer::AddLine(const CString& sFormat) { +int CBuffer::AddLine(const CString& sFormat, const CString& sText, time_t tm) { if (!m_uLineCount) { return 0; } @@ -34,37 +50,39 @@ int CBuffer::AddLine(const CString& sFormat) { erase(begin()); } - push_back(CBufLine(sFormat)); + push_back(CBufLine(sFormat, sText, tm)); return size(); } -int CBuffer::UpdateLine(const CString& sMatch, const CString& sFormat) { +int CBuffer::UpdateLine(const CString& sMatch, const CString& sFormat, const CString& sText) { for (iterator it = begin(); it != end(); ++it) { if (it->GetFormat().compare(0, sMatch.length(), sMatch) == 0) { it->SetFormat(sFormat); + it->SetText(sText); + it->UpdateTime(); return size(); } } - return AddLine(sFormat); + return AddLine(sFormat, sText); } -int CBuffer::UpdateExactLine(const CString& sFormat) { +int CBuffer::UpdateExactLine(const CString& sFormat, const CString& sText) { for (iterator it = begin(); it != end(); ++it) { - if (it->GetFormat() == sFormat) { + if (it->GetFormat() == sFormat && it->GetText() == sText) { return size(); } } - return AddLine(sFormat); + return AddLine(sFormat, sText); } const CBufLine& CBuffer::GetBufLine(unsigned int uIdx) const { return (*this)[uIdx]; } -CString CBuffer::GetLine(unsigned int uIdx, const MCString& msParams) const { - return (*this)[uIdx].GetLine(msParams); +CString CBuffer::GetLine(unsigned int uIdx, const CClient& Client, const MCString& msParams) const { + return (*this)[uIdx].GetLine(Client, msParams); } bool CBuffer::SetLineCount(unsigned int u, bool bForce) { diff --git a/src/Chan.cpp b/src/Chan.cpp index 96494052..edd2cd1d 100644 --- a/src/Chan.cpp +++ b/src/Chan.cpp @@ -538,7 +538,7 @@ void CChan::SendBuffer(CClient* pClient) { unsigned int uSize = m_Buffer.Size(); for (unsigned int uIdx = 0; uIdx < uSize; uIdx++) { - CString sLine = m_Buffer.GetLine(uIdx); + CString sLine = m_Buffer.GetLine(uIdx, *pClient); NETWORKMODULECALL(OnChanBufferPlayLine(*this, *pUseClient, sLine), m_pNetwork->GetUser(), m_pNetwork, NULL, continue); m_pNetwork->PutUser(sLine, pUseClient); } diff --git a/src/Client.cpp b/src/Client.cpp index 0401e40f..a76559dc 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -239,7 +239,7 @@ void CClient::ReadLine(const CString& sData) { CChan* pChan = m_pNetwork->FindChan(sTarget); if ((pChan) && (pChan->KeepBuffer())) { - pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " NOTICE " + _NAMEDFMT(sTarget) + " :" + _NAMEDFMT(m_pUser->AddTimestamp(sMsg))); + pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " NOTICE " + _NAMEDFMT(sTarget) + " :{text}", sMsg); } // Relay to the rest of the clients that may be connected to this user @@ -285,7 +285,7 @@ void CClient::ReadLine(const CString& sData) { sCTCP = "ACTION " + sMessage; if (pChan && pChan->KeepBuffer()) { - pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :\001ACTION " + _NAMEDFMT(m_pUser->AddTimestamp(sMessage)) + "\001"); + pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :\001ACTION {text}\001", sMessage); } // Relay to the rest of the clients that may be connected to this user @@ -333,7 +333,7 @@ void CClient::ReadLine(const CString& sData) { CChan* pChan = m_pNetwork->FindChan(sTarget); if ((pChan) && (pChan->KeepBuffer())) { - pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :" + _NAMEDFMT(m_pUser->AddTimestamp(sMsg))); + pChan->AddBuffer(":" + _NAMEDFMT(GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sTarget) + " :{text}", sMsg); } PutIRC("PRIVMSG " + sTarget + " :" + sMsg); diff --git a/src/IRCNetwork.cpp b/src/IRCNetwork.cpp index c5ade057..3eb446f1 100644 --- a/src/IRCNetwork.cpp +++ b/src/IRCNetwork.cpp @@ -353,7 +353,7 @@ void CIRCNetwork::ClientConnected(CClient *pClient) { } else { uSize = m_RawBuffer.Size(); for (uIdx = 0; uIdx < uSize; uIdx++) { - pClient->PutClient(m_RawBuffer.GetLine(uIdx, msParams)); + pClient->PutClient(m_RawBuffer.GetLine(uIdx, *pClient, msParams)); } // The assumption is that the client got this nick from the 001 reply @@ -363,7 +363,7 @@ void CIRCNetwork::ClientConnected(CClient *pClient) { // Send the cached MOTD uSize = m_MotdBuffer.Size(); for (uIdx = 0; uIdx < uSize; uIdx++) { - pClient->PutClient(m_MotdBuffer.GetLine(uIdx, msParams)); + pClient->PutClient(m_MotdBuffer.GetLine(uIdx, *pClient, msParams)); } if (GetIRCSock() != NULL) { @@ -393,7 +393,7 @@ void CIRCNetwork::ClientConnected(CClient *pClient) { uSize = m_QueryBuffer.Size(); for (uIdx = 0; uIdx < uSize; uIdx++) { - CString sLine = m_QueryBuffer.GetLine(uIdx, msParams); + CString sLine = m_QueryBuffer.GetLine(uIdx, *pClient, msParams); NETWORKMODULECALL(OnPrivBufferPlayLine(*pClient, sLine), m_pUser, this, NULL, continue); pClient->PutClient(sLine); } diff --git a/src/IRCSock.cpp b/src/IRCSock.cpp index ca2c0b42..93cdbacd 100644 --- a/src/IRCSock.cpp +++ b/src/IRCSock.cpp @@ -665,7 +665,7 @@ void CIRCSock::ReadLine(const CString& sData) { CString sMsg = sRest.Token(0, true).TrimPrefix_n(); if (!m_pNetwork->IsUserOnline()) { - m_pNetwork->AddQueryBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " WALLOPS :" + _NAMEDFMT(m_pNetwork->GetUser()->AddTimestamp(sMsg))); + m_pNetwork->AddQueryBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " WALLOPS :{text}", sMsg); } } else if (sCmd.Equals("CAP")) { // CAPs are supported only before authorization. @@ -772,7 +772,7 @@ bool CIRCSock::OnPrivCTCP(CNick& Nick, CString& sMessage) { if (!m_pNetwork->IsUserOnline()) { // If the user is detached, add to the buffer - m_pNetwork->AddQueryBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG {target} :\001ACTION " + _NAMEDFMT(m_pNetwork->GetUser()->AddTimestamp(sMessage)) + "\001"); + m_pNetwork->AddQueryBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG {target} :\001ACTION {text}\001", sMessage); } sMessage = "ACTION " + sMessage; @@ -827,7 +827,7 @@ bool CIRCSock::OnPrivNotice(CNick& Nick, CString& sMessage) { if (!m_pNetwork->IsUserOnline()) { // If the user is detached, add to the buffer - m_pNetwork->AddQueryBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " NOTICE {target} :" + _NAMEDFMT(m_pNetwork->GetUser()->AddTimestamp(sMessage))); + m_pNetwork->AddQueryBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " NOTICE {target} :{text}", sMessage); } return false; @@ -838,7 +838,7 @@ bool CIRCSock::OnPrivMsg(CNick& Nick, CString& sMessage) { if (!m_pNetwork->IsUserOnline()) { // If the user is detached, add to the buffer - m_pNetwork->AddQueryBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG {target} :" + _NAMEDFMT(m_pNetwork->GetUser()->AddTimestamp(sMessage))); + m_pNetwork->AddQueryBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG {target} :{text}", sMessage); } return false; @@ -853,7 +853,7 @@ bool CIRCSock::OnChanCTCP(CNick& Nick, const CString& sChan, CString& sMessage) if (sMessage.TrimPrefix("ACTION ")) { IRCSOCKMODULECALL(OnChanAction(Nick, *pChan, sMessage), return true); if (pChan->KeepBuffer() || !m_pNetwork->IsUserOnline() || pChan->IsDetached()) { - pChan->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sChan) + " :\001ACTION " + _NAMEDFMT(m_pNetwork->GetUser()->AddTimestamp(sMessage)) + "\001"); + pChan->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sChan) + " :\001ACTION {text}\001", sMessage); } sMessage = "ACTION " + sMessage; } @@ -871,7 +871,7 @@ bool CIRCSock::OnChanNotice(CNick& Nick, const CString& sChan, CString& sMessage IRCSOCKMODULECALL(OnChanNotice(Nick, *pChan, sMessage), return true); if (pChan->KeepBuffer() || !m_pNetwork->IsUserOnline() || pChan->IsDetached()) { - pChan->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " NOTICE " + _NAMEDFMT(sChan) + " :" + _NAMEDFMT(m_pNetwork->GetUser()->AddTimestamp(sMessage))); + pChan->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " NOTICE " + _NAMEDFMT(sChan) + " :{text}", sMessage); } } @@ -884,7 +884,7 @@ bool CIRCSock::OnChanMsg(CNick& Nick, const CString& sChan, CString& sMessage) { IRCSOCKMODULECALL(OnChanMsg(Nick, *pChan, sMessage), return true); if (pChan->KeepBuffer() || !m_pNetwork->IsUserOnline() || pChan->IsDetached()) { - pChan->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sChan) + " :" + _NAMEDFMT(m_pNetwork->GetUser()->AddTimestamp(sMessage))); + pChan->AddBuffer(":" + _NAMEDFMT(Nick.GetNickMask()) + " PRIVMSG " + _NAMEDFMT(sChan) + " :{text}", sMessage); } } diff --git a/src/User.cpp b/src/User.cpp index 978c566a..4b5b468b 100644 --- a/src/User.cpp +++ b/src/User.cpp @@ -502,17 +502,15 @@ CString& CUser::ExpandString(const CString& sStr, CString& sRet) const { } CString CUser::AddTimestamp(const CString& sStr) const { - CString sRet; - return AddTimestamp(sStr, sRet); + time_t tm; + return AddTimestamp(time(&tm), sStr); } -CString& CUser::AddTimestamp(const CString& sStr, CString& sRet) const { +CString CUser::AddTimestamp(time_t tm, const CString& sStr) const { char szTimestamp[1024]; - time_t tm; - sRet = sStr; + CString sRet = sStr; if (!GetTimestampFormat().empty() && (m_bAppendTimestamp || m_bPrependTimestamp)) { - time(&tm); tm += (time_t)(m_fTimezoneOffset * 60 * 60); // offset is in hours size_t i = strftime(szTimestamp, sizeof(szTimestamp), GetTimestampFormat().c_str(), localtime(&tm)); // If strftime returns 0, an error occured in format, or result is empty @@ -530,6 +528,7 @@ CString& CUser::AddTimestamp(const CString& sStr, CString& sRet) const { sRet += szTimestamp; } } + return sRet; }