diff --git a/Chan.cpp b/Chan.cpp index 050ab200..0610ff01 100644 --- a/Chan.cpp +++ b/Chan.cpp @@ -21,8 +21,10 @@ CChan::CChan(const CString& sName, CUser* pUser, bool bInConfig) { m_bDetached = false; m_uBufferCount = m_pUser->GetBufferCount(); m_bKeepBuffer = m_pUser->KeepBuffer(); + m_bDisabled = false; Reset(); } + CChan::~CChan() { ClearNicks(); } @@ -155,7 +157,7 @@ CString CChan::GetModeString() const { } } - return (sModes.empty()) ? sModes : ("+" + sModes + sArgs); + return sModes.empty() ? sModes : CString("+" + sModes + sArgs); } CString CChan::GetModeForNames() const { diff --git a/Chan.h b/Chan.h index 1af5d5a4..ccc1ee36 100644 --- a/Chan.h +++ b/Chan.h @@ -111,6 +111,8 @@ public: void SetDetached(bool b = true) { m_bDetached = b; } void SetInConfig(bool b) { m_bInConfig = b; } void SetCreationDate(unsigned long u) { m_ulCreationDate = u; } + void Disable() { m_bDisabled = true; } + void Enable() { m_bDisabled = false; } // !Setters // Getters @@ -137,6 +139,7 @@ public: bool IsDetached() const { return m_bDetached; } bool InConfig() const { return m_bInConfig; } unsigned long GetCreationDate() const { return m_ulCreationDate; } + bool IsDisabled() const { return m_bDisabled; } // !Getters private: protected: @@ -146,6 +149,7 @@ protected: bool m_bKeepBuffer; bool m_bAutoCycle; bool m_bInConfig; + bool m_bDisabled; CString m_sName; CString m_sKey; CString m_sCurKey; diff --git a/Client.cpp b/Client.cpp index 3a82bd8a..31781cde 100644 --- a/Client.cpp +++ b/Client.cpp @@ -9,6 +9,17 @@ #include "DCCSock.h" #include "Server.h" +CClient::~CClient() { + if (!m_spAuth.IsNull()) { + CClientAuth* pAuth = (CClientAuth*) &(*m_spAuth); + pAuth->SetClient(NULL); + } + if (m_pUser != NULL) { + m_pUser->AddBytesRead(GetBytesRead()); + m_pUser->AddBytesWritten(GetBytesWritten()); + } +} + void CClient::ReadLine(const CString& sData) { CString sLine = sData; @@ -765,6 +776,21 @@ void CClient::UserCommand(const CString& sLine) { return; } } + } else if (sCommand.CaseCmp("ENABLECHAN") == 0) { + CString sChan = sLine.Token(1, true); + + if (sChan.empty()) { + PutStatus("Usage: EnableChan "); + } else { + CChan* pChan = m_pUser->FindChan(sChan); + if (!pChan) { + PutStatus("Channel [" + sChan + "] not found."); + return; + } + + pChan->Enable(); + PutStatus("Channel [" + sChan + "] enabled."); + } } else if (sCommand.CaseCmp("LISTCHANS") == 0) { if (m_pUser) { const vector& vChans = m_pUser->GetChans(); @@ -794,7 +820,7 @@ void CClient::UserCommand(const CString& sLine) { CChan* pChan = vChans[a]; Table.AddRow(); Table.SetCell("Name", pChan->GetPermStr() + pChan->GetName()); - Table.SetCell("Status", ((vChans[a]->IsOn()) ? ((vChans[a]->IsDetached()) ? "Detached" : "Joined") : "Trying")); + Table.SetCell("Status", ((vChans[a]->IsOn()) ? ((vChans[a]->IsDetached()) ? "Detached" : "Joined") : ((vChans[a]->IsDisabled()) ? "Disabled" : "Trying"))); Table.SetCell("Conf", CString((pChan->InConfig()) ? "yes" : "")); Table.SetCell("Buf", CString((pChan->KeepBuffer()) ? "*" : "") + CString(pChan->GetBufferCount())); Table.SetCell("Modes", pChan->GetModeString()); @@ -1320,6 +1346,50 @@ void CClient::UserCommand(const CString& sLine) { pChan->SetBufferCount(uLineCount); PutStatus("BufferCount for [" + sChan + "] set to [" + CString(pChan->GetBufferCount()) + "]"); + } else if (m_pUser->IsAdmin() && sCommand.CaseCmp("TRAFFIC") == 0) { + CZNC::Get().UpdateTrafficStats(); + const map& msUsers = CZNC::Get().GetUserMap(); + CTable Table; + Table.AddColumn("Username"); + Table.AddColumn("In"); + Table.AddColumn("Out"); + Table.AddColumn("Total"); + unsigned long long users_total_in = 0; + unsigned long long users_total_out = 0; + for (map::const_iterator it = msUsers.begin(); it != msUsers.end(); it++) { + Table.AddRow(); + Table.SetCell("Username", it->first); + Table.SetCell("In", CString(it->second->BytesRead())); + Table.SetCell("Out", CString(it->second->BytesWritten())); + Table.SetCell("Total", CString(it->second->BytesRead() + it->second->BytesWritten())); + users_total_in += it->second->BytesRead(); + users_total_out += it->second->BytesWritten(); + } + Table.AddRow(); + Table.SetCell("Username", ""); + Table.SetCell("In", CString(users_total_in)); + Table.SetCell("Out", CString(users_total_out)); + Table.SetCell("Total", CString(users_total_in + users_total_out)); + + Table.AddRow(); + Table.SetCell("Username", ""); + Table.SetCell("In", CString(CZNC::Get().BytesRead())); + Table.SetCell("Out", CString(CZNC::Get().BytesWritten())); + Table.SetCell("Total", CString(CZNC::Get().BytesRead() + CZNC::Get().BytesWritten())); + + Table.AddRow(); + Table.SetCell("Username", ""); + Table.SetCell("In", CString(users_total_in + CZNC::Get().BytesRead())); + Table.SetCell("Out", CString(users_total_out + CZNC::Get().BytesWritten())); + Table.SetCell("Total", CString(users_total_in + CZNC::Get().BytesRead() + users_total_out + CZNC::Get().BytesWritten())); + + if (Table.size()) { + unsigned int uTableIdx = 0; + CString sLine; + while (Table.GetLine(uTableIdx++, sLine)) { + PutStatus(sLine); + } + } } else { PutStatus("Unknown command [" + sCommand + "] try 'Help'"); } diff --git a/Client.h b/Client.h index 9fc14613..ae46c271 100644 --- a/Client.h +++ b/Client.h @@ -67,12 +67,7 @@ public: Init(); } - virtual ~CClient() { - if (!m_spAuth.IsNull()) { - CClientAuth* pAuth = (CClientAuth*) &(*m_spAuth); - pAuth->SetClient(NULL); - } - } + virtual ~CClient(); void Init() { m_pUser = NULL; @@ -120,6 +115,7 @@ public: virtual Csock* GetSockObj(const CString& sHost, unsigned short uPort); void SetNick(const CString& s); + CUser* GetUser() const { return m_pUser; } private: protected: bool m_bAuthed; diff --git a/IRCSock.cpp b/IRCSock.cpp index 6faad514..26a70a03 100644 --- a/IRCSock.cpp +++ b/IRCSock.cpp @@ -51,6 +51,8 @@ CIRCSock::~CIRCSock() { PutIRC("QUIT :" + m_pUser->GetQuitMsg()); m_msChans.clear(); + GetUser()->AddBytesRead(GetBytesRead()); + GetUser()->AddBytesWritten(GetBytesWritten()); } void CIRCSock::ReadLine(const CString& sData) { @@ -156,6 +158,12 @@ void CIRCSock::ReadLine(const CString& sData) { } break; + case 437: + // :irc.server.net 437 * badnick :Nick/channel is temporarily unavailable + // :irc.server.net 437 mynick badnick :Nick/channel is temporarily unavailable + // :irc.server.net 437 mynick badnick :Cannot change nickname while banned on channel + if (m_pUser->IsChan(sRest.Token(0)) || sNick != "*") + break; case 433: { unsigned int uMax = GetMaxNickLen(); CString sBadNick = sRest.Token(0); @@ -873,7 +881,7 @@ void CIRCSock::Disconnected() { void CIRCSock::SockError(int iErrno) { DEBUG_ONLY(cout << GetSockName() << " == SockError(" << iErrno << ")" << endl); if (!m_pUser->IsBeingDeleted()) { - m_pUser->PutStatus("Disconnected from IRC. Reconnecting..."); + m_pUser->PutStatus("Disconnected from IRC (" + CString(strerror(iErrno)) + "). Reconnecting..."); } m_pUser->ClearRawBuffer(); m_pUser->ClearMotdBuffer(); diff --git a/IRCSock.h b/IRCSock.h index c0dc6893..31bfa71e 100644 --- a/IRCSock.h +++ b/IRCSock.h @@ -66,6 +66,7 @@ public: const CString& GetNick() const { return m_Nick.GetNick(); } const CString& GetPass() const { return m_sPass; } bool IsOrigNickPending() const { return m_bOrigNickPending; } + CUser* GetUser() const { return m_pUser; } bool HasNamesx() const { return m_bNamesx; } bool HasUHNames() const { return m_bUHNames; } const set& GetUserModes() const { return m_scUserModes; } diff --git a/Modules.h b/Modules.h index 4eb0f07f..a8b541fc 100644 --- a/Modules.h +++ b/Modules.h @@ -25,6 +25,11 @@ using std::set; #endif #endif +#ifndef RTLD_LOCAL +# define RTLD_LOCAL 0 +# warning "your crap box doesnt define RTLD_LOCAL !?" +#endif + #define MODCONSTRUCTOR(CLASS) \ CLASS(void *pDLL, CUser* pUser, const CString& sModName) : CModule(pDLL, pUser, sModName) #define MODULEDEFS(CLASS, DESCRIPTION) \ diff --git a/Server.cpp b/Server.cpp index 48eb6007..72b99617 100644 --- a/Server.cpp +++ b/Server.cpp @@ -36,5 +36,5 @@ bool CServer::IsSSL() const { return m_bSSL; } bool CServer::IsIPV6() const { return m_bIPV6; } CString CServer::GetString() const { - return m_sName + " " + CString(m_bSSL ? "+" : "") + CString(m_uPort) + CString(m_sPass.empty() ? CString("") : " " + m_sPass); + return m_sName + " " + CString(m_bSSL ? "+" : "") + CString(m_uPort) + CString(m_sPass.empty() ? "" : " " + m_sPass); } diff --git a/Timers.h b/Timers.h index ae1aa635..99dd8d53 100644 --- a/Timers.h +++ b/Timers.h @@ -10,6 +10,7 @@ public: CKeepNickTimer(CUser* pUser) : CCron() { m_pUser = pUser; m_uTrys = 0; + SetName("CKeepNickTimer::" + m_pUser->GetUserName()); Start(5); } virtual ~CKeepNickTimer() {} @@ -37,6 +38,7 @@ class CMiscTimer : public CCron { public: CMiscTimer(CUser* pUser) : CCron() { m_pUser = pUser; + SetName("CMiscTimer::" + m_pUser->GetUserName()); Start(30); } virtual ~CMiscTimer() {} @@ -67,6 +69,7 @@ class CJoinTimer : public CCron { public: CJoinTimer(CUser* pUser) : CCron() { m_pUser = pUser; + SetName("CJoinTimer::" + m_pUser->GetUserName()); Start(20); } virtual ~CJoinTimer() {} diff --git a/User.cpp b/User.cpp index d97f6b42..762e9ff8 100644 --- a/User.cpp +++ b/User.cpp @@ -19,6 +19,8 @@ CUser::CUser(const CString& sUserName) { m_sIdent = m_sCleanUserName; m_sRealName = sUserName; m_uServerIdx = 0; + m_uBytesRead = 0; + m_uBytesWritten = 0; #ifdef _MODULES m_pModules = new CModules; #endif @@ -615,7 +617,7 @@ CChan* CUser::FindChan(const CString& sName) const { void CUser::JoinChans() { for (unsigned int a = 0; a < m_vChans.size(); a++) { CChan* pChan = m_vChans[a]; - if (!pChan->IsOn()) { + if (!pChan->IsOn() && !pChan->IsDisabled()) { PutIRC("JOIN " + pChan->GetName() + " " + pChan->GetKey()); } } diff --git a/User.h b/User.h index da7b883c..4b19e91c 100644 --- a/User.h +++ b/User.h @@ -106,6 +106,9 @@ public: bool Clone(const CUser& User, CString& sErrorRet); void BounceAllClients(); + void AddBytesRead(unsigned long long u) { m_uBytesRead += u; } + void AddBytesWritten(unsigned long long u) { m_uBytesWritten += u; } + // Setters void SetUserName(const CString& s); void SetNick(const CString& s); @@ -181,6 +184,8 @@ public: bool IsBeingDeleted() const { return m_bBeingDeleted; } bool HasServers() const { return m_vServers.size() > 0; } float GetTimezoneOffset() const { return m_fTimezoneOffset; } + unsigned long long BytesRead() const { return m_uBytesRead; } + unsigned long long BytesWritten() const { return m_uBytesWritten; } // !Getters private: protected: @@ -235,6 +240,8 @@ protected: set m_ssAllowedHosts; unsigned int m_uServerIdx; unsigned int m_uBufferCount; + unsigned long long m_uBytesRead; + unsigned long long m_uBytesWritten; #ifdef _MODULES CModules* m_pModules; diff --git a/configure.in b/configure.in index 5796d677..97560576 100644 --- a/configure.in +++ b/configure.in @@ -2,9 +2,11 @@ dnl Keep the version number in sync with main.h! AC_INIT([znc], [0.048]) AC_PROG_CXX AC_CANONICAL_HOST + CXXFLAGS="-D_GNU_SOURCE" INCLUDES="" LIBS="" + function appendLib { if test "$LIBS" != ""; then LIBS="$LIBS $*" @@ -37,16 +39,27 @@ function appendLD { fi } -if `echo $host_os | grep -i 'freebsd' >/dev/null 2>/dev/null`; then +case "${host_os}" in + freebsd*) appendInc -I/usr/local/include appendLib -L/usr/local/lib -lcompat appendCXX -D__GNU_LIBRARY__ -elif `echo $host_os | grep -i 'sol' >/dev/null 2>/dev/null`; then + ;; + solaris*) appendLib -lsocket -lnsl ISSUN=1 -fi + ;; + cygwin) + ISCYGWIN=1 + ;; +esac -appendCXX -fPIC +# cygwin +# warning: -fPIC ignored for target (all code is position independent) + +if test -z "$ISCYGWIN" ; then + appendCXX -fPIC +fi AC_ARG_WITH( [openssl], AC_HELP_STRING([--with-openssl=/path/to/openssl], []), diff --git a/main.h b/main.h index 5a57659d..499588d0 100644 --- a/main.h +++ b/main.h @@ -47,6 +47,10 @@ using std::cout; using std::cerr; using std::endl; +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + #include "String.h" #include "Csocket.h" #include "Utils.h" diff --git a/znc.cpp b/znc.cpp index 9ffcc712..2b6ca6fa 100644 --- a/znc.cpp +++ b/znc.cpp @@ -22,6 +22,8 @@ CZNC::CZNC() { m_pISpoofLockFile = NULL; m_uiConnectDelay = 30; SetISpoofFormat(""); // Set ISpoofFormat to default + m_uBytesRead = 0; + m_uBytesWritten = 0; } CZNC::~CZNC() { @@ -110,6 +112,8 @@ int CZNC::Loop() { #ifdef _MODULES pUser->DelModules(); #endif + AddBytesRead(pUser->BytesRead()); + AddBytesWritten(pUser->BytesWritten()); delete pUser; } @@ -1303,3 +1307,22 @@ CZNC& CZNC::Get() { return *pZNC; } +void CZNC::UpdateTrafficStats() { + CSockManager* p = &m_Manager; + for (unsigned int a = 0; a < p->size(); a++) { + if ((*p)[a]->GetSockName().Left(5) == "IRC::") { + CIRCSock *i = (CIRCSock *)(*p)[a]; + i->GetUser()->AddBytesRead((*p)[a]->GetBytesRead()); + (*p)[a]->ResetBytesRead(); + i->GetUser()->AddBytesWritten((*p)[a]->GetBytesWritten()); + (*p)[a]->ResetBytesWritten(); + } else if ((*p)[a]->GetSockName().Left(5) == "USR::") { + CClient *c = (CClient *)(*p)[a]; + c->GetUser()->AddBytesRead((*p)[a]->GetBytesRead()); + (*p)[a]->ResetBytesRead(); + c->GetUser()->AddBytesWritten((*p)[a]->GetBytesWritten()); + (*p)[a]->ResetBytesWritten(); + } + } +} + diff --git a/znc.h b/znc.h index aba7b89e..93be459a 100644 --- a/znc.h +++ b/znc.h @@ -106,6 +106,11 @@ public: bool AddVHost(const CString& sHost); bool RemVHost(const CString& sHost); void Broadcast(const CString& sMessage, CUser* pUser = NULL); + void AddBytesRead(unsigned long long u) { m_uBytesRead += u; } + void AddBytesWritten(unsigned long long u) { m_uBytesWritten += u; } + unsigned long long BytesRead() const { return m_uBytesRead; } + unsigned long long BytesWritten() const { return m_uBytesWritten; } + void UpdateTrafficStats(); // Setters void SetStatusPrefix(const CString& s) { m_sStatusPrefix = (s.empty()) ? "*" : s; } @@ -179,6 +184,8 @@ protected: #ifdef _MODULES CGlobalModules* m_pModules; #endif + unsigned long long m_uBytesRead; + unsigned long long m_uBytesWritten; }; class CListener { diff --git a/znc.spec b/znc.spec index ae212754..b7070031 100644 --- a/znc.spec +++ b/znc.spec @@ -1,22 +1,22 @@ Name: znc -Version: 0.046 +Version: 0.048 Release: 1 Packager: imaginos@imaginos.net -Summary: znc +Summary: znc - an advanced IRC bouncer License: GPL -Group: none +Group: Applications/Communications URL: http://sourceforge.net/projects/znc/ BuildRequires: gcc >= 3.2 BuildRequires: openssl >= 0.9.7d -BuildRoot: /tmp/znc-TMP/ +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root Prefix: /usr -Source: znc-%{version}.tar.gz +Source: %{name}-%{version}.tar.gz %description ZNC is an IRC bounce with many advanced features like detaching, multiple users, per channel playback buffer, SSL, transparent DCC bouncing, and c++ module support to name a few. %prep -%setup -n znc-%{version} +%setup -n %{name}-%{version} %build ./configure --prefix=%{prefix} @@ -30,5 +30,7 @@ make install DESTDIR=$RPM_BUILD_ROOT %files +%doc AUTHORS +%doc docs/*.html docs/*.txt docs/*.pm %{prefix}