From 0a622749754fed38a0dfe673daf3d2ad49f166a3 Mon Sep 17 00:00:00 2001 From: prozacx Date: Mon, 12 Mar 2007 06:26:54 +0000 Subject: [PATCH] Committing patches from crox/psychon git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@790 726aef4b-f618-498e-8847-2d620e286838 --- Chan.cpp | 66 +++++++++++++++++++++++------ Chan.h | 6 ++- Client.cpp | 53 ++++++++++++++++++++++-- Client.h | 6 +++ DCCBounce.cpp | 2 +- FileUtils.cpp | 33 ++++++++++++--- FileUtils.h | 3 ++ IRCSock.cpp | 88 ++++++++++++++++++++++++++++++++------- IRCSock.h | 4 ++ Makefile.in | 5 ++- Nick.cpp | 12 ++++-- String.h | 2 +- User.cpp | 20 +++++---- User.h | 4 +- Utils.cpp | 2 +- Utils.h | 13 +++--- configure | 18 ++++++-- configure.in | 12 +++++- docs/Configuration.html | 7 ++-- docs/WritingModules.html | 2 +- main.cpp | 30 ++++++++------ modules/awaynick.cpp | 15 ++++++- modules/perform.cpp | 16 +++++--- modules/webadmin.cpp | 21 +++++++++- znc-0.000.ebuild | 41 ++++++++---------- znc.cpp | 89 +++++++++++++++++++++++++++------------- znc.h | 7 ++-- 27 files changed, 432 insertions(+), 145 deletions(-) diff --git a/Chan.cpp b/Chan.cpp index 3686d6c9..6974efbe 100644 --- a/Chan.cpp +++ b/Chan.cpp @@ -38,6 +38,7 @@ void CChan::Reset() { m_sTopic = ""; m_sTopicOwner = ""; m_ulTopicDate = 0; + m_ulCreationDate = 0; ClearNicks(); } @@ -81,16 +82,27 @@ void CChan::JoinUser(bool bForce, const CString& sKey, CClient* pClient) { m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 333 " + m_pUser->GetIRCNick().GetNick() + " " + GetName() + " " + GetTopicOwner() + " " + CString(GetTopicDate()), pClient); } - CString sPre = ":" + m_pUser->GetIRCServer() + " 353 " + m_pUser->GetIRCNick().GetNick() + " = " + GetName() + " :"; + CString sPre = ":" + m_pUser->GetIRCServer() + " 353 " + m_pUser->GetIRCNick().GetNick() + " " + GetModeForNames() + " " + GetName() + " :"; CString sLine = sPre; + CString sPerm, sNick; for (map::iterator a = m_msNicks.begin(); a != m_msNicks.end(); a++) { - char c = a->second->GetPermChar(); - if (c != '\0') { - sLine += c; + if(pClient->HasNamesx()) { + sPerm = a->second->GetPermStr(); + } else { + char c = a->second->GetPermChar(); + sPerm = ""; + if (c != '\0') { + sPerm += c; + } + } + if(pClient->HasUHNames() && !a->second->GetIdent().empty() && a->second->GetHost().empty()) { + sNick = a->first + "!" + a->second->GetIdent() + "@" + a->second->GetHost(); + } else { + sNick = a->first; } - sLine += a->first; + sLine += sPerm + sNick; if (sLine.size() >= 490 || a == (--m_msNicks.end())) { m_pUser->PutUser(sLine, pClient); @@ -134,6 +146,20 @@ CString CChan::GetModeString() const { return (sModes.empty()) ? sModes : ("+" + sModes + sArgs); } +CString CChan::GetModeForNames() const { + CString sMode; + + for (map::const_iterator it = m_musModes.begin(); it != m_musModes.end(); it++) { + if (it->first == 's') { + sMode = "@"; + } else if ((it->first == 'p') && sMode.empty()){ + sMode = "*"; + } + } + + return (sMode.empty() ? "=" : sMode); +} + void CChan::SetModes(const CString& sModes) { m_musModes.clear(); m_uLimit = 0; @@ -373,28 +399,42 @@ int CChan::AddNicks(const CString& sNicks) { bool CChan::AddNick(const CString& sNick) { const char* p = sNick.c_str(); - char cPrefix = '\0'; + CString sPrefix, sTmp, sIdent, sHost; - if (m_pUser->GetIRCSock()->IsPermChar(*p)) { - cPrefix = *p; + while (m_pUser->GetIRCSock()->IsPermChar(*p)) { + sPrefix += *p; if (!*++p) { return false; } } - CNick* pNick = FindNick(p); + sTmp = p; + sIdent = sTmp.Token(1, true, "!").Token(0, true, "@"); + sHost = sTmp.Token(1, true, "@"); + sTmp = sTmp.Token(0, false, "!"); + + CNick* pNick = FindNick(sTmp); if (!pNick) { - pNick = new CNick(p); + pNick = new CNick(sTmp); pNick->SetUser(m_pUser); } - if (pNick->AddPerm(cPrefix)) { - IncPermCount(cPrefix); + if(!sIdent.empty()) + pNick->SetIdent(sIdent); + if(!sHost.empty()) + pNick->SetHost(sHost); + + for(CString::size_type i = 0; i < sPrefix.length(); i++) { + if (pNick->AddPerm(sPrefix[i])) { + IncPermCount(sPrefix[i]); + } } if (pNick->GetNick().CaseCmp(m_pUser->GetCurNick()) == 0) { - AddPerm(cPrefix); + for(CString::size_type i = 0; i < sPrefix.length(); i++) { + AddPerm(sPrefix[i]); + } } m_msNicks[pNick->GetNick()] = pNick; diff --git a/Chan.h b/Chan.h index 98b471c4..1af5d5a4 100644 --- a/Chan.h +++ b/Chan.h @@ -41,7 +41,7 @@ public: M_Op = 'o', M_Voice = 'v', M_Ban = 'b', - M_Except = 'e', + M_Except = 'e' } EModes; CChan(const CString& sName, CUser* pUser, bool bInConfig); @@ -70,6 +70,7 @@ public: void OnVoice(const CString& sOpNick, const CString& sNick, bool bVoiced); CString GetModeString() const; CString GetModeArg(CString& sArgs) const; + CString GetModeForNames() const; // !Modes // Nicks @@ -109,6 +110,7 @@ public: void SetWhoDone(bool b = true) { m_bWhoDone = b; } void SetDetached(bool b = true) { m_bDetached = b; } void SetInConfig(bool b) { m_bInConfig = b; } + void SetCreationDate(unsigned long u) { m_ulCreationDate = u; } // !Setters // Getters @@ -134,6 +136,7 @@ public: bool AutoCycle() const { return m_bAutoCycle; } bool IsDetached() const { return m_bDetached; } bool InConfig() const { return m_bInConfig; } + unsigned long GetCreationDate() const { return m_ulCreationDate; } // !Getters private: protected: @@ -149,6 +152,7 @@ protected: CString m_sTopic; CString m_sTopicOwner; unsigned long m_ulTopicDate; + unsigned long m_ulCreationDate; CUser* m_pUser; CNick m_Nick; unsigned int m_uLimit; diff --git a/Client.cpp b/Client.cpp index 2b7c632f..c1c70c93 100644 --- a/Client.cpp +++ b/Client.cpp @@ -115,6 +115,13 @@ void CClient::ReadLine(const CString& sData) { PutStatusNotice("Detached from [" + sChan + "]"); return; } + } else if (sCommand.CaseCmp("PING") == 0) { + CString sTarget = sLine.Token(1); + + if (sTarget.CaseCmp("irc.znc.com") == 0) { + PutClient("PONG " + sLine.substr(5)); + return; + } } else if (sCommand.CaseCmp("PONG") == 0) { return; // Block pong replies, we already responded to the pings } else if (sCommand.CaseCmp("JOIN") == 0) { @@ -185,6 +192,21 @@ void CClient::ReadLine(const CString& sData) { if (!sMessage.empty()) { sLine += " :" + sMessage; } + } else if (sCommand.CaseCmp("MODE") == 0) { + CString sTarget = sLine.Token(1); + CString sModes = sLine.Token(2, true); + + if (m_pUser && m_pUser->IsChan(sTarget)) { + CChan *pChan = m_pUser->FindChan(sTarget); + + if (pChan && sModes.empty()) { + PutClient(":" + m_pUser->GetIRCServer() + " 324 " + GetNick() + " " + sTarget + " " + pChan->GetModeString()); + if (pChan->GetCreationDate() > 0) { + PutClient(":" + m_pUser->GetIRCServer() + " 329 " + GetNick() + " " + sTarget + " " + CString(pChan->GetCreationDate())); + } + return; + } + } } else if (sCommand.CaseCmp("QUIT") == 0) { if (m_pUser) { m_pUser->UserDisconnected(this); @@ -192,6 +214,17 @@ void CClient::ReadLine(const CString& sData) { Close(); // Treat a client quit as a detach return; // Don't forward this msg. We don't want the client getting us disconnected. + } else if (sCommand.CaseCmp("PROTOCTL") == 0) { + unsigned int i = 1; + while(!sLine.Token(i).empty()) { + if(sLine.Token(i).CaseCmp("NAMESX") == 0) { + m_bNamesx = true; + } else if(sLine.Token(i).CaseCmp("UHNAMES") == 0) { + m_bUHNames = true; + } + i++; + } + return; // If the server understands it, we already enabled namesx / uhnames } else if (sCommand.CaseCmp("NOTICE") == 0) { CString sTarget = sLine.Token(1); CString sMsg = sLine.Token(2, true); @@ -805,8 +838,8 @@ void CClient::UserCommand(const CString& sLine) { const vector& vServers = m_pUser->GetServers(); - if (vServers.size() <= 1) { - PutStatus("You must have at least one server at all times."); + if (vServers.size() <= 0) { + PutStatus("You don't have any servers added."); return; } @@ -817,6 +850,7 @@ void CClient::UserCommand(const CString& sLine) { } } else if (sCommand.CaseCmp("LISTSERVERS") == 0) { if (m_pUser) { + if (m_pUser->HasServers()) { const vector& vServers = m_pUser->GetServers(); CTable Table; Table.AddColumn("Host"); @@ -841,6 +875,9 @@ void CClient::UserCommand(const CString& sLine) { PutStatus(sLine); } } + } else { + PutStatus("You don't have any servers added."); + } } } else if (sCommand.CaseCmp("TOPICS") == 0) { if (m_pUser) { @@ -870,13 +907,17 @@ void CClient::UserCommand(const CString& sLine) { } else if (sCommand.CaseCmp("SEND") == 0) { CString sToNick = sLine.Token(1); CString sFile = sLine.Token(2); + CString sAllowedPath = m_pUser->GetDLPath(); + CString sAbsolutePath; if ((sToNick.empty()) || (sFile.empty())) { PutStatus("Usage: Send "); return; } - if ((!m_pUser->IsAdmin() && sFile.Left(1) == "~") || sFile.Left(1) == "/" || sFile.find("..") != CString::npos) { + sAbsolutePath = CUtils::ChangeDir(m_pUser->GetDLPath(), sFile, CZNC::Get().GetHomePath()); + + if (sAbsolutePath.Left(sAllowedPath.length()) != sAllowedPath) { PutStatus("Illegal path."); return; } @@ -886,13 +927,17 @@ void CClient::UserCommand(const CString& sLine) { } } else if (sCommand.CaseCmp("GET") == 0) { CString sFile = sLine.Token(1); + CString sAllowedPath = m_pUser->GetDLPath(); + CString sAbsolutePath; if (sFile.empty()) { PutStatus("Usage: Get "); return; } - if ((!m_pUser->IsAdmin() && sFile.Left(1) == "~") || sFile.Left(1) == "/" || sFile.find("..") != CString::npos) { + sAbsolutePath = CUtils::ChangeDir(m_pUser->GetDLPath(), sFile, CZNC::Get().GetHomePath()); + + if (sAbsolutePath.Left(sAllowedPath.length()) != sAllowedPath) { PutStatus("Illegal path."); return; } diff --git a/Client.h b/Client.h index 563657c7..f8e7923f 100644 --- a/Client.h +++ b/Client.h @@ -81,6 +81,8 @@ public: m_bGotPass = false; m_bGotNick = false; m_bGotUser = false; + m_bNamesx = false; + m_bUHNames = false; m_uKeepNickCounter = 0; EnableReadLine(); } @@ -90,6 +92,8 @@ public: CString GetNick() const; CString GetNickMask() const; + bool HasNamesx() const { return m_bNamesx; } + bool HasUHNames() const { return m_bUHNames; } bool DecKeepNickCounter(); void UserCommand(const CString& sCommand); @@ -122,6 +126,8 @@ protected: bool m_bGotPass; bool m_bGotNick; bool m_bGotUser; + bool m_bNamesx; + bool m_bUHNames; CUser* m_pUser; CString m_sNick; CString m_sPass; diff --git a/DCCBounce.cpp b/DCCBounce.cpp index ca602b07..5591bda2 100644 --- a/DCCBounce.cpp +++ b/DCCBounce.cpp @@ -121,7 +121,7 @@ void CDCCBounce::PutPeer(const CString& sLine) { unsigned short CDCCBounce::DCCRequest(const CString& sNick, unsigned long uLongIP, unsigned short uPort, const CString& sFileName, bool bIsChat, CUser* pUser, const CString& sLocalIP, const CString& sRemoteIP) { CDCCBounce* pDCCBounce = new CDCCBounce(pUser, uLongIP, uPort, sFileName, sNick, sRemoteIP, sLocalIP, bIsChat); - unsigned short uListenPort = CZNC::Get().GetManager().ListenAllRand("DCC::" + CString((bIsChat) ? "Chat" : "Xfer") + "::Local::" + sNick, false, SOMAXCONN, pDCCBounce, 120); + unsigned short uListenPort = CZNC::Get().GetManager().ListenRand("DCC::" + CString((bIsChat) ? "Chat" : "Xfer") + "::Local::" + sNick, sLocalIP, false, SOMAXCONN, pDCCBounce, 120); return uListenPort; } diff --git a/FileUtils.cpp b/FileUtils.cpp index d2730102..79339441 100644 --- a/FileUtils.cpp +++ b/FileUtils.cpp @@ -10,23 +10,31 @@ using std::endl; CFile::CFile() { m_iFD = -1; + m_bClose = false; } CFile::CFile(const CString& sLongName) { m_iFD = -1; + m_bClose = false; + + SetFileName(sLongName); +} + +CFile::CFile(int iFD, const CString& sLongName) { + m_iFD = iFD; + m_bClose = false; SetFileName(sLongName); } CFile::~CFile() { - if (m_iFD != -1) { + if (m_bClose && m_iFD != -1) { Close(); } } void CFile::SetFileName(const CString& sLongName) { m_sLongName = sLongName; - m_iFD = -1; m_sShortName = sLongName; m_sShortName.TrimRight("/"); @@ -217,6 +225,15 @@ bool CFile::Seek(unsigned long uPos) { return false; } +bool CFile::Truncate() { + if (m_iFD != -1 && ftruncate(m_iFD, 0) == 0) { + ClearBuffer(); + return true; + } + + return false; +} + bool CFile::Open(const CString& sFileName, int iFlags, mode_t iMode) { SetFileName(sFileName); return Open(iFlags, iMode); @@ -228,7 +245,11 @@ bool CFile::Open(int iFlags, mode_t iMode) { } m_iFD = open(m_sLongName.c_str(), iFlags, iMode); - return (m_iFD > -1); + if (m_iFD < 0) + return false; + + m_bClose = true; + return true; } int CFile::Read(char *pszBuffer, int iBytes) { @@ -306,8 +327,10 @@ int CFile::Write(const CString & sData) { return Write(sData.data(), sData.size()); } void CFile::Close() { - if (m_iFD >= 0) { - close(m_iFD); m_iFD = -1; + if (m_iFD >= 0 && m_bClose) { + close(m_iFD); + m_iFD = -1; + m_bClose = false; } } void CFile::ClearBuffer() { m_sBuffer.clear(); } diff --git a/FileUtils.h b/FileUtils.h index cd76a479..d78538d2 100644 --- a/FileUtils.h +++ b/FileUtils.h @@ -23,6 +23,7 @@ class CFile { public: CFile(); CFile(const CString& sLongName); + CFile(int iFD, const CString& sLongName); virtual ~CFile(); enum EOptions { @@ -106,6 +107,7 @@ public: bool Chmod(mode_t mode); static bool Chmod(const CString& sFile, mode_t mode); bool Seek(unsigned long uPos); + bool Truncate(); bool Open(const CString& sFileName, int iFlags, mode_t iMode = 0644); bool Open(int iFlags, mode_t iMode = 0644); int Read(char *pszBuffer, int iBytes); @@ -128,6 +130,7 @@ private: protected: CString m_sLongName; //!< Absolute filename (m_sPath + "/" + m_sShortName) CString m_sShortName; //!< Filename alone, without path + bool m_bClose; }; class CDir : public vector { diff --git a/IRCSock.cpp b/IRCSock.cpp index 880e23aa..3b64f77a 100644 --- a/IRCSock.cpp +++ b/IRCSock.cpp @@ -12,6 +12,8 @@ CIRCSock::CIRCSock(CUser* pUser) : Csock() { m_bKeepNick = true; m_bAuthed = false; m_bOrigNickPending = false; + m_bNamesx = false; + m_bUHNames = false; EnableReadLine(); m_Nick.SetIdent(pUser->GetIdent()); m_Nick.SetHost(pUser->GetVHost()); @@ -299,20 +301,65 @@ void CIRCSock::ReadLine(const CString& sData) { } } break; + case 329: { + sRest.Trim(); + CChan* pChan = m_pUser->FindChan(sRest.Token(0)); + + if (pChan) { + unsigned long ulDate = strtoul(sLine.Token(4).c_str(), NULL, 10); + pChan->SetCreationDate(ulDate); + } + } + break; case 353: { // NAMES sRest.Trim(); // Todo: allow for non @+= server msgs CChan* pChan = m_pUser->FindChan(sRest.Token(1)); - if (pChan) { - CString sNicks = sRest.Token(2, true); - if (sNicks.Left(1) == ":") { - sNicks.LeftChomp(); - } + if (!pChan) // Todo: should this still be forwarded to clients? + return; - pChan->AddNicks(sNicks); + CString sNicks = sRest.Token(2, true); + if (sNicks.Left(1) == ":") { + sNicks.LeftChomp(); } + + pChan->AddNicks(sNicks); + + CString sTmp; + vector& vClients = m_pUser->GetClients(); + for (unsigned int a = 0; a < vClients.size(); a++) { + if((!m_bNamesx || vClients[a]->HasNamesx()) && + (!m_bUHNames || vClients[a]->HasUHNames())) { + m_pUser->PutUser(sLine, vClients[a]); + } else { + sTmp = sLine.Token(0) + " "; + sTmp += sLine.Token(1) + " "; + sTmp += sLine.Token(2) + " "; + sTmp += sLine.Token(3) + " "; + sTmp += sLine.Token(4) + " :"; + while(!sNicks.empty()) { + CString sNick = sNicks.Token(0); + sNicks = sNicks.Token(1, true); + if(m_bNamesx && !vClients[a]->HasNamesx() + && IsPermChar(sNick[0])) { + while(sNick.length() > 2 + && IsPermChar(sNick[1])) { + sNick = sNick[0] + sNick.substr(2); + } + } + + if(m_bUHNames && !vClients[a]->HasUHNames()) { + sNick = sNick.Token(0, false, "!"); + } + + sTmp += sNick + " "; + } + sTmp.RightChomp(); + m_pUser->PutUser(sTmp, vClients[a]); + } + } + return; } - break; case 366: { // end of names list m_pUser->PutUser(sLine); // First send them the raw @@ -612,7 +659,7 @@ bool CIRCSock::OnCTCPReply(CNick& Nick, CString& sMessage) { bool CIRCSock::OnPrivCTCP(CNick& Nick, CString& sMessage) { MODULECALL(OnPrivCTCP(Nick, sMessage), m_pUser, NULL, return true); - if (strncasecmp(sMessage.c_str(), "DCC ", 4) == 0 && m_pUser && m_pUser->BounceDCCs()) { + if (strncasecmp(sMessage.c_str(), "DCC ", 4) == 0 && m_pUser && m_pUser->BounceDCCs() && m_pUser->IsUserAttached()) { // DCC CHAT chat 2453612361 44592 CString sType = sMessage.Token(1); CString sFile = sMessage.Token(2); @@ -621,13 +668,10 @@ bool CIRCSock::OnPrivCTCP(CNick& Nick, CString& sMessage) { unsigned long uFileSize = strtoul(sMessage.Token(5).c_str(), NULL, 10); if (sType.CaseCmp("CHAT") == 0) { - if (m_pUser->IsUserAttached()) { - CNick FromNick(Nick.GetNickMask()); - unsigned short uBNCPort = CDCCBounce::DCCRequest(FromNick.GetNick(), uLongIP, uPort, "", true, m_pUser, GetLocalIP(), CUtils::GetIP(uLongIP)); - - if (uBNCPort) { - m_pUser->PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + GetNick() + " :\001DCC CHAT chat " + CString(CUtils::GetLongIP(GetLocalIP())) + " " + CString(uBNCPort) + "\001"); - } + CNick FromNick(Nick.GetNickMask()); + unsigned short uBNCPort = CDCCBounce::DCCRequest(FromNick.GetNick(), uLongIP, uPort, "", true, m_pUser, GetLocalIP(), CUtils::GetIP(uLongIP)); + if (uBNCPort) { + m_pUser->PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + GetNick() + " :\001DCC CHAT chat " + CString(CUtils::GetLongIP(GetLocalIP())) + " " + CString(uBNCPort) + "\001"); } } else if (sType.CaseCmp("SEND") == 0) { // DCC SEND readme.txt 403120438 5550 1104 @@ -780,6 +824,8 @@ void CIRCSock::Disconnected() { if (!m_pUser->IsBeingDeleted()) { m_pUser->PutStatus("Disconnected from IRC. Reconnecting..."); } + m_pUser->ClearRawBuffer(); + m_pUser->ClearMotdBuffer(); ResetChans(); } @@ -789,6 +835,8 @@ void CIRCSock::SockError(int iErrno) { if (!m_pUser->IsBeingDeleted()) { m_pUser->PutStatus("Disconnected from IRC. Reconnecting..."); } + m_pUser->ClearRawBuffer(); + m_pUser->ClearMotdBuffer(); ResetChans(); } @@ -798,6 +846,8 @@ void CIRCSock::Timeout() { if (!m_pUser->IsBeingDeleted()) { m_pUser->PutStatus("IRC connection timed out. Reconnecting..."); } + m_pUser->ClearRawBuffer(); + m_pUser->ClearMotdBuffer(); ResetChans(); } @@ -807,6 +857,8 @@ void CIRCSock::ConnectionRefused() { if (!m_pUser->IsBeingDeleted()) { m_pUser->PutStatus("Connection Refused. Reconnecting..."); } + m_pUser->ClearRawBuffer(); + m_pUser->ClearMotdBuffer(); } void CIRCSock::ParseISupport(const CString& sLine) { @@ -846,6 +898,12 @@ void CIRCSock::ParseISupport(const CString& sLine) { } } } + } else if (sName.CaseCmp("NAMESX") == 0) { + m_bNamesx = true; + PutIRC("PROTOCTL NAMESX"); + } else if (sName.CaseCmp("UHNAMES") == 0) { + m_bUHNames = true; + PutIRC("PROTOCTL UHNAMES"); } sArg = sLine.Token(i++); diff --git a/IRCSock.h b/IRCSock.h index 4a5b9515..3dfbe7e4 100644 --- a/IRCSock.h +++ b/IRCSock.h @@ -66,6 +66,8 @@ public: const CString& GetNick() const { return m_Nick.GetNick(); } const CString& GetPass() const { return m_sPass; } bool IsOrigNickPending() const { return m_bOrigNickPending; } + bool HasNamesx() const { return m_bNamesx; } + bool HasUHNames() const { return m_bUHNames; } // !Getters private: void SetNick(const CString& sNick); @@ -74,6 +76,8 @@ protected: bool m_bAuthed; bool m_bKeepNick; bool m_bOrigNickPending; + bool m_bNamesx; + bool m_bUHNames; CString m_sPerms; CString m_sPermModes; map m_mueChanModes; diff --git a/Makefile.in b/Makefile.in index 7af934c8..3a6bcc4b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,5 +1,6 @@ CXX=@CXX@ CXXFLAGS=@CXXFLAGS@ +LDFLAGS=@LDFLAGS@ INCLUDES=@INCLUDES@ LIBS=@LIBS@ prefix=@prefix@ @@ -14,10 +15,10 @@ depend:: @if test -n "@MODTARGET@"; then (cd modules; $(MAKE) depend); fi znc: $(OBJS) - $(CXX) $(CXXFLAGS) $(INCLUDES) -o $@ $(LIBS) $(OBJS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $@ $(INCLUDES) $(OBJS) $(LIBS) znc-static: $(OBJS) - $(CXX) $(CXXFLAGS) -static -o $@ $(INCLUDES) $(OBJS) $(LIBS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -static -o $@ $(INCLUDES) $(OBJS) $(LIBS) strip $@ modules:: diff --git a/Nick.cpp b/Nick.cpp index 2e356ede..42ff1984 100644 --- a/Nick.cpp +++ b/Nick.cpp @@ -117,11 +117,17 @@ void CNick::UpdatePermChar() { const set& CNick::GetChanPerms() const { return m_suChanPerms; } const unsigned char CNick::GetPermChar() const { return m_cPerm; } CString CNick::GetPermStr() const { + CIRCSock* pIRCSock = (!m_pUser) ? NULL : m_pUser->GetIRCSock(); + const CString& sChanPerms = (!pIRCSock) ? "@+" : pIRCSock->GetPerms(); CString sRet; - if (m_cPerm) { - sRet += m_cPerm; - } + for (unsigned int a = 0; a < sChanPerms.size(); a++) { + const unsigned char& c = sChanPerms[a]; + + if (HasPerm(c)) { + sRet += c; + } + } return sRet; } diff --git a/String.h b/String.h index d7af93d1..0d6cd99e 100644 --- a/String.h +++ b/String.h @@ -64,7 +64,7 @@ public: EASCII, EURL, EHTML, - ESQL, + ESQL } EEscape; explicit CString(char c); diff --git a/User.cpp b/User.cpp index 94337416..ca16ef19 100644 --- a/User.cpp +++ b/User.cpp @@ -88,8 +88,9 @@ void CUser::DelClients() { bool CUser::OnBoot() { #ifdef _MODULES return GetModules().OnBoot(); -#endif +#else return true; +#endif } void CUser::IRCConnected(CIRCSock* pIRCSock) { @@ -114,7 +115,8 @@ CString CUser::ExpandString(const CString& sStr) const { CString& CUser::ExpandString(const CString& sStr, CString& sRet) const { sRet = sStr; sRet.Replace("%user%", GetUserName()); - sRet.Replace("%nick%", GetUserName()); + sRet.Replace("%defnick%", GetNick()); + sRet.Replace("%nick%", GetCurNick()); sRet.Replace("%altnick%", GetAltNick()); sRet.Replace("%ident%", GetIdent()); sRet.Replace("%realname%", GetRealName()); @@ -414,11 +416,6 @@ bool CUser::IsValid(CString& sErrMsg, bool bSkipPass) const { return false; } - if (m_vServers.empty()) { - sErrMsg = "No servers defined"; - return false; - } - return true; } @@ -723,6 +720,11 @@ CIRCSock* CUser::GetIRCSock() { return (CIRCSock*) CZNC::Get().GetManager().FindSockByName("IRC::" + m_sUserName); } +const CIRCSock* CUser::GetIRCSock() const { + // Todo: same as above + return (CIRCSock*) CZNC::Get().GetManager().FindSockByName("IRC::" + m_sUserName); +} + CString CUser::GetLocalIP() { CIRCSock* pIRCSock = GetIRCSock(); @@ -872,8 +874,8 @@ bool CUser::GetFile(const CString& sRemoteNick, const CString& sRemoteIP, unsign return true; } -CString CUser::GetCurNick() { - CIRCSock* pIRCSock = GetIRCSock(); +CString CUser::GetCurNick() const { + const CIRCSock* pIRCSock = GetIRCSock(); if (pIRCSock) { return pIRCSock->GetNick(); diff --git a/User.h b/User.h index ee7649d2..5bbb4bfd 100644 --- a/User.h +++ b/User.h @@ -96,7 +96,7 @@ public: bool SendFile(const CString& sRemoteNick, const CString& sFileName, const CString& sModuleName = ""); bool GetFile(const CString& sRemoteNick, const CString& sRemoteIP, unsigned short uRemotePort, const CString& sFileName, unsigned long uFileSize, const CString& sModuleName = ""); bool ResumeFile(const CString& sRemoteNick, unsigned short uPort, unsigned long uFileSize); - CString GetCurNick(); + CString GetCurNick() const; bool Clone(const CUser& User, CString& sErrorRet); void BounceAllClients(); @@ -130,6 +130,7 @@ public: // Getters vector& GetClients() { return m_vClients; } CIRCSock* GetIRCSock(); + const CIRCSock* GetIRCSock() const; const CString& GetUserName() const; const CString& GetCleanUserName() const; const CString& GetNick(bool bAllowDefault = true) const; @@ -165,6 +166,7 @@ public: bool KeepBuffer() const; bool AutoCycle() const; bool IsBeingDeleted() const { return m_bBeingDeleted; } + bool HasServers() const { return m_vServers.size() > 0; } // !Getters private: protected: diff --git a/Utils.cpp b/Utils.cpp index d3409408..f2b38435 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -117,7 +117,7 @@ void CUtils::GenerateCert(FILE *pOut, bool bEncPrivKey, const CString& sHost) { X509_free( pCert ); EVP_PKEY_free( pKey ); } -}; +} #endif /* HAVE_LIBSSL */ CString CUtils::GetIP(unsigned long addr) { diff --git a/Utils.h b/Utils.h index 58dfec43..27e32f34 100644 --- a/Utils.h +++ b/Utils.h @@ -86,8 +86,8 @@ public: } } - void Open(const CString& sFile) { - m_fd = open(sFile.c_str(), O_RDONLY); + void Open(const CString& sFile, bool bRw = false) { + m_fd = open(sFile.c_str(), bRw ? O_RDWR : O_RDONLY); m_bCreated = false; if (m_fd == -1) { @@ -101,8 +101,8 @@ public: } //! timeout in milliseconds - bool TryExLock(const CString& sLockFile, unsigned long long iTimeout = 0) { - Open(sLockFile); + bool TryExLock(const CString& sLockFile, unsigned long long iTimeout = 0, bool bRw = false) { + Open(sLockFile, bRw); return TryExLock(iTimeout); } @@ -154,6 +154,9 @@ public: bool LockSh() { return Lock(LOCK_SH); } bool UnLock() { return Lock(LOCK_UN); } + CString GetFileName() { return m_sFileName; } + int GetFD() { return m_fd; } + private: bool Lock(int iOperation) { if (m_fd == -1) { @@ -177,7 +180,7 @@ class CException { public: typedef enum { EX_Shutdown, - EX_BadModVersion, + EX_BadModVersion } EType; CException(EType e) { diff --git a/configure b/configure index f353737e..3fd09d24 100755 --- a/configure +++ b/configure @@ -681,13 +681,13 @@ echo X"$0" | /^X\(\/\).*/{ s//\1/; q; } s/.*/./; q'` srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then + if test ! -r $srcdir/$ac_unique_file; then srcdir=.. fi else ac_srcdir_defaulted=no fi -if test ! -r "$srcdir/$ac_unique_file"; then +if test ! -r $srcdir/$ac_unique_file; then if test "$ac_srcdir_defaulted" = yes; then { echo "$as_me: error: cannot find sources ($ac_unique_file) in $ac_confdir or .." >&2 { (exit 1); exit 1; }; } @@ -696,7 +696,7 @@ if test ! -r "$srcdir/$ac_unique_file"; then { (exit 1); exit 1; }; } fi fi -(cd $srcdir && test -r "./$ac_unique_file") 2>/dev/null || +(cd $srcdir && test -r ./$ac_unique_file) 2>/dev/null || { echo "$as_me: error: sources are in $srcdir, but \`cd $srcdir' does not work" >&2 { (exit 1); exit 1; }; } srcdir=`echo "$srcdir" | sed 's%\([^\\/]\)[\\/]*$%\1%'` @@ -1931,6 +1931,15 @@ function appendCXX { CXXFLAGS=$* fi } + +function appendLD { + if test "$LDFLAGS" != ""; then + LDFLAGS="$LDFLAGS $*" + else + LDFLAGS=$* + fi +} + if `echo $host_os | grep -i 'freebsd' >/dev/null 2>/dev/null`; then appendInc -I/usr/local/include appendLib -L/usr/local/lib -lcompat @@ -3325,7 +3334,7 @@ fi MODFLAGS="$CXXFLAGS" else MODFLAGS="$CXXFLAGS" - appendCXX -rdynamic + appendLD -Wl,--export-dynamic fi MODFLAGS="$MODFLAGS -I`pwd`" MODTARGET="modules" @@ -3435,6 +3444,7 @@ VERSION=`grep '#define VERSION' main.h | awk '{print $3}'` + ac_config_files="$ac_config_files Makefile" ac_config_files="$ac_config_files znc-config" diff --git a/configure.in b/configure.in index 165c4a55..cf2d6977 100644 --- a/configure.in +++ b/configure.in @@ -27,6 +27,15 @@ function appendCXX { CXXFLAGS=$* fi } + +function appendLD { + if test "$LDFLAGS" != ""; then + LDFLAGS="$LDFLAGS $*" + else + LDFLAGS=$* + fi +} + if `echo $host_os | grep -i 'freebsd' >/dev/null 2>/dev/null`; then appendInc -I/usr/local/include appendLib -L/usr/local/lib -lcompat @@ -83,7 +92,7 @@ if test "$MODULES" = "yes"; then MODFLAGS="$CXXFLAGS" else MODFLAGS="$CXXFLAGS" - appendCXX -rdynamic + appendLD -Wl,--export-dynamic fi MODFLAGS="$MODFLAGS -I`pwd`" MODTARGET="modules" @@ -116,6 +125,7 @@ VERSION=`grep '#define VERSION' main.h | awk '{print $3}'` AC_SUBST([CXXFLAGS]) AC_SUBST([MODFLAGS]) +AC_SUBST([LDFLAGS]) AC_SUBST([INCLUDES]) AC_SUBST([LIBS]) AC_SUBST([MODULES]) diff --git a/docs/Configuration.html b/docs/Configuration.html index 5dd8c6ab..522ede7d 100644 --- a/docs/Configuration.html +++ b/docs/Configuration.html @@ -18,17 +18,18 @@ File Locations
    -
  • Config - ZNC gets its configuration by reading the file ~/.znc/znc.conf +
  • Config - ZNC gets its configuration by reading the file ~/.znc/znc.conf. See znc --help and znc --makeconf.
  • Misc - Other files are also stored in the ~/.znc directory such as the SSL cert (znc.pem) and PidFile (znc.pid).
  • Local Modules - Stored in ~/.znc/modules. ZNC will look in the local module dir first when trying to load a module.
  • Global Modules - Stored in /usr/share/znc/modules by default. -
  • Binaries - znc and znc-config are stored in /usr/bin by default. You can change this when you configure by using ./configure --prefix=/whatever/path/you/want +
  • Binaries - znc, znc-config and znc-buildmod are stored in /usr/bin by default. You can change this when you configure by using ./configure --prefix=/whatever/path/you/want

Config File - (~/.znc/znc.conf)

    -
  • ListenPort - The port that ZNC will listen on. If the port is prepended with a '+' then ZNC listens using ssl. +
  • Listen - The port that ZNC will listen on. If the port is prepended with a '+' then ZNC listens using ssl. If you want to listen on a specific ip, use the address as first argument and the port as second. +
  • Listen6 - The same as Listen, but uses IPv6 instead of IPv4.
  • ISpoofFile - ZNC will write the ident of the user trying to connect to this file. Very useful if your shell supports oidentd.
  • PidFile - The pid file that is created when znc starts.
  • StatusPrefix - The prefix for the status and module queries. diff --git a/docs/WritingModules.html b/docs/WritingModules.html index 037df4e0..2d26520c 100644 --- a/docs/WritingModules.html +++ b/docs/WritingModules.html @@ -33,7 +33,7 @@
  • g++ `znc-config --cflags` `znc-config --include` `znc-config --libs` -shared -o example.so example.cpp
-
  • Place the .so file into your ~/.znc/modules directory !!!WARNING!!! if you overwrite a .so file while znc has it loaded it can and probably will crash znc, /msg *status unloadmod foo first! +
  • Place the .so file into your ~/.znc/modules directory. You can load it with /msg *status loadmod foo. If you overwrite a .so file while znc has it loaded it can crash znc, /msg *status unloadmod foo first!

    Code diff --git a/main.cpp b/main.cpp index 7868162b..9cad0087 100644 --- a/main.cpp +++ b/main.cpp @@ -9,15 +9,16 @@ #include "MD5.h" static struct option g_LongOpts[] = { - { "help", 0, NULL, 'h' }, - { "version", 0, NULL, 'v' }, - { "makeconf", 0, NULL, 'c' }, - { "makepass", 0, NULL, 's' }, + { "help", no_argument, 0, 'h' }, + { "version", no_argument, 0, 'v' }, + { "makeconf", no_argument, 0, 'c' }, + { "makepass", no_argument, 0, 's' }, #ifdef HAVE_LIBSSL - { "makepem", 0, NULL, 'p' }, - { "encrypt-pem", 0, NULL, 'e' }, + { "makepem", no_argument, 0, 'p' }, + { "encrypt-pem", no_argument, 0, 'e' }, #endif /* HAVE_LIBSSL */ - { NULL } + { "datadir", required_argument, 0, 'd' }, + { 0, 0, 0, 0 } }; void GenerateHelp(const char *appname) { @@ -31,6 +32,7 @@ void GenerateHelp(const char *appname) { CUtils::PrintMessage("\t-p, --makepem Generates a pemfile for use with SSL"); CUtils::PrintMessage("\t-e, --encrypt-pem when used along with --makepem, encrypts the private key in the pemfile"); #endif /* HAVE_LIBSSL */ + CUtils::PrintMessage("\t-d, --datadir Set a different znc repository"); } void die(int sig) { @@ -51,6 +53,7 @@ void die(int sig) { int main(int argc, char** argv, char** envp) { CString sConfig; + CString sDataDir = ""; #ifdef HAVE_LIBSSL InitSSL(); @@ -63,10 +66,10 @@ int main(int argc, char** argv, char** envp) { bool bMakePem = false; bool bEncPem = false; - while ((iArg = getopt_long(argc, argv, "hvcspe", g_LongOpts, &iOptIndex)) != -1) { + while ((iArg = getopt_long(argc, argv, "hvcsped:", g_LongOpts, &iOptIndex)) != -1) { #else - while ((iArg = getopt_long(argc, argv, "hvcs", g_LongOpts, &iOptIndex)) != -1) { + while ((iArg = getopt_long(argc, argv, "hvcsd:", g_LongOpts, &iOptIndex)) != -1) { #endif /* HAVE_LIBSSL */ switch (iArg) { case 'h': @@ -89,6 +92,9 @@ int main(int argc, char** argv, char** envp) { bEncPem = true; break; #endif /* HAVE_LIBSSL */ + case 'd': + sDataDir = CString(optarg); + break; case '?': default: GenerateHelp(argv[0]); @@ -104,7 +110,7 @@ int main(int argc, char** argv, char** envp) { if (bMakeConf) { CZNC& ZNC = CZNC::Get(); - ZNC.InitDirs(""); + ZNC.InitDirs("", sDataDir); if (ZNC.WriteNewConfig(sConfig)) { char* args[3]; @@ -134,7 +140,7 @@ int main(int argc, char** argv, char** envp) { #ifdef HAVE_LIBSSL if (bMakePem) { CZNC* pZNC = &CZNC::Get(); - pZNC->InitDirs(""); + pZNC->InitDirs("", sDataDir); pZNC->WritePemFile( bEncPem ); delete pZNC; @@ -155,7 +161,7 @@ int main(int argc, char** argv, char** envp) { } CZNC* pZNC = &CZNC::Get(); - pZNC->InitDirs(((argc) ? argv[0] : "")); + pZNC->InitDirs(((argc) ? argv[0] : ""), sDataDir); if (!pZNC->ParseConfig(sConfig)) { CUtils::PrintError("Unrecoverable config error."); diff --git a/modules/awaynick.cpp b/modules/awaynick.cpp index 4a07b7af..c7c8ca99 100644 --- a/modules/awaynick.cpp +++ b/modules/awaynick.cpp @@ -117,6 +117,19 @@ public: PutModule(sMsg); } + } else if (sCommand.Token(0).CaseCmp("SHOW") == 0) { + if (m_pUser) { + CString sExpanded = GetAwayNick(); + CString sMsg = "AwayNick is set to [" + m_sFormat + "]"; + + if (m_sFormat != sExpanded) { + sMsg += " (" + sExpanded + ")"; + } + + PutModule(sMsg); + } + } else if(sCommand.Token(0).CaseCmp("HELP") == 0) { + PutModule("Commands are: show, timers, set [awaynick]"); } } @@ -125,7 +138,7 @@ public: CIRCSock* pIRCSock = m_pUser->GetIRCSock(); if (pIRCSock) { - pIRCSock->GetMaxNickLen(); + uLen = pIRCSock->GetMaxNickLen(); } return m_pUser->ExpandString(m_sFormat).Left(uLen); diff --git a/modules/perform.cpp b/modules/perform.cpp index 8100609a..40f349b1 100644 --- a/modules/perform.cpp +++ b/modules/perform.cpp @@ -35,12 +35,13 @@ public: if(sPerf.Left(1) == "/") sPerf.LeftChomp(); - if(sPerf.Token(0).AsUpper() == "MSG") { + if(sPerf.Token(0).CaseCmp("MSG") == 0) { sPerf = "PRIVMSG " + sPerf.Token(1, true); } - if(sPerf.Token(0).AsUpper() == "PRIVMSG" || - sPerf.Token(0).AsUpper() == "NOTICE") { + if((sPerf.Token(0).CaseCmp("PRIVMSG") == 0 || + sPerf.Token(0).CaseCmp("NOTICE") == 0) && + sPerf.Token(2).Left(1) != ":") { sPerf = sPerf.Token(0) + " " + sPerf.Token(1) + " :" + sPerf.Token(2, true); } @@ -64,9 +65,14 @@ public: } else if(sCmdName == "list") { int i = 1; + CString sExpanded; for(VCString::iterator it = m_vPerform.begin(); it != m_vPerform.end(); it++, i++) { - PutModule(CString( i ) + ": " + *it); + sExpanded = GetUser()->ExpandString( *it ); + if(sExpanded != *it) + PutModule(CString( i ) + ": " + *it + " (" + sExpanded + ")"); + else + PutModule(CString( i ) + ": " + *it); } PutModule(" -- End of List"); } else if(sCmdName == "save") @@ -86,7 +92,7 @@ public: for( VCString::iterator it = m_vPerform.begin(); it != m_vPerform.end(); it++) { - PutIRC(*it); + PutIRC( GetUser()->ExpandString( *it ) ); } } diff --git a/modules/webadmin.cpp b/modules/webadmin.cpp index 435ac59a..eb2e345f 100644 --- a/modules/webadmin.cpp +++ b/modules/webadmin.cpp @@ -115,10 +115,27 @@ public: return true; } - virtual bool OnLoad(const CString& sArgs) { + virtual bool OnLoad(const CString& sArgStr) { bool bSSL = false; + bool bIPv6 = false; + CString sArgs(sArgStr); + CString sOpt; CString sPort; + if (sArgs.Left(1) == "-") { + sOpt = sArgs.Token(0); + sArgs = sArgs.Token(1, true); + + if (sOpt.CaseCmp("-IPV6") == 0) { + bIPv6 = true; + } else if (sOpt.CaseCmp("-IPV4") == 0) { + bIPv6 = false; + } else { + CUtils::PrintMessage("Unknown option [" + sOpt + "] valid options are -ipv4 or -ipv6", true); + return false; + } + } + if (sArgs.find(" ") != CString::npos) { m_sListenHost = sArgs.Token(0); sPort = sArgs.Token(1); @@ -146,7 +163,7 @@ public: } #endif - return m_pManager->ListenHost(m_uPort, "WebAdmin::Listener", m_sListenHost, bSSL, SOMAXCONN, pListenSock); + return m_pManager->ListenHost(m_uPort, "WebAdmin::Listener", m_sListenHost, bSSL, SOMAXCONN, pListenSock, 0, bIPv6); } void AddSock(CWebAdminSock* pSock) { diff --git a/znc-0.000.ebuild b/znc-0.000.ebuild index 234a45c9..7fcb54ce 100644 --- a/znc-0.000.ebuild +++ b/znc-0.000.ebuild @@ -1,4 +1,4 @@ -# Copyright 1999-2005 Gentoo Foundation +# Copyright 1999-2007 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # $Header$ @@ -10,34 +10,29 @@ SRC_URI="mirror://sourceforge/${PN}/${P}.tar.gz" LICENSE="GPL-2" SLOT="0" -KEYWORDS="x86 amd64 ~sparc" -IUSE="ssl ipv6 nomodules debug" -RESTRICT="nostrip" +KEYWORDS="~amd64 ~sparc ~x86 ~x86-fbsd" +IUSE="ssl ipv6 modules debug perl sasl" -RDEPEND="virtual/libc" -DEPEND="virtual/libc - >=sys-devel/gcc-3.2.3-r4 - ssl? ( >=dev-libs/openssl-0.9.7d )" - -src_unpack() { - unpack ${A} || die "unpack failed" -} +DEPEND="ssl? ( >=dev-libs/openssl-0.9.7d ) + perl? ( dev-lang/perl ) + sasl? ( dev-libs/cyrus-sasl )" +RDEPEND="${DEPEND}" src_compile() { - local MY_CONFARGS="" - - use ssl || MY_CONFARGS="${MY_CONFARGS} --disable-openssl" - use ipv6 && MY_CONFARGS="${MY_CONFARGS} --enable-ipv6" - use nomodules && MY_CONFARGS="${MY_CONFARGS} --disable-modules" - use debug && MY_CONFARGS="${MY_CONFARGS} --enable-debug" - - econf ${MY_CONFARGS} || die "econf failed" - emake CFLAGS="${CFLAGS}" || die "emake failed" + econf \ + $(use_enable ssl openssl) \ + $(use_enable ipv6) \ + $(use_enable modules) \ + $(use_enable debug) \ + $(use_enable perl) \ + $(use_enable sasl) \ + || die "econf failed" + emake || die "emake failed" } src_install() { - make install DESTDIR=${D} - dodoc docs/*.html || die "dodoc failed" + make install DESTDIR="${D}" || die "make install failed." + dohtml docs/*.html || die "dohtml failed" dodoc AUTHORS znc.conf || die "dodoc failed" } diff --git a/znc.cpp b/znc.cpp index 0e9f1c9e..8d4efd7a 100644 --- a/znc.cpp +++ b/znc.cpp @@ -19,11 +19,14 @@ CZNC::CZNC() { #ifdef _MODULES m_pModules = new CGlobalModules(); #endif - m_bISpoofLocked = false; + m_pISpoofLockFile = NULL; SetISpoofFormat(""); // Set ISpoofFormat to default } CZNC::~CZNC() { + if(m_pISpoofLockFile) + ReleaseISpoof(); + #ifdef _MODULES m_pModules->UnloadAll(); @@ -115,7 +118,7 @@ int CZNC::Loop() { m_Manager.Loop(); - if (m_bISpoofLocked) { + if (m_pISpoofLockFile != NULL) { continue; } @@ -135,7 +138,7 @@ int CZNC::Loop() { CIRCSock* pIRCSock = (CIRCSock*) m_Manager.FindSockByName(sSockName); - if (!pIRCSock) { + if (!pIRCSock && pUser->HasServers()) { if (pUser->ConnectPaused() && pUser->IsLastServer()) { continue; } @@ -146,24 +149,10 @@ int CZNC::Loop() { continue; } - if (!m_sISpoofFile.empty()) { - CFile File(m_sISpoofFile); - - if (File.Open(O_RDONLY)) { - char buf[1024]; - memset((char*) buf, 0, 1024); - File.Read(buf, 1023); - File.Close(); - m_sOrigISpoof = buf; - } - - if (File.Open(O_WRONLY | O_TRUNC | O_CREAT)) { - CString sData = m_sISpoofFormat.Token(0, false, "%") + pUser->GetIdent() + m_sISpoofFormat.Token(1, true, "%"); - File.Write(sData + "\n"); - File.Close(); - } - - m_bISpoofLocked = true; + if(!WriteISpoof(pUser)) { + DEBUG_ONLY(cout << "ISpoof could not be written" << endl); + pUser->PutStatus("ISpoof could not be written, retrying..."); + continue; } DEBUG_ONLY(cout << "User [" << pUser->GetUserName() << "] is connecting to [" << pServer->GetName() << ":" << pServer->GetPort() << "] ..." << endl); @@ -190,19 +179,53 @@ int CZNC::Loop() { return 0; } -void CZNC::ReleaseISpoof() { - if (!m_sISpoofFile.empty()) { - CFile File(m_sISpoofFile); +bool CZNC::WriteISpoof(CUser* pUser) { + if(m_pISpoofLockFile != NULL) + return false; - if (File.Open(O_WRONLY | O_TRUNC | O_CREAT)) { + if (!m_sISpoofFile.empty()) { + m_pISpoofLockFile = new CLockFile; + if(!m_pISpoofLockFile->TryExLock(m_sISpoofFile, 50, true)) { + delete m_pISpoofLockFile; + m_pISpoofLockFile = NULL; + return false; + } + + CFile File(m_pISpoofLockFile->GetFD(), m_pISpoofLockFile->GetFileName()); + + char buf[1024]; + memset((char*) buf, 0, 1024); + File.Read(buf, 1023); + m_sOrigISpoof = buf; + + if (!File.Seek(0) || !File.Truncate()) { + delete m_pISpoofLockFile; + m_pISpoofLockFile = NULL; + return false; + } + + CString sData = m_sISpoofFormat.Token(0, false, "%") + pUser->GetIdent() + m_sISpoofFormat.Token(1, true, "%"); + File.Write(sData + "\n"); + } + return true; +} + +void CZNC::ReleaseISpoof() { + if(m_pISpoofLockFile == NULL) + return; + + if (!m_sISpoofFile.empty()) { + CFile File(m_pISpoofLockFile->GetFD(), m_pISpoofLockFile->GetFileName()); + + if (File.Seek(0) && File.Truncate()) { File.Write(m_sOrigISpoof); - File.Close(); } m_sOrigISpoof = ""; } - m_bISpoofLocked = false; + delete m_pISpoofLockFile; + m_pISpoofLockFile = NULL; } bool CZNC::WritePidFile(int iPid) { @@ -289,7 +312,7 @@ bool CZNC::IsHostAllowed(const CString& sHostMask) { return false; } -void CZNC::InitDirs(const CString& sArgvPath) { +void CZNC::InitDirs(const CString& sArgvPath, const CString& sDataDir) { char buf[PATH_MAX]; getcwd(buf, PATH_MAX); @@ -308,7 +331,11 @@ void CZNC::InitDirs(const CString& sArgvPath) { m_sHomePath = m_sCurPath; } - m_sZNCPath = m_sHomePath + "/.znc"; + if (sDataDir.empty()) { + m_sZNCPath = m_sHomePath + "/.znc"; + } else { + m_sZNCPath = sDataDir; + } // Other dirs that we use m_sConfPath = m_sZNCPath + "/configs"; @@ -1090,6 +1117,10 @@ bool CZNC::ParseConfig(const CString& sConfig) { m_sISpoofFormat = sValue; continue; } else if (sName.CaseCmp("ISpoofFile") == 0) { + if(sValue.Left(2) == "~/") { + sValue.LeftChomp(2); + sValue = GetHomePath() + "/" + sValue; + } m_sISpoofFile = sValue; continue; } else if (sName.CaseCmp("MOTD") == 0) { diff --git a/znc.h b/znc.h index f2617727..3a9abf36 100644 --- a/znc.h +++ b/znc.h @@ -88,13 +88,14 @@ public: void DeleteUsers(); int Loop(); + bool WriteISpoof(CUser* pUser); void ReleaseISpoof(); bool WritePidFile(int iPid); CUser* GetUser(const CString& sUser); Csock* FindSockByName(const CString& sSockName); bool ParseConfig(const CString& sConfig); bool IsHostAllowed(const CString& sHostMask); - void InitDirs(const CString& sArgvPath); + void InitDirs(const CString& sArgvPath, const CString& sDataDir); bool OnBoot(); CString ExpandConfigPath(const CString& sConfigFile); bool WriteNewConfig(const CString& sConfig); @@ -172,7 +173,7 @@ protected: VCString m_vsVHosts; VCString m_vsMotd; CLockFile m_LockFile; - bool m_bISpoofLocked; + CLockFile* m_pISpoofLockFile; map::iterator m_itUserIter; // This needs to be reset to m_msUsers.begin() if anything is added or removed to the map #ifdef _MODULES CGlobalModules* m_pModules; @@ -219,7 +220,7 @@ public: } #endif - return CZNC::Get().GetManager().ListenHost(m_uPort, "_LISTENER", m_sBindHost, bSSL, SOMAXCONN, pClient, m_bIPV6); + return CZNC::Get().GetManager().ListenHost(m_uPort, "_LISTENER", m_sBindHost, bSSL, SOMAXCONN, pClient, 0, m_bIPV6); } private: protected: