diff --git a/configure.ac b/configure.ac index 968d6376..ad76691f 100644 --- a/configure.ac +++ b/configure.ac @@ -201,6 +201,11 @@ PKG_PROG_PKG_CONFIG() AC_SEARCH_LIBS([dlopen], [dl], [], [AC_MSG_ERROR([Could not find dlopen. ZNC will not work on this box until you upgrade this ancient system or at least install the necessary system libraries.])]) +# ----- librt is needed for clock_gettime +# if it exists, _POSIX_TIMERS should be defined to a value > 0 (in unistd.h) + +AC_SEARCH_LIBS([clock_gettime], [rt]) + # ----- Check for pthreads DNS_TEXT=blocking diff --git a/include/znc/Buffer.h b/include/znc/Buffer.h index b55a6a66..5afdebe0 100644 --- a/include/znc/Buffer.h +++ b/include/znc/Buffer.h @@ -11,6 +11,7 @@ #include #include +#include #include // Forward Declarations @@ -19,28 +20,28 @@ class CClient; class CBufLine { public: - CBufLine(const CString& sFormat, const CString& sText = "", time_t tm = 0); + CBufLine(const CString& sFormat, const CString& sText = "", const timespec* ts = 0); ~CBufLine(); CString GetLine(const CClient& Client, const MCString& msParams) const; - void UpdateTime() { time(&m_tm); } + void UpdateTime(); // Setters void SetFormat(const CString& sFormat) { m_sFormat = sFormat; } void SetText(const CString& sText) { m_sText = sText; } - void SetTime(time_t tm) { m_tm = tm; } + void SetTime(const timespec& ts) { m_time = ts; } // !Setters // Getters const CString& GetFormat() const { return m_sFormat; } const CString& GetText() const { return m_sText; } - time_t GetTime() const { return m_tm; } + timespec GetTime() const { return m_time; } // !Getters private: protected: - CString m_sFormat; - CString m_sText; - time_t m_tm; + CString m_sFormat; + CString m_sText; + timespec m_time; }; class CBuffer : private std::deque { @@ -48,7 +49,7 @@ public: CBuffer(unsigned int uLineCount = 100); ~CBuffer(); - int AddLine(const CString& sFormat, const CString& sText = "", time_t tm = 0); + int AddLine(const CString& sFormat, const CString& sText = "", const timespec* ts = 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. diff --git a/include/znc/Chan.h b/include/znc/Chan.h index 863100d1..45d6453d 100644 --- a/include/znc/Chan.h +++ b/include/znc/Chan.h @@ -85,7 +85,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, const CString& sText = "", time_t tm = 0) { return m_Buffer.AddLine(sFormat, sText, tm); } + int AddBuffer(const CString& sFormat, const CString& sText = "", const timespec* ts = NULL) { return m_Buffer.AddLine(sFormat, sText, ts); } void ClearBuffer() { m_Buffer.Clear(); } void SendBuffer(CClient* pClient); // !Buffer diff --git a/modules/savebuff.cpp b/modules/savebuff.cpp index b46b3402..760a2122 100644 --- a/modules/savebuff.cpp +++ b/modules/savebuff.cpp @@ -122,14 +122,16 @@ public: { CString sTimestamp = sLine.Token(0); sTimestamp.TrimLeft("@"); - time_t tm = sTimestamp.ToLongLong(); + timespec ts; + ts.tv_sec = sTimestamp.Token(0, false, ",").ToLongLong(); + ts.tv_nsec = sTimestamp.Token(1, false, ",").ToLong(); CString sFormat = sLine.Token(1, true); CString sText(*++it); sText.Trim(); - pChan->AddBuffer(sFormat, sText, tm); + pChan->AddBuffer(sFormat, sText, &ts); } else { // Old format, escape the line and use as is. @@ -169,8 +171,9 @@ public: unsigned int uSize = Buffer.Size(); for (unsigned int uIdx = 0; uIdx < uSize; uIdx++) { const CBufLine& Line = Buffer.GetBufLine(uIdx); + timespec ts = Line.GetTime(); sFile += - "@" + CString(Line.GetTime()) + " " + + "@" + CString(ts.tv_sec) + "," + CString(ts.tv_nsec) + " " + Line.GetFormat() + "\n" + Line.GetText() + "\n"; } diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 55c41c46..c44c5d9c 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -11,26 +11,40 @@ #include #include -CBufLine::CBufLine(const CString& sFormat, const CString& sText, time_t tm) { +CBufLine::CBufLine(const CString& sFormat, const CString& sText, const timespec* ts) { m_sFormat = sFormat; m_sText = sText; - if (tm == 0) + if (ts == NULL) UpdateTime(); else - m_tm = tm; + m_time = *ts; } CBufLine::~CBufLine() {} +void CBufLine::UpdateTime() { +#if _POSIX_TIMERS + if (0 == clock_gettime(CLOCK_REALTIME, &m_time)) { + return; + } +#endif + time(&m_time.tv_sec); + m_time.tv_nsec = 0; +} + 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 "@t=" + CString(m_tm) + " " + sStr; + CString s_msec(m_time.tv_nsec / 1000000); + while (s_msec.length() < 3) { + s_msec = "0" + s_msec; + } + return "@time=" + CString(m_time.tv_sec) + "." + s_msec + " " + sStr; } else { - msThisParams["text"] = Client.GetUser()->AddTimestamp(m_tm, m_sText); + msThisParams["text"] = Client.GetUser()->AddTimestamp(m_time.tv_sec, m_sText); return CString::NamedFormat(m_sFormat, msThisParams); } } @@ -41,7 +55,7 @@ CBuffer::CBuffer(unsigned int uLineCount) { CBuffer::~CBuffer() {} -int CBuffer::AddLine(const CString& sFormat, const CString& sText, time_t tm) { +int CBuffer::AddLine(const CString& sFormat, const CString& sText, const timespec* ts) { if (!m_uLineCount) { return 0; } @@ -50,7 +64,7 @@ int CBuffer::AddLine(const CString& sFormat, const CString& sText, time_t tm) { erase(begin()); } - push_back(CBufLine(sFormat, sText, tm)); + push_back(CBufLine(sFormat, sText, ts)); return size(); } diff --git a/src/Client.cpp b/src/Client.cpp index c655aea1..c7efbe67 100644 --- a/src/Client.cpp +++ b/src/Client.cpp @@ -810,7 +810,7 @@ void CClient::HandleCap(const CString& sLine) for (SCString::iterator i = ssOfferCaps.begin(); i != ssOfferCaps.end(); ++i) { sRes += *i + " "; } - RespondCap("LS :" + sRes + "userhost-in-names multi-prefix znc.in/server-time"); + RespondCap("LS :" + sRes + "userhost-in-names multi-prefix server-time"); m_bInCap = true; } else if (sSubCmd.Equals("END")) { m_bInCap = false; @@ -832,7 +832,7 @@ void CClient::HandleCap(const CString& sLine) if (sCap.TrimPrefix("-")) bVal = false; - bool bAccepted = ("multi-prefix" == sCap) || ("userhost-in-names" == sCap) || ("znc.in/server-time" == sCap); + bool bAccepted = ("multi-prefix" == sCap) || ("userhost-in-names" == sCap) || ("server-time" == sCap); GLOBALMODULECALL(IsClientCapSupported(this, sCap, bVal), bAccepted = true); if (!bAccepted) { @@ -852,7 +852,7 @@ void CClient::HandleCap(const CString& sLine) m_bNamesx = bVal; } else if ("userhost-in-names" == *it) { m_bUHNames = bVal; - } else if ("znc.in/server-time" == *it) { + } else if ("server-time" == *it) { m_bServerTime = bVal; } GLOBALMODULECALL(OnClientCapRequest(this, *it, bVal), NOTHING); @@ -891,7 +891,7 @@ void CClient::HandleCap(const CString& sLine) } if (m_bServerTime) { m_bServerTime = false; - ssRemoved.insert("znc.in/server-time"); + ssRemoved.insert("server-time"); } CString sList = ""; for (SCString::iterator i = ssRemoved.begin(); i != ssRemoved.end(); ++i) {