mirror of
https://github.com/znc/znc.git
synced 2026-08-02 23:12:46 +02:00
Make CClient network aware
This commit is contained in:
+323
-230
@@ -11,17 +11,20 @@
|
|||||||
#include "FileUtils.h"
|
#include "FileUtils.h"
|
||||||
#include "IRCSock.h"
|
#include "IRCSock.h"
|
||||||
#include "User.h"
|
#include "User.h"
|
||||||
|
#include "IRCNetwork.h"
|
||||||
#include "znc.h"
|
#include "znc.h"
|
||||||
#include "WebModules.h"
|
#include "WebModules.h"
|
||||||
|
|
||||||
#define CALLMOD(MOD, CLIENT, USER, FUNC) { \
|
#define CALLMOD(MOD, CLIENT, USER, NETWORK, FUNC) { \
|
||||||
CModule* pModule = CZNC::Get().GetModules().FindModule(MOD); \
|
CModule* pModule = CZNC::Get().GetModules().FindModule(MOD); \
|
||||||
if (pModule) { \
|
if (pModule) { \
|
||||||
try { \
|
try { \
|
||||||
pModule->SetClient(CLIENT); \
|
pModule->SetClient(CLIENT); \
|
||||||
|
pModule->SetNetwork(NETWORK); \
|
||||||
pModule->SetUser(USER); \
|
pModule->SetUser(USER); \
|
||||||
pModule->FUNC; \
|
pModule->FUNC; \
|
||||||
pModule->SetClient(NULL); \
|
pModule->SetClient(NULL); \
|
||||||
|
pModule->SetNetwork(NULL); \
|
||||||
pModule->SetUser(NULL); \
|
pModule->SetUser(NULL); \
|
||||||
} catch (CModule::EModException e) { \
|
} catch (CModule::EModException e) { \
|
||||||
if (e == CModule::UNLOAD) { \
|
if (e == CModule::UNLOAD) { \
|
||||||
@@ -33,13 +36,30 @@
|
|||||||
if (pModule) { \
|
if (pModule) { \
|
||||||
try { \
|
try { \
|
||||||
pModule->SetClient(CLIENT); \
|
pModule->SetClient(CLIENT); \
|
||||||
|
pModule->SetNetwork(NETWORK); \
|
||||||
pModule->FUNC; \
|
pModule->FUNC; \
|
||||||
pModule->SetClient(NULL); \
|
pModule->SetClient(NULL); \
|
||||||
|
pModule->SetNetwork(NULL); \
|
||||||
} catch (CModule::EModException e) { \
|
} catch (CModule::EModException e) { \
|
||||||
if (e == CModule::UNLOAD) { \
|
if (e == CModule::UNLOAD) { \
|
||||||
(USER)->GetModules().UnloadModule(MOD); \
|
(USER)->GetModules().UnloadModule(MOD); \
|
||||||
} \
|
} \
|
||||||
} \
|
} \
|
||||||
|
} else if (NETWORK) { \
|
||||||
|
pModule = (NETWORK)->GetModules().FindModule(MOD); \
|
||||||
|
if (pModule) { \
|
||||||
|
try { \
|
||||||
|
pModule->SetClient(CLIENT); \
|
||||||
|
pModule->FUNC; \
|
||||||
|
pModule->SetClient(NULL); \
|
||||||
|
} catch (CModule::EModException e) { \
|
||||||
|
if (e == CModule::UNLOAD) { \
|
||||||
|
(NETWORK)->GetModules().UnloadModule(MOD); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
} else { \
|
||||||
|
PutStatus("No such module [" + MOD + "]"); \
|
||||||
|
} \
|
||||||
} else { \
|
} else { \
|
||||||
PutStatus("No such module [" + MOD + "]"); \
|
PutStatus("No such module [" + MOD + "]"); \
|
||||||
} \
|
} \
|
||||||
@@ -57,17 +77,36 @@ CClient::~CClient() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CClient::ParseAuthLine(CString sLine, bool bPassword) {
|
||||||
|
// bPassword ? [user[/network]:]password : user[/network]
|
||||||
|
|
||||||
|
if (bPassword) {
|
||||||
|
if (sLine.find(":") == CString::npos) {
|
||||||
|
m_sPass = sLine;
|
||||||
|
sLine = "";
|
||||||
|
} else {
|
||||||
|
m_sPass = sLine.Token(1, true, ":");
|
||||||
|
sLine = sLine.Token(0, false, ":");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_sUser.empty() && !sLine.empty()) {
|
||||||
|
m_sUser = sLine.Token(0, false, "/");
|
||||||
|
m_sNetwork = sLine.Token(1, true, "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CClient::ReadLine(const CString& sData) {
|
void CClient::ReadLine(const CString& sData) {
|
||||||
CString sLine = sData;
|
CString sLine = sData;
|
||||||
|
|
||||||
sLine.TrimRight("\n\r");
|
sLine.TrimRight("\n\r");
|
||||||
|
|
||||||
DEBUG("(" << ((m_pUser) ? m_pUser->GetUserName() : GetRemoteIP()) << ") CLI -> ZNC [" << sLine << "]");
|
DEBUG("(" << ((m_pUser) ? m_pUser->GetUserName() : GetRemoteIP()) << ((m_pNetwork) ? ("/" + m_pNetwork->GetName()) : "") << ") CLI -> ZNC [" << sLine << "]");
|
||||||
|
|
||||||
if (IsAttached()) {
|
if (IsAttached()) {
|
||||||
MODULECALL(OnUserRaw(sLine), m_pUser, this, return);
|
MODULECALL(OnUserRaw(sLine), m_pUser, m_pNetwork, this, return);
|
||||||
} else {
|
} else {
|
||||||
GLOBALMODULECALL(OnUnknownUserRaw(sLine), m_pUser, this, return);
|
GLOBALMODULECALL(OnUnknownUserRaw(sLine), m_pUser, m_pNetwork, this, return);
|
||||||
}
|
}
|
||||||
|
|
||||||
CString sCommand = sLine.Token(0);
|
CString sCommand = sLine.Token(0);
|
||||||
@@ -81,15 +120,13 @@ void CClient::ReadLine(const CString& sData) {
|
|||||||
if (sCommand.Equals("PASS")) {
|
if (sCommand.Equals("PASS")) {
|
||||||
if (!IsAttached()) {
|
if (!IsAttached()) {
|
||||||
m_bGotPass = true;
|
m_bGotPass = true;
|
||||||
m_sPass = sLine.Token(1);
|
|
||||||
if (m_sPass.Left(1) == ":")
|
|
||||||
m_sPass.LeftChomp();
|
|
||||||
|
|
||||||
if (m_sPass.find(":") != CString::npos) {
|
CString sAuthLine = sLine.Token(1, true);
|
||||||
m_sUser = m_sPass.Token(0, false, ":");
|
if (sAuthLine.Left(1) == ":") {
|
||||||
m_sPass = m_sPass.Token(1, true, ":");
|
sAuthLine.LeftChomp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParseAuthLine(sAuthLine, true);
|
||||||
AuthUser();
|
AuthUser();
|
||||||
return; // Don't forward this msg. ZNC has already registered us.
|
return; // Don't forward this msg. ZNC has already registered us.
|
||||||
}
|
}
|
||||||
@@ -108,10 +145,7 @@ void CClient::ReadLine(const CString& sData) {
|
|||||||
}
|
}
|
||||||
} else if (sCommand.Equals("USER")) {
|
} else if (sCommand.Equals("USER")) {
|
||||||
if (!IsAttached()) {
|
if (!IsAttached()) {
|
||||||
if (m_sUser.empty()) {
|
ParseAuthLine(sLine.Token(1));
|
||||||
m_sUser = sLine.Token(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_bGotUser = true;
|
m_bGotUser = true;
|
||||||
|
|
||||||
if (m_bGotPass) {
|
if (m_bGotPass) {
|
||||||
@@ -155,28 +189,11 @@ void CClient::ReadLine(const CString& sData) {
|
|||||||
UserCommand(sModCommand);
|
UserCommand(sModCommand);
|
||||||
} else {
|
} else {
|
||||||
if (sModCommand.empty())
|
if (sModCommand.empty())
|
||||||
CALLMOD(sTarget, this, m_pUser, PutModule("Hello. How may I help you?"))
|
CALLMOD(sTarget, this, m_pUser, m_pNetwork, PutModule("Hello. How may I help you?"))
|
||||||
else
|
else
|
||||||
CALLMOD(sTarget, this, m_pUser, OnModCommand(sModCommand))
|
CALLMOD(sTarget, this, m_pUser, m_pNetwork, OnModCommand(sModCommand))
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (sCommand.Equals("DETACH")) {
|
|
||||||
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.Equals("PING")) {
|
} else if (sCommand.Equals("PING")) {
|
||||||
// All PONGs are generated by znc. We will still forward this to
|
// All PONGs are generated by znc. We will still forward this to
|
||||||
// the ircd, but all PONGs from irc will be blocked.
|
// the ircd, but all PONGs from irc will be blocked.
|
||||||
@@ -187,6 +204,206 @@ void CClient::ReadLine(const CString& sData) {
|
|||||||
} else if (sCommand.Equals("PONG")) {
|
} else if (sCommand.Equals("PONG")) {
|
||||||
// Block PONGs, we already responded to the pings
|
// Block PONGs, we already responded to the pings
|
||||||
return;
|
return;
|
||||||
|
} else if (sCommand.Equals("QUIT")) {
|
||||||
|
SetNetwork(NULL, true, false);
|
||||||
|
Close(Csock::CLT_AFTERWRITE); // 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.Equals("PROTOCTL")) {
|
||||||
|
VCString vsTokens;
|
||||||
|
VCString::const_iterator it;
|
||||||
|
sLine.Token(1, true).Split(" ", vsTokens, false);
|
||||||
|
|
||||||
|
for (it = vsTokens.begin(); it != vsTokens.end(); ++it) {
|
||||||
|
if (*it == "NAMESX") {
|
||||||
|
m_bNamesx = true;
|
||||||
|
} else if (*it == "UHNAMES") {
|
||||||
|
m_bUHNames = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return; // If the server understands it, we already enabled namesx / uhnames
|
||||||
|
} else if (sCommand.Equals("NOTICE")) {
|
||||||
|
CString sTarget = sLine.Token(1);
|
||||||
|
CString sMsg = sLine.Token(2, true);
|
||||||
|
|
||||||
|
if (sMsg.Left(1) == ":") {
|
||||||
|
sMsg.LeftChomp();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) {
|
||||||
|
if (!sTarget.Equals("status")) {
|
||||||
|
CALLMOD(sTarget, this, m_pUser, m_pNetwork, OnModNotice(sMsg));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sMsg.WildCmp("\001*\001")) {
|
||||||
|
CString sCTCP = sMsg;
|
||||||
|
sCTCP.LeftChomp();
|
||||||
|
sCTCP.RightChomp();
|
||||||
|
|
||||||
|
MODULECALL(OnUserCTCPReply(sTarget, sCTCP), m_pUser, m_pNetwork, this, return);
|
||||||
|
|
||||||
|
sMsg = "\001" + sCTCP + "\001";
|
||||||
|
} else {
|
||||||
|
MODULECALL(OnUserNotice(sTarget, sMsg), m_pUser, m_pNetwork, this, return);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GetIRCSock()) {
|
||||||
|
// Some lagmeters do a NOTICE to their own nick, ignore those.
|
||||||
|
if (!sTarget.Equals(m_sNick))
|
||||||
|
PutStatus("Your notice to [" + sTarget + "] got lost, "
|
||||||
|
"you are not connected to IRC!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pNetwork) {
|
||||||
|
CChan* pChan = m_pNetwork->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_pNetwork->IsChan(sTarget)) {
|
||||||
|
vector<CClient*>& vClients = 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.Equals("PRIVMSG")) {
|
||||||
|
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 (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) {
|
||||||
|
if (sTarget.Equals("status")) {
|
||||||
|
StatusCTCP(sCTCP);
|
||||||
|
} else {
|
||||||
|
CALLMOD(sTarget, this, m_pUser, m_pNetwork, OnModCTCP(sCTCP));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pNetwork) {
|
||||||
|
CChan* pChan = m_pNetwork->FindChan(sTarget);
|
||||||
|
|
||||||
|
if (sCTCP.Token(0).Equals("ACTION")) {
|
||||||
|
CString sMessage = sCTCP.Token(1, true);
|
||||||
|
MODULECALL(OnUserAction(sTarget, sMessage), m_pUser, m_pNetwork, 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_pNetwork->IsChan(sTarget)) {
|
||||||
|
vector<CClient*>& vClients = 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, m_pNetwork, this, return);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pNetwork) {
|
||||||
|
PutIRC("PRIVMSG " + sTarget + " :\001" + sCTCP + "\001");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) {
|
||||||
|
if (sTarget.Equals("status")) {
|
||||||
|
UserCommand(sMsg);
|
||||||
|
} else {
|
||||||
|
CALLMOD(sTarget, this, m_pUser, m_pNetwork, OnModCommand(sMsg));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MODULECALL(OnUserMsg(sTarget, sMsg), m_pUser, m_pNetwork, this, return);
|
||||||
|
|
||||||
|
if (!GetIRCSock()) {
|
||||||
|
// Some lagmeters do a PRIVMSG to their own nick, ignore those.
|
||||||
|
if (!sTarget.Equals(m_sNick))
|
||||||
|
PutStatus("Your message to [" + sTarget + "] got lost, "
|
||||||
|
"you are not connected to IRC!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pNetwork) {
|
||||||
|
CChan* pChan = m_pNetwork->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_pNetwork->IsChan(sTarget)) {
|
||||||
|
vector<CClient*>& vClients = GetClients();
|
||||||
|
|
||||||
|
for (unsigned int a = 0; a < vClients.size(); a++) {
|
||||||
|
CClient* pClient = vClients[a];
|
||||||
|
|
||||||
|
if (pClient != this) {
|
||||||
|
pClient->PutClient(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + sMsg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_pNetwork) {
|
||||||
|
return; // The following commands require a network
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sCommand.Equals("DETACH")) {
|
||||||
|
CString sChan = sLine.Token(1);
|
||||||
|
|
||||||
|
if (sChan.empty()) {
|
||||||
|
PutStatusNotice("Usage: /detach <#chan>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CChan* pChan = m_pNetwork->FindChan(sChan);
|
||||||
|
if (!pChan) {
|
||||||
|
PutStatusNotice("You are not on [" + sChan + "]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pChan->DetachUser();
|
||||||
|
PutStatusNotice("Detached from [" + sChan + "]");
|
||||||
|
return;
|
||||||
} else if (sCommand.Equals("JOIN")) {
|
} else if (sCommand.Equals("JOIN")) {
|
||||||
CString sChans = sLine.Token(1);
|
CString sChans = sLine.Token(1);
|
||||||
CString sKey = sLine.Token(2);
|
CString sKey = sLine.Token(2);
|
||||||
@@ -201,10 +418,9 @@ void CClient::ReadLine(const CString& sData) {
|
|||||||
|
|
||||||
for (unsigned int a = 0; a < vChans.size(); a++) {
|
for (unsigned int a = 0; a < vChans.size(); a++) {
|
||||||
CString sChannel = vChans[a];
|
CString sChannel = vChans[a];
|
||||||
MODULECALL(OnUserJoin(sChannel, sKey), m_pUser, this, continue);
|
MODULECALL(OnUserJoin(sChannel, sKey), m_pUser, m_pNetwork, this, continue);
|
||||||
|
|
||||||
CChan* pChan = m_pUser->FindChan(sChannel);
|
|
||||||
|
|
||||||
|
CChan* pChan = m_pNetwork->FindChan(sChannel);
|
||||||
if (pChan) {
|
if (pChan) {
|
||||||
pChan->JoinUser(false, sKey);
|
pChan->JoinUser(false, sKey);
|
||||||
continue;
|
continue;
|
||||||
@@ -236,13 +452,13 @@ void CClient::ReadLine(const CString& sData) {
|
|||||||
sMessage.LeftChomp();
|
sMessage.LeftChomp();
|
||||||
}
|
}
|
||||||
|
|
||||||
MODULECALL(OnUserPart(sChan, sMessage), m_pUser, this, return);
|
MODULECALL(OnUserPart(sChan, sMessage), m_pUser, m_pNetwork, this, return);
|
||||||
|
|
||||||
CChan* pChan = m_pUser->FindChan(sChan);
|
CChan* pChan = m_pNetwork->FindChan(sChan);
|
||||||
|
|
||||||
if (pChan && !pChan->IsOn()) {
|
if (pChan && !pChan->IsOn()) {
|
||||||
PutStatusNotice("Removing channel [" + sChan + "]");
|
PutStatusNotice("Removing channel [" + sChan + "]");
|
||||||
m_pUser->DelChan(sChan);
|
m_pNetwork->DelChan(sChan);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,198 +474,29 @@ void CClient::ReadLine(const CString& sData) {
|
|||||||
if (!sTopic.empty()) {
|
if (!sTopic.empty()) {
|
||||||
if (sTopic.Left(1) == ":")
|
if (sTopic.Left(1) == ":")
|
||||||
sTopic.LeftChomp();
|
sTopic.LeftChomp();
|
||||||
MODULECALL(OnUserTopic(sChan, sTopic), m_pUser, this, return);
|
MODULECALL(OnUserTopic(sChan, sTopic), m_pUser, m_pNetwork, this, return);
|
||||||
sLine = "TOPIC " + sChan + " :" + sTopic;
|
sLine = "TOPIC " + sChan + " :" + sTopic;
|
||||||
} else {
|
} else {
|
||||||
MODULECALL(OnUserTopicRequest(sChan), m_pUser, this, return);
|
MODULECALL(OnUserTopicRequest(sChan), m_pUser, m_pNetwork, this, return);
|
||||||
}
|
}
|
||||||
} else if (sCommand.Equals("MODE")) {
|
} else if (m_pNetwork && sCommand.Equals("MODE")) {
|
||||||
CString sTarget = sLine.Token(1);
|
CString sTarget = sLine.Token(1);
|
||||||
CString sModes = sLine.Token(2, true);
|
CString sModes = sLine.Token(2, true);
|
||||||
|
|
||||||
if (m_pUser->IsChan(sTarget)) {
|
if (m_pNetwork->IsChan(sTarget)) {
|
||||||
CChan *pChan = m_pUser->FindChan(sTarget);
|
CChan *pChan = m_pNetwork->FindChan(sTarget);
|
||||||
|
|
||||||
// If we are on that channel and already received a
|
// If we are on that channel and already received a
|
||||||
// /mode reply from the server, we can answer this
|
// /mode reply from the server, we can answer this
|
||||||
// request ourself.
|
// request ourself.
|
||||||
if (pChan && pChan->IsOn() && sModes.empty() && !pChan->GetModeString().empty()) {
|
if (pChan && pChan->IsOn() && sModes.empty() && !pChan->GetModeString().empty()) {
|
||||||
PutClient(":" + m_pUser->GetIRCServer() + " 324 " + GetNick() + " " + sTarget + " " + pChan->GetModeString());
|
PutClient(":" + m_pNetwork->GetIRCServer() + " 324 " + GetNick() + " " + sTarget + " " + pChan->GetModeString());
|
||||||
if (pChan->GetCreationDate() > 0) {
|
if (pChan->GetCreationDate() > 0) {
|
||||||
PutClient(":" + m_pUser->GetIRCServer() + " 329 " + GetNick() + " " + sTarget + " " + CString(pChan->GetCreationDate()));
|
PutClient(":" + m_pNetwork->GetIRCServer() + " 329 " + GetNick() + " " + sTarget + " " + CString(pChan->GetCreationDate()));
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (sCommand.Equals("QUIT")) {
|
|
||||||
m_pUser->UserDisconnected(this);
|
|
||||||
|
|
||||||
Close(Csock::CLT_AFTERWRITE); // 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.Equals("PROTOCTL")) {
|
|
||||||
VCString vsTokens;
|
|
||||||
VCString::const_iterator it;
|
|
||||||
sLine.Token(1, true).Split(" ", vsTokens, false);
|
|
||||||
|
|
||||||
for (it = vsTokens.begin(); it != vsTokens.end(); ++it) {
|
|
||||||
if (*it == "NAMESX") {
|
|
||||||
m_bNamesx = true;
|
|
||||||
} else if (*it == "UHNAMES") {
|
|
||||||
m_bUHNames = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return; // If the server understands it, we already enabled namesx / uhnames
|
|
||||||
} else if (sCommand.Equals("NOTICE")) {
|
|
||||||
CString sTarget = sLine.Token(1);
|
|
||||||
CString sMsg = sLine.Token(2, true);
|
|
||||||
|
|
||||||
if (sMsg.Left(1) == ":") {
|
|
||||||
sMsg.LeftChomp();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) {
|
|
||||||
if (!sTarget.Equals("status")) {
|
|
||||||
CALLMOD(sTarget, this, m_pUser, OnModNotice(sMsg));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!GetIRCSock()) {
|
|
||||||
// Some lagmeters do a NOTICE to their own nick, ignore those.
|
|
||||||
if (!sTarget.Equals(m_sNick))
|
|
||||||
PutStatus("Your notice to [" + sTarget + "] got lost, "
|
|
||||||
"you are not connected to IRC!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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->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.Equals("PRIVMSG")) {
|
|
||||||
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 (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) {
|
|
||||||
if (sTarget.Equals("status")) {
|
|
||||||
StatusCTCP(sCTCP);
|
|
||||||
} else {
|
|
||||||
CALLMOD(sTarget, this, m_pUser, OnModCTCP(sCTCP));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CChan* pChan = m_pUser->FindChan(sTarget);
|
|
||||||
|
|
||||||
if (sCTCP.Token(0).Equals("ACTION")) {
|
|
||||||
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->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 (sTarget.TrimPrefix(m_pUser->GetStatusPrefix())) {
|
|
||||||
if (sTarget.Equals("status")) {
|
|
||||||
UserCommand(sMsg);
|
|
||||||
} else {
|
|
||||||
CALLMOD(sTarget, this, m_pUser, OnModCommand(sMsg));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULECALL(OnUserMsg(sTarget, sMsg), m_pUser, this, return);
|
|
||||||
|
|
||||||
if (!GetIRCSock()) {
|
|
||||||
// Some lagmeters do a PRIVMSG to their own nick, ignore those.
|
|
||||||
if (!sTarget.Equals(m_sNick))
|
|
||||||
PutStatus("Your message to [" + sTarget + "] got lost, "
|
|
||||||
"you are not connected to IRC!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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->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);
|
PutIRC(sLine);
|
||||||
@@ -459,12 +506,48 @@ void CClient::SetNick(const CString& s) {
|
|||||||
m_sNick = s;
|
m_sNick = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CClient::SetNetwork(CIRCNetwork* pNetwork, bool bDisconnect, bool bReconnect) {
|
||||||
|
if (bDisconnect) {
|
||||||
|
if (m_pNetwork) {
|
||||||
|
m_pNetwork->ClientDisconnected(this);
|
||||||
|
} else if (m_pUser) {
|
||||||
|
m_pUser->UserDisconnected(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pNetwork = pNetwork;
|
||||||
|
|
||||||
|
if (bReconnect) {
|
||||||
|
if (m_pNetwork) {
|
||||||
|
m_pNetwork->ClientConnected(this);
|
||||||
|
} else if (m_pUser) {
|
||||||
|
m_pUser->UserConnected(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<CClient*>& CClient::GetClients() {
|
||||||
|
if (m_pNetwork) {
|
||||||
|
return m_pNetwork->GetClients();
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_pUser->GetUserClients();
|
||||||
|
}
|
||||||
|
|
||||||
const CIRCSock* CClient::GetIRCSock() const {
|
const CIRCSock* CClient::GetIRCSock() const {
|
||||||
return m_pUser->GetIRCSock();
|
if (m_pNetwork) {
|
||||||
|
return m_pNetwork->GetIRCSock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
CIRCSock* CClient::GetIRCSock() {
|
CIRCSock* CClient::GetIRCSock() {
|
||||||
return m_pUser->GetIRCSock();
|
if (m_pNetwork) {
|
||||||
|
return m_pNetwork->GetIRCSock();
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::StatusCTCP(const CString& sLine) {
|
void CClient::StatusCTCP(const CString& sLine) {
|
||||||
@@ -542,7 +625,7 @@ void CAuthBase::RefuseLogin(const CString& sReason) {
|
|||||||
"to login as you, but was rejected [" + sReason + "].");
|
"to login as you, but was rejected [" + sReason + "].");
|
||||||
}
|
}
|
||||||
|
|
||||||
GLOBALMODULECALL(OnFailedLogin(GetUsername(), GetRemoteIP()), NULL, NULL, NOTHING);
|
GLOBALMODULECALL(OnFailedLogin(GetUsername(), GetRemoteIP()), NULL, NULL, NULL, NOTHING);
|
||||||
RefusedLogin(sReason);
|
RefusedLogin(sReason);
|
||||||
Invalidate();
|
Invalidate();
|
||||||
}
|
}
|
||||||
@@ -569,11 +652,21 @@ void CClient::AcceptLogin(CUser& User) {
|
|||||||
|
|
||||||
SetSockName("USR::" + m_pUser->GetUserName());
|
SetSockName("USR::" + m_pUser->GetUserName());
|
||||||
|
|
||||||
m_pUser->UserConnected(this);
|
if (!m_sNetwork.empty()) {
|
||||||
|
m_pNetwork = m_pUser->FindNetwork(m_sNetwork);
|
||||||
|
if (!m_pNetwork) {
|
||||||
|
PutStatus("Network (" + m_sNetwork + ") doesn't exist.");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If a user didn't supply a network, and they have a network called "user" then automatically use this network.
|
||||||
|
m_pNetwork = m_pUser->FindNetwork("user");
|
||||||
|
}
|
||||||
|
|
||||||
|
SetNetwork(m_pNetwork, false);
|
||||||
|
|
||||||
SendMotd();
|
SendMotd();
|
||||||
|
|
||||||
MODULECALL(OnClientLogin(), m_pUser, this, NOTHING);
|
MODULECALL(OnClientLogin(), m_pUser, m_pNetwork, this, NOTHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::Timeout() {
|
void CClient::Timeout() {
|
||||||
@@ -590,11 +683,9 @@ void CClient::ConnectionRefused() {
|
|||||||
|
|
||||||
void CClient::Disconnected() {
|
void CClient::Disconnected() {
|
||||||
DEBUG(GetSockName() << " == Disconnected()");
|
DEBUG(GetSockName() << " == Disconnected()");
|
||||||
if (m_pUser) {
|
SetNetwork(NULL, true, false);
|
||||||
m_pUser->UserDisconnected(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
MODULECALL(OnClientDisconnect(), m_pUser, this, NOTHING);
|
MODULECALL(OnClientDisconnect(), m_pUser, m_pNetwork, this, NOTHING);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::ReachedMaxBuffer() {
|
void CClient::ReachedMaxBuffer() {
|
||||||
@@ -611,7 +702,9 @@ void CClient::BouncedOff() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CClient::PutIRC(const CString& sLine) {
|
void CClient::PutIRC(const CString& sLine) {
|
||||||
m_pUser->PutIRC(sLine);
|
if (m_pNetwork) {
|
||||||
|
m_pNetwork->PutIRC(sLine);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CClient::PutClient(const CString& sLine) {
|
void CClient::PutClient(const CString& sLine) {
|
||||||
@@ -687,7 +780,7 @@ void CClient::HandleCap(const CString& sLine)
|
|||||||
|
|
||||||
if (sSubCmd.Equals("LS")) {
|
if (sSubCmd.Equals("LS")) {
|
||||||
SCString ssOfferCaps;
|
SCString ssOfferCaps;
|
||||||
GLOBALMODULECALL(OnClientCapLs(ssOfferCaps), m_pUser, this, NOTHING);
|
GLOBALMODULECALL(OnClientCapLs(ssOfferCaps), m_pUser, m_pNetwork, this, NOTHING);
|
||||||
CString sRes;
|
CString sRes;
|
||||||
for (SCString::iterator i = ssOfferCaps.begin(); i != ssOfferCaps.end(); ++i) {
|
for (SCString::iterator i = ssOfferCaps.begin(); i != ssOfferCaps.end(); ++i) {
|
||||||
sRes += *i + " ";
|
sRes += *i + " ";
|
||||||
@@ -709,7 +802,7 @@ void CClient::HandleCap(const CString& sLine)
|
|||||||
bVal = false;
|
bVal = false;
|
||||||
|
|
||||||
bool bAccepted = ("multi-prefix" == sCap) || ("userhost-in-names" == sCap);
|
bool bAccepted = ("multi-prefix" == sCap) || ("userhost-in-names" == sCap);
|
||||||
GLOBALMODULECALL(IsClientCapSupported(sCap, bVal), m_pUser, this, bAccepted = true);
|
GLOBALMODULECALL(IsClientCapSupported(sCap, bVal), m_pUser, m_pNetwork, this, bAccepted = true);
|
||||||
|
|
||||||
if (!bAccepted) {
|
if (!bAccepted) {
|
||||||
// Some unsupported capability is requested
|
// Some unsupported capability is requested
|
||||||
@@ -729,7 +822,7 @@ void CClient::HandleCap(const CString& sLine)
|
|||||||
} else if ("userhost-in-names" == *it) {
|
} else if ("userhost-in-names" == *it) {
|
||||||
m_bUHNames = bVal;
|
m_bUHNames = bVal;
|
||||||
}
|
}
|
||||||
GLOBALMODULECALL(OnClientCapRequest(*it, bVal), m_pUser, this, NOTHING);
|
GLOBALMODULECALL(OnClientCapRequest(*it, bVal), m_pUser, m_pNetwork, this, NOTHING);
|
||||||
|
|
||||||
if (bVal) {
|
if (bVal) {
|
||||||
m_ssAcceptedCaps.insert(*it);
|
m_ssAcceptedCaps.insert(*it);
|
||||||
@@ -749,9 +842,9 @@ void CClient::HandleCap(const CString& sLine)
|
|||||||
SCString ssRemoved;
|
SCString ssRemoved;
|
||||||
for (SCString::iterator i = m_ssAcceptedCaps.begin(); i != m_ssAcceptedCaps.end(); ++i) {
|
for (SCString::iterator i = m_ssAcceptedCaps.begin(); i != m_ssAcceptedCaps.end(); ++i) {
|
||||||
bool bRemoving = false;
|
bool bRemoving = false;
|
||||||
GLOBALMODULECALL(IsClientCapSupported(*i, false), m_pUser, this, bRemoving = true);
|
GLOBALMODULECALL(IsClientCapSupported(*i, false), m_pUser, m_pNetwork, this, bRemoving = true);
|
||||||
if (bRemoving) {
|
if (bRemoving) {
|
||||||
GLOBALMODULECALL(OnClientCapRequest(*i, false), m_pUser, this, NOTHING);
|
GLOBALMODULECALL(OnClientCapRequest(*i, false), m_pUser, m_pNetwork, this, NOTHING);
|
||||||
ssRemoved.insert(*i);
|
ssRemoved.insert(*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
// Forward Declarations
|
// Forward Declarations
|
||||||
class CZNC;
|
class CZNC;
|
||||||
class CUser;
|
class CUser;
|
||||||
|
class CIRCNetwork;
|
||||||
class CIRCSock;
|
class CIRCSock;
|
||||||
class CClient;
|
class CClient;
|
||||||
// !Forward Declarations
|
// !Forward Declarations
|
||||||
@@ -76,6 +77,7 @@ class CClient : public CZNCSock {
|
|||||||
public:
|
public:
|
||||||
CClient() : CZNCSock() {
|
CClient() : CZNCSock() {
|
||||||
m_pUser = NULL;
|
m_pUser = NULL;
|
||||||
|
m_pNetwork = NULL;
|
||||||
m_bGotPass = false;
|
m_bGotPass = false;
|
||||||
m_bGotNick = false;
|
m_bGotNick = false;
|
||||||
m_bGotUser = false;
|
m_bGotUser = false;
|
||||||
@@ -120,6 +122,7 @@ public:
|
|||||||
bool SendMotd();
|
bool SendMotd();
|
||||||
void HelpUser();
|
void HelpUser();
|
||||||
void AuthUser();
|
void AuthUser();
|
||||||
|
void ParseAuthLine(CString sLine, bool bPassword = false);
|
||||||
virtual void Connected();
|
virtual void Connected();
|
||||||
virtual void Timeout();
|
virtual void Timeout();
|
||||||
virtual void Disconnected();
|
virtual void Disconnected();
|
||||||
@@ -128,6 +131,9 @@ public:
|
|||||||
|
|
||||||
void SetNick(const CString& s);
|
void SetNick(const CString& s);
|
||||||
CUser* GetUser() const { return m_pUser; }
|
CUser* GetUser() const { return m_pUser; }
|
||||||
|
void SetNetwork(CIRCNetwork* pNetwork, bool bDisconnect=true, bool bReconnect=true);
|
||||||
|
CIRCNetwork* GetNetwork() const { return m_pNetwork; }
|
||||||
|
vector<CClient*>& GetClients();
|
||||||
const CIRCSock* GetIRCSock() const;
|
const CIRCSock* GetIRCSock() const;
|
||||||
CIRCSock* GetIRCSock();
|
CIRCSock* GetIRCSock();
|
||||||
private:
|
private:
|
||||||
@@ -142,9 +148,11 @@ protected:
|
|||||||
bool m_bNamesx;
|
bool m_bNamesx;
|
||||||
bool m_bUHNames;
|
bool m_bUHNames;
|
||||||
CUser* m_pUser;
|
CUser* m_pUser;
|
||||||
|
CIRCNetwork* m_pNetwork;
|
||||||
CString m_sNick;
|
CString m_sNick;
|
||||||
CString m_sPass;
|
CString m_sPass;
|
||||||
CString m_sUser;
|
CString m_sUser;
|
||||||
|
CString m_sNetwork;
|
||||||
CSmartPtr<CAuthBase> m_spAuth;
|
CSmartPtr<CAuthBase> m_spAuth;
|
||||||
SCString m_ssAcceptedCaps;
|
SCString m_ssAcceptedCaps;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user