From aaec84a317acb0b280f335d4d23eb4cc37c67311 Mon Sep 17 00:00:00 2001 From: prozacx Date: Sun, 9 Oct 2005 08:40:40 +0000 Subject: [PATCH] Added preliminary support for multiple clients per user git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@547 726aef4b-f618-498e-8847-2d620e286838 --- Chan.cpp | 23 +++--- Chan.h | 4 +- IRCSock.cpp | 174 ++++++++++++----------------------------- IRCSock.h | 11 --- Modules.cpp | 11 ++- Modules.h | 4 + User.cpp | 192 ++++++++++++++++++++++++++++++++++------------ User.h | 36 +++++++-- UserSock.cpp | 29 ++++++- main.h | 2 +- modules/shell.cpp | 11 ++- znc.cpp | 16 +--- 12 files changed, 283 insertions(+), 230 deletions(-) diff --git a/Chan.cpp b/Chan.cpp index 8e94bb58..58f82191 100644 --- a/Chan.cpp +++ b/Chan.cpp @@ -64,7 +64,7 @@ void CChan::Cycle() const { m_pUser->PutIRC("PART " + GetName() + "\r\nJOIN " + GetName() + " " + GetKey()); } -void CChan::JoinUser(bool bForce, const CString& sKey) { +void CChan::JoinUser(bool bForce, const CString& sKey, CUserSock* pUserSock) { if (!bForce && (!IsOn() || !IsDetached())) { IncClientRequests(); @@ -72,11 +72,11 @@ void CChan::JoinUser(bool bForce, const CString& sKey) { return; } - m_pUser->PutUser(":" + m_pUser->GetIRCNick().GetNickMask() + " JOIN :" + GetName()); + m_pUser->PutUser(":" + m_pUser->GetIRCNick().GetNickMask() + " JOIN :" + GetName(), pUserSock); if (!GetTopic().empty()) { - m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 332 " + m_pUser->GetIRCNick().GetNick() + " " + GetName() + " :" + GetTopic()); - m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 333 " + m_pUser->GetIRCNick().GetNick() + " " + GetName() + " " + GetTopicOwner() + " " + CString::ToString(GetTopicDate())); + m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 332 " + m_pUser->GetIRCNick().GetNick() + " " + GetName() + " :" + GetTopic(), pUserSock); + m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 333 " + m_pUser->GetIRCNick().GetNick() + " " + GetName() + " " + GetTopicOwner() + " " + CString::ToString(GetTopicDate()), pUserSock); } CString sPre = ":" + m_pUser->GetIRCServer() + " 353 " + m_pUser->GetIRCNick().GetNick() + " = " + GetName() + " :"; @@ -91,35 +91,32 @@ void CChan::JoinUser(bool bForce, const CString& sKey) { sLine += a->first; if (sLine.size() >= 490 || a == (--m_msNicks.end())) { - m_pUser->PutUser(sLine); + m_pUser->PutUser(sLine, pUserSock); sLine = sPre; } else { sLine += " "; } } - m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 366 " + m_pUser->GetIRCNick().GetNick() + " " + GetName() + " :End of /NAMES list."); - SendBuffer(); - + m_pUser->PutUser(":" + m_pUser->GetIRCServer() + " 366 " + m_pUser->GetIRCNick().GetNick() + " " + GetName() + " :End of /NAMES list.", pUserSock); m_bDetached = false; -} -void CChan::SendBuffer() { + // Send Buffer if (m_pUser->IsUserAttached()) { const vector& vsBuffer = GetBuffer(); if (vsBuffer.size()) { - m_pUser->PutUser(":***!znc@znc.com PRIVMSG " + GetName() + " :Buffer Playback..."); + m_pUser->PutUser(":***!znc@znc.com PRIVMSG " + GetName() + " :Buffer Playback...", pUserSock); for (unsigned int a = 0; a < vsBuffer.size(); a++) { - m_pUser->PutUser(vsBuffer[a]); + m_pUser->PutUser(vsBuffer[a], pUserSock); } if (!KeepBuffer()) { ClearBuffer(); } - m_pUser->PutUser(":***!znc@znc.com PRIVMSG " + GetName() + " :Playback Complete."); + m_pUser->PutUser(":***!znc@znc.com PRIVMSG " + GetName() + " :Playback Complete.", pUserSock); } } } diff --git a/Chan.h b/Chan.h index bbd48306..0109b952 100644 --- a/Chan.h +++ b/Chan.h @@ -5,6 +5,7 @@ #include "Nick.h" #include "String.h" #include "FileUtils.h" +#include "UserSock.h" #include #include #include @@ -48,10 +49,9 @@ public: bool WriteConfig(CFile& File); void Joined(); void Cycle() const; - void JoinUser(bool bForce = false, const CString& sKey = ""); + void JoinUser(bool bForce = false, const CString& sKey = "", CUserSock* pUserSock = NULL); void DetachUser(); void AttachUser(); - void SendBuffer(); void IncClientRequests(); bool DecClientRequests(); diff --git a/IRCSock.cpp b/IRCSock.cpp index 505b16ac..5ff66dbe 100644 --- a/IRCSock.cpp +++ b/IRCSock.cpp @@ -7,16 +7,12 @@ CIRCSock::CIRCSock(CUser* pUser) : Csock() { m_pUser = pUser; - m_pUserSock = NULL; m_pAwayNickTimer = NULL; - m_uQueryBufferCount = 50; m_bISpoofReleased = false; m_bKeepNick = true; m_bAuthed = false; m_bOrigNickPending = false; EnableReadLine(); - m_RawBuffer.SetLineCount(100); // This should be more than enough raws, especially since we are buffering the MOTD separately - m_MotdBuffer.SetLineCount(200); // This should be more than enough motd lines m_Nick.SetIdent(pUser->GetIdent()); m_Nick.SetHost(pUser->GetVHost()); @@ -41,10 +37,7 @@ CIRCSock::~CIRCSock() { vChans[a]->Reset(); } - if (m_pUserSock) { - m_pUserSock->IRCDisconnected(); - m_pUserSock = NULL; - } + m_pUser->IRCDisconnected(); for (map::iterator a = m_msChans.begin(); a != m_msChans.end(); a++) { delete a->second; @@ -103,18 +96,22 @@ void CIRCSock::ReadLine(const CString& sData) { m_bAuthed = true; m_pUser->PutStatus("Connected!"); - if (m_pUserSock) { - CString sClientNick = m_pUserSock->GetNick(); + vector& vUserSocks = m_pUser->GetUserSocks(); + + for (unsigned int a = 0; a < vUserSocks.size(); a++) { + CUserSock* pUserSock = vUserSocks[a]; + CString sClientNick = pUserSock->GetNick(); + if (sClientNick.CaseCmp(sNick) != 0) { // If they connected with a nick that doesn't match the one we got on irc, then we need to update them - PutUser(":" + sClientNick + "!" + m_Nick.GetIdent() + "@" + m_Nick.GetHost() + " NICK :" + sNick); + pUserSock->PutServ(":" + sClientNick + "!" + m_Nick.GetIdent() + "@" + m_Nick.GetHost() + " NICK :" + sNick); } } SetNick(sNick); - m_RawBuffer.Clear(); - m_RawBuffer.AddLine(":" + sServer + " " + sCmd + " ", " " + sRest); + m_pUser->ClearRawBuffer(); + m_pUser->AddRawBuffer(":" + sServer + " " + sCmd + " ", " " + sRest); // Now that we are connected, we need to join our chans const vector& vChans = m_pUser->GetChans(); @@ -140,18 +137,18 @@ void CIRCSock::ReadLine(const CString& sData) { case 255: // client count case 265: // local users case 266: // global users - m_RawBuffer.AddLine(":" + sServer + " " + sCmd + " ", " " + sRest); + m_pUser->AddRawBuffer(":" + sServer + " " + sCmd + " ", " " + sRest); break; case 375: // begin motd - m_MotdBuffer.Clear(); + m_pUser->ClearMotdBuffer(); case 372: // motd case 376: // end motd - m_MotdBuffer.AddLine(":" + sServer + " " + sCmd + " ", " " + sRest); + m_pUser->AddMotdBuffer(":" + sServer + " " + sCmd + " ", " " + sRest); break; case 471: // :irc.server.net 471 nick #chan :Cannot join channel (+l) case 473: // :irc.server.net 473 nick #chan :Cannot join channel (+i) case 475: // :irc.server.net 475 nick #chan :Cannot join channel (+k) - if (m_pUserSock) { + if (m_pUser->IsUserAttached()) { CChan* pChan = m_pUser->FindChan(sRest.substr(0, sRest.find(' '))); if ((pChan) && (!pChan->IsOn())) { @@ -207,9 +204,15 @@ void CIRCSock::ReadLine(const CString& sData) { // :irc.server.net 433 mynick badnick :Nickname is already in use. if ((m_bKeepNick) && (m_pUser->GetKeepNick())) { if (sBadNick.CaseCmp(sConfNick) == 0) { - if ((!m_pUserSock) || (!m_pUserSock->DecKeepNickCounter())) { - SetOrigNickPending(false); - return; + vector& vUserSocks = m_pUser->GetUserSocks(); + + for (unsigned int a = 0; a < vUserSocks.size(); a++) { + CUserSock* pUserSock = vUserSocks[a]; + + if (!pUserSock || !pUserSock->DecKeepNickCounter()) { + SetOrigNickPending(false); + return; + } } } } @@ -311,27 +314,27 @@ void CIRCSock::ReadLine(const CString& sData) { } break; case 366: { // end of names list - PutUser(sLine); // First send them the raw + m_pUser->PutUser(sLine); // First send them the raw // :irc.server.com 366 nick #chan :End of /NAMES list. CChan* pChan = m_pUser->FindChan(sRest.Token(0)); if (pChan) { - if (IsUserAttached()) { + if (m_pUser->IsUserAttached()) { const vector& vsBuffer = pChan->GetBuffer(); if (vsBuffer.size()) { - PutUser(":***!znc@znc.com PRIVMSG " + pChan->GetName() + " :Buffer Playback..."); + m_pUser->PutUser(":***!znc@znc.com PRIVMSG " + pChan->GetName() + " :Buffer Playback..."); for (unsigned int a = 0; a < vsBuffer.size(); a++) { - PutUser(vsBuffer[a]); + m_pUser->PutUser(vsBuffer[a]); } if (!pChan->KeepBuffer()) { pChan->ClearBuffer(); } - PutUser(":***!znc@znc.com PRIVMSG " + pChan->GetName() + " :Playback Complete."); + m_pUser->PutUser(":***!znc@znc.com PRIVMSG " + pChan->GetName() + " :Playback Complete."); } } @@ -527,7 +530,7 @@ void CIRCSock::ReadLine(const CString& sData) { } } - PutUser(":" + Nick.GetNickMask() + " NOTICE " + sTarget + " :\001" + sMsg + "\001"); + m_pUser->PutUser(":" + Nick.GetNickMask() + " NOTICE " + sTarget + " :\001" + sMsg + "\001"); return; } else { if (sTarget.CaseCmp(GetNick()) == 0) { @@ -541,7 +544,7 @@ void CIRCSock::ReadLine(const CString& sData) { } } - PutUser(":" + Nick.GetNickMask() + " NOTICE " + sTarget + " :" + sMsg); + m_pUser->PutUser(":" + Nick.GetNickMask() + " NOTICE " + sTarget + " :" + sMsg); return; } else if (sCmd.CaseCmp("TOPIC") == 0) { // :nick!ident@host.com TOPIC #chan :This is a topic @@ -551,7 +554,7 @@ void CIRCSock::ReadLine(const CString& sData) { CString sTopic = sLine.Token(3, true); sTopic.LeftChomp(); pChan->SetTopicOwner(Nick.GetNick()); - pChan->SetTopicDate((unsigned long) time(NULL)); // @todo use local time + pChan->SetTopicDate((unsigned long) time(NULL)); pChan->SetTopic(sTopic); } } else if (sCmd.CaseCmp("PRIVMSG") == 0) { @@ -577,7 +580,7 @@ void CIRCSock::ReadLine(const CString& sData) { } } - PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + sTarget + " :\001" + sMsg + "\001"); + m_pUser->PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + sTarget + " :\001" + sMsg + "\001"); return; } else { if (sTarget.CaseCmp(GetNick()) == 0) { @@ -590,14 +593,14 @@ void CIRCSock::ReadLine(const CString& sData) { } } - PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + sTarget + " :" + sMsg); + m_pUser->PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + sTarget + " :" + sMsg); return; } } } } - PutUser(sLine); + m_pUser->PutUser(sLine); } void CIRCSock::KeepNick(bool bForce) { @@ -628,26 +631,26 @@ 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_pUserSock) { + 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) { - PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + GetNick() + " :\001DCC CHAT chat " + CString::ToString(CUtils::GetLongIP(GetLocalIP())) + " " + CString::ToString(uBNCPort) + "\001"); + m_pUser->PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + GetNick() + " :\001DCC CHAT chat " + CString::ToString(CUtils::GetLongIP(GetLocalIP())) + " " + CString::ToString(uBNCPort) + "\001"); } } } else if (sType.CaseCmp("SEND") == 0) { // DCC SEND readme.txt 403120438 5550 1104 unsigned short uBNCPort = CDCCBounce::DCCRequest(Nick.GetNick(), uLongIP, uPort, sFile, false, m_pUser, GetLocalIP(), CUtils::GetIP(uLongIP)); if (uBNCPort) { - PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + GetNick() + " :\001DCC SEND " + sFile + " " + CString::ToString(CUtils::GetLongIP(GetLocalIP())) + " " + CString::ToString(uBNCPort) + " " + CString::ToString(uFileSize) + "\001"); + m_pUser->PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + GetNick() + " :\001DCC SEND " + sFile + " " + CString::ToString(CUtils::GetLongIP(GetLocalIP())) + " " + CString::ToString(uBNCPort) + " " + CString::ToString(uFileSize) + "\001"); } } else if (sType.CaseCmp("RESUME") == 0) { // Need to lookup the connection by port, filter the port, and forward to the user CDCCBounce* pSock = (CDCCBounce*) CZNC::Get().GetManager().FindSockByLocalPort(atoi(sMessage.Token(3).c_str())); if ((pSock) && (strncasecmp(pSock->GetSockName().c_str(), "DCC::", 5) == 0)) { - PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + GetNick() + " :\001DCC " + sType + " " + sFile + " " + CString::ToString(pSock->GetUserPort()) + " " + sMessage.Token(4) + "\001"); + m_pUser->PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + GetNick() + " :\001DCC " + sType + " " + sFile + " " + CString::ToString(pSock->GetUserPort()) + " " + sMessage.Token(4) + "\001"); } } else if (sType.CaseCmp("ACCEPT") == 0) { // Need to lookup the connection by port, filter the port, and forward to the user @@ -658,7 +661,7 @@ bool CIRCSock::OnPrivCTCP(CNick& Nick, CString& sMessage) { if ((pSock) && (strncasecmp(pSock->GetSockName().c_str(), "DCC::", 5) == 0)) { if (pSock->GetUserPort() == atoi(sMessage.Token(3).c_str())) { - PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + GetNick() + " :\001DCC " + sType + " " + sFile + " " + CString::ToString(pSock->GetLocalPort()) + " " + sMessage.Token(4) + "\001"); + m_pUser->PutUser(":" + Nick.GetNickMask() + " PRIVMSG " + GetNick() + " :\001DCC " + sType + " " + sFile + " " + CString::ToString(pSock->GetLocalPort()) + " " + sMessage.Token(4) + "\001"); } } } @@ -675,7 +678,7 @@ bool CIRCSock::OnPrivCTCP(CNick& Nick, CString& sMessage) { sReply = it->second; } - if (sReply.empty() && sQuery == "VERSION" && !IsUserAttached()) { + if (sReply.empty() && sQuery == "VERSION" && !m_pUser->IsUserAttached()) { sReply = "ZNC by prozac - http://znc.sourceforge.net"; } @@ -691,9 +694,9 @@ bool CIRCSock::OnPrivCTCP(CNick& Nick, CString& sMessage) { bool CIRCSock::OnPrivNotice(CNick& Nick, CString& sMessage) { MODULECALL(OnPrivNotice(Nick, sMessage)); - if (!m_pUserSock) { + if (!m_pUser->IsUserAttached()) { // If the user is detached, add to the buffer - m_QueryBuffer.AddLine(":" + Nick.GetNickMask() + " NOTICE ", " :" + sMessage); + m_pUser->AddQueryBuffer(":" + Nick.GetNickMask() + " NOTICE ", " :" + sMessage); } return false; @@ -702,9 +705,9 @@ bool CIRCSock::OnPrivNotice(CNick& Nick, CString& sMessage) { bool CIRCSock::OnPrivMsg(CNick& Nick, CString& sMessage) { MODULECALL(OnPrivMsg(Nick, sMessage)); - if (!m_pUserSock) { + if (!m_pUser->IsUserAttached()) { // If the user is detached, add to the buffer - m_QueryBuffer.AddLine(":" + Nick.GetNickMask() + " PRIVMSG ", " :" + sMessage); + m_pUser->AddQueryBuffer(":" + Nick.GetNickMask() + " PRIVMSG ", " :" + sMessage); } return false; @@ -728,7 +731,7 @@ bool CIRCSock::OnChanNotice(CNick& Nick, const CString& sChan, CString& sMessage if (pChan) { MODULECALL(OnChanNotice(Nick, *pChan, sMessage)); - if ((pChan->KeepBuffer()) || (!m_pUserSock)) { + if ((pChan->KeepBuffer()) || (!m_pUser->IsUserAttached())) { pChan->AddBuffer(":" + Nick.GetNickMask() + " NOTICE " + sChan + " :" + sMessage); } } @@ -741,7 +744,7 @@ bool CIRCSock::OnChanMsg(CNick& Nick, const CString& sChan, CString& sMessage) { if (pChan) { MODULECALL(OnChanMsg(Nick, *pChan, sMessage)); - if ((pChan->KeepBuffer()) || (!m_pUserSock)) { + if (pChan->KeepBuffer() || !m_pUser->IsUserAttached()) { pChan->AddBuffer(":" + Nick.GetNickMask() + " PRIVMSG " + sChan + " :" + sMessage); } } @@ -749,98 +752,19 @@ bool CIRCSock::OnChanMsg(CNick& Nick, const CString& sChan, CString& sMessage) { return ((pChan) && (pChan->IsDetached())); } -void CIRCSock::UserConnected(CUserSock* pUserSock) { - if (m_pUserSock) { - m_pUserSock->BouncedOff(); - } - - m_pUserSock = pUserSock; - CString sConfNick = m_pUser->GetNick(); - - if (GetNick().CaseCmp(CNick::Concat(sConfNick, m_pUser->GetAwaySuffix(), GetMaxNickLen())) == 0) { - PutServ("NICK " + sConfNick); - } - - if (m_RawBuffer.IsEmpty()) { - PutUser(":irc.znc.com 001 " + m_pUserSock->GetNick() + " :- Welcome to ZNC -"); - } else { - unsigned int uIdx = 0; - CString sLine; - - while (m_RawBuffer.GetLine(GetNick(), sLine, uIdx++)) { - PutUser(sLine); - } - } - - // Send the cached MOTD - if (m_MotdBuffer.IsEmpty()) { - PutServ("MOTD"); - } else { - unsigned int uIdx = 0; - CString sLine; - - while (m_MotdBuffer.GetLine(GetNick(), sLine, uIdx++)) { - PutUser(sLine); - } - } - - const vector& vChans = m_pUser->GetChans(); - for (unsigned int a = 0; a < vChans.size(); a++) { - if ((vChans[a]->IsOn()) && (!vChans[a]->IsDetached())) { - vChans[a]->JoinUser(true); - } - } - - CString sBufLine; - while (m_QueryBuffer.GetNextLine(GetNick(), sBufLine)) { - PutUser(sBufLine); - } -} - -void CIRCSock::UserDisconnected() { - if (m_pUserSock && !m_pAwayNickTimer) { - m_pAwayNickTimer = new CAwayNickTimer(m_pUser); - CZNC::Get().GetManager().AddCron(m_pAwayNickTimer); - } - - m_pUserSock = NULL; -} - void CIRCSock::PutServ(const CString& sLine) { DEBUG_ONLY(cout << GetSockName() << " -> [" << sLine << "]" << endl); Write(sLine + "\r\n"); } -void CIRCSock::PutUser(const CString& sLine) { - if (m_pUserSock) { - m_pUserSock->PutServ(sLine); - } -} - -void CIRCSock::PutStatus(const CString& sLine) { - if (m_pUserSock) { - m_pUserSock->PutStatus(sLine); - } -} - void CIRCSock::SetNick(const CString& sNick) { m_Nick.SetNick(sNick); m_pUser->SetIRCNick(m_Nick); - - if (m_pUserSock) { - m_pUserSock->SetNick(sNick); - } } void CIRCSock::Connected() { DEBUG_ONLY(cout << GetSockName() << " == Connected()" << endl); - - CUserSock* pUserSock = (CUserSock*) CZNC::Get().FindSockByName("USR::" + m_pUser->GetUserName()); - - if (pUserSock) { - m_pUserSock = pUserSock; - pUserSock->IRCConnected(this); - } + m_pUser->IRCConnected(this); if (!m_sPass.empty()) { PutServ("PASS " + m_sPass); @@ -889,7 +813,9 @@ void CIRCSock::ParseISupport(const CString& sLine) { m_sPerms = sPrefixes; m_sPermModes = sPermModes; } - } else if (sName.CaseCmp("CHANMODES") == 0) { + } else if (sName.CaseCmp("CHANTYPES") == 0) { + m_pUser->SetChanPrefixes(sValue); + } else if (sName.CaseCmp("NICKLEN") == 0) { unsigned int uMax = sValue.ToUInt(); if (uMax) { diff --git a/IRCSock.h b/IRCSock.h index 29b68f34..7bb5173e 100644 --- a/IRCSock.h +++ b/IRCSock.h @@ -8,7 +8,6 @@ // Forward Declarations class CZNC; -class CUserSock; class CAwayNickTimer; // !Forward Declarations @@ -42,12 +41,7 @@ public: virtual void Timeout(); void KeepNick(bool bForce = false); - bool IsUserAttached() { return (m_pUserSock != NULL); } - void UserConnected(CUserSock* pUserSock); - void UserDisconnected(); void PutServ(const CString& sLine); - void PutUser(const CString& sLine); - void PutStatus(const CString& sLine); void CIRCSock::ParseISupport(const CString& sLine); // Setters @@ -84,14 +78,9 @@ protected: CUser* m_pUser; CNick m_Nick; CString m_sPass; - CBuffer m_RawBuffer; - CBuffer m_MotdBuffer; - CUserSock* m_pUserSock; map m_msChans; unsigned int m_uMaxNickLen; - unsigned int m_uQueryBufferCount; CAwayNickTimer* m_pAwayNickTimer; - CBuffer m_QueryBuffer; }; #endif // !_IRCSOCK_H diff --git a/Modules.cpp b/Modules.cpp index 703c1d44..9d9b2835 100644 --- a/Modules.cpp +++ b/Modules.cpp @@ -164,6 +164,7 @@ CModule::CModule(void* pDLL, CUser* pUser, const CString& sModName) { m_pDLL = pDLL; m_pManager = &(CZNC::Get().GetManager());; m_pUser = pUser; + m_pUserSock = NULL; m_sModName = sModName; if (m_pUser) { @@ -177,6 +178,7 @@ CModule::CModule(void* pDLL, const CString& sModName) { m_pDLL = pDLL; m_pManager = &(CZNC::Get().GetManager()); m_pUser = NULL; + m_pUserSock = NULL; m_sModName = sModName; m_sSavePath = CZNC::Get().GetZNCPath() + "/moddata/" + m_sModName; @@ -196,6 +198,7 @@ CModule::~CModule() { } void CModule::SetUser(CUser* pUser) { m_pUser = pUser; } +void CModule::SetUserSock(CUserSock* pUserSock) { m_pUserSock = pUserSock; } void CModule::Unload() { throw UNLOAD; } bool CModule::LoadRegistry() { @@ -478,16 +481,16 @@ bool CModule::PutIRC(const CString& sLine) { return (m_pUser) ? m_pUser->PutIRC(sLine) : false; } bool CModule::PutUser(const CString& sLine) { - return (m_pUser) ? m_pUser->PutUser(sLine) : false; + return (m_pUser) ? m_pUser->PutUser(sLine, m_pUserSock) : false; } bool CModule::PutStatus(const CString& sLine) { - return (m_pUser) ? m_pUser->PutStatus(sLine) : false; + return (m_pUser) ? m_pUser->PutStatus(sLine, m_pUserSock) : false; } bool CModule::PutModule(const CString& sLine, const CString& sIdent, const CString& sHost) { - return (m_pUser) ? m_pUser->PutUser(":" + GetModNick() + "!" + sIdent + "@" + sHost + " PRIVMSG " + m_pUser->GetCurNick() + " :" + sLine) : false; + return (m_pUser) ? m_pUser->PutUser(":" + GetModNick() + "!" + sIdent + "@" + sHost + " PRIVMSG " + m_pUser->GetCurNick() + " :" + sLine, m_pUserSock) : false; } bool CModule::PutModNotice(const CString& sLine, const CString& sIdent, const CString& sHost) { - return (m_pUser) ? m_pUser->PutUser(":" + GetModNick() + "!" + sIdent + "@" + sHost + " NOTICE " + m_pUser->GetCurNick() + " :" + sLine) : false; + return (m_pUser) ? m_pUser->PutUser(":" + GetModNick() + "!" + sIdent + "@" + sHost + " NOTICE " + m_pUser->GetCurNick() + " :" + sLine, m_pUserSock) : false; } diff --git a/Modules.h b/Modules.h index 12b5cc77..f30776a3 100644 --- a/Modules.h +++ b/Modules.h @@ -3,6 +3,7 @@ #include "main.h" #include "FileUtils.h" +#include "UserSock.h" #include #include #include @@ -192,6 +193,7 @@ public: } EModException; void SetUser(CUser* pUser); + void SetUserSock(CUserSock* pUserSock); void Unload(); virtual bool OnLoad(const CString& sArgs); @@ -290,6 +292,7 @@ public: const CString& GetDescription() const { return m_sDescription; } const CString& GetArgs() const { return m_sArgs; } CUser* GetUser() { return m_pUser; } + CUserSock* GetUserSock() { return m_pUserSock; } TSocketManager* GetManager() { return m_pManager; } // !Getters @@ -301,6 +304,7 @@ protected: void* m_pDLL; TSocketManager* m_pManager; CUser* m_pUser; + CUserSock* m_pUserSock; CString m_sModName; CString m_sSavePath; CString m_sArgs; diff --git a/User.cpp b/User.cpp index 846f76e8..95d067d5 100644 --- a/User.cpp +++ b/User.cpp @@ -19,6 +19,8 @@ CUser::CUser(const CString& sUserName) { #ifdef _MODULES m_pModules = new CModules; #endif + m_RawBuffer.SetLineCount(100); // This should be more than enough raws, especially since we are buffering the MOTD separately + m_MotdBuffer.SetLineCount(200); // This should be more than enough motd lines m_bBounceDCCs = true; m_bPassHashed = false; m_bUseClientIP = false; @@ -26,6 +28,7 @@ CUser::CUser(const CString& sUserName) { m_bDenyLoadMod = false; m_bAdmin= false; m_sStatusPrefix = "*"; + m_sChanPrefixes = "#&"; m_uBufferCount = 50; m_bKeepBuffer = false; m_bAutoCycle = true; @@ -49,6 +52,10 @@ CUser::~CUser() { delete m_vChans[b]; } + for (unsigned int c = 0; c < m_vUserSocks.size(); c++) { + CZNC::Get().GetManager().DelSockByAddr(m_vUserSocks[c]); + } + CZNC::Get().GetManager().DelCronByAddr(m_pKeepNickTimer); CZNC::Get().GetManager().DelCronByAddr(m_pJoinTimer); } @@ -60,6 +67,84 @@ bool CUser::OnBoot() { return true; } +void CUser::IRCConnected(CIRCSock* pIRCSock) { + TSocketManager& Manager = CZNC::Get().GetManager(); + + for (unsigned int a = 0; a < Manager.size(); a++) { + CUserSock* pUserSock = (CUserSock*) Manager[a]; + const CString& sSockName = pUserSock->GetSockName(); + + if (sSockName == ("USR::" + GetUserName())) { + m_vUserSocks.push_back(pUserSock); + pUserSock->IRCConnected(pIRCSock); + } + } +} + +void CUser::IRCDisconnected() { + for (unsigned int a = 0; a < m_vUserSocks.size(); a++) { + m_vUserSocks[a]->IRCDisconnected(); + } +} + +void CUser::UserConnected(CUserSock* pUserSock) { + m_vUserSocks.push_back(pUserSock); + CString sConfNick = GetNick(); + + /*if (ircsock.Nick().CaseCmp(CNick::Concat(sConfNick, GetAwaySuffix(), GetMaxNickLen())) == 0) { + PutIRC("NICK " + sConfNick); + } nigs */ + + if (m_RawBuffer.IsEmpty()) { + pUserSock->PutServ(":irc.znc.com 001 " + pUserSock->GetNick() + " :- Welcome to ZNC -"); + } else { + unsigned int uIdx = 0; + CString sLine; + + while (m_RawBuffer.GetLine(GetNick(), sLine, uIdx++)) { + pUserSock->PutServ(sLine); + } + } + + // Send the cached MOTD + if (m_MotdBuffer.IsEmpty()) { + PutIRC("MOTD"); + } else { + unsigned int uIdx = 0; + CString sLine; + + while (m_MotdBuffer.GetLine(GetNick(), sLine, uIdx++)) { + pUserSock->PutServ(sLine); + } + } + + const vector& vChans = GetChans(); + for (unsigned int a = 0; a < vChans.size(); a++) { + if ((vChans[a]->IsOn()) && (!vChans[a]->IsDetached())) { + vChans[a]->JoinUser(true, "", pUserSock); + } + } + + CString sBufLine; + while (m_QueryBuffer.GetNextLine(GetNick(), sBufLine)) { + pUserSock->PutServ(sBufLine); + } +} + +void CUser::UserDisconnected(CUserSock* pUserSock) { + /*if (!m_pAwayNickTimer) { + m_pAwayNickTimer = new CAwayNickTimer(this); + CZNC::Get().GetManager().AddCron(m_pAwayNickTimer); + }*/ + + for (unsigned int a = 0; a < m_vUserSocks.size(); a++) { + if (m_vUserSocks[a] == pUserSock) { + m_vUserSocks.erase(m_vUserSocks.begin() + a); + break; + } + } +} + bool CUser::Clone(const CUser& User, CString& sErrorRet) { unsigned int a = 0; sErrorRet.clear(); @@ -99,8 +184,9 @@ bool CUser::Clone(const CUser& User, CString& sErrorRet) { AddAllowedHost(*it); } - CUserSock* pSock = GetUserSock(); - if (pSock) { + for (unsigned int a = 0; a < m_vUserSocks.size(); a++) { + CUserSock* pSock = m_vUserSocks[a]; + if (!IsHostAllowed(pSock->GetRemoteIP())) { pSock->PutStatusNotice("You are being disconnected because your IP is no longer allowed to connect to this user"); pSock->Close(); @@ -540,7 +626,7 @@ bool CUser::CheckPass(const CString& sPass) { return (m_sPass.CaseCmp((char*) CMD5(sPass)) == 0); } -CUserSock* CUser::GetUserSock() { +/*CUserSock* CUser::GetUserSock() { // Todo: optimize this by saving a pointer to the sock TSocketManager& Manager = CZNC::Get().GetManager(); CString sSockName = "USR::" + m_sUserName; @@ -555,17 +641,7 @@ CUserSock* CUser::GetUserSock() { } return (CUserSock*) CZNC::Get().GetManager().FindSockByName(sSockName); -} - -bool CUser::IsUserAttached() { - CUserSock* pUserSock = GetUserSock(); - - if (!pUserSock) { - return false; - } - - return pUserSock->IsAttached(); -} +}*/ CIRCSock* CUser::GetIRCSock() { // Todo: optimize this by saving a pointer to the sock @@ -579,10 +655,8 @@ CString CUser::GetLocalIP() { return pIRCSock->GetLocalIP(); } - CUserSock* pUserSock = GetUserSock(); - - if (pUserSock) { - return pUserSock->GetLocalIP(); + if (m_vUserSocks.size()) { + return m_vUserSocks[0]->GetLocalIP(); } return ""; @@ -599,48 +673,60 @@ bool CUser::PutIRC(const CString& sLine) { return true; } -bool CUser::PutUser(const CString& sLine) { - CUserSock* pUserSock = GetUserSock(); +bool CUser::PutUser(const CString& sLine, CUserSock* pUserSock) { + for (unsigned int a = 0; a < m_vUserSocks.size(); a++) { + if (!pUserSock || pUserSock == m_vUserSocks[a]) { + m_vUserSocks[a]->PutServ(sLine); - if (!pUserSock) { - return false; + if (pUserSock) { + return true; + } + } } - pUserSock->PutServ(sLine); - return true; + return (pUserSock == NULL); } -bool CUser::PutStatus(const CString& sLine) { - CUserSock* pUserSock = GetUserSock(); +bool CUser::PutStatus(const CString& sLine, CUserSock* pUserSock) { + for (unsigned int a = 0; a < m_vUserSocks.size(); a++) { + if (!pUserSock || pUserSock == m_vUserSocks[a]) { + m_vUserSocks[a]->PutStatus(sLine); - if (!pUserSock) { - return false; + if (pUserSock) { + return true; + } + } } - pUserSock->PutStatus(sLine); - return true; + return (pUserSock == NULL); } -bool CUser::PutStatusNotice(const CString& sLine) { - CUserSock* pUserSock = GetUserSock(); +bool CUser::PutStatusNotice(const CString& sLine, CUserSock* pUserSock) { + for (unsigned int a = 0; a < m_vUserSocks.size(); a++) { + if (!pUserSock || pUserSock == m_vUserSocks[a]) { + m_vUserSocks[a]->PutStatusNotice(sLine); - if (!pUserSock) { - return false; + if (pUserSock) { + return true; + } + } } - pUserSock->PutStatusNotice(sLine); - return true; + return (pUserSock == NULL); } -bool CUser::PutModule(const CString& sModule, const CString& sLine) { - CUserSock* pUserSock = GetUserSock(); +bool CUser::PutModule(const CString& sModule, const CString& sLine, CUserSock* pUserSock) { + for (unsigned int a = 0; a < m_vUserSocks.size(); a++) { + if (!pUserSock || pUserSock == m_vUserSocks[a]) { + m_vUserSocks[a]->PutModule(sModule, sLine); - if (!pUserSock) { - return false; + if (pUserSock) { + return true; + } + } } - pUserSock->PutModule(sModule, sLine); - return true; + return (pUserSock == NULL); } bool CUser::ResumeFile(const CString& sRemoteNick, unsigned short uPort, unsigned long uFileSize) { @@ -718,10 +804,8 @@ CString CUser::GetCurNick() { return pIRCSock->GetNick(); } - CUserSock* pUserSock = GetUserSock(); - - if (pUserSock) { - return pUserSock->GetNick(); + if (m_vUserSocks.size()) { + return m_vUserSocks[0]->GetNick(); } return ""; @@ -742,9 +826,20 @@ void CUser::SetKeepNick(bool b) { m_bKeepNick = b; } void CUser::SetDenyLoadMod(bool b) { m_bDenyLoadMod = b; } void CUser::SetAdmin(bool b) { m_bAdmin = b; } void CUser::SetDefaultChanModes(const CString& s) { m_sDefaultChanModes = s; } -void CUser::SetIRCNick(const CNick& n) { m_IRCNick = n; } void CUser::SetIRCServer(const CString& s) { m_sIRCServer = s; } void CUser::SetQuitMsg(const CString& s) { m_sQuitMsg = s; } +void CUser::SetBufferCount(unsigned int u) { m_uBufferCount = u; } +void CUser::SetKeepBuffer(bool b) { m_bKeepBuffer = b; } +void CUser::SetAutoCycle(bool b) { m_bAutoCycle = b; } + +void CUser::SetIRCNick(const CNick& n) { + m_IRCNick = n; + + for (unsigned int a = 0; a < m_vUserSocks.size(); a++) { + m_vUserSocks[a]->SetNick(n.GetNick()); + } +} + bool CUser::AddCTCPReply(const CString& sCTCP, const CString& sReply) { if (sCTCP.empty() || sReply.empty()) { return false; @@ -753,9 +848,6 @@ bool CUser::AddCTCPReply(const CString& sCTCP, const CString& sReply) { m_mssCTCPReplies[sCTCP.AsUpper()] = sReply; return true; } -void CUser::SetBufferCount(unsigned int u) { m_uBufferCount = u; } -void CUser::SetKeepBuffer(bool b) { m_bKeepBuffer = b; } -void CUser::SetAutoCycle(bool b) { m_bAutoCycle = b; } bool CUser::SetStatusPrefix(const CString& s) { if ((!s.empty()) && (s.length() < 6) && (s.find(' ') == CString::npos)) { diff --git a/User.h b/User.h index cec7ec4b..49c13edf 100644 --- a/User.h +++ b/User.h @@ -10,6 +10,7 @@ #include #include "Nick.h" #include "FileUtils.h" +#include "Buffer.h" using std::vector; using std::set; @@ -55,16 +56,29 @@ public: // !Modules #endif + // Buffers + void AddRawBuffer(const CString& sPre, const CString& sPost) { m_RawBuffer.AddLine(sPre, sPost); } + void AddMotdBuffer(const CString& sPre, const CString& sPost) { m_MotdBuffer.AddLine(sPre, sPost); } + void AddQueryBuffer(const CString& sPre, const CString& sPost) { m_QueryBuffer.AddLine(sPre, sPost); } + void ClearRawBuffer() { m_RawBuffer.Clear(); } + void ClearMotdBuffer() { m_MotdBuffer.Clear(); } + void ClearQueryBuffer() { m_QueryBuffer.Clear(); } + // !Buffers bool OnBoot(); - bool IsUserAttached(); bool PutIRC(const CString& sLine); - bool PutUser(const CString& sLine); - bool PutStatus(const CString& sLine); - bool PutStatusNotice(const CString& sLine); - bool PutModule(const CString& sModule, const CString& sLine); + bool PutUser(const CString& sLine, CUserSock* pUserSock = NULL); + bool PutStatus(const CString& sLine, CUserSock* pUserSock = NULL); + bool PutStatusNotice(const CString& sLine, CUserSock* pUserSock = NULL); + bool PutModule(const CString& sModule, const CString& sLine, CUserSock* pUserSock = NULL); + + bool IsUserAttached() { return (m_vUserSocks.size() > 0); } + void UserConnected(CUserSock* pUserSock); + void UserDisconnected(CUserSock* pUserSock); CString GetLocalIP(); + void IRCConnected(CIRCSock* pIRCSock); + void IRCDisconnected(); 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 = ""); @@ -95,10 +109,11 @@ public: void SetBufferCount(unsigned int u); void SetKeepBuffer(bool b); void SetAutoCycle(bool b); + void SetChanPrefixes(const CString& s) { m_sChanPrefixes = (s.empty()) ? "#&" : s; } // !Setters // Getters - CUserSock* GetUserSock(); + vector& GetUserSocks() { return m_vUserSocks; } CIRCSock* GetIRCSock(); const CString& GetUserName() const; const CString& GetNick() const; @@ -111,6 +126,9 @@ public: bool IsPassHashed() const; const set& GetAllowedHosts() const; + const CString& GetChanPrefixes() const { return m_sChanPrefixes; } + bool IsChan(const CString& sChan) const { return (sChan.size() && GetChanPrefixes().find(sChan[0]) != CString::npos); } + const CString& GetUserPath() const { if (!CFile::Exists(m_sUserPath)) { CUtils::MakeDir(m_sUserPath); } return m_sUserPath; } const CString& GetDLPath() const { if (!CFile::Exists(m_sDLPath)) { CUtils::MakeDir(m_sDLPath); } return m_sDLPath; } @@ -144,6 +162,7 @@ protected: CString m_sPass; CString m_sStatusPrefix; CString m_sDefaultChanModes; + CString m_sChanPrefixes; CNick m_IRCNick; CString m_sIRCServer; CString m_sQuitMsg; @@ -154,6 +173,10 @@ protected: CString m_sDLPath; // !Paths + CBuffer m_RawBuffer; + CBuffer m_MotdBuffer; + CBuffer m_QueryBuffer; + bool m_bBounceDCCs; bool m_bPassHashed; bool m_bUseClientIP; @@ -168,6 +191,7 @@ protected: vector m_vServers; vector m_vChans; + vector m_vUserSocks; set m_ssAllowedHosts; unsigned int m_uServerIdx; unsigned int m_uBufferCount; diff --git a/UserSock.cpp b/UserSock.cpp index d5ebd603..4d285090 100644 --- a/UserSock.cpp +++ b/UserSock.cpp @@ -142,7 +142,7 @@ void CUserSock::ReadLine(const CString& sData) { } } else if (sCommand.CaseCmp("QUIT") == 0) { if (m_pIRCSock) { - m_pIRCSock->UserDisconnected(); + m_pUser->UserDisconnected(this); } Close(); // Treat a client quit as a detach @@ -168,9 +168,13 @@ void CUserSock::ReadLine(const CString& sData) { CModule* pModule = CZNC::Get().GetModules().FindModule(sModule); if (pModule) { + pModule->SetUserSock(this); pModule->OnModNotice(sMsg); + pModule->SetUserSock(NULL); } else if ((pModule = m_pUser->GetModules().FindModule(sModule))) { + pModule->SetUserSock(this); pModule->OnModNotice(sMsg); + pModule->SetUserSock(NULL); } else { PutStatus("No such module [" + sModule + "]"); } @@ -318,7 +322,9 @@ void CUserSock::ReadLine(const CString& sData) { CModule* pModule = m_pUser->GetModules().FindModule(sModule); if (pModule) { + pModule->SetUserSock(this); pModule->OnModCTCP(sCTCP); + pModule->SetUserSock(NULL); } else { PutStatus("No such module [" + sModule + "]"); } @@ -349,7 +355,9 @@ void CUserSock::ReadLine(const CString& sData) { CModule* pModule = m_pUser->GetModules().FindModule(sModule); if (pModule) { + pModule->SetUserSock(this); pModule->OnModCommand(sMsg); + pModule->SetUserSock(NULL); } else { PutStatus("No such module [" + sModule + "]"); } @@ -369,6 +377,21 @@ void CUserSock::ReadLine(const CString& sData) { } PutIRC("PRIVMSG " + sTarget + " :" + sMsg); + + // Relay to the rest of the clients that may be connected to this user + + if (m_pUser && m_pUser->IsChan(sTarget)) { + vector& vUserSocks = m_pUser->GetUserSocks(); + + for (unsigned int a = 0; a < vUserSocks.size(); a++) { + CUserSock* pUserSock = vUserSocks[a]; + + if (pUserSock != this) { + pUserSock->PutServ(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + sMsg); + } + } + } + return; } @@ -974,7 +997,7 @@ void CUserSock::AuthUser() { if (pIRCSock) { m_pIRCSock = pIRCSock; - pIRCSock->UserConnected(this); + m_pUser->UserConnected(this); } VOIDMODULECALL(OnUserAttached()); @@ -992,7 +1015,7 @@ void CUserSock::ConnectionRefused() { void CUserSock::Disconnected() { if (m_pIRCSock) { - m_pIRCSock->UserDisconnected(); + m_pUser->UserDisconnected(this); m_pIRCSock = NULL; } diff --git a/main.h b/main.h index 55074a69..23d6b227 100644 --- a/main.h +++ b/main.h @@ -1,7 +1,7 @@ #ifndef _MAIN_H #define _MAIN_H -#define VERSION 0.041 +#define VERSION 0.042 #ifndef _MODDIR_ #define _MODDIR_ "/usr/share/znc" diff --git a/modules/shell.cpp b/modules/shell.cpp index 1c9ca18c..9823cb99 100644 --- a/modules/shell.cpp +++ b/modules/shell.cpp @@ -14,9 +14,10 @@ class CShellMod; class CExecSock : public Csock { public: - CExecSock(CShellMod* pShellMod, const CString& sExec) : Csock() { + CExecSock(CShellMod* pShellMod, CUserSock* pUserSock, const CString& sExec) : Csock() { EnableReadLine(); m_pParent = pShellMod; + m_pUserSock = pUserSock; int iReadFD, iWriteFD; m_iPid = popen2(iReadFD, iWriteFD, sExec); ConnectFD(iReadFD, iWriteFD, "0.0.0.0:0"); @@ -83,6 +84,8 @@ public: } return; } +private: + CUserSock* m_pUserSock; }; class CShellMod : public CModule { @@ -185,7 +188,7 @@ public: } void RunCommand(const CString& sCommand) { - m_pManager->AddSock((Csock*) new CExecSock(this, "cd " + m_sPath + " && " + sCommand), "SHELL"); + m_pManager->AddSock((Csock*) new CExecSock(this, m_pUserSock, "cd " + m_sPath + " && " + sCommand), "SHELL"); } private: CString m_sPath; @@ -204,11 +207,15 @@ void CExecSock::ReadLine(const CString& sData) { a = sLine.find('\t'); } + m_pParent->SetUserSock(m_pUserSock); m_pParent->PutShell(sLine); + m_pParent->SetUserSock(NULL); } void CExecSock::Disconnected() { + m_pParent->SetUserSock(m_pUserSock); m_pParent->PutShell("znc$"); + m_pParent->SetUserSock(NULL); } MODULEDEFS(CShellMod, "Gives shell access") diff --git a/znc.cpp b/znc.cpp index aa8371be..6f3b436c 100644 --- a/znc.cpp +++ b/znc.cpp @@ -74,11 +74,6 @@ int CZNC::Loop() { for (set::iterator it = m_ssDelUsers.begin(); it != m_ssDelUsers.end(); it++) { CUser* pUser = *it; m_msUsers.erase(pUser->GetUserName()); - CUserSock* pUserSock = pUser->GetUserSock(); - - if (pUserSock) { - m_Manager.DelSockByAddr(pUserSock); - } CIRCSock* pIRCSock = pUser->GetIRCSock(); @@ -148,11 +143,7 @@ int CZNC::Loop() { } DEBUG_ONLY( cout << "User [" << pUser->GetUserName() << "] is connecting to [" << pServer->GetName() << ":" << pServer->GetPort() << "] ..." << endl); - CUserSock* pUserSock = pUser->GetUserSock(); - - if (pUserSock) { - pUserSock->PutStatus("Attempting to connect to [" + pServer->GetName() + ":" + CString::ToString(pServer->GetPort()) + "] ..."); - } + pUser->PutStatus("Attempting to connect to [" + pServer->GetName() + ":" + CString::ToString(pServer->GetPort()) + "] ..."); pIRCSock = new CIRCSock(pUser); pIRCSock->SetPass(pServer->GetPass()); @@ -166,10 +157,7 @@ int CZNC::Loop() { #endif if (!m_Manager.Connect(pServer->GetName(), pServer->GetPort(), sSockName, 20, bSSL, pUser->GetVHost(), pIRCSock)) { ReleaseISpoof(); - - if (pUserSock) { - pUserSock->PutStatus("Unable to connect. (Bad host?)"); - } + pUser->PutStatus("Unable to connect. (Bad host?)"); } } }