mirror of
https://github.com/znc/znc.git
synced 2026-08-08 01:43:03 +02:00
Initial revision
git-svn-id: https://znc.svn.sourceforge.net/svnroot/znc/trunk@2 726aef4b-f618-498e-8847-2d620e286838
This commit is contained in:
+52
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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"
|
||||
+130
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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...");
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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 */
|
||||
Executable
+45
@@ -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
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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>*/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user