Initial revision

git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@2 726aef4b-f618-498e-8847-2d620e286838
This commit is contained in:
prozacx
2004-08-24 00:08:51 +00:00
parent 71a0088bea
commit 538d3ece4e
41 changed files with 10362 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
#include "Buffer.h"
CBufLine::CBufLine(const string& sPre, const string& sPost) {
m_sPre = sPre;
m_sPost = sPost;
}
CBufLine::~CBufLine() {}
void CBufLine::GetLine(const string& sTarget, string& sRet) {
sRet = m_sPre + sTarget + m_sPost;
}
CBuffer::CBuffer(unsigned int uLineCount) {
m_uLineCount = uLineCount;
}
CBuffer::~CBuffer() {}
int CBuffer::AddLine(const string& sPre, const string& sPost) {
if (!m_uLineCount) {
return 0;
}
if (size() >= m_uLineCount) {
erase(begin());
}
push_back(CBufLine(sPre, sPost));
return size();
}
bool CBuffer::GetLine(const string& sTarget, string& sRet, unsigned int uIdx) {
if (uIdx >= size()) {
return false;
}
(*this)[uIdx].GetLine(sTarget, sRet);
return true;
}
bool CBuffer::GetNextLine(const string& sTarget, string& sRet) {
sRet = "";
if (!size()) {
return false;
}
begin()->GetLine(sTarget, sRet);
erase(begin());
return true;
}
+45
View File
@@ -0,0 +1,45 @@
#ifndef _BUFFER_H
#define _BUFFER_H
#include <string>
#include <vector>
using std::vector;
using std::string;
class CBufLine {
public:
CBufLine(const string& sPre, const string& sPost);
virtual ~CBufLine();
void GetLine(const string& sTarget, string& sRet);
private:
protected:
string m_sPre;
string m_sPost;
};
class CBuffer : private vector<CBufLine> {
public:
CBuffer(unsigned int uLineCount = 100);
virtual ~CBuffer();
int AddLine(const string& sPre, const string& sPost);
bool GetNextLine(const string& sTarget, string& sRet);
bool GetLine(const string& sTarget, string& sRet, unsigned int uIdx);
bool IsEmpty() { return empty(); }
void Clear() { clear(); }
// Setters
void SetLineCount(unsigned int u) { m_uLineCount = u; }
// !Setters
// Getters
unsigned int GetLineCount() const { return m_uLineCount; }
// !Getters
private:
protected:
unsigned int m_uLineCount;
};
#endif // !_BUFFER_H
+311
View File
@@ -0,0 +1,311 @@
#include "Chan.h"
#include "znc.h"
#include "User.h"
#include "Utils.h"
void CChan::Reset() {
m_bWhoDone = false;
m_bIsOn = false;
m_uOpCount = 0;
m_uVoiceCount = 0;
m_uModes = 0;
m_uLimit = 0;
m_uClientRequests = 0;
ClearNicks();
}
void CChan::Joined() {
}
void CChan::Cycle() const {
m_pUser->PutIRC("PART " + GetName() + "\r\nJOIN " + GetName() + " " + GetKey());
}
string CChan::GetModeString() const {
string sRet;
if (m_uModes & Secret) { sRet += "s"; }
if (m_uModes & Private) { sRet += "p"; }
if (m_uModes & OpTopic) { sRet += "t"; }
if (m_uModes & InviteOnly) { sRet += "i"; }
if (m_uModes & NoMessages) { sRet += "n"; }
if (m_uModes & Moderated) { sRet += "m"; }
if (m_uLimit) { sRet += "l"; }
if (m_uModes & Key) { sRet += "k"; }
return (sRet.empty()) ? sRet : ("+" + sRet);
}
void CChan::SetModes(const string& sModes) {
m_uModes = 0;
m_uLimit = 0;
m_sKey = "";
ModeChange(sModes);
}
void CChan::IncClientRequests() {
m_uClientRequests++;
}
bool CChan::DecClientRequests() {
if (!m_uClientRequests) {
return false;
}
m_uClientRequests--;
return true;
}
bool CChan::Who() {
if (m_bWhoDone) {
return false;
}
m_pUser->PutIRC("WHO " + GetName());
return true;
}
void CChan::OnWho(const string& sNick, const string& sIdent, const string& sHost) {
CNick* pNick = FindNick(sNick);
if (pNick) {
pNick->SetIdent(sIdent);
pNick->SetHost(sHost);
}
}
void CChan::ModeChange(const string& sModes, const string& sOpNick) {
string sModeArg = CUtils::Token(sModes, 0);
string sArgs = CUtils::Token(sModes, 1, true);
bool bAdd = true;
#ifdef _MODULES
CNick* pNick = FindNick(sOpNick);
if (pNick) {
m_pUser->GetModules().OnRawMode(*pNick, *this, sModeArg, sArgs);
}
#endif
for (unsigned int a = 0; a < sModeArg.size(); a++) {
switch (sModeArg[a]) {
case '+': bAdd = true; break;
case '-': bAdd = false; break;
case 's': if (bAdd) { m_uModes |= Secret; } else { m_uModes &= ~Secret; } break;
case 'p': if (bAdd) { m_uModes |= Private; } else { m_uModes &= ~Private; } break;
case 'm': if (bAdd) { m_uModes |= Moderated; } else { m_uModes &= ~Moderated; } break;
case 'i': if (bAdd) { m_uModes |= InviteOnly; } else { m_uModes &= ~InviteOnly; } break;
case 'n': if (bAdd) { m_uModes |= NoMessages; } else { m_uModes &= ~NoMessages; } break;
case 't': if (bAdd) { m_uModes |= OpTopic; } else { m_uModes &= ~OpTopic; } break;
case 'l': if (bAdd) { m_uLimit = strtoul(GetModeArg(sArgs).c_str(), NULL, 10); } else { m_uLimit = 0; } break;
case 'k': if (bAdd) { m_uModes |= Key; SetKey(GetModeArg(sArgs)); } else { m_uModes &= ~Key; GetModeArg(sArgs); } break;
case 'o': OnOp(sOpNick, GetModeArg(sArgs), bAdd); break;
case 'v': OnVoice(sOpNick, GetModeArg(sArgs), bAdd); break;
case 'b': // Don't do anything with bans yet
case 'e': // Don't do anything with excepts yet
default: GetModeArg(sArgs); // Pop off an arg, assume new modes will have an argument
}
}
}
string CChan::GetModeArg(string& sArgs) const {
string sRet = sArgs.substr(0, sArgs.find(' '));
sArgs = (sRet.size() < sArgs.size()) ? sArgs.substr(sRet.size() +1) : "";
return sRet;
}
void CChan::ClearNicks() {
for (map<string,CNick*>::iterator a = m_msNicks.begin(); a != m_msNicks.end(); a++) {
delete a->second;
}
m_msNicks.clear();
}
int CChan::AddNicks(const string& sNicks) {
if (IsOn()) {
return 0;
}
int iRet = 0;
string sCurNick;
for (unsigned int a = 0; a < sNicks.size(); a++) {
switch (sNicks[a]) {
case ' ':
if (AddNick(sCurNick)) {
iRet++;
}
sCurNick = "";
break;
default:
sCurNick += sNicks[a];
break;
}
}
if (!sCurNick.empty()) {
if (AddNick(sCurNick)) {
iRet++;
}
}
return iRet;
}
bool CChan::AddNick(const string& sNick) {
const char* p = sNick.c_str();
bool bIsOp = false;
bool bIsVoice = false;
switch (*p) {
case '\0':
return false;
case '@':
bIsOp = true;
case '+':
if (!*++p) {
return false;
}
bIsVoice = !bIsOp;
}
CNick* pNick = FindNick(p);
if (!pNick) {
pNick = new CNick(p);
}
if ((bIsOp) && (!pNick->IsOp())) {
IncOpCount();
pNick->SetOp(true);
} else if ((bIsVoice) && (!pNick->IsVoice())) {
IncVoiceCount();
pNick->SetVoice(true);
}
m_msNicks[pNick->GetNick()] = pNick;
return true;
}
bool CChan::RemNick(const string& sNick) {
map<string,CNick*>::iterator it = m_msNicks.find(sNick);
if (it == m_msNicks.end()) {
return false;
}
if (it->second->IsOp()) {
DecOpCount();
}
if (it->second->IsVoice()) {
DecVoiceCount();
}
delete it->second;
m_msNicks.erase(it);
if ((m_msNicks.size() == 1) && (!m_msNicks.begin()->second->IsOp())) {
Cycle();
}
return true;
}
bool CChan::ChangeNick(const string& sOldNick, const string& sNewNick) {
map<string,CNick*>::iterator it = m_msNicks.find(sOldNick);
if (it == m_msNicks.end()) {
return false;
}
// Rename this nick
it->second->SetNick(sNewNick);
// Insert a new element into the map then erase the old one, do this to change the key
m_msNicks[sNewNick] = it->second;
m_msNicks.erase(it);
return true;
}
void CChan::OnOp(const string& sOpNick, const string& sNick, bool bOpped) {
CNick* pNick = FindNick(sNick);
if (pNick) {
bool bNoChange = (pNick->IsOp() == bOpped);
#ifdef _MODULES
CNick* pOpNick = FindNick(sOpNick);
if (pOpNick) {
if (bOpped) {
m_pUser->GetModules().OnOp(*pOpNick, *pNick, *this, bNoChange);
} else {
m_pUser->GetModules().OnDeop(*pOpNick, *pNick, *this, bNoChange);
}
}
#endif
if (bNoChange) {
// If no change, return
return;
}
pNick->SetOp(bOpped);
(bOpped) ? IncOpCount() : DecOpCount();
}
}
void CChan::OnVoice(const string& sOpNick, const string& sNick, bool bVoiced) {
CNick* pNick = FindNick(sNick);
if (pNick) {
bool bNoChange = (pNick->IsVoice() == bVoiced);
#ifdef _MODULES
CNick* pOpNick = FindNick(sOpNick);
if (pOpNick) {
if (bVoiced) {
m_pUser->GetModules().OnVoice(*pOpNick, *pNick, *this, bNoChange);
} else {
m_pUser->GetModules().OnDevoice(*pOpNick, *pNick, *this, bNoChange);
}
}
#endif
if (bNoChange) {
// If no change, return
return;
}
pNick->SetVoice(bVoiced);
(bVoiced) ? IncVoiceCount() : DecVoiceCount();
}
}
CNick* CChan::FindNick(const string& sNick) const {
map<string,CNick*>::const_iterator it = m_msNicks.find(sNick);
return (it != m_msNicks.end()) ? it->second : NULL;
}
int CChan::AddBuffer(const string& sLine) {
// Todo: revisit the buffering
if (!m_uBufferCount) {
return 0;
}
if (m_vsBuffer.size() >= m_uBufferCount) {
m_vsBuffer.erase(m_vsBuffer.begin());
}
m_vsBuffer.push_back(sLine);
return m_vsBuffer.size();
}
void CChan::ClearBuffer() {
m_vsBuffer.clear();
}
+123
View File
@@ -0,0 +1,123 @@
#ifndef _CHAN_H
#define _CHAN_H
#include "Nick.h"
#include <vector>
#include <map>
using std::vector;
using std::map;
// Forward Declarations
class CUser;
// !Forward Declarations
class CChan {
public:
typedef enum {
Private = 1 << 0,
Secret = 1 << 1,
NoMessages = 1 << 2,
Moderated = 1 << 3,
OpTopic = 1 << 4,
InviteOnly = 1 << 5,
Key = 1 << 6
} EMode;
CChan(const string& sName, CUser* pUser, unsigned int uBufferCount = 0) {
m_sName = sName;
m_pUser = pUser;
m_bKeepBuffer = false;
m_uBufferCount = uBufferCount;
Reset();
}
virtual ~CChan() {
ClearNicks();
}
void Reset();
void Joined();
void Cycle() const;
void IncClientRequests();
bool DecClientRequests();
bool Who();
void OnWho(const string& sNick, const string& sIdent, const string& sHost);
// Modes
void SetModes(const string& s);
void ModeChange(const string& sModes, const string& sNick = "");
void OnOp(const string& sOpNick, const string& sNick, bool bOpped);
void OnVoice(const string& sOpNick, const string& sNick, bool bVoiced);
string GetModeString() const;
string GetModeArg(string& sArgs) const;
// !Modes
// Nicks
void ClearNicks();
CNick* FindNick(const string& sNick) const;
int AddNicks(const string& sNicks);
bool AddNick(const string& sNick);
bool RemNick(const string& sNick);
bool ChangeNick(const string& sOldNick, const string& sNewNick);
// !Nicks
// Buffer
int AddBuffer(const string& sLine);
void ClearBuffer();
// !Buffer
// Setters
void SetIsOn(bool b) { m_bIsOn = b; if (!b) { Reset(); } else { Joined(); } }
void SetKey(const string& s) { m_sKey = s; }
void SetTopic(const string& s) { m_sTopic = s; }
void SetDefaultModes(const string& s) { m_sDefaultModes = s; }
void IncOpCount() { m_uOpCount++; }
void DecOpCount() { m_uOpCount -= (m_uOpCount > 0); }
void IncVoiceCount() { m_uVoiceCount++; }
void DecVoiceCount() { m_uVoiceCount -= (m_uVoiceCount > 0); }
void SetBufferCount(unsigned int u) { m_uBufferCount = u; }
void SetKeepBuffer(bool b) { m_bKeepBuffer = b; }
void SetWhoDone(bool b = true) { m_bWhoDone = b; }
// !Setters
// Getters
const bool IsOn() const { return m_bIsOn; }
const string& GetName() const { return m_sName; }
unsigned int GetModes() const { return m_uModes; }
const string& GetKey() const { return m_sKey; }
unsigned int GetLimit() const { return m_uLimit; }
const string& GetTopic() const { return m_sTopic; }
const string& GetDefaultModes() const { return m_sDefaultModes; }
const vector<string>& GetBans() const { return m_vsBans; }
const vector<string>& GetBuffer() const { return m_vsBuffer; }
const map<string,CNick*>& GetNicks() const { return m_msNicks; }
unsigned int GetNickCount() const { return m_msNicks.size(); }
unsigned int GetOpCount() const { return m_uOpCount; }
unsigned int GetVoiceCount() const { return m_uVoiceCount; }
unsigned int GetBufferCount() const { return m_uBufferCount; }
bool HasMode(EMode eMode) const { return (m_uModes & eMode); }
bool KeepBuffer() const { return m_bKeepBuffer; }
// !Getters
private:
protected:
bool m_bIsOn;
bool m_bWhoDone;
bool m_bKeepBuffer;
string m_sName;
string m_sKey;
string m_sTopic;
CUser* m_pUser;
unsigned int m_uLimit;
unsigned int m_uModes;
string m_sDefaultModes;
vector<string> m_vsBans;
map<string,CNick*> m_msNicks; // Todo: make this caseless (irc style)
unsigned int m_uBufferCount;
unsigned int m_uOpCount;
unsigned int m_uVoiceCount;
unsigned int m_uClientRequests; // Used to tell how many times a client tried to join this chan
vector<string> m_vsBuffer;
};
#endif // !_CHAN_H
Executable
+28
View File
@@ -0,0 +1,28 @@
#!/bin/sh
if [ "$1" = "" ]; then
echo CreatePem.sh file.pem
exit 1
fi
log () {
echo [`date`] $*
}
log Creating Random File for key seed
dd if=/dev/urandom of=blah-1234.txt bs=1024k count=10 >/dev/null 2>&1
openssl genrsa -rand blah-1234.txt -out ${1}.key
openssl req -new -key ${1}.key -out ${1}.csr
openssl x509 -req -days 365 -in ${1}.csr -signkey ${1}.key -out ${1}.crt
log Cleaning up
rm -f blah-1234.txt ${1}.csr
log done
cat ${1}.key > $1
cat ${1}.crt >> $1
rm ${1}.key ${1}.crt
echo "Created $1"
+2545
View File
File diff suppressed because it is too large Load Diff
+130
View File
@@ -0,0 +1,130 @@
#include "DCCBounce.h"
void CDCCBounce::ReadLine(const string& sData) {
string sLine = sData;
while ((CUtils::Right(sLine, 1) == "\r") || (CUtils::Right(sLine, 1) == "\n")) {
CUtils::RightChomp(sLine);
}
DEBUG_ONLY(cout << GetSockName() << " <- [" << sLine << "]" << endl);
PutPeer(sLine);
}
void CDCCBounce::ReadData(const char* data, int len) {
if (m_pPeer) {
m_pPeer->Write(data, len);
}
}
void CDCCBounce::Timeout() {
DEBUG_ONLY(cout << GetSockName() << " == Timeout()" << endl);
string sType = (m_bIsChat) ? "Chat" : "Xfer";
if (IsRemote()) {
string sHost = Csock::GetHostName();
if (!sHost.empty()) {
sHost = " to [" + sHost + ":" + CUtils::ToString(Csock::GetPort()) + "]";
} else {
sHost = ".";
}
m_pUser->PutStatus("DCC " + sType + " Bounce (" + m_sRemoteNick + "): Timeout while connecting" + sHost);
} else {
m_pUser->PutStatus("DCC " + sType + " Bounce (" + m_sRemoteNick + "): Timeout waiting for incoming connection [" + Csock::GetLocalIP() + ":" + CUtils::ToString(Csock::GetLocalPort()) + "]");
}
}
void CDCCBounce::ConnectionRefused() {
DEBUG_ONLY(cout << GetSockName() << " == ConnectionRefused()" << endl);
string sType = (m_bIsChat) ? "Chat" : "Xfer";
string sHost = Csock::GetHostName();
if (!sHost.empty()) {
sHost = " to [" + sHost + ":" + CUtils::ToString(Csock::GetPort()) + "]";
} else {
sHost = ".";
}
m_pUser->PutStatus("DCC " + sType + " Bounce (" + m_sRemoteNick + "): Connection Refused while connecting" + sHost);
}
void CDCCBounce::SockError(int iErrno) {
DEBUG_ONLY(cout << GetSockName() << " == SockError(" << iErrno << ")" << endl);
string sType = (m_bIsChat) ? "Chat" : "Xfer";
if (IsRemote()) {
string sHost = Csock::GetHostName();
if (!sHost.empty()) {
sHost = "[" + sHost + ":" + CUtils::ToString(Csock::GetPort()) + "]";
}
m_pUser->PutStatus("DCC " + sType + " Bounce (" + m_sRemoteNick + "): Socket error [" + string(strerror(iErrno)) + "]" + sHost);
} else {
m_pUser->PutStatus("DCC " + sType + " Bounce (" + m_sRemoteNick + "): Socket error [" + string(strerror(iErrno)) + "] [" + Csock::GetLocalIP() + ":" + CUtils::ToString(Csock::GetLocalPort()) + "]");
}
}
void CDCCBounce::Connected() {
DEBUG_ONLY(cout << GetSockName() << " == Connected()" << endl);
SetTimeout(0);
}
void CDCCBounce::Disconnected() {
DEBUG_ONLY(cout << GetSockName() << " == Disconnected()" << endl);
}
void CDCCBounce::Shutdown() {
m_pPeer = NULL;
DEBUG_ONLY(cerr << GetSockName() << " == Close(); because my peer told me to" << endl);
Close();
}
Csock* CDCCBounce::GetSockObj(const string& sHost, int iPort) {
Close();
if (!m_pManager) {
return NULL;
}
if (m_sRemoteIP.empty()) {
m_sRemoteIP = sHost;
}
CDCCBounce* pSock = new CDCCBounce(sHost, iPort, m_pUser, m_sRemoteNick, m_sRemoteIP, m_sFileName, m_bIsChat);
CDCCBounce* pRemoteSock = new CDCCBounce(sHost, iPort, m_pUser, m_sRemoteNick, m_sRemoteIP, m_sFileName, m_bIsChat);
pSock->SetPeer(pRemoteSock);
pRemoteSock->SetPeer(pSock);
pRemoteSock->SetRemote(true);
pSock->SetRemote(false);
if (!m_pManager->Connect(m_sConnectIP, m_uRemotePort, "DCC::" + string((m_bIsChat) ? "Chat" : "XFER") + "::Remote::" + m_sRemoteNick, 60, false, m_sLocalIP, pRemoteSock)) {
pRemoteSock->Close();
}
pSock->SetSockName(GetSockName());
pSock->SetTimeout(0);
return pSock;
}
void CDCCBounce::PutServ(const string& sLine) {
DEBUG_ONLY(cout << GetSockName() << " -> [" << sLine << "]" << endl);
Write(sLine + "\r\n");
}
void CDCCBounce::PutPeer(const string& sLine) {
if (m_pPeer) {
m_pPeer->PutServ(sLine);
} else {
PutServ("*** Not connected yet ***");
}
}
unsigned short CDCCBounce::DCCRequest(const string& sNick, unsigned long uLongIP, unsigned short uPort, const string& sFileName, bool bIsChat, CUser* pUser, const string& sLocalIP, const string& sRemoteIP) {
CDCCBounce* pDCCBounce = new CDCCBounce(pUser, uLongIP, uPort, sFileName, sNick, sRemoteIP, sLocalIP, bIsChat);
unsigned short uListenPort = pUser->GetManager()->ListenAllRand("DCC::" + string((bIsChat) ? "Chat" : "Xfer") + "::Local::" + sNick, false, SOMAXCONN, pDCCBounce, 120);
return uListenPort;
}
+98
View File
@@ -0,0 +1,98 @@
#ifndef _DCCBOUNCE_H
#define _DCCBOUNCE_H
#include "main.h"
#include "Utils.h"
#include "User.h"
class CDCCBounce : public Csock {
public:
CDCCBounce(CUser* pUser, unsigned long uLongIP, unsigned short uPort, const string& sFileName, const string& sRemoteNick, const string& sRemoteIP, string sLocalIP, bool bIsChat = false) : Csock() {
m_uRemotePort = uPort;
m_sConnectIP = CUtils::GetIP(uLongIP);
m_sRemoteIP = sRemoteIP;
m_sFileName = sFileName;
m_sRemoteNick = sRemoteNick;
m_pUser = pUser;
m_pManager = pUser->GetManager();
m_bIsChat = bIsChat;
m_sLocalIP = sLocalIP;
m_pPeer = NULL;
m_bIsRemote = false;
if (bIsChat) {
EnableReadLine();
}
}
CDCCBounce(const string& sHostname, int iport, CUser* pUser, const string& sRemoteNick, const string& sRemoteIP, const string& sFileName, int itimeout = 60, bool bIsChat = false) : Csock(sHostname, iport, itimeout) {
m_uRemotePort = 0;
m_bIsChat = bIsChat;
m_pManager = pUser->GetManager();
m_pUser = pUser;
m_pPeer = NULL;
m_sRemoteNick = sRemoteNick;
m_sFileName = sFileName;
m_sRemoteIP = sRemoteIP;
m_bIsRemote = false;
if (bIsChat) {
EnableReadLine();
}
}
virtual ~CDCCBounce() {
if (m_pPeer) {
m_pPeer->Shutdown();
m_pPeer = NULL;
}
}
static unsigned short DCCRequest(const string& sNick, unsigned long uLongIP, unsigned short uPort, const string& sFileName, bool bIsChat, CUser* pUser, const string& sLocalIP, const string& sRemoteIP);
void ReadLine(const string& sData);
virtual void ReadData(const char* data, int len);
virtual void Timeout();
virtual void ConnectionRefused();
virtual void SockError(int iErrno);
virtual void Connected();
virtual void Disconnected();
void Shutdown();
Csock* GetSockObj(const string& sHost, int iPort);
void PutServ(const string& sLine);
void PutPeer(const string& sLine);
bool IsPeerConnected() { return (m_pPeer) ? m_pPeer->IsConnected() : false; }
// Setters
void SetPeer(CDCCBounce* p) { m_pPeer = p; }
void SetRemoteIP(const string& s) { m_sRemoteIP = s; }
void SetRemoteNick(const string& s) { m_sRemoteNick = s; }
void SetManager(TSocketManager<Csock>* p) { m_pManager = p; }
void SetRemote(bool b) { m_bIsRemote = b; }
// !Setters
// Getters
unsigned short GetUserPort() const { return m_uRemotePort; }
const string& GetRemoteIP() const { return m_sRemoteIP; }
const string& GetRemoteNick() const { return m_sRemoteNick; }
const string& GetFileName() const { return m_sFileName; }
CDCCBounce* GetPeer() const { return m_pPeer; }
TSocketManager<Csock>* GetManager() const { return m_pManager; }
bool IsRemote() { return m_bIsRemote; }
// !Getters
private:
protected:
string m_sRemoteNick;
string m_sRemoteIP;
string m_sConnectIP;
string m_sLocalIP;
string m_sFileName;
CUser* m_pUser;
CDCCBounce* m_pPeer;
TSocketManager<Csock>* m_pManager;
unsigned short m_uRemotePort;
bool m_bIsChat;
bool m_bIsRemote;
};
#endif // !_DCCBOUNCE_H
+156
View File
@@ -0,0 +1,156 @@
#include "DCCSock.h"
void CDCCSock::ReadData(const char* data, int len) {
if (!m_pFile) {
DEBUG_ONLY(cout << "File not open! closing get." << endl);
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - File not open!");
Close();
}
if (m_bSend) {
m_sSendBuf.append(data, len);
while (m_sSendBuf.size() >= 4) {
unsigned int iRemoteSoFar;
memcpy(&iRemoteSoFar, m_sSendBuf.data(), 4);
iRemoteSoFar = ntohl(iRemoteSoFar);
if (iRemoteSoFar >= m_uBytesSoFar) {
SendPacket();
}
m_sSendBuf.erase(0, 4);
}
} else {
m_pFile->Write(data, len);
m_uBytesSoFar += len;
unsigned long uSoFar = htonl(m_uBytesSoFar);
Write((char*) &uSoFar, sizeof(unsigned long));
if (m_uBytesSoFar >= m_uFileSize) {
Close();
}
}
}
void CDCCSock::ConnectionRefused() {
DEBUG_ONLY(cout << GetSockName() << " == ConnectionRefused()" << endl);
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Connection Refused.");
}
void CDCCSock::Timeout() {
DEBUG_ONLY(cout << GetSockName() << " == Timeout()" << endl);
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Timed Out.");
}
void CDCCSock::SockError(int iErrno) {
DEBUG_ONLY(cout << GetSockName() << " == SockError(" << iErrno << ")" << endl);
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Socket Error [" + CUtils::ToString(iErrno) + "]");
}
void CDCCSock::Connected() {
DEBUG_ONLY(cout << GetSockName() << " == Connected(" << GetRemoteIP() << ")" << endl);
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Transfer Started.");
if (m_bSend) {
SendPacket();
}
SetTimeout(120);
}
void CDCCSock::Disconnected() {
DEBUG_ONLY(cout << GetSockName() << " == Disconnected()" << endl);
if (m_uBytesSoFar > m_uFileSize) {
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - TooMuchData!");
} else if (m_uBytesSoFar == m_uFileSize) {
if (m_bSend) {
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Completed! - Sent [" + m_sLocalFile + "] at [" + CUtils::ToKBytes(GetAvgWrite() / 1000.0) + "]");
} else {
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Completed! - Saved to [" + m_sLocalFile + "] at [" + CUtils::ToKBytes(GetAvgRead() / 1000.0) + "]");
}
} else {
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Incomplete!");
}
}
void CDCCSock::SendPacket() {
if (!m_pFile) {
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - File closed prematurely.");
Close();
return;
}
char szBuf[4096];
int iLen = m_pFile->Read(szBuf, 4096);
if (iLen < 0) {
m_pUser->PutModule(m_sModuleName, ((m_bSend) ? "DCC -> [" : "DCC <- [") + m_sRemoteNick + "][" + m_sFileName + "] - Error reading from file.");
Close();
return;
}
if (iLen > 0) {
Write(szBuf, iLen);
m_uBytesSoFar += iLen;
}
}
Csock* CDCCSock::GetSockObj(const string& sHost, int iPort) {
Close();
CDCCSock* pSock = new CDCCSock(m_pUser, m_sRemoteNick, m_sLocalFile, m_sModuleName, m_uFileSize, m_pFile);
pSock->SetSockName("DCC::SEND::" + m_sRemoteNick);
pSock->SetTimeout(120);
pSock->SetFileName(m_sFileName);
pSock->SetFileOffset(m_uBytesSoFar);
m_bNoDelFile = true;
return pSock;
}
CFile* CDCCSock::OpenFile(bool bWrite) {
if ((m_pFile) || (m_sLocalFile.empty())) {
m_pUser->PutModule(m_sModuleName, ((bWrite) ? "DCC <- [" : "DCC -> [") + m_sRemoteNick + "][" + m_sLocalFile + "] - Unable to open file.");
return false;
}
m_pFile = new CFile(m_sLocalFile);
if (bWrite) {
if (m_pFile->Exists()) {
delete m_pFile;
m_pFile = NULL;
m_pUser->PutModule(m_sModuleName, "DCC <- [" + m_sRemoteNick + "] - File already exists [" + m_sLocalFile + "]");
return NULL;
}
if (!m_pFile->Open(O_WRONLY | O_TRUNC | O_CREAT)) {
delete m_pFile;
m_pFile = NULL;
m_pUser->PutModule(m_sModuleName, "DCC <- [" + m_sRemoteNick + "] - Could not open file [" + m_sLocalFile + "]");
return NULL;
}
} else {
if (!m_pFile->IsReg()) {
delete m_pFile;
m_pFile = NULL;
m_pUser->PutModule(m_sModuleName, "DCC -> [" + m_sRemoteNick + "] - Not a file [" + m_sLocalFile + "]");
return NULL;
}
if (!m_pFile->Open(O_RDONLY)) {
delete m_pFile;
m_pFile = NULL;
m_pUser->PutModule(m_sModuleName, "DCC -> [" + m_sRemoteNick + "] - Could not open file [" + m_sLocalFile + "]");
return NULL;
}
m_uFileSize = m_pFile->GetSize();
}
m_sFileName = m_pFile->GetShortName();
return m_pFile;
}
+108
View File
@@ -0,0 +1,108 @@
#ifndef _DCCSOCK_H
#define _DCCSOCK_H
#include "main.h"
#include "Utils.h"
#include "User.h"
class CDCCSock : public Csock {
public:
CDCCSock(CUser* pUser, const string& sRemoteNick, const string& sLocalFile, const string& sModuleName, unsigned long uFileSize = 0, CFile* pFile = NULL) : Csock() {
m_sRemoteNick = sRemoteNick;
m_uFileSize = uFileSize;
m_uRemotePort = 0;
m_uBytesSoFar = 0;
m_pUser = pUser;
m_pFile = pFile;
m_sLocalFile = sLocalFile;
m_sModuleName = sModuleName;
m_bSend = true;
m_bNoDelFile = false;
}
CDCCSock(CUser* pUser, const string& sRemoteNick, const string& sRemoteIP, unsigned short uRemotePort, const string& sLocalFile, unsigned long uFileSize, const string& sModuleName) : Csock() {
m_sRemoteNick = sRemoteNick;
m_sRemoteIP = sRemoteIP;
m_uRemotePort = uRemotePort;
m_uFileSize = uFileSize;
m_uBytesSoFar = 0;
m_pUser = pUser;
m_pFile = NULL;
m_sLocalFile = sLocalFile;
m_sModuleName = sModuleName;
m_bSend = false;
m_bNoDelFile = false;
}
/* CDCCSock(CUser* pUser, const string& sHostname, int iport, int itimeout = 60) : Csock(sHostname, iport, itimeout) {
m_uRemotePort = 0;
m_uBytesSoFar = 0;
m_uFileSize = 0;
m_pFile = NULL;
m_pUser = pUser;
m_bNoDelFile = false;
}
*/
virtual ~CDCCSock() {
if ((m_pFile) && (!m_bNoDelFile)) {
m_pFile->Close();
delete m_pFile;
}
}
virtual void ReadData(const char* data, int len);
virtual void ConnectionRefused();
virtual void SockError(int iErrno);
virtual void Timeout();
virtual void Connected();
virtual void Disconnected();
void SendPacket();
Csock* GetSockObj(const string& sHost, int iPort);
CFile* OpenFile(bool bWrite = true);
bool Seek(unsigned int uPos) {
if (m_pFile) {
if (m_pFile->Seek(uPos)) {
m_uBytesSoFar = uPos;
return true;
}
}
return false;
}
// Setters
void SetRemoteIP(const string& s) { m_sRemoteIP = s; }
void SetRemoteNick(const string& s) { m_sRemoteNick = s; }
void SetFileName(const string& s) { m_sFileName = s; }
void SetFileOffset(unsigned long u) { m_uBytesSoFar = u; }
// !Setters
// Getters
unsigned short GetUserPort() const { return m_uRemotePort; }
const string& GetRemoteNick() const { return m_sRemoteNick; }
const string& GetFileName() const { return m_sFileName; }
const string& GetLocalFile() const { return m_sLocalFile; }
const string& GetModuleName() const { return m_sModuleName; }
CFile* GetFile() { return m_pFile; }
double GetProgress() const { return ((m_uFileSize) && (m_uBytesSoFar)) ? (double) (((double) m_uBytesSoFar / (double) m_uFileSize) *100.0) : 0; }
//const string& GetRemoteIP() const { return m_sRemoteIP; }
// !Getters
private:
protected:
string m_sRemoteNick;
string m_sRemoteIP;
string m_sFileName;
string m_sLocalFile;
string m_sSendBuf;
string m_sModuleName;
unsigned short m_uRemotePort;
unsigned long m_uFileSize;
unsigned long m_uBytesSoFar;
bool m_bSend;
bool m_bNoDelFile;
CFile* m_pFile;
CUser* m_pUser;
};
#endif // !_DCCSOCK_H
+742
View File
@@ -0,0 +1,742 @@
#include "znc.h"
#include "IRCSock.h"
#include "DCCBounce.h"
#include "UserSock.h"
CIRCSock::CIRCSock(CZNC* pZNC, CUser* pUser) : Csock() {
m_pZNC = pZNC;
m_pUser = pUser;
m_pUserSock = NULL;
m_uQueryBufferCount = 50;
m_bISpoofReleased = false;
m_bKeepNick = true;
m_bAuthed = false;
EnableReadLine();
m_RawBuffer.SetLineCount(100); // This should be more than enough raws, especially since we are asking the server to resend MOTD
m_Nick.SetIdent(pUser->GetIdent());
m_Nick.SetHost(pUser->GetVHost());
}
CIRCSock::~CIRCSock() {
for (map<string, CChan*>::iterator a = m_msChans.begin(); a != m_msChans.end(); a++) {
delete a->second;
}
if (!m_bISpoofReleased) {
m_pZNC->ReleaseISpoof();
}
PutServ("QUIT :");
m_msChans.clear();
}
void CIRCSock::ReadLine(const string& sData) {
string sLine = sData;
while ((CUtils::Right(sLine, 1) == "\r") || (CUtils::Right(sLine, 1) == "\n")) {
CUtils::RightChomp(sLine);
}
DEBUG_ONLY(cout << GetSockName() << " <- [" << sLine << "]" << endl);
#ifdef _MODULES
if (m_pUser->GetModules().OnRaw(sLine)) {
return;
}
#endif
if (strncasecmp(sLine.c_str(), "PING ", 5) == 0) {
PutServ("PONG " + sLine.substr(5));
} else if (CUtils::WildCmp(":* * *", sLine.c_str())) { //"^:(\\S+) (\\d\\d\\d) (.*?) (.*)$", vCap)) {
string sCmd = CUtils::Token(sLine, 1);
if ((sCmd.length() == 3) && (isdigit(sCmd[0])) && (isdigit(sCmd[1])) && (isdigit(sCmd[2]))) {
string sServer = CUtils::Token(sLine, 0); CUtils::LeftChomp(sServer);
unsigned int uRaw = strtoul(sCmd.c_str(), NULL, 10);
string sNick = CUtils::Token(sLine, 2);
string sRest = CUtils::Token(sLine, 3, true);
switch (uRaw) {
case 1: {// :irc.server.com 001 nick :Welcome to the Internet Relay Network nick
SetTimeout(900); // Now that we are connected, let nature take its course
PutServ("WHO " + sNick);
#ifdef _MODULES
m_pUser->GetModules().OnIRCConnected();
#endif
m_bAuthed = true;
m_pUser->PutStatus("Connected!");
if (m_pUserSock) {
string sClientNick = m_pUserSock->GetNick();
if (strcasecmp(sClientNick.c_str(), sNick.c_str()) != 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);
}
}
SetNick(sNick);
m_RawBuffer.Clear();
m_RawBuffer.AddLine(":" + sServer + " " + sCmd + " ", " " + sRest);
// Now that we are connected, we need to join our chans
const vector<CChan*>& vChans = m_pUser->GetChans();
for (unsigned int a = 0; a < vChans.size(); a++) {
PutServ("JOIN " + vChans[a]->GetName() + " " + vChans[a]->GetKey());
}
m_pZNC->ReleaseISpoof();
m_bISpoofReleased = true;
break;
}
case 2:
case 3:
case 4:
case 5:
case 250: // highest connection count
case 251: // user count
case 252: // oper count
case 254: // channel count
case 255: // client count
case 265: // local users
case 266: // global users
m_RawBuffer.AddLine(":" + sServer + " " + sCmd + " ", " " + sRest);
break;
case 372: // motd
case 375: // begin motd
case 376: // end motd
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) {
CChan* pChan = m_pUser->FindChan(sRest.substr(0, sRest.find(' ')));
if ((pChan) && (!pChan->IsOn())) {
if (!pChan->DecClientRequests()) {
return;
}
}
}
break;
case 433: {
string sBadNick = CUtils::Token(sRest, 0);
string sConfNick = m_pUser->GetNick();
if (sNick == "*") {
string sAltNick = m_pUser->GetAltNick();
if (strcasecmp(sBadNick.c_str(), sConfNick.c_str()) == 0) {
if ((!sAltNick.empty()) && (strcasecmp(sConfNick.c_str(), sAltNick.c_str()) != 0)) {
PutServ("NICK " + sAltNick);
} else {
PutServ("NICK " + CUtils::Left(sConfNick, 8) + "-");
}
} else if (strcasecmp(sBadNick.c_str(), sAltNick.c_str()) == 0) {
PutServ("NICK " + CUtils::Left(sConfNick, 8) + "-");
} else if (strcasecmp(sBadNick.c_str(), string(CUtils::Left(sConfNick, 8) + "-").c_str()) == 0) {
PutServ("NICK " + CUtils::Left(sConfNick, 8) + "|");
} else if (strcasecmp(sBadNick.c_str(), string(CUtils::Left(sConfNick, 8) + "|").c_str()) == 0) {
PutServ("NICK " + CUtils::Left(sConfNick, 8) + "^");
} else {
char cLetter = 0;
if (sBadNick.empty()) {
Close();
return;
}
cLetter = CUtils::Right(sBadNick, 1)[0];
if (cLetter == 'z') {
Close();
return;
}
string sSend = "NICK " + CUtils::Left(sConfNick, 8) + cLetter++;
PutServ(sSend);
}
return;
} else {
// :irc.server.net 433 mynick badnick :Nickname is already in use.
if ((m_bKeepNick) && (m_pUser->KeepNick())) {
if (strcasecmp(sBadNick.c_str(), sConfNick.c_str()) == 0) {
if ((!m_pUserSock) || (!m_pUserSock->DecKeepNickCounter())) {
return;
}
}
}
}
break;
}
case 315: {
// :irc.server.com 315 yournick #chan :End of /WHO list.
CChan* pChan = m_pUser->FindChan(CUtils::Token(sLine, 3));
if (pChan) {
pChan->SetWhoDone();
}
}
case 352: {
// :irc.yourserver.com 352 yournick #chan ident theirhost.com irc.theirserver.com theirnick H :0 Real Name
string sNick = CUtils::Token(sLine, 7);
string sIdent = CUtils::Token(sLine, 4);
string sHost = CUtils::Token(sLine, 5);
if (strcasecmp(sNick.c_str(), GetNick().c_str()) == 0) {
m_Nick.SetIdent(sIdent);
m_Nick.SetHost(sHost);
}
const vector<CChan*>& vChans = m_pUser->GetChans();
for (unsigned int a = 0; a < vChans.size(); a++) {
vChans[a]->OnWho(sNick, sIdent, sHost);
}
break;
}
case 324: { // MODE
CUtils::Trim(sRest);
CChan* pChan = m_pUser->FindChan(CUtils::Token(sRest, 0));
if (pChan) {
pChan->SetModes(CUtils::Token(sRest, 1, true));
}
}
break;
case 353: { // NAMES
CUtils::Trim(sRest);
// Todo: allow for non @+= server msgs
CChan* pChan = m_pUser->FindChan(CUtils::Token(sRest, 1));
if (pChan) {
string sNicks = CUtils::Token(sRest, 2, true);
if (CUtils::Left(sNicks, 1) == ":") {
CUtils::LeftChomp(sNicks);
}
pChan->AddNicks(sNicks);
}
}
break;
case 366: { // end of names list
PutUser(sLine); // First send them the raw
// :irc.server.com 366 nick #chan :End of /NAMES list.
CChan* pChan = m_pUser->FindChan(CUtils::Token(sRest, 0));
if (pChan) {
if (IsUserAttached()) {
const vector<string>& vsBuffer = pChan->GetBuffer();
if (vsBuffer.size()) {
PutUser(":***!znc@znc.com PRIVMSG " + pChan->GetName() + " :Buffer Playback...");
for (unsigned int a = 0; a < vsBuffer.size(); a++) {
PutUser(vsBuffer[a]);
}
if (!pChan->KeepBuffer()) {
pChan->ClearBuffer();
}
PutUser(":***!znc@znc.com PRIVMSG " + pChan->GetName() + " :Playback Complete.");
}
}
if (!pChan->IsOn()) {
pChan->SetIsOn(true);
PutServ("MODE " + pChan->GetName());
// If we are the only one in the chan, set our default modes
if (pChan->GetNickCount() == 1) {
string sModes = pChan->GetDefaultModes();
if (sModes.empty()) {
sModes = m_pUser->GetDefaultChanModes();
}
if (!sModes.empty()) {
PutServ("MODE " + pChan->GetName() + " " + sModes);
}
}
}
}
return; // return so we don't send them the raw twice
}
}
} else { //if (CUtils::WildCmp(":*!*@* * *", sLine.c_str())) {
string sNickMask = CUtils::Token(sLine, 0);
CUtils::LeftChomp(sNickMask);
string sNick = CUtils::Token(sNickMask, 0, false, '!');
string sCmd = CUtils::Token(sLine, 1);
string sRest = CUtils::Token(sLine, 2, true);
if (strcasecmp(sCmd.c_str(), "NICK") == 0) {
string sNewNick = sRest;
if (CUtils::Left(sNewNick, 1) == ":") {
CUtils::LeftChomp(sNewNick);
}
const vector<CChan*>& vChans = m_pUser->GetChans();
for (unsigned int a = 0; a < vChans.size(); a++) {
vChans[a]->ChangeNick(sNick, sNewNick);
}
if (strcasecmp(sNick.c_str(), GetNick().c_str()) == 0) {
SetNick(sNewNick);
if (strcasecmp(sNick.c_str(), m_pUser->GetNick().c_str()) == 0) {
// If the user changes his nick away from the config nick, we shut off keepnick for this session
m_bKeepNick = false;
}
} else if (strcasecmp(sNick.c_str(), m_pUser->GetNick().c_str()) == 0) {
KeepNick();
}
#ifdef _MODULES
m_pUser->GetModules().OnNick(sNickMask, sNewNick);
#endif
} else if (strcasecmp(sCmd.c_str(), "QUIT") == 0) {
string sChan = sRest;
if (CUtils::Left(sChan, 1) == ":") {
CUtils::LeftChomp(sChan);
}
// :nick!ident@host.com QUIT :message
CNick Nick(sNickMask);
const vector<CChan*>& vChans = m_pUser->GetChans();
for (unsigned int a = 0; a < vChans.size(); a++) {
vChans[a]->RemNick(sNick);
}
if (strcasecmp(Nick.GetNick().c_str(), m_pUser->GetNick().c_str()) == 0) {
KeepNick();
}
#ifdef _MODULES
m_pUser->GetModules().OnQuit(Nick, sChan);
#endif
} else if (strcasecmp(sCmd.c_str(), "JOIN") == 0) {
string sChan = sRest;
if (CUtils::Left(sChan, 1) == ":") {
CUtils::LeftChomp(sChan);
}
if (strcasecmp(sNick.c_str(), GetNick().c_str()) == 0) {
m_pUser->AddChan(sChan);
}
CChan* pChan = m_pUser->FindChan(sChan);
if (pChan) {
pChan->AddNick(sNickMask);
#ifdef _MODULES
m_pUser->GetModules().OnJoin(sNickMask, *pChan);
#endif
}
} else if (strcasecmp(sCmd.c_str(), "PART") == 0) {
string sChan = sRest;
if (CUtils::Left(sChan, 1) == ":") {
CUtils::LeftChomp(sChan);
}
CChan* pChan = m_pUser->FindChan(sChan);
if (pChan) {
pChan->RemNick(sNick);
#ifdef _MODULES
m_pUser->GetModules().OnPart(sNickMask, *pChan);
#endif
}
if (strcasecmp(sNick.c_str(), GetNick().c_str()) == 0) {
m_pUser->DelChan(sChan);
}
} else if (strcasecmp(sCmd.c_str(), "MODE") == 0) {
string sChan = CUtils::Token(sRest, 0);
string sModes = CUtils::Token(sRest, 1, true);
CChan* pChan = m_pUser->FindChan(sChan);
if (pChan) {
pChan->ModeChange(sModes, sNick);
}
} else if (strcasecmp(sCmd.c_str(), "KICK") == 0) {
// :opnick!ident@host.com KICK #chan nick :msg
string sChan = CUtils::Token(sRest, 0);
string sKickedNick = CUtils::Token(sRest, 1);
string sMsg = CUtils::Token(sRest, 2, true);
CUtils::LeftChomp(sMsg);
CChan* pChan = m_pUser->FindChan(sChan);
if (pChan) {
pChan->RemNick(sKickedNick);
#ifdef _MODULES
m_pUser->GetModules().OnKick(sNickMask, sKickedNick, *pChan, sMsg);
#endif
}
if (strcasecmp(GetNick().c_str(), sKickedNick.c_str()) == 0) {
string sKey;
if (pChan) {
sKey = pChan->GetKey();
pChan->SetIsOn(false);
}
PutServ("JOIN " + sChan + " " + sKey);
}
} else if (strcasecmp(sCmd.c_str(), "NOTICE") == 0) {
// :nick!ident@host.com NOTICE #chan :Message
CNick Nick(sNickMask);
string sTarget = CUtils::Token(sRest, 0);
string sMsg = CUtils::Token(sRest, 1, true);
CUtils::LeftChomp(sMsg);
if (CUtils::WildCmp("\001*\001", sMsg.c_str())) {
CUtils::LeftChomp(sMsg);
CUtils::RightChomp(sMsg);
if (strcasecmp(sTarget.c_str(), GetNick().c_str()) == 0) {
if (OnCTCPReply(sNickMask, sMsg)) {
return;
}
}
PutUser(":" + sNickMask + " NOTICE " + sTarget + " :\001" + sMsg + "\001");
return;
} else {
if (strcasecmp(sTarget.c_str(), GetNick().c_str()) == 0) {
if (OnPrivNotice(sNickMask, sMsg)) {
return;
}
} else {
if (OnChanNotice(sNickMask, sTarget, sMsg)) {
return;
}
}
}
PutUser(":" + sNickMask + " NOTICE " + sTarget + " :" + sMsg);
return;
} else if (strcasecmp(sCmd.c_str(), "PRIVMSG") == 0) {
// :nick!ident@host.com PRIVMSG #chan :Message
CNick Nick(sNickMask);
string sTarget = CUtils::Token(sRest, 0);
string sMsg = CUtils::Token(sRest, 1, true);
if (CUtils::Left(sMsg, 1) == ":") {
CUtils::LeftChomp(sMsg);
}
if (CUtils::WildCmp("\001*\001", sMsg.c_str())) {
CUtils::LeftChomp(sMsg);
CUtils::RightChomp(sMsg);
if (strcasecmp(sTarget.c_str(), GetNick().c_str()) == 0) {
if (OnPrivCTCP(sNickMask, sMsg)) {
return;
}
} else {
if (OnChanCTCP(sNickMask, sTarget, sMsg)) {
return;
}
}
PutUser(":" + sNickMask + " PRIVMSG " + sTarget + " :\001" + sMsg + "\001");
return;
} else {
if (strcasecmp(sTarget.c_str(), GetNick().c_str()) == 0) {
if (OnPrivMsg(sNickMask, sMsg)) {
return;
}
} else {
if (OnChanMsg(sNickMask, sTarget, sMsg)) {
return;
}
}
PutUser(":" + sNickMask + " PRIVMSG " + sTarget + " :" + sMsg);
return;
}
}
}
}
PutUser(sLine);
}
void CIRCSock::KeepNick() {
const string& sConfNick = m_pUser->GetNick();
if ((m_bAuthed) && (m_bKeepNick) && (m_pUser->KeepNick()) && (strcasecmp(GetNick().c_str(), sConfNick.c_str()) != 0)) {
PutServ("NICK " + sConfNick);
}
}
bool CIRCSock::OnCTCPReply(const string& sNickMask, string& sMessage) {
#ifdef _MODULES
if (m_pUser->GetModules().OnCTCPReply(sNickMask, sMessage)) {
return true;
}
#endif
return false;
}
bool CIRCSock::OnPrivCTCP(const string& sNickMask, string& sMessage) {
#ifdef _MODULES
if (m_pUser->GetModules().OnPrivCTCP(sNickMask, sMessage)) {
return true;
}
#endif
// DCC CHAT chat 2453612361 44592
if (strncasecmp(sMessage.c_str(), "DCC ", 4) == 0) {
string sType = CUtils::Token(sMessage, 1);
string sFile = CUtils::Token(sMessage, 2);
unsigned long uLongIP = strtoul(CUtils::Token(sMessage, 3).c_str(), NULL, 10);
unsigned short uPort = strtoul(CUtils::Token(sMessage, 4).c_str(), NULL, 10);
unsigned long uFileSize = strtoul(CUtils::Token(sMessage, 5).c_str(), NULL, 10);
if (strcasecmp(sType.c_str(), "CHAT") == 0) {
if (m_pUserSock) {
CNick FromNick(sNickMask);
unsigned short uBNCPort = CDCCBounce::DCCRequest(FromNick.GetNick(), uLongIP, uPort, "", true, m_pUser, GetLocalIP(), CUtils::GetIP(uLongIP));
if (uBNCPort) {
PutUser(":" + sNickMask + " PRIVMSG " + GetNick() + " :\001DCC CHAT chat " + CUtils::ToString(CUtils::GetLongIP(GetLocalIP())) + " " + CUtils::ToString(uBNCPort) + "\001");
}
}
} else if (strcasecmp(sType.c_str(), "SEND") == 0) {
// DCC SEND readme.txt 403120438 5550 1104
CNick FromNick(sNickMask);
unsigned short uBNCPort = CDCCBounce::DCCRequest(FromNick.GetNick(), uLongIP, uPort, sFile, false, m_pUser, GetLocalIP(), CUtils::GetIP(uLongIP));
if (uBNCPort) {
PutUser(":" + sNickMask + " PRIVMSG " + GetNick() + " :\001DCC SEND " + sFile + " " + CUtils::ToString(CUtils::GetLongIP(GetLocalIP())) + " " + CUtils::ToString(uBNCPort) + " " + CUtils::ToString(uFileSize));
}
} else if (strcasecmp(sType.c_str(), "RESUME") == 0) {
// Need to lookup the connection by port, filter the port, and forward to the user
CDCCBounce* pSock = (CDCCBounce*) m_pZNC->GetManager().FindSockByLocalPort(atoi(CUtils::Token(sMessage, 3).c_str()));
if ((pSock) && (strncasecmp(pSock->GetSockName().c_str(), "DCC::", 5) == 0)) {
PutUser(":" + sNickMask + " PRIVMSG " + GetNick() + " :\001DCC " + sType + " " + sFile + " " + CUtils::ToString(pSock->GetUserPort()) + " " + CUtils::Token(sMessage, 4) + "\001");
}
} else if (strcasecmp(sType.c_str(), "ACCEPT") == 0) {
// Need to lookup the connection by port, filter the port, and forward to the user
TSocketManager<Csock>& Manager = m_pZNC->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(CUtils::Token(sMessage, 3).c_str())) {
PutUser(":" + sNickMask + " PRIVMSG " + GetNick() + " :\001DCC " + sType + " " + sFile + " " + CUtils::ToString(pSock->GetLocalPort()) + " " + CUtils::Token(sMessage, 4) + "\001");
}
}
}
}
return true;
}
return false;
}
bool CIRCSock::OnPrivNotice(const string& sNickMask, string& sMessage) {
#ifdef _MODULES
if (m_pUser->GetModules().OnPrivNotice(sNickMask, sMessage)) {
return true;
}
#endif
if (!m_pUserSock) {
// If the user is detached, add to the buffer
m_QueryBuffer.AddLine(":" + sNickMask + " NOTICE ", " :" + sMessage);
}
return false;
}
bool CIRCSock::OnPrivMsg(const string& sNickMask, string& sMessage) {
#ifdef _MODULES
if (m_pUser->GetModules().OnPrivMsg(sNickMask, sMessage)) {
return true;
}
#endif
if (!m_pUserSock) {
// If the user is detached, add to the buffer
m_QueryBuffer.AddLine(":" + sNickMask + " PRIVMSG ", " :" + sMessage);
}
return false;
}
bool CIRCSock::OnChanCTCP(const string& sNickMask, const string& sChan, string& sMessage) {
CChan* pChan = m_pUser->FindChan(sChan);
if (pChan) {
#ifdef _MODULES
if (m_pUser->GetModules().OnChanCTCP(sNickMask, *pChan, sMessage)) {
return true;
}
#endif
}
return false;
}
bool CIRCSock::OnChanNotice(const string& sNickMask, const string& sChan, string& sMessage) {
CChan* pChan = m_pUser->FindChan(sChan);
if (pChan) {
#ifdef _MODULES
if (m_pUser->GetModules().OnChanNotice(sNickMask, *pChan, sMessage)) {
return true;
}
#endif
if ((pChan->KeepBuffer()) || (!m_pUserSock)) {
pChan->AddBuffer(":" + sNickMask + " NOTICE " + sChan + " :" + sMessage);
}
}
return false;
}
bool CIRCSock::OnChanMsg(const string& sNickMask, const string& sChan, string& sMessage) {
CChan* pChan = m_pUser->FindChan(sChan);
if (pChan) {
#ifdef _MODULES
if (m_pUser->GetModules().OnChanMsg(sNickMask, *pChan, sMessage)) {
return true;
}
#endif
if ((pChan->KeepBuffer()) || (!m_pUserSock)) {
pChan->AddBuffer(":" + sNickMask + " PRIVMSG " + sChan + " :" + sMessage);
}
}
return false;
}
void CIRCSock::UserConnected(CUserSock* pUserSock) {
if (m_pUserSock) {
m_pUserSock->BouncedOff();
}
m_pUserSock = pUserSock;
if (m_RawBuffer.IsEmpty()) {
PutUser(":irc.znc.com 001 " + m_pUserSock->GetNick() + " :- Welcome to ZNC -");
} else {
unsigned int uIdx = 0;
string sLine;
while (m_RawBuffer.GetLine(GetNick(), sLine, uIdx++)) {
PutUser(sLine);
}
}
PutServ("MOTD");
const vector<CChan*>& vChans = m_pUser->GetChans();
for (unsigned int a = 0; a < vChans.size(); a++) {
if (vChans[a]->IsOn()) {
PutUser(":" + m_Nick.GetNickMask() + " JOIN :" + vChans[a]->GetName());
PutServ("NAMES " + vChans[a]->GetName());
}
}
//PutUser("");
string sBufLine;
while (m_QueryBuffer.GetNextLine(GetNick(), sBufLine)) {
PutUser(sBufLine);
}
}
void CIRCSock::UserDisconnected() {
m_pUserSock = NULL;
}
void CIRCSock::PutServ(const string& sLine) {
DEBUG_ONLY(cout << GetSockName() << " -> [" << sLine << "]" << endl);
Write(sLine + "\r\n");
}
void CIRCSock::PutUser(const string& sLine) {
if (m_pUserSock) {
m_pUserSock->PutServ(sLine);
}
}
void CIRCSock::PutStatus(const string& sLine) {
if (m_pUserSock) {
m_pUserSock->PutStatus(sLine);
}
}
void CIRCSock::SetNick(const string& sNick) {
m_Nick.SetNick(sNick);
if (m_pUserSock) {
m_pUserSock->SetNick(sNick);
}
}
void CIRCSock::Connected() {
DEBUG_ONLY(cout << GetSockName() << " == Connected()" << endl);
CUserSock* pUserSock = (CUserSock*) m_pZNC->FindSockByName("USR::" + m_pUser->GetUserName());
if (pUserSock) {
m_pUserSock = pUserSock;
pUserSock->IRCConnected(this);
}
if (!m_sPass.empty()) {
PutServ("PASS " + m_sPass);
}
PutServ("NICK " + m_pUser->GetNick());
PutServ("USER " + m_pUser->GetIdent() + " \"" + m_pUser->GetIdent() + "\" \"" + m_pUser->GetIdent() + "\" :" + m_pUser->GetRealName());
}
void CIRCSock::Disconnected() {
DEBUG_ONLY(cout << GetSockName() << " == Disconnected()" << endl);
m_pUser->PutStatus("Disconnected from IRC. Reconnecting...");
#ifdef _MODULES
m_pUser->GetModules().OnIRCDisconnected();
#endif
const vector<CChan*>& vChans = m_pUser->GetChans();
for (unsigned int a = 0; a < vChans.size(); a++) {
vChans[a]->SetIsOn(false);
}
if (m_pUserSock) {
m_pUserSock->IRCDisconnected();
m_pUserSock = NULL;
}
}
void CIRCSock::SockError(int iErrno) {
DEBUG_ONLY(cout << GetSockName() << " == SockError(" << iErrno << ")" << endl);
m_pUser->PutStatus("Disconnected from IRC. Reconnecting...");
}
void CIRCSock::Timeout() {
DEBUG_ONLY(cout << GetSockName() << " == Timeout()" << endl);
m_pUser->PutStatus("IRC connection timed out. Reconnecting...");
}
void CIRCSock::ConnectionRefused() {
DEBUG_ONLY(cout << GetSockName() << " == ConnectionRefused()" << endl);
m_pUser->PutStatus("Connection Refused. Reconnecting...");
}
+72
View File
@@ -0,0 +1,72 @@
#ifndef _IRCSOCK_H
#define _IRCSOCK_H
#include "main.h"
#include "User.h"
#include "Chan.h"
#include "Buffer.h"
// Forward Declarations
class CZNC;
class CUserSock;
// !Forward Declarations
class CIRCSock : public Csock {
public:
CIRCSock(CZNC* pZNC, CUser* pUser);
virtual ~CIRCSock();
// Message Handlers
bool OnCTCPReply(const string& sNickMask, string& sMessage);
bool OnPrivCTCP(const string& sNickMask, string& sMessage);
bool OnChanCTCP(const string& sNickMask, const string& sChan, string& sMessage);
bool OnPrivMsg(const string& sNickMask, string& sMessage);
bool OnChanMsg(const string& sNickMask, const string& sChan, string& sMessage);
bool OnPrivNotice(const string& sNickMask, string& sMessage);
bool OnChanNotice(const string& sNickMask, const string& sChan, string& sMessage);
// !Message Handlers
virtual void ReadLine(const string& sData);
virtual void Connected();
virtual void Disconnected();
virtual void ConnectionRefused();
virtual void SockError(int iErrno);
virtual void Timeout();
void KeepNick();
bool IsUserAttached() { return (m_pUserSock != NULL); }
void UserConnected(CUserSock* pUserSock);
void UserDisconnected();
void PutServ(const string& sLine);
void PutUser(const string& sLine);
void PutStatus(const string& sLine);
// Setters
void SetPass(const string& s) { m_sPass = s; }
// !Setters
// Getters
string GetNickMask() const {
return m_Nick.GetNickMask();
}
const string& GetNick() const { return m_Nick.GetNick(); }
const string& GetPass() const { return m_sPass; }
// !Getters
private:
void SetNick(const string& sNick);
protected:
bool m_bISpoofReleased;
bool m_bAuthed;
bool m_bKeepNick;
CZNC* m_pZNC;
CUser* m_pUser;
CNick m_Nick;
string m_sPass;
CBuffer m_RawBuffer;
CUserSock* m_pUserSock;
map<string, CChan*> m_msChans;
unsigned int m_uQueryBufferCount;
CBuffer m_QueryBuffer;
};
#endif // !_IRCSOCK_H
+31
View File
@@ -0,0 +1,31 @@
CXX=g++
TARGET=linux-gnu
MACHINE=i686
CXXFLAGS=-s -O2 -fomit-frame-pointer -D_MODULES -Wall -D_GNU_SOURCE -DHAVE_LIBSSL
#CXXFLAGS=-Wall -ggdb -D_DEBUG -D_MODULES -D_GNU_SOURCE -DHAVE_LIBSSL
INCLUDES=
LIBS=-ldl -lssl -rdynamic
OBJS=main.o znc.o User.o IRCSock.o UserSock.o DCCBounce.o DCCSock.o Chan.o Nick.o Server.o Modules.o md5.o Buffer.o Utils.o
SRCS=main.cpp znc.cpp User.cpp IRCSock.cpp UserSock.cpp DCCBounce.cpp DCCSock.cpp Chan.cpp Nick.cpp Server.cpp Modules.cpp md5.cpp Buffer.cpp Utils.cpp
all: znc
depend::
cat /dev/null >.depend
g++ -M $(CXXFLAGS) $(SRCS) $(INCLUDES) >.depend
znc: $(OBJS)
$(CXX) $(CXXFLAGS) $(INCLUDES) -o $@ $(LIBS) $(OBJS)
znc-static: $(OBJS)
$(CXX) $(CXXFLAGS) -static -o $@ $(INCLUDES) $(OBJS) $(LIBS)
strip $@
clean:
rm -rf znc znc-static *.o core core.*
include .depend
.cpp.o:
$(CXX) $(CXXFLAGS) $(INCLUDES) -c -o $*.o $*.cpp
+594
View File
@@ -0,0 +1,594 @@
#include "main.h"
#include "Modules.h"
#include "Utils.h"
#include "User.h"
#include "Nick.h"
#include "Chan.h"
/////////////////// Timer ///////////////////
CTimer::CTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const string& sLabel, const string& sDescription) : CCron() {
SetName(sLabel);
m_sDescription = sDescription;
m_pModule = pModule;
if (uCycles) {
StartMaxCycles(uInterval, uCycles);
} else {
Start(uInterval);
}
}
CTimer::~CTimer() {
m_pModule->UnlinkTimer(this);
}
void CTimer::SetModule(CModule* p) { m_pModule = p; }
void CTimer::SetDescription(const string& s) { m_sDescription = s; }
CModule* CTimer::GetModule() const { return m_pModule; }
const string& CTimer::GetDescription() const { return m_sDescription; }
/////////////////// !Timer ///////////////////
CModule::CModule(void* pDLL, CUser* pUser, const string& sModName) {
m_pDLL = pDLL;
m_pManager = pUser->GetManager();
m_pUser = pUser;
m_sModName = sModName;
}
CModule::~CModule() {
while (m_vTimers.size()) {
RemTimer(m_vTimers[0]->GetName());
}
}
bool CModule::AddTimer(CTimer* pTimer) {
if ((!pTimer) || (FindTimer(pTimer->GetName()))) {
delete pTimer;
return false;
}
m_pManager->AddCron(pTimer);
m_vTimers.push_back(pTimer);
return true;
}
bool CModule::RemTimer(const string& sLabel) {
for (unsigned int a = 0; a < m_vTimers.size(); a++) {
CTimer* pTimer = m_vTimers[a];
if (strcasecmp(pTimer->GetName().c_str(), sLabel.c_str()) == 0) {
m_vTimers.erase(m_vTimers.begin() +a);
m_pManager->DelCronByAddr(pTimer);
return true;
}
}
return false;
}
bool CModule::UnlinkTimer(CTimer* pTimer) {
for (unsigned int a = 0; a < m_vTimers.size(); a++) {
if (pTimer == m_vTimers[a]) {
m_vTimers.erase(m_vTimers.begin() +a);
return true;
}
}
return false;
}
CTimer* CModule::FindTimer(const string& sLabel) {
for (unsigned int a = 0; a < m_vTimers.size(); a++) {
CTimer* pTimer = m_vTimers[a];
if (strcasecmp(pTimer->GetName().c_str(), sLabel.c_str()) == 0) {
return pTimer;
}
}
return NULL;
}
void CModule::ListTimers() {
if (!m_vTimers.size()) {
PutModule("You have no timers running.");
return;
}
CTable Table;
Table.AddColumn("Name");
Table.AddColumn("Secs");
Table.AddColumn("Cycles");
Table.AddColumn("Description");
for (unsigned int a = 0; a < m_vTimers.size(); a++) {
CTimer* pTimer = (CTimer*) m_vTimers[a];
unsigned int uCycles = pTimer->GetCyclesLeft();
Table.AddRow();
Table.SetCell("Name", pTimer->GetName());
Table.SetCell("Secs", CUtils::ToString(pTimer->GetInterval()));
Table.SetCell("Cycles", ((uCycles) ? CUtils::ToString(uCycles) : "INF"));
Table.SetCell("Description", pTimer->GetDescription());
}
if (Table.size()) {
unsigned int uTableIdx = 0;
string sLine;
while (Table.GetLine(uTableIdx++, sLine)) {
PutModule(sLine);
}
}
}
const string& CModule::GetModName() { return m_sModName; }
string CModule::GetModNick() { return ((m_pUser) ? m_pUser->GetStatusPrefix() : "*") + m_sModName; }
string CModule::GetDescription() { return "Unknown"; }
bool CModule::OnLoad(const string& sArgs) { return true; }
bool CModule::OnBoot() { return true; }
void CModule::OnUserAttached() {}
void CModule::OnUserDetached() {}
void CModule::OnIRCDisconnected() {}
void CModule::OnIRCConnected() {}
bool CModule::OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, const string& sFile, unsigned long uFileSize) { return false; }
void CModule::OnOp(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {}
void CModule::OnDeop(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {}
void CModule::OnVoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {}
void CModule::OnDevoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {}
void CModule::OnRawMode(const CNick& OpNick, const CChan& Channel, const string& sModes, const string& sArgs) {}
bool CModule::OnUserRaw(string& sLine) { return false; }
bool CModule::OnRaw(string& sLine) { return false; }
bool CModule::OnStatusCommand(const string& sCommand) { return false; }
void CModule::OnModCommand(const string& sCommand) {}
void CModule::OnModNotice(const string& sMessage) {}
void CModule::OnModCTCP(const string& sMessage) {}
void CModule::OnQuit(const CNick& Nick, const string& sMessage) {}
void CModule::OnNick(const CNick& Nick, const string& sNewNick) {}
void CModule::OnKick(const CNick& Nick, const string& sKickedNick, const CChan& Channel, const string& sMessage) {}
void CModule::OnJoin(const CNick& Nick, const CChan& Channel) {}
void CModule::OnPart(const CNick& Nick, const CChan& Channel) {}
bool CModule::OnUserCTCPReply(const CNick& Nick, string& sMessage) { return false; }
bool CModule::OnCTCPReply(const CNick& Nick, string& sMessage) { return false; }
bool CModule::OnUserCTCP(const string& sTarget, string& sMessage) { return false; }
bool CModule::OnPrivCTCP(const CNick& Nick, string& sMessage) { return false; }
bool CModule::OnChanCTCP(const CNick& Nick, const CChan& Channel, string& sMessage) { return false; }
bool CModule::OnUserMsg(const string& sTarget, string& sMessage) { return false; }
bool CModule::OnPrivMsg(const CNick& Nick, string& sMessage) { return false; }
bool CModule::OnChanMsg(const CNick& Nick, const CChan& Channel, string& sMessage) { return false; }
bool CModule::OnUserNotice(const string& sTarget, string& sMessage) { return false; }
bool CModule::OnPrivNotice(const CNick& Nick, string& sMessage) { return false; }
bool CModule::OnChanNotice(const CNick& Nick, const CChan& Channel, string& sMessage) { return false; }
void* CModule::GetDLL() { return m_pDLL; }
bool CModule::PutIRC(const string& sLine) {
return (m_pUser) ? m_pUser->PutIRC(sLine) : false;
}
bool CModule::PutUser(const string& sLine) {
return (m_pUser) ? m_pUser->PutUser(sLine) : false;
}
bool CModule::PutStatus(const string& sLine) {
return (m_pUser) ? m_pUser->PutStatus(sLine) : false;
}
bool CModule::PutModule(const string& sLine, const string& sIdent, const string& sHost) {
return (m_pUser) ? m_pUser->PutUser(":" + GetModNick() + "!" + sIdent + "@" + sHost + " PRIVMSG " + m_pUser->GetCurNick() + " :" + sLine) : false;
}
bool CModule::PutModNotice(const string& sLine, const string& sIdent, const string& sHost) {
return (m_pUser) ? m_pUser->PutUser(":" + GetModNick() + "!" + sIdent + "@" + sHost + " NOTICE " + m_pUser->GetCurNick() + " :" + sLine) : false;
}
CModules::CModules() {}
CModules::~CModules() {}
void CModules::UnloadAll() {
while (size()) {
string sRetMsg;
string sModName = (*this)[0]->GetModName();
UnloadModule(sModName, sRetMsg);
}
}
void CModules::OnIRCConnected() {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnIRCConnected();
}
}
bool CModules::OnLoad(const string& sArgs) {
for (unsigned int a = 0; a < size(); a++) {
if (!(*this)[a]->OnLoad(sArgs)) {
return false;
}
}
return true;
}
bool CModules::OnBoot() {
for (unsigned int a = 0; a < size(); a++) {
if (!(*this)[a]->OnBoot()) {
return false;
}
}
return true;
}
void CModules::OnUserAttached() {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnUserAttached();
}
}
void CModules::OnUserDetached() {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnUserDetached();
}
}
void CModules::OnIRCDisconnected() {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnIRCDisconnected();
}
}
bool CModules::OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, const string& sFile, unsigned long uFileSize) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnDCCUserSend(RemoteNick, uLongIP, uPort, sFile, uFileSize)) {
return true;
}
}
return false;
}
void CModules::OnOp(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnOp(OpNick, Nick, Channel, bNoChange);
}
}
void CModules::OnDeop(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnDeop(OpNick, Nick, Channel, bNoChange);
}
}
void CModules::OnVoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnVoice(OpNick, Nick, Channel, bNoChange);
}
}
void CModules::OnDevoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnDevoice(OpNick, Nick, Channel, bNoChange);
}
}
void CModules::OnRawMode(const CNick& OpNick, const CChan& Channel, const string& sModes, const string& sArgs) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnRawMode(OpNick, Channel, sModes, sArgs);
}
}
bool CModules::OnRaw(string& sLine) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnRaw(sLine)) {
return true;
}
}
return false;
}
bool CModules::OnUserRaw(string& sLine) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnUserRaw(sLine)) {
return true;
}
}
return false;
}
void CModules::OnQuit(const CNick& Nick, const string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnQuit(Nick, sMessage);
}
}
void CModules::OnNick(const CNick& Nick, const string& sNewNick) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnNick(Nick, sNewNick);
}
}
void CModules::OnKick(const CNick& Nick, const string& sKickedNick, const CChan& Channel, const string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnKick(Nick, sKickedNick, Channel, sMessage);
}
}
void CModules::OnJoin(const CNick& Nick, const CChan& Channel) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnJoin(Nick, Channel);
}
}
void CModules::OnPart(const CNick& Nick, const CChan& Channel) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnPart(Nick, Channel);
}
}
bool CModules::OnUserCTCP(const string& sTarget, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnUserCTCP(sTarget, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnUserCTCPReply(const CNick& Nick, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnUserCTCPReply(Nick, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnCTCPReply(const CNick& Nick, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnCTCPReply(Nick, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnPrivCTCP(const CNick& Nick, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnPrivCTCP(Nick, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnChanCTCP(const CNick& Nick, const CChan& Channel, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnChanCTCP(Nick, Channel, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnUserMsg(const string& sTarget, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnUserMsg(sTarget, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnPrivMsg(const CNick& Nick, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnPrivMsg(Nick, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnChanMsg(const CNick& Nick, const CChan& Channel, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnChanMsg(Nick, Channel, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnUserNotice(const string& sTarget, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnUserNotice(sTarget, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnPrivNotice(const CNick& Nick, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnPrivNotice(Nick, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnChanNotice(const CNick& Nick, const CChan& Channel, string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnChanNotice(Nick, Channel, sMessage)) {
return true;
}
}
return false;
}
bool CModules::OnStatusCommand(const string& sCommand) {
for (unsigned int a = 0; a < size(); a++) {
if ((*this)[a]->OnStatusCommand(sCommand)) {
return true;
}
}
return false;
}
void CModules::OnModCommand(const string& sCommand) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnModCommand(sCommand);
}
}
void CModules::OnModNotice(const string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnModNotice(sMessage);
}
}
void CModules::OnModCTCP(const string& sMessage) {
for (unsigned int a = 0; a < size(); a++) {
(*this)[a]->OnModCTCP(sMessage);
}
}
CModule* CModules::FindModule(const string& sModule) {
for (unsigned int a = 0; a < size(); a++) {
if (strcasecmp(sModule.c_str(), (*this)[a]->GetModName().c_str()) == 0) {
return (*this)[a];
}
}
return NULL;
}
bool CModules::LoadModule(const string& sModule, const string& sArgs, CUser* pUser, const string& sPath, string& sRetMsg) {
sRetMsg = "";
if (!pUser) {
sRetMsg = "Unable to load module [" + sModule + "] Internal Error 1.";
return false;
}
for (unsigned int a = 0; a < sModule.length(); a++) {
if (((sModule[a] < '0') || (sModule[a] > '9')) && ((sModule[a] < 'a') || (sModule[a] > 'z')) && ((sModule[a] < 'A') || (sModule[a] > 'Z')) && (sModule[a] != '_')) {
sRetMsg = "Unable to load module [" + sModule + "] module names can only be letters, numbers, or underscores.";
return false;
}
}
if (FindModule(sModule) != NULL) {
sRetMsg = "Module [" + sModule + "] already loaded.";
return false;
}
void* p = dlopen((pUser->GetModPath() + "/" + sModule + ".so").c_str(), RTLD_LAZY);
if (!p) {
sRetMsg = "Unable to load module [" + sModule + "] [" + dlerror() + "]";
return false;
}
typedef double (*fpp)();
fpp Version = (fpp) dlsym(p, "GetVersion");
if (!Version) {
dlclose(p);
sRetMsg = "Could not find Version() in module [" + sModule + "]";
return false;
}
if (CModule::GetVersion() != Version()) {
dlclose(p);
sRetMsg = "Version mismatch in module [" + sModule + "] - You need to recompile your modules using this version of znc.";
return false;
}
typedef CModule* (*fp)(void*, CUser* pUser, const string& sModName);
fp Load = (fp) dlsym(p, "Load");
if (!Load) {
dlclose(p);
sRetMsg = "Could not find Load() in module [" + sModule + "]";
return false;
}
CModule* pModule = Load(p, pUser, sModule);
push_back(pModule);
if (!pModule->OnLoad(sArgs)) {
UnloadModule(sModule, sRetMsg);
sRetMsg = "Module [" + sModule + "] aborted.";
return false;
}
sRetMsg = "Loaded module [" + sModule + "]";
return true;
}
bool CModules::UnloadModule(const string& sModule, string& sRetMsg) {
CModule* pModule = FindModule(sModule);
sRetMsg = "";
if (!pModule) {
sRetMsg = "Module [" + sModule + "] not loaded.";
return false;
}
void* p = pModule->GetDLL();
if (p) {
typedef void (*fp)(CModule*);
fp Unload = (fp)dlsym(p, "Unload");
if (Unload) {
Unload(pModule);
for (iterator it = begin(); it != end(); it++) {
if (*it == pModule) {
erase(it);
break;
}
}
dlclose(p);
sRetMsg = "Module [" + sModule + "] unloaded";
return true;
} else {
sRetMsg = "Unable to unload module [" + sModule + "] could not find Unload()";
return false;
}
}
sRetMsg = "Unable to unload module [" + sModule + "]";
return false;
}
bool CModules::ReloadModule(const string& sModule, const string& sArgs, CUser* pUser, const string& sPath, string& sRetMsg) {
sRetMsg = "";
if (!UnloadModule(sModule, sRetMsg)) {
return false;
}
if (!LoadModule(sModule, sArgs, pUser, sPath, sRetMsg)) {
return false;
}
sRetMsg = "Reloaded module [" + sModule + "]";
return true;
}
+174
View File
@@ -0,0 +1,174 @@
#ifndef _MODULES_H
#define _MODULES_H
#include <dlfcn.h>
#include <string.h>
#include <vector>
using std::vector;
using std::string;
#define VERSION 0.022
#define MODULEDEFS(CLASS) extern "C" { CModule* Load(void* p, CUser* pUser, const string& sModName); void Unload(CModule* pMod); double GetVersion(); } double GetVersion() { return VERSION; } CModule* Load(void* p, CUser* pUser, const string& sModName) { return new CLASS(p, pUser, sModName); } void Unload(CModule* pMod) { if (pMod) { delete pMod; } }
#define MODCONSTRUCTOR(CLASS) CLASS(void *pDLL, CUser* pUser, const string& sModName) : CModule(pDLL, pUser, sModName)
// Forward Declarations
class CUser;
class CNick;
class CChan;
class Csock;
class CModule;
template<class T> class TSocketManager;
// !Forward Declarations
class CTimer : public CCron {
public:
CTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const string& sLabel, const string& sDescription);
virtual ~CTimer();
// Setters
void SetModule(CModule* p);
void SetDescription(const string& s);
// !Setters
// Getters
CModule* GetModule() const;
const string& GetDescription() const;
// !Getters
private:
protected:
CModule* m_pModule;
string m_sDescription;
};
class CModule {
public:
CModule(void* pDLL, CUser* pUser, const string& sModName);
virtual ~CModule();
virtual string GetDescription();
virtual bool OnLoad(const string& sArgs);
virtual bool OnBoot();
virtual void OnUserAttached();
virtual void OnUserDetached();
virtual void OnIRCDisconnected();
virtual void OnIRCConnected();
virtual bool OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, const string& sFile, unsigned long uFileSize);
virtual void OnOp(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange);
virtual void OnDeop(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange);
virtual void OnVoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange);
virtual void OnDevoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange);
virtual void OnRawMode(const CNick& OpNick, const CChan& Channel, const string& sModes, const string& sArgs);
virtual bool OnUserRaw(string& sLine);
virtual bool OnRaw(string& sLine);
virtual bool OnStatusCommand(const string& sCommand);
virtual void OnModCommand(const string& sCommand);
virtual void OnModNotice(const string& sMessage);
virtual void OnModCTCP(const string& sMessage);
virtual void OnQuit(const CNick& Nick, const string& sMessage);
virtual void OnNick(const CNick& Nick, const string& sNewNick);
virtual void OnKick(const CNick& Nick, const string& sOpNick, const CChan& Channel, const string& sMessage);
virtual void OnJoin(const CNick& Nick, const CChan& Channel);
virtual void OnPart(const CNick& Nick, const CChan& Channel);
virtual bool OnUserCTCPReply(const CNick& Nick, string& sMessage);
virtual bool OnCTCPReply(const CNick& Nick, string& sMessage);
virtual bool OnUserCTCP(const string& sTarget, string& sMessage);
virtual bool OnPrivCTCP(const CNick& Nick, string& sMessage);
virtual bool OnChanCTCP(const CNick& Nick, const CChan& Channel, string& sMessage);
virtual bool OnUserMsg(const string& sTarget, string& sMessage);
virtual bool OnPrivMsg(const CNick& Nick, string& sMessage);
virtual bool OnChanMsg(const CNick& Nick, const CChan& Channel, string& sMessage);
virtual bool OnUserNotice(const string& sTarget, string& sMessage);
virtual bool OnPrivNotice(const CNick& Nick, string& sMessage);
virtual bool OnChanNotice(const CNick& Nick, const CChan& Channel, string& sMessage);
void * GetDLL();
static double GetVersion() { return VERSION; }
virtual bool PutIRC(const string& sLine);
virtual bool PutUser(const string& sLine);
virtual bool PutStatus(const string& sLine);
virtual bool PutModule(const string& sLine, const string& sIdent = "znc", const string& sHost = "znc.com");
virtual bool PutModNotice(const string& sLine, const string& sIdent = "znc", const string& sHost = "znc.com");
const string& GetModName();
string GetModNick();
// Timer stuff
bool AddTimer(CTimer* pTimer);
bool RemTimer(const string& sLabel);
bool UnlinkTimer(CTimer* pTimer);
CTimer* FindTimer(const string& sLabel);
virtual void ListTimers();
// !Timer stuff
protected:
vector<CTimer*> m_vTimers;
void* m_pDLL;
TSocketManager<Csock>* m_pManager;
CUser* m_pUser;
string m_sModName;
};
class CModules : public vector<CModule*> {
public:
CModules();
virtual ~CModules();
void UnloadAll();
virtual bool OnLoad(const string& sArgs);
virtual bool OnBoot();
virtual void OnUserAttached();
virtual void OnUserDetached();
virtual void OnIRCDisconnected();
virtual void OnIRCConnected();
virtual bool OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, const string& sFile, unsigned long uFileSize);
virtual void OnOp(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange);
virtual void OnDeop(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange);
virtual void OnVoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange);
virtual void OnDevoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange);
virtual void OnRawMode(const CNick& OpNick, const CChan& Channel, const string& sModes, const string& sArgs);
virtual bool OnUserRaw(string& sLine);
virtual bool OnRaw(string& sLine);
virtual bool OnStatusCommand(const string& sCommand);
virtual void OnModCommand(const string& sCommand);
virtual void OnModNotice(const string& sMessage);
virtual void OnModCTCP(const string& sMessage);
virtual void OnQuit(const CNick& Nick, const string& sMessage);
virtual void OnNick(const CNick& Nick, const string& sNewNick);
virtual void OnKick(const CNick& Nick, const string& sOpNick, const CChan& Channel, const string& sMessage);
virtual void OnJoin(const CNick& Nick, const CChan& Channel);
virtual void OnPart(const CNick& Nick, const CChan& Channel);
virtual bool OnUserCTCPReply(const CNick& Nick, string& sMessage);
virtual bool OnCTCPReply(const CNick& Nick, string& sMessage);
virtual bool OnUserCTCP(const string& sTarget, string& sMessage);
virtual bool OnPrivCTCP(const CNick& Nick, string& sMessage);
virtual bool OnChanCTCP(const CNick& Nick, const CChan& Channel, string& sMessage);
virtual bool OnUserMsg(const string& sTarget, string& sMessage);
virtual bool OnPrivMsg(const CNick& Nick, string& sMessage);
virtual bool OnChanMsg(const CNick& Nick, const CChan& Channel, string& sMessage);
virtual bool OnUserNotice(const string& sTarget, string& sMessage);
virtual bool OnPrivNotice(const CNick& Nick, string& sMessage);
virtual bool OnChanNotice(const CNick& Nick, const CChan& Channel, string& sMessage);
CModule* FindModule(const string& sModule);
bool LoadModule(const string& sModule, const string& sArgs, CUser* pUser, const string& sPath, string& sRetMsg);
bool UnloadModule(const string& sModule, string& sRetMsg);
bool ReloadModule(const string& sModule, const string& sArgs, CUser* pUser, const string& sPath, string& sRetMsg);
};
#endif // !_MODULES_H
+62
View File
@@ -0,0 +1,62 @@
#include "Nick.h"
CNick::CNick() {
m_bIsOp = false;
m_bIsVoice = false;
}
CNick::CNick(const string& sNick) {
Parse(sNick);
m_bIsOp = false;
m_bIsVoice = false;
}
CNick::~CNick() {}
void CNick::Parse(const string& sNickMask) {
if (sNickMask.empty()) {
return;
}
unsigned int uPos = sNickMask.find('!');
if (uPos == string::npos) {
m_sNick = sNickMask.substr((sNickMask[0] == ':'));
return;
}
m_sNick = sNickMask.substr((sNickMask[0] == ':'), uPos);
m_sHost = sNickMask.substr(uPos +1);
if ((uPos = m_sHost.find('@')) != string::npos) {
m_sIdent = m_sHost.substr(0, uPos);
m_sHost = m_sHost.substr(uPos +1);
}
}
void CNick::SetNick(const string& s) { m_sNick = s; }
void CNick::SetIdent(const string& s) { m_sIdent = s; }
void CNick::SetHost(const string& s) { m_sHost = s; }
void CNick::SetOp(bool b) { m_bIsOp = b; }
void CNick::SetVoice(bool b) { m_bIsVoice = b; }
bool CNick::IsOp() const { return m_bIsOp; }
bool CNick::IsVoice() const { return m_bIsVoice; }
const string& CNick::GetNick() const { return m_sNick; }
const string& CNick::GetIdent() const { return m_sIdent; }
const string& CNick::GetHost() const { return m_sHost; }
string CNick::GetNickMask() const { return m_sNick + "!" + m_sIdent + "@" + m_sHost; }
string CNick::GetHostMask() const {
string sRet = m_sNick;
if (!m_sIdent.empty()) {
sRet += "!" + m_sIdent;
}
if (!m_sHost.empty()) {
sRet += "@" + m_sHost;
}
return (sRet);
}
+44
View File
@@ -0,0 +1,44 @@
#ifndef _NICK_H
#define _NICK_H
#include <string>
using std::string;
class CNick
{
public:
CNick();
CNick(const string& sNick);
virtual ~CNick();
void Parse(const string& sNickMask);
string GetHostMask() const;
// Setters
void SetNick(const string& s);
void SetIdent(const string& s);
void SetHost(const string& s);
void SetOp(bool b);
void SetVoice(bool b);
// !Setters
// Getters
bool IsOp() const;
bool IsVoice() const;
const string& GetNick() const;
const string& GetIdent() const;
const string& GetHost() const;
string GetNickMask() const;
// !Getters
private:
protected:
string m_sNick;
string m_sIdent;
string m_sHost;
bool m_bIsOp;
bool m_bIsVoice;
};
#endif // !_NICK_H
+17
View File
@@ -0,0 +1,17 @@
#include "main.h"
#include "Server.h"
CServer::CServer(const string& sName, unsigned short uPort, const string& sPass, bool bSSL) {
m_sName = sName;
m_uPort = (uPort) ? uPort : 6667;
m_sPass = sPass;
m_bSSL = bSSL;
}
CServer::~CServer() {}
const string& CServer::GetName() const { return m_sName; }
unsigned short CServer::GetPort() const { return m_uPort; }
const string& CServer::GetPass() const { return m_sPass; }
bool CServer::IsSSL() const { return m_bSSL; }
+23
View File
@@ -0,0 +1,23 @@
#ifndef _SERVER_H
#define _SERVER_H
#include <string.h>
class CServer {
public:
CServer(const string& sName, unsigned short uPort = 6667, const string& sPass = "", bool bSSL = false);
virtual ~CServer();
const string& GetName() const;
unsigned short GetPort() const;
const string& GetPass() const;
bool IsSSL() const;
private:
protected:
string m_sName;
unsigned short m_uPort;
string m_sPass;
bool m_bSSL;
};
#endif // !_SERVER_H
+49
View File
@@ -0,0 +1,49 @@
#include "main.h"
class CKeepNickTimer : public CCron {
public:
CKeepNickTimer(CUser* pUser) : CCron() {
m_pUser = pUser;
Start(5);
}
virtual ~CKeepNickTimer() {}
private:
protected:
virtual void RunJob() {
CIRCSock* pSock = m_pUser->GetIRCSock();
if (pSock) {
pSock->KeepNick();
}
}
CUser* m_pUser;
};
class CJoinTimer : public CCron {
public:
CJoinTimer(CUser* pUser) : CCron() {
m_pUser = pUser;
Start(20);
}
virtual ~CJoinTimer() {}
private:
protected:
virtual void RunJob() {
CIRCSock* pSock = m_pUser->GetIRCSock();
if (pSock) {
const vector<CChan*>& vChans = m_pUser->GetChans();
for (unsigned int a = 0; a < vChans.size(); a++) {
if (!vChans[a]->IsOn()) {
pSock->PutServ("JOIN " + vChans[a]->GetName() + " " + vChans[a]->GetKey());
}
}
}
}
CUser* m_pUser;
};
+397
View File
@@ -0,0 +1,397 @@
#include "main.h"
#include "znc.h"
#include "User.h"
#include "Server.h"
#include "IRCSock.h"
#include "UserSock.h"
#include "DCCBounce.h"
#include "DCCSock.h"
#include "md5.h"
#include "Timers.h"
CUser::CUser(const string& sUserName, CZNC* pZNC) {
m_sUserName = sUserName;
m_sNick = sUserName;
m_sIdent = sUserName;
m_sRealName = sUserName;
m_uServerIdx = 0;
m_pZNC = pZNC;
m_bPassHashed = false;
m_bUseClientIP = false;
m_bKeepNick = false;
m_bDenyLoadMod = false;
m_sStatusPrefix = "*";
m_pZNC->GetManager().AddCron(new CKeepNickTimer(this));
m_pZNC->GetManager().AddCron(new CJoinTimer(this));
}
CUser::~CUser() {
#ifdef _MODULES
m_Modules.UnloadAll();
#endif
for (unsigned int a = 0; a < m_vServers.size(); a++) {
delete m_vServers[a];
}
for (unsigned int b = 0; b < m_vChans.size(); b++) {
delete m_vChans[b];
}
}
bool CUser::OnBoot() {
#ifdef _MODULES
return m_Modules.OnBoot();
#endif
return true;
}
bool CUser::AddAllowedHost(const string& sHostMask) {
if (m_ssAllowedHosts.find(sHostMask) != m_ssAllowedHosts.end()) {
return false;
}
m_ssAllowedHosts.insert(sHostMask);
return true;
}
bool CUser::IsHostAllowed(const string& sHostMask) {
for (set<string>::iterator a = m_ssAllowedHosts.begin(); a != m_ssAllowedHosts.end(); a++) {
if (CUtils::WildCmp(*a, sHostMask)) {
return true;
}
}
return false;
}
bool CUser::AddChan(CChan* pChan) {
if (!pChan) {
return false;
}
for (unsigned int a = 0; a < m_vChans.size(); a++) {
if (strcasecmp(m_vChans[a]->GetName().c_str(), pChan->GetName().c_str()) == 0) {
delete pChan;
return false;
}
}
m_vChans.push_back(pChan);
return true;
}
bool CUser::AddChan(const string& sName, unsigned int uBufferCount) {
if (sName.empty()) {
return false;
}
for (unsigned int a = 0; a < m_vChans.size(); a++) {
if (strcasecmp(sName.c_str(), m_vChans[a]->GetName().c_str()) == 0) {
return false;
}
}
CChan* pChan = new CChan(sName, this, uBufferCount);
m_vChans.push_back(pChan);
return true;
}
bool CUser::DelChan(const string& sName) {
for (vector<CChan*>::iterator a = m_vChans.begin(); a != m_vChans.end(); a++) {
if (strcasecmp(sName.c_str(), (*a)->GetName().c_str()) == 0) {
m_vChans.erase(a);
return true;
}
}
return false;
}
CChan* CUser::FindChan(const string& sName) {
for (unsigned int a = 0; a < m_vChans.size(); a++) {
if (strcasecmp(sName.c_str(), m_vChans[a]->GetName().c_str()) == 0) {
return m_vChans[a];
}
}
return NULL;
}
bool CUser::AddServer(const string& sName) {
if (sName.empty()) {
return false;
}
bool bSSL = false;
string sLine = sName;
CUtils::Trim(sLine);
string sHost = CUtils::Token(sLine, 0);
string sPort = CUtils::Token(sLine, 1);
if (CUtils::Left(sPort, 1) == "+") {
bSSL = true;
CUtils::LeftChomp(sPort);
}
unsigned short uPort = strtoul(sPort.c_str(), NULL, 10);
string sPass = CUtils::Token(sLine, 2, true);
return AddServer(sHost, uPort, sPass, bSSL);
}
bool CUser::AddServer(const string& sName, unsigned short uPort, const string& sPass, bool bSSL) {
#ifndef HAVE_LIBSSL
if (bSSL) {
return false;
}
#endif
if (sName.empty()) {
return false;
}
if (!uPort) {
uPort = 6667;
}
CServer* pServer = new CServer(sName, uPort, sPass, bSSL);
m_vServers.push_back(pServer);
return true;
}
CServer* CUser::GetNextServer() {
if (m_vServers.empty()) {
return NULL;
}
if (m_uServerIdx >= m_vServers.size()) {
m_uServerIdx = 0;
}
return m_vServers[m_uServerIdx++]; // Todo: cycle through these
}
bool CUser::CheckPass(const string& sPass) {
if (!m_bPassHashed) {
return (sPass == m_sPass);
}
return (strcasecmp(m_sPass.c_str(), CMD5(sPass)) == 0);
}
TSocketManager<Csock>* CUser::GetManager() {
return &m_pZNC->GetManager();
}
CZNC* CUser::GetZNC() {
return m_pZNC;
}
CUserSock* CUser::GetUserSock() {
// Todo: optimize this by saving a pointer to the sock
return (CUserSock*) m_pZNC->GetManager().FindSockByName("USR::" + m_sUserName);
}
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
return (CIRCSock*) m_pZNC->GetManager().FindSockByName("IRC::" + m_sUserName);
}
string CUser::GetLocalIP() {
CIRCSock* pIRCSock = GetIRCSock();
if (pIRCSock) {
return pIRCSock->GetLocalIP();
}
CUserSock* pUserSock = GetUserSock();
if (pUserSock) {
return pUserSock->GetLocalIP();
}
return "";
}
bool CUser::PutIRC(const string& sLine) {
CIRCSock* pIRCSock = GetIRCSock();
if (!pIRCSock) {
return false;
}
pIRCSock->PutServ(sLine);
return true;
}
bool CUser::PutUser(const string& sLine) {
CUserSock* pUserSock = GetUserSock();
if (!pUserSock) {
return false;
}
pUserSock->PutServ(sLine);
return true;
}
bool CUser::PutStatus(const string& sLine) {
CUserSock* pUserSock = GetUserSock();
if (!pUserSock) {
return false;
}
pUserSock->PutStatus(sLine);
return true;
}
bool CUser::PutModule(const string& sModule, const string& sLine) {
CUserSock* pUserSock = GetUserSock();
if (!pUserSock) {
return false;
}
pUserSock->PutModule(sModule, sLine);
return true;
}
bool CUser::ResumeFile(const string& sRemoteNick, unsigned short uPort, unsigned long uFileSize) {
TSocketManager<Csock>& Manager = m_pZNC->GetManager();
for (unsigned int a = 0; a < Manager.size(); a++) {
if (strncasecmp(Manager[a]->GetSockName().c_str(), "DCC::LISTEN::", 13) == 0) {
CDCCSock* pSock = (CDCCSock*) Manager[a];
if (pSock->GetLocalPort() == uPort) {
if (pSock->Seek(uFileSize)) {
PutModule(pSock->GetModuleName(), "DCC -> [" + pSock->GetRemoteNick() + "][" + pSock->GetFileName() + "] - Attempting to resume from file position [" + CUtils::ToString(uFileSize) + "]");
return true;
} else {
return false;
}
}
}
}
return false;
}
bool CUser::SendFile(const string& sRemoteNick, const string& sFileName, const string& sModuleName) {
string sFullPath = CUtils::ChangeDir(GetDLPath(), sFileName, GetHomePath());
CDCCSock* pSock = new CDCCSock(this, sRemoteNick, sFullPath, sModuleName);
CFile* pFile = pSock->OpenFile(false);
if (!pFile) {
delete pSock;
return false;
}
int iPort = GetManager()->ListenAllRand("DCC::LISTEN::" + sRemoteNick, false, SOMAXCONN, pSock, 120);
if (strcasecmp(GetNick().c_str(), sRemoteNick.c_str()) == 0) {
PutUser(":" + GetStatusPrefix() + "status!znc@znc.com PRIVMSG " + sRemoteNick + " :\001DCC SEND " + pFile->GetShortName() + " " + CUtils::ToString(CUtils::GetLongIP(GetLocalIP())) + " "
+ CUtils::ToString(iPort) + " " + CUtils::ToString(pFile->GetSize()) + "\001");
} else {
PutIRC("PRIVMSG " + sRemoteNick + " :\001DCC SEND " + pFile->GetShortName() + " " + CUtils::ToString(CUtils::GetLongIP(GetLocalIP())) + " "
+ CUtils::ToString(iPort) + " " + CUtils::ToString(pFile->GetSize()) + "\001");
}
PutModule(sModuleName, "DCC -> [" + sRemoteNick + "][" + pFile->GetShortName() + "] - Attempting Send.");
return true;
}
bool CUser::GetFile(const string& sRemoteNick, const string& sRemoteIP, unsigned short uRemotePort, const string& sFileName, unsigned long uFileSize, const string& sModuleName) {
if (CFile::Exists(sFileName)) {
PutModule(sModuleName, "DCC <- [" + sRemoteNick + "][" + sFileName + "] - File already exists.");
return false;
}
CDCCSock* pSock = new CDCCSock(this, sRemoteNick, sRemoteIP, uRemotePort, sFileName, uFileSize, sModuleName);
if (!pSock->OpenFile()) {
delete pSock;
return false;
}
if (!GetManager()->Connect(sRemoteIP, uRemotePort, "DCC::GET::" + sRemoteNick, 60, false, GetLocalIP(), pSock)) {
PutModule(sModuleName, "DCC <- [" + sRemoteNick + "][" + sFileName + "] - Unable to connect.");
return false;
}
PutModule(sModuleName, "DCC <- [" + sRemoteNick + "][" + sFileName + "] - Attempting to connect to [" + sRemoteIP + "]");
return true;
}
string CUser::GetCurNick() {
CIRCSock* pIRCSock = GetIRCSock();
if (pIRCSock) {
return pIRCSock->GetNick();
}
CUserSock* pUserSock = GetUserSock();
if (pUserSock) {
return pUserSock->GetNick();
}
return "";
}
// Setters
void CUser::SetNick(const string& s) { m_sNick = s; }
void CUser::SetAltNick(const string& s) { m_sAltNick = s; }
void CUser::SetIdent(const string& s) { m_sIdent = s; }
void CUser::SetRealName(const string& s) { m_sRealName = s; }
void CUser::SetVHost(const string& s) { m_sVHost = s; }
void CUser::SetPass(const string& s, bool bHashed) { m_sPass = s; m_bPassHashed = bHashed; }
void CUser::SetUseClientIP(bool b) { m_bUseClientIP = b; }
void CUser::SetKeepNick(bool b) { m_bKeepNick = b; }
void CUser::SetDenyLoadMod(bool b) { m_bDenyLoadMod = b; }
void CUser::SetDefaultChanModes(const string& s) { m_sDefaultChanModes = s; }
bool CUser::SetStatusPrefix(const string& s) {
if ((!s.empty()) && (s.length() < 6) && (s.find(' ') == string::npos)) {
m_sStatusPrefix = s;
return true;
}
return false;
}
// !Setters
// Getters
const string& CUser::GetUserName() const { return m_sUserName; }
const string& CUser::GetNick() const { return m_sNick; }
const string& CUser::GetAltNick() const { return m_sAltNick; }
const string& CUser::GetIdent() const { return m_sIdent; }
const string& CUser::GetRealName() const { return m_sRealName; }
const string& CUser::GetVHost() const { return m_sVHost; }
const string& CUser::GetPass() const { return m_sPass; }
const string& CUser::GetBinPath() const { return m_pZNC->GetBinPath(); }
const string& CUser::GetDLPath() const { return m_pZNC->GetDLPath(); }
const string& CUser::GetModPath() const { return m_pZNC->GetModPath(); }
const string& CUser::GetHomePath() const { return m_pZNC->GetHomePath(); }
bool CUser::UseClientIP() const { return m_bUseClientIP; }
bool CUser::KeepNick() const { return m_bKeepNick; }
bool CUser::DenyLoadMod() const { return m_bDenyLoadMod; }
const string& CUser::GetStatusPrefix() const { return m_sStatusPrefix; }
const string& CUser::GetDefaultChanModes() const { return m_sDefaultChanModes; }
const vector<CChan*>& CUser::GetChans() const { return m_vChans; }
// !Getters
+124
View File
@@ -0,0 +1,124 @@
#ifndef _USER_H
#define _USER_H
#ifdef _MODULES
#include "Modules.h"
#endif
#include <vector>
#include <set>
using std::vector;
using std::set;
class CZNC;
class CChan;
class CServer;
class CIRCSock;
class CUserSock;
class CUser {
public:
CUser(const string& sUserName, CZNC* pZNC);
virtual ~CUser();
CChan* FindChan(const string& sName);
bool AddChan(CChan* pChan);
bool AddChan(const string& sName, unsigned int uBufferCount = 50);
bool DelChan(const string& sName);
bool AddServer(const string& sName);
bool AddServer(const string& sName, unsigned short uPort, const string& sPass = "", bool bSSL = false);
CServer* GetNextServer();
bool CheckPass(const string& sPass);
bool AddAllowedHost(const string& sHostMask);
bool IsHostAllowed(const string& sHostMask);
#ifdef _MODULES
// Modules
CModules& GetModules() { return m_Modules; }
// !Modules
#endif
bool OnBoot();
bool IsUserAttached();
bool PutIRC(const string& sLine);
bool PutUser(const string& sLine);
bool PutStatus(const string& sLine);
bool PutModule(const string& sModule, const string& sLine);
string GetLocalIP();
bool SendFile(const string& sRemoteNick, const string& sFileName, const string& sModuleName = "");
bool GetFile(const string& sRemoteNick, const string& sRemoteIP, unsigned short uRemotePort, const string& sFileName, unsigned long uFileSize, const string& sModuleName = "");
bool ResumeFile(const string& sRemoteNick, unsigned short uPort, unsigned long uFileSize);
string GetCurNick();
// Setters
void SetNick(const string& s);
void SetAltNick(const string& s);
void SetIdent(const string& s);
void SetRealName(const string& s);
void SetVHost(const string& s);
void SetPass(const string& s, bool bHashed);
void SetUseClientIP(bool b);
void SetKeepNick(bool b);
void SetDenyLoadMod(bool b);
bool SetStatusPrefix(const string& s);
void SetDefaultChanModes(const string& s);
// !Setters
// Getters
CUserSock* GetUserSock();
CIRCSock* GetIRCSock();
TSocketManager<Csock>* GetManager();
CZNC* GetZNC();
const string& GetUserName() const;
const string& GetNick() const;
const string& GetAltNick() const;
const string& GetIdent() const;
const string& GetRealName() const;
const string& GetVHost() const;
const string& GetPass() const;
const string& GetBinPath() const;
const string& GetDLPath() const;
const string& GetModPath() const;
const string& GetHomePath() const;
bool UseClientIP() const;
bool KeepNick() const;
bool DenyLoadMod() const;
const string& GetStatusPrefix() const;
const string& GetDefaultChanModes() const;
const vector<CChan*>& GetChans() const;
// !Getters
private:
protected:
CZNC* m_pZNC;
string m_sUserName;
string m_sNick;
string m_sAltNick;
string m_sIdent;
string m_sRealName;
string m_sVHost;
string m_sPass;
string m_sStatusPrefix;
string m_sDefaultChanModes;
bool m_bPassHashed;
bool m_bUseClientIP;
bool m_bKeepNick;
bool m_bDenyLoadMod;
vector<CServer*> m_vServers;
vector<CChan*> m_vChans;
set<string> m_ssAllowedHosts;
unsigned int m_uServerIdx;
#ifdef _MODULES
CModules m_Modules;
#endif
};
#endif // !_USER_H
+846
View File
@@ -0,0 +1,846 @@
#include "main.h"
#include "UserSock.h"
#include "User.h"
#include "znc.h"
#include "IRCSock.h"
#include "DCCBounce.h"
#include "DCCSock.h"
void CUserSock::ReadLine(const string& sData) {
string sLine = sData;
while ((CUtils::Right(sLine, 1) == "\r") || (CUtils::Right(sLine, 1) == "\n")) {
CUtils::RightChomp(sLine);
}
DEBUG_ONLY(cout << GetSockName() << " <- [" << sLine << "]" << endl);
#ifdef _MODULES
if (m_bAuthed) {
if ((m_pUser) && (m_pUser->GetModules().OnUserRaw(sLine))) {
return;
}
}
#endif
string sCommand = CUtils::Token(sLine, 0);
if (strcasecmp(sCommand.c_str(), "ZNC") == 0) {
PutStatus("Hello. How may I help you?");
return;
} else if (strcasecmp(sCommand.c_str(), "PONG") == 0) {
return; // Block pong replies, we already responded to the pings
} else if (strcasecmp(sCommand.c_str(), "PASS") == 0) {
m_sPass = CUtils::Token(sLine, 1);
if (m_sPass.find(":") != string::npos) {
m_sUser = CUtils::Token(m_sPass, 0, false, ':');
m_sPass = CUtils::Token(m_sPass, 1, true, ':');
}
m_bGotUser = (!m_sUser.empty());
if ((m_bGotNick) && (m_bGotUser)) {
AuthUser();
}
return; // Don't forward this msg. ZNC has already registered us.
} else if (strcasecmp(sCommand.c_str(), "NICK") == 0) {
string sNick = CUtils::Token(sLine, 1);
if (CUtils::Left(sNick, 1) == ":") {
CUtils::LeftChomp(sNick);
}
if (!m_bAuthed) {
m_sNick = sNick;
m_bGotNick = true;
if (m_bGotUser) {
AuthUser();
}
return; // Don't forward this msg. The bnc will handle nick changes until auth is complete
}
if ((m_pUser) && (strcasecmp(sNick.c_str(), m_pUser->GetNick().c_str()) == 0)) {
m_uKeepNickCounter++;
}
} else if (strcasecmp(sCommand.c_str(), "USER") == 0) {
if ((!m_bGotUser) && (!m_bAuthed)) {
m_sUser = CUtils::Token(sLine, 1);
m_bGotUser = true;
if (m_bGotNick) {
AuthUser();
}
}
return; // Don't forward this msg. ZNC has already registered us.
} else if (strcasecmp(sCommand.c_str(), "JOIN") == 0) {
string sChan = CUtils::Token(sLine, 1);
if (CUtils::Left(sChan, 1) == ":") {
CUtils::LeftChomp(sChan);
}
if (m_pUser) {
CChan* pChan = m_pUser->FindChan(sChan);
if ((pChan) && (!pChan->IsOn())) {
pChan->IncClientRequests();
}
}
} else if (strcasecmp(sCommand.c_str(), "QUIT") == 0) {
if (m_pIRCSock) {
m_pIRCSock->UserDisconnected();
}
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 (strcasecmp(sCommand.c_str(), "NOTICE") == 0) {
string sTarget = CUtils::Token(sLine, 1);
string sMsg = CUtils::Token(sLine, 2, true);
if (CUtils::Left(sMsg, 1) == ":") {
CUtils::LeftChomp(sMsg);
}
if ((!m_pUser) || (strcasecmp(sTarget.c_str(), string(m_pUser->GetStatusPrefix() + "status").c_str())) == 0) {
return;
}
if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
#ifdef _MODULES
if (m_pUser) {
string sModule = sTarget;
CUtils::LeftChomp(sModule, m_pUser->GetStatusPrefix().length());
CModule* pModule = m_pUser->GetModules().FindModule(sModule);
if (pModule) {
pModule->OnModNotice(sMsg);
} else {
PutStatus("No such module [" + sModule + "]");
}
}
#endif
return;
}
if (CUtils::WildCmp("DCC * (*)", sMsg.c_str())) {
sMsg = "DCC " + CUtils::Token(sLine, 3) + " (" + ((m_pIRCSock) ? m_pIRCSock->GetLocalIP() : GetLocalIP()) + ")";
}
CChan* pChan = m_pUser->FindChan(sTarget);
if ((pChan) && (pChan->KeepBuffer())) {
pChan->AddBuffer(":" + GetNickMask() + " NOTICE " + sTarget + " :" + sMsg);
}
#ifdef _MODULES
if (CUtils::WildCmp("\001*\001", sMsg.c_str())) {
string sCTCP = sMsg;
CUtils::LeftChomp(sCTCP);
CUtils::RightChomp(sCTCP);
if ((m_pUser) && (m_pUser->GetModules().OnUserCTCPReply(sTarget, sCTCP))) {
return;
}
sMsg = "\001" + sCTCP + "\001";
} else {
if ((m_pUser) && (m_pUser->GetModules().OnUserNotice(sTarget, sMsg))) {
return;
}
}
#endif
PutIRC("NOTICE " + sTarget + " :" + sMsg);
return;
} else if (strcasecmp(sCommand.c_str(), "PRIVMSG") == 0) {
string sTarget = CUtils::Token(sLine, 1);
string sMsg = CUtils::Token(sLine, 2, true);
if (CUtils::Left(sMsg, 1) == ":") {
CUtils::LeftChomp(sMsg);
}
if (CUtils::WildCmp("\001*\001", sMsg.c_str())) {
string sCTCP = sMsg;
CUtils::LeftChomp(sCTCP);
CUtils::RightChomp(sCTCP);
if (strncasecmp(sCTCP.c_str(), "DCC ", 4) == 0) {
string sType = CUtils::Token(sCTCP, 1);
string sFile = CUtils::Token(sCTCP, 2);
unsigned long uLongIP = strtoul(CUtils::Token(sCTCP, 3).c_str(), NULL, 10);
unsigned short uPort = strtoul(CUtils::Token(sCTCP, 4).c_str(), NULL, 10);
unsigned long uFileSize = strtoul(CUtils::Token(sCTCP, 5).c_str(), NULL, 10);
string sIP = (m_pIRCSock) ? m_pIRCSock->GetLocalIP() : GetLocalIP();
if (!m_pUser->UseClientIP()) {
uLongIP = CUtils::GetLongIP(GetRemoteIP());
}
if (strcasecmp(sType.c_str(), "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 " + CUtils::ToString(CUtils::GetLongIP(sIP)) + " " + CUtils::ToString(uBNCPort) + "\001");
}
}
} else if (strcasecmp(sType.c_str(), "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) || (strcasecmp(sTarget.c_str(), string(m_pUser->GetStatusPrefix() + "status").c_str()) == 0)) {
if (!m_pUser) {
return;
}
string sPath = m_pUser->GetDLPath();
if (!CFile::Exists(sPath)) {
PutStatus("Directory [" + sPath + "] not found, creating.");
if (mkdir(sPath.c_str(), 0700)) {
PutStatus("Could not create [" + sPath + "] directory.");
return;
}
} else if (!CFile::IsDir(sPath)) {
PutStatus("Error: [" + sPath + "] is not a directory.");
return;
}
string sLocalFile = sPath + "/" + sFile;
if (m_pUser) {
m_pUser->GetFile(GetNick(), CUtils::GetIP(uLongIP), uPort, sLocalFile, uFileSize);
}
} else {
#ifdef _MODULES
if ((m_pUser) && (m_pUser->GetModules().OnDCCUserSend(sTarget, uLongIP, uPort, sFile, uFileSize))) {
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 + " " + CUtils::ToString(CUtils::GetLongIP(sIP)) + " " + CUtils::ToString(uBNCPort) + " " + CUtils::ToString(uFileSize) + "\001");
}
}
} else if (strcasecmp(sType.c_str(), "RESUME") == 0) {
// PRIVMSG user :DCC RESUME "znc.o" 58810 151552
unsigned short uResumePort = atoi(CUtils::Token(sCTCP, 3).c_str());
unsigned long uResumeSize = strtoul(CUtils::Token(sCTCP, 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))) {
PutServ(":" + sTarget + "!znc@znc.com PRIVMSG " + GetNick() + " :\001DCC ACCEPT " + sFile + " " + CUtils::ToString(uResumePort) + " " + CUtils::ToString(uResumeSize) + "\001");
} else {
PutStatus("DCC -> [" + GetNick() + "][" + sFile + "] Unable to find send to initiate resume.");
}
} else {
CDCCBounce* pSock = (CDCCBounce*) m_pZNC->GetManager().FindSockByLocalPort(uResumePort);
if ((pSock) && (strncasecmp(pSock->GetSockName().c_str(), "DCC::", 5) == 0)) {
PutIRC("PRIVMSG " + sTarget + " :\001DCC " + sType + " " + sFile + " " + CUtils::ToString(pSock->GetUserPort()) + " " + CUtils::Token(sCTCP, 4) + "\001");
}
}
} else if (strcasecmp(sType.c_str(), "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
TSocketManager<Csock>& Manager = m_pZNC->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(CUtils::Token(sCTCP, 3).c_str())) {
PutIRC("PRIVMSG " + sTarget + " :\001DCC " + sType + " " + sFile + " " + CUtils::ToString(pSock->GetLocalPort()) + " " + CUtils::Token(sCTCP, 4) + "\001");
}
}
}
}
}
return;
}
if (strncasecmp(sTarget.c_str(), m_pUser->GetStatusPrefix().c_str(), m_pUser->GetStatusPrefix().length()) == 0) {
#ifdef _MODULES
string sModule = sTarget;
CUtils::LeftChomp(sModule, m_pUser->GetStatusPrefix().length());
CModule* pModule = m_pUser->GetModules().FindModule(sModule);
if (pModule) {
pModule->OnModCTCP(sCTCP);
} else {
PutStatus("No such module [" + sModule + "]");
}
#endif
return;
}
#ifdef _MODULES
if ((m_pUser) && (m_pUser->GetModules().OnUserCTCP(sTarget, sCTCP))) {
return;
}
#endif
PutIRC("PRIVMSG " + sTarget + " :\001" + sCTCP + "\001");
return;
}
if ((m_pUser) && (strcasecmp(sTarget.c_str(), string(m_pUser->GetStatusPrefix() + "status").c_str()) == 0)) {
#ifdef _MODULES
if ((m_pUser) && (m_pUser->GetModules().OnStatusCommand(sMsg))) {
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) {
string sModule = sTarget;
CUtils::LeftChomp(sModule, m_pUser->GetStatusPrefix().length());
CModule* pModule = m_pUser->GetModules().FindModule(sModule);
if (pModule) {
pModule->OnModCommand(sMsg);
} else {
PutStatus("No such module [" + sModule + "]");
}
}
#endif
return;
}
CChan* pChan = m_pUser->FindChan(sTarget);
if ((pChan) && (pChan->KeepBuffer())) {
pChan->AddBuffer(":" + GetNickMask() + " PRIVMSG " + sTarget + " :" + sMsg);
}
#ifdef _MODULES
if ((m_pUser) && (m_pUser->GetModules().OnUserMsg(sTarget, sMsg))) {
return;
}
#endif
PutIRC("PRIVMSG " + sTarget + " :" + sMsg);
return;
}
PutIRC(sLine);
}
void CUserSock::SetNick(const string& s) {
m_sNick = s;
if (m_pUser) {
if (strcasecmp(m_sNick.c_str(), m_pUser->GetNick().c_str()) == 0) {
m_uKeepNickCounter = 0;
}
}
}
bool CUserSock::DecKeepNickCounter() {
if (!m_uKeepNickCounter) {
return false;
}
m_uKeepNickCounter--;
return true;
}
void CUserSock::UserCommand(const string& sLine) {
if (!m_pUser) {
return;
}
if (sLine.empty()) {
return;
}
string sCommand = CUtils::Token(sLine, 0);
if (strcasecmp(sCommand.c_str(), "LISTNICKS") == 0) {
string sChan = CUtils::Token(sLine, 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<string,CNick*>& msNicks = pChan->GetNicks();
if (!msNicks.size()) {
PutStatus("No nicks on [" + sChan + "]");
return;
}
CTable Table;
Table.AddColumn("@");
Table.AddColumn("+");
Table.AddColumn("Nick");
Table.AddColumn("Ident");
Table.AddColumn("Host");
for (map<string,CNick*>::const_iterator a = msNicks.begin(); a != msNicks.end(); a++) {
Table.AddRow();
if (a->second->IsOp()) { Table.SetCell("@", "@"); }
if (a->second->IsVoice()) { Table.SetCell("+", "+"); }
Table.SetCell("Nick", a->second->GetNick());
Table.SetCell("Ident", a->second->GetIdent());
Table.SetCell("Host", a->second->GetHost());
}
unsigned int uTableIdx = 0;
string sLine;
while (Table.GetLine(uTableIdx++, sLine)) {
PutStatus(sLine);
}
} else if (strcasecmp(sCommand.c_str(), "JUMP") == 0) {
if (m_pUser) {
if (m_pIRCSock) {
m_pIRCSock->Close();
PutStatus("Jumping to the next server in the list...");
return;
}
}
} else if (strcasecmp(sCommand.c_str(), "LISTCHANS") == 0) {
if (m_pUser) {
const vector<CChan*>& vChans = m_pUser->GetChans();
CTable Table;
Table.AddColumn("Name");
Table.AddColumn("Status");
Table.AddColumn("Buf");
Table.AddColumn("Modes");
Table.AddColumn("Users");
Table.AddColumn("+o");
Table.AddColumn("+v");
for (unsigned int a = 0; a < vChans.size(); a++) {
CChan* pChan = vChans[a];
Table.AddRow();
Table.SetCell("Name", pChan->GetName());
Table.SetCell("Status", ((vChans[a]->IsOn()) ? "Joined" : "Trying"));
Table.SetCell("Buf", CUtils::ToString(pChan->GetBufferCount()));
string sModes = pChan->GetModeString();
unsigned int uLimit = pChan->GetLimit();
const string& sKey = pChan->GetKey();
if (uLimit) { sModes += " " + CUtils::ToString(uLimit); }
if (!sKey.empty()) { sModes += " " + sKey; }
Table.SetCell("Modes", sModes);
Table.SetCell("Users", CUtils::ToString(pChan->GetNickCount()));
Table.SetCell("+o", CUtils::ToString(pChan->GetOpCount()));
Table.SetCell("+v", CUtils::ToString(pChan->GetVoiceCount()));
}
if (Table.size()) {
unsigned int uTableIdx = 0;
string sLine;
while (Table.GetLine(uTableIdx++, sLine)) {
PutStatus(sLine);
}
}
}
} else if (strcasecmp(sCommand.c_str(), "SEND") == 0) {
string sToNick = CUtils::Token(sLine, 1);
string sFile = CUtils::Token(sLine, 2);
if ((sToNick.empty()) || (sFile.empty())) {
PutStatus("Usage: Send <nick> <file>");
return;
}
if (m_pUser) {
m_pUser->SendFile(sToNick, sFile);
}
} else if (strcasecmp(sCommand.c_str(), "GET") == 0) {
string sFile = CUtils::Token(sLine, 1);
if (sFile.empty()) {
PutStatus("Usage: Get <file>");
return;
}
if (m_pUser) {
m_pUser->SendFile(GetNick(), sFile);
}
} else if (strcasecmp(sCommand.c_str(), "LISTDCCS") == 0) {
TSocketManager<Csock>& Manager = m_pZNC->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 string& 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", CUtils::ToPercent(pSock->GetProgress()));
Table.SetCell("Speed", CUtils::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", CUtils::ToPercent(pSock->GetProgress()));
Table.SetCell("Speed", CUtils::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];
string 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];
string 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;
string sLine;
while (Table.GetLine(uTableIdx++, sLine)) {
PutStatus(sLine);
}
} else {
PutStatus("You have no active DCCs.");
}
} else if ((strcasecmp(sCommand.c_str(), "LISTMODS") == 0) || (strcasecmp(sCommand.c_str(), "LISTMODULES") == 0)) {
#ifdef _MODULES
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", CUtils::Ellipsize(Modules[b]->GetDescription(), 128));
}
unsigned int uTableIdx = 0; string sLine;
while (Table.GetLine(uTableIdx++, sLine)) {
PutStatus(sLine);
}
}
#else
PutStatus("Modules are not enabled.");
#endif
return;
} else if ((strcasecmp(sCommand.c_str(), "LOADMOD") == 0) || (strcasecmp(sCommand.c_str(), "LOADMODULE") == 0)) {
string sMod = CUtils::Token(sLine, 1);
string sArgs = CUtils::Token(sLine, 2, true);
if (m_pUser->DenyLoadMod()) {
PutStatus("Unable to load [" + sMod + "] Access Denied.");
return;
}
#ifdef _MODULES
if (sMod.empty()) {
PutStatus("Usage: LoadMod <module> [args]");
return;
}
string sModRet;
m_pUser->GetModules().LoadModule(sMod, sArgs, m_pUser, m_pZNC->GetBinPath(), sModRet);
PutStatus(sModRet);
#else
PutStatus("Unable to load [" + sMod + "] Modules are not enabled.");
#endif
return;
} else if ((strcasecmp(sCommand.c_str(), "UNLOADMOD") == 0) || (strcasecmp(sCommand.c_str(), "UNLOADMODULE") == 0)) {
string sMod = CUtils::Token(sLine, 1);
if (m_pUser->DenyLoadMod()) {
PutStatus("Unable to unload [" + sMod + "] Access Denied.");
return;
}
#ifdef _MODULES
if (sMod.empty()) {
PutStatus("Usage: UnloadMod <module>");
return;
}
string sModRet;
m_pUser->GetModules().UnloadModule(sMod, sModRet);
PutStatus(sModRet);
#else
PutStatus("Unable to unload [" + sMod + "] Modules are not enabled.");
#endif
return;
} else if ((strcasecmp(sCommand.c_str(), "RELOADMOD") == 0) || (strcasecmp(sCommand.c_str(), "RELOADMODULE") == 0)) {
string sMod = CUtils::Token(sLine, 1);
string sArgs = CUtils::Token(sLine, 2, true);
if (m_pUser->DenyLoadMod()) {
PutStatus("Unable to reload [" + sMod + "] Access Denied.");
return;
}
#ifdef _MODULES
if (sMod.empty()) {
PutStatus("Usage: ReloadMod <module> [args]");
return;
}
string sModRet;
m_pUser->GetModules().ReloadModule(sMod, sArgs, m_pUser, m_pZNC->GetBinPath(), sModRet);
PutStatus(sModRet);
#else
PutStatus("Unable to unload [" + sMod + "] Modules are not enabled.");
#endif
return;
} else if (strcasecmp(sCommand.c_str(), "SETBUFFER") == 0) {
string sChan = CUtils::Token(sLine, 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(CUtils::Token(sLine, 2).c_str(), NULL, 10);
if (uLineCount > 500) {
PutStatus("Max linecount is 500.");
return;
}
pChan->SetBufferCount(uLineCount);
PutStatus("BufferCount for [" + sChan + "] set to [" + CUtils::ToString(pChan->GetBufferCount()) + "]");
} else {
PutStatus("I'm too stupid to help you with [" + sCommand + "]");
}
}
bool CUserSock::ConnectionFrom(const string& sHost, int iPort) {
DEBUG_ONLY(cout << GetSockName() << " == ConnectionFrom(" << sHost << ", " << iPort << ")" << endl);
return m_pZNC->IsHostAllowed(sHost);
}
void CUserSock::AuthUser() {
if (!m_pZNC) {
DEBUG_ONLY(cout << "znc not set!" << endl);
Close();
return;
}
CUser* pUser = m_pZNC->GetUser(m_sUser);
if ((!pUser) || (!pUser->CheckPass(m_sPass))) {
if (pUser) {
pUser->PutStatus("Another user attempted to login as you, with a bad password.");
}
PutStatus("Bad username and/or password.");
PutServ(":irc.znc.com 464 " + GetNick() + " :Password Incorrect");
Close();
} else {
m_sPass = "";
m_pUser = pUser;
if (!m_pUser->IsHostAllowed(GetRemoteIP())) {
Close();
return;
}
m_bAuthed = true;
SetSockName("USR::" + pUser->GetUserName());
CIRCSock* pIRCSock = (CIRCSock*) m_pZNC->FindSockByName("IRC::" + pUser->GetUserName());
if (pIRCSock) {
m_pIRCSock = pIRCSock;
pIRCSock->UserConnected(this);
}
#ifdef _MODULES
m_pUser->GetModules().OnUserAttached();
#endif
}
}
void CUserSock::Connected() {
DEBUG_ONLY(cout << GetSockName() << " == Connected();" << endl);
SetTimeout(900); // Now that we are connected, let nature take its course
}
void CUserSock::ConnectionRefused() {
DEBUG_ONLY(cout << GetSockName() << " == ConnectionRefused()" << endl);
}
void CUserSock::Disconnected() {
if (m_pIRCSock) {
m_pIRCSock->UserDisconnected();
m_pIRCSock = NULL;
}
#ifdef _MODULES
if (m_pUser) {
m_pUser->GetModules().OnUserDetached();
}
#endif
}
void CUserSock::IRCConnected(CIRCSock* pIRCSock) {
m_pIRCSock = pIRCSock;
}
void CUserSock::BouncedOff() {
PutStatus("You are being disconnected because another user just authenticated as you.");
m_pIRCSock = NULL;
Close();
}
void CUserSock::IRCDisconnected() {
m_pIRCSock = NULL;
}
Csock* CUserSock::GetSockObj(const string& sHost, int iPort) {
CUserSock* pSock = new CUserSock(sHost, iPort);
pSock->SetZNC(m_pZNC);
return pSock;
}
void CUserSock::PutIRC(const string& sLine) {
if (m_pIRCSock) {
m_pIRCSock->PutServ(sLine);
}
}
void CUserSock::PutServ(const string& sLine) {
DEBUG_ONLY(cout << GetSockName() << " -> [" << sLine << "]" << endl);
Write(sLine + "\r\n");
}
void CUserSock::PutStatus(const string& sLine) {
PutModule("status", sLine);
}
void CUserSock::PutModule(const string& sModule, const string& sLine) {
if (!m_pUser) {
return;
}
DEBUG_ONLY(cout << GetSockName() << " -> [:" + 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");
}
string CUserSock::GetNick() const {
string sRet;
if ((m_bAuthed) && (m_pIRCSock)) {
sRet = m_pIRCSock->GetNick();
}
return (sRet.empty()) ? m_sNick : sRet;
}
string CUserSock::GetNickMask() const {
if (m_pIRCSock) {
return m_pIRCSock->GetNickMask();
}
return GetNick() + "!" + m_pUser->GetIdent() + "@" + m_pUser->GetVHost();
}
+73
View File
@@ -0,0 +1,73 @@
#ifndef _USERSOCK_H
#define _USERSOCK_H
#include "main.h"
// Forward Declarations
class CZNC;
class CUser;
class CIRCSock;
// !Forward Declarations
class CUserSock : public Csock {
public:
CUserSock() : Csock() {
Init();
}
CUserSock(const string& sHostname, int iport, int itimeout = 60) : Csock(sHostname, iport, itimeout) {
Init();
}
virtual ~CUserSock() {}
void Init() {
m_pZNC = NULL;
m_pUser = NULL;
m_pIRCSock = NULL;
m_bAuthed = false;
m_bGotNick = false;
m_bGotUser = false;
m_uKeepNickCounter = 0;
EnableReadLine();
}
string GetNick() const;
string GetNickMask() const;
bool DecKeepNickCounter();
void UserCommand(const string& sCommand);
void IRCConnected(CIRCSock* pIRCSock);
void IRCDisconnected();
void BouncedOff();
bool IsAttached() const { return m_bAuthed; }
void PutIRC(const string& sLine);
void PutServ(const string& sLine);
void PutStatus(const string& sLine);
void PutModule(const string& sModule, const string& sLine);
virtual void ReadLine(const string& sData);
void AuthUser();
virtual void Connected();
virtual void Disconnected();
virtual void ConnectionRefused();
virtual bool ConnectionFrom(const string& sHost, int iPort);
virtual Csock* GetSockObj(const string& sHost, int iPort);
void SetZNC(CZNC* pZNC) { m_pZNC = pZNC; }
void SetNick(const string& s);
private:
protected:
bool m_bAuthed;
bool m_bGotNick;
bool m_bGotUser;
CZNC* m_pZNC;
CUser* m_pUser;
string m_sNick;
string m_sPass;
string m_sUser;
CIRCSock* m_pIRCSock;
unsigned int m_uKeepNickCounter;
};
#endif // !_USERSOCK_H
+687
View File
@@ -0,0 +1,687 @@
#include "Utils.h"
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sstream>
using std::stringstream;
CUtils::CUtils() {}
CUtils::~CUtils() {}
string CUtils::GetIP(unsigned long addr) {
char szBuf[16];
memset((char*) szBuf, 0, 16);
if (addr >= (1 << 24)) {
unsigned long ip[4];
ip[0] = addr >> 24 & 255;
ip[1] = addr >> 16 & 255;
ip[2] = addr >> 8 & 255;
ip[3] = addr & 255;
sprintf(szBuf, "%lu.%lu.%lu.%lu", ip[0], ip[1], ip[2], ip[3]);
}
return szBuf;
}
unsigned long CUtils::GetLongIP(const string& sIP) {
register int i;
char *addr = (char *) malloc(sIP.length() +1);
char ip[4][4], n;
strcpy(addr, sIP.c_str());
for (i=0; i<4; ip[0][i]=ip[1][i]=ip[2][i]=ip[3][i]='\0', i++);
if (sscanf(addr, "%3[0-9].%3[0-9].%3[0-9].%3[0-9]%[^\n]", ip[0], ip[1], ip[2], ip[3], &n) != 4) {
free(addr);
return 0;
}
free(addr);
return (unsigned long) ((atoi(ip[0]) << 24) + (atoi(ip[1]) << 16) + (atoi(ip[2]) << 8) + atoi(ip[3]));
}
string CUtils::ChangeDir(const string& sPath, const string& sAdd, const string& sHomeDir) {
if (sAdd == "~") {
return sHomeDir;
}
string sAddDir = sAdd;
if (CUtils::Left(sAddDir, 2) == "~/") {
CUtils::LeftChomp(sAddDir);
sAddDir = sHomeDir + sAddDir;
}
string sRet = ((sAddDir.size()) && (sAddDir[0] == '/')) ? "" : sPath;
sAddDir += "/";
string sCurDir;
if (CUtils::Right(sRet, 1) == "/") {
CUtils::RightChomp(sRet);
}
for (unsigned int a = 0; a < sAddDir.size(); a++) {
switch (sAddDir[a]) {
case '/':
if (sCurDir == "..") {
sRet = sRet.substr(0, sRet.rfind('/'));
} else if ((sCurDir != "") && (sCurDir != ".")) {
sRet += "/" + sCurDir;
}
sCurDir = "";
break;
default:
sCurDir += sAddDir[a];
break;
}
}
return (sRet.empty()) ? "/" : sRet;
}
string CUtils::ToString(short i) { stringstream s; s << i; return s.str(); }
string CUtils::ToString(unsigned short i) { stringstream s; s << i; return s.str(); }
string CUtils::ToString(int i) { stringstream s; s << i; return s.str(); }
string CUtils::ToString(unsigned int i) { stringstream s; s << i; return s.str(); }
string CUtils::ToString(long i) { stringstream s; s << i; return s.str(); }
string CUtils::ToString(unsigned long i) { stringstream s; s << i; return s.str(); }
string CUtils::ToString(unsigned long long i) { stringstream s; s << i; return s.str(); }
string CUtils::ToString(double i) { stringstream s; s << i; return s.str(); }
string CUtils::ToString(float i) { stringstream s; s << i; return s.str(); }
string CUtils::ToPercent(double d) {
char szRet[32];
snprintf(szRet, 32, "%.02f%%", d);
return szRet;
}
string CUtils::ToKBytes(double d) {
char szRet[32];
snprintf(szRet, 32, "%.0f K/s", d);
return szRet;
}
string CUtils::Left(const string& s, unsigned int u) {
u = (u > s.length()) ? s.length() : u;
return s.substr(0, u);
}
string CUtils::Right(const string& s, unsigned int u) {
u = (u > s.length()) ? s.length() : u;
return s.substr(s.length() - u, u);
}
string& CUtils::Trim(string& s) {
while ((Right(s, 1) == " ") || (Right(s, 1) == "\t") || (Right(s, 1) == "\r") || (Right(s, 1) == "\n")) {
RightChomp(s);
}
while ((Left(s, 1) == " ") || (Left(s, 1) == "\t") || (Left(s, 1) == "\r") || (Left(s, 1) == "\n")) {
LeftChomp(s);
}
return s;
}
string& CUtils::LeftChomp(string& s, unsigned int uLen) {
while ((uLen--) && (s.length())) {
s.erase(0, 1);
}
return s;
}
string& CUtils::RightChomp(string& s, unsigned int uLen) {
while ((uLen--) && (s.length())) {
s.erase(s.length() -1);
}
return s;
}
string CUtils::Token(const string& s, unsigned int uPos, bool bRest, char cSep) {
string sRet;
const char* p = s.c_str();
while (*p) {
if (uPos) {
if (*p == cSep) {
uPos--;
}
} else {
if ((*p == cSep) && (!bRest)) {
return sRet;
}
sRet += *p;
}
p++;
}
return sRet;
}
string CUtils::Ellipsize(const string& s, unsigned int uLen) {
if (uLen >= s.size()) {
return s;
}
string sRet;
if (uLen < 4) {
for (unsigned int a = 0; a < uLen; a++) {
sRet += ".";
}
return sRet;
}
sRet = s.substr(0, uLen -3) + "...";
return sRet;
}
bool CUtils::WildCmp(const string& sWild, const string& sString) {
char *wild = (char*) sWild.c_str();
char *string = (char*) sString.c_str();
register int i, len;
char *copy, *cp, *p, *lastmatch = string;
if ((p = strchr (wild, '*')) == NULL) {
return (strcasecmp(wild, string) ? false : true);
}
if (wild[0] != '*' && strncasecmp(string, wild, p-wild)) {
return false;
}
len = strlen(wild) + 1;
if (wild[len -2] != '*') {
p = strrchr(wild, '*') + 1;
if (strcasecmp(string + strlen(string) - strlen(p), p) != 0) {
return false;
}
}
cp = copy = (char*) malloc(len);
memset((char*) copy, 0, len);
for (i=0; i<len; i++) {
if (wild[i] == '*' || wild[i] == '\0') {
if ((p = strcasestr(lastmatch, copy)) != NULL) {
lastmatch = p + strlen(copy);
memset((char*) copy, 0, len);
cp = copy;
continue;
} else {
free(copy);
return false;
}
}
*cp++ = wild[i];
}
free(copy);
return true;
}
CTable::CTable() {}
CTable::~CTable() {
for (unsigned int a = 0; a < size(); a++) {
delete (*this)[a];
}
clear();
}
bool CTable::AddColumn(const string& sName) {
for (unsigned int a = 0; a < m_vsHeaders.size(); a++) {
if (strcasecmp(m_vsHeaders[a].c_str(), sName.c_str()) == 0) {
return false;
}
}
m_vsHeaders.push_back(sName);
return true;
}
unsigned int CTable::AddRow() {
push_back(new map<string, string>);
return size() -1;
}
bool CTable::SetCell(const string& sColumn, const string& sValue, unsigned int uRowIdx) {
if (uRowIdx == (unsigned int) ~0) {
if (!size()) {
return false;
}
uRowIdx = size() -1;
}
(*(*this)[uRowIdx])[sColumn] = sValue;
return true;
}
bool CTable::GetLine(unsigned int uIdx, string& sLine) {
stringstream ssRet;
if (!size()) {
return false;
}
if (uIdx == 1) {
m_msuWidths.clear(); // Clear out the width cache
ssRet.fill(' ');
ssRet << "| ";
for (unsigned int a = 0; a < m_vsHeaders.size(); a++) {
ssRet.width(GetColumnWidth(a));
ssRet << std::left << m_vsHeaders[a];
ssRet << ((a == m_vsHeaders.size() -1) ? " |" : " | ");
}
sLine = ssRet.str();
return true;
} else if ((uIdx == 0) || (uIdx == 2) || (uIdx == (size() +3))) {
ssRet.fill('-');
ssRet << "+-";
for (unsigned int a = 0; a < m_vsHeaders.size(); a++) {
ssRet.width(GetColumnWidth(a));
ssRet << std::left << "-";
ssRet << ((a == m_vsHeaders.size() -1) ? "-+" : "-+-");
}
sLine = ssRet.str();
return true;
} else {
uIdx -= 3;
if (uIdx < size()) {
map<string, string>* pRow = (*this)[uIdx];
ssRet.fill(' ');
ssRet << "| ";
for (unsigned int c = 0; c < m_vsHeaders.size(); c++) {
ssRet.width(GetColumnWidth(c));
ssRet << std::left << (*pRow)[m_vsHeaders[c]];
ssRet << ((c == m_vsHeaders.size() -1) ? " |" : " | ");
}
sLine = ssRet.str();
return true;
}
}
return false;
}
/*
bool CTable::Output(std::ostream oOut) {
stringstream ssSep;
ssSep << "-+-";
oOut << endl << ssSep.str() << endl;
for (unsigned int b = 0; b < size(); b++) {
map<string, string>* pRow = (*this)[b];
oOut << " | ";
for (unsigned int c = 0; c < m_vsHeaders.size(); c++) {
oOut.width(GetColumnWidth(c));
oOut << (*pRow)[m_vsHeaders[c]];
oOut << " | ";
}
oOut << endl;
}
oOut << ssSep.str() << endl;
return true;
}
*/
unsigned int CTable::GetColumnWidth(unsigned int uIdx) {
if (uIdx >= m_vsHeaders.size()) {
return 0;
}
const string& sColName = m_vsHeaders[uIdx];
unsigned int uRet = sColName.size();
map<string, unsigned int>::iterator it = m_msuWidths.find(sColName);
if (it != m_msuWidths.end()) {
return it->second;
}
for (unsigned int a = 0; a < size(); a++) {
map<string, string>* pRow = (*this)[a];
uRet = uRet >? (*pRow)[m_vsHeaders[uIdx]].size();
}
return uRet;
}
CFile::CFile(const string& sLongName) {
m_sLongName = sLongName;
m_iFD = -1;
m_sShortName = sLongName;
while (CUtils::Left(m_sShortName, 1) == "/") {
CUtils::LeftChomp(m_sShortName);
}
unsigned int uPos = m_sShortName.rfind('/');
if (uPos != string::npos) {
m_sShortName = m_sShortName.substr(uPos +1);
}
}
CFile::~CFile() {
if (m_iFD != -1) {
Close();
}
}
bool CFile::IsReg(const string& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_REGULAR, bUseLstat); }
bool CFile::IsDir(const string& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_DIRECTORY, bUseLstat); }
bool CFile::IsChr(const string& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_CHARACTER, bUseLstat); }
bool CFile::IsBlk(const string& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_BLOCK, bUseLstat); }
bool CFile::IsFifo(const string& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_FIFO, bUseLstat); }
bool CFile::IsLnk(const string& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_LINK, bUseLstat); }
bool CFile::IsSock(const string& sLongName, bool bUseLstat) { return CFile::FType(sLongName, FT_SOCK, bUseLstat); }
bool CFile::IsReg(bool bUseLstat) { return CFile::IsReg(m_sLongName, bUseLstat); }
bool CFile::IsDir(bool bUseLstat) { return CFile::IsDir(m_sLongName, bUseLstat); }
bool CFile::IsChr(bool bUseLstat) { return CFile::IsChr(m_sLongName, bUseLstat); }
bool CFile::IsBlk(bool bUseLstat) { return CFile::IsBlk(m_sLongName, bUseLstat); }
bool CFile::IsFifo(bool bUseLstat) { return CFile::IsFifo(m_sLongName, bUseLstat); }
bool CFile::IsLnk(bool bUseLstat) { return CFile::IsLnk(m_sLongName, bUseLstat); }
bool CFile::IsSock(bool bUseLstat) { return CFile::IsSock(m_sLongName, bUseLstat); }
bool CFile::access(int mode) { return (::access(m_sLongName.c_str(), mode) == 0); }
// for gettin file types, using fstat instead
bool CFile::FType(const string sFileName, EFileTypes eType, bool bUseLstat) {
struct stat st;
if (!bUseLstat) {
if (stat(sFileName.c_str(), &st) != 0) {
return false;
}
} else {
if (lstat(sFileName.c_str(), &st) != 0) {
return false;
}
}
switch (eType) {
case FT_REGULAR:
return S_ISREG(st.st_mode);
case FT_DIRECTORY:
return S_ISDIR(st.st_mode);
case FT_CHARACTER:
return S_ISCHR(st.st_mode);
case FT_BLOCK:
return S_ISBLK(st.st_mode);
case FT_FIFO:
return S_ISFIFO(st.st_mode);
case FT_LINK:
return S_ISLNK(st.st_mode);
case FT_SOCK:
return S_ISSOCK(st.st_mode);
default:
return false;
}
return false;
}
//
// Functions to retrieve file information
//
bool CFile::Exists() const { return CFile::Exists(m_sLongName); }
unsigned long long CFile::GetSize() const { return CFile::GetSize(m_sLongName); }
unsigned int CFile::GetATime() const { return CFile::GetATime(m_sLongName); }
unsigned int CFile::GetMTime() const { return CFile::GetMTime(m_sLongName); }
unsigned int CFile::GetCTime() const { return CFile::GetCTime(m_sLongName); }
int CFile::GetUID() const { return CFile::GetUID(m_sLongName); }
int CFile::GetGID() const { return CFile::GetGID(m_sLongName); }
bool CFile::Exists(const string& sFile) {
struct stat st;
return (stat(sFile.c_str(), &st) == 0);
}
unsigned long long CFile::GetSize(const string& sFile) {
struct stat st;
if(stat(sFile.c_str(), &st) != 0) {
return 0;
}
return (S_ISREG(st.st_mode)) ? st.st_size : 0;
}
unsigned int CFile::GetATime(const string& sFile) {
struct stat st;
return (stat(sFile.c_str(), &st) != 0) ? 0 : st.st_atime;
}
unsigned int CFile::GetMTime(const string& sFile) {
struct stat st;
return (stat(sFile.c_str(), &st) != 0) ? 0 : st.st_mtime;
}
unsigned int CFile::GetCTime(const string& sFile) {
struct stat st;
return (stat(sFile.c_str(), &st) != 0) ? 0 : st.st_ctime;
}
int CFile::GetUID(const string& sFile) {
struct stat st;
return (stat(sFile.c_str(), &st) != 0) ? -1 : (int) st.st_uid;
}
int CFile::GetGID(const string& sFile) {
struct stat st;
return (stat(sFile.c_str(), &st) != 0) ? -1 : (int) st.st_gid;
}
int CFile::GetInfo(const string& sFile, struct stat& st) {
return stat(sFile.c_str(), &st);
}
//
// Functions to manipulate the file on the filesystem
//
int CFile::Delete() { return CFile::Delete(m_sLongName); }
int CFile::Move(const string& sNewFileName, bool bOverwrite) {
return CFile::Move(m_sLongName, sNewFileName, bOverwrite);
}
bool CFile::Delete(const string& sFileName) {
if(!CFile::Exists(sFileName)) {
return false;
}
return (unlink(sFileName.c_str()) == 0) ? true : false;
}
bool CFile::Move(const string& sOldFileName, const string& sNewFileName, bool bOverwrite) {
if((!bOverwrite) && (CFile::Exists(sNewFileName))) {
return false;
}
//string sNewLongName = (sNewFileName[0] == '/') ? sNewFileName : m_sPath + "/" + sNewFileName;
return (rename(sOldFileName.c_str(), sNewFileName.c_str()) == 0) ? true : false;
}
bool CFile::Chmod(mode_t mode) {
return CFile::Chmod(m_sLongName, mode);
}
bool CFile::Chmod(const string& sFile, mode_t mode) {
return (chmod(sFile.c_str(), mode) == 0);
}
bool CFile::Seek(unsigned long uPos) {
return (m_iFD == -1) ? false : ((unsigned int) lseek(m_iFD, uPos, SEEK_SET) == uPos);
}
bool CFile::Open(int iFlags, mode_t iMode) {
if (m_iFD != -1) {
return false;
}
m_iFD = open(m_sLongName.c_str(), iFlags, iMode);
return (m_iFD > -1);
}
int CFile::Read(char *pszBuffer, int iBytes) {
if (m_iFD == -1) {
return -1;
}
return read(m_iFD, pszBuffer, iBytes);
}
bool CFile::ReadLine(string & sData) {
char buff[64];
sData.clear();
if (m_iFD == -1) {
return false;
}
bool bEOF = false;
while(true) {
u_int iFind = m_sBuffer.find("\n");
if (iFind != string::npos) {
sData = m_sBuffer.substr(0, (iFind + 1));
m_sBuffer.erase(0, (iFind + 1));
break;
}
memset((char *)buff, '\0', 64);
int iBytes = read(m_iFD, buff, 64);
switch(iBytes) {
case -1: {
bEOF = true;
break;
}
case 0: {
bEOF = true;
break;
}
default: {
m_sBuffer.append(buff, iBytes);
break;
}
}
if (bEOF) {
break;
}
}
u_int iFind = m_sBuffer.find("\n");
if (iFind != string::npos) {
return true;
}
return !bEOF;
}
int CFile::Write(const char *pszBuffer, u_int iBytes) {
if (m_iFD == -1) {
return -1;
}
return write(m_iFD, pszBuffer, iBytes);
}
int CFile::Write(const string & sData) {
return Write(sData.data(), sData.size());
}
void CFile::Close() { close(m_iFD); m_iFD = -1; }
string CFile::GetLongName() const { return m_sLongName; }
string CFile::GetShortName() const { return m_sShortName; }
void CFile::SetFD(int iFD) { m_iFD = iFD; }
#ifdef HAVE_LIBSSL
CBlowfish::CBlowfish(const string & sPassword, int iEncrypt, const string & sIvec) {
m_iEncrypt = iEncrypt;
m_ivec = (unsigned char *)calloc(sizeof(unsigned char), 8);
m_num = 0;
if (sIvec.length() >= 8) {
memcpy(m_ivec, sIvec.data(), 8);
}
BF_set_key(&m_bkey, sPassword.length(), (unsigned char *)sPassword.data());
}
CBlowfish::~CBlowfish() {
free(m_ivec);
}
//! output must be freed
unsigned char *CBlowfish::MD5(const unsigned char *input, u_int ilen) {
unsigned char *output = (unsigned char *)malloc(MD5_DIGEST_LENGTH);
::MD5(input, ilen, output);
return output;
}
//! returns an md5 of the string (not hex encoded)
string CBlowfish::MD5(const string & sInput, bool bHexEncode) {
string sRet;
unsigned char *data = MD5((const unsigned char *)sInput.data(), sInput.length());
if (!bHexEncode) {
sRet.append((const char *)data, MD5_DIGEST_LENGTH);
} else {
for(int a = 0; a < MD5_DIGEST_LENGTH; a++) {
sRet += g_HexDigits[data[a] >> 4];
sRet += g_HexDigits[data[a] & 0xf];
}
}
free(data);
return sRet;
}
//! output must be the same size as input
void CBlowfish::Crypt(unsigned char *input, unsigned char *output, u_int ibytes) {
BF_cfb64_encrypt(input, output, ibytes, &m_bkey, m_ivec, &m_num, m_iEncrypt);
}
//! must free result
unsigned char * CBlowfish::Crypt(unsigned char *input, u_int ibytes) {
unsigned char *buff = (unsigned char *)malloc(ibytes);
Crypt(input, buff, ibytes);
return buff;
}
string CBlowfish::Crypt(const string & sData) {
unsigned char *buff = Crypt((unsigned char *)sData.data(), sData.length());
string sOutput;
sOutput.append((const char *)buff, sData.length());
free(buff);
return sOutput;
}
#endif // HAVE_LIBSSL
+291
View File
@@ -0,0 +1,291 @@
#ifndef _UTILS_H
#define _UTILS_H
#include <unistd.h>
#include <ctype.h>
#include <string>
#include <vector>
#include <map>
using std::string;
using std::vector;
using std::map;
#ifdef _DEBUG
#define DEBUG_ONLY(f) f
#else
#define DEBUG_ONLY(f) ((void)0)
#endif
static const char g_HexDigits[] = "0123456789abcdef";
class CUtils
{
public:
CUtils();
virtual ~CUtils();
static string GetIP(unsigned long addr);
static unsigned long GetLongIP(const string& sIP);
static string ChangeDir(const string& sPath, const string& sAdd, const string& sHomeDir);
static string ToString(short i);
static string ToString(unsigned short i);
static string ToString(int i);
static string ToString(unsigned int i);
static string ToString(long i);
static string ToString(unsigned long i);
static string ToString(unsigned long long i);
static string ToString(double i);
static string ToString(float i);
static string ToPercent(double d);
static string ToKBytes(double d);
static string Left(const string& s, unsigned int u);
static string Right(const string& s, unsigned int u);
static string& Trim(string& s);
static string& LeftChomp(string& s, unsigned int uLen = 1);
static string& RightChomp(string& s, unsigned int uLen = 1);
static string Token(const string& s, unsigned int uPos, bool bRest = false, char cSep = ' ');
static string Ellipsize(const string& s, unsigned int uLen);
static bool WildCmp(const string& sWild, const string& sString);
private:
protected:
};
class CTable : public vector<map<string, string>* > {
public:
CTable();
virtual ~CTable();
bool AddColumn(const string& sName);
unsigned int AddRow();
bool SetCell(const string& sColumn, const string& sValue, unsigned int uRowIdx = ~0);
bool GetLine(unsigned int uIdx, string& sLine);
unsigned int GetColumnWidth(unsigned int uIdx);
private:
protected:
vector<string> m_vsHeaders;
map<string, unsigned int> m_msuWidths; // Used to cache the width of a column
};
class CFile {
public:
CFile(const string& sLongName);
virtual ~CFile();
enum EFileTypes
{
FT_REGULAR,
FT_DIRECTORY,
FT_CHARACTER,
FT_BLOCK,
FT_FIFO,
FT_LINK,
FT_SOCK
};
static bool IsReg( const string& sLongName, bool bUseLstat = false );
static bool IsDir( const string& sLongName, bool bUseLstat = false );
static bool IsChr( const string& sLongName, bool bUseLstat = false );
static bool IsBlk( const string& sLongName, bool bUseLstat = false );
static bool IsFifo( const string& sLongName, bool bUseLstat = false );
static bool IsLnk( const string& sLongName, bool bUseLstat = true );
static bool IsSock( const string& sLongName, bool bUseLstat = false );
bool IsReg( bool bUseLstat = false );
bool IsDir( bool bUseLstat = false );
bool IsChr( bool bUseLstat = false );
bool IsBlk( bool bUseLstat = false );
bool IsFifo( bool bUseLstat = false );
bool IsLnk( bool bUseLstat = true );
bool IsSock( bool bUseLstat = false );
bool access( int mode );
// for gettin file types, using fstat instead
static bool FType( const string sFileName, EFileTypes eType, bool bUseLstat = false );
enum EFileAttr {
FA_Name,
FA_Size,
FA_ATime,
FA_MTime,
FA_CTime,
FA_UID
};
//
// Functions to retrieve file information
//
bool Exists() const;
unsigned long long GetSize() const;
unsigned int GetATime() const;
unsigned int GetMTime() const;
unsigned int GetCTime() const;
int GetUID() const;
int GetGID() const;
static bool Exists(const string& sFile);
static unsigned long long GetSize(const string& sFile);
static unsigned int GetATime(const string& sFile);
static unsigned int GetMTime(const string& sFile);
static unsigned int GetCTime(const string& sFile);
static int GetUID(const string& sFile);
static int GetGID(const string& sFile);
static int GetInfo(const string& sFile, struct stat& st);
//
// Functions to manipulate the file on the filesystem
//
int Delete();
int Move(const string& sNewFileName, bool bOverwrite = false);
static bool Delete(const string& sFileName);
static bool Move(const string& sOldFileName, const string& sNewFileName, bool bOverwrite = false);
bool Chmod(mode_t mode);
static bool Chmod(const string& sFile, mode_t mode);
bool Seek(unsigned long uPos);
bool Open( int iFlags, mode_t iMode = 0644 );
int Read( char *pszBuffer, int iBytes );
bool ReadLine( string & sData );
int Write( const char *pszBuffer, u_int iBytes );
int Write( const string & sData );
void Close();
string GetLongName() const;
string GetShortName() const;
void SetFD( int iFD );
private:
string m_sBuffer;
int m_iFD;
protected:
string m_sLongName; //!< Absolute filename (m_sPath + "/" + m_sShortName)
string m_sShortName; //!< Filename alone, without path
};
#ifdef HAVE_LIBSSL
#include <openssl/blowfish.h>
#include <openssl/md5.h>
//! does Blowfish w/64 bit feedback, no padding
class CBlowfish
{
public:
/**
* @sPassword key to encrypt with
* @iEncrypt encrypt method (BF_DECRYPT or BF_ENCRYPT)
* @sIvec what to set the ivector to start with, default sets it all 0's
*/
CBlowfish(const string & sPassword, int iEncrypt, const string & sIvec = "");
~CBlowfish();
//! output must be freed
static unsigned char *MD5(const unsigned char *input, u_int ilen);
//! returns an md5 of the string ( not hex encoded )
static string MD5(const string & sInput, bool bHexEncode = false);
//! output must be the same size as input
void Crypt(unsigned char *input, unsigned char *output, u_int ibytes);
//! must free result
unsigned char * Crypt(unsigned char *input, u_int ibytes);
string Crypt(const string & sData);
private:
unsigned char *m_ivec;
BF_KEY m_bkey;
int m_iEncrypt, m_num;
};
#endif /* HAVE_LIBSSL */
#define RF_BUFF 4096
inline bool ReadFile(const string & sFilename, string & sLine) {
char inbuff[RF_BUFF];
int bytes;
// clear ourselves out
sLine.clear();
FILE *f = fopen(sFilename.c_str(), "r");
if (!f) {
return false;
}
while((bytes = fread(inbuff, sizeof(char), RF_BUFF, f)) > 0) {
sLine.append(inbuff, bytes);
}
fclose(f);
if (bytes < 0) {
return false;
}
return true;
}
inline bool WriteFile(const string & sFilename, const string & sData) {
FILE *f = fopen(sFilename.c_str(), "w");
if (!f) {
return false;
}
int iRet = fwrite(sData.data(), sizeof(char), sData.length(), f);
fclose(f);
if (iRet <= 0) {
return false;
}
return true;
}
inline bool ReadLine(const string & sData, string & sLine, u_int & iPos) {
sLine.clear();
if (iPos >= sData.length()) {
return false;
}
u_int iFind = sData.find("\n", iPos);
if (iFind == string::npos) {
sLine = sData.substr(iPos, (sData.length() - iPos));
iPos = string::npos;
return true;
}
sLine = sData.substr(iPos, (iFind - iPos)) + "\n";
iPos = iFind + 1;
return true;
}
inline string Lower(const string & sLine) {
string sRet;
for(u_int a = 0; a < sLine.length(); a++) {
sRet += tolower(sLine[a]);
}
return sRet;
}
inline string Upper(const string & sLine) {
string sRet;
for(u_int a = 0; a < sLine.length(); a++) {
sRet += toupper(sLine[a]);
}
return sRet;
}
#endif // !_UTILS_H
+92
View File
@@ -0,0 +1,92 @@
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include "znc.h"
#include "md5.h"
void die(int sig) {
signal( SIGSEGV, SIG_DFL );
signal( SIGABRT, SIG_DFL );
signal( SIGPIPE, SIG_DFL );
delete CZNC::New();
exit(sig);
}
int main(int argc, char** argv) {
string sConfig = "znc.conf";
if (argc > 1) {
if ((argc > 2) || (strcasecmp(argv[1], "--help") == 0) || (strcasecmp(argv[1], "-h") == 0)) {
cerr << "Usage: " << argv[0] << " [--makepass|--help|znc.conf]" << endl;
return 1;
}
if (strcasecmp(argv[1], "--makepass") == 0) {
char* pass = getpass( "Enter Password: " );
int iLen = strlen(pass);
cout << "Use this in the <User> section of your config:" << endl << endl << "Pass = " << CMD5(pass, iLen) << " -" << endl << endl;
memset((char*) pass, 0, iLen); // Null out our pass so it doesn't sit in memory
return 0;
} else {
sConfig = argv[1];
}
}
CZNC* pZNC = CZNC::New();
pZNC->InitDirs(((argc) ? argv[0] : ""));
if (!pZNC->ParseConfig(sConfig)) {
cerr << endl << "*** Unrecoverable error while parsing [" << sConfig << "]" << endl;
delete pZNC;
return 1;
}
if (!pZNC->GetListenPort()) {
cerr << "You must supply a ListenPort in your config." << endl;
delete pZNC;
return 1;
}
if (!pZNC->OnBoot()) {
cerr << "Exiting due to module boot errors." << endl;
delete pZNC;
return 1;
}
#ifndef _DEBUG
int iPid = fork();
if (iPid == -1) {
cerr << "Failed to fork into background: [" << strerror(errno) << "]" << endl;
delete pZNC;
exit(1);
}
if (iPid > 0) {
cout << "ZNC - by prozac [port: " << ((pZNC->IsSSL()) ? "+" : "") << pZNC->GetListenPort() << "] [pid: " << iPid << "]" << endl;
pZNC->WritePidFile(iPid);
exit(0);
}
#endif
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, (struct sigaction *)NULL);
sa.sa_handler = die;
sigaction(SIGINT, &sa, (struct sigaction *)NULL);
sigaction(SIGILL, &sa, (struct sigaction *)NULL);
sigaction(SIGQUIT, &sa, (struct sigaction *)NULL);
sigaction(SIGBUS, &sa, (struct sigaction *)NULL);
sigaction(SIGSEGV, &sa, (struct sigaction *)NULL);
sigaction(SIGTERM, &sa, (struct sigaction *)NULL);
int iRet = pZNC->Loop();
delete pZNC;
return iRet;
}
+17
View File
@@ -0,0 +1,17 @@
#ifndef _MAIN_H
#define _MAIN_H
#ifndef CS_STRING
#define CS_STRING string
#endif
#ifndef _NO_CSOCKET_NS
#define _NO_CSOCKET_NS
#endif
#include <string>
using std::string;
#include "Csocket.h"
#endif // !_MAIN_H
+283
View File
@@ -0,0 +1,283 @@
/*
* RFC 1321 compliant MD5 implementation
*
* Copyright (C) 2001-2003 Christophe Devine
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <string.h>
#include "md5.h"
CMD5::CMD5()
{
*m_szMD5 = '\0';
}
CMD5::CMD5(const string& sText)
{
MakeHash(sText.c_str(), sText.length());
}
CMD5::CMD5(const char* szText, uint32 nTextLen)
{
MakeHash(szText, nTextLen);
}
CMD5::~CMD5()
{
}
#define GET_UINT32(n,b,i) \
{ \
(n) = ( (uint32) (b)[(i) ] ) \
| ( (uint32) (b)[(i) + 1] << 8 ) \
| ( (uint32) (b)[(i) + 2] << 16 ) \
| ( (uint32) (b)[(i) + 3] << 24 ); \
}
#define PUT_UINT32(n,b,i) \
{ \
(b)[(i) ] = (uint8) ( (n) ); \
(b)[(i) + 1] = (uint8) ( (n) >> 8 ); \
(b)[(i) + 2] = (uint8) ( (n) >> 16 ); \
(b)[(i) + 3] = (uint8) ( (n) >> 24 ); \
}
void CMD5::md5_starts( md5_context *ctx ) const
{
ctx->total[0] = 0;
ctx->total[1] = 0;
ctx->state[0] = 0x67452301;
ctx->state[1] = 0xEFCDAB89;
ctx->state[2] = 0x98BADCFE;
ctx->state[3] = 0x10325476;
}
void CMD5::md5_process( md5_context *ctx, uint8 data[64] ) const
{
uint32 X[16], A, B, C, D;
GET_UINT32( X[0], data, 0 );
GET_UINT32( X[1], data, 4 );
GET_UINT32( X[2], data, 8 );
GET_UINT32( X[3], data, 12 );
GET_UINT32( X[4], data, 16 );
GET_UINT32( X[5], data, 20 );
GET_UINT32( X[6], data, 24 );
GET_UINT32( X[7], data, 28 );
GET_UINT32( X[8], data, 32 );
GET_UINT32( X[9], data, 36 );
GET_UINT32( X[10], data, 40 );
GET_UINT32( X[11], data, 44 );
GET_UINT32( X[12], data, 48 );
GET_UINT32( X[13], data, 52 );
GET_UINT32( X[14], data, 56 );
GET_UINT32( X[15], data, 60 );
#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
#define P(a,b,c,d,k,s,t) \
{ \
a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \
}
A = ctx->state[0];
B = ctx->state[1];
C = ctx->state[2];
D = ctx->state[3];
#define F(x,y,z) (z ^ (x & (y ^ z)))
P( A, B, C, D, 0, 7, 0xD76AA478 );
P( D, A, B, C, 1, 12, 0xE8C7B756 );
P( C, D, A, B, 2, 17, 0x242070DB );
P( B, C, D, A, 3, 22, 0xC1BDCEEE );
P( A, B, C, D, 4, 7, 0xF57C0FAF );
P( D, A, B, C, 5, 12, 0x4787C62A );
P( C, D, A, B, 6, 17, 0xA8304613 );
P( B, C, D, A, 7, 22, 0xFD469501 );
P( A, B, C, D, 8, 7, 0x698098D8 );
P( D, A, B, C, 9, 12, 0x8B44F7AF );
P( C, D, A, B, 10, 17, 0xFFFF5BB1 );
P( B, C, D, A, 11, 22, 0x895CD7BE );
P( A, B, C, D, 12, 7, 0x6B901122 );
P( D, A, B, C, 13, 12, 0xFD987193 );
P( C, D, A, B, 14, 17, 0xA679438E );
P( B, C, D, A, 15, 22, 0x49B40821 );
#undef F
#define F(x,y,z) (y ^ (z & (x ^ y)))
P( A, B, C, D, 1, 5, 0xF61E2562 );
P( D, A, B, C, 6, 9, 0xC040B340 );
P( C, D, A, B, 11, 14, 0x265E5A51 );
P( B, C, D, A, 0, 20, 0xE9B6C7AA );
P( A, B, C, D, 5, 5, 0xD62F105D );
P( D, A, B, C, 10, 9, 0x02441453 );
P( C, D, A, B, 15, 14, 0xD8A1E681 );
P( B, C, D, A, 4, 20, 0xE7D3FBC8 );
P( A, B, C, D, 9, 5, 0x21E1CDE6 );
P( D, A, B, C, 14, 9, 0xC33707D6 );
P( C, D, A, B, 3, 14, 0xF4D50D87 );
P( B, C, D, A, 8, 20, 0x455A14ED );
P( A, B, C, D, 13, 5, 0xA9E3E905 );
P( D, A, B, C, 2, 9, 0xFCEFA3F8 );
P( C, D, A, B, 7, 14, 0x676F02D9 );
P( B, C, D, A, 12, 20, 0x8D2A4C8A );
#undef F
#define F(x,y,z) (x ^ y ^ z)
P( A, B, C, D, 5, 4, 0xFFFA3942 );
P( D, A, B, C, 8, 11, 0x8771F681 );
P( C, D, A, B, 11, 16, 0x6D9D6122 );
P( B, C, D, A, 14, 23, 0xFDE5380C );
P( A, B, C, D, 1, 4, 0xA4BEEA44 );
P( D, A, B, C, 4, 11, 0x4BDECFA9 );
P( C, D, A, B, 7, 16, 0xF6BB4B60 );
P( B, C, D, A, 10, 23, 0xBEBFBC70 );
P( A, B, C, D, 13, 4, 0x289B7EC6 );
P( D, A, B, C, 0, 11, 0xEAA127FA );
P( C, D, A, B, 3, 16, 0xD4EF3085 );
P( B, C, D, A, 6, 23, 0x04881D05 );
P( A, B, C, D, 9, 4, 0xD9D4D039 );
P( D, A, B, C, 12, 11, 0xE6DB99E5 );
P( C, D, A, B, 15, 16, 0x1FA27CF8 );
P( B, C, D, A, 2, 23, 0xC4AC5665 );
#undef F
#define F(x,y,z) (y ^ (x | ~z))
P( A, B, C, D, 0, 6, 0xF4292244 );
P( D, A, B, C, 7, 10, 0x432AFF97 );
P( C, D, A, B, 14, 15, 0xAB9423A7 );
P( B, C, D, A, 5, 21, 0xFC93A039 );
P( A, B, C, D, 12, 6, 0x655B59C3 );
P( D, A, B, C, 3, 10, 0x8F0CCC92 );
P( C, D, A, B, 10, 15, 0xFFEFF47D );
P( B, C, D, A, 1, 21, 0x85845DD1 );
P( A, B, C, D, 8, 6, 0x6FA87E4F );
P( D, A, B, C, 15, 10, 0xFE2CE6E0 );
P( C, D, A, B, 6, 15, 0xA3014314 );
P( B, C, D, A, 13, 21, 0x4E0811A1 );
P( A, B, C, D, 4, 6, 0xF7537E82 );
P( D, A, B, C, 11, 10, 0xBD3AF235 );
P( C, D, A, B, 2, 15, 0x2AD7D2BB );
P( B, C, D, A, 9, 21, 0xEB86D391 );
#undef F
ctx->state[0] += A;
ctx->state[1] += B;
ctx->state[2] += C;
ctx->state[3] += D;
}
void CMD5::md5_update( md5_context *ctx, uint8 *input, uint32 length ) const
{
uint32 left, fill;
if( ! length ) return;
left = ctx->total[0] & 0x3F;
fill = 64 - left;
ctx->total[0] += length;
ctx->total[0] &= 0xFFFFFFFF;
if( ctx->total[0] < length )
ctx->total[1]++;
if( left && length >= fill )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, fill );
md5_process( ctx, ctx->buffer );
length -= fill;
input += fill;
left = 0;
}
while( length >= 64 )
{
md5_process( ctx, input );
length -= 64;
input += 64;
}
if( length )
{
memcpy( (void *) (ctx->buffer + left),
(void *) input, length );
}
}
static uint8 md5_padding[64] =
{
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
void CMD5::md5_finish( md5_context *ctx, uint8 digest[16] ) const
{
uint32 last, padn;
uint32 high, low;
uint8 msglen[8];
high = ( ctx->total[0] >> 29 )
| ( ctx->total[1] << 3 );
low = ( ctx->total[0] << 3 );
PUT_UINT32( low, msglen, 0 );
PUT_UINT32( high, msglen, 4 );
last = ctx->total[0] & 0x3F;
padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
md5_update( ctx, md5_padding, padn );
md5_update( ctx, msglen, 8 );
PUT_UINT32( ctx->state[0], digest, 0 );
PUT_UINT32( ctx->state[1], digest, 4 );
PUT_UINT32( ctx->state[2], digest, 8 );
PUT_UINT32( ctx->state[3], digest, 12 );
}
char* CMD5::MakeHash(const char* szText, uint32 nTextLen)
{
md5_context ctx;
unsigned char md5sum[16];
unsigned short i;
md5_starts(&ctx);
md5_update(&ctx, (uint8*)szText, nTextLen);
md5_finish(&ctx, md5sum);
for (i = 0; i < 16; i++)
{
sprintf(m_szMD5 + i * 2, "%02x", md5sum[i]);
}
return(m_szMD5);
}
+56
View File
@@ -0,0 +1,56 @@
/* C implementation by Christophe Devine, C++ "class-ified" by [T3] */
#include <string>
using std::string;
#ifndef _MD5_H
#define _MD5_H
#ifndef uint8
#define uint8 unsigned char
#endif
#ifndef uint32
#define uint32 unsigned long int
#endif
typedef struct
{
uint32 total[2];
uint32 state[4];
uint8 buffer[64];
}
md5_context;
class CMD5 {
protected:
char m_szMD5[33];
public:
CMD5();
CMD5(const string& sText);
CMD5(const char* szText, uint32 nTextLen);
virtual ~CMD5();
operator string() const
{
return (string) m_szMD5;
}
operator char*() const
{
return (char*)m_szMD5;
}
char* MakeHash(const char* szText, uint32 nTextLen);
protected:
void md5_starts( md5_context *ctx ) const;
void md5_update( md5_context *ctx, uint8 *input, uint32 length ) const;
void md5_finish( md5_context *ctx, uint8 digest[16] ) const;
private:
void md5_process( md5_context *ctx, uint8 data[64] ) const;
};
#endif /* _MD5_H */
+45
View File
@@ -0,0 +1,45 @@
#!/bin/sh
CXXFLAGS="-Wall -D_GNU_SOURCE -DHAVE_LIBSSL -I.."
LIBS="-lssl"
if test -z "$1"; then
echo "Usage: $0 <module> [...]"
exit 1
fi
for arg in "$@"
do
if test -d $arg; then
(cd $arg && make || exit 1)
elif test -f "$arg"; then
FILE="$arg"
MOD="${FILE%.cpp}"
MOD="${MOD%.cc}"
elif test -f "$arg.cpp"; then
FILE="$arg.cpp"
MOD="$arg"
elif test -f "$arg.cc"; then
FILE="$arg.cc"
MOD="$arg"
fi
rm -f "$MOD.so"
if test -n "$FILE"; then
COMMAND="g++ $CXXFLAGS -c $FILE"
echo $COMMAND
$COMMAND || exit 1
COMMAND="g++ $CXXFLAGS -shared -o $MOD.so $MOD.o $LIBS"
echo $COMMAND
$COMMAND || exit 1
fi
if ! test -f "$MOD.so"; then
echo "Failed to build $MOD.so!"
exit 1
else
echo "Built $MOD.so"
fi
done
exit 0
+269
View File
@@ -0,0 +1,269 @@
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "Utils.h"
#include "md5.h"
#include <pwd.h>
#include <sstream>
/*
* Email Monitor / Retrieval
* Author: imaginos <imaginos@imaginos.net>
*
* $Log$
* Revision 1.1 2004/08/24 00:08:52 prozacx
* Initial revision
*
*
*/
struct EmailST
{
string sFrom;
string sSubject;
string sUidl;
u_int iSize;
};
class CEmailJob : public CTimer
{
public:
CEmailJob( CModule* pModule, unsigned int uInterval, unsigned int uCycles, const string& sLabel, const string& sDescription )
: CTimer( pModule, uInterval, uCycles, sLabel, sDescription) {}
virtual ~CEmailJob() {}
protected:
virtual void RunJob();
};
class CEmail : public CModule
{
public:
MODCONSTRUCTOR(CEmail)
{
m_iLastCheck = 0;
m_bInitialized = false;
}
virtual ~CEmail()
{
vector<Csock*> vSocks = m_pManager->FindSocksByName( "EMAIL::" + m_pUser->GetUserName() );
for( u_int a = 0; a < vSocks.size(); a++ )
m_pManager->DelSockByAddr( vSocks[a] );
}
virtual bool OnLoad(const string & sArgs) {
m_sMailPath = sArgs;
StartParser();
if ( m_pUser->IsUserAttached() )
StartTimer();
return true;
}
virtual void OnUserAttached()
{
stringstream s;
s << "You have " << m_ssUidls.size() << " emails.";
PutModule( s.str() );
StartTimer();
}
virtual void OnUserDetached()
{
RemTimer( "EMAIL::" + m_pUser->GetUserName() );
}
void StartTimer()
{
if ( !FindTimer( "EMAIL::" + m_pUser->GetUserName() ) )
{
CEmailJob *p = new CEmailJob( this, 60, 0, "EmailMonitor", "Monitors email activity" );
AddTimer( p );
}
}
virtual string GetDescription()
{
return ( "Monitors Email activity on local disk /var/mail/user" );
}
virtual void OnModCommand( const string& sCommand );
void StartParser();
void ParseEmails( const vector<EmailST> & vEmails )
{
if ( !m_bInitialized )
{
m_bInitialized = true;
for( u_int a = 0; a < vEmails.size(); a++ )
m_ssUidls.insert( vEmails[a].sUidl );
stringstream s;
s << "You have " << vEmails.size() << " emails.";
PutModule( s.str() );
} else
{
set<string> ssUidls;
CTable Table;
Table.AddColumn("From");
Table.AddColumn("Size");
Table.AddColumn("Subject");
for( u_int a = 0; a < vEmails.size(); a++ )
{
if ( m_ssUidls.find( vEmails[a].sUidl ) == m_ssUidls.end() )
{
//PutModule( "------------------- New Email -------------------" );
Table.AddRow();
Table.SetCell( "From", CUtils::Ellipsize( vEmails[a].sFrom, 32 ) );
Table.SetCell( "Size", CUtils::ToString( vEmails[a].iSize ) );
Table.SetCell( "Subject", CUtils::Ellipsize( vEmails[a].sSubject, 64 ) );
}
ssUidls.insert( vEmails[a].sUidl );
}
m_ssUidls = ssUidls; // keep the list in synch
if (Table.size()) {
unsigned int uTableIdx = 0;
string sLine;
while ( Table.GetLine( uTableIdx++, sLine ) ) {
PutModule( sLine );
}
stringstream s;
s << "You have " << vEmails.size() << " emails.";
PutModule( s.str() );
}
}
}
private:
string m_sMailPath;
u_int m_iLastCheck;
set<string> m_ssUidls;
bool m_bInitialized;
};
class CEmailFolder : public Csock
{
public:
CEmailFolder( CEmail *pModule, const string & sMailbox ) : Csock()
{
m_pModule = pModule;
m_sMailbox = sMailbox;
EnableReadLine();
}
virtual ~CEmailFolder()
{
if ( !m_sMailBuffer.empty() )
ProcessMail(); // get the last one
if ( !m_vEmails.empty() )
m_pModule->ParseEmails( m_vEmails );
}
virtual void ReadLine( const CS_STRING & sLine )
{
if ( sLine.substr( 0, 5 ) == "From " )
{
if ( !m_sMailBuffer.empty() )
{
ProcessMail();
m_sMailBuffer.clear();
}
}
m_sMailBuffer += sLine;
}
void ProcessMail()
{
EmailST tmp;
tmp.sUidl = (char *)CMD5( m_sMailBuffer.substr( 0, 255 ) );
string sLine;
u_int iPos = 0;
while( ::ReadLine( m_sMailBuffer, sLine, iPos ) )
{
CUtils::Trim( sLine );
if ( sLine.empty() )
break; // out of the headers
if ( strncasecmp( sLine.c_str(), "From: ", 6 ) == 0 )
tmp.sFrom = sLine.substr( 6, string::npos );
else if ( strncasecmp( sLine.c_str(), "Subject: ", 9 ) == 0 )
tmp.sSubject = sLine.substr( 9, string::npos );
if ( ( !tmp.sFrom.empty() ) && ( !tmp.sSubject.empty() ) )
break;
}
tmp.iSize = m_sMailBuffer.length();
m_vEmails.push_back( tmp );
}
private:
CEmail *m_pModule;
string m_sMailbox;
string m_sMailBuffer;
vector<EmailST> m_vEmails;
};
void CEmail::OnModCommand( const string& sCommand )
{
u_int iPos = sCommand.find( " " );
string sCom, sArgs;
if ( iPos == string::npos )
sCom = sCommand;
else
{
sCom = sCommand.substr( 0, iPos );
sArgs = sCommand.substr( iPos + 1, string::npos );
}
if ( sCom == "timers" )
{
ListTimers();
} else
PutModule( "Error, no such command [" + sCom + "]" );
}
void CEmail::StartParser()
{
string sParserName = "EMAIL::" + m_pUser->GetUserName();
if ( m_pManager->FindSockByName( sParserName ) )
return; // one at a time sucker
CFile cFile( m_sMailPath );
if ( ( !cFile.Exists() ) || ( cFile.GetSize() == 0 ) )
{
m_bInitialized = true;
return; // der
}
if ( cFile.GetMTime() <= m_iLastCheck )
return; // only check if modified
int iFD = open( m_sMailPath.c_str(), O_RDONLY );
if ( iFD >= 0 )
{
m_iLastCheck = time( NULL );
CEmailFolder *p = new CEmailFolder( this, m_sMailPath );
p->SetRSock( iFD );
p->SetWSock( iFD );
m_pManager->AddSock( (Csock *)p, "EMAIL::" + m_pUser->GetUserName() );
}
}
void CEmailJob::RunJob()
{
CEmail *p = (CEmail *)m_pModule;
p->StartParser();
}
MODULEDEFS(CEmail)
+28
View File
@@ -0,0 +1,28 @@
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
class CRawMod : public CModule {
public:
MODCONSTRUCTOR(CRawMod) {}
virtual ~CRawMod() {}
virtual string GetDescription() {
return "View all of the raw traffic.";
}
virtual bool OnRaw(string& sLine) {
PutModule("IRC -> [" + sLine + "]");
return false;
}
virtual bool OnUserRaw(string& sLine) {
PutModule("YOU -> [" + sLine + "]");
return false;
}
};
MODULEDEFS(CRawMod)
+198
View File
@@ -0,0 +1,198 @@
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
class CSampleTimer : public CTimer {
public:
CSampleTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const string& sLabel, const string& sDescription) : CTimer(pModule, uInterval, uCycles, sLabel, sDescription) {}
virtual ~CSampleTimer() {}
private:
protected:
virtual void RunJob() {
m_pModule->PutModule("TEST!!!!");
}
};
class CSampleMod : public CModule {
public:
MODCONSTRUCTOR(CSampleMod) {}
virtual bool OnLoad(const string& sArgs) {
PutModule("I'm being loaded with the arguments: [" + sArgs + "]");
//AddTimer(new CSampleTimer(this, 300, 0, "Sample", "Sample timer for sample things."));
//AddTimer(new CSampleTimer(this, 5, 20, "Another", "Another sample timer."));
//AddTimer(new CSampleTimer(this, 25000, 5, "Third", "A third sample timer."));
return true;
}
virtual ~CSampleMod() {
PutModule("I'm being unloaded!");
}
virtual bool OnBoot() {
// This is called when the app starts up (only modules that are loaded in the config will get this event)
return true;
}
virtual string GetDescription() {
return "To be used as a sample for writing modules.";
}
virtual void OnIRCConnected() {
PutModule("You got connected BoyOh.");
}
virtual void OnIRCDisconnected() {
PutModule("You got disconnected BoyOh.");
}
virtual void OnOp(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
PutModule(((bNoChange) ? "[0] " : "[1] [") + OpNick.GetNick() + "] opped [" + Nick.GetNick() + "] on [" + Channel.GetName() + "]");
}
virtual void OnDeop(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
PutModule(((bNoChange) ? "[0] " : "[1] [") + OpNick.GetNick() + "] deopped [" + Nick.GetNick() + "] on [" + Channel.GetName() + "]");
}
virtual void OnVoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
PutModule(((bNoChange) ? "[0] " : "[1] [") + OpNick.GetNick() + "] voiced [" + Nick.GetNick() + "] on [" + Channel.GetName() + "]");
}
virtual void OnDevoice(const CNick& OpNick, const CNick& Nick, const CChan& Channel, bool bNoChange) {
PutModule(((bNoChange) ? "[0] " : "[1] [") + OpNick.GetNick() + "] devoiced [" + Nick.GetNick() + "] on [" + Channel.GetName() + "]");
}
virtual void OnRawMode(const CNick& OpNick, const CChan& Channel, const string& sModes, const string& sArgs) {
PutModule("* " + OpNick.GetNick() + " sets mode: " + sModes + " " + sArgs + " (" + Channel.GetName() + ")");
}
virtual bool OnRaw(string& sLine) {
// PutModule("OnRaw() [" + sLine + "]");
return false;
}
virtual bool OnUserRaw(string& sLine) {
// PutModule("UserRaw() [" + sLine + "]");
return false;
}
virtual void OnKick(const CNick& OpNick, const string& sKickedNick, const CChan& Channel, const string& sMessage) {
PutModule("[" + OpNick.GetNick() + "] kicked [" + sKickedNick + "] from [" + Channel.GetName() + "] with the msg [" + sMessage + "]");
}
virtual void OnQuit(const CNick& Nick, const string& sMessage) {
PutModule("* Quits: " + Nick.GetNick() + " (" + Nick.GetIdent() + "!" + Nick.GetHost() + ") (" + sMessage + ")");
}
virtual void OnJoin(const CNick& Nick, const CChan& Channel) {
PutModule("* Joins: " + Nick.GetNick() + " (" + Nick.GetIdent() + "!" + Nick.GetHost() + ")");
}
virtual void OnPart(const CNick& Nick, const CChan& Channel) {
PutModule("* Parts: " + Nick.GetNick() + " (" + Nick.GetIdent() + "!" + Nick.GetHost() + ")");
}
virtual void OnNick(const CNick& OldNick, const string& sNewNick) {
PutModule("* " + OldNick.GetNick() + " is now known as " + sNewNick);
}
virtual bool OnUserCTCPReply(const CNick& Nick, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] userctcpreply [" + sMessage + "]");
sMessage = "\037" + sMessage + "\037";
return false;
}
virtual bool OnCTCPReply(const CNick& Nick, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] ctcpreply [" + sMessage + "]");
return false;
}
virtual bool OnUserCTCP(const string& sTarget, string& sMessage) {
PutModule("[" + sTarget + "] userctcp [" + sMessage + "]");
return false;
}
virtual bool OnPrivCTCP(const CNick& Nick, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] privctcp [" + sMessage + "]");
sMessage = "\002" + sMessage + "\002";
return false;
}
virtual bool OnChanCTCP(const CNick& Nick, const CChan& Channel, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] chanctcp [" + sMessage + "] to [" + Channel.GetName() + "]");
sMessage = "\00311,5 " + sMessage + " \003";
return false;
}
virtual bool OnUserNotice(const string& sTarget, string& sMessage) {
PutModule("[" + sTarget + "] usernotice [" + sMessage + "]");
sMessage = "\037" + sMessage + "\037";
return false;
}
virtual bool OnPrivNotice(const CNick& Nick, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] privnotice [" + sMessage + "]");
sMessage = "\002" + sMessage + "\002";
return false;
}
virtual bool OnChanNotice(const CNick& Nick, const CChan& Channel, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] channotice [" + sMessage + "] to [" + Channel.GetName() + "]");
sMessage = "\00311,5 " + sMessage + " \003";
return false;
}
virtual bool OnUserMsg(const string& sTarget, string& sMessage) {
PutModule("[" + sTarget + "] usermsg [" + sMessage + "]");
sMessage = "\0034" + sMessage + "\003";
return false;
}
virtual bool OnPrivMsg(const CNick& Nick, string& sMessage) {
PutModule("[" + Nick.GetNick() + "] privmsg [" + sMessage + "]");
sMessage = "\002" + sMessage + "\002";
return false;
}
virtual bool OnChanMsg(const CNick& Nick, const CChan& Channel, string& sMessage) {
if (sMessage == "!ping") {
PutIRC("PRIVMSG " + Channel.GetName() + " :PONG?");
}
sMessage = "x " + sMessage + " x";
return false;
}
virtual void OnModCommand(const string& sCommand) {
if (strcasecmp(sCommand.c_str(), "TIMERS") == 0) {
ListTimers();
}
}
virtual bool OnStatusCommand(const string& sCommand) {
if (strcasecmp(sCommand.c_str(), "SAMPLE") == 0) {
PutModule("Hi, I'm your friendly sample module.");
return true;
}
return false;
}
};
MODULEDEFS(CSampleMod)
+211
View File
@@ -0,0 +1,211 @@
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "Utils.h"
#include <pwd.h>
#ifndef HAVE_LIBSSL
#error This plugin only works with OpenSSL
#endif /* HAVE_LIBSSL */
#define CRYPT_VERIFICATION_TOKEN "::__:SAVEBUFF:__::"
/*
* Buffer Saving thing, incase your shit goes out while your out
* Author: imaginos <imaginos@imaginos.net>
*
* Its only as secure as your shell, the encryption only offers a slightly
* better solution then plain text.
*
* $Log$
* Revision 1.1 2004/08/24 00:08:52 prozacx
* Initial revision
*
*
*/
class CSaveBuff;
class CSaveBuffJob : public CTimer
{
public:
CSaveBuffJob( CModule* pModule, unsigned int uInterval, unsigned int uCycles, const string& sLabel, const string& sDescription )
: CTimer( pModule, uInterval, uCycles, sLabel, sDescription) {}
virtual ~CSaveBuffJob() {}
protected:
virtual void RunJob();
};
class CSaveBuff : public CModule
{
public:
MODCONSTRUCTOR(CSaveBuff)
{
// m_sPassword = CBlowfish::MD5( "" );
AddTimer( new CSaveBuffJob( this, 60, 0, "SaveBuff", "Saves the current buffer to disk every 1 minute" ) );
}
virtual ~CSaveBuff()
{
SaveBufferToDisk();
}
virtual bool OnBoot()
{
if ( m_sPassword.empty() )
{
char *pTmp = getpass( "Enter Encryption Key for savebuff.so: " );
if ( pTmp )
m_sPassword = CBlowfish::MD5( pTmp );
*pTmp = 0;
}
const vector<CChan *>& vChans = m_pUser->GetChans();
for( u_int a = 0; a < vChans.size(); a++ )
{
string sFile;
string sPath = GetPath( vChans[a]->GetName() );
if ( ( sPath.empty() ) || ( !ReadFile( sPath, sFile ) ) )
continue;
if ( !sFile.empty() )
{
CBlowfish c( m_sPassword, BF_DECRYPT );
sFile = c.Crypt( sFile );
if ( sFile.substr( 0, strlen( CRYPT_VERIFICATION_TOKEN ) ) != CRYPT_VERIFICATION_TOKEN )
{
// failed to decode :(
cerr << "Unable to decode Encrypted file [" << sPath << "]" << endl;
continue;
}
sFile.erase( 0, strlen( CRYPT_VERIFICATION_TOKEN ) );
string sLine;
u_int iPos = 0;
while( ReadLine( sFile, sLine, iPos ) )
{
CUtils::Trim( sLine );
vChans[a]->AddBuffer( sLine );
}
}
}
return true;
}
void SaveBufferToDisk()
{
if ( !m_sPassword.empty() )
{
const vector<CChan *>& vChans = m_pUser->GetChans();
for( u_int a = 0; a < vChans.size(); a++ )
{
const vector<string> & vBuffer = vChans[a]->GetBuffer();
if ( vBuffer.empty() )
continue;
string sFile = CRYPT_VERIFICATION_TOKEN;
for( u_int b = 0; b < vBuffer.size(); b++ )
sFile += vBuffer[b] + "\n";
CBlowfish c( m_sPassword, BF_ENCRYPT );
sFile = c.Crypt( sFile );
string sPath = GetPath( vChans[a]->GetName() );
if ( !sPath.empty() )
{
WriteFile( sPath, sFile );
chmod( sPath.c_str(), 0600 );
}
}
}
}
virtual string GetDescription()
{
return ( "Stores channel buffers to disk, encrypted." );
}
virtual void OnModCommand( const string& sCommand )
{
u_int iPos = sCommand.find( " " );
string sCom, sArgs;
if ( iPos == string::npos )
sCom = sCommand;
else
{
sCom = sCommand.substr( 0, iPos );
sArgs = sCommand.substr( iPos + 1, string::npos );
}
if ( strcasecmp( sCom.c_str(), "setpass" ) == 0 )
{
PutModule( "Password set to [" + sArgs + "]" );
m_sPassword = CBlowfish::MD5( sArgs );
} else if ( strcasecmp( sCom.c_str(), "dumpbuff" ) == 0 )
{
string sChannel = GetPath( sArgs );
string sFile;
if ( ( sChannel.empty() ) || ( !ReadFile( sChannel, sFile ) ) )
{
PutModule( "Unable to find buffer for that channel" );
return;
}
if ( !sFile.empty() )
{
CBlowfish c( m_sPassword, BF_DECRYPT );
sFile = c.Crypt( sFile );
if ( sFile.substr( 0, strlen( CRYPT_VERIFICATION_TOKEN ) ) != CRYPT_VERIFICATION_TOKEN )
{
// failed to decode :(
PutModule( "Unable to decode Encrypted file [" + sChannel + "]" );
return;
}
sFile.erase( 0, strlen( CRYPT_VERIFICATION_TOKEN ) );
string sLine;
u_int iPos = 0;
while( ReadLine( sFile, sLine, iPos ) )
{
CUtils::Trim( sLine );
PutModule( "[" + sLine + "]" );
}
}
} else if ( strcasecmp( sCom.c_str(), "save" ) == 0 )
{
SaveBufferToDisk();
PutModule( "Done." );
} else
PutModule( "Unknown command [" + sCommand + "]" );
}
string GetPath( const string & sChannel )
{
string sBuffer = m_pUser->GetUserName() + Lower( sChannel );
string sRet = m_pUser->GetHomePath();
sRet += "/.znc-savebuff-" + CBlowfish::MD5( sBuffer, true );
return( sRet );
}
private:
string m_sPassword;
};
void CSaveBuffJob::RunJob()
{
CSaveBuff *p = (CSaveBuff *)m_pModule;
p->SaveBufferToDisk();
}
MODULEDEFS(CSaveBuff)
+462
View File
@@ -0,0 +1,462 @@
#include "main.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "Utils.h"
#include "Csocket.h"
#include "md5.h"
#include <pwd.h>
#include <sstream>
/*
* Secure chat system
* Author: imaginos <imaginos@imaginos.net>
*
* $Log$
* Revision 1.1 2004/08/24 00:08:52 prozacx
* Initial revision
*
*
*/
class CSChat;
class CRemMarkerJob : public CTimer
{
public:
CRemMarkerJob( CModule* pModule, unsigned int uInterval, unsigned int uCycles, const string& sLabel, const string& sDescription )
: CTimer( pModule, uInterval, uCycles, sLabel, sDescription) {}
virtual ~CRemMarkerJob() {}
void SetNick( const string & sNick )
{
m_sNick = sNick;
}
protected:
virtual void RunJob();
string m_sNick;
};
class CSChatSock : public Csock
{
public:
CSChatSock( CSChat *pMod ) : Csock()
{
m_pModule = pMod;
}
CSChatSock( int itimeout = 60 ) : Csock( itimeout )
{
m_pModule = NULL;
EnableReadLine();
}
CSChatSock( const CS_STRING & sHost, int iPort, int iTimeout = 60 )
: Csock( sHost, iPort, iTimeout )
{
m_pModule = NULL;
EnableReadLine();
}
virtual Csock *GetSockObj( const CS_STRING & sHostname, int iPort )
{
CSChatSock *p = new CSChatSock( sHostname, iPort );
return( p );
}
virtual bool ConnectionFrom( const CS_STRING & sHost, int iPort )
{
Close(); // close the listener after the first connection
return( true );
}
virtual void Connected();
virtual bool CreatedChild( Csock *pSock )
{
CSChatSock *p = (CSChatSock *)pSock;
p->SetModule( m_pModule );
p->SetChatNick( m_sChatNick );
p->SetSockName( GetSockName() + "::" + m_sChatNick );
return( true );
}
virtual void Timeout();
void SetModule( CSChat *p )
{
m_pModule = p;
}
void SetChatNick( const string & sNick )
{
m_sChatNick = sNick;
}
const string & GetChatNick() const { return( m_sChatNick ); }
virtual void ReadLine( const CS_STRING & sLine );
virtual void Disconnected();
virtual void AddLine( const string & sLine )
{
m_vBuffer.insert( m_vBuffer.begin(), sLine );
if ( m_vBuffer.size() > 200 )
m_vBuffer.pop_back();
}
virtual void DumpBuffer()
{
for( vector<CS_STRING>::reverse_iterator it = m_vBuffer.rbegin(); it != m_vBuffer.rend(); it++ )
ReadLine( *it );
m_vBuffer.clear();
}
private:
CSChat *m_pModule;
string m_sChatNick;
vector<CS_STRING> m_vBuffer;
};
class CSChat : public CModule
{
public:
MODCONSTRUCTOR(CSChat) {}
virtual ~CSChat() { CleanSocks(); }
virtual bool OnLoad( const string & sArgs )
{
m_sPemFile = sArgs;
if ( m_sPemFile.empty() )
{
m_sPemFile = m_pUser->GetBinPath() + "/znc.pem";
}
if (!CFile::Exists(m_sPemFile)) {
PutModule("Unable to load pem file [" + m_sPemFile + "]");
return false;
}
return true;
}
virtual void OnUserAttached()
{
string sName = "SCHAT::" + m_pUser->GetUserName();
for( u_int a = 0; a < m_pManager->size(); a++ )
{
if ( ( strncmp( (*m_pManager)[a]->GetSockName().c_str(), sName.c_str(), sName.length() ) != 0 ) || ( (*m_pManager)[a]->GetType() == CSChatSock::LISTENER ) )
continue;
CSChatSock *p = (CSChatSock *)(*m_pManager)[a];
p->DumpBuffer();
}
}
virtual void OnUserDetached() {}
void CleanSocks()
{
string sName = "SCHAT::" + m_pUser->GetUserName();
for( u_int a= 0; a < m_pManager->size(); a++ )
{
if ( strncmp( (*m_pManager)[a]->GetSockName().c_str(), sName.c_str(), sName.length() ) == 0 )
m_pManager->DelSock( a-- );
}
}
virtual string GetDescription()
{
return ( "Secure cross platform (:P) chat system" );
}
virtual bool OnUserRaw( string & sLine )
{
if ( strncasecmp( sLine.c_str(), "schat ", 6 ) == 0 )
{
OnModCommand( "chat " + sLine.substr( 6, string::npos ) );
return( true );
} else if ( strcasecmp( sLine.c_str(), "schat" ) == 0 )
{
PutModule( "SChat User Area ..." );
OnModCommand( "help" );
return( true );
}
return( false );
}
virtual void OnModCommand( const string& sCommand )
{
u_int iPos = sCommand.find( " " );
string sCom, sArgs;
if ( iPos == string::npos )
sCom = sCommand;
else
{
sCom = sCommand.substr( 0, iPos );
sArgs = sCommand.substr( iPos + 1, string::npos );
}
if ( ( strcasecmp( sCom.c_str(), "chat" ) == 0 ) && ( !sArgs.empty() ) )
{
string sSockName = "SCHAT::" + m_pUser->GetUserName();
string sNick = "(s)" + sArgs;
for( u_int a= 0; a < m_pManager->size(); a++ )
{
if ( strncmp( (*m_pManager)[a]->GetSockName().c_str(), sSockName.c_str(), sSockName.length() ) != 0 )
continue;
CSChatSock *pSock = (CSChatSock *)(*m_pManager)[a];
if ( strcasecmp( pSock->GetChatNick().c_str(), sNick.c_str() ) == 0 )
{
PutModule( "Already Connected to [" + sArgs + "]" );
return;
}
}
CSChatSock *pSock = new CSChatSock;
pSock->SetCipher( "HIGH" );
pSock->SetPemLocation( m_sPemFile );
pSock->SetModule( this );
pSock->SetChatNick( sNick );
u_short iPort = m_pManager->ListenRand( sSockName, m_pUser->GetLocalIP(), true, SOMAXCONN, pSock, 60 );
if ( iPort == 0 )
{
PutModule( "Failed to start chat!" );
return;
}
stringstream s;
s << "PRIVMSG " << sArgs << " :\001";
s << "DCC SCHAT chat ";
s << CUtils::GetLongIP( m_pUser->GetLocalIP() );
s << " " << iPort << "\001";
PutIRC( s.str() );
} else if ( strcasecmp( sCom.c_str(), "list" ) == 0 )
{
string sName = "SCHAT::" + m_pUser->GetUserName();
CTable Table;
Table.AddColumn( "Nick" );
Table.AddColumn( "Created" );
Table.AddColumn( "Host" );
Table.AddColumn( "Port" );
Table.AddColumn( "Status" );
Table.AddColumn( "Cipher" );
for( u_int a= 0; a < m_pManager->size(); a++ )
{
if ( strncmp( (*m_pManager)[a]->GetSockName().c_str(), sName.c_str(), sName.length() ) != 0 )
continue;
Table.AddRow();
CSChatSock *pSock = (CSChatSock *)(*m_pManager)[a];
Table.SetCell( "Nick", pSock->GetChatNick() );
unsigned long long iStartTime = pSock->GetStartTime();
time_t iTime = iStartTime / 1000;
char *pTime = ctime( &iTime );
if ( pTime )
{
string sTime = pTime;
CUtils::Trim( sTime );
Table.SetCell( "Created", sTime );
}
if ( pSock->GetType() != CSChatSock::LISTENER )
{
Table.SetCell( "Status", "Established" );
Table.SetCell( "Host", pSock->GetRemoteIP() );
Table.SetCell( "Port", CUtils::ToString( pSock->GetRemotePort() ) );
SSL_SESSION *pSession = pSock->GetSSLSession();
if ( ( pSession ) && ( pSession->cipher ) && ( pSession->cipher->name ) )
Table.SetCell( "Cipher", pSession->cipher->name );
} else
{
Table.SetCell( "Status", "Waiting" );
Table.SetCell( "Port", CUtils::ToString( pSock->GetLocalPort() ) );
}
}
if ( Table.size() )
{
unsigned int uTableIdx = 0;
string sLine;
while ( Table.GetLine( uTableIdx++, sLine ) )
PutModule( sLine );
} else
PutModule( "No SDCCs currently in session" );
} else if ( strcasecmp( sCom.c_str(), "close" ) == 0 )
{
string sName = "SCHAT::" + m_pUser->GetUserName();
for( u_int a= 0; a < m_pManager->size(); a++ )
{
if ( strncmp( (*m_pManager)[a]->GetSockName().c_str(), sName.c_str(), sName.length() ) != 0 )
continue;
CSChatSock *pSock = (CSChatSock *)(*m_pManager)[a];
if ( strncasecmp( sArgs.c_str(), "(s)", 3 ) != 0 )
sArgs = "(s)" + sArgs;
if ( strcasecmp( sArgs.c_str(), pSock->GetChatNick().c_str() ) == 0 )
{
pSock->Close();
return;
}
PutModule( "No Such Chat [" + sArgs + "]" );
}
} else if ( strcasecmp( sCom.c_str(), "help" ) == 0 )
{
PutModule( "Commands are: " );
PutModule( " help - This text." );
PutModule( " chat <nick> - Chat a nick." );
PutModule( " list - List current chats." );
PutModule( " close <nick> - Close a chat to a nick." );
PutModule( " timers - Shows related timers." );
} else if ( strcasecmp( sCom.c_str(), "timers" ) == 0 )
ListTimers();
else
PutModule( "Unknown command [" + sCom + "] [" + sArgs + "]" );
}
virtual bool OnPrivCTCP( const CNick& Nick, string& sMessage )
{
if ( strncasecmp( sMessage.c_str(), "DCC SCHAT ", 10 ) == 0 )
{
// chat ip port
unsigned long iIP = strtoul( CUtils::Token( sMessage, 3 ).c_str(), NULL, 10 );
unsigned short iPort = strtoul( CUtils::Token( sMessage, 4 ).c_str(), NULL, 10 );
if ( ( iIP > 0 ) && ( iPort > 0 ) )
{
pair<u_long, u_short> pTmp;
pTmp.first = iIP;
pTmp.second = iPort;
m_siiWaitingChats["(s)" + Nick.GetNick()] = pTmp;
SendToUser( "(s)" + Nick.GetNick() + "!" + "(s)" + Nick.GetNick() + "@" + CUtils::GetIP( iIP ), "*** Incoming DCC SCHAT, Accept ? (yes/no)" );
CRemMarkerJob *p = new CRemMarkerJob( this, 60, 1, "Remove (s)" + Nick.GetNick(), "Removes this nicks entry for waiting DCC." );
p->SetNick( "(s)" + Nick.GetNick() );
AddTimer( p );
return( true );
}
}
return( false );
}
void AcceptSDCC( const string & sNick, u_long iIP, u_short iPort )
{
CSChatSock *p = new CSChatSock( CUtils::GetIP( iIP ), iPort, 60 );
p->SetModule( this );
p->SetChatNick( sNick );
string sSockName = "SCHAT::" + m_pUser->GetUserName() + "::" + sNick;
m_pManager->Connect( CUtils::GetIP( iIP ), iPort, sSockName, 60, true, m_pUser->GetLocalIP(), p );
RemTimer( "Remove " + sNick ); // delete any associated timer to this nick
}
virtual bool OnUserMsg( const string& sTarget, string& sMessage )
{
if ( strncmp( sTarget.c_str(), "(s)", 3 ) == 0 )
{
string sSockName = "SCHAT::" + m_pUser->GetUserName() + "::" + sTarget;
CSChatSock *p = (CSChatSock *)m_pManager->FindSockByName( sSockName );
if ( !p )
{
map< string,pair< u_long,u_short > >::iterator it = m_siiWaitingChats.find( sTarget );
if ( it != m_siiWaitingChats.end() )
{
if ( strcasecmp( sMessage.c_str(), "yes" ) != 0 )
SendToUser( sTarget + "!" + sTarget + "@" + CUtils::GetIP( it->second.first ), "Refusing to accept DCC SCHAT!" );
else
AcceptSDCC( sTarget, it->second.first, it->second.second );
m_siiWaitingChats.erase( it );
return( true );
}
PutModule( "No such SCHAT to [" + sTarget + "]" );
} else
p->Write( sMessage + "\n" );
return( true );
}
return( false );
}
virtual void RemoveMarker( const string & sNick )
{
map< string,pair< u_long,u_short > >::iterator it = m_siiWaitingChats.find( sNick );
if ( it != m_siiWaitingChats.end() )
m_siiWaitingChats.erase( it );
}
void SendToUser( const string & sFrom, const string & sText )
{
//:*schat!znc@znc.com PRIVMSG Jim :
string sSend = ":" + sFrom + " PRIVMSG " + m_pUser->GetCurNick() + " :" + sText;
PutUser( sSend );
}
bool IsAttached()
{
return( m_pUser->IsUserAttached() );
}
private:
map< string,pair< u_long,u_short > > m_siiWaitingChats;
string m_sPemFile;
};
//////////////////// methods ////////////////
void CSChatSock::ReadLine( const CS_STRING & sLine )
{
if ( m_pModule )
{
string sText = sLine;
CUtils::Trim( sText );
if ( m_pModule->IsAttached() )
m_pModule->SendToUser( m_sChatNick + "!" + m_sChatNick + "@" + GetRemoteIP(), sText );
else
AddLine( sText );
}
}
void CSChatSock::Disconnected()
{
if ( m_pModule )
m_pModule->SendToUser( m_sChatNick + "!" + m_sChatNick + "@" + GetRemoteIP(), "*** Disconnected." );
}
void CSChatSock::Connected()
{
SetTimeout( 0 );
if ( m_pModule )
m_pModule->SendToUser( m_sChatNick + "!" + m_sChatNick + "@" + GetRemoteIP(), "*** Connected." );
}
void CSChatSock::Timeout()
{
if ( m_pModule )
{
if ( GetType() == LISTENER )
m_pModule->PutModule( "Timeout while waiting for [" + m_sChatNick + "]" );
else
m_pModule->SendToUser( m_sChatNick + "!" + m_sChatNick + "@" + GetRemoteIP(), "*** Connection Timed out." );
}
}
void CRemMarkerJob::RunJob()
{
CSChat *p = (CSChat *)m_pModule;
p->RemoveMarker( m_sNick );
// store buffer
}
MODULEDEFS(CSChat)
+220
View File
@@ -0,0 +1,220 @@
#ifndef _NO_CSOCKET_NS
#define _NO_CSOCKET_NS
#endif
#include "Csocket.h"
#include "User.h"
#include "Nick.h"
#include "Modules.h"
#include "Chan.h"
#include "Utils.h"
#include <sys/wait.h>
// Forward Declaration
class CShellMod;
class CExecSock : public Csock {
public:
CExecSock(CShellMod* pShellMod, const string& sExec) : Csock() {
EnableReadLine();
m_pParent = pShellMod;
int iReadFD, iWriteFD;
m_iPid = popen2(iReadFD, iWriteFD, sExec);
ConnectFD(iReadFD, iWriteFD, "0.0.0.0:0");
}
virtual ~CExecSock() {
close2(m_iPid, GetRSock(), GetWSock());
SetRSock( -1 );
SetWSock( -1 );
}
// These next two function's bodies are at the bottom of the file since they reference CShellMod
virtual void ReadLine(const string& sData);
virtual void Disconnected();
CShellMod* m_pParent;
int m_iPid;
int popen2(int & iReadFD, int & iWriteFD, const string & sCommand) {
int rpipes[2] = { -1, -1 };
int wpipes[2] = { -1, -1 };
iReadFD = -1;
iWriteFD = -1;
pipe(rpipes);
pipe(wpipes);
int iPid = fork();
if (iPid == -1) {
return -1;
}
if (iPid == 0) {
close(wpipes[1]);
close(rpipes[0]);
dup2(wpipes[0], 0);
dup2(rpipes[1], 1);
dup2(rpipes[1], 2);
close(wpipes[0]);
close(rpipes[1]);
system( sCommand.c_str() );
exit(0);
}
close(wpipes[0]);
close(rpipes[1]);
iWriteFD = wpipes[1];
iReadFD = rpipes[0];
return iPid;
}
void close2(int iPid, int iReadFD, int iWriteFD) {
close( iReadFD );
close( iWriteFD );
u_int iNow = time( NULL );
while( waitpid( iPid, NULL, WNOHANG ) == 0 )
{
if ( ( time( NULL ) - iNow ) > 5 )
break; // giveup
usleep( 100 );
}
return;
}
};
class CShellMod : public CModule {
public:
MODCONSTRUCTOR(CShellMod) {
m_sPath = pUser->GetHomePath();
}
virtual ~CShellMod() {
vector<Csock*> vSocks = m_pManager->FindSocksByName("SHELL");
for (unsigned int a = 0; a < vSocks.size(); a++) {
m_pManager->DelSockByAddr(vSocks[a]);
}
}
virtual string GetDescription() {
return "Gives shell access.";
}
virtual void OnModCommand(const string& sCommand) {
if ((strcasecmp(sCommand.c_str(), "cd") == 0) || (strncasecmp(sCommand.c_str(), "cd ", 3) == 0)) {
string sPath = CUtils::ChangeDir(m_sPath, ((sCommand.length() == 2) ? m_pUser->GetHomePath() : sCommand.substr(3)), m_pUser->GetHomePath());
CFile Dir(sPath);
if (Dir.IsDir()) {
m_sPath = sPath;
} else if (Dir.Exists()) {
PutShell("cd: not a directory [" + sPath + "]");
} else {
PutShell("cd: no such directory [" + sPath + "]");
}
PutShell("znc$");
} else if (strcasecmp(CUtils::Token(sCommand, 0).c_str(), "SEND") == 0) {
string sToNick = CUtils::Token(sCommand, 1);
string sFile = CUtils::Token(sCommand, 2);
if ((sToNick.empty()) || (sFile.empty())) {
PutShell("usage: Send <nick> <file>");
} else {
sFile = CUtils::ChangeDir(m_sPath, sFile, m_pUser->GetHomePath());
if (!CFile::Exists(sFile)) {
PutShell("get: no such file [" + sFile + "]");
} else if (!CFile::IsReg(sFile)) {
PutShell("get: not a file [" + sFile + "]");
} else {
m_pUser->SendFile(sToNick, sFile, GetModName());
}
}
} else if (strcasecmp(CUtils::Token(sCommand, 0).c_str(), "GET") == 0) {
string sFile = CUtils::Token(sCommand, 1);
if (sFile.empty()) {
PutShell("usage: Get <file>");
} else {
sFile = CUtils::ChangeDir(m_sPath, sFile, m_pUser->GetHomePath());
if (!CFile::Exists(sFile)) {
PutShell("get: no such file [" + sFile + "]");
} else if (!CFile::IsReg(sFile)) {
PutShell("get: not a file [" + sFile + "]");
} else {
m_pUser->SendFile(m_pUser->GetCurNick(), sFile, GetModName());
}
}
} else {
RunCommand(sCommand);
}
}
virtual bool OnStatusCommand(const string& sCommand) {
if (strcasecmp(sCommand.c_str(), "SHELL") == 0) {
PutShell("-- ZNC Shell Service --");
return true;
}
return false;
}
virtual bool OnDCCUserSend(const CNick& RemoteNick, unsigned long uLongIP, unsigned short uPort, const string& sFile, unsigned long uFileSize) {
if (strcasecmp(RemoteNick.GetNick().c_str(), string(GetModNick()).c_str()) == 0) {
string sLocalFile = CUtils::ChangeDir(m_sPath, sFile, m_pUser->GetHomePath());
m_pUser->GetFile(m_pUser->GetCurNick(), CUtils::GetIP(uLongIP), uPort, sLocalFile, uFileSize, GetModName());
return true;
}
return false;
}
void PutShell(const string& sLine) {
string sPath = m_sPath;
unsigned int a = sPath.find(' ');
while (a != string::npos) {
sPath.replace(a, 1, "_");
a = sPath.find(' ');
}
PutModule(sLine, m_pUser->GetCurNick(), sPath);
}
void RunCommand(const string& sCommand) {
m_pManager->AddSock((Csock*) new CExecSock(this, "cd " + m_sPath + " && " + sCommand), "SHELL");
}
private:
string m_sPath;
};
void CExecSock::ReadLine(const string& sData) {
string sLine = sData;
while ((sLine.length()) && (sLine[sLine.length() -1] == '\r') || (sLine[sLine.length() -1] == '\n')) {
sLine = sLine.substr(0, sLine.length() -1);
}
unsigned int a = sLine.find('\t');
while (a != string::npos) {
sLine.replace(a, 1, " ");
a = sLine.find('\t');
}
m_pParent->PutShell(sLine);
}
void CExecSock::Disconnected() {
m_pParent->PutShell("znc$");
}
MODULEDEFS(CShellMod)
+95
View File
@@ -0,0 +1,95 @@
/* This is znc's config file */
/* C style comments are supported, but may only be preceded by whitespace. */
/* perl style #comments are also supported, and also must be preceded only by whitespace. */
/* the ending of multiline comments (star slash) must be at the end of a line. */
// This is the port that znc will listen on
// If the port is prepended with a '+' then znc listens using ssl. Note: znc must be compiled with ssl enabled.
ListenPort = 12345
// If you define the ISpoofFile, znc will write the ident of the user trying to connect to the file. Very useful if your box supports oidentd.
#ISpoofFile = /tmp/ispoof
// This is the pid file that is needed if you want to crontab the zncchk shell script
PidFile = znc.pid
// This is the prefix for the status window. Some clients or scripts may require you to change it, default is *status
StatusPrefix = *
// User definition
<User user>
// You can override the global StatusPrefix on a per user basis. Using - is a good alternative in mIRC but it breaks BitchX
#StatusPrefix = -
// Password used to connect.
Pass = pass
// You can use an md5 hash by supplying a - after the hash (with a space between)
// To generate a hashed password, use ./znc --makepass
// This next line would be just like doing "Pass = pass" like above, except your pass is not exposed simply by reading the config
#Pass = 1a1dc91c907325c69271ddf0c944bc72 -
Nick = zncuser
AltNick = zncus3r
Ident = znc
RealName = Got ZNC?
#VHost = uncomment.and.put.your.vhost.here.com
ChanModes = +stn
KeepNick = true
// You may use multiple Allow lines to restrict access to this user. All connections are denied by default unless they match an ip below.
// Note: IPs only!
Allow = *
#Allow = 24.24.24.*
#Allow = 192.168.1.*
// Uncomment this next line if you want znc to use the longip that your client sends it when establishing a dcc connection
// By default znc will use the ip that you connect to it to contact your end of a bounced dcc
#DCCLookupMethod = Client
// You can write modules and dynamically load them at runtime
// Uncomment the next line to deny this user access to (un)loading modules. Only the modules you load for them in this config will be available to them
#DenyLoadMod = true
// The sample module does random things, it is meant to be a sample for module authors to learn from
#LoadModule = sample
// The shell module gives you shell access to the system in a query window
#LoadModule = shell
// The savebuff module is a module that saves your (encrypted) channel buffers to disk. It is best used when KeepBuffer = true
#LoadModule = savebuff
// Add the servers that you wish znc to use when connecting to IRC. <server> [[+]port [pass]]
// If the port is prepended with a '+' then znc connects to this server with ssl. Note: znc must be compiled with ssl enabled.
Server = irc.nac.net 6667
Server = irc.efnet.pl 6667
#Server = irc.someserver.com +8000 serverpass
// Add channels that you want znc to join on start.
<Chan #znc>
Key = znc
Modes = +sn-t
// This is the playback buffer size (in LINES) - WARNING: setting this too high could cause you to get a lot of text when you attach
Buffer = 50
// This will play the whole buffer back to you each time you connect. It will also buffer channels while you are attached
#KeepBuffer = true
</Chan>
</User>
// Multiple users are supported, this one is commented out
/*<User user2>
Pass = somepass
Nick = user2
Ident = user2
RealName = Second User
Allow = *
Server = irc.efnet.pl 6667
</User>*/
+471
View File
@@ -0,0 +1,471 @@
#include "znc.h"
#include "User.h"
#include "Server.h"
#include "UserSock.h"
#include "IRCSock.h"
#include "Utils.h"
#include <pwd.h>
#include <sys/types.h>
#ifdef _MODULES
#include "Modules.h"
#endif
CZNC::CZNC() {
m_uListenPort = 0;
m_bISpoofLocked = false;
}
CZNC::~CZNC() {
m_Manager.Cleanup();
DeleteUsers();
}
bool CZNC::OnBoot() {
for (map<string,CUser*>::iterator it = m_msUsers.begin(); it != m_msUsers.end(); it++) {
if (!it->second->OnBoot()) {
return false;
}
}
return true;
}
int CZNC::Loop() {
m_Manager.SetSelectTimeout(10000);
m_itUserIter = m_msUsers.begin();
while (true) {
m_Manager.Loop();
if (m_bISpoofLocked) {
continue;
}
if (m_itUserIter == m_msUsers.end()) {
m_itUserIter = m_msUsers.begin();
}
string sSockName = "IRC::" + m_itUserIter->first;
CUser* pUser = m_itUserIter->second;
m_itUserIter++;
CIRCSock* pIRCSock = (CIRCSock*) m_Manager.FindSockByName(sSockName);
if (!pIRCSock) {
CServer* pServer = pUser->GetNextServer();
if (!pServer) {
continue;
}
if (!m_sISpoofFile.empty()) {
CFile File(m_sISpoofFile);
if (File.Open(O_RDONLY)) {
char buf[1024];
memset((char*) buf, 0, 1024);
File.Read(buf, 1023);
File.Close();
m_sOrigISpoof = buf;
}
if (File.Open(O_WRONLY | O_TRUNC | O_CREAT)) {
File.Write(pUser->GetIdent() + "\r\n");
File.Close();
}
m_bISpoofLocked = true;
}
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() + ":" + CUtils::ToString(pServer->GetPort()) + "] ...");
}
pIRCSock = new CIRCSock(this, pUser);
pIRCSock->SetPass(pServer->GetPass());
bool bSSL = false;
#ifdef HAVE_LIBSSL
if (pServer->IsSSL()) {
bSSL = true;
pIRCSock->SetPemLocation(GetBinPath() + "/znc.pem");
}
#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?)");
}
}
}
}
return 0;
}
void CZNC::ReleaseISpoof() {
if (!m_sISpoofFile.empty()) {
CFile File(m_sISpoofFile);
if (File.Open(O_WRONLY | O_TRUNC | O_CREAT)) {
File.Write(m_sOrigISpoof);
File.Close();
}
m_sOrigISpoof = "";
}
m_bISpoofLocked = false;
}
bool CZNC::WritePidFile(int iPid) {
if (!m_sPidFile.empty()) {
CFile File(m_sPidFile);
if (File.Open(O_WRONLY | O_TRUNC | O_CREAT)) {
File.Write(CUtils::ToString(iPid) + "\n");
File.Close();
return true;
}
}
return false;
}
void CZNC::DeleteUsers() {
for (map<string,CUser*>::iterator a = m_msUsers.begin(); a != m_msUsers.end(); a++) {
delete a->second;
}
m_msUsers.clear();
m_itUserIter = m_msUsers.end();
}
CUser* CZNC::GetUser(const string& sUser) {
// Todo: make this case insensitive
map<string,CUser*>::iterator it = m_msUsers.find(sUser);
return (it == m_msUsers.end()) ? NULL : it->second;
}
Csock* CZNC::FindSockByName(const string& sSockName) {
return m_Manager.FindSockByName(sSockName);
}
bool CZNC::Listen() {
if (!m_uListenPort) {
return false;
}
CUserSock* pUserSock = new CUserSock;
pUserSock->SetZNC(this);
bool bSSL = false;
#ifdef HAVE_LIBSSL
if (IsSSL()) {
bSSL = true;
pUserSock->SetPemLocation(GetBinPath() + "/znc.pem");
}
#endif
return m_Manager.ListenAll(m_uListenPort, "_LISTENER", bSSL, SOMAXCONN, pUserSock);
}
bool CZNC::IsHostAllowed(const string& sHostMask) {
for (map<string,CUser*>::iterator a = m_msUsers.begin(); a != m_msUsers.end(); a++) {
if (a->second->IsHostAllowed(sHostMask)) {
return true;
}
}
return false;
}
void CZNC::InitDirs(const string& sArgvPath) {
char buf[PATH_MAX];
getcwd(buf, PATH_MAX);
// If the bin was not ran from the current directory, we need to add that dir onto our cwd
unsigned int uPos = sArgvPath.rfind('/');
m_sBinPath = (uPos == string::npos) ? string(buf) : CUtils::ChangeDir(buf, sArgvPath.substr(0, uPos), "");
// Try to set the user's home dir, default to binpath on failure
struct passwd* pUserInfo = getpwuid(getuid());
if (pUserInfo) {
m_sHomePath = pUserInfo->pw_dir;
}
if (m_sHomePath.empty()) {
m_sHomePath = m_sBinPath;
}
// Other dirs that we use
m_sDLPath = m_sBinPath + "/downloads";
m_sModPath = m_sBinPath + "/modules";
}
bool CZNC::ParseConfig(const string& sConfigFile) {
string sStatusPrefix;
string sFilePath = sConfigFile;
if (CUtils::Left(sConfigFile, 1) != "/") {
sFilePath = m_sBinPath + "/" + sFilePath;
}
CFile File(sFilePath);
if (!File.Open(O_RDONLY)) {
cerr << "Could not open config [" << sFilePath << "]" << endl;
return false;
}
string sLine;
bool bCommented = false; // support for /**/ style comments
CUser* pUser = NULL; // Used to keep track of which user block we are in
CChan* pChan = NULL; // Used to keep track of which chan block we are in
while (File.ReadLine(sLine)) {
while ((CUtils::Right(sLine, 1) == "\r") || (CUtils::Right(sLine, 1) == "\n")) {
CUtils::Trim(sLine);
}
if ((sLine.empty()) || (sLine[0] == '#') || (CUtils::Left(sLine, 2) == "//")) {
continue;
}
if (CUtils::Left(sLine, 2) == "/*") {
if (CUtils::Right(sLine, 2) != "*/") {
bCommented = true;
}
continue;
}
if (bCommented) {
if (CUtils::Right(sLine, 2) == "*/") {
bCommented = false;
}
continue;
}
if ((CUtils::Left(sLine, 1) == "<") && (CUtils::Right(sLine, 1) == ">")) {
CUtils::LeftChomp(sLine);
CUtils::RightChomp(sLine);
CUtils::Trim(sLine);
string sTag = sLine.substr(0, sLine.find_first_of(" \t\r\n"));
string sValue = (sTag.size() < sLine.size()) ? sLine.substr(sTag.size() +1) : "";
CUtils::Trim(sTag);
CUtils::Trim(sValue);
if (CUtils::Left(sLine, 1) == "/") {
string sTag = sLine.substr(1);
if (pUser) {
if (pChan) {
if (strcasecmp(sTag.c_str(), "Chan") == 0) {
pUser->AddChan(pChan);
pChan = NULL;
continue;
}
} else if (strcasecmp(sTag.c_str(), "User") == 0) {
pUser = NULL;
continue;
}
}
} else if (strcasecmp(sTag.c_str(), "User") == 0) {
if (pUser) {
cerr << "You may not nest <User> tags inside of other <User> tags." << endl;
return false;
}
if (sValue.empty()) {
cerr << "You must supply a username in the <User> tag." << endl;
return false;
}
if (m_msUsers.find(sValue) != m_msUsers.end()) {
cerr << "User [" << sValue << "] defined more than once." << endl;
return false;
}
pUser = new CUser(sValue, this);
if (!sStatusPrefix.empty()) {
if (!pUser->SetStatusPrefix(sStatusPrefix)) {
cerr << "Invalid StatusPrefix [" + sStatusPrefix + "] Must be 1-5 chars, no spaces." << endl;
}
}
m_msUsers[sValue] = pUser;
continue;
} else if (strcasecmp(sTag.c_str(), "Chan") == 0) {
if (!pUser) {
cerr << "<Chan> tags must be nested inside of a <User> tag." << endl;
return false;
}
if (pChan) {
cerr << "You may not nest <Chan> tags inside of other <Chan> tags." << endl;
return false;
}
pChan = new CChan(sValue, pUser);
continue;
}
}
// If we have a regular line, figure out where it goes
string sName = CUtils::Token(sLine, 0, false, '=');
string sValue = CUtils::Token(sLine, 1, true, '=');
CUtils::Trim(sName);
CUtils::Trim(sValue);
if ((!sName.empty()) && (!sValue.empty())) {
if (pUser) {
if (pChan) {
if (strcasecmp(sName.c_str(), "Buffer") == 0) {
pChan->SetBufferCount(strtoul(sValue.c_str(), NULL, 10));
continue;
} else if (strcasecmp(sName.c_str(), "KeepBuffer") == 0) {
pChan->SetKeepBuffer((strcasecmp(sValue.c_str(), "true") == 0));
continue;
} else if (strcasecmp(sName.c_str(), "Key") == 0) {
pChan->SetKey(sValue);
continue;
} else if (strcasecmp(sName.c_str(), "Modes") == 0) {
pChan->SetDefaultModes(sValue);
continue;
}
} else {
if (strcasecmp(sName.c_str(), "Nick") == 0) {
pUser->SetNick(sValue);
continue;
} else if (strcasecmp(sName.c_str(), "AltNick") == 0) {
pUser->SetAltNick(sValue);
continue;
} else if (strcasecmp(sName.c_str(), "Pass") == 0) {
if (CUtils::Right(sValue, 1) == "-") {
CUtils::RightChomp(sValue);
CUtils::Trim(sValue);
pUser->SetPass(sValue, true);
} else {
pUser->SetPass(sValue, false);
}
continue;
} else if (strcasecmp(sName.c_str(), "Ident") == 0) {
pUser->SetIdent(sValue);
continue;
} else if (strcasecmp(sName.c_str(), "DenyLoadMod") == 0) {
pUser->SetDenyLoadMod((strcasecmp(sValue.c_str(), "TRUE") == 0));
continue;
} else if (strcasecmp(sName.c_str(), "StatusPrefix") == 0) {
if (!pUser->SetStatusPrefix(sValue)) {
cerr << "Invalid StatusPrefix [" + sValue + "] Must be 1-5 chars, no spaces." << endl;
}
continue;
} else if (strcasecmp(sName.c_str(), "DCCLookupMethod") == 0) {
pUser->SetUseClientIP((strcasecmp(sValue.c_str(), "Client") == 0));
continue;
} else if (strcasecmp(sName.c_str(), "RealName") == 0) {
pUser->SetRealName(sValue);
continue;
} else if (strcasecmp(sName.c_str(), "KeepNick") == 0) {
pUser->SetKeepNick((strcasecmp(sValue.c_str(), "true") == 0));
continue;
} else if (strcasecmp(sName.c_str(), "ChanModes") == 0) {
pUser->SetDefaultChanModes(sValue);
continue;
} else if (strcasecmp(sName.c_str(), "VHost") == 0) {
pUser->SetVHost(sValue);
continue;
} else if (strcasecmp(sName.c_str(), "Allow") == 0) {
pUser->AddAllowedHost(sValue);
continue;
} else if (strcasecmp(sName.c_str(), "Server") == 0) {
if (!pUser->AddServer(sValue)) {
cerr << "Unable to add server [" << sValue << "]" << endl;
}
continue;
} else if (strcasecmp(sName.c_str(), "Chan") == 0) {
pUser->AddChan(sValue);
continue;
} else if (strcasecmp(sName.c_str(), "LoadModule") == 0) {
#ifdef _MODULES
string sModRet;
string sModName = CUtils::Token(sValue, 0);
string sArgs = CUtils::Token(sValue, 1, true);
pUser->GetModules().LoadModule(sModName, sArgs, pUser, m_sBinPath, sModRet);
cout << sModRet << endl;
#else
cerr << "Unable to load [" << sValue << "] Modules are not enabled." << endl;
#endif
continue;
}
}
} else {
if (strcasecmp(sName.c_str(), "ListenPort") == 0) {
m_bSSL = false;
string sPort = sValue;
if (CUtils::Left(sPort, 1) == "+") {
CUtils::LeftChomp(sPort);
m_bSSL = true;
}
m_uListenPort = strtol(sPort.c_str(), NULL, 10);
#ifndef HAVE_LIBSSL
if (m_bSSL) {
cerr << "SSL is not enabled, could not bind to ssl port [" << m_uListenPort << "]" << endl;
return false;
}
#endif
if ((m_bSSL) && (!CFile::Exists(GetBinPath() + "/znc.pem"))) {
cerr << "Unable to locate pem file: [" << GetBinPath() << "/znc.pem]" << endl;
return false;
}
if (!Listen()) {
cerr << "Could not bind to port [" << m_uListenPort << "]" << endl;
return false;
}
continue;
} else if (strcasecmp(sName.c_str(), "ISpoofFile") == 0) {
m_sISpoofFile = sValue;
continue;
} else if (strcasecmp(sName.c_str(), "PidFile") == 0) {
m_sPidFile = sValue;
continue;
} else if (strcasecmp(sName.c_str(), "StatusPrefix") == 0) {
sStatusPrefix = sValue;
continue;
}
}
}
cerr << "Unhandled line in config: [" << sLine << "]" << endl;
}
if (pChan) {
delete pChan;
}
File.Close();
if (!m_msUsers.size()) {
cerr << "You must define at least one user in your config." << endl;
return false;
}
return true;
}
+68
View File
@@ -0,0 +1,68 @@
#ifndef _ZNC_H
#define _ZNC_H
#include "main.h"
#include <map>
using std::map;
class CUser;
class CUserSock;
class CZNC {
public:
CZNC();
virtual ~CZNC();
void DeleteUsers();
int Loop();
void ReleaseISpoof();
bool WritePidFile(int iPid);
CUser* GetUser(const string& sUser);
Csock* FindSockByName(const string& sSockName);
bool Listen();
bool ParseConfig(const string& sConfigFile);
bool IsHostAllowed(const string& sHostMask);
void InitDirs(const string& sArgvPath);
bool OnBoot();
// Getters
TSocketManager<Csock>& GetManager() { return m_Manager; }
unsigned int GetListenPort() const { return m_uListenPort; }
const string& GetBinPath() const { return m_sBinPath; }
const string& GetDLPath() const { return m_sDLPath; }
const string& GetModPath() const { return m_sModPath; }
const string& GetHomePath() const { return m_sHomePath; }
bool IsSSL() const {
#ifdef HAVE_LIBSSL
return m_bSSL;
#endif
return false;
}
// !Getters
// Static allocator
static CZNC* New() {
static CZNC* pZNC = new CZNC;
return pZNC;
}
private:
protected:
unsigned short m_uListenPort;
map<string,CUser*> m_msUsers;
TSocketManager<Csock> m_Manager;
string m_sBinPath;
string m_sDLPath;
string m_sModPath;
string m_sHomePath;
string m_sISpoofFile;
string m_sOrigISpoof;
string m_sPidFile;
bool m_bISpoofLocked;
bool m_bSSL;
map<string,CUser*>::iterator m_itUserIter; // This needs to be reset to m_msUsers.begin() if anything is added or removed to the map
};
#endif // !_ZNC_H
Executable
+25
View File
@@ -0,0 +1,25 @@
#!/bin/sh
dir="."
cmd="znc"
pidfile="znc.pid"
PATH=.:$PATH
export PATH
cd $dir
if test -s $pidfile; then
pid=`cat $pidfile`
if `kill -0 $pid >/dev/null 2>&1`; then
exit 0
fi
rm -f $pidfile
fi
echo ""
echo "Reloading..."
echo ""
$cmd
exit 0