mirror of
https://github.com/znc/znc.git
synced 2026-03-28 17:42:41 +01:00
All the headers are now self-contained (g++ Header.h -o /dev/null). Some system headers where moved to the .cpp they are actually needed in, some of our own headers are includes less. (Especially MD5.h) Headers are sorted alphabetically while in e.g. FileUtils.cpp FileUtils.h is the first file included. git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@915 726aef4b-f618-498e-8847-2d620e286838
1834 lines
51 KiB
C++
1834 lines
51 KiB
C++
/*
|
|
* Copyright (C) 2004-2008 See the AUTHORS file for details.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 as published
|
|
* by the Free Software Foundation.
|
|
*/
|
|
|
|
#include "Client.h"
|
|
#include "Chan.h"
|
|
#include "DCCBounce.h"
|
|
#include "DCCSock.h"
|
|
#include "IRCSock.h"
|
|
#include "Server.h"
|
|
#include "User.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;
|
|
|
|
while ((sLine.Right(1) == "\r") || (sLine.Right(1) == "\n")) {
|
|
sLine.RightChomp();
|
|
}
|
|
|
|
DEBUG_ONLY(cout << "(" << ((m_pUser) ? m_pUser->GetUserName() : CString("")) << ") CLI -> ZNC [" << sLine << "]" << endl);
|
|
|
|
#ifdef _MODULES
|
|
if (m_bAuthed) {
|
|
MODULECALL(OnUserRaw(sLine), m_pUser, this, return);
|
|
}
|
|
#endif
|
|
|
|
CString sCommand = sLine.Token(0);
|
|
|
|
if (sCommand.CaseCmp("PASS") == 0) {
|
|
if (!m_bAuthed) {
|
|
m_bGotPass = true;
|
|
m_sPass = sLine.Token(1);
|
|
|
|
if (m_sPass.find(":") != CString::npos) {
|
|
m_sUser = m_sPass.Token(0, false, ":");
|
|
m_sPass = m_sPass.Token(1, true, ":");
|
|
}
|
|
|
|
if ((m_bGotNick) && (m_bGotUser)) {
|
|
AuthUser();
|
|
}
|
|
|
|
return; // Don't forward this msg. ZNC has already registered us.
|
|
}
|
|
} else if (sCommand.CaseCmp("NICK") == 0) {
|
|
CString sNick = sLine.Token(1);
|
|
if (sNick.Left(1) == ":") {
|
|
sNick.LeftChomp();
|
|
}
|
|
|
|
if (!m_bAuthed) {
|
|
m_sNick = sNick;
|
|
m_bGotNick = true;
|
|
|
|
if ((m_bGotPass) && (m_bGotUser)) {
|
|
AuthUser();
|
|
}
|
|
return; // Don't forward this msg. ZNC will handle nick changes until auth is complete
|
|
}
|
|
|
|
if (!m_pIRCSock) {
|
|
// No need to check against IRC nick or to forward it
|
|
return;
|
|
}
|
|
|
|
if ((m_pUser) && (sNick.CaseCmp(m_pUser->GetNick()) == 0)) {
|
|
m_uKeepNickCounter++;
|
|
// If the user is changing his nick to the conifg nick, set keepnick to the config value
|
|
if (m_pUser->GetKeepNick() && !m_pIRCSock->GetKeepNick()) {
|
|
m_pIRCSock->SetKeepNick(true);
|
|
PutStatusNotice("Reset KeepNick back to true");
|
|
}
|
|
}
|
|
|
|
if (m_pUser && GetNick().CaseCmp(m_pUser->GetNick()) == 0) {
|
|
// If the user changes his nick away from the config nick, we shut off keepnick for this session
|
|
if (m_pUser->GetKeepNick()) {
|
|
m_pIRCSock->SetKeepNick(false);
|
|
PutStatusNotice("Set KeepNick to false");
|
|
}
|
|
}
|
|
} else if (sCommand.CaseCmp("USER") == 0) {
|
|
if (!m_bAuthed) {
|
|
if (m_sUser.empty()) {
|
|
m_sUser = sLine.Token(1);
|
|
}
|
|
|
|
m_bGotUser = true;
|
|
|
|
if ((m_bGotPass) && (m_bGotNick)) {
|
|
AuthUser();
|
|
} else if (!m_bGotPass) {
|
|
PutClient(":irc.znc.com NOTICE AUTH :*** "
|
|
"You need to send your password. "
|
|
"Try /quote PASS <username>:<password>");
|
|
}
|
|
|
|
return; // Don't forward this msg. ZNC has already registered us.
|
|
}
|
|
}
|
|
|
|
if (!m_pUser) {
|
|
PutClient("ERROR :You need to send your password first!");
|
|
Close();
|
|
return;
|
|
}
|
|
|
|
if (sCommand.CaseCmp("ZNC") == 0) {
|
|
PutStatus("Hello. How may I help you?");
|
|
return;
|
|
} else if (sCommand.CaseCmp("DETACH") == 0) {
|
|
if (m_pUser) {
|
|
CString sChan = sLine.Token(1);
|
|
|
|
if (sChan.empty()) {
|
|
PutStatusNotice("Usage: /detach <#chan>");
|
|
return;
|
|
}
|
|
|
|
CChan* pChan = m_pUser->FindChan(sChan);
|
|
if (!pChan) {
|
|
PutStatusNotice("You are not on [" + sChan + "]");
|
|
return;
|
|
}
|
|
|
|
pChan->DetachUser();
|
|
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) {
|
|
CString sChans = sLine.Token(1);
|
|
CString sKey = sLine.Token(2);
|
|
|
|
if (sChans.Left(1) == ":") {
|
|
sChans.LeftChomp();
|
|
}
|
|
|
|
if (m_pUser) {
|
|
VCString vChans;
|
|
sChans.Split(",", vChans, false);
|
|
sChans.clear();
|
|
|
|
for (unsigned int a = 0; a < vChans.size(); a++) {
|
|
CString sChannel = vChans[a];
|
|
#ifdef _MODULES
|
|
MODULECALL(OnUserJoin(sChannel, sKey), m_pUser, this, continue);
|
|
#endif
|
|
|
|
CChan* pChan = m_pUser->FindChan(sChannel);
|
|
|
|
if (pChan) {
|
|
pChan->JoinUser(false, sKey);
|
|
continue;
|
|
}
|
|
|
|
if (!sChannel.empty()) {
|
|
sChans += (sChans.empty()) ? sChannel : CString("," + sChannel);
|
|
}
|
|
}
|
|
|
|
if (sChans.empty()) {
|
|
return;
|
|
}
|
|
|
|
sLine = "JOIN " + sChans;
|
|
|
|
if (!sKey.empty()) {
|
|
sLine += " " + sKey;
|
|
}
|
|
}
|
|
} else if (sCommand.CaseCmp("PART") == 0) {
|
|
CString sChan = sLine.Token(1);
|
|
CString sMessage = sLine.Token(2, true);
|
|
|
|
if (sMessage.Left(1) == ":") {
|
|
sMessage.LeftChomp();
|
|
}
|
|
|
|
#ifdef _MODULES
|
|
MODULECALL(OnUserPart(sChan, sMessage), m_pUser, this, return);
|
|
#endif
|
|
|
|
if (m_pUser) {
|
|
CChan* pChan = m_pUser->FindChan(sChan);
|
|
|
|
if (pChan && !pChan->IsOn()) {
|
|
PutStatusNotice("Removing channel [" + sChan + "]");
|
|
m_pUser->DelChan(sChan);
|
|
return;
|
|
}
|
|
}
|
|
|
|
sLine = "PART " + sChan;
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
|
|
if (sMsg.Left(1) == ":") {
|
|
sMsg.LeftChomp();
|
|
}
|
|
|
|
if ((!m_pUser) || (sTarget.CaseCmp(CString(m_pUser->GetStatusPrefix() + "status"))) == 0) {
|
|
return;
|
|
}
|
|
|
|
if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
|
|
#ifdef _MODULES
|
|
if (m_pUser) {
|
|
CString sModule = sTarget;
|
|
sModule.LeftChomp(m_pUser->GetStatusPrefix().length());
|
|
|
|
CModule* pModule = CZNC::Get().GetModules().FindModule(sModule);
|
|
|
|
if (pModule) {
|
|
pModule->SetClient(this);
|
|
pModule->OnModNotice(sMsg);
|
|
pModule->SetClient(NULL);
|
|
} else if ((pModule = m_pUser->GetModules().FindModule(sModule))) {
|
|
pModule->SetClient(this);
|
|
pModule->OnModNotice(sMsg);
|
|
pModule->SetClient(NULL);
|
|
} else {
|
|
PutStatus("No such module [" + sModule + "]");
|
|
}
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if (sMsg.WildCmp("DCC * (*)")) {
|
|
sMsg = "DCC " + sLine.Token(3) + " (" + ((m_pIRCSock) ? m_pIRCSock->GetLocalIP() : GetLocalIP()) + ")";
|
|
}
|
|
|
|
#ifdef _MODULES
|
|
if (sMsg.WildCmp("\001*\001")) {
|
|
CString sCTCP = sMsg;
|
|
sCTCP.LeftChomp();
|
|
sCTCP.RightChomp();
|
|
|
|
MODULECALL(OnUserCTCPReply(sTarget, sCTCP), m_pUser, this, return);
|
|
|
|
sMsg = "\001" + sCTCP + "\001";
|
|
} else {
|
|
MODULECALL(OnUserNotice(sTarget, sMsg), m_pUser, this, return);
|
|
}
|
|
#endif
|
|
|
|
CChan* pChan = m_pUser->FindChan(sTarget);
|
|
|
|
if ((pChan) && (pChan->KeepBuffer())) {
|
|
pChan->AddBuffer(":" + GetNickMask() + " NOTICE " + sTarget + " :" + m_pUser->AddTimestamp(sMsg));
|
|
}
|
|
|
|
// Relay to the rest of the clients that may be connected to this user
|
|
if (m_pUser && m_pUser->IsChan(sTarget)) {
|
|
vector<CClient*>& vClients = m_pUser->GetClients();
|
|
|
|
for (unsigned int a = 0; a < vClients.size(); a++) {
|
|
CClient* pClient = vClients[a];
|
|
|
|
if (pClient != this) {
|
|
pClient->PutClient(":" + GetNickMask() + " NOTICE " + sTarget + " :" + sMsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
PutIRC("NOTICE " + sTarget + " :" + sMsg);
|
|
return;
|
|
} else if (sCommand.CaseCmp("PRIVMSG") == 0) {
|
|
CString sTarget = sLine.Token(1);
|
|
CString sMsg = sLine.Token(2, true);
|
|
|
|
if (sMsg.Left(1) == ":") {
|
|
sMsg.LeftChomp();
|
|
}
|
|
|
|
if (sMsg.WildCmp("\001*\001")) {
|
|
CString sCTCP = sMsg;
|
|
sCTCP.LeftChomp();
|
|
sCTCP.RightChomp();
|
|
|
|
if (strncasecmp(sCTCP.c_str(), "DCC ", 4) == 0 && m_pUser && m_pUser->BounceDCCs()) {
|
|
CString sType = sCTCP.Token(1);
|
|
CString sFile = sCTCP.Token(2);
|
|
unsigned long uLongIP = strtoul(sCTCP.Token(3).c_str(), NULL, 10);
|
|
unsigned short uPort = strtoul(sCTCP.Token(4).c_str(), NULL, 10);
|
|
unsigned long uFileSize = strtoul(sCTCP.Token(5).c_str(), NULL, 10);
|
|
CString sIP = (m_pIRCSock) ? m_pIRCSock->GetLocalIP() : GetLocalIP();
|
|
|
|
if (!m_pUser->UseClientIP()) {
|
|
uLongIP = CUtils::GetLongIP(GetRemoteIP());
|
|
}
|
|
|
|
if (sType.CaseCmp("CHAT") == 0) {
|
|
if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
|
|
} else {
|
|
unsigned short uBNCPort = CDCCBounce::DCCRequest(sTarget, uLongIP, uPort, "", true, m_pUser, (m_pIRCSock) ? m_pIRCSock->GetLocalIP() : GetLocalIP(), "");
|
|
if (uBNCPort) {
|
|
PutIRC("PRIVMSG " + sTarget + " :\001DCC CHAT chat " + CString(CUtils::GetLongIP(sIP)) + " " + CString(uBNCPort) + "\001");
|
|
}
|
|
}
|
|
} else if (sType.CaseCmp("SEND") == 0) {
|
|
// DCC SEND readme.txt 403120438 5550 1104
|
|
|
|
if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
|
|
if ((!m_pUser) || (sTarget.CaseCmp(CString(m_pUser->GetStatusPrefix() + "status")) == 0)) {
|
|
if (!m_pUser) {
|
|
return;
|
|
}
|
|
|
|
CString sPath = m_pUser->GetDLPath();
|
|
if (!CFile::Exists(sPath)) {
|
|
PutStatus("Could not create [" + sPath + "] directory.");
|
|
return;
|
|
} else if (!CFile::IsDir(sPath)) {
|
|
PutStatus("Error: [" + sPath + "] is not a directory.");
|
|
return;
|
|
}
|
|
|
|
CString sLocalFile = sPath + "/" + sFile;
|
|
|
|
if (m_pUser) {
|
|
m_pUser->GetFile(GetNick(), CUtils::GetIP(uLongIP), uPort, sLocalFile, uFileSize);
|
|
}
|
|
#ifdef _MODULES
|
|
} else {
|
|
MODULECALL(OnDCCUserSend(sTarget, uLongIP, uPort, sFile, uFileSize), m_pUser, this, return);
|
|
#endif
|
|
}
|
|
} else {
|
|
unsigned short uBNCPort = CDCCBounce::DCCRequest(sTarget, uLongIP, uPort, sFile, false, m_pUser, (m_pIRCSock) ? m_pIRCSock->GetLocalIP() : GetLocalIP(), "");
|
|
if (uBNCPort) {
|
|
PutIRC("PRIVMSG " + sTarget + " :\001DCC SEND " + sFile + " " + CString(CUtils::GetLongIP(sIP)) + " " + CString(uBNCPort) + " " + CString(uFileSize) + "\001");
|
|
}
|
|
}
|
|
} else if (sType.CaseCmp("RESUME") == 0) {
|
|
// PRIVMSG user :DCC RESUME "znc.o" 58810 151552
|
|
unsigned short uResumePort = atoi(sCTCP.Token(3).c_str());
|
|
unsigned long uResumeSize = strtoul(sCTCP.Token(4).c_str(), NULL, 10);
|
|
|
|
// Need to lookup the connection by port, filter the port, and forward to the user
|
|
if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
|
|
if ((m_pUser) && (m_pUser->ResumeFile(sTarget, uResumePort, uResumeSize))) {
|
|
PutClient(":" + sTarget + "!znc@znc.com PRIVMSG " + GetNick() + " :\001DCC ACCEPT " + sFile + " " + CString(uResumePort) + " " + CString(uResumeSize) + "\001");
|
|
} else {
|
|
PutStatus("DCC -> [" + GetNick() + "][" + sFile + "] Unable to find send to initiate resume.");
|
|
}
|
|
} else {
|
|
CDCCBounce* pSock = (CDCCBounce*) CZNC::Get().GetManager().FindSockByLocalPort(uResumePort);
|
|
if ((pSock) && (strncasecmp(pSock->GetSockName().c_str(), "DCC::", 5) == 0)) {
|
|
PutIRC("PRIVMSG " + sTarget + " :\001DCC " + sType + " " + sFile + " " + CString(pSock->GetUserPort()) + " " + sCTCP.Token(4) + "\001");
|
|
}
|
|
}
|
|
} else if (sType.CaseCmp("ACCEPT") == 0) {
|
|
if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
|
|
} else {
|
|
// Need to lookup the connection by port, filter the port, and forward to the user
|
|
CSockManager& Manager = CZNC::Get().GetManager();
|
|
|
|
for (unsigned int a = 0; a < Manager.size(); a++) {
|
|
CDCCBounce* pSock = (CDCCBounce*) Manager[a];
|
|
|
|
if ((pSock) && (strncasecmp(pSock->GetSockName().c_str(), "DCC::", 5) == 0)) {
|
|
if (pSock->GetUserPort() == atoi(sCTCP.Token(3).c_str())) {
|
|
PutIRC("PRIVMSG " + sTarget + " :\001DCC " + sType + " " + sFile + " " + CString(pSock->GetLocalPort()) + " " + sCTCP.Token(4) + "\001");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
|
|
CString sModule = sTarget;
|
|
sModule.LeftChomp(m_pUser->GetStatusPrefix().length());
|
|
|
|
if (sModule == "status") {
|
|
StatusCTCP(sCTCP);
|
|
|
|
return;
|
|
}
|
|
|
|
#ifdef _MODULES
|
|
CModule* pModule = m_pUser->GetModules().FindModule(sModule);
|
|
if (pModule) {
|
|
pModule->SetClient(this);
|
|
pModule->OnModCTCP(sCTCP);
|
|
pModule->SetClient(NULL);
|
|
} else {
|
|
PutStatus("No such module [" + sModule + "]");
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
CChan* pChan = m_pUser->FindChan(sTarget);
|
|
|
|
if (sCTCP.Token(0).CaseCmp("ACTION") == 0) {
|
|
CString sMessage = sCTCP.Token(1, true);
|
|
MODULECALL(OnUserAction(sTarget, sMessage), m_pUser, this, return);
|
|
sCTCP = "ACTION " + sMessage;
|
|
|
|
if (pChan && pChan->KeepBuffer()) {
|
|
pChan->AddBuffer(":" + GetNickMask() + " PRIVMSG " + sTarget + " :\001ACTION " + m_pUser->AddTimestamp(sMessage) + "\001");
|
|
}
|
|
|
|
// Relay to the rest of the clients that may be connected to this user
|
|
if (m_pUser && m_pUser->IsChan(sTarget)) {
|
|
vector<CClient*>& vClients = m_pUser->GetClients();
|
|
|
|
for (unsigned int a = 0; a < vClients.size(); a++) {
|
|
CClient* pClient = vClients[a];
|
|
|
|
if (pClient != this) {
|
|
pClient->PutClient(":" + GetNickMask() + " PRIVMSG " + sTarget + " :\001" + sCTCP + "\001");
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
MODULECALL(OnUserCTCP(sTarget, sCTCP), m_pUser, this, return);
|
|
}
|
|
|
|
PutIRC("PRIVMSG " + sTarget + " :\001" + sCTCP + "\001");
|
|
return;
|
|
}
|
|
|
|
if ((m_pUser) && (sTarget.CaseCmp(CString(m_pUser->GetStatusPrefix() + "status")) == 0)) {
|
|
#ifdef _MODULES
|
|
MODULECALL(OnStatusCommand(sMsg), m_pUser, this, return);
|
|
#endif
|
|
UserCommand(sMsg);
|
|
return;
|
|
}
|
|
|
|
if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
|
|
#ifdef _MODULES
|
|
if (m_pUser) {
|
|
CString sModule = sTarget;
|
|
sModule.LeftChomp(m_pUser->GetStatusPrefix().length());
|
|
|
|
CModule* pModule = CZNC::Get().GetModules().FindModule(sModule);
|
|
|
|
if (pModule) {
|
|
pModule->SetClient(this);
|
|
pModule->SetUser(m_pUser);
|
|
pModule->OnModCommand(sMsg);
|
|
pModule->SetClient(NULL);
|
|
pModule->SetUser(NULL);
|
|
} else {
|
|
pModule = m_pUser->GetModules().FindModule(sModule);
|
|
if (pModule) {
|
|
pModule->SetClient(this);
|
|
pModule->OnModCommand(sMsg);
|
|
pModule->SetClient(NULL);
|
|
} else {
|
|
PutStatus("No such module [" + sModule + "]");
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
#ifdef _MODULES
|
|
MODULECALL(OnUserMsg(sTarget, sMsg), m_pUser, this, return);
|
|
#endif
|
|
|
|
CChan* pChan = m_pUser->FindChan(sTarget);
|
|
|
|
if ((pChan) && (pChan->KeepBuffer())) {
|
|
pChan->AddBuffer(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + m_pUser->AddTimestamp(sMsg));
|
|
}
|
|
|
|
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<CClient*>& vClients = m_pUser->GetClients();
|
|
|
|
for (unsigned int a = 0; a < vClients.size(); a++) {
|
|
CClient* pClient = vClients[a];
|
|
|
|
if (pClient != this) {
|
|
pClient->PutClient(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + sMsg);
|
|
}
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
PutIRC(sLine);
|
|
}
|
|
|
|
void CClient::SetNick(const CString& s) {
|
|
m_sNick = s;
|
|
|
|
if (m_pUser) {
|
|
if (m_sNick.CaseCmp(m_pUser->GetNick()) == 0) {
|
|
m_uKeepNickCounter = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CClient::DecKeepNickCounter() {
|
|
if (!m_uKeepNickCounter) {
|
|
return false;
|
|
}
|
|
|
|
m_uKeepNickCounter--;
|
|
return true;
|
|
}
|
|
|
|
void CClient::StatusCTCP(const CString& sLine) {
|
|
CString sCommand = sLine.Token(0);
|
|
|
|
if (sCommand.CaseCmp("PING") == 0) {
|
|
PutStatusNotice("\001PING " + sLine.Token(1, true) + "\001");
|
|
} else if (sCommand.CaseCmp("VERSION") == 0) {
|
|
PutStatusNotice("\001VERSION " + CZNC::GetTag() + "\001");
|
|
}
|
|
}
|
|
|
|
void CClient::UserCommand(const CString& sLine) {
|
|
if (!m_pUser) {
|
|
return;
|
|
}
|
|
|
|
if (sLine.empty()) {
|
|
return;
|
|
}
|
|
|
|
CString sCommand = sLine.Token(0);
|
|
|
|
if (sCommand.CaseCmp("HELP") == 0) {
|
|
HelpUser();
|
|
} else if (sCommand.CaseCmp("LISTNICKS") == 0) {
|
|
CString sChan = sLine.Token(1);
|
|
|
|
if (sChan.empty()) {
|
|
PutStatus("Usage: ListNicks <#chan>");
|
|
return;
|
|
}
|
|
|
|
CChan* pChan = m_pUser->FindChan(sChan);
|
|
|
|
if (!pChan) {
|
|
PutStatus("You are not on [" + sChan + "]");
|
|
return;
|
|
}
|
|
|
|
if (!pChan->IsOn()) {
|
|
PutStatus("You are not on [" + sChan + "] [trying]");
|
|
return;
|
|
}
|
|
|
|
const map<CString,CNick*>& msNicks = pChan->GetNicks();
|
|
CIRCSock* pIRCSock = (!m_pUser) ? NULL : m_pUser->GetIRCSock();
|
|
const CString& sPerms = (pIRCSock) ? pIRCSock->GetPerms() : "";
|
|
|
|
if (!msNicks.size()) {
|
|
PutStatus("No nicks on [" + sChan + "]");
|
|
return;
|
|
}
|
|
|
|
CTable Table;
|
|
|
|
for (unsigned int p = 0; p < sPerms.size(); p++) {
|
|
CString sPerm;
|
|
sPerm += sPerms[p];
|
|
Table.AddColumn(sPerm);
|
|
}
|
|
|
|
Table.AddColumn("Nick");
|
|
Table.AddColumn("Ident");
|
|
Table.AddColumn("Host");
|
|
|
|
for (map<CString,CNick*>::const_iterator a = msNicks.begin(); a != msNicks.end(); a++) {
|
|
Table.AddRow();
|
|
|
|
for (unsigned int b = 0; b < sPerms.size(); b++) {
|
|
if (a->second->HasPerm(sPerms[b])) {
|
|
CString sPerm;
|
|
sPerm += sPerms[b];
|
|
Table.SetCell(sPerm, sPerm);
|
|
}
|
|
}
|
|
|
|
Table.SetCell("Nick", a->second->GetNick());
|
|
Table.SetCell("Ident", a->second->GetIdent());
|
|
Table.SetCell("Host", a->second->GetHost());
|
|
}
|
|
|
|
unsigned int uTableIdx = 0;
|
|
CString sLine;
|
|
|
|
while (Table.GetLine(uTableIdx++, sLine)) {
|
|
PutStatus(sLine);
|
|
}
|
|
} else if (sCommand.CaseCmp("DETACH") == 0) {
|
|
if (m_pUser) {
|
|
CString sChan = sLine.Token(1);
|
|
|
|
if (sChan.empty()) {
|
|
PutStatus("Usage: Detach <#chan>");
|
|
return;
|
|
}
|
|
|
|
CChan* pChan = m_pUser->FindChan(sChan);
|
|
if (!pChan) {
|
|
PutStatus("You are not on [" + sChan + "]");
|
|
return;
|
|
}
|
|
|
|
PutStatus("Detaching you from [" + sChan + "]");
|
|
pChan->DetachUser();
|
|
}
|
|
} else if (sCommand.CaseCmp("VERSION") == 0) {
|
|
PutStatus(CZNC::GetTag());
|
|
} else if (sCommand.CaseCmp("MOTD") == 0) {
|
|
if (!SendMotd()) {
|
|
PutStatus("There is no MOTD set.");
|
|
}
|
|
} else if (m_pUser->IsAdmin() && sCommand.CaseCmp("SaveConfig") == 0) {
|
|
if (CZNC::Get().WriteConfig()) {
|
|
PutStatus("Wrote config to [" + CZNC::Get().GetConfigFile() + "]");
|
|
} else {
|
|
PutStatus("Error while trying to write config.");
|
|
}
|
|
} else if (sCommand.CaseCmp("LISTCLIENTS") == 0) {
|
|
if (m_pUser) {
|
|
CUser* pUser = m_pUser;
|
|
CString sNick = sLine.Token(1);
|
|
|
|
if (!sNick.empty()) {
|
|
if (!m_pUser->IsAdmin()) {
|
|
PutStatus("Usage: ListClients");
|
|
return;
|
|
}
|
|
|
|
pUser = CZNC::Get().FindUser(sNick);
|
|
|
|
if (!pUser) {
|
|
PutStatus("No such user [" + sNick + "]");
|
|
return;
|
|
}
|
|
}
|
|
|
|
vector<CClient*>& vClients = pUser->GetClients();
|
|
|
|
if (vClients.empty()) {
|
|
PutStatus("No clients are connected");
|
|
return;
|
|
}
|
|
|
|
CTable Table;
|
|
Table.AddColumn("Host");
|
|
|
|
for (unsigned int a = 0; a < vClients.size(); a++) {
|
|
Table.AddRow();
|
|
Table.SetCell("Host", vClients[a]->GetRemoteIP());
|
|
}
|
|
|
|
if (Table.size()) {
|
|
unsigned int uTableIdx = 0;
|
|
CString sLine;
|
|
|
|
while (Table.GetLine(uTableIdx++, sLine)) {
|
|
PutStatus(sLine);
|
|
}
|
|
}
|
|
}
|
|
} else if (m_pUser->IsAdmin() && sCommand.CaseCmp("LISTUSERS") == 0) {
|
|
const map<CString, CUser*>& msUsers = CZNC::Get().GetUserMap();
|
|
CTable Table;
|
|
Table.AddColumn("Username");
|
|
Table.AddColumn("Clients");
|
|
Table.AddColumn("OnIRC");
|
|
Table.AddColumn("IRC Server");
|
|
Table.AddColumn("IRC User");
|
|
|
|
for (map<CString, CUser*>::const_iterator it = msUsers.begin(); it != msUsers.end(); it++) {
|
|
Table.AddRow();
|
|
Table.SetCell("Username", it->first);
|
|
Table.SetCell("Clients", CString(it->second->GetClients().size()));
|
|
if (!it->second->IsIRCConnected()) {
|
|
Table.SetCell("OnIRC", "No");
|
|
} else {
|
|
Table.SetCell("OnIRC", "Yes");
|
|
Table.SetCell("IRC Server", it->second->GetIRCServer());
|
|
Table.SetCell("IRC User", it->second->GetIRCNick().GetNickMask());
|
|
}
|
|
}
|
|
|
|
if (Table.size()) {
|
|
unsigned int uTableIdx = 0;
|
|
CString sLine;
|
|
|
|
while (Table.GetLine(uTableIdx++, sLine)) {
|
|
PutStatus(sLine);
|
|
}
|
|
}
|
|
} else if (m_pUser->IsAdmin() && sCommand.CaseCmp("SetMOTD") == 0) {
|
|
CString sMessage = sLine.Token(1, true);
|
|
|
|
if (sMessage.empty()) {
|
|
PutStatus("Usage: SetMOTD <Message>");
|
|
} else {
|
|
CZNC::Get().SetMotd(sMessage);
|
|
PutStatus("MOTD set to [" + sMessage + "]");
|
|
}
|
|
} else if (m_pUser->IsAdmin() && sCommand.CaseCmp("AddMOTD") == 0) {
|
|
CString sMessage = sLine.Token(1, true);
|
|
|
|
if (sMessage.empty()) {
|
|
PutStatus("Usage: AddMOTD <Message>");
|
|
} else {
|
|
CZNC::Get().AddMotd(sMessage);
|
|
PutStatus("Added [" + sMessage + "] to MOTD");
|
|
}
|
|
} else if (m_pUser->IsAdmin() && sCommand.CaseCmp("ClearMOTD") == 0) {
|
|
CZNC::Get().ClearMotd();
|
|
PutStatus("Cleared MOTD");
|
|
} else if (m_pUser->IsAdmin() && sCommand.CaseCmp("BROADCAST") == 0) {
|
|
CZNC::Get().Broadcast(sLine.Token(1, true));
|
|
} else if (m_pUser->IsAdmin() && sCommand.CaseCmp("SHUTDOWN") == 0) {
|
|
CString sMessage = sLine.Token(1, true);
|
|
|
|
if (sMessage.empty()) {
|
|
sMessage = "ZNC is being shutdown NOW!!";
|
|
}
|
|
|
|
CZNC::Get().Broadcast(sMessage);
|
|
usleep(100000); // Sleep for 10ms to attempt to allow the previous Broadcast() to go through to all users
|
|
|
|
throw CException(CException::EX_Shutdown);
|
|
} else if (sCommand.CaseCmp("JUMP") == 0 ||
|
|
sCommand.CaseCmp("CONNECT") == 0) {
|
|
if (m_pUser) {
|
|
if (m_pIRCSock) {
|
|
m_pIRCSock->Quit();
|
|
PutStatus("Jumping to the next server in the list...");
|
|
} else {
|
|
PutStatus("Connecting...");
|
|
}
|
|
|
|
m_pUser->SetIRCConnectEnabled(true);
|
|
m_pUser->CheckIRCConnect();
|
|
return;
|
|
}
|
|
} else if (sCommand.CaseCmp("DISCONNECT") == 0) {
|
|
if (m_pUser) {
|
|
if (m_pIRCSock)
|
|
m_pIRCSock->Quit();
|
|
m_pUser->SetIRCConnectEnabled(false);
|
|
PutStatus("Disconnected from IRC. Use 'connect' to reconnect.");
|
|
return;
|
|
}
|
|
} else if (sCommand.CaseCmp("ENABLECHAN") == 0) {
|
|
CString sChan = sLine.Token(1, true);
|
|
|
|
if (sChan.empty()) {
|
|
PutStatus("Usage: EnableChan <channel>");
|
|
} 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<CChan*>& vChans = m_pUser->GetChans();
|
|
CIRCSock* pIRCSock = (!m_pUser) ? NULL : m_pUser->GetIRCSock();
|
|
const CString& sPerms = (pIRCSock) ? pIRCSock->GetPerms() : "";
|
|
|
|
if (!vChans.size()) {
|
|
PutStatus("You have no channels defined");
|
|
return;
|
|
}
|
|
|
|
CTable Table;
|
|
Table.AddColumn("Name");
|
|
Table.AddColumn("Status");
|
|
Table.AddColumn("Conf");
|
|
Table.AddColumn("Buf");
|
|
Table.AddColumn("Modes");
|
|
Table.AddColumn("Users");
|
|
|
|
for (unsigned int p = 0; p < sPerms.size(); p++) {
|
|
CString sPerm;
|
|
sPerm += sPerms[p];
|
|
Table.AddColumn(sPerm);
|
|
}
|
|
|
|
for (unsigned int a = 0; a < vChans.size(); a++) {
|
|
CChan* pChan = vChans[a];
|
|
Table.AddRow();
|
|
Table.SetCell("Name", pChan->GetPermStr() + pChan->GetName());
|
|
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());
|
|
Table.SetCell("Users", CString(pChan->GetNickCount()));
|
|
|
|
for (unsigned int b = 0; b < sPerms.size(); b++) {
|
|
CString sPerm;
|
|
sPerm += sPerms[b];
|
|
Table.SetCell(sPerm, CString(pChan->GetPermCount(sPerms[b])));
|
|
}
|
|
}
|
|
|
|
if (Table.size()) {
|
|
unsigned int uTableIdx = 0;
|
|
CString sLine;
|
|
|
|
while (Table.GetLine(uTableIdx++, sLine)) {
|
|
PutStatus(sLine);
|
|
}
|
|
}
|
|
}
|
|
} else if (sCommand.CaseCmp("ADDSERVER") == 0) {
|
|
CString sServer = sLine.Token(1);
|
|
|
|
if (sServer.empty()) {
|
|
PutStatus("Usage: AddServer <host> [[+]port] [pass]");
|
|
return;
|
|
}
|
|
|
|
if (m_pUser->FindServer(sLine.Token(1))) {
|
|
PutStatus("That server already exists");
|
|
return;
|
|
}
|
|
|
|
if (m_pUser && m_pUser->AddServer(sLine.Token(1, true))) {
|
|
PutStatus("Server added");
|
|
} else {
|
|
PutStatus("Unable to add that server");
|
|
}
|
|
} else if (sCommand.CaseCmp("REMSERVER") == 0 || sCommand.CaseCmp("DELSERVER") == 0) {
|
|
CString sServer = sLine.Token(1);
|
|
|
|
if (sServer.empty()) {
|
|
PutStatus("Usage: RemServer <host>");
|
|
return;
|
|
}
|
|
|
|
const vector<CServer*>& vServers = m_pUser->GetServers();
|
|
|
|
if (vServers.size() <= 0) {
|
|
PutStatus("You don't have any servers added.");
|
|
return;
|
|
}
|
|
|
|
if (m_pUser && m_pUser->DelServer(sServer)) {
|
|
PutStatus("Server removed");
|
|
} else {
|
|
PutStatus("No such server");
|
|
}
|
|
} else if (sCommand.CaseCmp("LISTSERVERS") == 0) {
|
|
if (m_pUser) {
|
|
if (m_pUser->HasServers()) {
|
|
const vector<CServer*>& vServers = m_pUser->GetServers();
|
|
CTable Table;
|
|
Table.AddColumn("Host");
|
|
Table.AddColumn("Port");
|
|
Table.AddColumn("SSL");
|
|
Table.AddColumn("Pass");
|
|
|
|
for (unsigned int a = 0; a < vServers.size(); a++) {
|
|
CServer* pServer = vServers[a];
|
|
Table.AddRow();
|
|
Table.SetCell("Host", pServer->GetName());
|
|
Table.SetCell("Port", CString(pServer->GetPort()));
|
|
Table.SetCell("SSL", (pServer->IsSSL()) ? "SSL" : "");
|
|
Table.SetCell("Pass", pServer->GetPass());
|
|
}
|
|
|
|
if (Table.size()) {
|
|
unsigned int uTableIdx = 0;
|
|
CString sLine;
|
|
|
|
while (Table.GetLine(uTableIdx++, sLine)) {
|
|
PutStatus(sLine);
|
|
}
|
|
}
|
|
} else {
|
|
PutStatus("You don't have any servers added.");
|
|
}
|
|
}
|
|
} else if (sCommand.CaseCmp("TOPICS") == 0) {
|
|
if (m_pUser) {
|
|
const vector<CChan*>& vChans = m_pUser->GetChans();
|
|
CTable Table;
|
|
Table.AddColumn("Name");
|
|
Table.AddColumn("Set By");
|
|
Table.AddColumn("Topic");
|
|
|
|
for (unsigned int a = 0; a < vChans.size(); a++) {
|
|
CChan* pChan = vChans[a];
|
|
Table.AddRow();
|
|
Table.SetCell("Name", pChan->GetName());
|
|
Table.SetCell("Set By", pChan->GetTopicOwner());
|
|
Table.SetCell("Topic", pChan->GetTopic());
|
|
}
|
|
|
|
if (Table.size()) {
|
|
unsigned int uTableIdx = 0;
|
|
CString sLine;
|
|
|
|
while (Table.GetLine(uTableIdx++, sLine)) {
|
|
PutStatus(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 <nick> <file>");
|
|
return;
|
|
}
|
|
|
|
sAbsolutePath = CUtils::ChangeDir(m_pUser->GetDLPath(), sFile, CZNC::Get().GetHomePath());
|
|
|
|
if (sAbsolutePath.Left(sAllowedPath.length()) != sAllowedPath) {
|
|
PutStatus("Illegal path.");
|
|
return;
|
|
}
|
|
|
|
if (m_pUser) {
|
|
m_pUser->SendFile(sToNick, sFile);
|
|
}
|
|
} else if (sCommand.CaseCmp("GET") == 0) {
|
|
CString sFile = sLine.Token(1);
|
|
CString sAllowedPath = m_pUser->GetDLPath();
|
|
CString sAbsolutePath;
|
|
|
|
if (sFile.empty()) {
|
|
PutStatus("Usage: Get <file>");
|
|
return;
|
|
}
|
|
|
|
sAbsolutePath = CUtils::ChangeDir(m_pUser->GetDLPath(), sFile, CZNC::Get().GetHomePath());
|
|
|
|
if (sAbsolutePath.Left(sAllowedPath.length()) != sAllowedPath) {
|
|
PutStatus("Illegal path.");
|
|
return;
|
|
}
|
|
|
|
if (m_pUser) {
|
|
m_pUser->SendFile(GetNick(), sFile);
|
|
}
|
|
} else if (sCommand.CaseCmp("LISTDCCS") == 0) {
|
|
CSockManager& Manager = CZNC::Get().GetManager();
|
|
|
|
CTable Table;
|
|
Table.AddColumn("Type");
|
|
Table.AddColumn("State");
|
|
Table.AddColumn("Speed");
|
|
Table.AddColumn("Nick");
|
|
Table.AddColumn("IP");
|
|
Table.AddColumn("File");
|
|
|
|
for (unsigned int a = 0; a < Manager.size(); a++) {
|
|
const CString& sSockName = Manager[a]->GetSockName();
|
|
|
|
if (strncasecmp(sSockName.c_str(), "DCC::", 5) == 0) {
|
|
if (strncasecmp(sSockName.c_str() +5, "XFER::REMOTE::", 14) == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (strncasecmp(sSockName.c_str() +5, "CHAT::REMOTE::", 14) == 0) {
|
|
continue;
|
|
}
|
|
|
|
if (strncasecmp(sSockName.c_str() +5, "SEND", 4) == 0) {
|
|
CDCCSock* pSock = (CDCCSock*) Manager[a];
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Type", "Sending");
|
|
Table.SetCell("State", CString::ToPercent(pSock->GetProgress()));
|
|
Table.SetCell("Speed", CString::ToKBytes(pSock->GetAvgWrite() / 1000.0));
|
|
Table.SetCell("Nick", pSock->GetRemoteNick());
|
|
Table.SetCell("IP", pSock->GetRemoteIP());
|
|
Table.SetCell("File", pSock->GetFileName());
|
|
} else if (strncasecmp(sSockName.c_str() +5, "GET", 3) == 0) {
|
|
CDCCSock* pSock = (CDCCSock*) Manager[a];
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Type", "Getting");
|
|
Table.SetCell("State", CString::ToPercent(pSock->GetProgress()));
|
|
Table.SetCell("Speed", CString::ToKBytes(pSock->GetAvgRead() / 1000.0));
|
|
Table.SetCell("Nick", pSock->GetRemoteNick());
|
|
Table.SetCell("IP", pSock->GetRemoteIP());
|
|
Table.SetCell("File", pSock->GetFileName());
|
|
} else if (strncasecmp(sSockName.c_str() +5, "LISTEN", 6) == 0) {
|
|
CDCCSock* pSock = (CDCCSock*) Manager[a];
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Type", "Sending");
|
|
Table.SetCell("State", "Waiting");
|
|
Table.SetCell("Nick", pSock->GetRemoteNick());
|
|
Table.SetCell("IP", pSock->GetRemoteIP());
|
|
Table.SetCell("File", pSock->GetFileName());
|
|
} else if (strncasecmp(sSockName.c_str() +5, "XFER::LOCAL", 11) == 0) {
|
|
CDCCBounce* pSock = (CDCCBounce*) Manager[a];
|
|
|
|
CString sState = "Waiting";
|
|
if ((pSock->IsConnected()) || (pSock->IsPeerConnected())) {
|
|
sState = "Halfway";
|
|
if ((pSock->IsPeerConnected()) && (pSock->IsPeerConnected())) {
|
|
sState = "Connected";
|
|
}
|
|
}
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Type", "Xfer");
|
|
Table.SetCell("State", sState);
|
|
Table.SetCell("Nick", pSock->GetRemoteNick());
|
|
Table.SetCell("IP", pSock->GetRemoteIP());
|
|
Table.SetCell("File", pSock->GetFileName());
|
|
} else if (strncasecmp(sSockName.c_str() +5, "CHAT::LOCAL", 11) == 0) {
|
|
CDCCBounce* pSock = (CDCCBounce*) Manager[a];
|
|
|
|
CString sState = "Waiting";
|
|
if ((pSock->IsConnected()) || (pSock->IsPeerConnected())) {
|
|
sState = "Halfway";
|
|
if ((pSock->IsPeerConnected()) && (pSock->IsPeerConnected())) {
|
|
sState = "Connected";
|
|
}
|
|
}
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Type", "Chat");
|
|
Table.SetCell("State", sState);
|
|
Table.SetCell("Nick", pSock->GetRemoteNick());
|
|
Table.SetCell("IP", pSock->GetRemoteIP());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Table.size()) {
|
|
unsigned int uTableIdx = 0;
|
|
CString sLine;
|
|
|
|
while (Table.GetLine(uTableIdx++, sLine)) {
|
|
PutStatus(sLine);
|
|
}
|
|
} else {
|
|
PutStatus("You have no active DCCs.");
|
|
}
|
|
} else if ((sCommand.CaseCmp("LISTMODS") == 0) || (sCommand.CaseCmp("LISTMODULES") == 0)) {
|
|
#ifdef _MODULES
|
|
if (m_pUser->IsAdmin()) {
|
|
CModules& GModules = CZNC::Get().GetModules();
|
|
|
|
if (!GModules.size()) {
|
|
PutStatus("No global modules loaded.");
|
|
} else {
|
|
CTable GTable;
|
|
GTable.AddColumn("Name");
|
|
GTable.AddColumn("Description");
|
|
|
|
for (unsigned int b = 0; b < GModules.size(); b++) {
|
|
GTable.AddRow();
|
|
GTable.SetCell("Name", GModules[b]->GetModName());
|
|
GTable.SetCell("Description", GModules[b]->GetDescription().Ellipsize(128));
|
|
}
|
|
|
|
unsigned int uTableIdx = 0; CString sLine;
|
|
|
|
while (GTable.GetLine(uTableIdx++, sLine)) {
|
|
PutStatus(sLine);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_pUser) {
|
|
CModules& Modules = m_pUser->GetModules();
|
|
|
|
if (!Modules.size()) {
|
|
PutStatus("You have no modules loaded.");
|
|
return;
|
|
}
|
|
|
|
CTable Table;
|
|
Table.AddColumn("Name");
|
|
Table.AddColumn("Description");
|
|
|
|
for (unsigned int b = 0; b < Modules.size(); b++) {
|
|
Table.AddRow();
|
|
Table.SetCell("Name", Modules[b]->GetModName());
|
|
Table.SetCell("Description", Modules[b]->GetDescription().Ellipsize(128));
|
|
}
|
|
|
|
unsigned int uTableIdx = 0; CString sLine;
|
|
while (Table.GetLine(uTableIdx++, sLine)) {
|
|
PutStatus(sLine);
|
|
}
|
|
}
|
|
#else
|
|
PutStatus("Modules are not enabled.");
|
|
#endif
|
|
return;
|
|
} else if ((sCommand.CaseCmp("LOADMOD") == 0) || (sCommand.CaseCmp("LOADMODULE") == 0)) {
|
|
CString sMod;
|
|
CString sArgs;
|
|
bool bGlobal = false;
|
|
|
|
if (sLine.Token(1).CaseCmp("-global") == 0) {
|
|
sMod = sLine.Token(2);
|
|
|
|
if (!m_pUser->IsAdmin()) {
|
|
PutStatus("Unable to load global module [" + sMod + "] Access Denied.");
|
|
return;
|
|
}
|
|
|
|
sArgs = sLine.Token(3, true);
|
|
bGlobal = true;
|
|
} else {
|
|
sMod = sLine.Token(1);
|
|
sArgs = sLine.Token(2, true);
|
|
}
|
|
|
|
if (m_pUser->DenyLoadMod()) {
|
|
PutStatus("Unable to load [" + sMod + "] Access Denied.");
|
|
return;
|
|
}
|
|
#ifdef _MODULES
|
|
if (sMod.empty()) {
|
|
PutStatus("Usage: LoadMod [-global] <module> [args]");
|
|
return;
|
|
}
|
|
|
|
CString sModRet;
|
|
|
|
try {
|
|
if (bGlobal) {
|
|
CZNC::Get().GetModules().LoadModule(sMod, sArgs, NULL, sModRet);
|
|
} else {
|
|
m_pUser->GetModules().LoadModule(sMod, sArgs, m_pUser, sModRet);
|
|
}
|
|
} catch (CException e) {
|
|
PutStatus("Unable to load module [" + sMod + "] [" + sModRet + "]");
|
|
return;
|
|
}
|
|
|
|
PutStatus(sModRet);
|
|
#else
|
|
PutStatus("Unable to load [" + sMod + "] Modules are not enabled.");
|
|
#endif
|
|
return;
|
|
} else if ((sCommand.CaseCmp("UNLOADMOD") == 0) || (sCommand.CaseCmp("UNLOADMODULE") == 0)) {
|
|
CString sMod;
|
|
bool bGlobal = false;
|
|
|
|
if (sLine.Token(1).CaseCmp("-global") == 0) {
|
|
sMod = sLine.Token(2);
|
|
|
|
if (!m_pUser->IsAdmin()) {
|
|
PutStatus("Unable to unload global module [" + sMod + "] Access Denied.");
|
|
return;
|
|
}
|
|
|
|
bGlobal = true;
|
|
} else
|
|
sMod = sLine.Token(1);
|
|
|
|
if (m_pUser->DenyLoadMod()) {
|
|
PutStatus("Unable to unload [" + sMod + "] Access Denied.");
|
|
return;
|
|
}
|
|
#ifdef _MODULES
|
|
if (sMod.empty()) {
|
|
PutStatus("Usage: UnloadMod [-global] <module>");
|
|
return;
|
|
}
|
|
|
|
CString sModRet;
|
|
|
|
if (bGlobal) {
|
|
CZNC::Get().GetModules().UnloadModule(sMod, sModRet);
|
|
} else {
|
|
m_pUser->GetModules().UnloadModule(sMod, sModRet);
|
|
}
|
|
|
|
PutStatus(sModRet);
|
|
#else
|
|
PutStatus("Unable to unload [" + sMod + "] Modules are not enabled.");
|
|
#endif
|
|
return;
|
|
} else if ((sCommand.CaseCmp("RELOADMOD") == 0) || (sCommand.CaseCmp("RELOADMODULE") == 0)) {
|
|
CString sMod;
|
|
CString sArgs;
|
|
bool bGlobal = false;
|
|
|
|
if (sLine.Token(1).CaseCmp("-global") == 0) {
|
|
sMod = sLine.Token(2);
|
|
|
|
if (!m_pUser->IsAdmin()) {
|
|
PutStatus("Unable to reload global module [" + sMod + "] Access Denied.");
|
|
return;
|
|
}
|
|
|
|
sArgs = sLine.Token(3, true);
|
|
bGlobal = true;
|
|
} else {
|
|
sMod = sLine.Token(1);
|
|
sArgs = sLine.Token(2, true);
|
|
}
|
|
|
|
if (m_pUser->DenyLoadMod()) {
|
|
PutStatus("Unable to reload [" + sMod + "] Access Denied.");
|
|
return;
|
|
}
|
|
#ifdef _MODULES
|
|
if (sMod.empty()) {
|
|
PutStatus("Usage: ReloadMod [-global] <module> [args]");
|
|
return;
|
|
}
|
|
|
|
CString sModRet;
|
|
|
|
if (bGlobal) {
|
|
CZNC::Get().GetModules().ReloadModule(sMod, sArgs, NULL, sModRet);
|
|
} else {
|
|
m_pUser->GetModules().ReloadModule(sMod, sArgs, m_pUser, sModRet);
|
|
}
|
|
|
|
PutStatus(sModRet);
|
|
#else
|
|
PutStatus("Unable to unload [" + sMod + "] Modules are not enabled.");
|
|
#endif
|
|
return;
|
|
} else if (sCommand.CaseCmp("SETVHOST") == 0) {
|
|
CString sVHost = sLine.Token(1);
|
|
|
|
if (sVHost.empty()) {
|
|
PutStatus("Usage: SetVHost <VHost>");
|
|
}
|
|
|
|
m_pUser->SetVHost(sVHost);
|
|
PutStatus("Set VHost to [" + m_pUser->GetVHost() + "]");
|
|
} else if (sCommand.CaseCmp("PLAYBUFFER") == 0) {
|
|
CString sChan = sLine.Token(1);
|
|
|
|
if (sChan.empty()) {
|
|
PutStatus("Usage: PlayBuffer <#chan>");
|
|
return;
|
|
}
|
|
|
|
CChan* pChan = m_pUser->FindChan(sChan);
|
|
|
|
if (!pChan) {
|
|
PutStatus("You are not on [" + sChan + "]");
|
|
return;
|
|
}
|
|
|
|
if (!pChan->IsOn()) {
|
|
PutStatus("You are not on [" + sChan + "] [trying]");
|
|
return;
|
|
}
|
|
|
|
if (pChan->GetBuffer().empty()) {
|
|
PutStatus("The buffer for [" + sChan + "] is empty");
|
|
return;
|
|
}
|
|
|
|
pChan->SendBuffer(this);
|
|
} else if (sCommand.CaseCmp("CLEARBUFFER") == 0) {
|
|
CString sChan = sLine.Token(1);
|
|
|
|
if (sChan.empty()) {
|
|
PutStatus("Usage: ClearBuffer <#chan>");
|
|
return;
|
|
}
|
|
|
|
CChan* pChan = m_pUser->FindChan(sChan);
|
|
|
|
if (!pChan) {
|
|
PutStatus("You are not on [" + sChan + "]");
|
|
return;
|
|
}
|
|
|
|
if (!pChan->IsOn()) {
|
|
PutStatus("You are not on [" + sChan + "] [trying]");
|
|
return;
|
|
}
|
|
|
|
pChan->ClearBuffer();
|
|
PutStatus("The buffer for [" + sChan + "] has been cleared");
|
|
} else if (sCommand.CaseCmp("CLEARALLCHANNELBUFFERS") == 0) {
|
|
vector<CChan*>::const_iterator it;
|
|
const vector<CChan*>& vChans = m_pUser->GetChans();
|
|
|
|
for (it = vChans.begin(); it != vChans.end(); it++) {
|
|
(*it)->ClearBuffer();
|
|
}
|
|
PutStatus("All channel buffers have been cleared");
|
|
} else if (sCommand.CaseCmp("SETBUFFER") == 0) {
|
|
CString sChan = sLine.Token(1);
|
|
|
|
if (sChan.empty()) {
|
|
PutStatus("Usage: SetBuffer <#chan> [linecount]");
|
|
return;
|
|
}
|
|
|
|
CChan* pChan = m_pUser->FindChan(sChan);
|
|
|
|
if (!pChan) {
|
|
PutStatus("You are not on [" + sChan + "]");
|
|
return;
|
|
}
|
|
|
|
if (!pChan->IsOn()) {
|
|
PutStatus("You are not on [" + sChan + "] [trying]");
|
|
return;
|
|
}
|
|
|
|
unsigned int uLineCount = strtoul(sLine.Token(2).c_str(), NULL, 10);
|
|
|
|
if (uLineCount > 500) {
|
|
PutStatus("Max linecount is 500.");
|
|
return;
|
|
}
|
|
|
|
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<CString, CUser*>& 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<CString, CUser*>::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", "<Users>");
|
|
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", "<ZNC>");
|
|
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", "<Total>");
|
|
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'");
|
|
}
|
|
}
|
|
|
|
bool CClient::SendMotd() {
|
|
const VCString& vsMotd = CZNC::Get().GetMotd();
|
|
|
|
if (!vsMotd.size()) {
|
|
return false;
|
|
}
|
|
|
|
for (unsigned int a = 0; a < vsMotd.size(); a++) {
|
|
PutStatusNotice(vsMotd[a]);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CClient::HelpUser() {
|
|
CTable Table;
|
|
Table.AddColumn("Command");
|
|
Table.AddColumn("Arguments");
|
|
Table.AddColumn("Description");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "Version");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "Prints which version of znc this is");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ListDCCs");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "List all active DCCs");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ListMods");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "List all loaded modules");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ListChans");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "List all channels");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ListNicks");
|
|
Table.SetCell("Arguments", "<#chan>");
|
|
Table.SetCell("Description", "List all nicks on a channel");
|
|
|
|
if (!m_pUser->IsAdmin()) { // If they are an admin we will add this command below with an argument
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ListClients");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "List all clients connected to your znc user");
|
|
}
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ListServers");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "List all servers");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "AddServer");
|
|
Table.SetCell("Arguments", "<host> [[+]port] [pass]");
|
|
Table.SetCell("Description", "Add a server to the list");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "RemServer");
|
|
Table.SetCell("Arguments", "<host>");
|
|
Table.SetCell("Description", "Remove a server from the list");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "Topics");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "Show topics in all channels");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "PlayBuffer");
|
|
Table.SetCell("Arguments", "<#chan>");
|
|
Table.SetCell("Description", "Play back the buffer for a given channel");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ClearBuffer");
|
|
Table.SetCell("Arguments", "<#chan>");
|
|
Table.SetCell("Description", "Clear the buffer for a given channel");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ClearAllChannelBuffers");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "Clear the channel buffers");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "SetBuffer");
|
|
Table.SetCell("Arguments", "<#chan> [linecount]");
|
|
Table.SetCell("Description", "Set the buffer count for a channel");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "SetVHost");
|
|
Table.SetCell("Arguments", "<vhost (ip preferred)>");
|
|
Table.SetCell("Description", "Set the VHost for this connection");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "Jump");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "Jump to the next server in the list");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "Disconnect");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "Disconnect from IRC");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "Connect");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "Reconnect to IRC");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "Send");
|
|
Table.SetCell("Arguments", "<nick> <file>");
|
|
Table.SetCell("Description", "Send a shell file to a nick on IRC");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "Get");
|
|
Table.SetCell("Arguments", "<file>");
|
|
Table.SetCell("Description", "Send a shell file to yourself");
|
|
|
|
if (m_pUser) {
|
|
if (!m_pUser->DenyLoadMod()) {
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "LoadMod");
|
|
Table.SetCell("Arguments", "<module>");
|
|
Table.SetCell("Description", "Load a module");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "UnloadMod");
|
|
Table.SetCell("Arguments", "<module>");
|
|
Table.SetCell("Description", "Unload a module");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ReloadMod");
|
|
Table.SetCell("Arguments", "<module>");
|
|
Table.SetCell("Description", "Reload a module");
|
|
}
|
|
|
|
if (m_pUser->IsAdmin()) {
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "SaveConfig");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "Save the current settings to disk");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ListUsers");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "List all users/clients connected to znc");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ListClients");
|
|
Table.SetCell("Arguments", "[User]");
|
|
Table.SetCell("Description", "List all clients connected to your znc user");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "SetMOTD");
|
|
Table.SetCell("Arguments", "<Message>");
|
|
Table.SetCell("Description", "Set the message of the day");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "AddMOTD");
|
|
Table.SetCell("Arguments", "<Message>");
|
|
Table.SetCell("Description", "Append <Message> to MOTD");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "ClearMOTD");
|
|
Table.SetCell("Arguments", "");
|
|
Table.SetCell("Description", "Clear the MOTD");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "Broadcast");
|
|
Table.SetCell("Arguments", "[message]");
|
|
Table.SetCell("Description", "Broadcast a message to all users");
|
|
|
|
Table.AddRow();
|
|
Table.SetCell("Command", "Shutdown");
|
|
Table.SetCell("Arguments", "[message]");
|
|
Table.SetCell("Description", "Shutdown znc completely");
|
|
}
|
|
}
|
|
|
|
if (Table.size()) {
|
|
unsigned int uTableIdx = 0;
|
|
CString sLine;
|
|
|
|
while (Table.GetLine(uTableIdx++, sLine)) {
|
|
PutStatus(sLine);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CClient::ConnectionFrom(const CString& sHost, unsigned short uPort) {
|
|
DEBUG_ONLY(cout << GetSockName() << " == ConnectionFrom(" << sHost << ", " << uPort << ")" << endl);
|
|
return CZNC::Get().IsHostAllowed(sHost);
|
|
}
|
|
|
|
void CClient::AuthUser() {
|
|
/*
|
|
#ifdef _MODULES
|
|
if (CZNC::Get().GetModules().OnLoginAttempt(m_sUser, m_sPass, *this)) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
CUser* pUser = CZNC::Get().GetUser(m_sUser);
|
|
|
|
if (pUser && pUser->CheckPass(m_sPass)) {
|
|
AcceptLogin(*pUser);
|
|
} else {
|
|
if (pUser) {
|
|
pUser->PutStatus("Another client attempted to login as you, with a bad password.");
|
|
}
|
|
|
|
RefuseLogin();
|
|
}
|
|
*/
|
|
|
|
m_spAuth = new CClientAuth(this, m_sUser, m_sPass);
|
|
|
|
CClientAuth::AuthUser(m_spAuth);
|
|
}
|
|
|
|
void CAuthBase::AuthUser(CSmartPtr<CAuthBase> AuthClass) {
|
|
#ifdef _MODULES
|
|
if (CZNC::Get().GetModules().OnLoginAttempt(AuthClass)) {
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
CUser* pUser = CZNC::Get().GetUser(AuthClass->GetUsername());
|
|
|
|
if (pUser && pUser->CheckPass(AuthClass->GetPassword())) {
|
|
AuthClass->AcceptLogin(*pUser);
|
|
} else {
|
|
if (pUser) {
|
|
pUser->PutStatus("Another client attempted to login as you, with a bad password.");
|
|
}
|
|
|
|
AuthClass->RefuseLogin("Invalid Password");
|
|
}
|
|
}
|
|
|
|
void CClientAuth::RefuseLogin(const CString& sReason) {
|
|
if (m_pClient) {
|
|
m_pClient->RefuseLogin(sReason);
|
|
}
|
|
#ifdef _MODULES
|
|
CZNC::Get().GetModules().OnFailedLogin(GetUsername(), ((m_pClient) ? m_pClient->GetRemoteIP() : CString("")));
|
|
#endif
|
|
}
|
|
|
|
void CClient::RefuseLogin(const CString& sReason) {
|
|
PutStatus("Bad username and/or password.");
|
|
PutClient(":irc.znc.com 464 " + GetNick() + " :" + sReason);
|
|
Close();
|
|
}
|
|
|
|
void CClientAuth::AcceptLogin(CUser& User) {
|
|
if (m_pClient) {
|
|
m_pClient->AcceptLogin(User);
|
|
}
|
|
}
|
|
|
|
void CClient::AcceptLogin(CUser& User) {
|
|
m_sPass = "";
|
|
m_pUser = &User;
|
|
|
|
if (!m_pUser->IsHostAllowed(GetRemoteIP())) {
|
|
PutClient(":irc.znc.com 463 " + GetNick() + " :Your host ("
|
|
+ GetRemoteIP() + ") is not allowed");
|
|
Close();
|
|
return;
|
|
}
|
|
|
|
m_bAuthed = true;
|
|
SetSockName("USR::" + m_pUser->GetUserName());
|
|
|
|
m_pIRCSock = (CIRCSock*) CZNC::Get().FindSockByName("IRC::" + m_pUser->GetUserName());
|
|
m_pUser->UserConnected(this);
|
|
|
|
SendMotd();
|
|
|
|
#ifdef _MODULES
|
|
MODULECALL(OnUserAttached(), m_pUser, this, );
|
|
#endif
|
|
}
|
|
|
|
void CClient::Connected() {
|
|
DEBUG_ONLY(cout << GetSockName() << " == Connected();" << endl);
|
|
SetTimeout(900); // Now that we are connected, let nature take its course
|
|
}
|
|
|
|
void CClient::ConnectionRefused() {
|
|
DEBUG_ONLY(cout << GetSockName() << " == ConnectionRefused()" << endl);
|
|
}
|
|
|
|
void CClient::Disconnected() {
|
|
if (m_pUser) {
|
|
m_pUser->UserDisconnected(this);
|
|
}
|
|
|
|
m_pIRCSock = NULL;
|
|
|
|
#ifdef _MODULES
|
|
MODULECALL(OnUserDetached(), m_pUser, this, );
|
|
#endif
|
|
}
|
|
|
|
void CClient::IRCConnected(CIRCSock* pIRCSock) {
|
|
m_pIRCSock = pIRCSock;
|
|
}
|
|
|
|
void CClient::BouncedOff() {
|
|
PutStatusNotice("You are being disconnected because another user just authenticated as you.");
|
|
m_pIRCSock = NULL;
|
|
Close();
|
|
}
|
|
|
|
void CClient::IRCDisconnected() {
|
|
m_pIRCSock = NULL;
|
|
}
|
|
|
|
Csock* CClient::GetSockObj(const CString& sHost, unsigned short uPort) {
|
|
CClient* pSock = new CClient(sHost, uPort);
|
|
return pSock;
|
|
}
|
|
|
|
void CClient::PutIRC(const CString& sLine) {
|
|
if (m_pIRCSock) {
|
|
m_pIRCSock->PutIRC(sLine);
|
|
}
|
|
}
|
|
|
|
void CClient::PutClient(const CString& sLine) {
|
|
DEBUG_ONLY(cout << "(" << ((m_pUser) ? m_pUser->GetUserName() : CString("")) << ") ZNC -> CLI [" << sLine << "]" << endl);
|
|
Write(sLine + "\r\n");
|
|
}
|
|
|
|
void CClient::PutStatusNotice(const CString& sLine) {
|
|
PutModNotice("status", sLine);
|
|
}
|
|
|
|
void CClient::PutStatus(const CString& sLine) {
|
|
PutModule("status", sLine);
|
|
}
|
|
|
|
void CClient::PutModNotice(const CString& sModule, const CString& sLine) {
|
|
if (!m_pUser) {
|
|
return;
|
|
}
|
|
|
|
DEBUG_ONLY(cout << "(" << m_pUser->GetUserName() << ") ZNC -> CLI [:" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.com NOTICE " << GetNick() << " :" << sLine << "]" << endl);
|
|
Write(":" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.com NOTICE " + GetNick() + " :" + sLine + "\r\n");
|
|
}
|
|
|
|
void CClient::PutModule(const CString& sModule, const CString& sLine) {
|
|
if (!m_pUser) {
|
|
return;
|
|
}
|
|
|
|
DEBUG_ONLY(cout << "(" << m_pUser->GetUserName() << ") ZNC -> CLI [:" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.com PRIVMSG " << GetNick() << " :" << sLine << "]" << endl);
|
|
Write(":" + m_pUser->GetStatusPrefix() + ((sModule.empty()) ? "status" : sModule) + "!znc@znc.com PRIVMSG " + GetNick() + " :" + sLine + "\r\n");
|
|
}
|
|
|
|
CString CClient::GetNick(bool bAllowIRCNick) const {
|
|
CString sRet;
|
|
|
|
if ((bAllowIRCNick) && (m_bAuthed) && (m_pIRCSock)) {
|
|
sRet = m_pIRCSock->GetNick();
|
|
}
|
|
|
|
return (sRet.empty()) ? m_sNick : sRet;
|
|
}
|
|
|
|
CString CClient::GetNickMask() const {
|
|
if (m_pIRCSock) {
|
|
return m_pIRCSock->GetNickMask();
|
|
}
|
|
|
|
return GetNick() + "!" + m_pUser->GetIdent() + "@" + m_pUser->GetVHost();
|
|
}
|